aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--angularFiles.js2
-rw-r--r--docs/src/templates/docs.js11
-rw-r--r--example/personalLog/test/personalLogSpec.js2
-rw-r--r--src/Angular.js58
-rw-r--r--src/AngularPublic.js11
-rw-r--r--src/Browser.js7
-rw-r--r--src/Injector.js10
-rw-r--r--src/angular-mocks.js127
-rw-r--r--src/service/compiler.js595
-rw-r--r--src/service/cookieStore.js92
-rw-r--r--src/service/cookies.js122
-rw-r--r--src/service/defer.js24
-rw-r--r--src/service/document.js8
-rw-r--r--src/service/exceptionHandler.js13
-rw-r--r--src/service/formFactory.js520
-rw-r--r--src/service/locale.js108
-rw-r--r--src/service/location.js151
-rw-r--r--src/service/log.js126
-rw-r--r--src/service/resource.js10
-rw-r--r--src/service/route.js473
-rw-r--r--src/service/routeParams.js6
-rw-r--r--src/service/scope.js1182
-rw-r--r--src/service/sniffer.js20
-rw-r--r--src/service/window.js4
-rw-r--r--src/service/xhr.bulk.js139
-rw-r--r--src/service/xhr.cache.js148
-rw-r--r--src/service/xhr.error.js12
-rw-r--r--src/service/xhr.js101
-rw-r--r--test/AngularSpec.js19
-rw-r--r--test/BinderSpec.js16
-rw-r--r--test/FiltersSpec.js8
-rw-r--r--test/InjectorSpec.js6
-rw-r--r--test/angular-mocksSpec.js113
-rw-r--r--test/mocks.js69
-rw-r--r--test/service/cookiesSpec.js2
-rw-r--r--test/service/exceptionHandlerSpec.js4
-rw-r--r--test/service/localeSpec.js2
-rw-r--r--test/service/logSpec.js4
-rw-r--r--test/service/scopeSpec.js12
-rw-r--r--test/service/snifferSpec.js2
-rw-r--r--test/testabilityPatch.js29
-rw-r--r--test/widget/inputSpec.js6
-rw-r--r--test/widgetsSpec.js8
43 files changed, 2206 insertions, 2176 deletions
diff --git a/angularFiles.js b/angularFiles.js
index a0a9ce5e..936f9b7d 100644
--- a/angularFiles.js
+++ b/angularFiles.js
@@ -70,7 +70,6 @@ angularFiles = {
'src/jstd-scenario-adapter/*.js',
'src/scenario/*.js',
'src/angular-mocks.js',
- 'test/mocks.js',
'test/scenario/*.js',
'test/scenario/output/*.js',
'test/jstd-scenario-adapter/*.js',
@@ -133,7 +132,6 @@ angularFiles = {
'src/jstd-scenario-adapter/*.js',
'src/scenario/*.js',
'src/angular-mocks.js',
- 'test/mocks.js',
'test/scenario/*.js',
'test/scenario/output/*.js',
'test/jstd-scenario-adapter/*.js',
diff --git a/docs/src/templates/docs.js b/docs/src/templates/docs.js
index b50333a5..2693da64 100644
--- a/docs/src/templates/docs.js
+++ b/docs/src/templates/docs.js
@@ -148,9 +148,12 @@ function TutorialInstructionsCtrl($cookieStore) {
};
}
-angular.service('$locationConfig', function() {
- return {
+window.angular = window.angular || {};
+angular.module = angular.module || {};
+
+angular.module.ngdocs = function($provide) {
+ $provide.value('$locationConfig', {
html5Mode: true,
hashPrefix: '!'
- };
-});
+ });
+};
diff --git a/example/personalLog/test/personalLogSpec.js b/example/personalLog/test/personalLogSpec.js
index 2e93925c..5e3a8409 100644
--- a/example/personalLog/test/personalLogSpec.js
+++ b/example/personalLog/test/personalLogSpec.js
@@ -2,7 +2,7 @@ describe('example.personalLog.LogCtrl', function() {
var logCtrl;
function createNotesCtrl() {
- var injector = angular.injector('NG');
+ var injector = angular.injector('NG', 'NG_MOCK');
var scope = injector('$rootScope');
scope.$cookies = injector('$cookies');
return scope.$new(example.personalLog.LogCtrl);
diff --git a/src/Angular.js b/src/Angular.js
index 4344425a..931a3e5a 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -99,8 +99,8 @@ var _undefined = undefined,
: noop,
/** @name angular */
- angular = window[$angular] || (window[$angular] = {}),
- angularModules = angular.modules || (angular.modules = {}),
+ angular = window.angular || (window.angular = {}),
+ angularModule = angular.module || (angular.module = {}),
/** @name angular.markup */
angularTextMarkup = extensionMap(angular, 'markup'),
/** @name angular.attrMarkup */
@@ -114,7 +114,6 @@ var _undefined = undefined,
/** @name angular.service */
angularInputType = extensionMap(angular, 'inputType', lowercase),
/** @name angular.service */
- angularService = extensionMap(angular, 'service'),
angularCallbacks = extensionMap(angular, 'callbacks'),
nodeName_,
uid = ['0', '0', '0'],
@@ -188,18 +187,6 @@ function forEachSorted(obj, iterator, context) {
}
-function formatError(arg) {
- if (arg instanceof Error) {
- if (arg.stack) {
- arg = (arg.message && arg.stack.indexOf(arg.message) === -1) ?
- 'Error: ' + arg.message + '\n' + arg.stack : arg.stack;
- } else if (arg.sourceURL) {
- arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
- }
- }
- return arg;
-}
-
/**
* 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
@@ -957,7 +944,7 @@ function angularInit(config, document){
modules.push(module);
}
});
- createInjector(modules, angularModules)(['$rootScope', '$compile', function(scope, compile){
+ createInjector(modules, angularModule)(['$rootScope', '$compile', '$injector', function(scope, compile, injector){
scope.$apply(function(){
compile(isString(autobind) ? document.getElementById(autobind) : document)(scope);
});
@@ -1030,7 +1017,7 @@ function publishExternalAPI(angular){
'extend': extend,
'equals': equals,
'forEach': forEach,
- 'injector': function(){ return createInjector(arguments, angularModules); },
+ 'injector': function(){ return createInjector(arguments, angularModule); },
'noop':noop,
'bind':bind,
'toJson': toJson,
@@ -1049,14 +1036,39 @@ function publishExternalAPI(angular){
'uppercase': uppercase
});
- angularModules.NG = ngModule;
+ angularModule.NG = ngModule;
}
-ngModule.$inject = ['$provide'];
-function ngModule($provide) {
- forEach(angularService, function(factory, name){
- $provide.factory(name, factory);
- });
+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);
+
+ $provide.service('$browser', $BrowserProvider);
+ $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('$formFactory', $FormFactoryProvider);
+ $provide.service('$locale', $LocaleProvider);
+ $provide.service('$location', $LocationProvider);
+ $provide.service('$locationConfig', $LocationConfigProvider);
+ $provide.service('$log', $LogProvider);
+ $provide.service('$resource', $ResourceProvider);
+ $provide.service('$route', $RouteProvider);
+ $provide.service('$routeParams', $RouteParamsProvider);
+ $provide.service('$rootScope', $RootScopeProvider);
+ $provide.service('$sniffer', $SnifferProvider);
+ $provide.service('$window', $WindowProvider);
+ $provide.service('$xhr.bulk', $XhrBulkProvider);
+ $provide.service('$xhr.cache', $XhrCacheProvider);
+ $provide.service('$xhr.error', $XhrErrorProvider);
+ $provide.service('$xhr', $XhrProvider);
}
diff --git a/src/AngularPublic.js b/src/AngularPublic.js
index 600f1ef8..64a7bf4d 100644
--- a/src/AngularPublic.js
+++ b/src/AngularPublic.js
@@ -1,16 +1,5 @@
'use strict';
-var browserSingleton;
-
-angularService('$browser', function($log, $sniffer) {
- if (!browserSingleton) {
- browserSingleton = new Browser(window, jqLite(window.document), jqLite(window.document.body),
- XHR, $log, $sniffer);
- }
- return browserSingleton;
-}, {$inject: ['$log', '$sniffer']});
-
-
publishExternalAPI(angular);
//try to bind to jquery now so that one can write angular.element().read()
diff --git a/src/Browser.js b/src/Browser.js
index 71252050..d4faebc8 100644
--- a/src/Browser.js
+++ b/src/Browser.js
@@ -473,3 +473,10 @@ function Browser(window, document, body, XHR, $log, $sniffer) {
return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : href;
};
}
+
+function $BrowserProvider(){
+ this.$get = ['$window', '$log', '$sniffer', '$document',
+ function( $window, $log, $sniffer, $document){
+ return new Browser($window, $document, $document.find('body'), XHR, $log, $sniffer);
+ }];
+}
diff --git a/src/Injector.js b/src/Injector.js
index 12c2ffa6..838a911d 100644
--- a/src/Injector.js
+++ b/src/Injector.js
@@ -33,10 +33,6 @@
* `injector.eager()`
*/
-function angularServiceInject(name, fn, inject, eager) {
- angularService(name, fn, {$inject:inject, $eager:eager});
-}
-
/**
* @returns the $inject property of function. If not found the
@@ -177,7 +173,11 @@ function createInjector(modulesToLoad, moduleRegistry) {
forEach(modulesToLoad, function(module){
if (isString(module)) {
- module = moduleRegistry[module];
+ if (moduleRegistry[module]) {
+ module = moduleRegistry[module];
+ } else {
+ throw Error("Module '" + module + "' is not defined!");
+ }
}
if (isFunction(module) || isArray(module)) {
$injector(module);
diff --git a/src/angular-mocks.js b/src/angular-mocks.js
index 679a78a3..b4b2fd19 100644
--- a/src/angular-mocks.js
+++ b/src/angular-mocks.js
@@ -1,4 +1,3 @@
-'use strict';
/**
* @license AngularJS v"NG_VERSION_FULL"
@@ -8,30 +7,6 @@
/*
-
- NUGGGGGH MUST TONGUE WANGS
- \
- .....
- C C /
- /< /
- ___ __________/_#__=o
- /(- /(\_\________ \
- \ ) \ )_ \o \
- /|\ /|\ |' |
- | _|
- /o __\
- / ' |
- / / |
- /_/\______|
- ( _( <
- \ \ \
- \ \ |
- \____\____\
- ____\_\__\_\
- /` /` o\
- |___ |_______|.. . b'ger
-
-
IN THE FINAL BUILD THIS FILE DOESN'T HAVE DIRECT ACCESS TO GLOBAL FUNCTIONS
DEFINED IN Angular.js YOU *MUST* REFER TO THEM VIA angular OBJECT
(e.g. angular.forEach(...)) AND MAKE SURE THAT THE GIVEN FUNCTION IS EXPORTED
@@ -56,8 +31,15 @@
* the angular service exception handler.
* * {@link angular.mock.service.$log $log } - A mock implementation of the angular service log.
*/
-angular.mock = {};
+window.angular = window.angular || {};
+angular.module = angular.module || {};
+angular.mock = angular.mock || {};
+angular.module.NG_MOCK = ['$provide', function($provide){
+ $provide.service('$browser', angular.mock.$BrowserProvider);
+ $provide.service('$exceptionHandler', angular.mock.$ExceptionHandlerProvider);
+ $provide.service('$log', angular.mock.$LogProvider);
+}];
/**
* @ngdoc service
@@ -81,7 +63,12 @@ angular.mock = {};
* - $browser.defer — enables testing of code that uses
* {@link angular.service.$defer $defer service} for executing functions via the `setTimeout` api.
*/
-function MockBrowser() {
+angular.mock.$BrowserProvider = function(){
+ this.$get = function(){
+ return new angular.mock.$Browser();
+ };
+};
+angular.mock.$Browser = function() {
var self = this,
expectations = {},
requests = [];
@@ -309,7 +296,7 @@ function MockBrowser() {
return this.$$baseHref;
};
}
-MockBrowser.prototype = {
+angular.mock.$Browser.prototype = {
/**
* @name angular.mock.service.$browser#poll
@@ -360,10 +347,6 @@ MockBrowser.prototype = {
addJs: function() {}
};
-angular.service('$browser', function() {
- return new MockBrowser();
-});
-
/**
* @ngdoc service
@@ -376,9 +359,29 @@ angular.service('$browser', function() {
*
* See {@link angular.mock} for more info on angular mocks.
*/
-angular.service('$exceptionHandler', function() {
- return function(e) { throw e; };
-});
+angular.mock.$ExceptionHandlerProvider = function(){
+ var handler;
+
+ this.mode = function(mode){
+ handler = {
+ rethrow: function(e) {
+ throw e;
+ },
+ log: angular.extend(function log(e) {
+ log.errors.push(e);
+ }, {errors:[]})
+ }[mode];
+ if (!handler) {
+ throw Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
+ }
+ };
+
+ this.$get = function(){
+ return handler;
+ };
+
+ this.mode('rethrow');
+};
/**
@@ -392,23 +395,43 @@ angular.service('$exceptionHandler', function() {
*
* See {@link angular.mock} for more info on angular mocks.
*/
-angular.service('$log', MockLogFactory);
-
-function MockLogFactory() {
- var $log = {
- log: function() { $log.log.logs.push(arguments); },
- warn: function() { $log.warn.logs.push(arguments); },
- info: function() { $log.info.logs.push(arguments); },
- error: function() { $log.error.logs.push(arguments); }
- };
+angular.mock.$LogProvider = function(){
+ this.$get = function () {
+ var $log = {
+ log: function() { $log.log.logs.push(concat([], arguments, 0)); },
+ warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
+ info: function() { $log.info.logs.push(concat([], arguments, 0)); },
+ error: function() { $log.error.logs.push(concat([], arguments, 0)); }
+ };
- $log.log.logs = [];
- $log.warn.logs = [];
- $log.info.logs = [];
- $log.error.logs = [];
+ $log.reset = function (){
+ $log.log.logs = [];
+ $log.warn.logs = [];
+ $log.info.logs = [];
+ $log.error.logs = [];
+ };
- return $log;
-}
+ $log.assertEmpty = function(){
+ var errors = [];
+ angular.forEach(['error', 'warn', 'info', 'log'], function(logLevel) {
+ angular.forEach($log[logLevel].logs, function(log) {
+ angular.forEach(log, function (logItem) {
+ errors.push('MOCK $log (' + logLevel + '): ' + (logItem.stack || logItem));
+ });
+ });
+ });
+ if (errors.length) {
+ errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or an expected " +
+ "log message was not checked and removed:");
+ errors.push('')
+ throw new Error(errors.join('\n---------\n'));
+ }
+ };
+
+ $log.reset();
+ return $log;
+ };
+};
/**
@@ -441,7 +464,7 @@ function MockLogFactory() {
* </pre>
*
*/
-function TzDate(offset, timestamp) {
+angular.mock.TzDate = function (offset, timestamp) {
if (angular.isString(timestamp)) {
var tsStr = timestamp;
@@ -545,4 +568,4 @@ function TzDate(offset, timestamp) {
}
//make "tzDateInstance instanceof Date" return true
-TzDate.prototype = Date.prototype;
+angular.mock.TzDate.prototype = Date.prototype;
diff --git a/src/service/compiler.js b/src/service/compiler.js
index 0bd3e54d..220d9c39 100644
--- a/src/service/compiler.js
+++ b/src/service/compiler.js
@@ -1,325 +1,322 @@
'use strict';
-// TODO(misko): temporary services to get the compiler working;
-angularService('$textMarkup', valueFn(angularTextMarkup));
-angularService('$attrMarkup', valueFn(angularAttrMarkup));
-angularService('$directive', valueFn(angularDirective));
-angularService('$widget', valueFn(angularWidget));
-angularServiceInject('$compile', function($injector, $exceptionHandler, $textMarkup, $attrMarkup, $directive, $widget){
- /**
- * Template provides directions an how to bind to a given element.
- * It contains a list of init functions which need to be called to
- * bind to a new instance of elements. It also provides a list
- * of child paths which contain child templates
- */
- function Template() {
- this.paths = [];
- this.children = [];
- this.linkFns = [];
- this.newScope = false;
- }
-
- Template.prototype = {
- link: function(element, scope) {
- var childScope = scope,
- locals = {$element: element};
- if (this.newScope) {
- childScope = isFunction(this.newScope) ? scope.$new(this.newScope(scope)) : scope.$new();
- element.data($$scope, childScope);
- }
- forEach(this.linkFns, function(fn) {
- try {
- $injector.invoke(childScope, fn, locals);
- } catch (e) {
- $exceptionHandler(e);
- }
- });
- var i,
- childNodes = element[0].childNodes,
- children = this.children,
- paths = this.paths,
- length = paths.length;
- for (i = 0; i < length; i++) {
- // sometimes `element` can be modified by one of the linker functions in `this.linkFns`
- // and childNodes may be added or removed
- // TODO: element structure needs to be re-evaluated if new children added
- // if the childNode still exists
- if (childNodes[paths[i]])
- children[i].link(jqLite(childNodes[paths[i]]), childScope);
- else
- delete paths[i]; // if child no longer available, delete path
+function $CompileProvider(){
+ this.$get = ['$injector', '$exceptionHandler', '$textMarkup', '$attrMarkup', '$directive', '$widget',
+ function( $injector, $exceptionHandler, $textMarkup, $attrMarkup, $directive, $widget){
+ /**
+ * Template provides directions an how to bind to a given element.
+ * It contains a list of init functions which need to be called to
+ * bind to a new instance of elements. It also provides a list
+ * of child paths which contain child templates
+ */
+ function Template() {
+ this.paths = [];
+ this.children = [];
+ this.linkFns = [];
+ this.newScope = false;
}
- },
-
- addLinkFn:function(linkingFn) {
- if (linkingFn) {
- //TODO(misko): temporary hack.
- if (isFunction(linkingFn) && !linkingFn.$inject) {
- linkingFn.$inject = ['$element'];
- }
- this.linkFns.push(linkingFn);
- }
- },
+ Template.prototype = {
+ link: function(element, scope) {
+ var childScope = scope,
+ locals = {$element: element};
+ if (this.newScope) {
+ childScope = isFunction(this.newScope) ? scope.$new(this.newScope(scope)) : scope.$new();
+ element.data($$scope, childScope);
+ }
+ forEach(this.linkFns, function(fn) {
+ try {
+ $injector.invoke(childScope, fn, locals);
+ } catch (e) {
+ $exceptionHandler(e);
+ }
+ });
+ var i,
+ childNodes = element[0].childNodes,
+ children = this.children,
+ paths = this.paths,
+ length = paths.length;
+ for (i = 0; i < length; i++) {
+ // sometimes `element` can be modified by one of the linker functions in `this.linkFns`
+ // and childNodes may be added or removed
+ // TODO: element structure needs to be re-evaluated if new children added
+ // if the childNode still exists
+ if (childNodes[paths[i]])
+ children[i].link(jqLite(childNodes[paths[i]]), childScope);
+ else
+ delete paths[i]; // if child no longer available, delete path
+ }
+ },
- addChild: function(index, template) {
- if (template) {
- this.paths.push(index);
- this.children.push(template);
- }
- },
+ addLinkFn:function(linkingFn) {
+ if (linkingFn) {
+ //TODO(misko): temporary hack.
+ if (isFunction(linkingFn) && !linkingFn.$inject) {
+ linkingFn.$inject = ['$element'];
+ }
+ this.linkFns.push(linkingFn);
+ }
+ },
- empty: function() {
- return this.linkFns.length === 0 && this.paths.length === 0;
- }
- };
- ///////////////////////////////////
- //Compiler
- //////////////////////////////////
+ addChild: function(index, template) {
+ if (template) {
+ this.paths.push(index);
+ this.children.push(template);
+ }
+ },
- /**
- * @ngdoc function
- * @name angular.compile
- * @function
- *
- * @description
- * Compiles a piece of HTML string or DOM into a template and produces a template function, which
- * can then be used to link {@link angular.scope scope} and the template together.
- *
- * The compilation is a process of walking the DOM tree and trying to match DOM elements to
- * {@link angular.markup markup}, {@link angular.attrMarkup attrMarkup},
- * {@link angular.widget widgets}, and {@link angular.directive directives}. For each match it
- * executes corresponding markup, attrMarkup, widget or directive template function and collects the
- * instance functions into a single template function which is then returned.
- *
- * The template function can then be used once to produce the view or as it is the case with
- * {@link angular.widget.@ng:repeat repeater} many-times, in which case each call results in a view
- * that is a DOM clone of the original template.
- *
- <pre>
- // compile the entire window.document and give me the scope bound to this template.
- var rootScope = angular.compile(window.document)();
+ empty: function() {
+ return this.linkFns.length === 0 && this.paths.length === 0;
+ }
+ };
- // compile a piece of html
- var rootScope2 = angular.compile('<div ng:click="clicked = true">click me</div>')();
+ ///////////////////////////////////
+ //Compiler
+ //////////////////////////////////
+ /**
+ * @ngdoc function
+ * @name angular.compile
+ * @function
+ *
+ * @description
+ * Compiles a piece of HTML string or DOM into a template and produces a template function, which
+ * can then be used to link {@link angular.scope scope} and the template together.
+ *
+ * The compilation is a process of walking the DOM tree and trying to match DOM elements to
+ * {@link angular.markup markup}, {@link angular.attrMarkup attrMarkup},
+ * {@link angular.widget widgets}, and {@link angular.directive directives}. For each match it
+ * executes corresponding markup, attrMarkup, widget or directive template function and collects the
+ * instance functions into a single template function which is then returned.
+ *
+ * The template function can then be used once to produce the view or as it is the case with
+ * {@link angular.widget.@ng:repeat repeater} many-times, in which case each call results in a view
+ * that is a DOM clone of the original template.
+ *
+ <pre>
+ // compile the entire window.document and give me the scope bound to this template.
+ var rootScope = angular.compile(window.document)();
- // compile a piece of html and retain reference to both the dom and scope
- var template = angular.element('<div ng:click="clicked = true">click me</div>'),
- scope = angular.compile(template)();
- // at this point template was transformed into a view
- </pre>
- *
- *
- * @param {string|DOMElement} element Element or HTML to compile into a template function.
- * @returns {function(scope[, cloneAttachFn])} a template function which is used to bind template
- * (a DOM element/tree) to a scope. Where:
- *
- * * `scope` - A {@link angular.scope Scope} to bind to.
- * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
- * `template` and call the `cloneAttachFn` function allowing the caller to attach the
- * cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
- * called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
- *
- * * `clonedElement` - is a clone of the original `element` passed into the compiler.
- * * `scope` - is the current scope with which the linking function is working with.
- *
- * Calling the template function returns the element of the template. It is either the original element
- * passed in, or the clone of the element if the `cloneAttachFn` is provided.
- *
- * It is important to understand that the returned scope is "linked" to the view DOM, but no linking
- * (instance) functions registered by {@link angular.directive directives} or
- * {@link angular.widget widgets} found in the template have been executed yet. This means that the
- * view is likely empty and doesn't contain any values that result from evaluation on the scope. To
- * bring the view to life, the scope needs to run through a $digest phase which typically is done by
- * Angular automatically, except for the case when an application is being
- * {@link guide/dev_guide.bootstrap.manual_bootstrap} manually bootstrapped, in which case the
- * $digest phase must be invoked by calling {@link angular.scope.$apply}.
- *
- * If you need access to the bound view, there are two ways to do it:
- *
- * - If you are not asking the linking function to clone the template, create the DOM element(s)
- * before you send them to the compiler and keep this reference around.
- * <pre>
- * var scope = angular.injector()('$rootScope');
- * var element = angular.compile('<p>{{total}}</p>')(scope);
- * </pre>
- *
- * - if on the other hand, you need the element to be cloned, the view reference from the original
- * example would not point to the clone, but rather to the original template that was cloned. In
- * this case, you can access the clone via the cloneAttachFn:
- * <pre>
- * var original = angular.element('<p>{{total}}</p>'),
- * scope = someParentScope.$new(),
- * clone;
- *
- * angular.compile(original)(scope, function(clonedElement, scope) {
- * clone = clonedElement;
- * //attach the clone to DOM document at the right place
- * });
- *
- * //now we have reference to the cloned DOM via `clone`
- * </pre>
- *
- *
- * Compiler Methods For Widgets and Directives:
- *
- * The following methods are available for use when you write your own widgets, directives,
- * and markup. (Recall that the compile function's this is a reference to the compiler.)
- *
- * `compile(element)` - returns linker -
- * Invoke a new instance of the compiler to compile a DOM element and return a linker function.
- * You can apply the linker function to the original element or a clone of the original element.
- * The linker function returns a scope.
- *
- * * `comment(commentText)` - returns element - Create a comment element.
- *
- * * `element(elementName)` - returns element - Create an element by name.
- *
- * * `text(text)` - returns element - Create a text element.
- *
- * * `descend([set])` - returns descend state (true or false). Get or set the current descend
- * state. If true the compiler will descend to children elements.
- *
- * * `directives([set])` - returns directive state (true or false). Get or set the current
- * directives processing state. The compiler will process directives only when directives set to
- * true.
- *
- * For information on how the compiler works, see the
- * {@link guide/dev_guide.compiler Angular HTML Compiler} section of the Developer Guide.
- */
- function Compiler(markup, attrMarkup, directives, widgets){
- this.markup = markup;
- this.attrMarkup = attrMarkup;
- this.directives = directives;
- this.widgets = widgets;
- }
+ // compile a piece of html
+ var rootScope2 = angular.compile('<div ng:click="clicked = true">click me</div>')();
- Compiler.prototype = {
- compile: function(templateElement) {
- templateElement = jqLite(templateElement);
- var index = 0,
- template,
- parent = templateElement.parent();
- if (templateElement.length > 1) {
- // https://github.com/angular/angular.js/issues/338
- throw Error("Cannot compile multiple element roots: " +
- jqLite('<div>').append(templateElement.clone()).html());
- }
- if (parent && parent[0]) {
- parent = parent[0];
- for(var i = 0; i < parent.childNodes.length; i++) {
- if (parent.childNodes[i] == templateElement[0]) {
- index = i;
- }
- }
+ // compile a piece of html and retain reference to both the dom and scope
+ var template = angular.element('<div ng:click="clicked = true">click me</div>'),
+ scope = angular.compile(template)();
+ // at this point template was transformed into a view
+ </pre>
+ *
+ *
+ * @param {string|DOMElement} element Element or HTML to compile into a template function.
+ * @returns {function(scope[, cloneAttachFn])} a template function which is used to bind template
+ * (a DOM element/tree) to a scope. Where:
+ *
+ * * `scope` - A {@link angular.scope Scope} to bind to.
+ * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
+ * `template` and call the `cloneAttachFn` function allowing the caller to attach the
+ * cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
+ * called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
+ *
+ * * `clonedElement` - is a clone of the original `element` passed into the compiler.
+ * * `scope` - is the current scope with which the linking function is working with.
+ *
+ * Calling the template function returns the element of the template. It is either the original element
+ * passed in, or the clone of the element if the `cloneAttachFn` is provided.
+ *
+ * It is important to understand that the returned scope is "linked" to the view DOM, but no linking
+ * (instance) functions registered by {@link angular.directive directives} or
+ * {@link angular.widget widgets} found in the template have been executed yet. This means that the
+ * view is likely empty and doesn't contain any values that result from evaluation on the scope. To
+ * bring the view to life, the scope needs to run through a $digest phase which typically is done by
+ * Angular automatically, except for the case when an application is being
+ * {@link guide/dev_guide.bootstrap.manual_bootstrap} manually bootstrapped, in which case the
+ * $digest phase must be invoked by calling {@link angular.scope.$apply}.
+ *
+ * If you need access to the bound view, there are two ways to do it:
+ *
+ * - If you are not asking the linking function to clone the template, create the DOM element(s)
+ * before you send them to the compiler and keep this reference around.
+ * <pre>
+ * var scope = angular.injector()('$rootScope');
+ * var element = angular.compile('<p>{{total}}</p>')(scope);
+ * </pre>
+ *
+ * - if on the other hand, you need the element to be cloned, the view reference from the original
+ * example would not point to the clone, but rather to the original template that was cloned. In
+ * this case, you can access the clone via the cloneAttachFn:
+ * <pre>
+ * var original = angular.element('<p>{{total}}</p>'),
+ * scope = someParentScope.$new(),
+ * clone;
+ *
+ * angular.compile(original)(scope, function(clonedElement, scope) {
+ * clone = clonedElement;
+ * //attach the clone to DOM document at the right place
+ * });
+ *
+ * //now we have reference to the cloned DOM via `clone`
+ * </pre>
+ *
+ *
+ * Compiler Methods For Widgets and Directives:
+ *
+ * The following methods are available for use when you write your own widgets, directives,
+ * and markup. (Recall that the compile function's this is a reference to the compiler.)
+ *
+ * `compile(element)` - returns linker -
+ * Invoke a new instance of the compiler to compile a DOM element and return a linker function.
+ * You can apply the linker function to the original element or a clone of the original element.
+ * The linker function returns a scope.
+ *
+ * * `comment(commentText)` - returns element - Create a comment element.
+ *
+ * * `element(elementName)` - returns element - Create an element by name.
+ *
+ * * `text(text)` - returns element - Create a text element.
+ *
+ * * `descend([set])` - returns descend state (true or false). Get or set the current descend
+ * state. If true the compiler will descend to children elements.
+ *
+ * * `directives([set])` - returns directive state (true or false). Get or set the current
+ * directives processing state. The compiler will process directives only when directives set to
+ * true.
+ *
+ * For information on how the compiler works, see the
+ * {@link guide/dev_guide.compiler Angular HTML Compiler} section of the Developer Guide.
+ */
+ function Compiler(markup, attrMarkup, directives, widgets){
+ this.markup = markup;
+ this.attrMarkup = attrMarkup;
+ this.directives = directives;
+ this.widgets = widgets;
}
- template = this.templatize(templateElement, index) || new Template();
- return function(scope, cloneConnectFn){
- assertArg(scope, 'scope');
- // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
- // and sometimes changes the structure of the DOM.
- var element = cloneConnectFn
- ? JQLitePrototype.clone.call(templateElement) // IMPORTANT!!!
- : templateElement;
- element.data($$scope, scope);
- scope.$element = element;
- (cloneConnectFn||noop)(element, scope);
- template.link(element, scope);
- return element;
- };
- },
- templatize: function(element, elementIndex){
- var self = this,
- widget,
- fn,
- directiveFns = self.directives,
- descend = true,
- directives = true,
- elementName = nodeName_(element),
- elementNamespace = elementName.indexOf(':') > 0 ? lowercase(elementName).replace(':', '-') : '',
- template,
- selfApi = {
- compile: bind(self, self.compile),
- descend: function(value){ if(isDefined(value)) descend = value; return descend;},
- directives: function(value){ if(isDefined(value)) directives = value; return directives;},
- scope: function(value){ if(isDefined(value)) template.newScope = template.newScope || value; return template.newScope;}
- };
- element.addClass(elementNamespace);
- template = new Template();
- eachAttribute(element, function(value, name){
- if (!widget) {
- if ((widget = self.widgets('@' + name))) {
- element.addClass('ng-attr-widget');
- widget = bind(selfApi, widget, value, element);
+ Compiler.prototype = {
+ compile: function(templateElement) {
+ templateElement = jqLite(templateElement);
+ var index = 0,
+ template,
+ parent = templateElement.parent();
+ if (templateElement.length > 1) {
+ // https://github.com/angular/angular.js/issues/338
+ throw Error("Cannot compile multiple element roots: " +
+ jqLite('<div>').append(templateElement.clone()).html());
}
- }
- });
- if (!widget) {
- if ((widget = self.widgets(elementName))) {
- if (elementNamespace)
- element.addClass('ng-widget');
- widget = bind(selfApi, widget, element);
- }
- }
- if (widget) {
- descend = false;
- directives = false;
- var parent = element.parent();
- template.addLinkFn(widget.call(selfApi, element));
- if (parent && parent[0]) {
- element = jqLite(parent[0].childNodes[elementIndex]);
- }
- }
- if (descend){
- // process markup for text nodes only
- for(var i=0, child=element[0].childNodes;
- i<child.length; i++) {
- if (isTextNode(child[i])) {
- forEach(self.markup, function(markup){
- if (i<child.length) {
- var textNode = jqLite(child[i]);
- markup.call(selfApi, textNode.text(), textNode, element);
+ if (parent && parent[0]) {
+ parent = parent[0];
+ for(var i = 0; i < parent.childNodes.length; i++) {
+ if (parent.childNodes[i] == templateElement[0]) {
+ index = i;
}
- });
+ }
}
- }
- }
+ template = this.templatize(templateElement, index) || new Template();
+ return function(scope, cloneConnectFn){
+ assertArg(scope, 'scope');
+ // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
+ // and sometimes changes the structure of the DOM.
+ var element = cloneConnectFn
+ ? JQLitePrototype.clone.call(templateElement) // IMPORTANT!!!
+ : templateElement;
+ element.data($$scope, scope);
+ scope.$element = element;
+ (cloneConnectFn||noop)(element, scope);
+ template.link(element, scope);
+ return element;
+ };
+ },
- if (directives) {
- // Process attributes/directives
- eachAttribute(element, function(value, name){
- forEach(self.attrMarkup, function(markup){
- markup.call(selfApi, value, name, element);
+ templatize: function(element, elementIndex){
+ var self = this,
+ widget,
+ fn,
+ directiveFns = self.directives,
+ descend = true,
+ directives = true,
+ elementName = nodeName_(element),
+ elementNamespace = elementName.indexOf(':') > 0 ? lowercase(elementName).replace(':', '-') : '',
+ template,
+ selfApi = {
+ compile: bind(self, self.compile),
+ descend: function(value){ if(isDefined(value)) descend = value; return descend;},
+ directives: function(value){ if(isDefined(value)) directives = value; return directives;},
+ scope: function(value){ if(isDefined(value)) template.newScope = template.newScope || value; return template.newScope;}
+ };
+ element.addClass(elementNamespace);
+ template = new Template();
+ eachAttribute(element, function(value, name){
+ if (!widget) {
+ if ((widget = self.widgets('@' + name))) {
+ element.addClass('ng-attr-widget');
+ widget = bind(selfApi, widget, value, element);
+ }
+ }
});
- });
- eachAttribute(element, function(value, name){
- name = lowercase(name);
- fn = directiveFns[name];
- if (fn) {
- element.addClass('ng-directive');
- template.addLinkFn((directiveFns[name]).call(selfApi, value, element));
+ if (!widget) {
+ if ((widget = self.widgets(elementName))) {
+ if (elementNamespace)
+ element.addClass('ng-widget');
+ widget = bind(selfApi, widget, element);
+ }
}
- });
- }
- // Process non text child nodes
- if (descend) {
- eachNode(element, function(child, i){
- template.addChild(i, self.templatize(child, i));
- });
- }
- return template.empty() ? null : template;
- }
- };
+ if (widget) {
+ descend = false;
+ directives = false;
+ var parent = element.parent();
+ template.addLinkFn(widget.call(selfApi, element));
+ if (parent && parent[0]) {
+ element = jqLite(parent[0].childNodes[elementIndex]);
+ }
+ }
+ if (descend){
+ // process markup for text nodes only
+ for(var i=0, child=element[0].childNodes;
+ i<child.length; i++) {
+ if (isTextNode(child[i])) {
+ forEach(self.markup, function(markup){
+ if (i<child.length) {
+ var textNode = jqLite(child[i]);
+ markup.call(selfApi, textNode.text(), textNode, element);
+ }
+ });
+ }
+ }
+ }
+
+ if (directives) {
+ // Process attributes/directives
+ eachAttribute(element, function(value, name){
+ forEach(self.attrMarkup, function(markup){
+ markup.call(selfApi, value, name, element);
+ });
+ });
+ eachAttribute(element, function(value, name){
+ name = lowercase(name);
+ fn = directiveFns[name];
+ if (fn) {
+ element.addClass('ng-directive');
+ template.addLinkFn((directiveFns[name]).call(selfApi, value, element));
+ }
+ });
+ }
+ // Process non text child nodes
+ if (descend) {
+ eachNode(element, function(child, i){
+ template.addChild(i, self.templatize(child, i));
+ });
+ }
+ return template.empty() ? null : template;
+ }
+ };
- /////////////////////////////////////////////////////////////////////
- var compiler = new Compiler($textMarkup, $attrMarkup, $directive, $widget);
- return bind(compiler, compiler.compile);
-}, ['$injector', '$exceptionHandler', '$textMarkup', '$attrMarkup', '$directive', '$widget']);
+ /////////////////////////////////////////////////////////////////////
+ var compiler = new Compiler($textMarkup, $attrMarkup, $directive, $widget);
+ return bind(compiler, compiler.compile);
+ }];
+};
function eachNode(element, fn){
diff --git a/src/service/cookieStore.js b/src/service/cookieStore.js
index 1b38cfac..0aa13ed2 100644
--- a/src/service/cookieStore.js
+++ b/src/service/cookieStore.js
@@ -11,52 +11,54 @@
* deserialized by angular's toJson/fromJson.
* @example
*/
-angularServiceInject('$cookieStore', function($store) {
+function $CookieStoreProvider(){
+ this.$get = ['$cookies', function($cookies) {
- return {
- /**
- * @ngdoc method
- * @name angular.service.$cookieStore#get
- * @methodOf angular.service.$cookieStore
- *
- * @description
- * Returns the value of given cookie key
- *
- * @param {string} key Id to use for lookup.
- * @returns {Object} Deserialized cookie value.
- */
- get: function(key) {
- return fromJson($store[key]);
- },
+ return {
+ /**
+ * @ngdoc method
+ * @name angular.service.$cookieStore#get
+ * @methodOf angular.service.$cookieStore
+ *
+ * @description
+ * Returns the value of given cookie key
+ *
+ * @param {string} key Id to use for lookup.
+ * @returns {Object} Deserialized cookie value.
+ */
+ get: function(key) {
+ return fromJson($cookies[key]);
+ },
- /**
- * @ngdoc method
- * @name angular.service.$cookieStore#put
- * @methodOf angular.service.$cookieStore
- *
- * @description
- * Sets a value for given cookie key
- *
- * @param {string} key Id for the `value`.
- * @param {Object} value Value to be stored.
- */
- put: function(key, value) {
- $store[key] = toJson(value);
- },
+ /**
+ * @ngdoc method
+ * @name angular.service.$cookieStore#put
+ * @methodOf angular.service.$cookieStore
+ *
+ * @description
+ * Sets a value for given cookie key
+ *
+ * @param {string} key Id for the `value`.
+ * @param {Object} value Value to be stored.
+ */
+ put: function(key, value) {
+ $cookies[key] = toJson(value);
+ },
- /**
- * @ngdoc method
- * @name angular.service.$cookieStore#remove
- * @methodOf angular.service.$cookieStore
- *
- * @description
- * Remove given cookie
- *
- * @param {string} key Id of the key-value pair to delete.
- */
- remove: function(key) {
- delete $store[key];
- }
- };
+ /**
+ * @ngdoc method
+ * @name angular.service.$cookieStore#remove
+ * @methodOf angular.service.$cookieStore
+ *
+ * @description
+ * Remove given cookie
+ *
+ * @param {string} key Id of the key-value pair to delete.
+ */
+ remove: function(key) {
+ delete $cookies[key];
+ }
+ };
-}, ['$cookies']);
+ }];
+}
diff --git a/src/service/cookies.js b/src/service/cookies.js
index 2cd2b9d6..16e14847 100644
--- a/src/service/cookies.js
+++ b/src/service/cookies.js
@@ -13,80 +13,82 @@
*
* @example
*/
-angularServiceInject('$cookies', function($rootScope, $browser) {
- var cookies = {},
- lastCookies = {},
- lastBrowserCookies,
- runEval = false;
+function $CookiesProvider() {
+ this.$get = ['$rootScope', '$browser', function ($rootScope, $browser) {
+ var cookies = {},
+ lastCookies = {},
+ lastBrowserCookies,
+ runEval = false;
- //creates a poller fn that copies all cookies from the $browser to service & inits the service
- $browser.addPollFn(function() {
- var currentCookies = $browser.cookies();
- if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl
- lastBrowserCookies = currentCookies;
- copy(currentCookies, lastCookies);
- copy(currentCookies, cookies);
- if (runEval) $rootScope.$apply();
- }
- })();
+ //creates a poller fn that copies all cookies from the $browser to service & inits the service
+ $browser.addPollFn(function() {
+ var currentCookies = $browser.cookies();
+ if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl
+ lastBrowserCookies = currentCookies;
+ copy(currentCookies, lastCookies);
+ copy(currentCookies, cookies);
+ if (runEval) $rootScope.$apply();
+ }
+ })();
- runEval = true;
+ runEval = true;
- //at the end of each eval, push cookies
- //TODO: this should happen before the "delayed" watches fire, because if some cookies are not
- // strings or browser refuses to store some cookies, we update the model in the push fn.
- $rootScope.$watch(push);
+ //at the end of each eval, push cookies
+ //TODO: this should happen before the "delayed" watches fire, because if some cookies are not
+ // strings or browser refuses to store some cookies, we update the model in the push fn.
+ $rootScope.$watch(push);
- return cookies;
+ return cookies;
- /**
- * Pushes all the cookies from the service to the browser and verifies if all cookies were stored.
- */
- function push() {
- var name,
- value,
- browserCookies,
- updated;
+ /**
+ * Pushes all the cookies from the service to the browser and verifies if all cookies were stored.
+ */
+ function push() {
+ var name,
+ value,
+ browserCookies,
+ updated;
- //delete any cookies deleted in $cookies
- for (name in lastCookies) {
- if (isUndefined(cookies[name])) {
- $browser.cookies(name, undefined);
+ //delete any cookies deleted in $cookies
+ for (name in lastCookies) {
+ if (isUndefined(cookies[name])) {
+ $browser.cookies(name, undefined);
+ }
}
- }
- //update all cookies updated in $cookies
- for(name in cookies) {
- value = cookies[name];
- if (!isString(value)) {
- if (isDefined(lastCookies[name])) {
- cookies[name] = lastCookies[name];
- } else {
- delete cookies[name];
+ //update all cookies updated in $cookies
+ for(name in cookies) {
+ value = cookies[name];
+ if (!isString(value)) {
+ if (isDefined(lastCookies[name])) {
+ cookies[name] = lastCookies[name];
+ } else {
+ delete cookies[name];
+ }
+ } else if (value !== lastCookies[name]) {
+ $browser.cookies(name, value);
+ updated = true;
}
- } else if (value !== lastCookies[name]) {
- $browser.cookies(name, value);
- updated = true;
}
- }
- //verify what was actually stored
- if (updated){
- updated = false;
- browserCookies = $browser.cookies();
+ //verify what was actually stored
+ if (updated){
+ updated = false;
+ browserCookies = $browser.cookies();
- for (name in cookies) {
- if (cookies[name] !== browserCookies[name]) {
- //delete or reset all cookies that the browser dropped from $cookies
- if (isUndefined(browserCookies[name])) {
- delete cookies[name];
- } else {
- cookies[name] = browserCookies[name];
+ for (name in cookies) {
+ if (cookies[name] !== browserCookies[name]) {
+ //delete or reset all cookies that the browser dropped from $cookies
+ if (isUndefined(browserCookies[name])) {
+ delete cookies[name];
+ } else {
+ cookies[name] = browserCookies[name];
+ }
+ updated = true;
}
- updated = true;
}
}
}
- }
-}, ['$rootScope', '$browser']);
+ }];
+}
diff --git a/src/service/defer.js b/src/service/defer.js
index 07c98065..90e6f19f 100644
--- a/src/service/defer.js
+++ b/src/service/defer.js
@@ -28,16 +28,18 @@
* @param {*} deferId Token returned by the `$defer` function.
* @returns {boolean} Returns `true` if the task hasn't executed yet and was successfuly canceled.
*/
-angularServiceInject('$defer', function($rootScope, $browser) {
- function defer(fn, delay) {
- return $browser.defer(function() {
- $rootScope.$apply(fn);
- }, delay);
- }
+function $DeferProvider(){
+ this.$get = ['$rootScope', '$browser', function($rootScope, $browser) {
+ function defer(fn, delay) {
+ return $browser.defer(function() {
+ $rootScope.$apply(fn);
+ }, delay);
+ }
- defer.cancel = function(deferId) {
- return $browser.defer.cancel(deferId);
- };
+ defer.cancel = function(deferId) {
+ return $browser.defer.cancel(deferId);
+ };
- return defer;
-}, ['$rootScope', '$browser']);
+ return defer;
+ }];
+}
diff --git a/src/service/document.js b/src/service/document.js
index ae13c1ed..f71ac33a 100644
--- a/src/service/document.js
+++ b/src/service/document.js
@@ -9,6 +9,8 @@
* A {@link angular.element jQuery (lite)}-wrapped reference to the browser's `window.document`
* element.
*/
-angularServiceInject("$document", function(window){
- return jqLite(window.document);
-}, ['$window']);
+function $DocumentProvider(){
+ this.$get = ['$window', function(window){
+ return jqLite(window.document);
+ }];
+}
diff --git a/src/service/exceptionHandler.js b/src/service/exceptionHandler.js
index 4bf6b6a6..b0c8e822 100644
--- a/src/service/exceptionHandler.js
+++ b/src/service/exceptionHandler.js
@@ -15,9 +15,10 @@
*
* @example
*/
-var $exceptionHandlerFactory; //reference to be used only in tests
-angularServiceInject('$exceptionHandler', $exceptionHandlerFactory = function($log){
- return function(e) {
- $log.error(e);
- };
-}, ['$log']);
+function $ExceptionHandlerProvider(){
+ this.$get = ['$log', function($log){
+ return function(e) {
+ $log.error(e);
+ };
+ }];
+}
diff --git a/src/service/formFactory.js b/src/service/formFactory.js
index fa6ad201..c9cb9c53 100644
--- a/src/service/formFactory.js
+++ b/src/service/formFactory.js
@@ -96,297 +96,299 @@
</doc:scenario>
</doc:example>
*/
-angularServiceInject('$formFactory', function($rootScope) {
+function $FormFactoryProvider() {
+ this.$get = ['$rootScope', function($rootScope) {
+
+ /**
+ * @ngdoc proprety
+ * @name rootForm
+ * @propertyOf angular.service.$formFactory
+ * @description
+ * Static property on `$formFactory`
+ *
+ * Each application ({@link guide/dev_guide.scopes.internals root scope}) gets a root form which
+ * is the top-level parent of all forms.
+ */
+ formFactory.rootForm = formFactory($rootScope);
+
+
+ /**
+ * @ngdoc method
+ * @name forElement
+ * @methodOf angular.service.$formFactory
+ * @description
+ * Static method on `$formFactory` service.
+ *
+ * Retrieve the closest form for a given element or defaults to the `root` form. Used by the
+ * {@link angular.widget.form form} element.
+ * @param {Element} element The element where the search for form should initiate.
+ */
+ formFactory.forElement = function(element) {
+ return element.inheritedData('$form') || formFactory.rootForm;
+ };
+ return formFactory;
+
+ function formFactory(parent) {
+ return (parent || formFactory.rootForm).$new(FormController);
+ }
+
+ }];
+
+ function propertiesUpdate(widget) {
+ widget.$valid = !(widget.$invalid =
+ !(widget.$readonly || widget.$disabled || equals(widget.$error, {})));
+ }
/**
- * @ngdoc proprety
- * @name rootForm
+ * @ngdoc property
+ * @name $error
* @propertyOf angular.service.$formFactory
* @description
- * Static property on `$formFactory`
+ * Property of the form and widget instance.
*
- * Each application ({@link guide/dev_guide.scopes.internals root scope}) gets a root form which
- * is the top-level parent of all forms.
+ * Summary of all of the errors on the page. If a widget emits `$invalid` with `REQUIRED` key,
+ * then the `$error` object will have a `REQUIRED` key with an array of widgets which have
+ * emitted this key. `form.$error.REQUIRED == [ widget ]`.
*/
- formFactory.rootForm = formFactory($rootScope);
-
/**
- * @ngdoc method
- * @name forElement
- * @methodOf angular.service.$formFactory
+ * @ngdoc property
+ * @name $invalid
+ * @propertyOf angular.service.$formFactory
* @description
- * Static method on `$formFactory` service.
+ * Property of the form and widget instance.
*
- * Retrieve the closest form for a given element or defaults to the `root` form. Used by the
- * {@link angular.widget.form form} element.
- * @param {Element} element The element where the search for form should initiate.
+ * True if any of the widgets of the form are invalid.
*/
- formFactory.forElement = function(element) {
- return element.inheritedData('$form') || formFactory.rootForm;
- };
- return formFactory;
-
- function formFactory(parent) {
- return (parent || formFactory.rootForm).$new(FormController);
- }
-
-}, ['$rootScope']);
-function propertiesUpdate(widget) {
- widget.$valid = !(widget.$invalid =
- !(widget.$readonly || widget.$disabled || equals(widget.$error, {})));
-}
-
-/**
- * @ngdoc property
- * @name $error
- * @propertyOf angular.service.$formFactory
- * @description
- * Property of the form and widget instance.
- *
- * Summary of all of the errors on the page. If a widget emits `$invalid` with `REQUIRED` key,
- * then the `$error` object will have a `REQUIRED` key with an array of widgets which have
- * emitted this key. `form.$error.REQUIRED == [ widget ]`.
- */
-
-/**
- * @ngdoc property
- * @name $invalid
- * @propertyOf angular.service.$formFactory
- * @description
- * Property of the form and widget instance.
- *
- * True if any of the widgets of the form are invalid.
- */
-
-/**
- * @ngdoc property
- * @name $valid
- * @propertyOf angular.service.$formFactory
- * @description
- * Property of the form and widget instance.
- *
- * True if all of the widgets of the form are valid.
- */
+ /**
+ * @ngdoc property
+ * @name $valid
+ * @propertyOf angular.service.$formFactory
+ * @description
+ * Property of the form and widget instance.
+ *
+ * True if all of the widgets of the form are valid.
+ */
-/**
- * @ngdoc event
- * @name angular.service.$formFactory#$valid
- * @eventOf angular.service.$formFactory
- * @eventType listen on form
- * @description
- * Upon receiving the `$valid` event from the widget update the `$error`, `$valid` and `$invalid`
- * properties of both the widget as well as the from.
- *
- * @param {String} validationKey The validation key to be used when updating the `$error` object.
- * The validation key is what will allow the template to bind to a specific validation error
- * such as `<div ng:show="form.$error.KEY">error for key</div>`.
- */
+ /**
+ * @ngdoc event
+ * @name angular.service.$formFactory#$valid
+ * @eventOf angular.service.$formFactory
+ * @eventType listen on form
+ * @description
+ * Upon receiving the `$valid` event from the widget update the `$error`, `$valid` and `$invalid`
+ * properties of both the widget as well as the from.
+ *
+ * @param {String} validationKey The validation key to be used when updating the `$error` object.
+ * The validation key is what will allow the template to bind to a specific validation error
+ * such as `<div ng:show="form.$error.KEY">error for key</div>`.
+ */
-/**
- * @ngdoc event
- * @name angular.service.$formFactory#$invalid
- * @eventOf angular.service.$formFactory
- * @eventType listen on form
- * @description
- * Upon receiving the `$invalid` event from the widget update the `$error`, `$valid` and `$invalid`
- * properties of both the widget as well as the from.
- *
- * @param {String} validationKey The validation key to be used when updating the `$error` object.
- * The validation key is what will allow the template to bind to a specific validation error
- * such as `<div ng:show="form.$error.KEY">error for key</div>`.
- */
+ /**
+ * @ngdoc event
+ * @name angular.service.$formFactory#$invalid
+ * @eventOf angular.service.$formFactory
+ * @eventType listen on form
+ * @description
+ * Upon receiving the `$invalid` event from the widget update the `$error`, `$valid` and `$invalid`
+ * properties of both the widget as well as the from.
+ *
+ * @param {String} validationKey The validation key to be used when updating the `$error` object.
+ * The validation key is what will allow the template to bind to a specific validation error
+ * such as `<div ng:show="form.$error.KEY">error for key</div>`.
+ */
-/**
- * @ngdoc event
- * @name angular.service.$formFactory#$validate
- * @eventOf angular.service.$formFactory
- * @eventType emit on widget
- * @description
- * Emit the `$validate` event on the widget, giving a widget a chance to emit a
- * `$valid` / `$invalid` event base on its state. The `$validate` event is triggered when the
- * model or the view changes.
- */
+ /**
+ * @ngdoc event
+ * @name angular.service.$formFactory#$validate
+ * @eventOf angular.service.$formFactory
+ * @eventType emit on widget
+ * @description
+ * Emit the `$validate` event on the widget, giving a widget a chance to emit a
+ * `$valid` / `$invalid` event base on its state. The `$validate` event is triggered when the
+ * model or the view changes.
+ */
-/**
- * @ngdoc event
- * @name angular.service.$formFactory#$viewChange
- * @eventOf angular.service.$formFactory
- * @eventType listen on widget
- * @description
- * A widget is responsible for emitting this event whenever the view changes do to user interaction.
- * The event takes a `$viewValue` parameter, which is the new value of the view. This
- * event triggers a call to `$parseView()` as well as `$validate` event on widget.
- *
- * @param {*} viewValue The new value for the view which will be assigned to `widget.$viewValue`.
- */
+ /**
+ * @ngdoc event
+ * @name angular.service.$formFactory#$viewChange
+ * @eventOf angular.service.$formFactory
+ * @eventType listen on widget
+ * @description
+ * A widget is responsible for emitting this event whenever the view changes do to user interaction.
+ * The event takes a `$viewValue` parameter, which is the new value of the view. This
+ * event triggers a call to `$parseView()` as well as `$validate` event on widget.
+ *
+ * @param {*} viewValue The new value for the view which will be assigned to `widget.$viewValue`.
+ */
-function FormController() {
- var form = this,
- $error = form.$error = {};
+ function FormController() {
+ var form = this,
+ $error = form.$error = {};
- form.$on('$destroy', function(event){
- var widget = event.targetScope;
- if (widget.$widgetId) {
- delete form[widget.$widgetId];
- }
- forEach($error, removeWidget, widget);
- });
+ form.$on('$destroy', function(event){
+ var widget = event.targetScope;
+ if (widget.$widgetId) {
+ delete form[widget.$widgetId];
+ }
+ forEach($error, removeWidget, widget);
+ });
+
+ form.$on('$valid', function(event, error){
+ var widget = event.targetScope;
+ delete widget.$error[error];
+ propertiesUpdate(widget);
+ removeWidget($error[error], error, widget);
+ });
+
+ form.$on('$invalid', function(event, error){
+ var widget = event.targetScope;
+ addWidget(error, widget);
+ widget.$error[error] = true;
+ propertiesUpdate(widget);
+ });
- form.$on('$valid', function(event, error){
- var widget = event.targetScope;
- delete widget.$error[error];
- propertiesUpdate(widget);
- removeWidget($error[error], error, widget);
- });
+ propertiesUpdate(form);
- form.$on('$invalid', function(event, error){
- var widget = event.targetScope;
- addWidget(error, widget);
- widget.$error[error] = true;
- propertiesUpdate(widget);
- });
-
- propertiesUpdate(form);
-
- function removeWidget(queue, errorKey, widget) {
- if (queue) {
- widget = widget || this; // so that we can be used in forEach;
- for (var i = 0, length = queue.length; i < length; i++) {
- if (queue[i] === widget) {
- queue.splice(i, 1);
- if (!queue.length) {
- delete $error[errorKey];
+ function removeWidget(queue, errorKey, widget) {
+ if (queue) {
+ widget = widget || this; // so that we can be used in forEach;
+ for (var i = 0, length = queue.length; i < length; i++) {
+ if (queue[i] === widget) {
+ queue.splice(i, 1);
+ if (!queue.length) {
+ delete $error[errorKey];
+ }
}
}
+ propertiesUpdate(form);
}
- propertiesUpdate(form);
}
- }
- function addWidget(errorKey, widget) {
- var queue = $error[errorKey];
- if (queue) {
- for (var i = 0, length = queue.length; i < length; i++) {
- if (queue[i] === widget) {
- return;
+ function addWidget(errorKey, widget) {
+ var queue = $error[errorKey];
+ if (queue) {
+ for (var i = 0, length = queue.length; i < length; i++) {
+ if (queue[i] === widget) {
+ return;
+ }
}
+ } else {
+ $error[errorKey] = queue = [];
}
- } else {
- $error[errorKey] = queue = [];
+ queue.push(widget);
+ propertiesUpdate(form);
}
- queue.push(widget);
- propertiesUpdate(form);
}
-}
-/**
- * @ngdoc method
- * @name $createWidget
- * @methodOf angular.service.$formFactory
- * @description
- *
- * Use form's `$createWidget` instance method to create new widgets. The widgets can be created
- * using an alias which makes the accessible from the form and available for data-binding,
- * useful for displaying validation error messages.
- *
- * The creation of a widget sets up:
- *
- * - `$watch` of `expression` on `model` scope. This code path syncs the model to the view.
- * The `$watch` listener will:
- *
- * - assign the new model value of `expression` to `widget.$modelValue`.
- * - call `widget.$parseModel` method if present. The `$parseModel` is responsible for copying
- * the `widget.$modelValue` to `widget.$viewValue` and optionally converting the data.
- * (For example to convert a number into string)
- * - emits `$validate` event on widget giving a widget a chance to emit `$valid` / `$invalid`
- * event.
- * - call `widget.$render()` method on widget. The `$render` method is responsible for
- * reading the `widget.$viewValue` and updating the DOM.
- *
- * - Listen on `$viewChange` event from the `widget`. This code path syncs the view to the model.
- * The `$viewChange` listener will:
- *
- * - assign the value to `widget.$viewValue`.
- * - call `widget.$parseView` method if present. The `$parseView` is responsible for copying
- * the `widget.$viewValue` to `widget.$modelValue` and optionally converting the data.
- * (For example to convert a string into number)
- * - emits `$validate` event on widget giving a widget a chance to emit `$valid` / `$invalid`
- * event.
- * - Assign the `widget.$modelValue` to the `expression` on the `model` scope.
- *
- * - Creates these set of properties on the `widget` which are updated as a response to the
- * `$valid` / `$invalid` events:
- *
- * - `$error` - object - validation errors will be published as keys on this object.
- * Data-binding to this property is useful for displaying the validation errors.
- * - `$valid` - boolean - true if there are no validation errors
- * - `$invalid` - boolean - opposite of `$valid`.
- * @param {Object} params Named parameters:
- *
- * - `scope` - `{Scope}` - The scope to which the model for this widget is attached.
- * - `model` - `{string}` - The name of the model property on model scope.
- * - `controller` - {WidgetController} - The controller constructor function.
- * The controller constructor should create these instance methods.
- * - `$parseView()`: optional method responsible for copying `$viewVale` to `$modelValue`.
- * The method may fire `$valid`/`$invalid` events.
- * - `$parseModel()`: optional method responsible for copying `$modelVale` to `$viewValue`.
- * The method may fire `$valid`/`$invalid` events.
- * - `$render()`: required method which needs to update the DOM of the widget to match the
- * `$viewValue`.
- *
- * - `controllerArgs` - `{Array}` (Optional) - Any extra arguments will be curried to the
- * WidgetController constructor.
- * - `onChange` - `{(string|function())}` (Optional) - Expression to execute when user changes the
- * value.
- * - `alias` - `{string}` (Optional) - The name of the form property under which the widget
- * instance should be published. The name should be unique for each form.
- * @returns {Widget} Instance of a widget scope.
- */
-FormController.prototype.$createWidget = function(params) {
- var form = this,
- modelScope = params.scope,
- onChange = params.onChange,
- alias = params.alias,
- scopeGet = parser(params.model).assignable(),
- scopeSet = scopeGet.assign,
- widget = this.$new(params.controller, params.controllerArgs);
-
- widget.$error = {};
- // Set the state to something we know will change to get the process going.
- widget.$modelValue = Number.NaN;
- // watch for scope changes and update the view appropriately
- modelScope.$watch(scopeGet, function(scope, value) {
- if (!equals(widget.$modelValue, value)) {
- widget.$modelValue = value;
- widget.$parseModel ? widget.$parseModel() : (widget.$viewValue = value);
- widget.$emit('$validate');
- widget.$render && widget.$render();
- }
- });
-
- widget.$on('$viewChange', function(event, viewValue){
- if (!equals(widget.$viewValue, viewValue)) {
- widget.$viewValue = viewValue;
- widget.$parseView ? widget.$parseView() : (widget.$modelValue = widget.$viewValue);
- scopeSet(modelScope, widget.$modelValue);
- if (onChange) modelScope.$eval(onChange);
- widget.$emit('$validate');
- }
- });
+ /**
+ * @ngdoc method
+ * @name $createWidget
+ * @methodOf angular.service.$formFactory
+ * @description
+ *
+ * Use form's `$createWidget` instance method to create new widgets. The widgets can be created
+ * using an alias which makes the accessible from the form and available for data-binding,
+ * useful for displaying validation error messages.
+ *
+ * The creation of a widget sets up:
+ *
+ * - `$watch` of `expression` on `model` scope. This code path syncs the model to the view.
+ * The `$watch` listener will:
+ *
+ * - assign the new model value of `expression` to `widget.$modelValue`.
+ * - call `widget.$parseModel` method if present. The `$parseModel` is responsible for copying
+ * the `widget.$modelValue` to `widget.$viewValue` and optionally converting the data.
+ * (For example to convert a number into string)
+ * - emits `$validate` event on widget giving a widget a chance to emit `$valid` / `$invalid`
+ * event.
+ * - call `widget.$render()` method on widget. The `$render` method is responsible for
+ * reading the `widget.$viewValue` and updating the DOM.
+ *
+ * - Listen on `$viewChange` event from the `widget`. This code path syncs the view to the model.
+ * The `$viewChange` listener will:
+ *
+ * - assign the value to `widget.$viewValue`.
+ * - call `widget.$parseView` method if present. The `$parseView` is responsible for copying
+ * the `widget.$viewValue` to `widget.$modelValue` and optionally converting the data.
+ * (For example to convert a string into number)
+ * - emits `$validate` event on widget giving a widget a chance to emit `$valid` / `$invalid`
+ * event.
+ * - Assign the `widget.$modelValue` to the `expression` on the `model` scope.
+ *
+ * - Creates these set of properties on the `widget` which are updated as a response to the
+ * `$valid` / `$invalid` events:
+ *
+ * - `$error` - object - validation errors will be published as keys on this object.
+ * Data-binding to this property is useful for displaying the validation errors.
+ * - `$valid` - boolean - true if there are no validation errors
+ * - `$invalid` - boolean - opposite of `$valid`.
+ * @param {Object} params Named parameters:
+ *
+ * - `scope` - `{Scope}` - The scope to which the model for this widget is attached.
+ * - `model` - `{string}` - The name of the model property on model scope.
+ * - `controller` - {WidgetController} - The controller constructor function.
+ * The controller constructor should create these instance methods.
+ * - `$parseView()`: optional method responsible for copying `$viewVale` to `$modelValue`.
+ * The method may fire `$valid`/`$invalid` events.
+ * - `$parseModel()`: optional method responsible for copying `$modelVale` to `$viewValue`.
+ * The method may fire `$valid`/`$invalid` events.
+ * - `$render()`: required method which needs to update the DOM of the widget to match the
+ * `$viewValue`.
+ *
+ * - `controllerArgs` - `{Array}` (Optional) - Any extra arguments will be curried to the
+ * WidgetController constructor.
+ * - `onChange` - `{(string|function())}` (Optional) - Expression to execute when user changes the
+ * value.
+ * - `alias` - `{string}` (Optional) - The name of the form property under which the widget
+ * instance should be published. The name should be unique for each form.
+ * @returns {Widget} Instance of a widget scope.
+ */
+ FormController.prototype.$createWidget = function(params) {
+ var form = this,
+ modelScope = params.scope,
+ onChange = params.onChange,
+ alias = params.alias,
+ scopeGet = parser(params.model).assignable(),
+ scopeSet = scopeGet.assign,
+ widget = this.$new(params.controller, params.controllerArgs);
+
+ widget.$error = {};
+ // Set the state to something we know will change to get the process going.
+ widget.$modelValue = Number.NaN;
+ // watch for scope changes and update the view appropriately
+ modelScope.$watch(scopeGet, function(scope, value) {
+ if (!equals(widget.$modelValue, value)) {
+ widget.$modelValue = value;
+ widget.$parseModel ? widget.$parseModel() : (widget.$viewValue = value);
+ widget.$emit('$validate');
+ widget.$render && widget.$render();
+ }
+ });
+
+ widget.$on('$viewChange', function(event, viewValue){
+ if (!equals(widget.$viewValue, viewValue)) {
+ widget.$viewValue = viewValue;
+ widget.$parseView ? widget.$parseView() : (widget.$modelValue = widget.$viewValue);
+ scopeSet(modelScope, widget.$modelValue);
+ if (onChange) modelScope.$eval(onChange);
+ widget.$emit('$validate');
+ }
+ });
- propertiesUpdate(widget);
+ propertiesUpdate(widget);
- // assign the widgetModel to the form
- if (alias && !form.hasOwnProperty(alias)) {
- form[alias] = widget;
- widget.$widgetId = alias;
- } else {
- alias = null;
- }
+ // assign the widgetModel to the form
+ if (alias && !form.hasOwnProperty(alias)) {
+ form[alias] = widget;
+ widget.$widgetId = alias;
+ } else {
+ alias = null;
+ }
- return widget;
-};
+ return widget;
+ };
+}
diff --git a/src/service/locale.js b/src/service/locale.js
index 069a691e..aae325ae 100644
--- a/src/service/locale.js
+++ b/src/service/locale.js
@@ -10,61 +10,63 @@
*
* * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
*/
-angularServiceInject('$locale', function() {
- return {
- id: 'en-us',
+function $LocaleProvider(){
+ this.$get = function() {
+ return {
+ id: 'en-us',
- NUMBER_FORMATS: {
- DECIMAL_SEP: '.',
- GROUP_SEP: ',',
- PATTERNS: [
- { // Decimal Pattern
- minInt: 1,
- minFrac: 0,
- maxFrac: 3,
- posPre: '',
- posSuf: '',
- negPre: '-',
- negSuf: '',
- gSize: 3,
- lgSize: 3
- },{ //Currency Pattern
- minInt: 1,
- minFrac: 2,
- maxFrac: 2,
- posPre: '\u00A4',
- posSuf: '',
- negPre: '(\u00A4',
- negSuf: ')',
- gSize: 3,
- lgSize: 3
- }
- ],
- CURRENCY_SYM: '$'
- },
+ NUMBER_FORMATS: {
+ DECIMAL_SEP: '.',
+ GROUP_SEP: ',',
+ PATTERNS: [
+ { // Decimal Pattern
+ minInt: 1,
+ minFrac: 0,
+ maxFrac: 3,
+ posPre: '',
+ posSuf: '',
+ negPre: '-',
+ negSuf: '',
+ gSize: 3,
+ lgSize: 3
+ },{ //Currency Pattern
+ minInt: 1,
+ minFrac: 2,
+ maxFrac: 2,
+ posPre: '\u00A4',
+ posSuf: '',
+ negPre: '(\u00A4',
+ negSuf: ')',
+ gSize: 3,
+ lgSize: 3
+ }
+ ],
+ CURRENCY_SYM: '$'
+ },
- DATETIME_FORMATS: {
- MONTH: 'January,February,March,April,May,June,July,August,September,October,November,December'
- .split(','),
- SHORTMONTH: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
- DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
- SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
- AMPMS: ['AM','PM'],
- medium: 'MMM d, y h:mm:ss a',
- short: 'M/d/yy h:mm a',
- fullDate: 'EEEE, MMMM d, y',
- longDate: 'MMMM d, y',
- mediumDate: 'MMM d, y',
- shortDate: 'M/d/yy',
- mediumTime: 'h:mm:ss a',
- shortTime: 'h:mm a'
- },
+ DATETIME_FORMATS: {
+ MONTH: 'January,February,March,April,May,June,July,August,September,October,November,December'
+ .split(','),
+ SHORTMONTH: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
+ DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
+ SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
+ AMPMS: ['AM','PM'],
+ medium: 'MMM d, y h:mm:ss a',
+ short: 'M/d/yy h:mm a',
+ fullDate: 'EEEE, MMMM d, y',
+ longDate: 'MMMM d, y',
+ mediumDate: 'MMM d, y',
+ shortDate: 'M/d/yy',
+ mediumTime: 'h:mm:ss a',
+ shortTime: 'h:mm a'
+ },
- pluralCat: function(num) {
- if (num === 1) {
- return 'one';
+ pluralCat: function(num) {
+ if (num === 1) {
+ return 'one';
+ }
+ return 'other';
}
- return 'other';
- }
+ };
};
-});
+}
diff --git a/src/service/location.js b/src/service/location.js
index c9b76122..7cc5c273 100644
--- a/src/service/location.js
+++ b/src/service/location.js
@@ -419,94 +419,99 @@ function locationGetterSetter(property, preprocess) {
*
* For more information see {@link guide/dev_guide.services.$location Developer Guide: Angular Services: Using $location}
*/
-angularServiceInject('$location', function($rootScope, $browser, $sniffer, $locationConfig, $document) {
- var currentUrl,
- basePath = $browser.baseHref() || '/',
- pathPrefix = pathPrefixFromBase(basePath),
- hashPrefix = $locationConfig.hashPrefix || '',
- initUrl = $browser.url();
-
- if ($locationConfig.html5Mode) {
- if ($sniffer.history) {
- currentUrl = new LocationUrl(convertToHtml5Url(initUrl, basePath, hashPrefix), pathPrefix);
- } else {
- currentUrl = new LocationHashbangUrl(convertToHashbangUrl(initUrl, basePath, hashPrefix),
- hashPrefix);
- }
-
- // link rewriting
- var u = currentUrl,
- absUrlPrefix = composeProtocolHostPort(u.protocol(), u.host(), u.port()) + pathPrefix;
+function $LocationProvider(){
+ this.$get = ['$rootScope', '$browser', '$sniffer', '$locationConfig', '$document',
+ function( $rootScope, $browser, $sniffer, $locationConfig, $document) {
+ var currentUrl,
+ basePath = $browser.baseHref() || '/',
+ pathPrefix = pathPrefixFromBase(basePath),
+ hashPrefix = $locationConfig.hashPrefix || '',
+ initUrl = $browser.url();
- $document.bind('click', function(event) {
- // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
- // currently we open nice url link and redirect then
+ if ($locationConfig.html5Mode) {
+ if ($sniffer.history) {
+ currentUrl = new LocationUrl(convertToHtml5Url(initUrl, basePath, hashPrefix), pathPrefix);
+ } else {
+ currentUrl = new LocationHashbangUrl(convertToHashbangUrl(initUrl, basePath, hashPrefix),
+ hashPrefix);
+ }
- if (event.ctrlKey || event.metaKey || event.which == 2) return;
+ // link rewriting
+ var u = currentUrl,
+ absUrlPrefix = composeProtocolHostPort(u.protocol(), u.host(), u.port()) + pathPrefix;
- var elm = jqLite(event.target);
+ $document.bind('click', function(event) {
+ // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
+ // currently we open nice url link and redirect then
- // traverse the DOM up to find first A tag
- while (elm.length && lowercase(elm[0].nodeName) !== 'a') {
- elm = elm.parent();
- }
+ if (event.ctrlKey || event.metaKey || event.which == 2) return;
- var href = elm.attr('href');
- if (!href || isDefined(elm.attr('ng:ext-link')) || elm.attr('target')) return;
+ var elm = jqLite(event.target);
- // remove same domain from full url links (IE7 always returns full hrefs)
- href = href.replace(absUrlPrefix, '');
+ // traverse the DOM up to find first A tag
+ while (elm.length && lowercase(elm[0].nodeName) !== 'a') {
+ elm = elm.parent();
+ }
- // link to different domain (or base path)
- if (href.substr(0, 4) == 'http') return;
+ var href = elm.attr('href');
+ if (!href || isDefined(elm.attr('ng:ext-link')) || elm.attr('target')) return;
- // remove pathPrefix from absolute links
- href = href.indexOf(pathPrefix) === 0 ? href.substr(pathPrefix.length) : href;
+ // remove same domain from full url links (IE7 always returns full hrefs)
+ href = href.replace(absUrlPrefix, '');
- currentUrl.url(href);
- $rootScope.$apply();
- event.preventDefault();
- // hack to work around FF6 bug 684208 when scenario runner clicks on links
- window.angular['ff-684208-preventDefault'] = true;
- });
- } else {
- currentUrl = new LocationHashbangUrl(initUrl, hashPrefix);
- }
+ // link to different domain (or base path)
+ if (href.substr(0, 4) == 'http') return;
- // rewrite hashbang url <> html5 url
- if (currentUrl.absUrl() != initUrl) {
- $browser.url(currentUrl.absUrl(), true);
- }
+ // remove pathPrefix from absolute links
+ href = href.indexOf(pathPrefix) === 0 ? href.substr(pathPrefix.length) : href;
- // update $location when $browser url changes
- $browser.onUrlChange(function(newUrl) {
- if (currentUrl.absUrl() != newUrl) {
- currentUrl.$$parse(newUrl);
- $rootScope.$apply();
- }
- });
-
- // update browser
- var changeCounter = 0;
- $rootScope.$watch(function() {
- if ($browser.url() != currentUrl.absUrl()) {
- changeCounter++;
- $rootScope.$evalAsync(function() {
- $browser.url(currentUrl.absUrl(), currentUrl.$$replace);
- currentUrl.$$replace = false;
+ currentUrl.url(href);
+ $rootScope.$apply();
+ event.preventDefault();
+ // hack to work around FF6 bug 684208 when scenario runner clicks on links
+ window.angular['ff-684208-preventDefault'] = true;
});
+ } else {
+ currentUrl = new LocationHashbangUrl(initUrl, hashPrefix);
}
- return changeCounter;
- });
+ // rewrite hashbang url <> html5 url
+ if (currentUrl.absUrl() != initUrl) {
+ $browser.url(currentUrl.absUrl(), true);
+ }
- return currentUrl;
-}, ['$rootScope', '$browser', '$sniffer', '$locationConfig', '$document']);
+ // update $location when $browser url changes
+ $browser.onUrlChange(function(newUrl) {
+ if (currentUrl.absUrl() != newUrl) {
+ currentUrl.$$parse(newUrl);
+ $rootScope.$apply();
+ }
+ });
+ // update browser
+ var changeCounter = 0;
+ $rootScope.$watch(function() {
+ if ($browser.url() != currentUrl.absUrl()) {
+ changeCounter++;
+ $rootScope.$evalAsync(function() {
+ $browser.url(currentUrl.absUrl(), currentUrl.$$replace);
+ currentUrl.$$replace = false;
+ });
+ }
-angular.service('$locationConfig', function() {
- return {
- html5Mode: false,
- hashPrefix: ''
+ return changeCounter;
+ });
+
+ return currentUrl;
+}];
+}
+
+//TODO(misko): refactor to service
+function $LocationConfigProvider(){
+ this.$get = function() {
+ return {
+ html5Mode: false,
+ hashPrefix: ''
+ };
};
-});
+}
diff --git a/src/service/log.js b/src/service/log.js
index 29577166..59094c42 100644
--- a/src/service/log.js
+++ b/src/service/log.js
@@ -34,64 +34,78 @@
</doc:scenario>
</doc:example>
*/
-var $logFactory; //reference to be used only in tests
-angularServiceInject("$log", $logFactory = function($window){
- return {
- /**
- * @ngdoc method
- * @name angular.service.$log#log
- * @methodOf angular.service.$log
- *
- * @description
- * Write a log message
- */
- log: consoleLog('log'),
- /**
- * @ngdoc method
- * @name angular.service.$log#warn
- * @methodOf angular.service.$log
- *
- * @description
- * Write a warning message
- */
- warn: consoleLog('warn'),
+function $LogProvider(){
+ this.$get = ['$window', function($window){
+ return {
+ /**
+ * @ngdoc method
+ * @name angular.service.$log#log
+ * @methodOf angular.service.$log
+ *
+ * @description
+ * Write a log message
+ */
+ log: consoleLog('log'),
- /**
- * @ngdoc method
- * @name angular.service.$log#info
- * @methodOf angular.service.$log
- *
- * @description
- * Write an information message
- */
- info: consoleLog('info'),
+ /**
+ * @ngdoc method
+ * @name angular.service.$log#warn
+ * @methodOf angular.service.$log
+ *
+ * @description
+ * Write a warning message
+ */
+ warn: consoleLog('warn'),
- /**
- * @ngdoc method
- * @name angular.service.$log#error
- * @methodOf angular.service.$log
- *
- * @description
- * Write an error message
- */
- error: consoleLog('error')
- };
+ /**
+ * @ngdoc method
+ * @name angular.service.$log#info
+ * @methodOf angular.service.$log
+ *
+ * @description
+ * Write an information message
+ */
+ info: consoleLog('info'),
- function consoleLog(type) {
- var console = $window.console || {};
- var logFn = console[type] || console.log || noop;
- if (logFn.apply) {
- return function() {
- var args = [];
- forEach(arguments, function(arg){
- args.push(formatError(arg));
- });
- return logFn.apply(console, args);
- };
- } else {
- // we are IE, in which case there is nothing we can do
- return logFn;
+ /**
+ * @ngdoc method
+ * @name angular.service.$log#error
+ * @methodOf angular.service.$log
+ *
+ * @description
+ * Write an error message
+ */
+ error: consoleLog('error')
+ };
+
+ function formatError(arg) {
+ if (arg instanceof Error) {
+ if (arg.stack) {
+ arg = (arg.message && arg.stack.indexOf(arg.message) === -1) ?
+ 'Error: ' + arg.message + '\n' + arg.stack : arg.stack;
+ } else if (arg.sourceURL) {
+ arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
+ }
+ }
+ return arg;
+ }
+
+ function consoleLog(type) {
+ var console = $window.console || {};
+ var logFn = console[type] || console.log || noop;
+ if (logFn.apply) {
+ return function() {
+ var args = [];
+ forEach(arguments, function(arg){
+ args.push(formatError(arg));
+ });
+ return logFn.apply(console, args);
+ };
+ } else {
+ // we are IE, in which case there is nothing we can do
+ return logFn;
+ }
}
- }
-}, ['$window']);
+ }];
+}
diff --git a/src/service/resource.js b/src/service/resource.js
index 8d77a9e4..e396e521 100644
--- a/src/service/resource.js
+++ b/src/service/resource.js
@@ -200,7 +200,9 @@
</doc:scenario>
</doc:example>
*/
-angularServiceInject('$resource', function($xhr){
- var resource = new ResourceFactory($xhr);
- return bind(resource, resource.route);
-}, ['$xhr.cache']);
+function $ResourceProvider() {
+ this.$get = ['$xhr.cache', function($xhr){
+ var resource = new ResourceFactory($xhr);
+ return bind(resource, resource.route);
+ }];
+}
diff --git a/src/service/route.js b/src/service/route.js
index 3918c251..f2ecbd2a 100644
--- a/src/service/route.js
+++ b/src/service/route.js
@@ -62,264 +62,267 @@
</doc:scenario>
</doc:example>
*/
-angularServiceInject('$route', function($rootScope, $location, $routeParams) {
- /**
- * @ngdoc event
- * @name angular.service.$route#$beforeRouteChange
- * @eventOf angular.service.$route
- * @eventType broadcast on root scope
- * @description
- * Broadcasted before a route change.
- *
- * @param {Route} next Future route information.
- * @param {Route} current Current route information.
- *
- * The `Route` object extends the route definition with the following properties.
- *
- * * `scope` - The instance of the route controller.
- * * `params` - The current {@link angular.service.$routeParams params}.
- *
- */
+function $RouteProvider(){
+ this.$get = ['$rootScope', '$location', '$routeParams',
+ function( $rootScope, $location, $routeParams) {
+ /**
+ * @ngdoc event
+ * @name angular.service.$route#$beforeRouteChange
+ * @eventOf angular.service.$route
+ * @eventType broadcast on root scope
+ * @description
+ * Broadcasted before a route change.
+ *
+ * @param {Route} next Future route information.
+ * @param {Route} current Current route information.
+ *
+ * The `Route` object extends the route definition with the following properties.
+ *
+ * * `scope` - The instance of the route controller.
+ * * `params` - The current {@link angular.service.$routeParams params}.
+ *
+ */
- /**
- * @ngdoc event
- * @name angular.service.$route#$afterRouteChange
- * @eventOf angular.service.$route
- * @eventType broadcast on root scope
- * @description
- * Broadcasted after a route change.
- *
- * @param {Route} current Current route information.
- * @param {Route} previous Previous route information.
- *
- * The `Route` object extends the route definition with the following properties.
- *
- * * `scope` - The instance of the route controller.
- * * `params` - The current {@link angular.service.$routeParams params}.
- *
- */
+ /**
+ * @ngdoc event
+ * @name angular.service.$route#$afterRouteChange
+ * @eventOf angular.service.$route
+ * @eventType broadcast on root scope
+ * @description
+ * Broadcasted after a route change.
+ *
+ * @param {Route} current Current route information.
+ * @param {Route} previous Previous route information.
+ *
+ * The `Route` object extends the route definition with the following properties.
+ *
+ * * `scope` - The instance of the route controller.
+ * * `params` - The current {@link angular.service.$routeParams params}.
+ *
+ */
- /**
- * @ngdoc event
- * @name angular.service.$route#$routeUpdate
- * @eventOf angular.service.$route
- * @eventType emit on the current route scope
- * @description
- *
- * The `reloadOnSearch` property has been set to false, and we are reusing the same
- * instance of the Controller.
- */
+ /**
+ * @ngdoc event
+ * @name angular.service.$route#$routeUpdate
+ * @eventOf angular.service.$route
+ * @eventType emit on the current route scope
+ * @description
+ *
+ * The `reloadOnSearch` property has been set to false, and we are reusing the same
+ * instance of the Controller.
+ */
- var routes = {},
- matcher = switchRouteMatcher,
- parentScope = $rootScope,
- dirty = 0,
- forceReload = false,
- $route = {
- routes: routes,
+ var routes = {},
+ matcher = switchRouteMatcher,
+ parentScope = $rootScope,
+ dirty = 0,
+ forceReload = false,
+ $route = {
+ routes: routes,
- /**
- * @ngdoc method
- * @name angular.service.$route#parent
- * @methodOf angular.service.$route
- *
- * @param {Scope} [scope=rootScope] Scope to be used as parent for newly created
- * `$route.current.scope` scopes.
- *
- * @description
- * Sets a scope to be used as the parent scope for scopes created on route change. If not
- * set, defaults to the root scope.
- */
- parent: function(scope) {
- if (scope) parentScope = scope;
- },
+ /**
+ * @ngdoc method
+ * @name angular.service.$route#parent
+ * @methodOf angular.service.$route
+ *
+ * @param {Scope} [scope=rootScope] Scope to be used as parent for newly created
+ * `$route.current.scope` scopes.
+ *
+ * @description
+ * Sets a scope to be used as the parent scope for scopes created on route change. If not
+ * set, defaults to the root scope.
+ */
+ parent: function(scope) {
+ if (scope) parentScope = scope;
+ },
- /**
- * @ngdoc method
- * @name angular.service.$route#when
- * @methodOf angular.service.$route
- *
- * @param {string} path Route path (matched against `$location.hash`)
- * @param {Object} route Mapping information to be assigned to `$route.current` on route
- * match.
- *
- * Object properties:
- *
- * - `controller` – `{function()=}` – Controller fn that should be associated with newly
- * created scope.
- * - `template` – `{string=}` – path to an html template that should be used by
- * {@link angular.widget.ng:view ng:view} or
- * {@link angular.widget.ng:include ng:include} widgets.
- * - `redirectTo` – {(string|function())=} – value to update
- * {@link angular.service.$location $location} path with and trigger route redirection.
- *
- * If `redirectTo` is a function, it will be called with the following parameters:
- *
- * - `{Object.<string>}` - route parameters extracted from the current
- * `$location.path()` by applying the current route template.
- * - `{string}` - current `$location.path()`
- * - `{Object}` - current `$location.search()`
- *
- * The custom `redirectTo` function is expected to return a string which will be used
- * to update `$location.path()` and `$location.search()`.
- *
- * - `[reloadOnSearch=true]` - {boolean=} - reload route when only $location.search()
- * changes.
- *
- * If the option is set to false and url in the browser changes, then
- * $routeUpdate event is emited on the current route scope. You can use this event to
- * react to {@link angular.service.$routeParams} changes:
- *
- * function MyCtrl($route, $routeParams) {
- * this.$on('$routeUpdate', function() {
- * // do stuff with $routeParams
- * });
- * }
- *
- * @returns {Object} route object
- *
- * @description
- * Adds a new route definition to the `$route` service.
- */
- when: function(path, route) {
- var routeDef = routes[path];
- if (!routeDef) routeDef = routes[path] = {reloadOnSearch: true};
- if (route) extend(routeDef, route); // TODO(im): what the heck? merge two route definitions?
- dirty++;
- return routeDef;
- },
+ /**
+ * @ngdoc method
+ * @name angular.service.$route#when
+ * @methodOf angular.service.$route
+ *
+ * @param {string} path Route path (matched against `$location.hash`)
+ * @param {Object} route Mapping information to be assigned to `$route.current` on route
+ * match.
+ *
+ * Object properties:
+ *
+ * - `controller` – `{function()=}` – Controller fn that should be associated with newly
+ * created scope.
+ * - `template` – `{string=}` – path to an html template that should be used by
+ * {@link angular.widget.ng:view ng:view} or
+ * {@link angular.widget.ng:include ng:include} widgets.
+ * - `redirectTo` – {(string|function())=} – value to update
+ * {@link angular.service.$location $location} path with and trigger route redirection.
+ *
+ * If `redirectTo` is a function, it will be called with the following parameters:
+ *
+ * - `{Object.<string>}` - route parameters extracted from the current
+ * `$location.path()` by applying the current route template.
+ * - `{string}` - current `$location.path()`
+ * - `{Object}` - current `$location.search()`
+ *
+ * The custom `redirectTo` function is expected to return a string which will be used
+ * to update `$location.path()` and `$location.search()`.
+ *
+ * - `[reloadOnSearch=true]` - {boolean=} - reload route when only $location.search()
+ * changes.
+ *
+ * If the option is set to false and url in the browser changes, then
+ * $routeUpdate event is emited on the current route scope. You can use this event to
+ * react to {@link angular.service.$routeParams} changes:
+ *
+ * function MyCtrl($route, $routeParams) {
+ * this.$on('$routeUpdate', function() {
+ * // do stuff with $routeParams
+ * });
+ * }
+ *
+ * @returns {Object} route object
+ *
+ * @description
+ * Adds a new route definition to the `$route` service.
+ */
+ when: function(path, route) {
+ var routeDef = routes[path];
+ if (!routeDef) routeDef = routes[path] = {reloadOnSearch: true};
+ if (route) extend(routeDef, route); // TODO(im): what the heck? merge two route definitions?
+ dirty++;
+ return routeDef;
+ },
- /**
- * @ngdoc method
- * @name angular.service.$route#otherwise
- * @methodOf angular.service.$route
- *
- * @description
- * Sets route definition that will be used on route change when no other route definition
- * is matched.
- *
- * @param {Object} params Mapping information to be assigned to `$route.current`.
- */
- otherwise: function(params) {
- $route.when(null, params);
- },
+ /**
+ * @ngdoc method
+ * @name angular.service.$route#otherwise
+ * @methodOf angular.service.$route
+ *
+ * @description
+ * Sets route definition that will be used on route change when no other route definition
+ * is matched.
+ *
+ * @param {Object} params Mapping information to be assigned to `$route.current`.
+ */
+ otherwise: function(params) {
+ $route.when(null, params);
+ },
- /**
- * @ngdoc method
- * @name angular.service.$route#reload
- * @methodOf angular.service.$route
- *
- * @description
- * Causes `$route` service to reload (and recreate the `$route.current` scope) upon the next
- * eval even if {@link angular.service.$location $location} hasn't changed.
- */
- reload: function() {
- dirty++;
- forceReload = true;
- }
- };
+ /**
+ * @ngdoc method
+ * @name angular.service.$route#reload
+ * @methodOf angular.service.$route
+ *
+ * @description
+ * Causes `$route` service to reload (and recreate the `$route.current` scope) upon the next
+ * eval even if {@link angular.service.$location $location} hasn't changed.
+ */
+ reload: function() {
+ dirty++;
+ forceReload = true;
+ }
+ };
- $rootScope.$watch(function() { return dirty + $location.url(); }, updateRoute);
+ $rootScope.$watch(function() { return dirty + $location.url(); }, updateRoute);
- return $route;
+ return $route;
- /////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////
- function switchRouteMatcher(on, when) {
- // TODO(i): this code is convoluted and inefficient, we should construct the route matching
- // regex only once and then reuse it
- var regex = '^' + when.replace(/([\.\\\(\)\^\$])/g, "\\$1") + '$',
- params = [],
- dst = {};
- forEach(when.split(/\W/), function(param) {
- if (param) {
- var paramRegExp = new RegExp(":" + param + "([\\W])");
- if (regex.match(paramRegExp)) {
- regex = regex.replace(paramRegExp, "([^\\/]*)$1");
- params.push(param);
+ function switchRouteMatcher(on, when) {
+ // TODO(i): this code is convoluted and inefficient, we should construct the route matching
+ // regex only once and then reuse it
+ var regex = '^' + when.replace(/([\.\\\(\)\^\$])/g, "\\$1") + '$',
+ params = [],
+ dst = {};
+ forEach(when.split(/\W/), function(param) {
+ if (param) {
+ var paramRegExp = new RegExp(":" + param + "([\\W])");
+ if (regex.match(paramRegExp)) {
+ regex = regex.replace(paramRegExp, "([^\\/]*)$1");
+ params.push(param);
+ }
}
- }
- });
- var match = on.match(new RegExp(regex));
- if (match) {
- forEach(params, function(name, index) {
- dst[name] = match[index + 1];
});
+ var match = on.match(new RegExp(regex));
+ if (match) {
+ forEach(params, function(name, index) {
+ dst[name] = match[index + 1];
+ });
+ }
+ return match ? dst : null;
}
- return match ? dst : null;
- }
- function updateRoute() {
- var next = parseRoute(),
- last = $route.current,
- Controller;
+ function updateRoute() {
+ var next = parseRoute(),
+ last = $route.current,
+ Controller;
- if (next && last && next.$route === last.$route
- && equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) {
- $route.current = next;
- copy(next.params, $routeParams);
- last.scope && last.scope.$emit('$routeUpdate');
- } else {
- forceReload = false;
- $rootScope.$broadcast('$beforeRouteChange', next, last);
- last && last.scope && last.scope.$destroy();
- $route.current = next;
- if (next) {
- if (next.redirectTo) {
- if (isString(next.redirectTo)) {
- $location.path(interpolate(next.redirectTo, next.params)).search(next.params)
- .replace();
+ if (next && last && next.$route === last.$route
+ && equals(next.pathParams, last.pathParams) && !next.reloadOnSearch && !forceReload) {
+ $route.current = next;
+ copy(next.params, $routeParams);
+ last.scope && last.scope.$emit('$routeUpdate');
+ } else {
+ forceReload = false;
+ $rootScope.$broadcast('$beforeRouteChange', next, last);
+ last && last.scope && last.scope.$destroy();
+ $route.current = next;
+ if (next) {
+ if (next.redirectTo) {
+ if (isString(next.redirectTo)) {
+ $location.path(interpolate(next.redirectTo, next.params)).search(next.params)
+ .replace();
+ } else {
+ $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
+ .replace();
+ }
} else {
- $location.url(next.redirectTo(next.pathParams, $location.path(), $location.search()))
- .replace();
+ copy(next.params, $routeParams);
+ (Controller = next.controller) && inferInjectionArgs(Controller);
+ next.scope = parentScope.$new(Controller);
}
- } else {
- copy(next.params, $routeParams);
- (Controller = next.controller) && inferInjectionArgs(Controller);
- next.scope = parentScope.$new(Controller);
}
+ $rootScope.$broadcast('$afterRouteChange', next, last);
}
- $rootScope.$broadcast('$afterRouteChange', next, last);
}
- }
- /**
- * @returns the current active route, by matching it against the URL
- */
- function parseRoute() {
- // Match a route
- var params, match;
- forEach(routes, function(route, path) {
- if (!match && (params = matcher($location.path(), path))) {
- match = inherit(route, {
- params: extend({}, $location.search(), params),
- pathParams: params});
- match.$route = route;
- }
- });
- // No route matched; fallback to "otherwise" route
- return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
- }
+ /**
+ * @returns the current active route, by matching it against the URL
+ */
+ function parseRoute() {
+ // Match a route
+ var params, match;
+ forEach(routes, function(route, path) {
+ if (!match && (params = matcher($location.path(), path))) {
+ match = inherit(route, {
+ params: extend({}, $location.search(), params),
+ pathParams: params});
+ match.$route = route;
+ }
+ });
+ // No route matched; fallback to "otherwise" route
+ return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
+ }
- /**
- * @returns interpolation of the redirect path with the parametrs
- */
- function interpolate(string, params) {
- var result = [];
- forEach((string||'').split(':'), function(segment, i) {
- if (i == 0) {
- result.push(segment);
- } else {
- var segmentMatch = segment.match(/(\w+)(.*)/);
- var key = segmentMatch[1];
- result.push(params[key]);
- result.push(segmentMatch[2] || '');
- delete params[key];
- }
- });
- return result.join('');
- }
+ /**
+ * @returns interpolation of the redirect path with the parametrs
+ */
+ function interpolate(string, params) {
+ var result = [];
+ forEach((string||'').split(':'), function(segment, i) {
+ if (i == 0) {
+ result.push(segment);
+ } else {
+ var segmentMatch = segment.match(/(\w+)(.*)/);
+ var key = segmentMatch[1];
+ result.push(params[key]);
+ result.push(segmentMatch[2] || '');
+ delete params[key];
+ }
+ });
+ return result.join('');
+ }
-}, ['$rootScope', '$location', '$routeParams']);
+ }];
+}
diff --git a/src/service/routeParams.js b/src/service/routeParams.js
index a9e201a3..df89c739 100644
--- a/src/service/routeParams.js
+++ b/src/service/routeParams.js
@@ -25,6 +25,6 @@
* $routeParams ==> {chapterId:1, sectionId:2, search:'moby'}
* </pre>
*/
-angularService('$routeParams', function() {
- return {};
-});
+function $RouteParamsProvider() {
+ this.$get = valueFn({});
+}
diff --git a/src/service/scope.js b/src/service/scope.js
index 94c41041..f78ac448 100644
--- a/src/service/scope.js
+++ b/src/service/scope.js
@@ -24,631 +24,633 @@
* implemented in the same way as watch. Watch requires return of initialization function which
* are expensive to construct.
*/
-
-angularServiceInject('$rootScope', function($injector, $exceptionHandler){
- /**
- * @ngdoc function
- * @name angular.scope
- *
- * @description
- * A root scope can be created by calling {@link angular.scope angular.scope()}. Child scopes
- * are created using the {@link angular.scope.$new $new()} method.
- * (Most scopes are created automatically when compiled HTML template is executed.)
- *
- * Here is a simple scope snippet to show how you can interact with the scope.
- * <pre>
- var scope = angular.scope();
- scope.salutation = 'Hello';
- scope.name = 'World';
-
- expect(scope.greeting).toEqual(undefined);
-
- scope.$watch('name', function() {
- this.greeting = this.salutation + ' ' + this.name + '!';
- }); // initialize the watch
-
- expect(scope.greeting).toEqual(undefined);
- scope.name = 'Misko';
- // still old value, since watches have not been called yet
- expect(scope.greeting).toEqual(undefined);
-
- scope.$digest(); // fire all the watches
- expect(scope.greeting).toEqual('Hello Misko!');
- * </pre>
- *
- * # Inheritance
- * A scope can inherit from a parent scope, as in this example:
- * <pre>
- var parent = angular.scope();
- var child = parent.$new();
-
- parent.salutation = "Hello";
- child.name = "World";
- expect(child.salutation).toEqual('Hello');
-
- child.salutation = "Welcome";
- expect(child.salutation).toEqual('Welcome');
- expect(parent.salutation).toEqual('Hello');
- * </pre>
- *
- * # Dependency Injection
- * See {@link guide/dev_guide.di dependency injection}.
- *
- *
- * @param {Object.<string, function()>=} providers Map of service factory which need to be provided
- * for the current scope. Defaults to {@link angular.service}.
- * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
- * append/override services provided by `providers`. This is handy when unit-testing and having
- * the need to override a default service.
- * @returns {Object} Newly created scope.
- *
- */
- function Scope() {
- this.$id = nextUid();
- this.$$phase = this.$parent = this.$$watchers =
- this.$$nextSibling = this.$$prevSibling =
- this.$$childHead = this.$$childTail = null;
- this.$destructor = noop;
- this['this'] = this.$root = this;
- this.$$asyncQueue = [];
- this.$$listeners = {};
- }
-
- /**
- * @ngdoc property
- * @name angular.scope.$id
- * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
- * debugging.
- */
-
-
- Scope.prototype = {
+function $RootScopeProvider(){
+ this.$get = ['$injector', '$exceptionHandler',
+ function( $injector, $exceptionHandler){
/**
* @ngdoc function
- * @name angular.scope.$new
- * @function
+ * @name angular.scope
*
* @description
- * Creates a new child {@link angular.scope scope}. The new scope can optionally behave as a
- * controller. The parent scope will propagate the {@link angular.scope.$digest $digest()} and
- * {@link angular.scope.$digest $digest()} events. The scope can be removed from the scope
- * hierarchy using {@link angular.scope.$destroy $destroy()}.
- *
- * {@link angular.scope.$destroy $destroy()} must be called on a scope when it is desired for
- * the scope and its child scopes to be permanently detached from the parent and thus stop
- * participating in model change detection and listener notification by invoking.
- *
- * @param {function()=} Class Constructor function which the scope should be applied to the scope.
- * @param {...*} curryArguments Any additional arguments which are curried into the constructor.
- * See {@link guide/dev_guide.di dependency injection}.
- * @returns {Object} The newly created child scope.
+ * A root scope can be created by calling {@link angular.scope angular.scope()}. Child scopes
+ * are created using the {@link angular.scope.$new $new()} method.
+ * (Most scopes are created automatically when compiled HTML template is executed.)
*
- */
- $new: function(Class, curryArguments) {
- var Child = function() {}; // should be anonymous; This is so that when the minifier munges
- // the name it does not become random set of chars. These will then show up as class
- // name in the debugger.
- var child;
- Child.prototype = this;
- child = new Child();
- child['this'] = child;
- child.$$listeners = {};
- child.$parent = this;
- child.$id = nextUid();
- child.$$asyncQueue = [];
- child.$$phase = child.$$watchers =
- child.$$nextSibling = child.$$childHead = child.$$childTail = null;
- child.$$prevSibling = this.$$childTail;
- if (this.$$childHead) {
- this.$$childTail.$$nextSibling = child;
- this.$$childTail = child;
- } else {
- this.$$childHead = this.$$childTail = child;
- }
- // short circuit if we have no class
- if (Class) {
- // can't use forEach, we need speed!
- var ClassPrototype = Class.prototype;
- for(var key in ClassPrototype) {
- child[key] = bind(child, ClassPrototype[key]);
- }
- $injector.invoke(child, Class, curryArguments);
- }
- return child;
- },
+ * Here is a simple scope snippet to show how you can interact with the scope.
+ * <pre>
+ var scope = angular.scope();
+ scope.salutation = 'Hello';
+ scope.name = 'World';
- /**
- * @ngdoc function
- * @name angular.scope.$watch
- * @function
- *
- * @description
- * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
- *
- * - The `watchExpression` is called on every call to {@link angular.scope.$digest $digest()} and
- * should return the value which will be watched. (Since {@link angular.scope.$digest $digest()}
- * reruns when it detects changes the `watchExpression` can execute multiple times per
- * {@link angular.scope.$digest $digest()} and should be idempotent.)
- * - The `listener` is called only when the value from the current `watchExpression` and the
- * previous call to `watchExpression' are not equal. The inequality is determined according to
- * {@link angular.equals} function. To save the value of the object for later comparison
- * {@link angular.copy} function is used. It also means that watching complex options will
- * have adverse memory and performance implications.
- * - The watch `listener` may change the model, which may trigger other `listener`s to fire. This
- * is achieved by rerunning the watchers until no changes are detected. The rerun iteration
- * limit is 100 to prevent infinity loop deadlock.
- *
- *
- * If you want to be notified whenever {@link angular.scope.$digest $digest} is called,
- * you can register an `watchExpression` function with no `listener`. (Since `watchExpression`,
- * can execute multiple times per {@link angular.scope.$digest $digest} cycle when a change is
- * detected, be prepared for multiple calls to your listener.)
- *
- *
- * # Example
- <pre>
- var scope = angular.scope();
- scope.name = 'misko';
- scope.counter = 0;
-
- expect(scope.counter).toEqual(0);
- scope.$watch('name', function(scope, newValue, oldValue) { counter = counter + 1; });
- expect(scope.counter).toEqual(0);
-
- scope.$digest();
- // no variable change
- expect(scope.counter).toEqual(0);
-
- scope.name = 'adam';
- scope.$digest();
- expect(scope.counter).toEqual(1);
- </pre>
+ expect(scope.greeting).toEqual(undefined);
+
+ scope.$watch('name', function() {
+ this.greeting = this.salutation + ' ' + this.name + '!';
+ }); // initialize the watch
+
+ expect(scope.greeting).toEqual(undefined);
+ scope.name = 'Misko';
+ // still old value, since watches have not been called yet
+ expect(scope.greeting).toEqual(undefined);
+
+ scope.$digest(); // fire all the watches
+ expect(scope.greeting).toEqual('Hello Misko!');
+ * </pre>
*
+ * # Inheritance
+ * A scope can inherit from a parent scope, as in this example:
+ * <pre>
+ var parent = angular.scope();
+ var child = parent.$new();
+
+ parent.salutation = "Hello";
+ child.name = "World";
+ expect(child.salutation).toEqual('Hello');
+
+ child.salutation = "Welcome";
+ expect(child.salutation).toEqual('Welcome');
+ expect(parent.salutation).toEqual('Hello');
+ * </pre>
*
+ * # Dependency Injection
+ * See {@link guide/dev_guide.di dependency injection}.
*
- * @param {(function()|string)} watchExpression Expression that is evaluated on each
- * {@link angular.scope.$digest $digest} cycle. A change in the return value triggers a
- * call to the `listener`.
*
- * - `string`: Evaluated as {@link guide/dev_guide.expressions expression}
- * - `function(scope)`: called with current `scope` as a parameter.
- * @param {(function()|string)=} listener Callback called whenever the return value of
- * the `watchExpression` changes.
+ * @param {Object.<string, function()>=} providers Map of service factory which need to be provided
+ * for the current scope. Defaults to {@link angular.service}.
+ * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
+ * append/override services provided by `providers`. This is handy when unit-testing and having
+ * the need to override a default service.
+ * @returns {Object} Newly created scope.
*
- * - `string`: Evaluated as {@link guide/dev_guide.expressions expression}
- * - `function(scope, newValue, oldValue)`: called with current `scope` an previous and
- * current values as parameters.
- * @returns {function()} Returns a deregistration function for this listener.
*/
- $watch: function(watchExp, listener) {
- var scope = this,
- get = compileToFn(watchExp, 'watch'),
- listenFn = compileToFn(listener || noop, 'listener'),
- array = scope.$$watchers,
- watcher = {
- fn: listenFn,
- last: Number.NaN, // NaN !== NaN. We used this to force $watch to fire on first run.
- get: get,
- exp: watchExp
- };
-
- if (!array) {
- array = scope.$$watchers = [];
- }
- // we use unshift since we use a while loop in $digest for speed.
- // the while loop reads in reverse order.
- array.unshift(watcher);
-
- return function() {
- angularArray.remove(array, watcher);
- };
- },
+ function Scope() {
+ this.$id = nextUid();
+ this.$$phase = this.$parent = this.$$watchers =
+ this.$$nextSibling = this.$$prevSibling =
+ this.$$childHead = this.$$childTail = null;
+ this.$destructor = noop;
+ this['this'] = this.$root = this;
+ this.$$asyncQueue = [];
+ this.$$listeners = {};
+ }
/**
- * @ngdoc function
- * @name angular.scope.$digest
- * @function
- *
- * @description
- * Process all of the {@link angular.scope.$watch watchers} of the current scope and its children.
- * Because a {@link angular.scope.$watch watcher}'s listener can change the model, the
- * `$digest()` keeps calling the {@link angular.scope.$watch watchers} until no more listeners are
- * firing. This means that it is possible to get into an infinite loop. This function will throw
- * `'Maximum iteration limit exceeded.'` if the number of iterations exceeds 100.
- *
- * Usually you don't call `$digest()` directly in
- * {@link angular.directive.ng:controller controllers} or in {@link angular.directive directives}.
- * Instead a call to {@link angular.scope.$apply $apply()} (typically from within a
- * {@link angular.directive directive}) will force a `$digest()`.
- *
- * If you want to be notified whenever `$digest()` is called,
- * you can register a `watchExpression` function with {@link angular.scope.$watch $watch()}
- * with no `listener`.
- *
- * You may have a need to call `$digest()` from within unit-tests, to simulate the scope
- * life-cycle.
- *
- * # Example
- <pre>
- var scope = angular.scope();
- scope.name = 'misko';
- scope.counter = 0;
-
- expect(scope.counter).toEqual(0);
- scope.$digest('name', function(scope, newValue, oldValue) { counter = counter + 1; });
- expect(scope.counter).toEqual(0);
-
- scope.$digest();
- // no variable change
- expect(scope.counter).toEqual(0);
-
- scope.name = 'adam';
- scope.$digest();
- expect(scope.counter).toEqual(1);
- </pre>
- *
+ * @ngdoc property
+ * @name angular.scope.$id
+ * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
+ * debugging.
*/
- $digest: function() {
- var watch, value, last,
- watchers,
- asyncQueue,
- length,
- dirty, ttl = 100,
- next, current, target = this,
- watchLog = [];
-
- if (target.$$phase) {
- throw Error(target.$$phase + ' already in progress');
- }
- do {
- dirty = false;
- current = target;
- do {
- current.$$phase = '$digest';
- asyncQueue = current.$$asyncQueue;
- while(asyncQueue.length) {
- try {
- current.$eval(asyncQueue.shift());
- } catch (e) {
- current.$service('$exceptionHandler')(e);
- }
+
+ Scope.prototype = {
+ /**
+ * @ngdoc function
+ * @name angular.scope.$new
+ * @function
+ *
+ * @description
+ * Creates a new child {@link angular.scope scope}. The new scope can optionally behave as a
+ * controller. The parent scope will propagate the {@link angular.scope.$digest $digest()} and
+ * {@link angular.scope.$digest $digest()} events. The scope can be removed from the scope
+ * hierarchy using {@link angular.scope.$destroy $destroy()}.
+ *
+ * {@link angular.scope.$destroy $destroy()} must be called on a scope when it is desired for
+ * the scope and its child scopes to be permanently detached from the parent and thus stop
+ * participating in model change detection and listener notification by invoking.
+ *
+ * @param {function()=} Class Constructor function which the scope should be applied to the scope.
+ * @param {...*} curryArguments Any additional arguments which are curried into the constructor.
+ * See {@link guide/dev_guide.di dependency injection}.
+ * @returns {Object} The newly created child scope.
+ *
+ */
+ $new: function(Class, curryArguments) {
+ var Child = function() {}; // should be anonymous; This is so that when the minifier munges
+ // the name it does not become random set of chars. These will then show up as class
+ // name in the debugger.
+ var child;
+ Child.prototype = this;
+ child = new Child();
+ child['this'] = child;
+ child.$$listeners = {};
+ child.$parent = this;
+ child.$id = nextUid();
+ child.$$asyncQueue = [];
+ child.$$phase = child.$$watchers =
+ child.$$nextSibling = child.$$childHead = child.$$childTail = null;
+ child.$$prevSibling = this.$$childTail;
+ if (this.$$childHead) {
+ this.$$childTail.$$nextSibling = child;
+ this.$$childTail = child;
+ } else {
+ this.$$childHead = this.$$childTail = child;
+ }
+ // short circuit if we have no class
+ if (Class) {
+ // can't use forEach, we need speed!
+ var ClassPrototype = Class.prototype;
+ for(var key in ClassPrototype) {
+ child[key] = bind(child, ClassPrototype[key]);
}
- if ((watchers = current.$$watchers)) {
- // process our watches
- length = watchers.length;
- while (length--) {
+ $injector.invoke(child, Class, curryArguments);
+ }
+ return child;
+ },
+
+ /**
+ * @ngdoc function
+ * @name angular.scope.$watch
+ * @function
+ *
+ * @description
+ * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
+ *
+ * - The `watchExpression` is called on every call to {@link angular.scope.$digest $digest()} and
+ * should return the value which will be watched. (Since {@link angular.scope.$digest $digest()}
+ * reruns when it detects changes the `watchExpression` can execute multiple times per
+ * {@link angular.scope.$digest $digest()} and should be idempotent.)
+ * - The `listener` is called only when the value from the current `watchExpression` and the
+ * previous call to `watchExpression' are not equal. The inequality is determined according to
+ * {@link angular.equals} function. To save the value of the object for later comparison
+ * {@link angular.copy} function is used. It also means that watching complex options will
+ * have adverse memory and performance implications.
+ * - The watch `listener` may change the model, which may trigger other `listener`s to fire. This
+ * is achieved by rerunning the watchers until no changes are detected. The rerun iteration
+ * limit is 100 to prevent infinity loop deadlock.
+ *
+ *
+ * If you want to be notified whenever {@link angular.scope.$digest $digest} is called,
+ * you can register an `watchExpression` function with no `listener`. (Since `watchExpression`,
+ * can execute multiple times per {@link angular.scope.$digest $digest} cycle when a change is
+ * detected, be prepared for multiple calls to your listener.)
+ *
+ *
+ * # Example
+ <pre>
+ var scope = angular.scope();
+ scope.name = 'misko';
+ scope.counter = 0;
+
+ expect(scope.counter).toEqual(0);
+ scope.$watch('name', function(scope, newValue, oldValue) { counter = counter + 1; });
+ expect(scope.counter).toEqual(0);
+
+ scope.$digest();
+ // no variable change
+ expect(scope.counter).toEqual(0);
+
+ scope.name = 'adam';
+ scope.$digest();
+ expect(scope.counter).toEqual(1);
+ </pre>
+ *
+ *
+ *
+ * @param {(function()|string)} watchExpression Expression that is evaluated on each
+ * {@link angular.scope.$digest $digest} cycle. A change in the return value triggers a
+ * call to the `listener`.
+ *
+ * - `string`: Evaluated as {@link guide/dev_guide.expressions expression}
+ * - `function(scope)`: called with current `scope` as a parameter.
+ * @param {(function()|string)=} listener Callback called whenever the return value of
+ * the `watchExpression` changes.
+ *
+ * - `string`: Evaluated as {@link guide/dev_guide.expressions expression}
+ * - `function(scope, newValue, oldValue)`: called with current `scope` an previous and
+ * current values as parameters.
+ * @returns {function()} Returns a deregistration function for this listener.
+ */
+ $watch: function(watchExp, listener) {
+ var scope = this,
+ get = compileToFn(watchExp, 'watch'),
+ listenFn = compileToFn(listener || noop, 'listener'),
+ array = scope.$$watchers,
+ watcher = {
+ fn: listenFn,
+ last: Number.NaN, // NaN !== NaN. We used this to force $watch to fire on first run.
+ get: get,
+ exp: watchExp
+ };
+
+ if (!array) {
+ array = scope.$$watchers = [];
+ }
+ // we use unshift since we use a while loop in $digest for speed.
+ // the while loop reads in reverse order.
+ array.unshift(watcher);
+
+ return function() {
+ angularArray.remove(array, watcher);
+ };
+ },
+
+ /**
+ * @ngdoc function
+ * @name angular.scope.$digest
+ * @function
+ *
+ * @description
+ * Process all of the {@link angular.scope.$watch watchers} of the current scope and its children.
+ * Because a {@link angular.scope.$watch watcher}'s listener can change the model, the
+ * `$digest()` keeps calling the {@link angular.scope.$watch watchers} until no more listeners are
+ * firing. This means that it is possible to get into an infinite loop. This function will throw
+ * `'Maximum iteration limit exceeded.'` if the number of iterations exceeds 100.
+ *
+ * Usually you don't call `$digest()` directly in
+ * {@link angular.directive.ng:controller controllers} or in {@link angular.directive directives}.
+ * Instead a call to {@link angular.scope.$apply $apply()} (typically from within a
+ * {@link angular.directive directive}) will force a `$digest()`.
+ *
+ * If you want to be notified whenever `$digest()` is called,
+ * you can register a `watchExpression` function with {@link angular.scope.$watch $watch()}
+ * with no `listener`.
+ *
+ * You may have a need to call `$digest()` from within unit-tests, to simulate the scope
+ * life-cycle.
+ *
+ * # Example
+ <pre>
+ var scope = angular.scope();
+ scope.name = 'misko';
+ scope.counter = 0;
+
+ expect(scope.counter).toEqual(0);
+ scope.$digest('name', function(scope, newValue, oldValue) { counter = counter + 1; });
+ expect(scope.counter).toEqual(0);
+
+ scope.$digest();
+ // no variable change
+ expect(scope.counter).toEqual(0);
+
+ scope.name = 'adam';
+ scope.$digest();
+ expect(scope.counter).toEqual(1);
+ </pre>
+ *
+ */
+ $digest: function() {
+ var watch, value, last,
+ watchers,
+ asyncQueue,
+ length,
+ dirty, ttl = 100,
+ next, current, target = this,
+ watchLog = [];
+
+ if (target.$$phase) {
+ throw Error(target.$$phase + ' already in progress');
+ }
+ do {
+
+ dirty = false;
+ current = target;
+ do {
+ current.$$phase = '$digest';
+ asyncQueue = current.$$asyncQueue;
+ while(asyncQueue.length) {
try {
- watch = watchers[length];
- // Most common watches are on primitives, in which case we can short
- // circuit it with === operator, only when === fails do we use .equals
- if ((value = watch.get(current)) !== (last = watch.last) && !equals(value, last)) {
- dirty = true;
- watch.last = copy(value);
- watch.fn(current, value, last);
- if (ttl < 5) {
- if (!watchLog[4-ttl]) watchLog[4-ttl] = [];
- if (isFunction(watch.exp)) {
- watchLog[4-ttl].push('fn: ' + (watch.exp.name || watch.exp.toString()));
- } else {
- watchLog[4-ttl].push(watch.exp);
+ current.$eval(asyncQueue.shift());
+ } catch (e) {
+ current.$service('$exceptionHandler')(e);
+ }
+ }
+ if ((watchers = current.$$watchers)) {
+ // process our watches
+ length = watchers.length;
+ while (length--) {
+ try {
+ watch = watchers[length];
+ // Most common watches are on primitives, in which case we can short
+ // circuit it with === operator, only when === fails do we use .equals
+ if ((value = watch.get(current)) !== (last = watch.last) && !equals(value, last)) {
+ dirty = true;
+ watch.last = copy(value);
+ watch.fn(current, value, last);
+ if (ttl < 5) {
+ if (!watchLog[4-ttl]) watchLog[4-ttl] = [];
+ if (isFunction(watch.exp)) {
+ watchLog[4-ttl].push('fn: ' + (watch.exp.name || watch.exp.toString()));
+ } else {
+ watchLog[4-ttl].push(watch.exp);
+ }
}
}
+ } catch (e) {
+ $exceptionHandler(e);
}
- } catch (e) {
- $exceptionHandler(e);
}
}
+
+ current.$$phase = null;
+
+ // Insanity Warning: scope depth-first traversal
+ // yes, this code is a bit crazy, but it works and we have tests to prove it!
+ // this piece should be kept in sync with the traversal in $broadcast
+ if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
+ while(current !== target && !(next = current.$$nextSibling)) {
+ current = current.$parent;
+ }
+ }
+ } while ((current = next));
+
+ if(!(ttl--)) {
+ throw Error('100 $digest() iterations reached. Aborting!\n' +
+ 'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
+ }
+ } while (dirty);
+ },
+
+ /**
+ * @ngdoc function
+ * @name angular.scope.$destroy
+ * @function
+ *
+ * @description
+ * Remove the current scope (and all of its children) from the parent scope. Removal implies
+ * that calls to {@link angular.scope.$digest $digest()} will no longer propagate to the current
+ * scope and its children. Removal also implies that the current scope is eligible for garbage
+ * collection.
+ *
+ * The destructing scope emits an `$destroy` {@link angular.scope.$emit event}.
+ *
+ * The `$destroy()` is usually used by directives such as
+ * {@link angular.widget.@ng:repeat ng:repeat} for managing the unrolling of the loop.
+ *
+ */
+ $destroy: function() {
+ if (this.$root == this) return; // we can't remove the root node;
+ this.$emit('$destroy');
+ var parent = this.$parent;
+
+ if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
+ if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
+ if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
+ if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
+ },
+
+ /**
+ * @ngdoc function
+ * @name angular.scope.$eval
+ * @function
+ *
+ * @description
+ * Executes the `expression` on the current scope returning the result. Any exceptions in the
+ * expression are propagated (uncaught). This is useful when evaluating engular expressions.
+ *
+ * # Example
+ <pre>
+ var scope = angular.scope();
+ scope.a = 1;
+ scope.b = 2;
+
+ expect(scope.$eval('a+b')).toEqual(3);
+ expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
+ </pre>
+ *
+ * @param {(string|function())=} expression An angular expression to be executed.
+ *
+ * - `string`: execute using the rules as defined in {@link guide/dev_guide.expressions expression}.
+ * - `function(scope)`: execute the function with the current `scope` parameter.
+ *
+ * @returns {*} The result of evaluating the expression.
+ */
+ $eval: function(expr) {
+ var fn = isString(expr)
+ ? expressionCompile(expr)
+ : expr || noop;
+ return fn(this);
+ },
+
+ /**
+ * @ngdoc function
+ * @name angular.scope.$evalAsync
+ * @function
+ *
+ * @description
+ * Executes the expression on the current scope at a later point in time.
+ *
+ * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only that:
+ *
+ * - it will execute in the current script execution context (before any DOM rendering).
+ * - at least one {@link angular.scope.$digest $digest cycle} will be performed after
+ * `expression` execution.
+ *
+ * Any exceptions from the execution of the expression are forwarded to the
+ * {@link angular.service.$exceptionHandler $exceptionHandler} service.
+ *
+ * @param {(string|function())=} expression An angular expression to be executed.
+ *
+ * - `string`: execute using the rules as defined in {@link guide/dev_guide.expressions expression}.
+ * - `function(scope)`: execute the function with the current `scope` parameter.
+ *
+ */
+ $evalAsync: function(expr) {
+ this.$$asyncQueue.push(expr);
+ },
+
+ /**
+ * @ngdoc function
+ * @name angular.scope.$apply
+ * @function
+ *
+ * @description
+ * `$apply()` is used to execute an expression in angular from outside of the angular framework.
+ * (For example from browser DOM events, setTimeout, XHR or third party libraries).
+ * Because we are calling into the angular framework we need to perform proper scope life-cycle
+ * of {@link angular.service.$exceptionHandler exception handling},
+ * {@link angular.scope.$digest executing watches}.
+ *
+ * ## Life cycle
+ *
+ * # Pseudo-Code of `$apply()`
+ function $apply(expr) {
+ try {
+ return $eval(expr);
+ } catch (e) {
+ $exceptionHandler(e);
+ } finally {
+ $root.$digest();
+ }
}
+ *
+ *
+ * Scope's `$apply()` method transitions through the following stages:
+ *
+ * 1. The {@link guide/dev_guide.expressions expression} is executed using the
+ * {@link angular.scope.$eval $eval()} method.
+ * 2. Any exceptions from the execution of the expression are forwarded to the
+ * {@link angular.service.$exceptionHandler $exceptionHandler} service.
+ * 3. The {@link angular.scope.$watch watch} listeners are fired immediately after the expression
+ * was executed using the {@link angular.scope.$digest $digest()} method.
+ *
+ *
+ * @param {(string|function())=} exp An angular expression to be executed.
+ *
+ * - `string`: execute using the rules as defined in {@link guide/dev_guide.expressions expression}.
+ * - `function(scope)`: execute the function with current `scope` parameter.
+ *
+ * @returns {*} The result of evaluating the expression.
+ */
+ $apply: function(expr) {
+ try {
+ return this.$eval(expr);
+ } catch (e) {
+ $exceptionHandler(e);
+ } finally {
+ this.$root.$digest();
+ }
+ },
+
+ /**
+ * @ngdoc function
+ * @name angular.scope.$on
+ * @function
+ *
+ * @description
+ * Listen on events of a given type. See {@link angular.scope.$emit $emit} for discussion of
+ * event life cycle.
+ *
+ * @param {string} name Event name to listen on.
+ * @param {function(event)} listener Function to call when the event is emitted.
+ * @returns {function()} Returns a deregistration function for this listener.
+ *
+ * The event listener function format is: `function(event)`. The `event` object passed into the
+ * listener has the following attributes
+ * - `targetScope` - {Scope}: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
+ * - `currentScope` - {Scope}: the current scope which is handling the event.
+ * - `name` - {string}: Name of the event.
+ * - `cancel` - {function=}: calling `cancel` function will cancel further event propagation
+ * (available only for events that were `$emit`-ed).
+ */
+ $on: function(name, listener) {
+ var namedListeners = this.$$listeners[name];
+ if (!namedListeners) {
+ this.$$listeners[name] = namedListeners = [];
+ }
+ namedListeners.push(listener);
+
+ return function() {
+ angularArray.remove(namedListeners, listener);
+ };
+ },
+
+
+ /**
+ * @ngdoc function
+ * @name angular.scope.$emit
+ * @function
+ *
+ * @description
+ * Dispatches an event `name` upwards through the scope hierarchy notifying the
+ * registered {@link angular.scope.$on} listeners.
+ *
+ * The event life cycle starts at the scope on which `$emit` was called. All
+ * {@link angular.scope.$on listeners} listening for `name` event on this scope get notified.
+ * Afterwards, the event traverses upwards toward the root scope and calls all registered
+ * listeners along the way. The event will stop propagating if one of the listeners cancels it.
+ *
+ * Any exception emmited from the {@link angular.scope.$on listeners} will be passed
+ * onto the {@link angular.service.$exceptionHandler $exceptionHandler} service.
+ *
+ * @param {string} name Event name to emit.
+ * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
+ */
+ $emit: function(name, args) {
+ var empty = [],
+ namedListeners,
+ canceled = false,
+ scope = this,
+ event = {
+ name: name,
+ targetScope: scope,
+ cancel: function() {canceled = true;}
+ },
+ listenerArgs = concat([event], arguments, 1),
+ i, length;
- current.$$phase = null;
+ do {
+ namedListeners = scope.$$listeners[name] || empty;
+ event.currentScope = scope;
+ for (i=0, length=namedListeners.length; i<length; i++) {
+ try {
+ namedListeners[i].apply(null, listenerArgs);
+ if (canceled) return;
+ } catch (e) {
+ $exceptionHandler(e);
+ }
+ }
+ //traverse upwards
+ scope = scope.$parent;
+ } while (scope);
+ },
+
+
+ /**
+ * @ngdoc function
+ * @name angular.scope.$broadcast
+ * @function
+ *
+ * @description
+ * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
+ * registered {@link angular.scope.$on} listeners.
+ *
+ * The event life cycle starts at the scope on which `$broadcast` was called. All
+ * {@link angular.scope.$on listeners} listening for `name` event on this scope get notified.
+ * Afterwards, the event propagates to all direct and indirect scopes of the current scope and
+ * calls all registered listeners along the way. The event cannot be canceled.
+ *
+ * Any exception emmited from the {@link angular.scope.$on listeners} will be passed
+ * onto the {@link angular.service.$exceptionHandler $exceptionHandler} service.
+ *
+ * @param {string} name Event name to emit.
+ * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
+ */
+ $broadcast: function(name, args) {
+ var target = this,
+ current = target,
+ next = target,
+ event = { name: name,
+ targetScope: target },
+ listenerArgs = concat([event], arguments, 1);
+
+ //down while you can, then up and next sibling or up and next sibling until back at root
+ do {
+ current = next;
+ event.currentScope = current;
+ forEach(current.$$listeners[name], function(listener) {
+ try {
+ listener.apply(null, listenerArgs);
+ } catch(e) {
+ $exceptionHandler(e);
+ }
+ });
// Insanity Warning: scope depth-first traversal
// yes, this code is a bit crazy, but it works and we have tests to prove it!
- // this piece should be kept in sync with the traversal in $broadcast
+ // this piece should be kept in sync with the traversal in $digest
if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
while(current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
} while ((current = next));
-
- if(!(ttl--)) {
- throw Error('100 $digest() iterations reached. Aborting!\n' +
- 'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
- }
- } while (dirty);
- },
-
- /**
- * @ngdoc function
- * @name angular.scope.$destroy
- * @function
- *
- * @description
- * Remove the current scope (and all of its children) from the parent scope. Removal implies
- * that calls to {@link angular.scope.$digest $digest()} will no longer propagate to the current
- * scope and its children. Removal also implies that the current scope is eligible for garbage
- * collection.
- *
- * The destructing scope emits an `$destroy` {@link angular.scope.$emit event}.
- *
- * The `$destroy()` is usually used by directives such as
- * {@link angular.widget.@ng:repeat ng:repeat} for managing the unrolling of the loop.
- *
- */
- $destroy: function() {
- if (this.$root == this) return; // we can't remove the root node;
- this.$emit('$destroy');
- var parent = this.$parent;
-
- if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
- if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
- if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
- if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
- },
-
- /**
- * @ngdoc function
- * @name angular.scope.$eval
- * @function
- *
- * @description
- * Executes the `expression` on the current scope returning the result. Any exceptions in the
- * expression are propagated (uncaught). This is useful when evaluating engular expressions.
- *
- * # Example
- <pre>
- var scope = angular.scope();
- scope.a = 1;
- scope.b = 2;
-
- expect(scope.$eval('a+b')).toEqual(3);
- expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
- </pre>
- *
- * @param {(string|function())=} expression An angular expression to be executed.
- *
- * - `string`: execute using the rules as defined in {@link guide/dev_guide.expressions expression}.
- * - `function(scope)`: execute the function with the current `scope` parameter.
- *
- * @returns {*} The result of evaluating the expression.
- */
- $eval: function(expr) {
- var fn = isString(expr)
- ? expressionCompile(expr)
- : expr || noop;
- return fn(this);
- },
-
- /**
- * @ngdoc function
- * @name angular.scope.$evalAsync
- * @function
- *
- * @description
- * Executes the expression on the current scope at a later point in time.
- *
- * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only that:
- *
- * - it will execute in the current script execution context (before any DOM rendering).
- * - at least one {@link angular.scope.$digest $digest cycle} will be performed after
- * `expression` execution.
- *
- * Any exceptions from the execution of the expression are forwarded to the
- * {@link angular.service.$exceptionHandler $exceptionHandler} service.
- *
- * @param {(string|function())=} expression An angular expression to be executed.
- *
- * - `string`: execute using the rules as defined in {@link guide/dev_guide.expressions expression}.
- * - `function(scope)`: execute the function with the current `scope` parameter.
- *
- */
- $evalAsync: function(expr) {
- this.$$asyncQueue.push(expr);
- },
-
- /**
- * @ngdoc function
- * @name angular.scope.$apply
- * @function
- *
- * @description
- * `$apply()` is used to execute an expression in angular from outside of the angular framework.
- * (For example from browser DOM events, setTimeout, XHR or third party libraries).
- * Because we are calling into the angular framework we need to perform proper scope life-cycle
- * of {@link angular.service.$exceptionHandler exception handling},
- * {@link angular.scope.$digest executing watches}.
- *
- * ## Life cycle
- *
- * # Pseudo-Code of `$apply()`
- function $apply(expr) {
- try {
- return $eval(expr);
- } catch (e) {
- $exceptionHandler(e);
- } finally {
- $root.$digest();
- }
- }
- *
- *
- * Scope's `$apply()` method transitions through the following stages:
- *
- * 1. The {@link guide/dev_guide.expressions expression} is executed using the
- * {@link angular.scope.$eval $eval()} method.
- * 2. Any exceptions from the execution of the expression are forwarded to the
- * {@link angular.service.$exceptionHandler $exceptionHandler} service.
- * 3. The {@link angular.scope.$watch watch} listeners are fired immediately after the expression
- * was executed using the {@link angular.scope.$digest $digest()} method.
- *
- *
- * @param {(string|function())=} exp An angular expression to be executed.
- *
- * - `string`: execute using the rules as defined in {@link guide/dev_guide.expressions expression}.
- * - `function(scope)`: execute the function with current `scope` parameter.
- *
- * @returns {*} The result of evaluating the expression.
- */
- $apply: function(expr) {
- try {
- return this.$eval(expr);
- } catch (e) {
- $exceptionHandler(e);
- } finally {
- this.$root.$digest();
- }
- },
-
- /**
- * @ngdoc function
- * @name angular.scope.$on
- * @function
- *
- * @description
- * Listen on events of a given type. See {@link angular.scope.$emit $emit} for discussion of
- * event life cycle.
- *
- * @param {string} name Event name to listen on.
- * @param {function(event)} listener Function to call when the event is emitted.
- * @returns {function()} Returns a deregistration function for this listener.
- *
- * The event listener function format is: `function(event)`. The `event` object passed into the
- * listener has the following attributes
- * - `targetScope` - {Scope}: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
- * - `currentScope` - {Scope}: the current scope which is handling the event.
- * - `name` - {string}: Name of the event.
- * - `cancel` - {function=}: calling `cancel` function will cancel further event propagation
- * (available only for events that were `$emit`-ed).
- */
- $on: function(name, listener) {
- var namedListeners = this.$$listeners[name];
- if (!namedListeners) {
- this.$$listeners[name] = namedListeners = [];
}
- namedListeners.push(listener);
-
- return function() {
- angularArray.remove(namedListeners, listener);
- };
- },
-
-
- /**
- * @ngdoc function
- * @name angular.scope.$emit
- * @function
- *
- * @description
- * Dispatches an event `name` upwards through the scope hierarchy notifying the
- * registered {@link angular.scope.$on} listeners.
- *
- * The event life cycle starts at the scope on which `$emit` was called. All
- * {@link angular.scope.$on listeners} listening for `name` event on this scope get notified.
- * Afterwards, the event traverses upwards toward the root scope and calls all registered
- * listeners along the way. The event will stop propagating if one of the listeners cancels it.
- *
- * Any exception emmited from the {@link angular.scope.$on listeners} will be passed
- * onto the {@link angular.service.$exceptionHandler $exceptionHandler} service.
- *
- * @param {string} name Event name to emit.
- * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
- */
- $emit: function(name, args) {
- var empty = [],
- namedListeners,
- canceled = false,
- scope = this,
- event = {
- name: name,
- targetScope: scope,
- cancel: function() {canceled = true;}
- },
- listenerArgs = concat([event], arguments, 1),
- i, length;
-
- do {
- namedListeners = scope.$$listeners[name] || empty;
- event.currentScope = scope;
- for (i=0, length=namedListeners.length; i<length; i++) {
- try {
- namedListeners[i].apply(null, listenerArgs);
- if (canceled) return;
- } catch (e) {
- $exceptionHandler(e);
- }
- }
- //traverse upwards
- scope = scope.$parent;
- } while (scope);
- },
-
-
- /**
- * @ngdoc function
- * @name angular.scope.$broadcast
- * @function
- *
- * @description
- * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
- * registered {@link angular.scope.$on} listeners.
- *
- * The event life cycle starts at the scope on which `$broadcast` was called. All
- * {@link angular.scope.$on listeners} listening for `name` event on this scope get notified.
- * Afterwards, the event propagates to all direct and indirect scopes of the current scope and
- * calls all registered listeners along the way. The event cannot be canceled.
- *
- * Any exception emmited from the {@link angular.scope.$on listeners} will be passed
- * onto the {@link angular.service.$exceptionHandler $exceptionHandler} service.
- *
- * @param {string} name Event name to emit.
- * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
- */
- $broadcast: function(name, args) {
- var target = this,
- current = target,
- next = target,
- event = { name: name,
- targetScope: target },
- listenerArgs = concat([event], arguments, 1);
-
- //down while you can, then up and next sibling or up and next sibling until back at root
- do {
- current = next;
- event.currentScope = current;
- forEach(current.$$listeners[name], function(listener) {
- try {
- listener.apply(null, listenerArgs);
- } catch(e) {
- $exceptionHandler(e);
- }
- });
-
- // Insanity Warning: scope depth-first traversal
- // yes, this code is a bit crazy, but it works and we have tests to prove it!
- // this piece should be kept in sync with the traversal in $digest
- if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
- while(current !== target && !(next = current.$$nextSibling)) {
- current = current.$parent;
- }
- }
- } while ((current = next));
+ };
+
+ // TODO(misko): remove this;
+ var scope = new Scope();
+ scope.$service = $injector;
+ return scope;
+
+ function compileToFn(exp, name) {
+ var fn = isString(exp)
+ ? expressionCompile(exp)
+ : exp;
+ assertArgFn(fn, name);
+ return fn;
}
- };
-
- // TODO(misko): remove this;
- var scope = new Scope();
- scope.$service = $injector;
- return scope;
-
- function compileToFn(exp, name) {
- var fn = isString(exp)
- ? expressionCompile(exp)
- : exp;
- assertArgFn(fn, name);
- return fn;
- }
-}, ['$injector', '$exceptionHandler']);
+ }];
+}
diff --git a/src/service/sniffer.js b/src/service/sniffer.js
index ed6d688d..8f6efeef 100644
--- a/src/service/sniffer.js
+++ b/src/service/sniffer.js
@@ -11,13 +11,15 @@
* @description
* This is very simple implementation of testing browser's features.
*/
-angularServiceInject('$sniffer', function($window) {
- if ($window.Modernizr) return $window.Modernizr;
+function $SnifferProvider(){
+ this.$get = ['$window', function($window){
+ if ($window.Modernizr) return $window.Modernizr;
- return {
- history: !!($window.history && $window.history.pushState),
- hashchange: 'onhashchange' in $window &&
- // IE8 compatible mode lies
- (!$window.document.documentMode || $window.document.documentMode > 7)
- };
-}, ['$window']);
+ return {
+ history: !!($window.history && $window.history.pushState),
+ hashchange: 'onhashchange' in $window &&
+ // IE8 compatible mode lies
+ (!$window.document.documentMode || $window.document.documentMode > 7)
+ };
+ }];
+}
diff --git a/src/service/window.js b/src/service/window.js
index bc264e30..d5c62146 100644
--- a/src/service/window.js
+++ b/src/service/window.js
@@ -23,4 +23,6 @@
</doc:scenario>
</doc:example>
*/
-angularServiceInject("$window", bind(window, identity, window));
+function $WindowProvider(){
+ this.$get = valueFn(window);
+}
diff --git a/src/service/xhr.bulk.js b/src/service/xhr.bulk.js
index bf5a1d95..b75f4046 100644
--- a/src/service/xhr.bulk.js
+++ b/src/service/xhr.bulk.js
@@ -11,76 +11,79 @@
*
* @example
*/
-angularServiceInject('$xhr.bulk', function($rootScope, $xhr, $error, $log){
- var requests = [];
- function bulkXHR(method, url, post, success, error) {
- if (isFunction(post)) {
- error = success;
- success = post;
- post = null;
- }
- var currentQueue;
- forEach(bulkXHR.urls, function(queue){
- if (isFunction(queue.match) ? queue.match(url) : queue.match.exec(url)) {
- currentQueue = queue;
+function $XhrBulkProvider() {
+ this.$get = ['$rootScope', '$xhr', '$xhr.error', '$log',
+ function( $rootScope, $xhr, $error, $log) {
+ var requests = [];
+ function bulkXHR(method, url, post, success, error) {
+ if (isFunction(post)) {
+ error = success;
+ success = post;
+ post = null;
+ }
+ var currentQueue;
+ forEach(bulkXHR.urls, function(queue){
+ if (isFunction(queue.match) ? queue.match(url) : queue.match.exec(url)) {
+ currentQueue = queue;
+ }
+ });
+ if (currentQueue) {
+ if (!currentQueue.requests) currentQueue.requests = [];
+ var request = {
+ method: method,
+ url: url,
+ data: post,
+ success: success};
+ if (error) request.error = error;
+ currentQueue.requests.push(request);
+ } else {
+ $xhr(method, url, post, success, error);
}
- });
- if (currentQueue) {
- if (!currentQueue.requests) currentQueue.requests = [];
- var request = {
- method: method,
- url: url,
- data: post,
- success: success};
- if (error) request.error = error;
- currentQueue.requests.push(request);
- } else {
- $xhr(method, url, post, success, error);
}
- }
- bulkXHR.urls = {};
- bulkXHR.flush = function(success, errorback) {
- assertArgFn(success = success || noop, 0);
- assertArgFn(errorback = errorback || noop, 1);
- forEach(bulkXHR.urls, function(queue, url) {
- var currentRequests = queue.requests;
- if (currentRequests && currentRequests.length) {
- queue.requests = [];
- queue.callbacks = [];
- $xhr('POST', url, {requests: currentRequests},
- function(code, response) {
- forEach(response, function(response, i) {
- try {
- if (response.status == 200) {
- (currentRequests[i].success || noop)(response.status, response.response);
- } else if (isFunction(currentRequests[i].error)) {
- currentRequests[i].error(response.status, response.response);
- } else {
- $error(currentRequests[i], response);
+ bulkXHR.urls = {};
+ bulkXHR.flush = function(success, errorback) {
+ assertArgFn(success = success || noop, 0);
+ assertArgFn(errorback = errorback || noop, 1);
+ forEach(bulkXHR.urls, function(queue, url) {
+ var currentRequests = queue.requests;
+ if (currentRequests && currentRequests.length) {
+ queue.requests = [];
+ queue.callbacks = [];
+ $xhr('POST', url, {requests: currentRequests},
+ function(code, response) {
+ forEach(response, function(response, i) {
+ try {
+ if (response.status == 200) {
+ (currentRequests[i].success || noop)(response.status, response.response);
+ } else if (isFunction(currentRequests[i].error)) {
+ currentRequests[i].error(response.status, response.response);
+ } else {
+ $error(currentRequests[i], response);
+ }
+ } catch(e) {
+ $log.error(e);
}
- } catch(e) {
- $log.error(e);
- }
- });
- success();
- },
- function(code, response) {
- forEach(currentRequests, function(request, i) {
- try {
- if (isFunction(request.error)) {
- request.error(code, response);
- } else {
- $error(request, response);
+ });
+ success();
+ },
+ function(code, response) {
+ forEach(currentRequests, function(request, i) {
+ try {
+ if (isFunction(request.error)) {
+ request.error(code, response);
+ } else {
+ $error(request, response);
+ }
+ } catch(e) {
+ $log.error(e);
}
- } catch(e) {
- $log.error(e);
- }
+ });
+ noop();
});
- noop();
- });
- }
- });
- };
- $rootScope.$watch(function() { bulkXHR.flush(); });
- return bulkXHR;
-}, ['$rootScope', '$xhr', '$xhr.error', '$log']);
+ }
+ });
+ };
+ $rootScope.$watch(function() { bulkXHR.flush(); });
+ return bulkXHR;
+ }];
+}
diff --git a/src/service/xhr.cache.js b/src/service/xhr.cache.js
index 335c481d..a448bfe0 100644
--- a/src/service/xhr.cache.js
+++ b/src/service/xhr.cache.js
@@ -28,87 +28,91 @@
* cached entry. The `success` function will be called when the response is received.
* @param {boolean=} [sync=false] in case of cache hit execute `success` synchronously.
*/
-angularServiceInject('$xhr.cache', function($xhr, $defer, $error, $log) {
- var inflight = {};
- function cache(method, url, post, success, error, verifyCache, sync) {
- if (isFunction(post)) {
- if (!isFunction(success)) {
- verifyCache = success;
- sync = error;
- error = null;
- } else {
+function $XhrCacheProvider() {
+ this.$get = ['$xhr.bulk', '$defer', '$xhr.error', '$log',
+ function($xhr, $defer, $error, $log) {
+ var inflight = {};
+ function cache(method, url, post, success, error, verifyCache, sync) {
+ if (isFunction(post)) {
+ if (!isFunction(success)) {
+ verifyCache = success;
+ sync = error;
+ error = null;
+ } else {
+ sync = verifyCache;
+ verifyCache = error;
+ error = success;
+ }
+ success = post;
+ post = null;
+ } else if (!isFunction(error)) {
sync = verifyCache;
verifyCache = error;
- error = success;
+ error = null;
}
- success = post;
- post = null;
- } else if (!isFunction(error)) {
- sync = verifyCache;
- verifyCache = error;
- error = null;
- }
- if (method == 'GET') {
- var data, dataCached;
- if ((dataCached = cache.data[url])) {
+ if (method == 'GET') {
+ var data, dataCached;
+ if ((dataCached = cache.data[url])) {
- if (sync) {
- success(200, copy(dataCached.value));
- } else {
- $defer(function() { success(200, copy(dataCached.value)); });
- }
+ if (sync) {
+ success(200, copy(dataCached.value));
+ } else {
+ $defer(function() { success(200, copy(dataCached.value)); });
+ }
- if (!verifyCache)
- return;
- }
+ if (!verifyCache)
+ return;
+ }
- if ((data = inflight[url])) {
- data.successes.push(success);
- data.errors.push(error);
- } else {
- inflight[url] = {successes: [success], errors: [error]};
- cache.delegate(method, url, post,
- function(status, response) {
- if (status == 200)
- cache.data[url] = {value: response};
- var successes = inflight[url].successes;
- delete inflight[url];
- forEach(successes, function(success) {
- try {
- (success||noop)(status, copy(response));
- } catch(e) {
- $log.error(e);
- }
- });
- },
- function(status, response) {
- var errors = inflight[url].errors,
- successes = inflight[url].successes;
- delete inflight[url];
+ if ((data = inflight[url])) {
+ data.successes.push(success);
+ data.errors.push(error);
+ } else {
+ inflight[url] = {successes: [success], errors: [error]};
+ cache.delegate(method, url, post,
+ function(status, response) {
+ if (status == 200)
+ cache.data[url] = {value: response};
+ var successes = inflight[url].successes;
+ delete inflight[url];
+ forEach(successes, function(success) {
+ try {
+ (success||noop)(status, copy(response));
+ } catch(e) {
+ $log.error(e);
+ }
+ });
+ },
+ function(status, response) {
+ var errors = inflight[url].errors,
+ successes = inflight[url].successes;
+ delete inflight[url];
- forEach(errors, function(error, i) {
- try {
- if (isFunction(error)) {
- error(status, copy(response));
- } else {
- $error(
- {method: method, url: url, data: post, success: successes[i]},
- {status: status, body: response});
+ forEach(errors, function(error, i) {
+ try {
+ if (isFunction(error)) {
+ error(status, copy(response));
+ } else {
+ $error(
+ {method: method, url: url, data: post, success: successes[i]},
+ {status: status, body: response});
+ }
+ } catch(e) {
+ $log.error(e);
}
- } catch(e) {
- $log.error(e);
- }
+ });
});
- });
- }
+ }
- } else {
- cache.data = {};
- cache.delegate(method, url, post, success, error);
+ } else {
+ cache.data = {};
+ cache.delegate(method, url, post, success, error);
+ }
}
- }
- cache.data = {};
- cache.delegate = $xhr;
- return cache;
-}, ['$xhr.bulk', '$defer', '$xhr.error', '$log']);
+ cache.data = {};
+ cache.delegate = $xhr;
+ return cache;
+ }];
+
+}
diff --git a/src/service/xhr.error.js b/src/service/xhr.error.js
index 01fb8fff..6bd2ac78 100644
--- a/src/service/xhr.error.js
+++ b/src/service/xhr.error.js
@@ -35,8 +35,10 @@
</doc:source>
</doc:example>
*/
-angularServiceInject('$xhr.error', function($log){
- return function(request, response){
- $log.error('ERROR: XHR: ' + request.url, request, response);
- };
-}, ['$log']);
+function $XhrErrorProvider() {
+ this.$get = ['$log', function($log) {
+ return function(request, response){
+ $log.error('ERROR: XHR: ' + request.url, request, response);
+ };
+ }];
+}
diff --git a/src/service/xhr.js b/src/service/xhr.js
index b2a5bdf2..bd1217b9 100644
--- a/src/service/xhr.js
+++ b/src/service/xhr.js
@@ -171,58 +171,61 @@
</doc:scenario>
</doc:example>
*/
-angularServiceInject('$xhr', function($rootScope, $browser, $error, $log){
- var xhrHeaderDefaults = {
- common: {
- "Accept": "application/json, text/plain, */*",
- "X-Requested-With": "XMLHttpRequest"
- },
- post: {'Content-Type': 'application/x-www-form-urlencoded'},
- get: {}, // all these empty properties are needed so that client apps can just do:
- head: {}, // $xhr.defaults.headers.head.foo="bar" without having to create head object
- put: {}, // it also means that if we add a header for these methods in the future, it
- 'delete': {}, // won't be easily silently lost due to an object assignment.
- patch: {}
- };
+function $XhrProvider() {
+ this.$get = ['$rootScope', '$browser', '$xhr.error', '$log',
+ function( $rootScope, $browser, $error, $log){
+ var xhrHeaderDefaults = {
+ common: {
+ "Accept": "application/json, text/plain, */*",
+ "X-Requested-With": "XMLHttpRequest"
+ },
+ post: {'Content-Type': 'application/x-www-form-urlencoded'},
+ get: {}, // all these empty properties are needed so that client apps can just do:
+ head: {}, // $xhr.defaults.headers.head.foo="bar" without having to create head object
+ put: {}, // it also means that if we add a header for these methods in the future, it
+ 'delete': {}, // won't be easily silently lost due to an object assignment.
+ patch: {}
+ };
- function xhr(method, url, post, success, error) {
- if (isFunction(post)) {
- error = success;
- success = post;
- post = null;
- }
- if (post && isObject(post)) {
- post = toJson(post);
- }
+ function xhr(method, url, post, success, error) {
+ if (isFunction(post)) {
+ error = success;
+ success = post;
+ post = null;
+ }
+ if (post && isObject(post)) {
+ post = toJson(post);
+ }
- $browser.xhr(method, url, post, function(code, response){
- try {
- if (isString(response)) {
- if (response.match(/^\)\]\}',\n/)) response=response.substr(6);
- if (/^\s*[\[\{]/.exec(response) && /[\}\]]\s*$/.exec(response)) {
- response = fromJson(response, true);
+ $browser.xhr(method, url, post, function(code, response){
+ try {
+ if (isString(response)) {
+ if (response.match(/^\)\]\}',\n/)) response=response.substr(6);
+ if (/^\s*[\[\{]/.exec(response) && /[\}\]]\s*$/.exec(response)) {
+ response = fromJson(response, true);
+ }
}
+ $rootScope.$apply(function() {
+ if (200 <= code && code < 300) {
+ success(code, response);
+ } else if (isFunction(error)) {
+ error(code, response);
+ } else {
+ $error(
+ {method: method, url: url, data: post, success: success},
+ {status: code, body: response});
+ }
+ });
+ } catch (e) {
+ $log.error(e);
}
- $rootScope.$apply(function() {
- if (200 <= code && code < 300) {
- success(code, response);
- } else if (isFunction(error)) {
- error(code, response);
- } else {
- $error(
- {method: method, url: url, data: post, success: success},
- {status: code, body: response});
- }
- });
- } catch (e) {
- $log.error(e);
- }
- }, extend({'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
- xhrHeaderDefaults.common,
- xhrHeaderDefaults[lowercase(method)]));
- }
+ }, extend({'X-XSRF-TOKEN': $browser.cookies()['XSRF-TOKEN']},
+ xhrHeaderDefaults.common,
+ xhrHeaderDefaults[lowercase(method)]));
+ }
- xhr.defaults = {headers: xhrHeaderDefaults};
+ xhr.defaults = {headers: xhrHeaderDefaults};
- return xhr;
-}, ['$rootScope', '$browser', '$xhr.error', '$log']);
+ return xhr;
+ }];
+}
diff --git a/test/AngularSpec.js b/test/AngularSpec.js
index 8902c2a9..6229120d 100644
--- a/test/AngularSpec.js
+++ b/test/AngularSpec.js
@@ -382,25 +382,6 @@ describe('angular', function() {
expect(fake).toEqual('new');
}));
- it('should not preserve properties on override', function() {
- angular.service('fake', {$one: true}, {$two: true}, {three: true});
- var result = angular.service('fake', {$four: true});
-
- expect(result.$one).toBeUndefined();
- expect(result.$two).toBeUndefined();
- expect(result.three).toBeUndefined();
- expect(result.$four).toBe(true);
- });
-
- it('should not preserve non-angular properties on override', function() {
- angular.service('fake', {one: true}, {two: true});
- var result = angular.service('fake', {third: true});
-
- expect(result.one).not.toBeDefined();
- expect(result.two).not.toBeDefined();
- expect(result.third).toBeTruthy();
- });
-
it('should inject dependencies specified by $inject and ignore function argument name', function() {
expect(angular.injector(function($provide){
$provide.factory('svc1', function() { return 'svc1'; });
diff --git a/test/BinderSpec.js b/test/BinderSpec.js
index 495d98a8..6ab94401 100644
--- a/test/BinderSpec.js
+++ b/test/BinderSpec.js
@@ -222,8 +222,8 @@ describe('Binder', function() {
}));
it('IfTextBindingThrowsErrorDecorateTheSpan', inject(
- function($provide){
- $provide.factory('$exceptionHandler', $exceptionHandlerMockFactory);
+ function($exceptionHandlerProvider){
+ $exceptionHandlerProvider.mode('log');
},
function($rootScope, $exceptionHandler, $compile) {
$compile('<div>{{error.throw()}}</div>', null, true)($rootScope);
@@ -245,8 +245,8 @@ describe('Binder', function() {
})
);
- it('IfAttrBindingThrowsErrorDecorateTheAttribute', inject(function($provide){
- $provide.factory('$exceptionHandler', $exceptionHandlerMockFactory);
+ it('IfAttrBindingThrowsErrorDecorateTheAttribute', inject(function($exceptionHandlerProvider){
+ $exceptionHandlerProvider.mode('log');
}, function($rootScope, $exceptionHandler, $compile) {
$compile('<div attr="before {{error.throw()}} after"></div>', null, true)($rootScope);
var errorLogs = $exceptionHandler.errors;
@@ -387,8 +387,8 @@ describe('Binder', function() {
}));
it('ActionOnAHrefThrowsError', inject(
- function($provide){
- $provide.factory('$exceptionHandler', $exceptionHandlerMockFactory);
+ function($exceptionHandlerProvider){
+ $exceptionHandlerProvider.mode('log');
},
function($rootScope, $exceptionHandler, $compile) {
var input = $compile('<a ng:click="action()">Add Phone</a>')($rootScope);
@@ -471,8 +471,8 @@ describe('Binder', function() {
}));
it('ItShouldDisplayErrorWhenActionIsSyntacticlyIncorrect', inject(
- function($provide){
- $provide.factory('$exceptionHandler', $exceptionHandlerMockFactory);
+ function($exceptionHandlerProvider){
+ $exceptionHandlerProvider.mode('log');
},
function($rootScope, $exceptionHandler, $log, $compile) {
var element = $compile(
diff --git a/test/FiltersSpec.js b/test/FiltersSpec.js
index 4b69bf03..8c567441 100644
--- a/test/FiltersSpec.js
+++ b/test/FiltersSpec.js
@@ -200,10 +200,10 @@ describe('filter', function() {
describe('date', function() {
- var morning = new TzDate(+5, '2010-09-03T12:05:08.000Z'); //7am
- var noon = new TzDate(+5, '2010-09-03T17:05:08.000Z'); //12pm
- var midnight = new TzDate(+5, '2010-09-03T05:05:08.000Z'); //12am
- var earlyDate = new TzDate(+5, '0001-09-03T05:05:08.000Z');
+ var morning = new angular.mock.TzDate(+5, '2010-09-03T12:05:08.000Z'); //7am
+ var noon = new angular.mock.TzDate(+5, '2010-09-03T17:05:08.000Z'); //12pm
+ var midnight = new angular.mock.TzDate(+5, '2010-09-03T05:05:08.000Z'); //12am
+ var earlyDate = new angular.mock.TzDate(+5, '0001-09-03T05:05:08.000Z');
var context, date;
diff --git a/test/InjectorSpec.js b/test/InjectorSpec.js
index 3ba819b8..ac412c39 100644
--- a/test/InjectorSpec.js
+++ b/test/InjectorSpec.js
@@ -239,6 +239,12 @@ describe('injector', function() {
expect($injector('a')).toEqual('abc');
});
+ it('should error on invalid madule name', function(){
+ expect(function(){
+ createInjector(['IDontExist'], {});
+ }).toThrow("Module 'IDontExist' is not defined!");
+ });
+
describe('$provide', function() {
describe('value', function(){
diff --git a/test/angular-mocksSpec.js b/test/angular-mocksSpec.js
index 205461af..343be966 100644
--- a/test/angular-mocksSpec.js
+++ b/test/angular-mocksSpec.js
@@ -8,90 +8,90 @@ describe('mocks', function() {
}
it('should take millis as constructor argument', function() {
- expect(new TzDate(0, 0).getTime()).toBe(0);
- expect(new TzDate(0, 1283555108000).getTime()).toBe(1283555108000);
+ expect(new angular.mock.TzDate(0, 0).getTime()).toBe(0);
+ expect(new angular.mock.TzDate(0, 1283555108000).getTime()).toBe(1283555108000);
});
it('should take dateString as constructor argument', function() {
- expect(new TzDate(0, '1970-01-01T00:00:00.000Z').getTime()).toBe(0);
- expect(new TzDate(0, '2010-09-03T23:05:08.023Z').getTime()).toBe(1283555108023);
+ expect(new angular.mock.TzDate(0, '1970-01-01T00:00:00.000Z').getTime()).toBe(0);
+ expect(new angular.mock.TzDate(0, '2010-09-03T23:05:08.023Z').getTime()).toBe(1283555108023);
});
it('should fake getLocalDateString method', function() {
//0 in -3h
- var t0 = new TzDate(-3, 0);
+ var t0 = new angular.mock.TzDate(-3, 0);
expect(t0.toLocaleDateString()).toMatch('1970');
//0 in +0h
- var t1 = new TzDate(0, 0);
+ var t1 = new angular.mock.TzDate(0, 0);
expect(t1.toLocaleDateString()).toMatch('1970');
//0 in +3h
- var t2 = new TzDate(3, 0);
+ var t2 = new angular.mock.TzDate(3, 0);
expect(t2.toLocaleDateString()).toMatch('1969');
});
it('should fake getHours method', function() {
//0 in -3h
- var t0 = new TzDate(-3, 0);
+ var t0 = new angular.mock.TzDate(-3, 0);
expect(t0.getHours()).toBe(3);
//0 in +0h
- var t1 = new TzDate(0, 0);
+ var t1 = new angular.mock.TzDate(0, 0);
expect(t1.getHours()).toBe(0);
//0 in +3h
- var t2 = new TzDate(3, 0);
+ var t2 = new angular.mock.TzDate(3, 0);
expect(t2.getHours()).toMatch(21);
});
it('should fake getMinutes method', function() {
//0:15 in -3h
- var t0 = new TzDate(-3, minutes(15));
+ var t0 = new angular.mock.TzDate(-3, minutes(15));
expect(t0.getMinutes()).toBe(15);
//0:15 in -3.25h
- var t0a = new TzDate(-3.25, minutes(15));
+ var t0a = new angular.mock.TzDate(-3.25, minutes(15));
expect(t0a.getMinutes()).toBe(30);
//0 in +0h
- var t1 = new TzDate(0, minutes(0));
+ var t1 = new angular.mock.TzDate(0, minutes(0));
expect(t1.getMinutes()).toBe(0);
//0:15 in +0h
- var t1a = new TzDate(0, minutes(15));
+ var t1a = new angular.mock.TzDate(0, minutes(15));
expect(t1a.getMinutes()).toBe(15);
//0:15 in +3h
- var t2 = new TzDate(3, minutes(15));
+ var t2 = new angular.mock.TzDate(3, minutes(15));
expect(t2.getMinutes()).toMatch(15);
//0:15 in +3.25h
- var t2a = new TzDate(3.25, minutes(15));
+ var t2a = new angular.mock.TzDate(3.25, minutes(15));
expect(t2a.getMinutes()).toMatch(0);
});
it('should fake getSeconds method', function() {
//0 in -3h
- var t0 = new TzDate(-3, 0);
+ var t0 = new angular.mock.TzDate(-3, 0);
expect(t0.getSeconds()).toBe(0);
//0 in +0h
- var t1 = new TzDate(0, 0);
+ var t1 = new angular.mock.TzDate(0, 0);
expect(t1.getSeconds()).toBe(0);
//0 in +3h
- var t2 = new TzDate(3, 0);
+ var t2 = new angular.mock.TzDate(3, 0);
expect(t2.getSeconds()).toMatch(0);
});
it('should create a date representing new year in Bratislava', function() {
- var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00.000Z');
+ var newYearInBratislava = new angular.mock.TzDate(-1, '2009-12-31T23:00:00.000Z');
expect(newYearInBratislava.getTimezoneOffset()).toBe(-60);
expect(newYearInBratislava.getFullYear()).toBe(2010);
expect(newYearInBratislava.getMonth()).toBe(0);
@@ -103,7 +103,7 @@ describe('mocks', function() {
it('should delegate all the UTC methods to the original UTC Date object', function() {
//from when created from string
- var date1 = new TzDate(-1, '2009-12-31T23:00:00.000Z');
+ var date1 = new angular.mock.TzDate(-1, '2009-12-31T23:00:00.000Z');
expect(date1.getUTCFullYear()).toBe(2009);
expect(date1.getUTCMonth()).toBe(11);
expect(date1.getUTCDate()).toBe(31);
@@ -113,7 +113,7 @@ describe('mocks', function() {
//from when created from millis
- var date2 = new TzDate(-1, angular.String.toDate('2009-12-31T23:00:00.000Z').getTime());
+ var date2 = new angular.mock.TzDate(-1, angular.String.toDate('2009-12-31T23:00:00.000Z').getTime());
expect(date2.getUTCFullYear()).toBe(2009);
expect(date2.getUTCMonth()).toBe(11);
expect(date2.getUTCDate()).toBe(31);
@@ -124,16 +124,20 @@ describe('mocks', function() {
it('should throw error when no third param but toString called', function() {
- expect(function() { new TzDate(0,0).toString(); }).
+ expect(function() { new angular.mock.TzDate(0,0).toString(); }).
toThrow('Method \'toString\' is not implemented in the TzDate mock');
});
});
- describe('$log mock', function() {
+ describe('$log', function() {
var $log;
- beforeEach(function() {
- $log = MockLogFactory();
- });
+ beforeEach(inject(['$log', function(log) {
+ $log = log;
+ }]));
+
+ afterEach(inject(function($log){
+ $log.reset();
+ }));
it('should provide log method', function() {
expect(function() { $log.log(''); }).not.toThrow();
@@ -170,14 +174,48 @@ describe('mocks', function() {
$log.error('fake log');
expect($log.error.logs).toContain(['fake log']);
});
+
+ it('should assertEmpty', function(){
+ try {
+ $log.error(Error('MyError'));
+ $log.warn(Error('MyWarn'));
+ $log.info(Error('MyInfo'));
+ $log.log(Error('MyLog'));
+ $log.assertEmpty();
+ } catch (error) {
+ error = error.message || error;
+ expect(error).toMatch(/Error: MyError/m);
+ expect(error).toMatch(/Error: MyWarn/m);
+ expect(error).toMatch(/Error: MyInfo/m);
+ expect(error).toMatch(/Error: MyLog/m);
+ } finally {
+ $log.reset();
+ }
+ });
+
+ it('should reset state', function(){
+ $log.error(Error('MyError'));
+ $log.warn(Error('MyWarn'));
+ $log.info(Error('MyInfo'));
+ $log.log(Error('MyLog'));
+ $log.reset();
+ var passed = false;
+ try {
+ $log.assertEmpty(); // should not throw error!
+ passed = true;
+ } catch (e) {
+ passed = e;
+ }
+ expect(passed).toBe(true);
+ });
});
describe('defer', function() {
var browser, log;
- beforeEach(function() {
- browser = new MockBrowser();
+ beforeEach(inject(function($browser) {
+ browser = $browser;
log = '';
- });
+ }));
function logFn(text){ return function() {
log += text +';';
@@ -229,5 +267,20 @@ describe('mocks', function() {
it('should rethrow exceptions', inject(function($exceptionHandler) {
expect(function() { $exceptionHandler('myException'); }).toThrow('myException');
}));
+
+
+ it('should log exceptions', inject(function($exceptionHandlerProvider){
+ $exceptionHandlerProvider.mode('log');
+ var $exceptionHandler = $exceptionHandlerProvider.$get();
+ $exceptionHandler('MyError');
+ expect($exceptionHandler.errors).toEqual(['MyError']);
+ }));
+
+
+ it('should thorw on wrong argument', inject(function($exceptionHandlerProvider) {
+ expect(function() {
+ $exceptionHandlerProvider.mode('XXX');
+ }).toThrow("Unknown mode 'XXX', only 'log'/'rethrow' modes are allowed!");
+ }));
});
});
diff --git a/test/mocks.js b/test/mocks.js
deleted file mode 100644
index da0449ac..00000000
--- a/test/mocks.js
+++ /dev/null
@@ -1,69 +0,0 @@
-'use strict';
-
-/**
- * Mock implementation of {@link angular.service.$log} that gathers all logged messages in arrays
- * (one array per logging level). These arrays are exposed as `logs` property of each of the
- * level-specific log function, e.g. for level `error` the array is exposed as
- * `$logMock.error.logs`
- *
- * Please note that this is not a factory function, but rather the actual mock instance. This is
- * important because it allows `beforeEach` and `afterEach` test hooks to clean up or check the
- * state of `logs` arrays in between tests.
- *
- * Exposing the instance in this way makes this mock a singleton, which means that the instance
- * becomes global state for tests. To mitigate the issue, each time the `$log` mock is registered
- * with the injector, a check is performed to ensure that there are no pending logs in `logs`
- * arrays. This means that if a message is logged via $log during a test, the `logs` array must be
- * emptied before the test is finished. `Array#shift` method can be used for this purpose as
- * follows:
- *
- * <pre>
- * it('should do some good', function() {
- * var scope = angular.scope(),
- * $log = scope.$service('$log');
- *
- * //do something that triggers a message to be logged
- * expect($log.error.logs.shift()).toEqual(['message', 'arg1', 'arg2']);
- * });
- * </pre>
- *
- * See {@link angular.mock} for more info on angular mocks.
- */
-var $logMock = {
- log: function() { $logMock.log.logs.push(concat([], arguments, 0)); },
- warn: function() { $logMock.warn.logs.push(concat([], arguments, 0)); },
- info: function() { $logMock.info.logs.push(concat([], arguments, 0)); },
- error: function() { $logMock.error.logs.push(concat([], arguments, 0)); }
-};
-$logMock.log.logs = [];
-$logMock.warn.logs = [];
-$logMock.info.logs = [];
-$logMock.error.logs = [];
-
-angular.service('$log', function() {
- return $logMock;
-});
-
-
-/**
- * Factory that returns mock implementation of {@link angular.service.$exceptionHandler} that
- * gathers all errors in an array. This array is exposed as `errors` property of the mock and can be
- * accessed as `$exceptionHandler.errors`.
- *
- * Note that this factory is not registered with angular's injector by default (as opposed to
- * `$logMock`). It is your responsibility to register this factory when you need it. Typically like
- * this:
- *
- * <pre>
- * var scope = angular.scope(null, {'$exceptionHandler': $exceptionHandlerMockFactory()});
- * </pre>
- *
- */
-function $exceptionHandlerMockFactory() {
- var mockHandler = function(e) {
- mockHandler.errors.push(e);
- };
- mockHandler.errors = [];
-
- return mockHandler;
-}
diff --git a/test/service/cookiesSpec.js b/test/service/cookiesSpec.js
index 66bdc504..d73923a6 100644
--- a/test/service/cookiesSpec.js
+++ b/test/service/cookiesSpec.js
@@ -3,7 +3,7 @@
describe('$cookies', function() {
beforeEach(inject(function($provide) {
$provide.factory('$browser', function(){
- return angular.extend(new MockBrowser(), {cookieHash: {preexisting:'oldCookie'}});
+ return angular.extend(new angular.mock.$Browser(), {cookieHash: {preexisting:'oldCookie'}});
});
}));
diff --git a/test/service/exceptionHandlerSpec.js b/test/service/exceptionHandlerSpec.js
index 821ad7b8..00abff30 100644
--- a/test/service/exceptionHandlerSpec.js
+++ b/test/service/exceptionHandlerSpec.js
@@ -5,11 +5,9 @@ describe('$exceptionHandler', function() {
it('should log errors', inject(
function($provide){
- $provide.factory('$exceptionHandler', $exceptionHandlerFactory);
- $provide.value('$log', $logMock);
+ $provide.service('$exceptionHandler', $ExceptionHandlerProvider);
},
function($log, $exceptionHandler) {
- $log.error.rethrow = false;
$exceptionHandler('myError');
expect($log.error.logs.shift()).toEqual(['myError']);
}
diff --git a/test/service/localeSpec.js b/test/service/localeSpec.js
index 86bc7b0e..83c4ecee 100644
--- a/test/service/localeSpec.js
+++ b/test/service/localeSpec.js
@@ -2,7 +2,7 @@
describe('$locale', function() {
- var $locale = angular.service('$locale')();
+ var $locale = new $LocaleProvider().$get();
it('should have locale id set to en-us', function() {
expect($locale.id).toBe('en-us');
diff --git a/test/service/logSpec.js b/test/service/logSpec.js
index 3b860756..93e705a9 100644
--- a/test/service/logSpec.js
+++ b/test/service/logSpec.js
@@ -12,7 +12,7 @@ describe('$log', function() {
beforeEach(inject(function($provide){
$window = {};
logger = '';
- $provide.factory('$log', $logFactory);
+ $provide.service('$log', $LogProvider);
$provide.value('$exceptionHandler', rethrow);
$provide.value('$window', $window);
}));
@@ -68,7 +68,7 @@ describe('$log', function() {
e.line = undefined;
e.stack = undefined;
- $log = $logFactory({console:{error:function() {
+ $log = new $LogProvider().$get[1]({console:{error:function() {
errorArgs = arguments;
}}});
});
diff --git a/test/service/scopeSpec.js b/test/service/scopeSpec.js
index b7f50edb..88824fcd 100644
--- a/test/service/scopeSpec.js
+++ b/test/service/scopeSpec.js
@@ -2,8 +2,8 @@
describe('Scope', function() {
- beforeEach(inject(function($provide) {
- $provide.factory('$exceptionHandler', $exceptionHandlerMockFactory);
+ beforeEach(inject(function($exceptionHandlerProvider) {
+ $exceptionHandlerProvider.mode('log');
}));
@@ -121,12 +121,12 @@ describe('Scope', function() {
expect(spy).wasCalled();
}));
- it('should delegate exceptions', inject(function($rootScope, $exceptionHandler) {
+ it('should delegate exceptions', inject(function($rootScope, $exceptionHandler, $log) {
$rootScope.$watch('a', function() {throw new Error('abc');});
$rootScope.a = 1;
$rootScope.$digest();
expect($exceptionHandler.errors[0].message).toEqual('abc');
- $logMock.error.logs.length = 0;
+ $log.assertEmpty();
}));
@@ -422,7 +422,7 @@ describe('Scope', function() {
}));
- it('should catch exceptions', inject(function($rootScope, $exceptionHandler) {
+ it('should catch exceptions', inject(function($rootScope, $exceptionHandler, $log) {
var log = '';
var child = $rootScope.$new();
$rootScope.$watch('a', function(scope, a){ log += '1'; });
@@ -430,7 +430,7 @@ describe('Scope', function() {
child.$apply(function() { throw new Error('MyError'); });
expect(log).toEqual('1');
expect($exceptionHandler.errors[0].message).toEqual('MyError');
- $logMock.error.logs.shift();
+ $log.error.logs.shift();
}));
diff --git a/test/service/snifferSpec.js b/test/service/snifferSpec.js
index 72c32046..7ec1dc8d 100644
--- a/test/service/snifferSpec.js
+++ b/test/service/snifferSpec.js
@@ -3,7 +3,7 @@
describe('$sniffer', function() {
function sniffer($window) {
- return angular.service('$sniffer')($window);
+ return new $SnifferProvider().$get[1]($window);
}
describe('history', function() {
diff --git a/test/testabilityPatch.js b/test/testabilityPatch.js
index eb98cb6f..4d576ab9 100644
--- a/test/testabilityPatch.js
+++ b/test/testabilityPatch.js
@@ -77,18 +77,13 @@ beforeEach(function() {
}
});
- $logMock.log.logs = [];
- $logMock.warn.logs = [];
- $logMock.info.logs = [];
- $logMock.error.logs = [];
-
});
function inject(){
var blockFns = sliceArgs(arguments);
return function(){
var spec = this;
- spec.$injector = spec.$injector || angular.injector('NG');
+ spec.$injector = spec.$injector || angular.injector('NG', 'NG_MOCK');
angular.forEach(blockFns, function(fn){
spec.$injector.invoke(spec, fn);
});
@@ -96,30 +91,12 @@ function inject(){
}
-afterEach(inject(function($rootScope) {
+afterEach(inject(function($rootScope, $log) {
// release the injector
dealoc($rootScope);
// check $log mock
- forEach(['error', 'warn', 'info', 'log'], function(logLevel) {
- if ($logMock[logLevel].logs.length) {
- forEach($logMock[logLevel].logs, function(log) {
- forEach(log, function deleteStack(logItem) {
- if (logItem instanceof Error) {
- dump(logItem.stack);
- delete logItem.stack;
- delete logItem.arguments;
- } else {
- dump(logItem);
- }
- });
- });
-
- throw new Error("Exprected $log." + logLevel + ".logs array to be empty. " +
- "Either a message was logged unexpectedly, or an expected log message was not checked " +
- "and removed. Array contents: " + toJson($logMock[logLevel].logs));
- }
- });
+ $log.assertEmpty && $log.assertEmpty();
clearJqCache();
}));
diff --git a/test/widget/inputSpec.js b/test/widget/inputSpec.js
index 8d409b25..cd70cea4 100644
--- a/test/widget/inputSpec.js
+++ b/test/widget/inputSpec.js
@@ -448,12 +448,12 @@ describe('widget: input', function() {
});
- it('should report error on assignment error', function() {
+ it('should report error on assignment error', inject(function($log) {
expect(function() {
compile('<input type="text" ng:model="throw \'\'">');
}).toThrow("Syntax Error: Token '''' is an unexpected token at column 7 of the expression [throw ''] starting at [''].");
- $logMock.error.logs.shift();
- });
+ $log.error.logs.shift();
+ }));
});
diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js
index ef28ea77..fc898f83 100644
--- a/test/widgetsSpec.js
+++ b/test/widgetsSpec.js
@@ -223,12 +223,12 @@ describe("widget", function() {
expect(element.text()).toEqual('name:value;');
}));
- it('should error on wrong parsing of ng:repeat', inject(function($rootScope, $compile) {
+ it('should error on wrong parsing of ng:repeat', inject(function($rootScope, $compile, $log) {
expect(function() {
var element = $compile('<ul><li ng:repeat="i dont parse"></li></ul>')($rootScope);
}).toThrow("Expected ng:repeat in form of '_item_ in _collection_' but got 'i dont parse'.");
- $logMock.error.logs.shift();
+ $log.error.logs.shift();
}));
it('should expose iterator offset as $index when iterating over arrays', inject(function($rootScope, $compile) {
@@ -487,9 +487,9 @@ describe("widget", function() {
}));
it('should be possible to nest ng:view in ng:include', inject(function() {
- var injector = angular.injector('NG');
+ var injector = angular.injector('NG', 'NG_MOCK');
var myApp = injector('$rootScope');
- var $browser = myApp.$service('$browser');
+ var $browser = injector('$browser');
$browser.xhr.expectGET('includePartial.html').respond('view: <ng:view></ng:view>');
injector('$location').path('/foo');