From 74151530828a6624d0aa44c0bbf7b348aff1ce96 Mon Sep 17 00:00:00 2001 From: Alfonso Presa Date: Wed, 15 Jul 2015 11:41:14 +0200 Subject: [PATCH 1/5] feat(tag-appender): Use requirejs to load js files if avail --- app/scripts/services/tag-appender.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/scripts/services/tag-appender.js b/app/scripts/services/tag-appender.js index f97db379..a09556f4 100644 --- a/app/scripts/services/tag-appender.js +++ b/app/scripts/services/tag-appender.js @@ -14,6 +14,10 @@ angular.module('angularWidgetInternal') return function (url, filetype) { var deferred = $q.defer(); + if (filetype === 'js' && window.requirejs) { + window.requirejs([url], deferred.resolve); + return deferred.promise; + } if (requireCache.indexOf(url) !== -1) { deferred.resolve(); return deferred.promise; From 1f6fcd168c26177340b4a9d0df0bf1194dea881b Mon Sep 17 00:00:00 2001 From: Alfonso Presa Date: Wed, 15 Jul 2015 12:03:40 +0200 Subject: [PATCH 2/5] docs(README): add comment about requirejs --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d0c1403..2c8375be 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,8 @@ angular.module('myApp').config(function (widgetsProvider) { You must set the manifest generator function in order for the directive to work. This is how we can know for a specific plugin, what files should be loaded and with which module name to create the injector. Above you can see an example for a manifest generator, but you can do whatever you like. You can put both relative and absolute URL's, of course. +*Note:* In case [requirejs](http://requirejs.org/) is available in the global scope, it will be used to load the javascript files. So if your widget needs more than one js file, you can include [requirejs](http://requirejs.org/) and use AMD to load them. + You can actually set multiple manifest generators and they will be evaluated in the order that they were defined. So a generator is allowed to return `undefined` in case it simply wants a different generator to handle it. The way the generators responses are handled is that the last generator that didn't return `undefined` will be used, unless a different generator returned a result with higher `priority`. ## Service Usage (widget) @@ -125,7 +127,7 @@ BTW, one event that is shared by default is `$locationChangeStart`. This is in o ## How to use in the real world -This framework is best used by having a separate project for each widget. During development, the developer sees only his own widget. All widgets should be built in a consistent manner, usually with one concatenated minified .js and .css files. +This framework is best used by having a separate project for each widget. During development, the developer sees only his own widget. All widgets should be built in a consistent manner, usually with one concatenated minified .js and .css files. ## License From c893a02571a86d6b82170dc4ff9499f872972fa5 Mon Sep 17 00:00:00 2001 From: Alfonso Presa Date: Wed, 15 Jul 2015 12:27:24 +0200 Subject: [PATCH 3/5] fix(jshint): allow global window --- .jshintrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.jshintrc b/.jshintrc index e9fd964f..a2c5aef5 100644 --- a/.jshintrc +++ b/.jshintrc @@ -21,6 +21,7 @@ "_": false, "angular": false, "require": false, - "module": false + "module": false, + "window": false } } From c57f044ae3e1598b0106e1365b9aea7ca8b4de06 Mon Sep 17 00:00:00 2001 From: Alfonso Presa Date: Mon, 20 Jul 2015 17:45:01 +0200 Subject: [PATCH 4/5] feat(tests): Add test for requirejs functionality --- app/scripts/services/tag-appender.js | 10 ++++-- bower.json | 3 +- karma.conf.js | 3 +- test/.jshintrc | 3 +- test/mock/mock-lazyloaded-file.js | 1 + test/spec/services/tag-appender.spec.js | 43 +++++++++++++++++++++++++ 6 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 test/mock/mock-lazyloaded-file.js diff --git a/app/scripts/services/tag-appender.js b/app/scripts/services/tag-appender.js index a09556f4..03ae724b 100644 --- a/app/scripts/services/tag-appender.js +++ b/app/scripts/services/tag-appender.js @@ -14,8 +14,14 @@ angular.module('angularWidgetInternal') return function (url, filetype) { var deferred = $q.defer(); - if (filetype === 'js' && window.requirejs) { - window.requirejs([url], deferred.resolve); + if (filetype === 'js' && window.requirejs && headElement === document.getElementsByTagName('head')[0]) { + window.requirejs([url], function () { + deferred.resolve(); + $rootScope.$digest(); + }, function () { + deferred.reject(); + $rootScope.$digest(); + }); return deferred.promise; } if (requireCache.indexOf(url) !== -1) { diff --git a/bower.json b/bower.json index 8e064ed2..1c7916c5 100644 --- a/bower.json +++ b/bower.json @@ -27,6 +27,7 @@ "es5-shim": "~2.1.0", "angular-route": ">= 1.2.0", "angular-ui-router": "~0.2.11", - "angular-widget": "~0.1.30" + "angular-widget": "~0.1.30", + "requirejs": "~2.1.19" } } diff --git a/karma.conf.js b/karma.conf.js index 49a424de..3698f50c 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -34,7 +34,8 @@ module.exports = function (config) { '{app,.tmp}/scripts/*.js', '{app,.tmp}/scripts/*/**/*.js', '{,.tmp/}test/**/*.js', - '{app,.tmp}/views/**/*.html' + '{app,.tmp}/views/**/*.html', + 'app/bower_components/requirejs/require.js' ], // list of files / patterns to exclude diff --git a/test/.jshintrc b/test/.jshintrc index 97fa3b49..07e32062 100644 --- a/test/.jshintrc +++ b/test/.jshintrc @@ -47,6 +47,7 @@ "using": false, "pause": false, "resume": false, - "sleep": false + "sleep": false, + "window": false } } diff --git a/test/mock/mock-lazyloaded-file.js b/test/mock/mock-lazyloaded-file.js new file mode 100644 index 00000000..1b3956c7 --- /dev/null +++ b/test/mock/mock-lazyloaded-file.js @@ -0,0 +1 @@ +window.lazyLoadingWorking = true; diff --git a/test/spec/services/tag-appender.spec.js b/test/spec/services/tag-appender.spec.js index 915757b4..691192bb 100644 --- a/test/spec/services/tag-appender.spec.js +++ b/test/spec/services/tag-appender.spec.js @@ -10,6 +10,49 @@ describe('Unit testing tagAppender service', function () { }); }); + describe('Loading with requirejs when available and headElement is head', function () { + beforeEach(function () { + //Restoring the head element makes requirejs come into action + module({ + headElement: window.document.getElementsByTagName('head')[0] + }); + }); + + it('should load the javascript files', inject (function (tagAppender, $window) { + var done = false; + tagAppender('base/test/mock/mock-lazyloaded-file.js', 'js').then(function () { + expect($window.lazyLoadingWorking).toBeTruthy(); + done = true; + }); + waitsFor(function() { + return done; + }); + })); + + it('should fail when file doesn\'t exist', inject (function (tagAppender) { + var done = false; + tagAppender('base/test/mock/non-existing-file.js', 'js').catch(function () { + done = true; + }); + waitsFor(function() { + return done; + }); + })); + + it('should not fail when same file loads two times', inject (function (tagAppender, $window) { + var done = false; + tagAppender('base/test/mock/mock-lazyloaded-file.js', 'js').then(function () { + tagAppender('base/test/mock/mock-lazyloaded-file.js', 'js').then(function () { + expect($window.lazyLoadingWorking).toBeTruthy(); + done= true; + }); + }); + waitsFor(function() { + return done; + }); + })); + }); + it('should append script tag when js file is added', inject(function (tagAppender) { tagAppender('dummy.js', 'js'); expect(headElement.appendChild.calls.length).toBe(1); From f6fb87e95f57302ab0a7f04750cf3fb9c2bbc4de Mon Sep 17 00:00:00 2001 From: Alfonso Presa Date: Tue, 21 Jul 2015 11:04:58 +0200 Subject: [PATCH 5/5] fix(tests): Not testing requirejs loading correctly --- app/scripts/services/tag-appender.js | 8 ++++---- karma.conf.js | 1 + test/spec/services/tag-appender.spec.js | 20 +++++++++++++++----- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/app/scripts/services/tag-appender.js b/app/scripts/services/tag-appender.js index 03ae724b..3746e684 100644 --- a/app/scripts/services/tag-appender.js +++ b/app/scripts/services/tag-appender.js @@ -15,11 +15,11 @@ angular.module('angularWidgetInternal') return function (url, filetype) { var deferred = $q.defer(); if (filetype === 'js' && window.requirejs && headElement === document.getElementsByTagName('head')[0]) { - window.requirejs([url], function () { - deferred.resolve(); + window.requirejs([url], function (module) { + deferred.resolve(module); $rootScope.$digest(); - }, function () { - deferred.reject(); + }, function (err) { + deferred.reject(err); $rootScope.$digest(); }); return deferred.promise; diff --git a/karma.conf.js b/karma.conf.js index 3698f50c..9f9390e1 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -33,6 +33,7 @@ module.exports = function (config) { '{app,.tmp}/*.js', '{app,.tmp}/scripts/*.js', '{app,.tmp}/scripts/*/**/*.js', + {pattern:'{,.tmp}/test/mock/mock-lazyloaded-file.js',included:false}, '{,.tmp/}test/**/*.js', '{app,.tmp}/views/**/*.html', 'app/bower_components/requirejs/require.js' diff --git a/test/spec/services/tag-appender.spec.js b/test/spec/services/tag-appender.spec.js index 691192bb..26ade7c1 100644 --- a/test/spec/services/tag-appender.spec.js +++ b/test/spec/services/tag-appender.spec.js @@ -11,6 +11,9 @@ describe('Unit testing tagAppender service', function () { }); describe('Loading with requirejs when available and headElement is head', function () { + + var moduleName = 'base/test/mock/mock-lazyloaded-file.js'; + beforeEach(function () { //Restoring the head element makes requirejs come into action module({ @@ -18,10 +21,16 @@ describe('Unit testing tagAppender service', function () { }); }); + afterEach(inject(function ($window){ + $window.requirejs.undef(moduleName); + $window.lazyLoadingWorking = undefined; + })); + it('should load the javascript files', inject (function (tagAppender, $window) { var done = false; - tagAppender('base/test/mock/mock-lazyloaded-file.js', 'js').then(function () { - expect($window.lazyLoadingWorking).toBeTruthy(); + expect($window.lazyLoadingWorking).toBeFalsy(); + tagAppender(moduleName, 'js').then(function (mod) { + expect($window.lazyLoadingWorking).toBe(true); done = true; }); waitsFor(function() { @@ -41,9 +50,10 @@ describe('Unit testing tagAppender service', function () { it('should not fail when same file loads two times', inject (function (tagAppender, $window) { var done = false; - tagAppender('base/test/mock/mock-lazyloaded-file.js', 'js').then(function () { - tagAppender('base/test/mock/mock-lazyloaded-file.js', 'js').then(function () { - expect($window.lazyLoadingWorking).toBeTruthy(); + expect($window.lazyLoadingWorking).toBeFalsy(); + tagAppender(moduleName, 'js').then(function () { + tagAppender(moduleName, 'js').then(function () { + expect($window.lazyLoadingWorking).toBe(true); done= true; }); });