diff options
| author | Misko Hevery | 2012-01-06 18:10:47 -0800 | 
|---|---|---|
| committer | Misko Hevery | 2012-01-10 22:27:00 -0800 | 
| commit | 5143e7bf065a3cbdf8400cf095b653d51bc83b8f (patch) | |
| tree | 980149c365d4cb5586d27975d26366a25ff7be6a /src | |
| parent | afd25446d23f24872eb20ac79c8fbd2cff203ef0 (diff) | |
| download | angular.js-5143e7bf065a3cbdf8400cf095b653d51bc83b8f.tar.bz2 | |
feat(module): new module loader
Diffstat (limited to 'src')
| -rw-r--r-- | src/Angular.js | 120 | ||||
| -rw-r--r-- | src/AngularPublic.js | 80 | ||||
| -rw-r--r-- | src/Injector.js | 48 | ||||
| -rw-r--r-- | src/angular-bootstrap.js | 9 | ||||
| -rw-r--r-- | src/angular-mocks.js | 63 | ||||
| -rw-r--r-- | src/angular.suffix | 4 | ||||
| -rw-r--r-- | src/directives.js | 27 | ||||
| -rw-r--r-- | src/loader.js | 167 | ||||
| -rw-r--r-- | src/loader.prefix | 7 | ||||
| -rw-r--r-- | src/loader.suffix | 20 | ||||
| -rw-r--r-- | src/scenario/Application.js | 12 | ||||
| -rw-r--r-- | src/scenario/angular.suffix | 12 | 
12 files changed, 393 insertions, 176 deletions
| diff --git a/src/Angular.js b/src/Angular.js index c14c6ea0..74443bd1 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -90,7 +90,7 @@ var $$scope           = '$scope',      /** @name angular */      angular           = window.angular || (window.angular = {}), -    angularModule     = angular.module || (angular.module  = {}), +    angularModule     = null,      /** @name angular.markup */      angularTextMarkup = extensionMap(angular, 'markup'),      /** @name angular.attrMarkup */ @@ -174,6 +174,15 @@ function forEachSorted(obj, iterator, context) {  /** + * when using forEach the params are value, key, but it is often useful to have key, value. + * @param {function(string, *)} iteratorFn + * @returns {function(*, string)} + */ +function reverseParams(iteratorFn) { +  return function(value, key) { iteratorFn(key, value) }; +} + +/**   * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric   * characters such as '012ABC'. The reason why we are not using simply a number counter is that   * the number string gets longer over time, and it can also overflow, where as the the nextId @@ -808,37 +817,73 @@ function encodeUriQuery(val, pctEncodeSpaces) {  /**   * @ngdoc directive - * @name angular.directive.ng:autobind - * @element script + * @name angular.directive.ng:app   * - * @TODO ng:autobind is not a directive!! it should be documented as bootstrap parameter in a - *     separate bootstrap section. - * @TODO rename to ng:autobind to ng:autoboot + * @element ANY + * @param {angular.Module} module on optional application + *   {@link angular.module module} name to load.   *   * @description - * Technically, ng:autobind is not a directive; it is an Angular bootstrap parameter that can act - * as a directive. It must exist in the script used to boot Angular and can be used only one time. - * For details on bootstrapping Angular, see {@link guide/dev_guide.bootstrap Initializing Angular} - * in the Angular Developer Guide.   * - * `ng:autobind` with no parameters tells Angular to compile and manage the whole page. + * Use this directive to auto-bootstrap on application. Only + * one directive can be used per HTML document. The directive + * designates the root of the application and is typically placed + * ot the root of the page. + * + * In the example below if the `ng:app` directive would not be placed + * on the `html` element then the document would not be compiled + * and the `{{ 1+2 }}` would not be resolved to `3`.   * - * `ng:autobind="[root element ID]"` tells Angular to compile and manage part of the document, - * starting at "root element ID". + * `ng:app` is the easiest way to bootstrap an application. + * + <doc:example> +   <doc:source> +    I can add: 1 + 2 =  {{ 1+2 }} +   </doc:source> + </doc:example>   *   */ -function angularInit(config, document){ -  var autobind = config.autobind; -   -  if (autobind) { -    var modules = []; -    forEach((config.modules || '').split(','), function(module){ -      module = trim(module); -      if (module) { -        modules.push(module); +function angularInit(element, bootstrap) { +  var elements = [element], +      appElement, +      module, +      names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'], +      NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/; + +  function append(element) { +    element && elements.push(element); +  } + +  forEach(names, function(name) { +    names[name] = true; +    append(document.getElementById(name)); +    name = name.replace(':', '\\:'); +    if (element.querySelectorAll) { +      forEach(element.querySelectorAll('.' + name), append); +      forEach(element.querySelectorAll('.' + name + '\\:'), append); +      forEach(element.querySelectorAll('[' + name + ']'), append); +    }; +  }); + +  forEach(elements, function(element) { +    if (!appElement) { +      var className = ' ' + element.className + ' '; +      var match = NG_APP_CLASS_REGEXP.exec(className); +      if (match) { +        appElement = element; +        module = (match[2] || '').replace(/\s+/g, ','); +      } else { +        forEach(element.attributes, function(attr) { +          if (!appElement && names[attr.name]) { +            appElement = element; +            module = attr.value; +          } +        });        } -    }); -    bootstrap(jqLite(isString(autobind) ? document.getElementById(autobind) : document), modules); +    } +  }); +  if (appElement) { +    bootstrap(appElement, module ? [module] : []);    }  } @@ -854,9 +899,10 @@ function angularInit(config, document){   * @param {Array<String,function>=} modules an array of module declarations. See: {@link angular.module modules}   */  function bootstrap(element, modules) { +  element = jqLite(element);    modules = modules || []; -  modules.unshift(ngModule); -  createInjector(modules, angularModule).invoke(null, +  modules.unshift('ng'); +  createInjector(modules).invoke(null,      ['$rootScope', '$compile', '$injector', function(scope, compile, injector){        scope.$apply(function() {          element.data('$injector', injector); @@ -866,28 +912,6 @@ function bootstrap(element, modules) {    );  } -function angularJsConfig(document) { -  bindJQuery(); -  var scripts = document.getElementsByTagName('script'), -      script = scripts[scripts.length-1], -      scriptSrc = script.src, -      config = {}, -      hashPos; - -  hashPos = scriptSrc.indexOf('#'); -  if (hashPos != -1) extend(config, parseKeyValue(scriptSrc.substr(hashPos+1))); - -  eachAttribute(jqLite(script), function(value, name){ -    if (/^ng:/.exec(name)) { -      name = name.substring(3).replace(/-/g, '_'); -      value = value || true; -      config[name] = value; -    } -  }); - -  return config; -} -  function bindJQuery() {    // bind to jQuery if present;    jQuery = window.jQuery; diff --git a/src/AngularPublic.js b/src/AngularPublic.js index 7664ed8c..ef3d3ccb 100644 --- a/src/AngularPublic.js +++ b/src/AngularPublic.js @@ -30,7 +30,7 @@ function publishExternalAPI(angular){      'equals': equals,      'element': jqLite,      'forEach': forEach, -    'injector': function(){ return createInjector(arguments, angularModule); }, +    'injector': function(){ return createInjector(arguments); },      'noop':noop,      'bind':bind,      'toJson': toJson, @@ -51,46 +51,46 @@ function publishExternalAPI(angular){      'callbacks': {counter: 0}    }); -  angularModule.ng = ngModule; -} - -ngModule.$inject = ['$provide', '$injector']; -function ngModule($provide, $injector) { -// TODO(misko): temporary services to get the compiler working; -  $provide.value('$textMarkup', angularTextMarkup); -  $provide.value('$attrMarkup', angularAttrMarkup); -  $provide.value('$directive', angularDirective); -  $provide.value('$widget', angularWidget); +  angularModule = setupModuleLoader(window); +  try { +    angularModule('ngLocale'); +  } catch (e) { +    angularModule('ngLocale', []).service('$locale', $LocaleProvider); +  } -  // load the LOCALE if present -  $injector.invoke(null, angularModule.ngLocale || function(){ -    $provide.service('$locale', $LocaleProvider); -  }); +  angularModule('ng', ['ngLocale'], ['$provide', '$injector', +    function ngModule($provide, $injector) { +    // TODO(misko): temporary services to get the compiler working; +      $provide.value('$textMarkup', angularTextMarkup); +      $provide.value('$attrMarkup', angularAttrMarkup); +      $provide.value('$directive', angularDirective); +      $provide.value('$widget', angularWidget); -  $provide.service('$autoScroll', $AutoScrollProvider); -  $provide.service('$browser', $BrowserProvider); -  $provide.service('$cacheFactory', $CacheFactoryProvider); -  $provide.service('$compile', $CompileProvider); -  $provide.service('$cookies', $CookiesProvider); -  $provide.service('$cookieStore', $CookieStoreProvider); -  $provide.service('$defer', $DeferProvider); -  $provide.service('$document', $DocumentProvider); -  $provide.service('$exceptionHandler', $ExceptionHandlerProvider); -  $provide.service('$filter', $FilterProvider); -  $provide.service('$interpolate', $InterpolateProvider); -  $provide.service('$formFactory', $FormFactoryProvider); -  $provide.service('$http', $HttpProvider); -  $provide.service('$httpBackend', $HttpBackendProvider); -  $provide.service('$location', $LocationProvider); -  $provide.service('$log', $LogProvider); -  $provide.service('$parse', $ParseProvider); -  $provide.service('$resource', $ResourceProvider); -  $provide.service('$route', $RouteProvider); -  $provide.service('$routeParams', $RouteParamsProvider); -  $provide.service('$rootScope', $RootScopeProvider); -  $provide.service('$q', $QProvider); -  $provide.service('$sniffer', $SnifferProvider); -  $provide.service('$templateCache', $TemplateCacheProvider); -  $provide.service('$window', $WindowProvider); +      $provide.service('$autoScroll', $AutoScrollProvider); +      $provide.service('$browser', $BrowserProvider); +      $provide.service('$cacheFactory', $CacheFactoryProvider); +      $provide.service('$compile', $CompileProvider); +      $provide.service('$cookies', $CookiesProvider); +      $provide.service('$cookieStore', $CookieStoreProvider); +      $provide.service('$defer', $DeferProvider); +      $provide.service('$document', $DocumentProvider); +      $provide.service('$exceptionHandler', $ExceptionHandlerProvider); +      $provide.service('$filter', $FilterProvider); +      $provide.service('$interpolate', $InterpolateProvider); +      $provide.service('$formFactory', $FormFactoryProvider); +      $provide.service('$http', $HttpProvider); +      $provide.service('$httpBackend', $HttpBackendProvider); +      $provide.service('$location', $LocationProvider); +      $provide.service('$log', $LogProvider); +      $provide.service('$parse', $ParseProvider); +      $provide.service('$resource', $ResourceProvider); +      $provide.service('$route', $RouteProvider); +      $provide.service('$routeParams', $RouteParamsProvider); +      $provide.service('$rootScope', $RootScopeProvider); +      $provide.service('$q', $QProvider); +      $provide.service('$sniffer', $SnifferProvider); +      $provide.service('$templateCache', $TemplateCacheProvider); +      $provide.service('$window', $WindowProvider); +    }]);  } diff --git a/src/Injector.js b/src/Injector.js index 517e3e00..8326d645 100644 --- a/src/Injector.js +++ b/src/Injector.js @@ -201,7 +201,7 @@ function inferInjectionArgs(fn) {   *   * @param {string} name The name of the instance. NOTE: the provider will be available under `name + 'Provide'` key.   * @param {(Object|function())} provider If the provider is: - *  + *   *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using   *               {@link angular.module.AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.   *   - `Constructor`: a new instance of the provider will be created using @@ -237,11 +237,12 @@ function inferInjectionArgs(fn) {   */ -function createInjector(modulesToLoad, moduleRegistry) { +function createInjector(modulesToLoad) {    var cache = {},        providerSuffix = 'Provider',        path = [], -      $injector; +      $injector, +      loadedModules = new HashMap();    value('$injector', $injector = {      get: getService, @@ -249,24 +250,34 @@ function createInjector(modulesToLoad, moduleRegistry) {      instantiate: instantiate    });    value('$provide', { -    service: service, -    factory: factory, -    value: value, +    service: supportObject(service), +    factory: supportObject(factory), +    value: supportObject(value),      decorator: decorator    }); -  loadModule(modulesToLoad); +  loadModules(modulesToLoad);    return $injector;    //////////////////////////////////// +  function supportObject(delegate) { +    return function(key, value) { +      if (isObject(key)) { +        forEach(key, reverseParams(delegate)); +      } else { +        delegate(key, value); +      } +    } +  } +    function service(name, provider) {      if (isFunction(provider)){        provider = instantiate(provider);      }      if (!provider.$get) { -      throw Error('Providers must define $get factory method.'); +      throw Error('Provider ' + name + ' must define $get factory method.');      }      cache['#' + name + providerSuffix] = provider;    } @@ -362,16 +373,21 @@ function createInjector(modulesToLoad, moduleRegistry) {      return invoke(instance, Type, locals) || instance;    } -  function loadModule(modulesToLoad){ -    forEach(isString(modulesToLoad) ? modulesToLoad.split(',') : modulesToLoad, function(module) { +  function loadModules(modulesToLoad){ +    forEach(modulesToLoad, function(module) { +      if (loadedModules.get(module)) return; +      loadedModules.put(module, true);        if (isString(module)) { -        if (moduleRegistry[module = trim(module)]) { -          module = moduleRegistry[module]; -        } else { -          throw Error("Module '" + module + "' is not defined!"); +        module = angularModule(module); +        loadModules(module.requires); + +        for(var invokeQueue = module.invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) { +          var invokeArgs = invokeQueue[i], +              service = getService(invokeArgs[0]); + +          service[invokeArgs[1]].apply(service, invokeArgs[2]);          } -      } -      if (isFunction(module) || isArray(module)) { +      } else if (isFunction(module) || isArray(module)) {          invoke(null, module);        } else {          assertArgFn(module, 'module'); diff --git a/src/angular-bootstrap.js b/src/angular-bootstrap.js index 169a1d5a..778eee6b 100644 --- a/src/angular-bootstrap.js +++ b/src/angular-bootstrap.js @@ -9,18 +9,11 @@    var filename = /^(.*\/)angular-bootstrap.js(#.*)?$/,        scripts = document.getElementsByTagName("SCRIPT"), -      autobind = scripts[scripts.length-1].getAttribute('ng:autobind'),        config,        serverPath,        match,        globalVars = {}; -  if (autobind) { -    config = {autobind: autobind}; -  } else { -    config = (autobind == '') ? {autobind: true} : {} -  } -    for(var j = 0; j < scripts.length; j++) {      match = (scripts[j].src || "").match(filename);      if (match) { @@ -109,7 +102,7 @@      bindJQuery(); -    angularInit(config, document); +    angularInit(document, angular.bootstrap);    }    if (window.addEventListener) { diff --git a/src/angular-mocks.js b/src/angular-mocks.js index cc7f63a8..62a37763 100644 --- a/src/angular-mocks.js +++ b/src/angular-mocks.js @@ -5,25 +5,14 @@   * License: MIT   */ - -window.angular = window.angular || {}; -angular.module = angular.module || {}; -  /**   * @ngdoc overview - * @name angular.module.ngMock + * @name angular.mock   * @description   * - * The `ngMock` is an angular module which is used with `ng` module and adds unit-test configuration as well as useful - * mocks to the {@link angular.module.AUTO.$injector $injector}. + * Namespace from 'angular-mocks.js' which contains testing related code.   */ -angular.module.ngMock = function($provide){ -  $provide.service('$browser', angular.module.ngMock.$BrowserProvider); -  $provide.service('$exceptionHandler', angular.module.ngMock.$ExceptionHandlerProvider); -  $provide.service('$log', angular.module.ngMock.$LogProvider); -  $provide.decorator('$httpBackend', angular.module.ngMock.$httpBackendDecorator); -}; -angular.module.ngMock.$inject = ['$provide']; +angular.mock = {};  /**   * @ngdoc object @@ -42,12 +31,12 @@ angular.module.ngMock.$inject = ['$provide'];   * - $browser.defer — enables testing of code that uses   *   {@link angular.module.ng.$defer $defer} for executing functions via the `setTimeout` api.   */ -angular.module.ngMock.$BrowserProvider = function(){ +angular.mock.$BrowserProvider = function(){    this.$get = function(){ -    return new angular.module.ngMock.$Browser(); +    return new angular.mock.$Browser();    };  }; -angular.module.ngMock.$Browser = function() { +angular.mock.$Browser = function() {    var self = this;    this.isMock = true; @@ -153,7 +142,7 @@ angular.module.ngMock.$Browser = function() {      return script;    };  } -angular.module.ngMock.$Browser.prototype = { +angular.mock.$Browser.prototype = {  /**    * @name angular.module.ngMock.$browser#poll @@ -226,7 +215,7 @@ angular.module.ngMock.$Browser.prototype = {   * information.   */ -angular.module.ngMock.$ExceptionHandlerProvider = function(){ +angular.mock.$ExceptionHandlerProvider = function(){    var handler;    /** @@ -284,7 +273,7 @@ angular.module.ngMock.$ExceptionHandlerProvider = function(){   * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`.   *   */ -angular.module.ngMock.$LogProvider = function(){ +angular.mock.$logProvider = function(){    function concat(array1, array2, index) {      return array1.concat(Array.prototype.slice.call(array2, index)); @@ -379,7 +368,7 @@ angular.module.ngMock.$LogProvider = function(){  /**   * @ngdoc object - * @name angular.module.ngMock.TzDate + * @name angular.mock.TzDate   * @description   *   * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`. @@ -413,7 +402,7 @@ angular.module.ngMock.$LogProvider = function(){   * </pre>   *   */ -angular.module.ngMock.TzDate = function (offset, timestamp) { +angular.mock.TzDate = function (offset, timestamp) {    var self = new Date(0);    if (angular.isString(timestamp)) {      var tsStr = timestamp; @@ -516,12 +505,12 @@ angular.module.ngMock.TzDate = function (offset, timestamp) {  }  //make "tzDateInstance instanceof Date" return true -angular.module.ngMock.TzDate.prototype = Date.prototype; +angular.mock.TzDate.prototype = Date.prototype;  /**   * @ngdoc function - * @name angular.module.ngMock.debug + * @name angular.mock.debug   * @description   *   * *NOTE*: this is not an injectable instance, just a globally available function. @@ -533,7 +522,7 @@ angular.module.ngMock.TzDate.prototype = Date.prototype;   * @param {*} object - any object to turn into string.   * @return a serialized string of the argument   */ -angular.module.ngMock.dump = function(object){ +angular.mock.dump = function(object){    return serialize(object);    function serialize(object) { @@ -593,7 +582,7 @@ angular.module.ngMock.dump = function(object){   * respond with static or dynamic responses via the `expect` and `when` apis and their shortcuts   * (`expectGET`, `whenPOST`, etc).   */ -angular.module.ngMock.$httpBackendDecorator = function($delegate, $defer) { +angular.mock.$httpBackendDecorator = function($delegate, $defer) {    var definitions = [],        expectations = [],        responses = [], @@ -836,6 +825,24 @@ function MockXhr() {    this.abort = angular.noop;  } +/** + * @ngdoc overview + * @name angular.module.ngMock + * @description + * + * The `ngMock` is an angular module which is used with `ng` module and adds unit-test configuration as well as useful + * mocks to the {@link angular.module.AUTO.$injector $injector}. + */ +angular.module('ngMock', ['ng']).service({ +  '$browser': angular.mock.$BrowserProvider, +  '$exceptionHandler': angular.mock.$ExceptionHandlerProvider, +  '$log': angular.mock.$logProvider +}).init(function($provide) { +  $provide.decorator('$httpBackend', angular.mock.$httpBackendDecorator); +}); + + +  window.jstestdriver && (function(window){    /**     * Global method to output any number of objects into JSTD console. Useful for debugging. @@ -843,7 +850,7 @@ window.jstestdriver && (function(window){    window.dump = function() {      var args = [];      angular.forEach(arguments, function(arg){ -      args.push(angular.module.ngMock.dump(arg)); +      args.push(angular.mock.dump(arg));      });      jstestdriver.console.log.apply(jstestdriver.console, args);    }; @@ -852,7 +859,7 @@ window.jstestdriver && (function(window){  /**   * @ngdoc function - * @name angular.module.ngMock.inject + * @name angular.mock.inject   * @description   *   * *NOTE*: this is not an injectable instance, just a globally available function on window. diff --git a/src/angular.suffix b/src/angular.suffix index 99726fbd..44cddef3 100644 --- a/src/angular.suffix +++ b/src/angular.suffix @@ -4,10 +4,8 @@    publishExternalAPI(angular); -  var config = angularJsConfig(document); -    jqLiteWrap(document).ready(function() { -    angularInit(config, document); +    angularInit(document, bootstrap);    });  })(window, document); diff --git a/src/directives.js b/src/directives.js index 17dd1531..6e565b83 100644 --- a/src/directives.js +++ b/src/directives.js @@ -9,33 +9,6 @@   * behavior of the element in which it is specified. Do not use directives to add elements to the   * DOM; instead, use {@link angular.widget widgets} to add DOM elements.   * - * Following is the list of built-in Angular directives: - * - * * {@link angular.directive.ng:autobind ng:autobind} - An Angular bootstrap parameter that can - * act as a directive. - * * {@link angular.directive.ng:bind ng:bind} - Creates a data-binding between an HTML text value - * and a data model. - * * {@link angular.directive.ng:bind-attr ng:bind-attr} - Creates a data-binding in a way similar - * to `ng:bind`, but uses JSON key / value pairs to do so. - * * {@link angular.directive.ng:bind-template ng:bind-template} - Replaces the text value of an - * element with a specified template. - * * {@link angular.directive.ng:class ng:class} - Conditionally set a CSS class on an element. - * * {@link angular.directive.ng:class-even ng:class-even} - Like `ng:class`, but works in - * conjunction with {@link angular.widget.@ng:repeat} to affect even rows in a collection. - * * {@link angular.directive.ng:class-odd ng:class-odd} - Like `ng:class`, but works with {@link - * angular.widget.@ng:repeat}  to affect odd rows. - * * {@link angular.directive.ng:click ng:click} - Executes custom behavior when an element is - * clicked. - * * {@link angular.directive.ng:controller ng:controller} - Creates a scope object linked to the - * DOM element and assigns behavior to the scope. - * * {@link angular.directive.ng:hide ng:hide} - Conditionally hides a portion of HTML. - * * {@link angular.directive.ng:href ng:href} - Places an href in the Angular namespace. - * * {@link angular.directive.ng:init} - Initialization tasks run before a template is executed. - * * {@link angular.directive.ng:show ng:show} - Conditionally displays a portion of HTML. - * * {@link angular.directive.ng:src ng:src} - Places a `src` attribute into the Angular namespace. - * * {@link angular.directive.ng:style ng:style} - Conditionally set CSS styles on an element. - * * {@link angular.directive.ng:submit} - Binds Angular expressions to `onSubmit` events. - *   * For more information about how Angular directives work, and to learn how to create your own   * directives, see {@link guide/dev_guide.compiler.directives Understanding Angular Directives} in   * the Angular Developer Guide. diff --git a/src/loader.js b/src/loader.js new file mode 100644 index 00000000..ec30ad9a --- /dev/null +++ b/src/loader.js @@ -0,0 +1,167 @@ +'use strict'; + +/** + * @ngdoc interface + * @name angular.Module + * @description + * + * Interface for configuring angular {@link angular.module modules}. + */ + +function setupModuleLoader(window) { + +  function ensure(obj, name, factory) { +    return obj[name] || (obj[name] = factory()); +  } + +  return ensure(ensure(window, 'angular', Object), 'module', function() { +    /** @type {Object.<string, angular.Module>} */ +    var modules = {}; + +    /** +     * @ngdoc function +     * @name angular.module +     * @description +     * +     * The `angular.module` is a global place for registering angular modules. All modules +     * (angular core or 3rd party) that should be available to an application must be registered using this mechanism. +     * +     * # Module +     * +     * A module is a collocation of services, directives, filters, and configure information. Module is used to configure the, +     * {@link angular.module.AUTO.$injector $injector}. +     * +     * <pre> +     * // Create a new module +     * var myModule = angular.module('myModule', []); +     * +     * // configure a new service +     * myModule.value('appName', 'MyCoolApp'); +     * +     * // configure existing services inside initialization blocks. +     * myModule.init(function($locationProvider) { +     *   // Configure existing providers +     *   $locationProvider.hashPrefix = '!'; +     * }); +     * </pre> +     * +     * Then you can load your module like this: +     * +     * <pre> +     * var injector = angular.injector('ng', 'MyModule') +     * </pre> +     * +     * @param {!string} name The name of the module to create or retrieve. +     * @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the +     *        the module is being retrieved for further configuration. +     * @param {Function} initFn Option configuration function for the module. Same as +     *        {@link angular.Module#init Module.init()}. +     * @return {angular.Module} +     */ +    return function module(name, requires, initFn) { +      if (requires && modules.hasOwnProperty(name)) { +        modules[name] = null; +      } +      return ensure(modules, name, function() { +        if (!requires) { +          throw Error('No module: ' + name); +        } + +        function init(fn) { +          invokeQueue.push(['$injector', 'invoke', [null, fn]]); +        } + +        /** @type {!Array.<Array.<*>>} */ +        var invokeQueue = []; + +        /** @type {angular.Module} */ +        var moduleInstance = { +          /** +           * @ngdoc property +           * @name angular.Module#requires +           * @propertyOf angular.Module +           * @returns {Array.<string>} List of module names which must be loaded before this module. +           * @description +           * Holds the list of modules which the injector will load before the current module is loaded. +           */ +          requires: requires, +          invokeQueue: invokeQueue, + +          /** +           * @ngdoc method +           * @name angular.Module#service +           * @methodOf angular.Module +           * @param {string} name service name +           * @param {Function} providerType Construction function for creating new instance of the service. +           * @description +           * See {@link angular.module.AUTO.$provide#service $provide.service()}. +           */ +          service: invokeLater('$provide', 'service'), + +          /** +           * @ngdoc method +           * @name angular.Module#factory +           * @methodOf angular.Module +           * @param {string} name service name +           * @param {Function} providerFunction Function for creating new instance of the service. +           * @description +           * See {@link angular.module.AUTO.$provide#service $provide.factory()}. +           */ +          factory: invokeLater('$provide', 'factory'), + +          /** +           * @ngdoc method +           * @name angular.Module#value +           * @methodOf angular.Module +           * @param {string} name service name +           * @param {*} object Service instance object. +           * @description +           * See {@link angular.module.AUTO.$provide#value $provide.value()}. +           */ +          value: invokeLater('$provide', 'value'), + +          /** +           * @ngdoc method +           * @name angular.Module#filter +           * @methodOf angular.Module +           * @param {string} name filterr name +           * @param {Function} filterFactory Factory function for creating new instance of filter. +           * @description +           * See {@link angular.module.ng.$filterProvider#register $filterProvider.register()}. +           */ +          filter: invokeLater('$filterProvider', 'register'), + +          /** +           * @ngdoc method +           * @name angular.Module#init +           * @methodOf angular.Module +           * @param {Function} initializationFn Execute this function on module load, allowing it to do any +           *   service configuration.. +           * @description +           * Use this method to register work which needs to be performed on module loading. +           */ +          init: init +        }; + +        if (initFn) { +          init(initFn); +        } + +        return  moduleInstance; + +        /** +         * @param {string} provider +         * @param {string} method +         * @returns {angular.Module} +         */ +        function invokeLater(provider, method) { +          return function() { +            invokeQueue.push([provider, method, arguments]); +            return moduleInstance; +          } +        } +      }); +    }; +  }); + +} diff --git a/src/loader.prefix b/src/loader.prefix new file mode 100644 index 00000000..b3969eb0 --- /dev/null +++ b/src/loader.prefix @@ -0,0 +1,7 @@ +/** + * @license AngularJS v"NG_VERSION_FULL" + * (c) 2010-2012 AngularJS http://angularjs.org + * License: MIT + */ +'use strict'; +( diff --git a/src/loader.suffix b/src/loader.suffix new file mode 100644 index 00000000..b8a5d43d --- /dev/null +++ b/src/loader.suffix @@ -0,0 +1,20 @@ +)(window); + +/** + * Closure compiler type information + * + * @typedef { { + *   requires: !Array.<string>, + *   invokeQueue: !Array.<Array.<*>>, + * + *   service: function(string, Function):angular.Module, + *   factory: function(string, Function):angular.Module, + *   value: function(string, *):angular.Module, + * + *   filter: function(string, Function):angular.Module, + * + *   init: function(Function):angular.Module + * } } + */ +angular.Module; + diff --git a/src/scenario/Application.js b/src/scenario/Application.js index 5e7b8370..ba6bbea7 100644 --- a/src/scenario/Application.js +++ b/src/scenario/Application.js @@ -90,11 +90,13 @@ angular.scenario.Application.prototype.executeAction = function(action) {    if (!$window.angular) {      return action.call(this, $window, _jQuery($window.document));    } -  var element = $window.angular.element($window.document); -  var $injector = element.inheritedData('$injector'); -  $injector.invoke(null, function($browser){ -    $browser.notifyWhenNoOutstandingRequests(function() { -      action.call(self, $window, _jQuery($window.document)); +  angularInit($window.document, function(element) { +    element = $window.angular.element(element); +    var $injector = element.inheritedData('$injector'); +    $injector.invoke(null, function($browser){ +      $browser.notifyWhenNoOutstandingRequests(function() { +        action.call(self, $window, _jQuery($window.document)); +      });      });    });  }; diff --git a/src/scenario/angular.suffix b/src/scenario/angular.suffix index a79fd270..c75c5cca 100644 --- a/src/scenario/angular.suffix +++ b/src/scenario/angular.suffix @@ -1,7 +1,17 @@ +bindJQuery();  publishExternalAPI(angular);  var $runner = new angular.scenario.Runner(window), -    config = angularJsConfig(document); +    scripts = document.getElementsByTagName('script'), +    script = scripts[scripts.length - 1], +    config = {}; + +angular.forEach(script.attributes, function(attr) { +  var match = attr.name.match(/ng[:\-](.*)/); +  if (match) { +    config[match[1]] = attr.value || true; +  } +});  if (config.autotest) {    jqLiteWrap(document).ready(function() { | 
