OK, finally got the query string problem resolved

This commit is contained in:
Shannon
2018-05-04 13:17:56 +10:00
parent 912711bfa0
commit 506365b8ff
8 changed files with 214 additions and 507 deletions

View File

@@ -1,10 +1,10 @@
angular.module('umbraco.security.interceptor')
// This http interceptor listens for authentication successes and failures
.factory('securityInterceptor', ['$injector', 'securityRetryQueue', 'notificationsService', 'eventsService', 'requestInterceptorFilter', function ($injector, queue, notifications, eventsService, requestInterceptorFilter) {
return function(promise) {
return function (promise) {
return promise.then(
function(originalResponse) {
function (originalResponse) {
// Intercept successful requests
//Here we'll check if our custom header is in the response which indicates how many seconds the user's session has before it
@@ -23,12 +23,12 @@ angular.module('umbraco.security.interceptor')
}
return promise;
}, function(originalResponse) {
}, function (originalResponse) {
// Intercept failed requests
// Make sure we have the configuration of the request (don't we always?)
var config = originalResponse.config ? originalResponse.config : {};
// Make sure we have an object for the headers of the request
var headers = config.headers ? config.headers : {};
@@ -37,7 +37,7 @@ angular.module('umbraco.security.interceptor')
//exit/ignore
return promise;
}
var filtered = _.find(requestInterceptorFilter(), function(val) {
var filtered = _.find(requestInterceptorFilter(), function (val) {
return config.url.indexOf(val) > 0;
});
if (filtered) {
@@ -47,18 +47,18 @@ angular.module('umbraco.security.interceptor')
//A 401 means that the user is not logged in
if (originalResponse.status === 401 && !originalResponse.config.url.endsWith("umbraco/backoffice/UmbracoApi/Authentication/GetCurrentUser")) {
var userService = $injector.get('userService'); // see above
var userService = $injector.get('userService'); // see above
//Associate the user name with the retry to ensure we retry for the right user
promise = userService.getCurrentUser()
.then(function (user) {
var userName = user ? user.name : null;
//The request bounced because it was not authorized - add a new request to the retry queue
return queue.pushRetryFn('unauthorized-server', userName, function retryRequest() {
// We must use $injector to get the $http service to prevent circular dependency
return $injector.get('$http')(originalResponse.config);
});
});
//Associate the user name with the retry to ensure we retry for the right user
promise = userService.getCurrentUser()
.then(function (user) {
var userName = user ? user.name : null;
//The request bounced because it was not authorized - add a new request to the retry queue
return queue.pushRetryFn('unauthorized-server', userName, function retryRequest() {
// We must use $injector to get the $http service to prevent circular dependency
return $injector.get('$http')(originalResponse.config);
});
});
}
else if (originalResponse.status === 404) {
@@ -103,18 +103,19 @@ angular.module('umbraco.security.interceptor')
};
}])
//used to set headers on all requests where necessary
.factory('umbracoRequestInterceptor', function ($q, queryStrings) {
return {
//dealing with requests:
'request': function(config) {
if (queryStrings.getParams().umbDebug === "true" || queryStrings.getParams().umbdebug === "true") {
config.headers["X-UMB-DEBUG"] = "true";
}
return config;
}
};
.factory('umbracoRequestInterceptor', function ($q, urlHelper) {
return {
//dealing with requests:
'request': function (config) {
var queryStrings = urlHelper.getQueryStringParams();
if (queryStrings.umbDebug === "true" || queryStrings.umbdebug === "true") {
config.headers["X-UMB-DEBUG"] = "true";
}
return config;
}
};
})
.value('requestInterceptorFilter', function() {
.value('requestInterceptorFilter', function () {
return ["www.gravatar.com"];
})

View File

@@ -15,7 +15,7 @@
* Section navigation and search, and maintain their state for the entire application lifetime
*
*/
function navigationService($rootScope, $routeParams, $log, $location, $q, $timeout, $injector, eventsService, dialogService, umbModelMapper, treeService, notificationsService, historyService, appState, angularHelper) {
function navigationService($rootScope, $route, $routeParams, $log, $location, $q, $timeout, $injector, urlHelper, eventsService, dialogService, umbModelMapper, treeService, notificationsService, historyService, appState, angularHelper) {
//the promise that will be resolved when the navigation is ready
var navReadyPromise = $q.defer();
@@ -28,6 +28,7 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
navReadyPromise.resolve(mainTreeApi);
});
//used to track the current dialog object
var currentDialog = null;
@@ -104,25 +105,6 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
return navReadyPromise.promise;
},
/**
* @ngdoc method
* @name umbraco.services.navigationService#setMainCulture
* @methodOf umbraco.services.navigationService
*
* @description
* Utility to set the mculture query string without changing the route. This is a hack to work around angular's limitations
*/
setMainCulture: function (culture) {
$location.search("mculture", culture);
//fixme: This can work but interferes with our other $locationChangeStart
//var un = $rootScope.$on('$locationChangeStart', function (event) {
// event.preventDefault();
// un();
//});
},
/**
* @ngdoc method
* @name umbraco.services.navigationService#clearSearch
@@ -132,10 +114,10 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
* utility to clear the querystring/search params while maintaining a known list of parameters that should be maintained throughout the app
*/
clearSearch: function () {
var retainKeys = ["mculture"];
var toRetain = ["mculture"];
var currentSearch = $location.search();
$location.search('');
_.each(retainKeys, function (k) {
_.each(toRetain, function (k) {
if (currentSearch[k]) {
$location.search(k, currentSearch[k]);
}

View File

@@ -0,0 +1,108 @@
/**
* @ngdoc service
* @name umbraco.services.urlHelper
* @description A helper used to work with URLs
**/
(function () {
"use strict";
function urlHelper($window) {
var pl = /\+/g; // Regex for replacing addition symbol with a space
var search = /([^&=]+)=?([^&]*)/g;
var decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); };
//Used for browsers that don't support $window.URL
function polyFillUrl(url) {
var parser = document.createElement('a');
// Let the browser do the work
parser.href = url;
return {
protocol: parser.protocol,
host: parser.host,
hostname: parser.hostname,
port: parser.port,
pathname: parser.pathname,
search: parser.search,
hash: parser.hash
};
}
return {
/**
* @ngdoc function
* @name parseUrl
* @methodOf umbraco.services.urlHelper
* @function
*
* @description
* Returns an object representing each part of the url
*
* @param {string} url the url string to parse
*/
parseUrl: function (url) {
//create a URL object based on either the native URL method or the polyfill method
var urlObj = $window.URL ? new $window.URL(url) : polyFillUrl(url);
//append the searchObject
urlObj.searchObject = this.getQueryStringParams(urlObj.search);
return urlObj;
},
/**
* @ngdoc function
* @name parseHashIntoUrl
* @methodOf umbraco.services.urlHelper
* @function
*
* @description
* If the hash of a URL contains a path + query strings, this will parse the hash into a url object
*
* @param {string} url the url string to parse
*/
parseHashIntoUrl: function (url) {
var urlObj = this.parseUrl(url);
if (!urlObj.hash) {
throw new "No hash found in url: " + url;
}
if (!urlObj.hash.startsWith("#/")) {
throw new "The hash in url does not contain a path to parse: " + url;
}
//now create a fake full URL with the hash
var fakeUrl = "http://fakeurl.com" + urlObj.hash.trimStart("#");
var fakeUrlObj = this.parseUrl(fakeUrl);
return fakeUrlObj;
},
/**
* @ngdoc function
* @name getQueryStringParams
* @methodOf umbraco.services.urlHelper
* @function
*
* @description
* Returns a dictionary of query string key/vals
*
* @param {string} location optional URL to parse, the default will use $window.location
*/
getQueryStringParams: function (location) {
var match;
//use the current location if none specified
var query = location ? location.substring(1) : $window.location.search.substring(1);
var urlParams = {};
while (match = search.exec(query)) {
urlParams[decode(match[1])] = decode(match[2]);
}
return urlParams;
}
};
}
angular.module('umbraco.services').factory('urlHelper', urlHelper);
})();

View File

@@ -141,307 +141,6 @@ function packageHelper(assetsService, treeService, eventsService, $templateCache
}
angular.module('umbraco.services').factory('packageHelper', packageHelper);
//TODO: I believe this is obsolete
function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, mediaHelper, umbRequestHelper) {
return {
/** sets the image's url, thumbnail and if its a folder */
setImageData: function (img) {
img.isFolder = !mediaHelper.hasFilePropertyType(img);
if (!img.isFolder) {
img.thumbnail = mediaHelper.resolveFile(img, true);
img.image = mediaHelper.resolveFile(img, false);
}
},
/** sets the images original size properties - will check if it is a folder and if so will just make it square */
setOriginalSize: function (img, maxHeight) {
//set to a square by default
img.originalWidth = maxHeight;
img.originalHeight = maxHeight;
var widthProp = _.find(img.properties, function (v) { return (v.alias === "umbracoWidth"); });
if (widthProp && widthProp.value) {
img.originalWidth = parseInt(widthProp.value, 10);
if (isNaN(img.originalWidth)) {
img.originalWidth = maxHeight;
}
}
var heightProp = _.find(img.properties, function (v) { return (v.alias === "umbracoHeight"); });
if (heightProp && heightProp.value) {
img.originalHeight = parseInt(heightProp.value, 10);
if (isNaN(img.originalHeight)) {
img.originalHeight = maxHeight;
}
}
},
/** sets the image style which get's used in the angular markup */
setImageStyle: function (img, width, height, rightMargin, bottomMargin) {
img.style = { width: width + "px", height: height + "px", "margin-right": rightMargin + "px", "margin-bottom": bottomMargin + "px" };
img.thumbStyle = {
"background-image": "url('" + img.thumbnail + "')",
"background-repeat": "no-repeat",
"background-position": "center",
"background-size": Math.min(width, img.originalWidth) + "px " + Math.min(height, img.originalHeight) + "px"
};
},
/** gets the image's scaled wdith based on the max row height */
getScaledWidth: function (img, maxHeight) {
var scaled = img.originalWidth * maxHeight / img.originalHeight;
return scaled;
//round down, we don't want it too big even by half a pixel otherwise it'll drop to the next row
//return Math.floor(scaled);
},
/** returns the target row width taking into account how many images will be in the row and removing what the margin is */
getTargetWidth: function (imgsPerRow, maxRowWidth, margin) {
//take into account the margin, we will have 1 less margin item than we have total images
return (maxRowWidth - ((imgsPerRow - 1) * margin));
},
/**
This will determine the row/image height for the next collection of images which takes into account the
ideal image count per row. It will check if a row can be filled with this ideal count and if not - if there
are additional images available to fill the row it will keep calculating until they fit.
It will return the calculated height and the number of images for the row.
targetHeight = optional;
*/
getRowHeightForImages: function (imgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin, targetHeight) {
var idealImages = imgs.slice(0, idealImgPerRow);
//get the target row width without margin
var targetRowWidth = this.getTargetWidth(idealImages.length, maxRowWidth, margin);
//this gets the image with the smallest height which equals the maximum we can scale up for this image block
var maxScaleableHeight = this.getMaxScaleableHeight(idealImages, maxRowHeight);
//if the max scale height is smaller than the min display height, we'll use the min display height
targetHeight = targetHeight !== undefined ? targetHeight : Math.max(maxScaleableHeight, minDisplayHeight);
var attemptedRowHeight = this.performGetRowHeight(idealImages, targetRowWidth, minDisplayHeight, targetHeight);
if (attemptedRowHeight != null) {
//if this is smaller than the min display then we need to use the min display,
// which means we'll need to remove one from the row so we can scale up to fill the row
if (attemptedRowHeight < minDisplayHeight) {
if (idealImages.length > 1) {
//we'll generate a new targetHeight that is halfway between the max and the current and recurse, passing in a new targetHeight
targetHeight += Math.floor((maxRowHeight - targetHeight) / 2);
return this.getRowHeightForImages(imgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow - 1, margin, targetHeight);
}
else {
//this will occur when we only have one image remaining in the row but it's still going to be too wide even when
// using the minimum display height specified. In this case we're going to have to just crop the image in it's center
// using the minimum display height and the full row width
return { height: minDisplayHeight, imgCount: 1 };
}
}
else {
//success!
return { height: attemptedRowHeight, imgCount: idealImages.length };
}
}
//we know the width will fit in a row, but we now need to figure out if we can fill
// the entire row in the case that we have more images remaining than the idealImgPerRow.
if (idealImages.length === imgs.length) {
//we have no more remaining images to fill the space, so we'll just use the calc height
return { height: targetHeight, imgCount: idealImages.length };
}
else if (idealImages.length === 1) {
//this will occur when we only have one image remaining in the row to process but it's not really going to fit ideally
// in the row.
return { height: minDisplayHeight, imgCount: 1 };
}
else if (idealImages.length === idealImgPerRow && targetHeight < maxRowHeight) {
//if we're already dealing with the ideal images per row and it's not quite wide enough, we can scale up a little bit so
// long as the targetHeight is currently less than the maxRowHeight. The scale up will be half-way between our current
// target height and the maxRowHeight (we won't loop forever though - if there's a difference of 5 px we'll just quit)
while (targetHeight < maxRowHeight && (maxRowHeight - targetHeight) > 5) {
targetHeight += Math.floor((maxRowHeight - targetHeight) / 2);
attemptedRowHeight = this.performGetRowHeight(idealImages, targetRowWidth, minDisplayHeight, targetHeight);
if (attemptedRowHeight != null) {
//success!
return { height: attemptedRowHeight, imgCount: idealImages.length };
}
}
//Ok, we couldn't actually scale it up with the ideal row count we'll just recurse with a lesser image count.
return this.getRowHeightForImages(imgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow - 1, margin);
}
else if (targetHeight === maxRowHeight) {
//This is going to happen when:
// * We can fit a list of images in a row, but they come up too short (based on minDisplayHeight)
// * Then we'll try to remove an image, but when we try to scale to fit, the width comes up too narrow but the images are already at their
// maximum height (maxRowHeight)
// * So we're stuck, we cannot precicely fit the current list of images, so we'll render a row that will be max height but won't be wide enough
// which is better than rendering a row that is shorter than the minimum since that could be quite small.
return { height: targetHeight, imgCount: idealImages.length };
}
else {
//we have additional images so we'll recurse and add 1 to the idealImgPerRow until it fits
return this.getRowHeightForImages(imgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow + 1, margin);
}
},
performGetRowHeight: function (idealImages, targetRowWidth, minDisplayHeight, targetHeight) {
var currRowWidth = 0;
for (var i = 0; i < idealImages.length; i++) {
var scaledW = this.getScaledWidth(idealImages[i], targetHeight);
currRowWidth += scaledW;
}
if (currRowWidth > targetRowWidth) {
//get the new scaled height to fit
var newHeight = targetRowWidth * targetHeight / currRowWidth;
return newHeight;
}
else if (idealImages.length === 1 && (currRowWidth <= targetRowWidth) && !idealImages[0].isFolder) {
//if there is only one image, then return the target height
return targetHeight;
}
else if (currRowWidth / targetRowWidth > 0.90) {
//it's close enough, it's at least 90% of the width so we'll accept it with the target height
return targetHeight;
}
else {
//if it's not successful, return null
return null;
}
},
/** builds an image grid row */
buildRow: function (imgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin, totalRemaining) {
var currRowWidth = 0;
var row = { images: [] };
var imageRowHeight = this.getRowHeightForImages(imgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin);
var targetWidth = this.getTargetWidth(imageRowHeight.imgCount, maxRowWidth, margin);
var sizes = [];
//loop through the images we know fit into the height
for (var i = 0; i < imageRowHeight.imgCount; i++) {
//get the lower width to ensure it always fits
var scaledWidth = Math.floor(this.getScaledWidth(imgs[i], imageRowHeight.height));
if (currRowWidth + scaledWidth <= targetWidth) {
currRowWidth += scaledWidth;
sizes.push({
width: scaledWidth,
//ensure that the height is rounded
height: Math.round(imageRowHeight.height)
});
row.images.push(imgs[i]);
}
else if (imageRowHeight.imgCount === 1 && row.images.length === 0) {
//the image is simply too wide, we'll crop/center it
sizes.push({
width: maxRowWidth,
//ensure that the height is rounded
height: Math.round(imageRowHeight.height)
});
row.images.push(imgs[i]);
}
else {
//the max width has been reached
break;
}
}
//loop through the images for the row and apply the styles
for (var j = 0; j < row.images.length; j++) {
var bottomMargin = margin;
//make the margin 0 for the last one
if (j === (row.images.length - 1)) {
margin = 0;
}
this.setImageStyle(row.images[j], sizes[j].width, sizes[j].height, margin, bottomMargin);
}
if (row.images.length === 1 && totalRemaining > 1) {
//if there's only one image on the row and there are more images remaining, set the container to max width
row.images[0].style.width = maxRowWidth + "px";
}
return row;
},
/** Returns the maximum image scaling height for the current image collection */
getMaxScaleableHeight: function (imgs, maxRowHeight) {
var smallestHeight = _.min(imgs, function (item) { return item.originalHeight; }).originalHeight;
//adjust the smallestHeight if it is larger than the static max row height
if (smallestHeight > maxRowHeight) {
smallestHeight = maxRowHeight;
}
return smallestHeight;
},
/** Creates the image grid with calculated widths/heights for images to fill the grid nicely */
buildGrid: function (images, maxRowWidth, maxRowHeight, startingIndex, minDisplayHeight, idealImgPerRow, margin, imagesOnly) {
var rows = [];
var imagesProcessed = 0;
//first fill in all of the original image sizes and URLs
for (var i = startingIndex; i < images.length; i++) {
var item = images[i];
this.setImageData(item);
this.setOriginalSize(item, maxRowHeight);
if (imagesOnly && !item.isFolder && !item.thumbnail) {
images.splice(i, 1);
i--;
}
}
while ((imagesProcessed + startingIndex) < images.length) {
//get the maxHeight for the current un-processed images
var currImgs = images.slice(imagesProcessed);
//build the row
var remaining = images.length - imagesProcessed;
var row = this.buildRow(currImgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin, remaining);
if (row.images.length > 0) {
rows.push(row);
imagesProcessed += row.images.length;
}
else {
if (currImgs.length > 0) {
throw "Could not fill grid with all images, images remaining: " + currImgs.length;
}
//if there was nothing processed, exit
break;
}
}
return rows;
}
};
}
angular.module("umbraco.services").factory("umbPhotoFolderHelper", umbPhotoFolderHelper);
/**
* @ngdoc function
* @name umbraco.services.umbModelMapper
@@ -596,34 +295,4 @@ function umbPropEditorHelper() {
}
};
}
angular.module('umbraco.services').factory('umbPropEditorHelper', umbPropEditorHelper);
/**
* @ngdoc service
* @name umbraco.services.queryStrings
* @description A helper used to get query strings in the real URL (not the hash URL)
**/
function queryStrings($window) {
var pl = /\+/g; // Regex for replacing addition symbol with a space
var search = /([^&=]+)=?([^&]*)/g;
var decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); };
return {
getParams: function () {
var match;
var query = $window.location.search.substring(1);
var urlParams = {};
while (match = search.exec(query)) {
urlParams[decode(match[1])] = decode(match[2]);
}
return urlParams;
}
};
}
angular.module('umbraco.services').factory('queryStrings', queryStrings);
angular.module('umbraco.services').factory('umbPropEditorHelper', umbPropEditorHelper);

View File

@@ -334,7 +334,7 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
});
}
if (!currCulture) {
navigationService.setMainCulture(defaultLang ? defaultLang.culture : null);
$location.search("mculture", defaultLang ? defaultLang.culture : null);
}
}
@@ -369,10 +369,8 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
$scope.selectLanguage = function (language) {
navigationService.setMainCulture(language.culture);
//$scope.selectedLanguage = language;
$location.search("mculture", language.culture);
// close the language selector
$scope.page.languageSelectorIsOpen = false;

View File

@@ -1,10 +1,6 @@
/** Executed when the application starts, binds to events and set global state */
app.run(['userService', '$q', '$log', '$rootScope', '$location', 'queryStrings', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache', 'localStorageService', 'tourService', 'dashboardResource',
function (userService, $q, $log, $rootScope, $location, queryStrings, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache, localStorageService, tourService, dashboardResource) {
$rootScope.$on('$locationChangeStart', function (event, next, current, newState, oldState) {
$log.info("location changing to:" + next);
});
app.run(['userService', '$q', '$log', '$rootScope', '$route', '$location', 'urlHelper', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache', 'localStorageService', 'tourService', 'dashboardResource',
function (userService, $q, $log, $rootScope, $route, $location, urlHelper, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache, localStorageService, tourService, dashboardResource) {
//This sets the default jquery ajax headers to include our csrf token, we
// need to user the beforeSend method because our token changes per user/login so
@@ -12,7 +8,8 @@ app.run(['userService', '$q', '$log', '$rootScope', '$location', 'queryStrings',
$.ajaxSetup({
beforeSend: function (xhr) {
xhr.setRequestHeader("X-UMB-XSRF-TOKEN", $cookies["UMB-XSRF-TOKEN"]);
if (queryStrings.getParams().umbDebug === "true" || queryStrings.getParams().umbdebug === "true") {
var queryStrings = urlHelper.getQueryStringParams();
if (queryStrings.umbDebug === "true" || queryStrings.umbdebug === "true") {
xhr.setRequestHeader("X-UMB-DEBUG", "true");
}
}
@@ -45,9 +42,14 @@ app.run(['userService', '$q', '$log', '$rootScope', '$location', 'queryStrings',
returnToPath = null, returnToSearch = null;
}
var currentRoute = null;
var globalQueryStrings = ["mculture"];
/** execute code on each successful route */
$rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
currentRoute = current; //store this so we can reference it in $routeUpdate
var deployConfig = Umbraco.Sys.ServerVariables.deploy;
var deployEnv, deployEnvTitle;
if (deployConfig) {
@@ -92,19 +94,61 @@ app.run(['userService', '$q', '$log', '$rootScope', '$location', 'queryStrings',
/** When the route change is rejected - based on checkAuth - we'll prevent the rejected route from executing including
wiring up it's controller, etc... and then redirect to the rejected URL. */
$rootScope.$on('$routeChangeError', function (event, current, previous, rejection) {
event.preventDefault();
var returnPath = null;
if (rejection.path == "/login" || rejection.path.startsWith("/login/")) {
//Set the current path before redirecting so we know where to redirect back to
returnPath = encodeURIComponent($location.url());
if (rejection.path) {
event.preventDefault();
var returnPath = null;
if (rejection.path == "/login" || rejection.path.startsWith("/login/")) {
//Set the current path before redirecting so we know where to redirect back to
returnPath = encodeURIComponent($location.url());
}
$location.path(rejection.path)
if (returnPath) {
$location.search("returnPath", returnPath);
}
}
$location.path(rejection.path)
if (returnPath) {
$location.search("returnPath", returnPath);
}
});
//Bind to $routeUpdate which will execute anytime a location changes but the route is not triggered.
//This is the case when a route uses reloadOnSearch: false which is the case for many or our routes so that we are able to maintain
//global state query strings without force re-loading views.
//We can then detect if it's a location change that should force a route or not programatically.
$rootScope.$on('$routeUpdate', function (event, next) {
if (!currentRoute) {
//if there is no current route then always route which is done with reload
$route.reload();
}
else {
//check if the location being changed is only the mculture query string, if so, cancel the routing since this is just
//used as a global persistent query string that does not change routes.
var currUrlParts = currentRoute.params;
var nextUrlParts = next.params;
var allowRoute = false;
if (_.keys(currUrlParts).length == _.keys(nextUrlParts).length) { //the number of parts are the same
//check if any route parameter is not the same (excluding our special global query strings), in that case
//we should allow the route.
_.each(currUrlParts, function (value, key) {
if (globalQueryStrings.indexOf(key) === -1) {
if (value.toLowerCase() !== nextUrlParts[key].toLowerCase()) {
allowRoute = true;
}
}
});
}
if (allowRoute) {
//continue the route
$route.reload();
}
}
});
//check for touch device, add to global appState

View File

@@ -1,5 +1,5 @@
app.config(function ($routeProvider) {
/**
* This determines if the route can continue depending on authentication and initialization requirements
* @param {boolean} authRequired If true, it checks if the user is authenticated and will resolve successfully
@@ -126,7 +126,8 @@ app.config(function ($routeProvider) {
$scope.templateUrl = 'views/common/dashboard.html';
}
});
},
},
reloadOnSearch: false,
resolve: canRoute(true)
})
.when('/:section/framed/:url', {
@@ -136,7 +137,8 @@ app.config(function ($routeProvider) {
throw "A framed resource must have a url route parameter";
return 'views/common/legacy.html';
},
},
reloadOnSearch: false,
resolve: canRoute(true)
})
.when('/:section/:tree/:method', {
@@ -147,7 +149,8 @@ app.config(function ($routeProvider) {
return "views/common/dashboard.html";
return ('views/' + rp.tree + '/' + rp.method + '.html');
},
},
reloadOnSearch: false,
resolve: canRoute(true)
})
.when('/:section/:tree/:method/:id', {
@@ -178,7 +181,8 @@ app.config(function ($routeProvider) {
$scope.templateUrl = ('views/' + $routeParams.tree + '/' + $routeParams.method + '.html');
}
},
},
reloadOnSearch: false,
resolve: canRoute(true)
})
.otherwise({ redirectTo: '/login' });

View File

@@ -1,99 +0,0 @@
describe('umbPhotoFolderHelper tests', function () {
var umbPhotoFolderHelper;
beforeEach(module('umbraco.services'));
beforeEach(inject(function ($injector) {
umbPhotoFolderHelper = $injector.get('umbPhotoFolderHelper');
}));
describe('Calculate row', function () {
it('Builds a row by scaling the height to fit the width', function () {
var images = [
{ "properties": [{ "id": 8737, "value": "/media/2173/Save-The-Date.jpg", "alias": "umbracoFile" }, { "id": 8738, "value": "443", "alias": "umbracoWidth" }, { "id": 8739, "value": "500", "alias": "umbracoHeight" }, { "id": 8740, "value": "30830", "alias": "umbracoBytes" }, { "id": 8741, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:56", "createDate": "2013-12-10 14:21:26", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 5, "name": "Save-The-Date.jpg", "id": 1349, "icon": "mediaPhoto.gif", "key": "8eb67ae3-49da-4a25-ab39-185667a9b412", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1349", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1349", "originalWidth": 443, "originalHeight": 500 },
{ "properties": [{ "id": 8742, "value": "/media/2174/IMG_2980.JPG", "alias": "umbracoFile" }, { "id": 8743, "value": "640", "alias": "umbracoWidth" }, { "id": 8744, "value": "480", "alias": "umbracoHeight" }, { "id": 8745, "value": "113311", "alias": "umbracoBytes" }, { "id": 8746, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:51", "createDate": "2013-12-10 14:22:33", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 6, "name": "IMG_2980.JPG", "id": 1350, "icon": "mediaPhoto.gif", "key": "0a9618ea-9b4a-4d34-bf53-e76a0d252048", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1350", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1350", "originalWidth": 640, "originalHeight": 480 },
{ "properties": [{ "id": 8747, "value": "/media/2175/IMG_3023.JPG", "alias": "umbracoFile" }, { "id": 8748, "value": "360", "alias": "umbracoWidth" }, { "id": 8749, "value": "480", "alias": "umbracoHeight" }, { "id": 8750, "value": "106365", "alias": "umbracoBytes" }, { "id": 8751, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:46", "createDate": "2013-12-10 14:39:28", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 7, "name": "IMG_3023.JPG", "id": 1351, "icon": "mediaPhoto.gif", "key": "44cb1ee0-e3d7-40f7-b27c-ae05fb1a8e0c", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1351", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1351", "originalWidth": 360, "originalHeight": 480 },
{ "properties": [{ "id": 8752, "value": "/media/2176/IMG_2055.JPG", "alias": "umbracoFile" }, { "id": 8753, "value": "1024", "alias": "umbracoWidth" }, { "id": 8754, "value": "630", "alias": "umbracoHeight" }, { "id": 8755, "value": "57046", "alias": "umbracoBytes" }, { "id": 8756, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:41", "createDate": "2013-12-10 15:09:47", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 8, "name": "IMG_2055.JPG", "id": 1352, "icon": "mediaPhoto.gif", "key": "8a45465c-251e-44d4-88c5-d86606377105", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1352", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1352", "originalWidth": 1024, "originalHeight": 630 },
{ "properties": [{ "id": 8757, "value": "/media/2177/Signature1.png", "alias": "umbracoFile" }, { "id": 8758, "value": "873", "alias": "umbracoWidth" }, { "id": 8759, "value": "269", "alias": "umbracoHeight" }, { "id": 8760, "value": "105616", "alias": "umbracoBytes" }, { "id": 8761, "value": "png", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:36", "createDate": "2013-12-10 15:11:53", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 9, "name": "Signature1.png", "id": 1353, "icon": "mediaPhoto.gif", "key": "e12d382a-56f8-4b85-b507-b82aa466cd6f", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1353", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1353", "originalWidth": 873, "originalHeight": 269 }
];
var maxRowHeight = 330;
var minDisplayHeight = 100;
var maxRowWidth = 851;
var idealImgPerRow = 5;
var margin = 5;
var result = umbPhotoFolderHelper.buildRow(images, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin);
expect(result.images.length).toBe(5);
});
it('Builds a row by removing an item to scale up to fit', function () {
var images = [
{ "properties": [{ "id": 8737, "value": "/media/2173/Save-The-Date.jpg", "alias": "umbracoFile" }, { "id": 8738, "value": "443", "alias": "umbracoWidth" }, { "id": 8739, "value": "500", "alias": "umbracoHeight" }, { "id": 8740, "value": "30830", "alias": "umbracoBytes" }, { "id": 8741, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:56", "createDate": "2013-12-10 14:21:26", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 5, "name": "Save-The-Date.jpg", "id": 1349, "icon": "mediaPhoto.gif", "key": "8eb67ae3-49da-4a25-ab39-185667a9b412", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1349", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1349", "originalWidth": 443, "originalHeight": 500 },
{ "properties": [{ "id": 8742, "value": "/media/2174/IMG_2980.JPG", "alias": "umbracoFile" }, { "id": 8743, "value": "640", "alias": "umbracoWidth" }, { "id": 8744, "value": "480", "alias": "umbracoHeight" }, { "id": 8745, "value": "113311", "alias": "umbracoBytes" }, { "id": 8746, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:51", "createDate": "2013-12-10 14:22:33", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 6, "name": "IMG_2980.JPG", "id": 1350, "icon": "mediaPhoto.gif", "key": "0a9618ea-9b4a-4d34-bf53-e76a0d252048", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1350", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1350", "originalWidth": 640, "originalHeight": 480 },
{ "properties": [{ "id": 8747, "value": "/media/2175/IMG_3023.JPG", "alias": "umbracoFile" }, { "id": 8748, "value": "360", "alias": "umbracoWidth" }, { "id": 8749, "value": "480", "alias": "umbracoHeight" }, { "id": 8750, "value": "106365", "alias": "umbracoBytes" }, { "id": 8751, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:46", "createDate": "2013-12-10 14:39:28", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 7, "name": "IMG_3023.JPG", "id": 1351, "icon": "mediaPhoto.gif", "key": "44cb1ee0-e3d7-40f7-b27c-ae05fb1a8e0c", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1351", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1351", "originalWidth": 360, "originalHeight": 480 },
{ "properties": [{ "id": 8752, "value": "/media/2176/IMG_2055.JPG", "alias": "umbracoFile" }, { "id": 8753, "value": "1024", "alias": "umbracoWidth" }, { "id": 8754, "value": "630", "alias": "umbracoHeight" }, { "id": 8755, "value": "57046", "alias": "umbracoBytes" }, { "id": 8756, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:41", "createDate": "2013-12-10 15:09:47", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 8, "name": "IMG_2055.JPG", "id": 1352, "icon": "mediaPhoto.gif", "key": "8a45465c-251e-44d4-88c5-d86606377105", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1352", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1352", "originalWidth": 1024, "originalHeight": 630 },
{ "properties": [{ "id": 8757, "value": "/media/2177/Signature1.png", "alias": "umbracoFile" }, { "id": 8758, "value": "873", "alias": "umbracoWidth" }, { "id": 8759, "value": "269", "alias": "umbracoHeight" }, { "id": 8760, "value": "105616", "alias": "umbracoBytes" }, { "id": 8761, "value": "png", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:36", "createDate": "2013-12-10 15:11:53", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 9, "name": "Signature1.png", "id": 1353, "icon": "mediaPhoto.gif", "key": "e12d382a-56f8-4b85-b507-b82aa466cd6f", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1353", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1353", "originalWidth": 873, "originalHeight": 269 }
];
var maxRowHeight = 330;
var minDisplayHeight = 100;
var maxRowWidth = 802;
var idealImgPerRow = 5;
var margin = 5;
var result = umbPhotoFolderHelper.buildRow(images, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin);
expect(result.images.length).toBe(4);
});
it('Builds a row by removing an item to scale up to fit, then attempts to upscale remaining 2 images, but that doesnt fit so drops another and we end up with one', function () {
var images = [
{ "properties": [{ "id": 8737, "value": "/media/2173/Save-The-Date.jpg", "alias": "umbracoFile" }, { "id": 8738, "value": "198", "alias": "umbracoWidth" }, { "id": 8739, "value": "220", "alias": "umbracoHeight" }, { "id": 8740, "value": "30830", "alias": "umbracoBytes" }, { "id": 8741, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:56", "createDate": "2013-12-10 14:21:26", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 5, "name": "Save-The-Date.jpg", "id": 1349, "icon": "mediaPhoto.gif", "key": "8eb67ae3-49da-4a25-ab39-185667a9b412", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1349", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1349", "originalWidth": 198, "originalHeight": 220 },
{ "properties": [{ "id": 8742, "value": "/media/2174/IMG_2980.JPG", "alias": "umbracoFile" }, { "id": 8743, "value": "211", "alias": "umbracoWidth" }, { "id": 8744, "value": "500", "alias": "umbracoHeight" }, { "id": 8745, "value": "113311", "alias": "umbracoBytes" }, { "id": 8746, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:51", "createDate": "2013-12-10 14:22:33", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 6, "name": "IMG_2980.JPG", "id": 1350, "icon": "mediaPhoto.gif", "key": "0a9618ea-9b4a-4d34-bf53-e76a0d252048", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1350", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1350", "originalWidth": 211, "originalHeight": 500 },
{ "properties": [{ "id": 8747, "value": "/media/2175/IMG_3023.JPG", "alias": "umbracoFile" }, { "id": 8748, "value": "940", "alias": "umbracoWidth" }, { "id": 8749, "value": "317", "alias": "umbracoHeight" }, { "id": 8750, "value": "106365", "alias": "umbracoBytes" }, { "id": 8751, "value": "jpg", "alias": "umbracoExtension" }], "updateDate": "2013-12-10 16:57:46", "createDate": "2013-12-10 14:39:28", "published": false, "owner": { "id": 0, "name": "admin" }, "updater": null, "contentTypeAlias": "Image", "sortOrder": 7, "name": "IMG_3023.JPG", "id": 1351, "icon": "mediaPhoto.gif", "key": "44cb1ee0-e3d7-40f7-b27c-ae05fb1a8e0c", "parentId": 1160, "alias": null, "path": "-1,1142,1160,1351", "metaData": {}, "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1351", "originalWidth": 940, "originalHeight": 317 }
];
var maxRowHeight = 250;
var minDisplayHeight = 105;
var maxRowWidth = 400;
var idealImgPerRow = 3;
var margin = 5;
var result = umbPhotoFolderHelper.buildRow(images, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin);
expect(result.images.length).toBe(1);
});
//SEE: http://issues.umbraco.org/issue/U4-5304
it('When a row fits with width but its too short, we remove one and scale up, but that comes up too narrow, so we just render what we have', function () {
var images = [
{ "properties": [{ "value": "/test35.jpg", "alias": "umbracoFile" }, { "value": "1000", "alias": "umbracoWidth" }, { "value": "1041", "alias": "umbracoHeight" }], "contentTypeAlias": "Image", "name": "Test.jpg", "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1349", "originalWidth": 1000, "originalHeight": 1041 },
{ "properties": [{ "value": "/test36.jpg", "alias": "umbracoFile" }, { "value": "1000", "alias": "umbracoWidth" }, { "value": "2013", "alias": "umbracoHeight" }], "contentTypeAlias": "Image", "name": "Test.jpg", "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1349", "originalWidth": 1000, "originalHeight": 2013 },
{ "properties": [{ "value": "/test37.jpg", "alias": "umbracoFile" }, { "value": "840", "alias": "umbracoWidth" }, { "value": "360", "alias": "umbracoHeight" }], "contentTypeAlias": "Image", "name": "Test.jpg", "thumbnail": "/umbraco/UmbracoApi/Images/GetBigThumbnail?mediaId=1349", "originalWidth": 840, "originalHeight": 360 }
];
var maxRowHeight = 250;
var minDisplayHeight = 105;
var maxRowWidth = 400;
var idealImgPerRow = 3;
var margin = 5;
var result = umbPhotoFolderHelper.buildRow(images, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin);
expect(result.images.length).toBe(2);
});
});
});