1/** 2 * oclazyload - Load modules on demand (lazy load) with angularJS 3 * @version v1.0.9 4 * @link https://github.com/ocombe/ocLazyLoad 5 * @license MIT 6 * @author Olivier Combe <[email protected]> 7 */ 8(function (angular, window) { 9 'use strict'; 10 11 var regModules = ['ng', 'oc.lazyLoad'], 12 regInvokes = {}, 13 regConfigs = [], 14 modulesToLoad = [], 15 // modules to load from angular.module or other sources 16 realModules = [], 17 // real modules called from angular.module 18 recordDeclarations = [], 19 broadcast = angular.noop, 20 runBlocks = {}, 21 justLoaded = []; 22 23 var ocLazyLoad = angular.module('oc.lazyLoad', ['ng']); 24 25 ocLazyLoad.provider('$ocLazyLoad', ["$controllerProvider", "$provide", "$compileProvider", "$filterProvider", "$injector", "$animateProvider", function ($controllerProvider, $provide, $compileProvider, $filterProvider, $injector, $animateProvider) { 26 var modules = {}, 27 providers = { 28 $controllerProvider: $controllerProvider, 29 $compileProvider: $compileProvider, 30 $filterProvider: $filterProvider, 31 $provide: $provide, // other things (constant, decorator, provider, factory, service) 32 $injector: $injector, 33 $animateProvider: $animateProvider 34 }, 35 debug = false, 36 events = false, 37 moduleCache = [], 38 modulePromises = {}; 39 40 moduleCache.push = function (value) { 41 if (this.indexOf(value) === -1) { 42 Array.prototype.push.apply(this, arguments); 43 } 44 }; 45 46 this.config = function (config) { 47 // If we want to define modules configs 48 if (angular.isDefined(config.modules)) { 49 if (angular.isArray(config.modules)) { 50 angular.forEach(config.modules, function (moduleConfig) { 51 modules[moduleConfig.name] = moduleConfig; 52 }); 53 } else { 54 modules[config.modules.name] = config.modules; 55 } 56 } 57 58 if (angular.isDefined(config.debug)) { 59 debug = config.debug; 60 } 61 62 if (angular.isDefined(config.events)) { 63 events = config.events; 64 } 65 }; 66 67 /** 68 * Get the list of existing registered modules 69 * @param element 70 */ 71 this._init = function _init(element) { 72 // this is probably useless now because we override angular.bootstrap 73 if (modulesToLoad.length === 0) { 74 var elements = [element], 75 names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'], 76 NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/, 77 append = function append(elm) { 78 return elm && elements.push(elm); 79 }; 80 81 angular.forEach(names, function (name) { 82 names[name] = true; 83 append(document.getElementById(name)); 84 name = name.replace(':', '\\:'); 85 if (typeof element[0] !== 'undefined' && element[0].querySelectorAll) { 86 angular.forEach(element[0].querySelectorAll('.' + name), append); 87 angular.forEach(element[0].querySelectorAll('.' + name + '\\:'), append); 88 angular.forEach(element[0].querySelectorAll('[' + name + ']'), append); 89 } 90 }); 91 92 angular.forEach(elements, function (elm) { 93 if (modulesToLoad.length === 0) { 94 var className = ' ' + element.className + ' '; 95 var match = NG_APP_CLASS_REGEXP.exec(className); 96 if (match) { 97 modulesToLoad.push((match[2] || '').replace(/\s+/g, ',')); 98 } else { 99 angular.forEach(elm.attributes, function (attr) { 100 if (modulesToLoad.length === 0 && names[attr.name]) { 101 modulesToLoad.push(attr.value); 102 } 103 }); 104 } 105 } 106 }); 107 } 108 109 if (modulesToLoad.length === 0 && !((window.jasmine || window.mocha) && angular.isDefined(angular.mock))) { 110 console.error('No module found during bootstrap, unable to init ocLazyLoad. You should always use the ng-app directive or angular.boostrap when you use ocLazyLoad.'); 111 } 112 113 var addReg = function addReg(moduleName) { 114 if (regModules.indexOf(moduleName) === -1) { 115 // register existing modules 116 regModules.push(moduleName); 117 var mainModule = angular.module(moduleName); 118 119 // register existing components (directives, services, ...) 120 _invokeQueue(null, mainModule._invokeQueue, moduleName); 121 _invokeQueue(null, mainModule._configBlocks, moduleName); // angular 1.3+ 122 123 angular.forEach(mainModule.requires, addReg); 124 } 125 }; 126 127 angular.forEach(modulesToLoad, function (moduleName) { 128 addReg(moduleName); 129 }); 130 131 modulesToLoad = []; // reset for next bootstrap 132 recordDeclarations.pop(); // wait for the next lazy load 133 }; 134 135 /** 136 * Like JSON.stringify but that doesn't throw on circular references 137 * @param obj 138 */ 139 var stringify = function stringify(obj) { 140 try { 141 return JSON.stringify(obj); 142 } catch (e) { 143 var cache = []; 144 return JSON.stringify(obj, function (key, value) { 145 if (angular.isObject(value) && value !== null) { 146 if (cache.indexOf(value) !== -1) { 147 // Circular reference found, discard key 148 return; 149 }
150 // Store value in our collection 151 cache.push(value); 152 } 153 return value; 154 }); 155 } 156 }; 157 158 var hashCode = function hashCode(str) { 159 var hash = 0, 160 i, 161 chr, 162 len; 163 if (str.length == 0) { 164 return hash; 165 } 166 for (i = 0, len = str.length; i < len; i++) { 167 chr = str.charCodeAt(i); 168 hash = (hash << 5) - hash + chr; 169 hash |= 0; // Convert to 32bit integer 170 } 171 return hash; 172 }; 173 174 function _register(providers, registerModules, params) { 175 if (registerModules) { 176 var k, 177 moduleName, 178 moduleFn, 179 tempRunBlocks = []; 180 for (k = registerModules.length - 1; k >= 0; k--) { 181 moduleName = registerModules[k]; 182 if (!angular.isString(moduleName)) { 183 moduleName = getModuleName(moduleName); 184 } 185 if (!moduleName || justLoaded.indexOf(moduleName) !== -1 || modules[moduleName] && realModules.indexOf(moduleName) === -1) { 186 continue; 187 } 188 // new if not registered 189 var newModule = regModules.indexOf(moduleName) === -1; 190 moduleFn = ngModuleFct(moduleName); 191 if (newModule) { 192 regModules.push(moduleName); 193 _register(providers, moduleFn.requires, params); 194 } 195 if (moduleFn._runBlocks.length > 0) { 196 // new run blocks detected! Replace the old ones (if existing) 197 runBlocks[moduleName] = []; 198 while (moduleFn._runBlocks.length > 0) { 199 runBlocks[moduleName].push(moduleFn._runBlocks.shift()); 200 } 201 } 202 if (angular.isDefined(runBlocks[moduleName]) && (newModule || params.rerun)) { 203 tempRunBlocks = tempRunBlocks.concat(runBlocks[moduleName]); 204 } 205 _invokeQueue(providers, moduleFn._invokeQueue, moduleName, params.reconfig); 206 _invokeQueue(providers, moduleFn._configBlocks, moduleName, params.reconfig); // angular 1.3+ 207 broadcast(newModule ? 'ocLazyLoad.moduleLoaded' : 'ocLazyLoad.moduleReloaded', moduleName); 208 registerModules.pop(); 209 justLoaded.push(moduleName); 210 } 211 // execute the run blocks at the end 212 var instanceInjector = providers.getInstanceInjector(); 213 angular.forEach(tempRunBlocks, function (fn) { 214 instanceInjector.invoke(fn); 215 }); 216 } 217 } 218 219 function _registerInvokeList(args, moduleName) { 220 var invokeList = args[2][0], 221 type = args[1], 222 newInvoke = false; 223 if (angular.isUndefined(regInvokes[moduleName])) { 224 regInvokes[moduleName] = {}; 225 } 226 if (angular.isUndefined(regInvokes[moduleName][type])) { 227 regInvokes[moduleName][type] = {}; 228 } 229 var onInvoke = function onInvoke(invokeName, invoke) { 230 if (!regInvokes[moduleName][type].hasOwnProperty(invokeName)) { 231 regInvokes[moduleName][type][invokeName] = []; 232 } 233 if (checkHashes(invoke, regInvokes[moduleName][type][invokeName])) { 234 newInvoke = true; 235 regInvokes[moduleName][type][invokeName].push(invoke); 236 broadcast('ocLazyLoad.componentLoaded', [moduleName, type, invokeName]); 237 } 238 }; 239 240 function checkHashes(potentialNew, invokes) { 241 var isNew = true, 242 newHash; 243 if (invokes.length) { 244 newHash = signature(potentialNew); 245 angular.forEach(invokes, function (invoke) { 246 isNew = isNew && signature(invoke) !== newHash; 247 }); 248 } 249 return isNew; 250 } 251 252 function signature(data) { 253 if (angular.isArray(data)) { 254 // arrays are objects, we need to test for it first
255 return hashCode(data.toString()); 256 } else if (angular.isObject(data)) { 257 // constants & values for example 258 return hashCode(stringify(data)); 259 } else { 260 if (angular.isDefined(data) && data !== null) { 261 return hashCode(data.toString()); 262 } else { 263 // null & undefined constants 264 return data; 265 } 266 } 267 } 268 269 if (angular.isString(invokeList)) { 270 onInvoke(invokeList, args[2][1]); 271 } else if (angular.isObject(invokeList)) { 272 angular.forEach(invokeList, function (invoke, key) { 273 if (angular.isString(invoke)) { 274 // decorators for example 275 onInvoke(invoke, invokeList[1]); 276 } else { 277 // components registered as object lists {"componentName": function() {}} 278 onInvoke(key, invoke); 279 } 280 }); 281 } else { 282 return false; 283 } 284 return newInvoke; 285 } 286 287 function _invokeQueue(providers, queue, moduleName, reconfig) { 288 if (!queue) { 289 return; 290 } 291 292 var i, len, args, provider; 293 for (i = 0, len = queue.length; i < len; i++) { 294 args = queue[i]; 295 if (angular.isArray(args)) { 296 if (providers !== null) { 297 if (providers.hasOwnProperty(args[0])) { 298 provider = providers[args[0]]; 299 } else { 300 throw new Error('unsupported provider ' + args[0]); 301 } 302 } 303 var isNew = _registerInvokeList(args, moduleName); 304 if (args[1] !== 'invoke') { 305 if (isNew && angular.isDefined(provider)) { 306 provider[args[1]].apply(provider, args[2]); 307 } 308 } else { 309 // config block 310 var callInvoke = function callInvoke(fct) { 311 var invoked = regConfigs.indexOf(moduleName + '-' + fct); 312 if (invoked === -1 || reconfig) { 313 if (invoked === -1) { 314 regConfigs.push(moduleName + '-' + fct); 315 } 316 if (angular.isDefined(provider)) { 317 provider[args[1]].apply(provider, args[2]); 318 } 319 } 320 }; 321 if (angular.isFunction(args[2][0])) { 322 callInvoke(args[2][0]); 323 } else if (angular.isArray(args[2][0])) { 324 for (var j = 0, jlen = args[2][0].length; j < jlen; j++) { 325 if (angular.isFunction(args[2][0][j])) { 326 callInvoke(args[2][0][j]); 327 } 328 } 329 } 330 } 331 } 332 } 333 } 334 335 function getModuleName(module) { 336 var moduleName = null; 337 if (angular.isString(module)) { 338 moduleName = module; 339 } else if (angular.isObject(module) && module.hasOwnProperty('name') && angular.isString(module.name)) { 340 moduleName = module.name; 341 } 342 return moduleName; 343 } 344 345 function moduleExists(moduleName) { 346 if (!angular.isString(moduleName)) { 347 return false; 348 } 349 try { 350 return ngModuleFct(moduleName); 351 } catch (e) { 352 if (/No module/.test(e) || e.message.indexOf('$injector:nomod') > -1) { 353 return false;
354 } 355 } 356 } 357 358 this.$get = ["$log", "$rootElement", "$rootScope", "$cacheFactory", "$q", function ($log, $rootElement, $rootScope, $cacheFactory, $q) { 359 var instanceInjector, 360 filesCache = $cacheFactory('ocLazyLoad'); 361 362 if (!debug) { 363 $log = {}; 364 $log['error'] = angular.noop; 365 $log['warn'] = angular.noop; 366 $log['info'] = angular.noop; 367 } 368 369 // Make this lazy because when $get() is called the instance injector hasn't been assigned to the rootElement yet 370 providers.getInstanceInjector = function () { 371 return instanceInjector ? instanceInjector : instanceInjector = $rootElement.data('$injector') || angular.injector(); 372 }; 373 374 broadcast = function broadcast(eventName, params) { 375 if (events) { 376 $rootScope.$broadcast(eventName, params); 377 } 378 if (debug) { 379 $log.info(eventName, params); 380 } 381 }; 382 383 function reject(e) { 384 var deferred = $q.defer(); 385 $log.error(e.message); 386 deferred.reject(e); 387 return deferred.promise; 388 } 389 390 return { 391 _broadcast: broadcast, 392 393 _$log: $log, 394 395 /** 396 * Returns the files cache used by the loaders to store the files currently loading 397 * @returns {*} 398 */ 399 _getFilesCache: function getFilesCache() { 400 return filesCache; 401 }, 402 403 /** 404 * Let the service know that it should monitor angular.module because files are loading 405 * @param watch boolean 406 */ 407 toggleWatch: function toggleWatch(watch) { 408 if (watch) { 409 recordDeclarations.push(true); 410 } else { 411 recordDeclarations.pop(); 412 } 413 }, 414 415 /** 416 * Let you get a module config object 417 * @param moduleName String the name of the module 418 * @returns {*} 419 */ 420 getModuleConfig: function getModuleConfig(moduleName) { 421 if (!angular.isString(moduleName)) { 422 throw new Error('You need to give the name of the module to get'); 423 } 424 if (!modules[moduleName]) { 425 return null; 426 } 427 return angular.copy(modules[moduleName]); 428 }, 429 430 /** 431 * Let you define a module config object 432 * @param moduleConfig Object the module config object 433 * @returns {*} 434 */ 435 setModuleConfig: function setModuleConfig(moduleConfig) { 436 if (!angular.isObject(moduleConfig)) { 437 throw new Error('You need to give the module config object to set'); 438 } 439 modules[moduleConfig.name] = moduleConfig; 440 return moduleConfig; 441 }, 442 443 /** 444 * Returns the list of loaded modules 445 * @returns {string[]} 446 */ 447 getModules: function getModules() { 448 return regModules; 449 }, 450 451 /** 452 * Let you check if a module has been loaded into Angular or not 453 * @param modulesNames String/Object a module name, or a list of module names 454 * @returns {boolean} 455 */ 456 isLoaded: function isLoaded(modulesNames) { 457 var moduleLoaded = function moduleLoaded(module) { 458 var isLoaded = regModules.indexOf(module) > -1; 459 if (!isLoaded) { 460 isLoaded = !!moduleExists(module); 461 } 462 return isLoaded; 463 }; 464 if (angular.isString(modulesNames)) { 465 modulesNames = [modulesNames]; 466 } 467 if (angular.isArray(modulesNames)) { 468 var i, len; 469 for (i = 0, len = modulesNames.length; i < len; i++) { 470 if (!moduleLoaded(modulesNames[i])) { 471 return false;
472 } 473 } 474 return true; 475 } else { 476 throw new Error('You need to define the module(s) name(s)'); 477 } 478 }, 479 480 /** 481 * Given a module, return its name 482 * @param module 483 * @returns {String} 484 */ 485 _getModuleName: getModuleName, 486 487 /** 488 * Returns a module if it exists 489 * @param moduleName 490 * @returns {module} 491 */ 492 _getModule: function getModule(moduleName) { 493 try { 494 return ngModuleFct(moduleName); 495 } catch (e) { 496 // this error message really suxx 497 if (/No module/.test(e) || e.message.indexOf('$injector:nomod') > -1) { 498 e.message = 'The module "' + stringify(moduleName) + '" that you are trying to load does not exist. ' + e.message; 499 } 500 throw e; 501 } 502 }, 503 504 /** 505 * Check if a module exists and returns it if it does 506 * @param moduleName 507 * @returns {boolean} 508 */ 509 moduleExists: moduleExists, 510 511 /** 512 * Load the dependencies, and might try to load new files depending on the config 513 * @param moduleName (String or Array of Strings) 514 * @param localParams 515 * @returns {*} 516 * @private 517 */ 518 _loadDependencies: function _loadDependencies(moduleName, localParams) { 519 var loadedModule, 520 requires, 521 diff, 522 promisesList = [], 523 self = this; 524 525 moduleName = self._getModuleName(moduleName); 526 527 if (moduleName === null) { 528 return $q.when(); 529 } else { 530 try { 531 loadedModule = self._getModule(moduleName); 532 } catch (e) { 533 return reject(e); 534 } 535 // get unloaded requires 536 requires = self.getRequires(loadedModule); 537 } 538 539 angular.forEach(requires, function (requireEntry) { 540 // If no configuration is provided, try and find one from a previous load. 541 // If there isn't one, bail and let the normal flow run 542 if (angular.isString(requireEntry)) { 543 var config = self.getModuleConfig(requireEntry); 544 if (config === null) { 545 moduleCache.push(requireEntry); // We don't know about this module, but something else might, so push it anyway. 546 return; 547 } 548 requireEntry = config; 549 // ignore the name because it's probably not a real module name 550 config.name = undefined; 551 } 552 553 // Check if this dependency has been loaded previously 554 if (self.moduleExists(requireEntry.name)) { 555 // compare against the already loaded module to see if the new definition adds any new files 556 diff = requireEntry.files.filter(function (n) { 557 return self.getModuleConfig(requireEntry.name).files.indexOf(n) < 0; 558 }); 559 560 // If the module was redefined, advise via the console 561 if (diff.length !== 0) { 562 self._$log.warn('Module "', moduleName, '" attempted to redefine configuration for dependency. "', requireEntry.name, '"\n Additional Files Loaded:', diff); 563 } 564 565 // Push everything to the file loader, it will weed out the duplicates. 566 if (angular.isDefined(self.filesLoader)) { 567 // if a files loader is defined 568 promisesList.push(self.filesLoader(requireEntry, localParams).then(function () { 569 return self._loadDependencies(requireEntry
569); 570 })); 571 } else { 572 return reject(new Error('Error: New dependencies need to be loaded from external files (' + requireEntry.files + '), but no loader has been defined.')); 573 } 574 return; 575 } else if (angular.isArray(requireEntry)) { 576 var files = []; 577 angular.forEach(requireEntry, function (entry) { 578 // let's check if the entry is a file name or a config name 579 var config = self.getModuleConfig(entry); 580 if (config === null) { 581 files.push(entry); 582 } else if (config.files) { 583 files = files.concat(config.files); 584 } 585 }); 586 if (files.length > 0) { 587 requireEntry = { 588 files: files 589 }; 590 } 591 } else if (angular.isObject(requireEntry)) { 592 if (requireEntry.hasOwnProperty('name') && requireEntry['name']) { 593 // The dependency doesn't exist in the module cache and is a new configuration, so store and push it. 594 self.setModuleConfig(requireEntry); 595 moduleCache.push(requireEntry['name']); 596 } 597 } 598 599 // Check if the dependency has any files that need to be loaded. If there are, push a new promise to the promise list. 600 if (angular.isDefined(requireEntry.files) && requireEntry.files.length !== 0) { 601 if (angular.isDefined(self.filesLoader)) { 602 // if a files loader is defined 603 promisesList.push(self.filesLoader(requireEntry, localParams).then(function () { 604 return self._loadDependencies(requireEntry); 605 })); 606 } else { 607 return reject(new Error('Error: the module "' + requireEntry.name + '" is defined in external files (' + requireEntry.files + '), but no loader has been defined.')); 608 } 609 } 610 }); 611 612 // Create a wrapper promise to watch the promise list and resolve it once everything is done. 613 return $q.all(promisesList); 614 }, 615 616 /** 617 * Inject new modules into Angular 618 * @param moduleName 619 * @param localParams 620 * @param real 621 */ 622 inject: function inject(moduleName) { 623 var localParams = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 624 var real = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2]; 625 626 var self = this, 627 deferred = $q.defer(); 628 if (angular.isDefined(moduleName) && moduleName !== null) { 629 if (angular.isArray(moduleName)) { 630 var promisesList = []; 631 angular.forEach(moduleName, function (module) { 632 promisesList.push(self.inject(module, localParams, real)); 633 }); 634 return $q.all(promisesList); 635 } else { 636 self._addToLoadList(self._getModuleName(moduleName), true, real); 637 } 638 } 639 if (modulesToLoad.length > 0) { 640 var res = modulesToLoad.slice(); // clean copy 641 var loadNext = function loadNext(moduleName) {
642 moduleCache.push(moduleName); 643 modulePromises[moduleName] = deferred.promise; 644 self._loadDependencies(moduleName, localParams).then(function success() { 645 try { 646 justLoaded = []; 647 _register(providers, moduleCache, localParams); 648 } catch (e) { 649 self._$log.error(e.message); 650 deferred.reject(e); 651 return; 652 } 653 654 if (modulesToLoad.length > 0) { 655 loadNext(modulesToLoad.shift()); // load the next in list 656 } else { 657 deferred.resolve(res); // everything has been loaded, resolve 658 } 659 }, function error(err) { 660 deferred.reject(err); 661 }); 662 }; 663 664 // load the first in list 665 loadNext(modulesToLoad.shift()); 666 } else if (localParams && localParams.name && modulePromises[localParams.name]) { 667 return modulePromises[localParams.name]; 668 } else { 669 deferred.resolve(); 670 } 671 return deferred.promise; 672 }, 673 674 /** 675 * Get the list of required modules/services/... for this module 676 * @param module 677 * @returns {Array} 678 */ 679 getRequires: function getRequires(module) { 680 var requires = []; 681 angular.forEach(module.requires, function (requireModule) { 682 if (regModules.indexOf(requireModule) === -1) { 683 requires.push(requireModule); 684 } 685 }); 686 return requires; 687 }, 688 689 /** 690 * Invoke the new modules & component by their providers 691 * @param providers 692 * @param queue 693 * @param moduleName 694 * @param reconfig 695 * @private 696 */ 697 _invokeQueue: _invokeQueue, 698 699 /** 700 * Check if a module has been invoked and registers it if not 701 * @param args 702 * @param moduleName 703 * @returns {boolean} is new 704 */ 705 _registerInvokeList: _registerInvokeList, 706 707 /** 708 * Register a new module and loads it, executing the run/config blocks if needed 709 * @param providers 710 * @param registerModules 711 * @param params 712 * @private 713 */ 714 _register: _register, 715 716 /** 717 * Add a module name to the list of modules that will be loaded in the next inject 718 * @param name 719 * @param force 720 * @private 721 */ 722 _addToLoadList: _addToLoadList, 723 724 /** 725 * Unregister modules (you shouldn't have to use this) 726 * @param modules 727 */ 728 _unregister: function _unregister(modules) { 729 if (angular.isDefined(modules)) { 730 if (angular.isArray(modules)) { 731 angular.forEach(modules, function (module) { 732 regInvokes[module] = undefined; 733 }); 734 } 735 } 736 } 737 }; 738 }]; 739 740 // Let's get the list of loaded modules & components 741 this._init(angular.element(window.document)); 742 }]); 743 744 var bootstrapFct = angular.bootstrap; 745 angular.bootstrap = function (element, modules, config) { 746 // we use slice to make a clean copy 747 angular.forEach(modules.slice(), function (module) { 748 _addToLoadList(module, true, true); 749 }); 750 return bootstrapFct(element, modules, config); 751 }; 752 753 var _addToLoadList = function _addToLoadList(name, force, real) { 754 if ((recordDeclarations.length > 0 || force) && angular.isString(name) && modulesToLoad.indexOf(name) === -1) { 755 modulesToLoad.push(name); 756 if (real) { 757 realModules.push(name); 758 } 759 } 760 }; 761 762 var ngModuleFct = angular.module; 763 angular.module = function (name, requires, configFn) { 764 _addToLoadList(name, false, true); 765 return ngModuleFct(name, requires, configFn); 766 }; 767 768 // CommonJS package manager support: 769 if (typeof module !== 'undefined' && typeof exports !== 'undefined' && module.exports === exports) { 770 module.exports = 'oc.lazyLoad'; 771 } 772})(angular, window); 773(function (angular) { 774 'use strict'; 775 776 angular.module('oc.lazyLoad').directive('ocLazyLoad', ["$ocLazyLoad", "$compile", "$animate", "$parse", "$timeout", function ($ocLazyLoad, $compile, $animate, $parse, $timeout) { 777 return { 778 restrict: 'A', 779 terminal: true, 780 priority: 1000, 781 compile: function compile(element, attrs) { 782 // we store the content and remove it before compilation 783 var content = element[0].innerHTML; 784 element.html(''); 785 786 return function ($scope, $element, $attr) { 787 var model = $parse($attr.ocLazyLoad); 788 $scope.$watch(function () { 789 return model($scope) || $attr.ocLazyLoad; // it can be a module name (string), an object, an array, or a scope reference to any of this 790 }, function (moduleName) { 791 if (angular.isDefined(moduleName)) { 792 $ocLazyLoad.load(moduleName).then(function () { 793 // Attach element contents to DOM and then compile them. 794 // This prevents an issue where IE invali
794dates saved element objects (HTMLCollections) 795 // of the compiled contents when attaching to the parent DOM. 796 $animate.enter(content, $element); 797 // get the new content & compile it 798 $compile($element.contents())($scope); 799 }); 800 } 801 }, true); 802 }; 803 } 804 }; 805 }]); 806})(angular); 807(function (angular) { 808 'use strict'; 809 810 angular.module('oc.lazyLoad').config(["$provide", function ($provide) { 811 $provide.decorator('$ocLazyLoad', ["$delegate", "$q", "$window", "$interval", function ($delegate, $q, $window, $interval) { 812 var uaCssChecked = false, 813 useCssLoadPatch = false, 814 anchor = $window.document.getElementsByTagName('head')[0] || $window.document.getElementsByTagName('body')[0]; 815 816 /** 817 * Load a js/css file 818 * @param type 819 * @param path 820 * @param params 821 * @returns promise 822 */ 823 $delegate.buildElement = function buildElement(type, path, params) { 824 var deferred = $q.defer(), 825 el, 826 loaded, 827 filesCache = $delegate._getFilesCache(), 828 cacheBuster = function cacheBuster(url) { 829 var dc = new Date().getTime(); 830 if (url.indexOf('?') >= 0) { 831 if (url.substring(0, url.length - 1) === '&') { 832 return url + '_dc=' + dc; 833 } 834 return url + '&_dc=' + dc; 835 } else { 836 return url + '?_dc=' + dc; 837 } 838 }; 839 840 // Store the promise early so the file load can be detected by other parallel lazy loads 841 // (ie: multiple routes on one page) a 'true' value isn't sufficient 842 // as it causes false positive load results. 843 if (angular.isUndefined(filesCache.get(path))) { 844 filesCache.put(path, deferred.promise); 845 } 846 847 // Switch in case more content types are added later 848 switch (type) { 849 case 'css': 850 el = $window.document.createElement('link'); 851 el.type = 'text/css'; 852 el.rel = 'stylesheet'; 853 el.href = params.cache === false ? cacheBuster(path) : path; 854 break; 855 case 'js': 856 el = $window.document.createElement('script'); 857 el.src = params.cache === false ? cacheBuster(path) : path; 858 break; 859 default: 860 filesCache.remove(path); 861 deferred.reject(new Error('Requested type "' + type + '" is not known. Could not inject "' + path + '"')); 862 break; 863 } 864 el.onload = el['onreadystatechange'] = function (e) { 865 if (el['readyState'] && !/^c|loade/.test(el['readyState']) || loaded) return; 866 el.onload = el['onreadystatechange'] = null; 867 loaded = 1; 868 $delegate._broadcast('ocLazyLoad.fileLoaded', path); 869 deferred.resolve(); 870 }; 871 el.onerror = function () { 872 filesCache.remove(path); 873 deferred.reject(new Error('Unable to load ' + path)); 874 }; 875 el.async = params.serie ? 0 : 1; 876 877 var insertBeforeElem = anchor.lastChild; 878 if (params.insertBefore) { 879 var element = angular.element(angular.isDefined(window.jQuery) ? params.insertBefore : document.querySelector(params.insertBefore)); 880 if (element && element.length > 0) { 881 insertBeforeElem = element[0]; 882 } 883 } 884 insertBeforeElem.parentNode.insertBefore(el, insertBeforeElem); 885 886 /* 887 The event load or readystatechange doesn't fire in: 888 - iOS < 6 (default mobile browser) 889 - Android < 4.4 (default mobile browser) 890 - Safari < 6 (desktop browser) 891 */ 892 if (type == 'css') { 893 if (!uaCssChecked) { 894 var ua = $window.navigator.userAgent.toLowerCase(); 895 896 // iOS < 6 897 if (/iP(hone|od|ad)/.test($window.navigator.platform)) { 898 var v = $window.navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/); 899 var iOSVersion = parseFloat([parseInt(v[1], 10), parseInt(v[2], 10), parseInt(v[3] || 0, 10)].join('.')); 900 useCssLoadPatch = iOSVersion < 6; 901 } else if (ua.indexOf("android") > -1) { 902 // Android < 4.4 903 var androidVersion = parseFloat(ua.slice(ua.indexOf("android") + 8)); 904 useCssLoadPatch = androidVersion < 4.4; 905 } else if (ua.indexOf('safari') > -1) { 906 var versionMatch = ua.match(/version\/([\.\d]+)/i); 907 useCssLoadPatch = versionMatch && versionMatch[1] && parseFloat(versionMatch[1]) < 6; 908 } 909 } 910 911 if (useCssLoadPatch) { 912 var tries = 1000; // * 20 = 20000 miliseconds 913 var interval = $interval(function () { 914 try { 915 el.sheet.cssRules; 916 $interval.cancel(interval); 917 el.onload(); 918 } catch (e) { 919 if (--tries <= 0) { 920 el.onerror(); 921 } 922 } 923 }, 20); 924 } 925 } 926 927 return deferred.promise; 928 }; 929 930 return $delegate; 931 }]); 932 }]); 933})(angular); 934(function (angular) { 935 'use strict'; 936 937 angular.module('oc.lazyLoad').config(["$provide", function ($provide) { 938 $provide.decorator('$ocLazyLoad', ["$delegate", "$q", function ($delegate, $q) { 939 /** 940 * The function that loads new files 941 * @param config 942 * @param params 943 * @returns {*} 944 */ 945 $delegate.filesLoader = function filesLoader(config) { 946 var params = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 947 948 var cssFiles = [], 949 templatesFiles = [], 950 jsFiles = [], 951 promises = [], 952 cachePromise = null, 953 filesCache = $delegate._getFilesCache(); 954 955 $delegate.toggleWatch(true); // start watching angular.module calls 956 957 angular.extend(params, config); 958 959 var pushFile = function pushFile(path) { 960 var file_type = null, 961 m; 962 if (angular.isObject(path)) { 963 file_type = path.type; 964 path = path.path; 965 } 966 cachePromise = filesCache.get(path); 967 if (angular.isUndefined(cachePromise) || params.cache === false) { 968 969 // always check for requirejs syntax just in case 970 if ((m = /^(css|less|html|htm|js)?(?=!)/.exec(path)) !== null) { 971 // Detect file type using preceding type declaration (ala requireJS) 972 file_type = m[1]; 973 path = path.substr(m[1].length + 1, path.length); // Strip the type from the path 974 } 975 976 if (!file_type) { 977 if ((m = /[.](css|less|html|htm|js)?((\?|#).*)?$/.exec(path)) !== null) { 978 // Detect file type via file extension 979 file_type = m[1]; 980 } else if (!$delegate.jsLoader.hasOwnProperty('ocLazyLoadLoader') && $delegate.jsLoader.hasOwnProperty('requirejs')) { 981 // requirejs 982 file_type = 'js'; 983 } else { 984 $delegate._$log.error('File type could not be determined. ' + path); 985 return; 986 } 987 } 988 989 if ((file_type === 'css' || file_type === 'less') && cssFiles.indexOf(path) === -1) { 990 cssFiles.push(path); 991 } else if ((file_type === 'html' || file_type === 'htm') && templatesFiles.indexOf(path) === -1) { 992 templatesFiles.push(path); 993 } else if (file_type === 'js' || jsFiles.indexOf(path) === -1) { 994 jsFiles.push(path); 995 } else { 996 $delegate._$log.error('File type is not val
996id. ' + path); 997 } 998 } else if (cachePromise) { 999 promises.push(cachePromise); 1000 } 1001 }; 1002 1003 if (params.serie) { 1004 pushFile(params.files.shift()); 1005 } else { 1006 angular.forEach(params.files, function (path) { 1007 pushFile(path); 1008 }); 1009 } 1010 1011 if (cssFiles.length > 0) { 1012 var cssDeferred = $q.defer(); 1013 $delegate.cssLoader(cssFiles, function (err) { 1014 if (angular.isDefined(err) && $delegate.cssLoader.hasOwnProperty('ocLazyLoadLoader')) { 1015 $delegate._$log.error(err); 1016 cssDeferred.reject(err); 1017 } else { 1018 cssDeferred.resolve(); 1019 } 1020 }, params); 1021 promises.push(cssDeferred.promise); 1022 } 1023 1024 if (templatesFiles.length > 0) { 1025 var templatesDeferred = $q.defer(); 1026 $delegate.templatesLoader(templatesFiles, function (err) { 1027 if (angular.isDefined(err) && $delegate.templatesLoader.hasOwnProperty('ocLazyLoadLoader')) { 1028 $delegate._$log.error(err); 1029 templatesDeferred.reject(err); 1030 } else { 1031 templatesDeferred.resolve(); 1032 } 1033 }, params); 1034 promises.push(templatesDeferred.promise); 1035 } 1036 1037 if (jsFiles.length > 0) { 1038 var jsDeferred = $q.defer(); 1039 $delegate.jsLoader(jsFiles, function (err) { 1040 if (angular.isDefined(err) && ($delegate.jsLoader.hasOwnProperty("ocLazyLoadLoader") || $delegate.jsLoader.hasOwnProperty("requirejs"))) { 1041 $delegate._$log.error(err); 1042 jsDeferred.reject(err); 1043 } else { 1044 jsDeferred.resolve(); 1045 } 1046 }, params); 1047 promises.push(jsDeferred.promise); 1048 } 1049 1050 if (promises.length === 0) { 1051 var deferred = $q.defer(), 1052 err = "Error: no file to load has been found, if you're trying to load an existing module you should use the 'inject' method instead of 'load'."; 1053 $delegate._$log.error(err); 1054 deferred.reject(err); 1055 return deferred.promise; 1056 } else if (params.serie && params.files.length > 0) { 1057 return $q.all(promises).then(function () { 1058 return $delegate.filesLoader(config, params); 1059 }); 1060 } else { 1061 return $q.all(promises)['finally'](function (res) { 1062 $delegate.toggleWatch(false); // stop watching angular.module calls 1063 return res; 1064 }); 1065 } 1066 }; 1067 1068 /** 1069 * Load a module or a list of modules into Angular 1070 * @param module Mixed the name of a predefined module config object, or a module config object, or an array of either 1071 * @param params Object optional parameters 1072 * @returns promise 1073 */ 1074 $delegate.load = function (originalModule) { 1075 var originalParams = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; 1076 1077 var self = this, 1078 config = null, 1079 deferredList = [], 1080 deferred = $q.defer(), 1081 errText; 1082 1083 // clean copy 1084 var module = angular.copy(originalModule); 1085 var params = angular.copy(originalParams); 1086 1087 // If module is an array, break it down 1088 if (angular.isArray(module)) {
1089 // Resubmit each entry as a single module 1090 angular.forEach(module, function (m) { 1091 deferredList.push(self.load(m, params)); 1092 }); 1093 1094 // Resolve the promise once everything has loaded 1095 $q.all(deferredList).then(function (res) { 1096 deferred.resolve(res); 1097 }, function (err) { 1098 deferred.reject(err); 1099 }); 1100 1101 return deferred.promise; 1102 } 1103 1104 // Get or Set a configuration depending on what was passed in 1105 if (angular.isString(module)) { 1106 config = self.getModuleConfig(module); 1107 if (!config) { 1108 config = { 1109 files: [module] 1110 }; 1111 } 1112 } else if (angular.isObject(module)) { 1113 // case {type: 'js', path: lazyLoadUrl + 'testModule.fakejs'} 1114 if (angular.isDefined(module.path) && angular.isDefined(module.type)) { 1115 config = { 1116 files: [module] 1117 }; 1118 } else { 1119 config = self.setModuleConfig(module); 1120 } 1121 } 1122 1123 if (config === null) { 1124 var moduleName = self._getModuleName(module); 1125 errText = 'Module "' + (moduleName || 'unknown') + '" is not configured, cannot load.'; 1126 $delegate._$log.error(errText); 1127 deferred.reject(new Error(errText)); 1128 return deferred.promise; 1129 } else { 1130 // deprecated 1131 if (angular.isDefined(config.template)) { 1132 if (angular.isUndefined(config.files)) { 1133 config.files = []; 1134 } 1135 if (angular.isString(config.template)) { 1136 config.files.push(config.template); 1137 } else if (angular.isArray(config.template)) { 1138 config.files.concat(config.template); 1139 } 1140 } 1141 } 1142 1143 var localParams = angular.extend({}, params, config); 1144 1145 // if someone used an external loader and called the load function with just the module name 1146 if (angular.isUndefined(config.files) && angular.isDefined(config.name) && $delegate.moduleExists(config.name)) { 1147 return $delegate.inject(config.name, localParams, true); 1148 } 1149 1150 $delegate.filesLoader(config, localParams).then(function () { 1151 $delegate.inject(null, localParams).then(function (res) { 1152 deferred.resolve(res); 1153 }, function (err) { 1154 deferred.reject(err); 1155 }); 1156 }, function (err) { 1157 deferred.reject(err); 1158 }); 1159 1160 return deferred.promise; 1161 }; 1162 1163 // return the patched service 1164 return $delegate; 1165 }]); 1166 }]); 1167})(angular); 1168(function (angular) { 1169 'use strict'; 1170 1171 angular.module('oc.lazyLoad').config(["$provide", function ($provide) { 1172 $provide.decorator('$ocLazyLoad', ["$delegate", "$q", function ($delegate, $q) { 1173 /** 1174 * cssLoader function 1175 * @type Function 1176 * @param paths array list of css files to load 1177 * @param callback to call when everything is loaded. We use a callback and not a promise 1178 * @param params object config parameters 1179 * because the user can overwrite cssLoader and it will probably not use promises :( 1180 */ 1181 $delegate.cssLoader = function (paths, callback, params) { 1182 var promises = []; 1183 angular.forEach(paths, function (path) { 1184 promises.push($delegate.buildElement('css', path, params)); 1185 }); 1186 $q.all(promises).then(function () { 1187 callback(); 1188 }, function (err) { 1189 callback(err); 1190 }); 1191 }; 1192 $delegate.cssLoader.ocLazyLoadLoader = true; 1193 1194 return $delegate; 1195 }]); 1196 }]); 1197})(angular); 1198(function (angular) { 1199 'use strict'; 1200 1201 angular.module('oc.lazyLoad').config(["$provide", function ($provide) { 1202 $provide.decorator('$ocLazyLoad', ["$delegate", "$q", function ($delegate, $q) { 1203 /** 1204 * jsLoader function 1205 * @type Function 1206 * @param paths array list of js files to load 1207 * @param callback to call when everything is loaded. We use a callback and not a promise
1208 * @param params object config parameters 1209 * because the user can overwrite jsLoader and it will probably not use promises :( 1210 */ 1211 $delegate.jsLoader = function (paths, callback, params) { 1212 var promises = []; 1213 angular.forEach(paths, function (path) { 1214 promises.push($delegate.buildElement('js', path, params)); 1215 }); 1216 $q.all(promises).then(function () { 1217 callback(); 1218 }, function (err) { 1219 callback(err); 1220 }); 1221 }; 1222 $delegate.jsLoader.ocLazyLoadLoader = true; 1223 1224 return $delegate; 1225 }]); 1226 }]); 1227})(angular); 1228(function (angular) { 1229 'use strict'; 1230 1231 angular.module('oc.lazyLoad').config(["$provide", function ($provide) { 1232 $provide.decorator('$ocLazyLoad', ["$delegate", "$templateCache", "$q", "$http", function ($delegate, $templateCache, $q, $http) { 1233 /** 1234 * templatesLoader function 1235 * @type Function 1236 * @param paths array list of css files to load 1237 * @param callback to call when everything is loaded. We use a callback and not a promise 1238 * @param params object config parameters for $http 1239 * because the user can overwrite templatesLoader and it will probably not use promises :( 1240 */ 1241 $delegate.templatesLoader = function (paths, callback, params) { 1242 var promises = [], 1243 filesCache = $delegate._getFilesCache(); 1244 1245 angular.forEach(paths, function (url) { 1246 var deferred = $q.defer(); 1247 promises.push(deferred.promise); 1248 $http.get(url, params).success(function (data) { 1249 if (angular.isString(data) && data.length > 0) { 1250 angular.forEach(angular.element(data), function (node) { 1251 if (node.nodeName === 'SCRIPT' && node.type === 'text/ng-template') { 1252 $templateCache.put(node.id, node.innerHTML); 1253 } 1254 }); 1255 } 1256 if (angular.isUndefined(filesCache.get(url))) { 1257 filesCache.put(url, true); 1258 } 1259 deferred.resolve(); 1260 }).error(function (err) { 1261 deferred.reject(new Error('Unable to load template file "' + url + '": ' + err)); 1262 }); 1263 }); 1264 return $q.all(promises).then(function () { 1265 callback(); 1266 }, function (err) { 1267 callback(err); 1268 }); 1269 }; 1270 $delegate.templatesLoader.ocLazyLoadLoader = true; 1271 1272 return $delegate; 1273 }]); 1274 }]); 1275})(angular); 1276// Array.indexOf polyfill for IE8 1277if (!Array.prototype.indexOf) { 1278 Array.prototype.indexOf = function (searchElement, fromIndex) { 1279 var k; 1280 1281 // 1. Let O be the result of calling ToObject passing 1282 // the this value as the argument. 1283 if (this == null) { 1284 throw new TypeError('"this" is null or not defined'); 1285 } 1286 1287 var O = Object(this); 1288 1289 // 2. Let lenValue be the result of calling the Get 1290 // internal method of O with the argument "length". 1291 // 3. Let len be ToUint32(lenValue). 1292 var len = O.length >>> 0; 1293 1294 // 4. If len is 0, return -1. 1295 if (len === 0) { 1296 return -1; 1297 } 1298 1299 // 5. If argument fromIndex was passed let n be 1300 // ToInteger(fromIndex); else let n be 0. 1301 var n = +fromIndex || 0; 1302 1303 if (Math.abs(n) === Infinity) { 1304 n = 0; 1305 } 1306 1307 // 6. If n >= len, return -1. 1308 if (n >= len) { 1309 return -1; 1310 } 1311 1312 // 7. If n >= 0, then Let k be n. 1313 // 8. Else, n<0, Let k be len - abs(n). 1314 // If k is less than 0, then let k be 0. 1315 k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); 1316 1317 // 9. Repeat, while k < len 1318 while (k < len) { 1319 // a. Let Pk be ToString(k). 1320 // This is implicit for LHS operands of the in operator
1321 // b. Let kPresent be the result of calling the 1322 // HasProperty internal method of O with argument Pk. 1323 // This step can be combined with c 1324 // c. If kPresent is true, then 1325 // i. Let elementK be the result of calling the Get 1326 // internal method of O with the argument ToString(k). 1327 // ii. Let same be the result of applying the 1328 // Strict Equality Comparison Algorithm to 1329 // searchElement and elementK. 1330 // iii. If same is true, return k. 1331 if (k in O && O[k] === searchElement) { 1332 return k; 1333 } 1334 k++; 1335 } 1336 return -1; 1337 }; 1338}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.