diff --git a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js
index 5cc717be46..86b5bdd0d0 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js
@@ -14,7 +14,7 @@
'use strict';
- function blockEditorModelObjectFactory($interpolate, $q, udiService, contentResource, localizationService) {
+ function blockEditorModelObjectFactory($interpolate, $q, udiService, contentResource, localizationService, umbRequestHelper) {
/**
* Simple mapping from property model content entry to editing model,
@@ -325,6 +325,18 @@
this.propertyEditorAlias = propertyEditorAlias;
this.blockConfigurations = blockConfigurations;
+ this.blockConfigurations.forEach(blockConfiguration => {
+ if (blockConfiguration.view != null && blockConfiguration.view !== "") {
+ blockConfiguration.view = umbRequestHelper.convertVirtualToAbsolutePath(blockConfiguration.view);
+ }
+ if (blockConfiguration.stylesheet != null && blockConfiguration.stylesheet !== "") {
+ blockConfiguration.stylesheet = umbRequestHelper.convertVirtualToAbsolutePath(blockConfiguration.stylesheet);
+ }
+ if (blockConfiguration.thumbnail != null && blockConfiguration.thumbnail !== "") {
+ blockConfiguration.thumbnail = umbRequestHelper.convertVirtualToAbsolutePath(blockConfiguration.thumbnail);
+ }
+ });
+
this.scaffolds = [];
this.isolatedScope = scopeOfExistance.$new(true);
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js
index 7b43b239ea..90125e7de6 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js
@@ -15,7 +15,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
*
* @description
* This will convert a virtual path (i.e. ~/App_Plugins/Blah/Test.html ) to an absolute path
- *
+ *
* @param {string} a virtual path, if this is already an absolute path it will just be returned, if this is a relative path an exception will be thrown
*/
convertVirtualToAbsolutePath: function(virtualPath) {
@@ -31,6 +31,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
return Umbraco.Sys.ServerVariables.application.applicationPath + virtualPath.trimStart("~/");
},
+
/**
* @ngdoc method
* @name umbraco.services.umbRequestHelper#dictionaryToQueryString
@@ -39,7 +40,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
*
* @description
* This will turn an array of key/value pairs or a standard dictionary into a query string
- *
+ *
* @param {Array} queryStrings An array of key/value pairs
*/
dictionaryToQueryString: function (queryStrings) {
@@ -76,9 +77,9 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
*
* @description
* This will return the webapi Url for the requested key based on the servervariables collection
- *
+ *
* @param {string} apiName The webapi name that is found in the servervariables["umbracoUrls"] dictionary
- * @param {string} actionName The webapi action name
+ * @param {string} actionName The webapi action name
* @param {object} queryStrings Can be either a string or an array containing key/value pairs
*/
getApiUrl: function (apiName, actionName, queryStrings) {
@@ -103,7 +104,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
*
* @description
* This returns a promise with an underlying http call, it is a helper method to reduce
- * the amount of duplicate code needed to query http resources and automatically handle any
+ * the amount of duplicate code needed to query http resources and automatically handle any
* Http errors. See /docs/source/using-promises-resources.md
*
* @param {object} opts A mixed object which can either be a string representing the error message to be
@@ -117,7 +118,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
* The error callback must return an object containing: {errorMsg: errorMessage, data: originalData, status: status }
*/
resourcePromise: function (httpPromise, opts) {
-
+
/** The default success callback used if one is not supplied in the opts */
function defaultSuccess(data, status, headers, config) {
//when it's successful, just return the data
@@ -151,7 +152,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
return httpPromise.then(function (response) {
- //invoke the callback
+ //invoke the callback
var result = callbacks.success.apply(this, [response.data, response.status, response.headers, response.config]);
formHelper.showNotifications(response.data);
@@ -183,7 +184,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
overlayService.ysod(error);
}
else {
- //show a simple error notification
+ //show a simple error notification
notificationsService.error("Server error", "Contact administrator, see log for full details.
" + result.errorMsg + "");
}
@@ -209,7 +210,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
*
* @description
* Used for saving content/media/members specifically
- *
+ *
* @param {Object} args arguments object
* @returns {Promise} http promise object.
*/
@@ -233,7 +234,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
if (args.showNotifications === null || args.showNotifications === undefined) {
args.showNotifications = true;
}
-
+
//save the active tab id so we can set it when the data is returned.
var activeTab = _.find(args.content.tabs, function (item) {
return item.active;
@@ -300,7 +301,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
overlayService.ysod(error);
}
else {
- //show a simple error notification
+ //show a simple error notification
notificationsService.error("Server error", "Contact administrator, see log for full details.
" + response.data.ExceptionMessage + "");
}
@@ -331,7 +332,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
});
}
else if (!jsonData.key || !jsonData.value) { throw "jsonData object must have both a key and a value property"; }
-
+
return $http({
method: 'POST',
url: url,
@@ -366,7 +367,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
return $q.reject(response);
});
},
-
+
/**
* @ngdoc method
* @name umbraco.resources.contentResource#downloadFile
@@ -374,7 +375,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
*
* @description
* Downloads a file to the client using AJAX/XHR
- *
+ *
* @param {string} httpPath the path (url) to the resource being downloaded
* @returns {Promise} http promise object.
*/
@@ -388,7 +389,7 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
// Use an arraybuffer
return $http.get(httpPath, { responseType: 'arraybuffer' })
.then(function (response) {
-
+
var octetStreamMime = 'application/octet-stream';
var success = false;
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/blockcard/umbBlockCard.component.js b/src/Umbraco.Web.UI.Client/src/views/components/blockcard/umbBlockCard.component.js
index 41ae035617..c0758aa2df 100644
--- a/src/Umbraco.Web.UI.Client/src/views/components/blockcard/umbBlockCard.component.js
+++ b/src/Umbraco.Web.UI.Client/src/views/components/blockcard/umbBlockCard.component.js
@@ -15,7 +15,7 @@
});
function BlockCardController() {
-
+
var vm = this;
}
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js
index decf05be5f..80207bb920 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js
@@ -11,13 +11,13 @@
/** Returns true if publish meets the requirements of mandatory languages */
function canPublish() {
-
+
var hasSomethingToPublish = false;
for (var i = 0; i < vm.variants.length; i++) {
var variant = vm.variants[i];
- // if varaint is mandatory and not already published:
+ // if varaint is mandatory and not already published, then we require it to be set to publish:
if (variant.publish === false && notPublishedMandatoryFilter(variant)) {
return false;
}
@@ -39,8 +39,9 @@
function hasAnyDataFilter(variant) {
- if (variant.name == null || variant.name.length === 0) {
- return false;
+ // if we have a name, then we have data.
+ if (variant.name != null && variant.name.length > 0) {
+ return true;
}
if(variant.isDirty === true) {
@@ -77,7 +78,7 @@
}
function notPublishedMandatoryFilter(variant) {
- return variant.state !== "Published" && isMandatoryFilter(variant);
+ return variant.state !== "Published" && variant.state !== "PublishedPendingChanges" && variant.isMandatory === true;
}
function isMandatoryFilter(variant) {
//determine a variant is 'dirty' (meaning it will show up as publish-able) if it's
@@ -98,11 +99,11 @@
vm.variants = $scope.model.variants;
_.each(vm.variants, (variant) => {
-
+
// reset to not be published
variant.publish = false;
variant.save = false;
-
+
variant.isMandatory = isMandatoryFilter(variant);
// If we have a variant thats not in the state of NotCreated, then we know we have adata and its not a new content node.
@@ -112,12 +113,12 @@
});
_.each(vm.variants, (variant) => {
-
+
// if this is a new node and we have data on this variant.
if(vm.isNew === true && hasAnyDataFilter(variant)) {
variant.save = true;
}
-
+
});
vm.availableVariants = vm.variants.filter(publishableVariantFilter);
@@ -139,7 +140,7 @@
if (a.language.name < b.language.name) {
return 1;
}
- }
+ }
if (a.segment && b.segment) {
if (a.segment > b.segment) {
return -1;
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html
index 71e19651d6..c3e0b90f5f 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html
+++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html
@@ -21,19 +21,16 @@
on-change="vm.changeSelection(variant)"
server-validation-field="{{variant.htmlId}}">
-
-
- *
-
-
-
- — {{variant.language.name}}
- *
+
+
+
+ — {{variant.language.name}}
+ *
-
-
+
{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.html
index 8c3bced573..7a49783203 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.html
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/blocklist.html
@@ -1 +1 @@
-
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.controller.js
index b1937e718d..b6be2963d1 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.blockconfiguration.overlay.controller.js
@@ -147,7 +147,7 @@
vm.addViewForBlock = function(block) {
- localizationService.localize("blockEditor_headlineSelectView").then(function(localizedTitle) {
+ localizationService.localize("blockEditor_headlineAddCustomView").then(function(localizedTitle) {
const filePicker = {
title: localizedTitle,
@@ -160,7 +160,7 @@
},
select: function (node) {
const filepath = decodeURIComponent(node.id.replace(/\+/g, " "));
- block.view = filepath;
+ block.view = "~/" + filepath;
editorService.close();
},
close: function () {
@@ -206,7 +206,7 @@
},
select: function (node) {
const filepath = decodeURIComponent(node.id.replace(/\+/g, " "));
- block.stylesheet = filepath;
+ block.stylesheet = "~/" + filepath;
editorService.close();
},
close: function () {
@@ -252,7 +252,8 @@
return !(i.name.indexOf(".jpg") !== -1 || i.name.indexOf(".jpeg") !== -1 || i.name.indexOf(".png") !== -1 || i.name.indexOf(".svg") !== -1 || i.name.indexOf(".webp") !== -1 || i.name.indexOf(".gif") !== -1);
},
select: function (file) {
- block.thumbnail = file.name;
+ const id = decodeURIComponent(file.id.replace(/\+/g, " "));
+ block.thumbnail = "~/" + id;
editorService.close();
},
close: function () {
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js
index 0f6d4d2bb0..489c1353ff 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbBlockListPropertyEditor.component.js
@@ -233,8 +233,7 @@
ensureCultureData(block.content);
ensureCultureData(block.settings);
- // TODO: Why is there a '/' prefixed? that means this will never work with virtual directories
- block.view = (block.config.view ? "/" + block.config.view : getDefaultViewForBlock(block));
+ block.view = (block.config.view ? block.config.view : getDefaultViewForBlock(block));
block.showValidation = block.config.view ? true : false;
block.hideContentInOverlay = block.config.forceHideContentEditorInOverlay === true || inlineEditing === true;
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbblocklistblock.component.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbblocklistblock.component.js
index 4474dbd55c..206fb0bb3a 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbblocklistblock.component.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/umbblocklistblock.component.js
@@ -5,11 +5,11 @@
* @ngdoc directive
* @name umbraco.directives.directive:umbBlockListBlock
* @description
- * The component to render the view for a block.
+ * The component to render the view for a block.
* If a stylesheet is used then this uses a ShadowDom to make a scoped element.
* This way the backoffice styling does not collide with the block style.
*/
-
+
angular
.module("umbraco")
.component("umbBlockListBlock", {
@@ -29,16 +29,16 @@
}
);
- function BlockListBlockController($scope, $compile, $element) {
+ function BlockListBlockController($scope, $compile, $element, umbRequestHelper) {
var model = this;
model.$onInit = function () {
- // This is ugly and is only necessary because we are not using components and instead
+ // This is ugly and is only necessary because we are not using components and instead
// relying on ng-include. It is definitely possible to compile the contents
- // of the view into the DOM using $templateCache and $http instead of using
- // ng - include which means that the controllerAs flows directly to the view.
- // This would mean that any custom components would need to be updated instead of relying on $scope.
- // Guess we'll leave it for now but means all things need to be copied to the $scope and then all
+ // of the view into the DOM using $templateCache and $http instead of using
+ // ng - include which means that the controllerAs flows directly to the view.
+ // This would mean that any custom components would need to be updated instead of relying on $scope.
+ // Guess we'll leave it for now but means all things need to be copied to the $scope and then all
// primitives need to be watched.
$scope.block = model.block;
@@ -48,8 +48,6 @@
$scope.valFormManager = model.valFormManager;
if (model.stylesheet) {
- // TODO: Not sure why this needs a prefixed /? this means it will never work in a virtual directory
- model.stylesheet = "/" + model.stylesheet;
var shadowRoot = $element[0].attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `