aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMisko Hevery2012-01-06 18:10:47 -0800
committerMisko Hevery2012-01-10 22:27:00 -0800
commit5143e7bf065a3cbdf8400cf095b653d51bc83b8f (patch)
tree980149c365d4cb5586d27975d26366a25ff7be6a /src
parentafd25446d23f24872eb20ac79c8fbd2cff203ef0 (diff)
downloadangular.js-5143e7bf065a3cbdf8400cf095b653d51bc83b8f.tar.bz2
feat(module): new module loader
Diffstat (limited to 'src')
-rw-r--r--src/Angular.js120
-rw-r--r--src/AngularPublic.js80
-rw-r--r--src/Injector.js48
-rw-r--r--src/angular-bootstrap.js9
-rw-r--r--src/angular-mocks.js63
-rw-r--r--src/angular.suffix4
-rw-r--r--src/directives.js27
-rw-r--r--src/loader.js167
-rw-r--r--src/loader.prefix7
-rw-r--r--src/loader.suffix20
-rw-r--r--src/scenario/Application.js12
-rw-r--r--src/scenario/angular.suffix12
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() {