diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbtree.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbtree.directive.js
index 15fa9ef5dc..00fa4e57e7 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/umbtree.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbtree.directive.js
@@ -70,7 +70,7 @@ angular.module("umbraco.directives")
if (scope.eventhandler) {
scope.eventhandler.clearCache = function(section){
- treeService.clearCache(section);
+ treeService.clearCache({ section: section });
};
scope.eventhandler.load = function(section){
@@ -110,7 +110,7 @@ angular.module("umbraco.directives")
enableDeleteAnimations = false;
//use $q.when because a promise OR raw data might be returned.
- $q.when(treeService.getTree({ section: scope.section, tree: scope.treealias, cachekey: scope.cachekey, isDialog: scope.isdialog ? scope.isdialog : false }))
+ treeService.getTree({ section: scope.section, tree: scope.treealias, cacheKey: scope.cachekey, isDialog: scope.isdialog ? scope.isdialog : false })
.then(function (data) {
//set the data once we have it
scope.tree = data;
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
index f8b0c8fef6..adef8a100c 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
@@ -288,7 +288,7 @@ angular.module('umbraco.services')
reloadSection: function (sectionAlias) {
if(this.ui.treeEventHandler){
- this.ui.treeEventHandler.clearCache(sectionAlias);
+ this.ui.treeEventHandler.clearCache({ section: sectionAlias });
this.ui.treeEventHandler.load(sectionAlias);
}
},
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js
index 8d294126bf..7288c570ec 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js
@@ -15,14 +15,12 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc
var standardCssClass = 'icon umb-tree-icon sprTree';
function getCacheKey(args) {
- if (!args) {
- args = {
- section: 'content',
- cacheKey: ''
- };
- }
+ //if there is no cache key they return null - it won't be cached.
+ if (!args || !args.cacheKey) {
+ return null;
+ }
- var cacheKey = args.cachekey;
+ var cacheKey = args.cacheKey;
cacheKey += "_" + args.section;
return cacheKey;
}
@@ -103,15 +101,35 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc
return undefined;
},
- /** clears the tree cache - with optional sectionAlias */
- clearCache: function(sectionAlias) {
- if (!sectionAlias) {
+ /** clears the tree cache - with optional cacheKey and optional section */
+ clearCache: function (args) {
+ //clear all if not specified
+ if (!args) {
treeCache = {};
}
else {
- var cacheKey = getCacheKey({ section: sectionAlias });
- if (treeCache && treeCache[cacheKey] != null) {
- treeCache = _.omit(treeCache, cacheKey);
+ //if section and cache key specified just clear that cache
+ if (args.section && args.cacheKey) {
+ var cacheKey = getCacheKey(args);
+ if (cacheKey && treeCache && treeCache[cacheKey] != null) {
+ treeCache = _.omit(treeCache, cacheKey);
+ }
+ }
+ else if (args.cacheKey) {
+ //if only the cache key is specified, then clear all cache starting with that key
+ var allKeys1 = _.keys(treeCache);
+ var toRemove1 = _.filter(allKeys1, function (k) {
+ return k.startsWith(args.cacheKey + "_");
+ });
+ treeCache = _.omit(treeCache, toRemove1);
+ }
+ else if (args.section) {
+ //if only the section is specified then clear all cache regardless of cache key by that section
+ var allKeys2 = _.keys(treeCache);
+ var toRemove2 = _.filter(allKeys2, function (k) {
+ return k.endsWith("_" + args.section);
+ });
+ treeCache = _.omit(treeCache, toRemove2);
}
}
},
@@ -240,25 +258,28 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc
return "";
},
+ /** gets the tree, returns a promise */
getTree: function (args) {
+ var deferred = $q.defer();
+
//set defaults
if (!args) {
- args = {
- section: 'content',
- cacheKey : ''
- };
+ args = { section: 'content', cacheKey: null };
+ }
+ else if (!args.section) {
+ args.section = 'content';
}
var cacheKey = getCacheKey(args);
//return the cache if it exists
- if (treeCache[cacheKey] !== undefined){
- return treeCache[cacheKey];
+ if (cacheKey && treeCache[cacheKey] !== undefined) {
+ deferred.resolve(treeCache[cacheKey]);
}
var self = this;
- return treeResource.loadApplication(args)
+ treeResource.loadApplication(args)
.then(function(data) {
//this will be called once the tree app data has loaded
var result = {
@@ -268,13 +289,19 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc
};
//we need to format/modify some of the node data to be used in our app.
self._formatNodeDataForUseInUI(result.root, result.root.children, args.section);
- //cache this result
- //TODO: We'll need to un-cache this in many circumstances
- treeCache[cacheKey] = result;
- //return the data result as promised
- //deferred.resolve(treeArray[cacheKey]);
- return treeCache[cacheKey];
+
+ //cache this result if a cache key is specified - generally a cache key should ONLY
+ // be specified for application trees, dialog trees should not be cached.
+ if (cacheKey) {
+ treeCache[cacheKey] = result;
+ deferred.resolve(treeCache[cacheKey]);
+ }
+
+ //return un-cached
+ deferred.resolve(result);
});
+
+ return deferred.promise;
},
getMenu: function (args) {
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.html
index 3da0a7e320..7890421360 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.html
+++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.html
@@ -38,7 +38,6 @@
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/move.html b/src/Umbraco.Web.UI.Client/src/views/content/move.html
index 2a288bcde8..5456118374 100644
--- a/src/Umbraco.Web.UI.Client/src/views/content/move.html
+++ b/src/Umbraco.Web.UI.Client/src/views/content/move.html
@@ -21,9 +21,9 @@
diff --git a/src/Umbraco.Web.UI.Client/src/views/directives/umb-navigation.html b/src/Umbraco.Web.UI.Client/src/views/directives/umb-navigation.html
index 714ef5b4dc..54baf2ba95 100644
--- a/src/Umbraco.Web.UI.Client/src/views/directives/umb-navigation.html
+++ b/src/Umbraco.Web.UI.Client/src/views/directives/umb-navigation.html
@@ -63,6 +63,7 @@
diff --git a/src/Umbraco.Web.UI.Client/test/unit/common/services/tree-service.spec.js b/src/Umbraco.Web.UI.Client/test/unit/common/services/tree-service.spec.js
index a4757a8ae4..cd79092385 100644
--- a/src/Umbraco.Web.UI.Client/test/unit/common/services/tree-service.spec.js
+++ b/src/Umbraco.Web.UI.Client/test/unit/common/services/tree-service.spec.js
@@ -1,5 +1,5 @@
describe('tree service tests', function () {
- var treeService;
+ var treeService, $rootScope, $httpBackend, mocks;
function getContentTree() {
@@ -37,66 +37,183 @@ describe('tree service tests', function () {
}
beforeEach(module('umbraco.services'));
+ beforeEach(module('umbraco.resources'));
+ beforeEach(module('umbraco.mocks'));
- beforeEach(inject(function ($injector) {
+ beforeEach(inject(function ($injector, mocksUtils) {
+
+ //for these tests we don't want any authorization to occur
+ mocksUtils.disableAuth();
+
+ $rootScope = $injector.get('$rootScope');
+ $httpBackend = $injector.get('$httpBackend');
+ mocks = $injector.get("treeMocks");
+ mocks.register();
treeService = $injector.get('treeService');
}));
describe('tree cache', function () {
- it('tree with no args caches as content', function () {
- treeService.getTree().then(function(data) {
+ //it('tree with section but no cache key does not cache', function () {
+ // treeService.getTree().then(function (data) {
- var cache = treeService._getTreeCache();
- expect(cache).toBeDefined();
- expect(cache["_content"]).toBeDefined();
+ // var cache = treeService._getTreeCache();
+ // expect(cache).toBeDefined();
+ // expect(cache["_content"]).toBeDefined();
- });
- });
-
- it('tree caches by section', function () {
- treeService.getTree({section: "media"}).then(function (data) {
+ // });
+ //});
- var cache = treeService._getTreeCache();
- expect(cache).toBeDefined();
- expect(cache["_media"]).toBeDefined();
+ it('does not cache with no args', function () {
- });
- });
-
- it('removes cache by section', function () {
- treeService.getTree({ section: "media" }).then(function (data) {
-
- var cache = treeService._getTreeCache();
- expect(cache["_media"]).toBeDefined();
- expect(_.keys(cache).length).toBe(1);
-
- treeService.clearCache("media");
-
+ var cache;
+ treeService.getTree().then(function (data) {
cache = treeService._getTreeCache();
- expect(cache["_media"]).not.toBeDefined();
- expect(_.keys(cache).length).toBe(0);
});
+
+ $rootScope.$digest();
+ $httpBackend.flush();
+
+ expect(_.keys(cache).length).toBe(0);
+ });
+
+ it('does not cache with no cacheKey', function () {
+ var cache;
+ treeService.getTree({section: "content"}).then(function (data) {
+ cache = treeService._getTreeCache();
+
+ });
+
+ $rootScope.$digest();
+ $httpBackend.flush();
+
+ expect(_.keys(cache).length).toBe(0);
+ });
+
+ it('caches by section with cache key', function () {
+ var cache;
+ treeService.getTree({ section: "media", cacheKey: "_" }).then(function (data) {
+ cache = treeService._getTreeCache();
+ });
+
+ $rootScope.$digest();
+ $httpBackend.flush();
+
+ expect(cache["__media"]).toBeDefined();
+ });
+
+ it('caches by default content section with cache key', function () {
+ var cache;
+ treeService.getTree({ cacheKey: "_" }).then(function (data) {
+ cache = treeService._getTreeCache();
+ });
+
+ $rootScope.$digest();
+ $httpBackend.flush();
+
+ expect(cache).toBeDefined();
+ expect(cache["__content"]).toBeDefined();
+ });
+
+ it('removes by section with cache key', function () {
+ var cache;
+ treeService.getTree({ section: "media", cacheKey: "_" }).then(function (data) {
+ treeService.getTree({ section: "content", cacheKey: "_" }).then(function (d) {
+ cache = treeService._getTreeCache();
+ });
+ });
+
+ $rootScope.$digest();
+ $httpBackend.flush();
+
+ expect(cache["__media"]).toBeDefined();
+ expect(_.keys(cache).length).toBe(2);
+
+ treeService.clearCache({ section: "media", cacheKey: "_" });
+ cache = treeService._getTreeCache();
+
+ expect(cache["__media"]).not.toBeDefined();
+ expect(_.keys(cache).length).toBe(1);
+
+ });
+
+ it('removes cache by key regardless of section', function () {
+ var cache;
+
+ treeService.getTree({ section: "media", cacheKey: "_" }).then(function (data) {
+ treeService.getTree({ section: "content", cacheKey: "_" }).then(function (d) {
+ treeService.getTree({ section: "content", cacheKey: "anotherkey" }).then(function (dd) {
+ cache = treeService._getTreeCache();
+ });
+ });
+ });
+
+ $rootScope.$digest();
+ $httpBackend.flush();
+
+ expect(cache["__media"]).toBeDefined();
+ expect(cache["__content"]).toBeDefined();
+ expect(_.keys(cache).length).toBe(3);
+
+ treeService.clearCache({ cacheKey: "_" });
+
+ cache = treeService._getTreeCache();
+ expect(cache["__media"]).not.toBeDefined();
+ expect(cache["__content"]).not.toBeDefined();
+ expect(_.keys(cache).length).toBe(1);
+ });
+
+ it('removes all section cache regardless of key', function () {
+
+ var cache;
+
+ treeService.getTree({ section: "media", cacheKey: "_" }).then(function (data) {
+ treeService.getTree({ section: "media", cacheKey: "anotherkey" }).then(function (d) {
+ treeService.getTree({ section: "content", cacheKey: "anotherkey" }).then(function (dd) {
+ cache = treeService._getTreeCache();
+ });
+ });
+ });
+
+ $rootScope.$digest();
+ $httpBackend.flush();
+
+ expect(cache["anotherkey_media"]).toBeDefined();
+ expect(cache["__media"]).toBeDefined();
+ expect(_.keys(cache).length).toBe(3);
+
+ treeService.clearCache({ section: "media" });
+
+ cache = treeService._getTreeCache();
+ expect(cache["anotherkey_media"]).not.toBeDefined();
+ expect(cache["__media"]).not.toBeDefined();
+ expect(_.keys(cache).length).toBe(1);
});
it('removes all cache', function () {
- treeService.getTree({ section: "media" }).then(function (data) {
- treeService.getTree({ section: "content" }).then(function (d) {
+ var cache;
- var cache = treeService._getTreeCache();
- expect(cache["_content"]).toBeDefined();
- expect(cache["_media"]).toBeDefined();
- expect(_.keys(cache).length).toBe(2);
-
- treeService.clearCache();
-
- cache = treeService._getTreeCache();
- expect(cache["_content"]).toBeDefined();
- expect(cache["_media"]).toBeDefined();
- expect(_.keys(cache).length).toBe(0);
+ treeService.getTree({ section: "media", cacheKey: "_" }).then(function (data) {
+ treeService.getTree({ section: "media", cacheKey: "anotherkey" }).then(function (d) {
+ treeService.getTree({ section: "content", cacheKey: "anotherkey" }).then(function(dd) {
+ cache = treeService._getTreeCache();
+ });
});
});
+
+ $rootScope.$digest();
+ $httpBackend.flush();
+
+ expect(cache["anotherkey_media"]).toBeDefined();
+ expect(cache["__media"]).toBeDefined();
+ expect(cache["anotherkey_content"]).toBeDefined();
+ expect(_.keys(cache).length).toBe(3);
+
+ treeService.clearCache();
+
+ cache = treeService._getTreeCache();
+ expect(_.keys(cache).length).toBe(0);
});
});