Fix to ensure we use virtual paths for any blocks with custom views (#8597)
Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com> Co-authored-by: Shannon <sdeminick@gmail.com>
This commit is contained in:
@@ -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.<br/><i>" + result.errorMsg + "</i>");
|
||||
}
|
||||
|
||||
@@ -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.<br/><i>" + response.data.ExceptionMessage + "</i>");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
@@ -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,7 @@
|
||||
$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;
|
||||
model.stylesheet = umbRequestHelper.convertVirtualToAbsolutePath(model.stylesheet);
|
||||
var shadowRoot = $element[0].attachShadow({ mode: 'open' });
|
||||
shadowRoot.innerHTML = `
|
||||
<style>
|
||||
@@ -60,7 +59,7 @@
|
||||
$compile(shadowRoot)($scope);
|
||||
}
|
||||
else {
|
||||
$element.append($compile('<div ng-include="model.view"></div>')($scope));
|
||||
$element.append($compile('<div ng-include="model.view"></div>')($scope));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -71,6 +70,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
})();
|
||||
|
||||
@@ -6,6 +6,13 @@ describe('umbRequestHelper tests', function () {
|
||||
|
||||
beforeEach(inject(function ($injector) {
|
||||
umbRequestHelper = $injector.get('umbRequestHelper');
|
||||
|
||||
// set the Umbraco.Sys.ServerVariables.application.applicationPath
|
||||
if (!Umbraco) Umbraco = {};
|
||||
if (!Umbraco.Sys) Umbraco.Sys = {};
|
||||
if (!Umbraco.Sys.ServerVariables) Umbraco.Sys.ServerVariables = {};
|
||||
if (!Umbraco.Sys.ServerVariables.application) Umbraco.Sys.ServerVariables.application = {};
|
||||
Umbraco.Sys.ServerVariables.application.applicationPath = "/mysite/";
|
||||
}));
|
||||
|
||||
describe('formatting Urls', function () {
|
||||
@@ -34,4 +41,25 @@ describe('umbRequestHelper tests', function () {
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('Virtual Paths', function () {
|
||||
|
||||
it('can convert virtual path to absolute url', function () {
|
||||
var result = umbRequestHelper.convertVirtualToAbsolutePath("~/App_Plugins/hello/world.css");
|
||||
expect(result).toBe("/mysite/App_Plugins/hello/world.css");
|
||||
});
|
||||
|
||||
it('can convert absolute path to absolute url', function () {
|
||||
var result = umbRequestHelper.convertVirtualToAbsolutePath("/App_Plugins/hello/world.css");
|
||||
expect(result).toBe("/App_Plugins/hello/world.css");
|
||||
});
|
||||
|
||||
it('throws on invalid virtual path', function () {
|
||||
var relativePath = "App_Plugins/hello/world.css";
|
||||
expect(function () {
|
||||
umbRequestHelper.convertVirtualToAbsolutePath(relativePath);
|
||||
}).toThrow("The path " + relativePath + " is not a virtual path");
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user