|
1 | 1 | /**
|
2 | 2 | * AngularCSS - CSS on-demand for AngularJS
|
3 |
| - * @version v1.0.6 |
| 3 | + * @version v1.0.7 |
4 | 4 | * @author DOOR3, Alex Castillo
|
5 | 5 | * @link http://door3.github.io/angular-css
|
6 | 6 | * @license MIT License, http://www.opensource.org/licenses/MIT
|
|
35 | 35 | weight: 0
|
36 | 36 | };
|
37 | 37 |
|
38 |
| - this.$get = ['$rootScope','$injector','$window','$timeout','$compile','$http','$filter','$log', |
39 |
| - function $get($rootScope, $injector, $window, $timeout, $compile, $http, $filter, $log) { |
| 38 | + this.$get = ['$rootScope','$injector','$q','$window','$timeout','$compile','$http','$filter','$log', |
| 39 | + function $get($rootScope, $injector, $q, $window, $timeout, $compile, $http, $filter, $log) { |
40 | 40 |
|
41 | 41 | var $css = {};
|
42 | 42 |
|
43 | 43 | var template = '<link ng-repeat="stylesheet in stylesheets track by $index | orderBy: \'weight\' " rel="{{ stylesheet.rel }}" type="{{ stylesheet.type }}" ng-href="{{ stylesheet.href }}" ng-attr-media="{{ stylesheet.media }}">';
|
44 | 44 |
|
45 | 45 | // Variables - default options that can be overridden from application config
|
46 | 46 | var mediaQuery = {}, mediaQueryListener = {}, mediaQueriesToIgnore = ['print'], options = angular.extend({}, defaults),
|
47 |
| - container = angular.element(document.querySelector ? document.querySelector(options.container) : document.getElementsByTagName(options.container)[0]); |
| 47 | + container = angular.element(document.querySelector ? document.querySelector(options.container) : document.getElementsByTagName(options.container)[0]), |
| 48 | + dynamicPaths = []; |
48 | 49 |
|
49 | 50 | // Parse all directives
|
50 | 51 | angular.forEach($directives, function (directive, key) {
|
|
69 | 70 | function $routeEventListener(event, current, prev) {
|
70 | 71 | // Removes previously added css rules
|
71 | 72 | if (prev) {
|
72 |
| - $css.remove($css.getFromRoute(prev)); |
| 73 | + $css.remove($css.getFromRoute(prev).concat(dynamicPaths)); |
| 74 | + // Reset dynamic paths array |
| 75 | + dynamicPaths.length = 0; |
73 | 76 | }
|
74 | 77 | // Adds current css rules
|
75 | 78 | if (current) {
|
|
83 | 86 | function $stateEventListener(event, current, params, prev) {
|
84 | 87 | // Removes previously added css rules
|
85 | 88 | if (prev) {
|
86 |
| - $css.remove($css.getFromState(prev)); |
| 89 | + $css.remove($css.getFromState(prev).concat(dynamicPaths)); |
| 90 | + // Reset dynamic paths array |
| 91 | + dynamicPaths.length = 0; |
87 | 92 | }
|
88 | 93 | // Adds current css rules
|
89 | 94 | if (current) {
|
90 | 95 | $css.add($css.getFromState(current));
|
91 | 96 | }
|
92 | 97 | }
|
93 | 98 |
|
| 99 | + /** |
| 100 | + * Map breakpoitns defined in defaults to stylesheet media attribute |
| 101 | + **/ |
| 102 | + function mapBreakpointToMedia(stylesheet) { |
| 103 | + if (angular.isDefined(options.breakpoints)) { |
| 104 | + if (stylesheet.breakpoint in options.breakpoints) { |
| 105 | + stylesheet.media = options.breakpoints[stylesheet.breakpoint]; |
| 106 | + } |
| 107 | + delete stylesheet.breakpoints; |
| 108 | + } |
| 109 | + } |
| 110 | + |
94 | 111 | /**
|
95 | 112 | * Parse: returns array with full all object based on defaults
|
96 | 113 | **/
|
97 | 114 | function parse(obj) {
|
98 | 115 | if (!obj) {
|
99 | 116 | return;
|
100 | 117 | }
|
| 118 | + // Function syntax |
| 119 | + if (angular.isFunction(obj)) { |
| 120 | + obj = angular.copy($injector.invoke(obj)); |
| 121 | + } |
101 | 122 | // String syntax
|
102 | 123 | if (angular.isString(obj)) {
|
103 | 124 | obj = angular.extend({
|
|
122 | 143 | obj = angular.extend(item, options);
|
123 | 144 | });
|
124 | 145 | }
|
| 146 | + // Map breakpoint to media attribute |
| 147 | + mapBreakpointToMedia(obj); |
125 | 148 | return obj;
|
126 | 149 | }
|
127 | 150 |
|
|
135 | 158 | $rootScope.$on('$directiveAdd', $directiveAddEventListener);
|
136 | 159 |
|
137 | 160 | // Routes event listener ($route required)
|
138 |
| - $rootScope.$on('$routeChangeStart', $routeEventListener); |
| 161 | + $rootScope.$on('$routeChangeSuccess', $routeEventListener); |
139 | 162 |
|
140 | 163 | // States event listener ($state required)
|
141 |
| - $rootScope.$on('$stateChangeStart', $stateEventListener); |
| 164 | + $rootScope.$on('$stateChangeSuccess', $stateEventListener); |
142 | 165 |
|
143 | 166 | /**
|
144 | 167 | * Bust Cache
|
|
249 | 272 | if (css) {
|
250 | 273 | if (angular.isArray(css)) {
|
251 | 274 | angular.forEach(css, function (cssItem) {
|
| 275 | + if (angular.isFunction(cssItem)) { |
| 276 | + dynamicPaths.push(parse(cssItem)); |
| 277 | + } |
252 | 278 | result.push(parse(cssItem));
|
253 | 279 | });
|
254 | 280 | } else {
|
255 |
| - result.push(parse(css)); |
| 281 | + if (angular.isFunction(css)) { |
| 282 | + dynamicPaths.push(parse(css)); |
| 283 | + } |
| 284 | + result.push(parse(css)); |
256 | 285 | }
|
257 | 286 | }
|
258 | 287 | return result;
|
|
288 | 317 | if (angular.isDefined(state.views)) {
|
289 | 318 | angular.forEach(state.views, function (item) {
|
290 | 319 | if (item.css) {
|
| 320 | + if (angular.isFunction(item.css)) { |
| 321 | + dynamicPaths.push(parse(item.css)); |
| 322 | + } |
291 | 323 | result.push(parse(item.css));
|
292 | 324 | }
|
293 | 325 | });
|
|
296 | 328 | if (angular.isDefined(state.children)) {
|
297 | 329 | angular.forEach(state.children, function (child) {
|
298 | 330 | if (child.css) {
|
| 331 | + if (angular.isFunction(child.css)) { |
| 332 | + dynamicPaths.push(parse(child.css)); |
| 333 | + } |
299 | 334 | result.push(parse(child.css));
|
300 | 335 | }
|
301 | 336 | if (angular.isDefined(child.children)) {
|
302 | 337 | angular.forEach(child.children, function (childChild) {
|
303 | 338 | if (childChild.css) {
|
| 339 | + if (angular.isFunction(childChild.css)) { |
| 340 | + dynamicPaths.push(parse(childChild.css)); |
| 341 | + } |
304 | 342 | result.push(parse(childChild.css));
|
305 | 343 | }
|
306 | 344 | });
|
|
312 | 350 | // For multiple stylesheets
|
313 | 351 | if (angular.isArray(state.css)) {
|
314 | 352 | angular.forEach(state.css, function (itemCss) {
|
| 353 | + if (angular.isFunction(itemCss)) { |
| 354 | + dynamicPaths.push(parse(itemCss)); |
| 355 | + } |
315 | 356 | result.push(parse(itemCss));
|
316 | 357 | });
|
317 | 358 | // For single stylesheets
|
318 | 359 | } else {
|
| 360 | + if (angular.isFunction(state.css)) { |
| 361 | + dynamicPaths.push(parse(state.css)); |
| 362 | + } |
319 | 363 | result.push(parse(state.css));
|
320 | 364 | }
|
321 | 365 | }
|
|
363 | 407 | if ($injector.has('$state')) {
|
364 | 408 | Array.prototype.push.apply(stylesheets, $css.getFromStates($injector.get('$state').get()));
|
365 | 409 | }
|
| 410 | + stylesheets = filterBy(stylesheets, 'preload'); |
366 | 411 | }
|
367 |
| - stylesheets = filterBy(stylesheets, 'preload'); |
368 |
| - angular.forEach(stylesheets, function(stylesheet, index) { |
369 |
| - // Preload via ajax request |
370 |
| - $http.get(stylesheet.href) |
371 |
| - .success(function (response) { |
372 |
| - $log.debug('preload response: ' + response); |
373 |
| - if (stylesheets.length === (index + 1) && angular.isFunction(callback)) { |
374 |
| - callback(stylesheets); |
375 |
| - } |
| 412 | + if (!angular.isArray(stylesheets)) { |
| 413 | + stylesheets = [stylesheets]; |
| 414 | + } |
| 415 | + var stylesheetLoadPromises = []; |
| 416 | + angular.forEach(stylesheets, function(stylesheet, key) { |
| 417 | + stylesheet = stylesheets[key] = parse(stylesheet); |
| 418 | + stylesheetLoadPromises.push( |
| 419 | + // Preload via ajax request |
| 420 | + $http.get(stylesheet.href).error(function (response) { |
| 421 | + $log.error('AngularCSS: Incorrect path for ' + stylesheet.href); |
376 | 422 | })
|
377 |
| - .error(function (response) { |
378 |
| - $log.error('Incorrect path for ' + stylesheet.href); |
379 |
| - }); |
| 423 | + ); |
380 | 424 | });
|
| 425 | + if (angular.isFunction(callback)) { |
| 426 | + $q.all(stylesheetLoadPromises).then(function () { |
| 427 | + callback(stylesheets); |
| 428 | + }); |
| 429 | + } |
381 | 430 | };
|
382 | 431 |
|
383 | 432 | /**
|
|
0 commit comments