From 319da4816a9f3a0ca339ee93ca00a01289786ee3 Mon Sep 17 00:00:00 2001 From: Per Ploug Krogslund Date: Mon, 5 Aug 2013 13:04:24 +0200 Subject: [PATCH] replaces scriptLoader references with assetsService --- .../tutorials/CreatingAPropertyEditor.ngdoc | 10 +- .../common/directives/umbtree.directive.js | 11 +- .../directives/umbtreeitem.directive.js | 11 +- .../src/common/services/assets.service.js | 171 ++++++++++++++++++ .../src/common/services/util.service.js | 4 +- .../markdowneditor.controller.js | 16 +- .../dialogs/contentpicker.controller.js | 5 +- .../views/common/dialogs/contentpicker.html | 4 +- .../src/views/common/navigation.controller.js | 14 +- .../src/views/directives/umb-navigation.html | 2 +- .../datepicker/datepicker.controller.js | 14 +- .../googlemaps/googlemaps.controller.js | 4 +- .../propertyeditors/rte/rte.controller.js | 8 +- .../propertyeditors/tags/tags.controller.js | 13 +- .../markdowneditor.controller.js | 16 +- 15 files changed, 243 insertions(+), 60 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/services/assets.service.js diff --git a/src/Umbraco.Web.UI.Client/docs/tutorials/CreatingAPropertyEditor.ngdoc b/src/Umbraco.Web.UI.Client/docs/tutorials/CreatingAPropertyEditor.ngdoc index 01dee13075..1a5a414653 100644 --- a/src/Umbraco.Web.UI.Client/docs/tutorials/CreatingAPropertyEditor.ngdoc +++ b/src/Umbraco.Web.UI.Client/docs/tutorials/CreatingAPropertyEditor.ngdoc @@ -104,12 +104,12 @@ Then open the `markdowneditor.controller.js` file and edit it so it looks like t angular.module("umbraco") .controller("My.MarkdownEditorController", - //inject umbracos scriptLoader - function ($scope,scriptLoader) { + //inject umbracos assetsService + function ($scope,assetsService) { - //tell the scriptloader to load the markdown.editor libs from the markdown editors + //tell the assetsService to load the markdown.editor libs from the markdown editors //plugin folder - scriptLoader + assetsService .load([ "/app_plugins/markdowneditor/lib/markdown.converter.js", "/app_plugins/markdowneditor/lib/markdown.sanitizer.js", @@ -121,7 +121,7 @@ Then open the `markdowneditor.controller.js` file and edit it so it looks like t }); //load the seperat css for the editor to avoid it blocking our js loading - scriptLoader.load(["/app_plugins/markdowneditor/lib/markdown.css"]); + assetsService.loadCss("/app_plugins/markdowneditor/lib/markdown.css"); }); This loads in our external dependency, but only when its needed by the editor. 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 88e57a8939..82b47c749c 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 @@ -15,7 +15,8 @@ angular.module("umbraco.directives") section: '@', showoptions: '@', showheader: '@', - cachekey: '@' + cachekey: '@', + eventhandler: '=' }, compile: function (element, attrs) { @@ -33,7 +34,7 @@ angular.module("umbraco.directives") ''; } template += '' + '' + ''; @@ -55,7 +56,11 @@ angular.module("umbraco.directives") /** Helper function to emit tree events */ function emitEvent(eventName, args) { - $rootScope.$broadcast(eventName, args); + + if (scope.eventhandler) { + $(scope.eventhandler).trigger(eventName, args); + } + // $rootScope.$broadcast(eventName, args); } /** Method to load in the tree data */ diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js index fcd6777a94..82966ace97 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js @@ -26,7 +26,7 @@ angular.module("umbraco.directives") scope: { section: '@', cachekey: '@', - callback: '=', + eventhandler: '=', node:'=' }, @@ -46,9 +46,12 @@ angular.module("umbraco.directives") var enableDeleteAnimations = true; /** Helper function to emit tree events */ - function emitEvent(eventName, args) { - $rootScope.$broadcast(eventName, args); + + if(scope.eventhandler){ + $(scope.eventhandler).trigger(eventName,args); + } + //$rootScope.$broadcast(eventName, args); } /** @@ -127,7 +130,7 @@ angular.module("umbraco.directives") return { 'padding-left': (node.level * 20) + "px" }; }; - var template = ''; + var template = ''; var newElement = angular.element(template); $compile(newElement)(scope); element.append(newElement); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js b/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js new file mode 100644 index 0000000000..fcefcdac0a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js @@ -0,0 +1,171 @@ +/** + * @ngdoc service + * @name umbraco.services.assetsService + * + * @requires $q + * @requires angularHelper + * + * @description + * Promise-based utillity service to lazy-load client-side dependencies inside angular controllers. + * + * ##usage + * To use, simply inject the assetsService into any controller that needs it, and make + * sure the umbraco.services module is accesible - which it should be by default. + * + *
+ *      angular.module("umbraco").controller("my.controller". function(assetsService){
+ *          assetsService.load(["script.js", "styles.css"], $scope).then(function(){
+ *                 //this code executes when the dependencies are done loading
+ *          });
+ *      });
+ * 
+ * + * You can also load individual files, which gives you greater control over what attibutes are passed to the file, as well as timeout + * + *
+ *      angular.module("umbraco").controller("my.controller". function(assetsService){
+ *          assetsService.loadJs("script.js", $scope, {charset: 'utf-8'}, 10000 }).then(function(){
+ *                 //this code executes when the script is done loading
+ *          });
+ *      });
+ * 
+ * + * For these cases, there are 2 individual methods, one for javascript, and one for stylesheets: + * + *
+ *      angular.module("umbraco").controller("my.controller". function(assetsService){
+ *          assetsService.loadCss("stye.css", $scope, {media: 'print'}, 10000 }).then(function(){
+ *                 //loadcss cannot determine when the css is done loading, so this will trigger instantly
+ *          });
+ *      });
+ * 
+ */ +angular.module('umbraco.services') +.factory('assetsService', function ($q, $log, angularHelper) { + + return { + /** + * @ngdoc method + * @name umbraco.services.assetsService#loadCss + * @methodOf umbraco.services.assetsService + * + * @description + * Injects a file as a stylesheet into the document head + * + * @param {String} path path to the css file to load + * @param {Scope} scope optional scope to pass into the loader + * @param {Object} keyvalue collection of attributes to pass to the stylesheet element + * @param {Number} timeout in milliseconds + * @returns {Promise} Promise object which resolves when the file has loaded + */ + loadCss : function(path, scope, attributes, timeout){ + var deferred = $q.defer(); + var t = timeout || 5000; + var a = attributes || undefined; + + yepnope.injectCss(path, function () { + + if (!scope) { + deferred.resolve(true); + }else{ + angularHelper.safeApply(scope, function () { + deferred.resolve(true); + }); + } + + },a,t); + + return deferred.promise; + }, + + /** + * @ngdoc method + * @name umbraco.services.assetsService#loadJs + * @methodOf umbraco.services.assetsService + * + * @description + * Injects a file as a javascript into the document + * + * @param {String} path path to the js file to load + * @param {Scope} scope optional scope to pass into the loader + * @param {Object} keyvalue collection of attributes to pass to the script element + * @param {Number} timeout in milliseconds + * @returns {Promise} Promise object which resolves when the file has loaded + */ + loadJs : function(path, scope, attributes, timeout){ + var deferred = $q.defer(); + var t = timeout || 5000; + var a = attributes || undefined; + + yepnope.injectJs(path, function () { + + if (!scope) { + deferred.resolve(true); + }else{ + angularHelper.safeApply(scope, function () { + deferred.resolve(true); + }); + } + + },a,t); + + return deferred.promise; + }, + + /** + * @ngdoc method + * @name umbraco.services.assetsService#load + * @methodOf umbraco.services.assetsService + * + * @description + * Injects a collection of files, this can be a mixed collection of css and js files, the loader will determine how to load them + * + * **Warning:** if the collection of files contains a .css file, you will in some cases not receive a resolved promise, it is therefore prefered to use the individual loadCss and loadJs methods + * + * @param {Array} pathArray string array of paths to the files to load + * @param {Scope} scope optional scope to pass into the loader + * @returns {Promise} Promise object which resolves when all the files has loaded + */ + load: function (pathArray, scope) { + var deferred = $q.defer(); + + var nonEmpty = _.reject(pathArray, function(item) { + return item === undefined || item === ""; + }); + + //don't load anything if there's nothing to load + if (nonEmpty.length > 0) { + + yepnope({ + load: pathArray, + complete: function() { + + //if a scope is supplied then we need to make a digest here because + // deferred only executes in a digest. This might be required if we + // are doing a load script after an http request or some other async call. + if (!scope) { + deferred.resolve(true); + } + else { + angularHelper.safeApply(scope, function () { + deferred.resolve(true); + }); + } + } + }); + } + else { + if (!scope) { + deferred.resolve(true); + } + else { + angularHelper.safeApply(scope, function () { + deferred.resolve(true); + }); + } + } + + return deferred.promise; + } + }; +}); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js index 0569c15c00..e2bdd5c668 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js @@ -8,13 +8,13 @@ * @description * Used to lazy load in any JS dependencies that need to be manually loaded in */ -function legacyJsLoader(scriptLoader, umbRequestHelper) { +function legacyJsLoader(assetsService, umbRequestHelper) { return { /** Called to load in the legacy tree js which is required on startup if a user is logged in or after login, but cannot be called until they are authenticated which is why it needs to be lazy loaded. */ loadLegacyTreeJs: function(scope) { - return scriptLoader.load([umbRequestHelper.getApiUrl("legacyTreeJs", "", "")], scope); + return assetsService.loadJs(umbRequestHelper.getApiUrl("legacyTreeJs", "", ""), scope); } }; } diff --git a/src/Umbraco.Web.UI.Client/src/packages/MarkdownEditor/markdowneditor.controller.js b/src/Umbraco.Web.UI.Client/src/packages/MarkdownEditor/markdowneditor.controller.js index 385f6e3bd5..445955fefc 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/MarkdownEditor/markdowneditor.controller.js +++ b/src/Umbraco.Web.UI.Client/src/packages/MarkdownEditor/markdowneditor.controller.js @@ -1,23 +1,23 @@ angular.module("umbraco") .controller("My.MarkdownEditorController", -//inject umbracos scriptLoader -function ($scope,scriptLoader) { +//inject umbracos assetsServce +function ($scope,assetsService) { - //tell the scriptloader to load the markdown.editor libs from the markdown editors + //tell the assets service to load the markdown.editor libs from the markdown editors //plugin folder - scriptLoader + assetsService .load([ "/app_plugins/markdowneditor/lib/markdown.converter.js", "/app_plugins/markdowneditor/lib/markdown.sanitizer.js", "/app_plugins/markdowneditor/lib/markdown.editor.js" ]) .then(function () { - //this function will execute when all dependencies have loaded - var converter2 = new Markdown.Converter(); - var editor2 = new Markdown.Editor(converter2, "-" + $scope.model.alias); + //this function will execute when all dependencies have loaded + var converter2 = new Markdown.Converter(); + var editor2 = new Markdown.Editor(converter2, "-" + $scope.model.alias); editor2.run(); }); //load the seperat css for the editor to avoid it blocking our js loading TEMP HACK - scriptLoader.load(["/app_plugins/markdowneditor/lib/markdown.css"]); + assetsService.loadCss("/app_plugins/markdowneditor/lib/markdown.css"); }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.controller.js index 522daaec8f..95f99b87d8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.controller.js @@ -1,10 +1,9 @@ //used for the media picker dialog angular.module("umbraco").controller("Umbraco.Dialogs.ContentPickerController", function ($scope) { - $scope.treeCallback = $({}); + $scope.dialogTreeEventHandler = $({}); - //$scope.treeCallback.bind("treeNodeSelect", function(event, args){ - $scope.$on("treeNodeSelect", function (ev, args) { + $scope.dialogTreeEventHandler.bind("treeNodeSelect", function(ev, args){ args.event.preventDefault(); args.event.stopPropagation(); 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 0425f7f14d..cef3668740 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 @@ -11,10 +11,10 @@
+ eventhandler="dialogTreeEventHandler">
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js index 6a0516e495..28a0f0b5d3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/navigation.controller.js @@ -16,6 +16,9 @@ function NavigationController($scope,$rootScope, $location, $log, navigationServ // when we create a dialog we pass in this scope to be used for the dialog's scope instead of creating a new one. $scope.nav = navigationService; + //the tree event handler i used to subscribe to the main tree click events + $scope.treeEventHandler = $({}); + $scope.selectedId = navigationService.currentId; $scope.sections = navigationService.sections; @@ -31,18 +34,21 @@ function NavigationController($scope,$rootScope, $location, $log, navigationServ angularHelper.safeApply($scope); } }); - + //this reacts to the options item in the tree - $scope.$on("treeOptionsClick", function (ev, args) { + $scope.treeEventHandler.bind("treeOptionsClick", function (ev, args) { + ev.stopPropagation(); + ev.preventDefault(); + $scope.currentNode = args.node; args.scope = $scope; + navigationService.showMenu(ev, args); }); //this reacts to tree items themselves being clicked //the tree directive should not contain any handling, simply just bubble events - $scope.$on("treeNodeSelect", function (ev, args) { - + $scope.treeEventHandler.bind("treeNodeSelect", function (ev, args) { var n = args.node; //here we need to check for some legacy tree code 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 bd28cc3dda..01f36746b5 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 @@ -65,7 +65,7 @@
- +
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js index f7021a955a..9757917895 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js @@ -1,9 +1,9 @@ angular.module("umbraco").controller("Umbraco.Editors.DatepickerController", - function ($scope, notificationsService, scriptLoader) { + function ($scope, notificationsService, assetsService) { - scriptLoader.load([ - 'views/propertyeditors/datepicker/bootstrap.datepicker.js', - ]).then( + assetsService.loadJs( + 'views/propertyeditors/datepicker/bootstrap.datepicker.js' + ).then( function () { //The Datepicker js and css files are available and all components are ready to use. @@ -21,7 +21,7 @@ angular.module("umbraco").controller("Umbraco.Editors.DatepickerController", }); - scriptLoader.load([ - 'css!/belle/views/propertyeditors/datepicker/bootstrap.datepicker.css' - ]); + assetsService.loadCss( + 'views/propertyeditors/datepicker/bootstrap.datepicker.css' + ); }); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/googlemaps/googlemaps.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/googlemaps/googlemaps.controller.js index ed6ab974f5..3ab8a8f434 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/googlemaps/googlemaps.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/googlemaps/googlemaps.controller.js @@ -1,8 +1,8 @@ angular.module("umbraco") .controller("Umbraco.Editors.GoogleMapsController", - function ($rootScope, $scope, notificationsService, dialogService, scriptLoader, $log, $timeout) { + function ($rootScope, $scope, notificationsService, dialogService, assetsService, $log, $timeout) { - scriptLoader.load(['http://www.google.com/jsapi']) + assetsService.loadJs('http://www.google.com/jsapi') .then(function(){ google.load("maps", "3", { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js index 96fa452a2c..c84635f7ec 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js @@ -1,10 +1,10 @@ angular.module("umbraco") .controller("Umbraco.Editors.RTEController", - function($rootScope, $scope, dialogService, $log, umbImageHelper, scriptLoader){ + function($rootScope, $scope, dialogService, $log, umbImageHelper, assetsService){ - scriptLoader.load(["lib/tinymce/tinymce.min.js"]).then(function(){ - + assetsService.loadJs("lib/tinymce/tinymce.min.js", $scope).then(function(){ tinymce.DOM.events.domLoaded = true; + tinymce.init({ selector: "#" + $scope.model.alias + "_rte", skin: "umbraco", @@ -55,7 +55,7 @@ angular.module("umbraco") }; function populate(data){ - $scope.model.value = data.selection; + $scope.model.value = data.selection; } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js index bdcfc7f478..20c08c5d0b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js @@ -1,13 +1,10 @@ angular.module("umbraco") .controller("Umbraco.Editors.TagsController", - //function($rootScope, $scope, $log, tagsResource, scriptLoader) { - function ($rootScope, $scope, $log, scriptLoader) { + function ($rootScope, $scope, $log, assetsService) { - scriptLoader.load( - [ - 'views/propertyeditors/tags/bootstrap-tags.custom.js', - 'css!views/propertyeditors/tags/bootstrap-tags.custom.css' - ]).then(function(){ + assetsService.loadJs( + 'views/propertyeditors/tags/bootstrap-tags.custom.js' + ).then(function(){ //// Get data from tagsFactory //$scope.tags = tagsResource.getTags("group"); @@ -22,5 +19,7 @@ angular.module("umbraco") tags.addTag(tag.label); }); }); + + assetsService.loadCss('views/propertyeditors/tags/bootstrap-tags.custom.css'); } ); \ No newline at end of file diff --git a/src/Umbraco.Web.UI/App_Plugins/MarkdownEditor/markdowneditor.controller.js b/src/Umbraco.Web.UI/App_Plugins/MarkdownEditor/markdowneditor.controller.js index 385f6e3bd5..445955fefc 100644 --- a/src/Umbraco.Web.UI/App_Plugins/MarkdownEditor/markdowneditor.controller.js +++ b/src/Umbraco.Web.UI/App_Plugins/MarkdownEditor/markdowneditor.controller.js @@ -1,23 +1,23 @@ angular.module("umbraco") .controller("My.MarkdownEditorController", -//inject umbracos scriptLoader -function ($scope,scriptLoader) { +//inject umbracos assetsServce +function ($scope,assetsService) { - //tell the scriptloader to load the markdown.editor libs from the markdown editors + //tell the assets service to load the markdown.editor libs from the markdown editors //plugin folder - scriptLoader + assetsService .load([ "/app_plugins/markdowneditor/lib/markdown.converter.js", "/app_plugins/markdowneditor/lib/markdown.sanitizer.js", "/app_plugins/markdowneditor/lib/markdown.editor.js" ]) .then(function () { - //this function will execute when all dependencies have loaded - var converter2 = new Markdown.Converter(); - var editor2 = new Markdown.Editor(converter2, "-" + $scope.model.alias); + //this function will execute when all dependencies have loaded + var converter2 = new Markdown.Converter(); + var editor2 = new Markdown.Editor(converter2, "-" + $scope.model.alias); editor2.run(); }); //load the seperat css for the editor to avoid it blocking our js loading TEMP HACK - scriptLoader.load(["/app_plugins/markdowneditor/lib/markdown.css"]); + assetsService.loadCss("/app_plugins/markdowneditor/lib/markdown.css"); }); \ No newline at end of file