Fixes tree cache - fixes the unit tests associated with the tree cache so they run properly, tree cache can now be cleared by section, by key, by both or all. There's no longer a default cache key since we don't want to cache things when not needed. ONLY the main trees are now cached, tree pickers and dialog trees should never be cached since tree structures change all of the time (i.e. by other users, changing node names, etc...). The tree-picker directive also had a cache which meant that anyone using that directive would end up with the same cache.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
<div ng-hide="showSearch">
|
||||
<umb-tree
|
||||
section="content"
|
||||
cachekey="contentpickerDialog"
|
||||
showheader="true"
|
||||
showoptions="false"
|
||||
isdialog="true"
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
<umb-tree
|
||||
section="content"
|
||||
cachekey="linkpickerDialog"
|
||||
showheader="true"
|
||||
showoptions="false"
|
||||
eventhandler="dialogTreeEventHandler"
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
<umb-tree
|
||||
section="member"
|
||||
treealias="memberGroup"
|
||||
cachekey="membergrouppickerDialog"
|
||||
showheader="false"
|
||||
showoptions="false"
|
||||
isdialog="true"
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
<umb-tree
|
||||
section="member"
|
||||
treealias="member"
|
||||
cachekey="memberpickerDialog"
|
||||
showheader="false"
|
||||
showoptions="false"
|
||||
isdialog="true"
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
<umb-tree
|
||||
section="{{section}}"
|
||||
treealias="{{treeAlias}}"
|
||||
cachekey="treepickerDialog"
|
||||
showheader="true"
|
||||
showoptions="false"
|
||||
isdialog="true"
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
<div ng-hide="success">
|
||||
<umb-tree
|
||||
section="content"
|
||||
cachekey="copypickerDialog"
|
||||
showheader="true"
|
||||
showoptions="false"
|
||||
isdialog="true"
|
||||
eventhandler="dialogTreeEventHandler">
|
||||
</umb-tree>
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
<div ng-hide="success">
|
||||
<umb-tree
|
||||
section="content"
|
||||
cachekey="movepickerDialog"
|
||||
showheader="true"
|
||||
showoptions="false"
|
||||
isdialog="true"
|
||||
eventhandler="dialogTreeEventHandler">
|
||||
</umb-tree>
|
||||
</div>
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
<!-- the tree -->
|
||||
<div id="tree" class="umb-modalcolumn-body">
|
||||
<umb-tree
|
||||
cachekey="_"
|
||||
eventhandler="treeEventHandler"
|
||||
path="{{nav.ui.currentPath}}"
|
||||
section="{{nav.ui.currentSection}}"
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
<div ng-hide="success">
|
||||
<umb-tree
|
||||
section="media"
|
||||
cachekey="movepickerDialog"
|
||||
showheader="true"
|
||||
showoptions="false"
|
||||
eventhandler="dialogTreeEventHandler">
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user