From 2430f52bb97fa9d682e5f028c977c5bf94c5ec38 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 23 Mar 2012 14:03:24 -0700 Subject: chore(module): move files around in preparation for more modules --- src/service/scope.js | 771 --------------------------------------------------- 1 file changed, 771 deletions(-) delete mode 100644 src/service/scope.js (limited to 'src/service/scope.js') diff --git a/src/service/scope.js b/src/service/scope.js deleted file mode 100644 index 4cf6a3e0..00000000 --- a/src/service/scope.js +++ /dev/null @@ -1,771 +0,0 @@ -'use strict'; - -/** - * DESIGN NOTES - * - * The design decisions behind the scope ware heavily favored for speed and memory consumption. - * - * The typical use of scope is to watch the expressions, which most of the time return the same - * value as last time so we optimize the operation. - * - * Closures construction is expensive from speed as well as memory: - * - no closures, instead ups prototypical inheritance for API - * - Internal state needs to be stored on scope directly, which means that private state is - * exposed as $$____ properties - * - * Loop operations are optimized by using while(count--) { ... } - * - this means that in order to keep the same order of execution as addition we have to add - * items to the array at the begging (shift) instead of at the end (push) - * - * Child scopes are created and removed often - * - Using array would be slow since inserts in meddle are expensive so we use linked list - * - * There are few watches then a lot of observers. This is why you don't want the observer to be - * implemented in the same way as watch. Watch requires return of initialization function which - * are expensive to construct. - */ - - -/** - * @ngdoc object - * @name angular.module.ng.$rootScopeProvider - * @description - * - * Provider for the $rootScope service. - */ - -/** - * @ngdoc function - * @name angular.module.ng.$rootScopeProvider#digestTtl - * @methodOf angular.module.ng.$rootScopeProvider - * @description - * - * Sets the number of digest iteration the scope should attempt to execute before giving up and - * assuming that the model is unstable. - * - * The current default is 10 iterations. - * - * @param {number} limit The number of digest iterations. - */ - - -/** - * @ngdoc object - * @name angular.module.ng.$rootScope - * @description - * - * Every application has a single root {@link angular.module.ng.$rootScope.Scope scope}. - * All other scopes are child scopes of the root scope. Scopes provide mechanism for watching the model and provide - * event processing life-cycle. See {@link guide/dev_guide.scopes developer guide on scopes}. - */ -function $RootScopeProvider(){ - var TTL = 10; - - this.digestTtl = function(value) { - if (arguments.length) { - TTL = value; - } - return TTL; - } - - this.$get = ['$injector', '$exceptionHandler', '$parse', - function( $injector, $exceptionHandler, $parse) { - - /** - * @ngdoc function - * @name angular.module.ng.$rootScope.Scope - * - * @description - * A root scope can be retrieved using the {@link angular.module.ng.$rootScope $rootScope} key from the - * {@link angular.module.AUTO.$injector $injector}. Child scopes are created using the - * {@link angular.module.ng.$rootScope.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. - *
- angular.injector(['ng']).invoke(function($rootScope) {
- var scope = $rootScope.$new();
- 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!');
- });
- *
- *
- * # Inheritance
- * A scope can inherit from a parent scope, as in this example:
- *
- var parent = $rootScope;
- 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');
- *
- *
- * # Dependency Injection
- * See {@link guide/dev_guide.di dependency injection}.
- *
- *
- * @param {Object.
- // let's assume that scope was dependency injected as the $rootScope
- var scope = $rootScope;
- scope.name = 'misko';
- scope.counter = 0;
-
- expect(scope.counter).toEqual(0);
- scope.$watch('name', function(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);
-
- *
- *
- *
- * @param {(function()|string)} watchExpression Expression that is evaluated on each
- * {@link angular.module.ng.$rootScope.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(newValue, oldValue, scope)`: called with current and previous values as parameters.
- *
- * @param {boolean=} objectEquality Compare object for equality rather then for refference.
- * @returns {function()} Returns a deregistration function for this listener.
- */
- $watch: function(watchExp, listener, objectEquality) {
- var scope = this,
- get = compileToFn(watchExp, 'watch'),
- array = scope.$$watchers,
- watcher = {
- fn: listener,
- last: initWatchVal,
- get: get,
- exp: watchExp,
- eq: !!objectEquality
- };
-
- // in the case user pass string, we need to compile it, do we really need this ?
- if (!isFunction(listener)) {
- var listenFn = compileToFn(listener || noop, 'listener');
- watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
- }
-
- 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() {
- arrayRemove(array, watcher);
- };
- },
-
- /**
- * @ngdoc function
- * @name angular.module.ng.$rootScope.Scope#$digest
- * @methodOf angular.module.ng.$rootScope.Scope
- * @function
- *
- * @description
- * Process all of the {@link angular.module.ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
- * Because a {@link angular.module.ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the
- * `$digest()` keeps calling the {@link angular.module.ng.$rootScope.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.module.ng.$compileProvider.directive.ng-controller controllers} or in
- * {@link angular.module.ng.$compileProvider.directive directives}.
- * Instead a call to {@link angular.module.ng.$rootScope.Scope#$apply $apply()} (typically from within a
- * {@link angular.module.ng.$compileProvider.directive directives}) will force a `$digest()`.
- *
- * If you want to be notified whenever `$digest()` is called,
- * you can register a `watchExpression` function with {@link angular.module.ng.$rootScope.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
-
- var 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);
-
- *
- */
- $digest: function() {
- var watch, value, last,
- watchers,
- asyncQueue,
- length,
- dirty, ttl = TTL,
- next, current, target = this,
- watchLog = [],
- logIdx, logMsg;
-
- flagPhase(target, '$digest');
-
- do {
- dirty = false;
- current = target;
- do {
- asyncQueue = current.$$asyncQueue;
- while(asyncQueue.length) {
- try {
- current.$eval(asyncQueue.shift());
- } catch (e) {
- $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) &&
- !(watch.eq
- ? equals(value, last)
- : (typeof value == 'number' && typeof last == 'number'
- && isNaN(value) && isNaN(last)))) {
- dirty = true;
- watch.last = watch.eq ? copy(value) : value;
- watch.fn(value, ((last === initWatchVal) ? value : last), current);
- if (ttl < 5) {
- logIdx = 4 - ttl;
- if (!watchLog[logIdx]) watchLog[logIdx] = [];
- logMsg = (isFunction(watch.exp))
- ? 'fn: ' + (watch.exp.name || watch.exp.toString())
- : watch.exp;
- logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
- watchLog[logIdx].push(logMsg);
- }
- }
- } 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
- if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
- while(current !== target && !(next = current.$$nextSibling)) {
- current = current.$parent;
- }
- }
- } while ((current = next));
-
- if(dirty && !(ttl--)) {
- throw Error(TTL + ' $digest() iterations reached. Aborting!\n' +
- 'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
- }
- } while (dirty || asyncQueue.length);
-
- this.$root.$$phase = null;
- },
-
-
- /**
- * @ngdoc event
- * @name angular.module.$rootScope.Scope#$destroy
- * @eventOf angular.module.ng.$rootScope.Scope
- * @eventType broadcast on scope being destroyed
- *
- * @description
- * Broadcasted when a scope and its children are being destroyed.
- */
-
- /**
- * @ngdoc function
- * @name angular.module.ng.$rootScope.Scope#$destroy
- * @methodOf angular.module.ng.$rootScope.Scope
- * @function
- *
- * @description
- * Remove the current scope (and all of its children) from the parent scope. Removal implies
- * that calls to {@link angular.module.ng.$rootScope.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 `$destroy()` is usually used by directives such as
- * {@link angular.module.ng.$compileProvider.directive.ng-repeat ng-repeat} for managing the
- * unrolling of the loop.
- *
- * Just before a scope is destroyed a `$destroy` event is broadcasted on this scope.
- * Application code can register a `$destroy` event handler that will give it chance to
- * perform any necessary cleanup.
- */
- $destroy: function() {
- if (this.$root == this) return; // we can't remove the root node;
- var parent = this.$parent;
-
- this.$broadcast('$destroy');
-
- 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.module.ng.$rootScope.Scope#$eval
- * @methodOf angular.module.ng.$rootScope.Scope
- * @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
-
- var scope = angular.module.ng.$rootScope.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);
-
- *
- * @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, locals)`: execute the function with the current `scope` parameter.
- * @param {Object=} locals Hash object of local variables for the expression.
- *
- * @returns {*} The result of evaluating the expression.
- */
- $eval: function(expr, locals) {
- return $parse(expr)(this, locals);
- },
-
- /**
- * @ngdoc function
- * @name angular.module.ng.$rootScope.Scope#$evalAsync
- * @methodOf angular.module.ng.$rootScope.Scope
- * @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.module.ng.$rootScope.Scope#$digest $digest cycle} will be performed after
- * `expression` execution.
- *
- * Any exceptions from the execution of the expression are forwarded to the
- * {@link angular.module.ng.$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.module.ng.$rootScope.Scope#$apply
- * @methodOf angular.module.ng.$rootScope.Scope
- * @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.module.ng.$exceptionHandler exception handling},
- * {@link angular.module.ng.$rootScope.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.module.ng.$rootScope.Scope#$eval $eval()} method.
- * 2. Any exceptions from the execution of the expression are forwarded to the
- * {@link angular.module.ng.$exceptionHandler $exceptionHandler} service.
- * 3. The {@link angular.module.ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the expression
- * was executed using the {@link angular.module.ng.$rootScope.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 {
- flagPhase(this, '$apply');
- return this.$eval(expr);
- } catch (e) {
- $exceptionHandler(e);
- } finally {
- this.$root.$$phase = null;
- this.$root.$digest();
- }
- },
-
- /**
- * @ngdoc function
- * @name angular.module.ng.$rootScope.Scope#$on
- * @methodOf angular.module.ng.$rootScope.Scope
- * @function
- *
- * @description
- * Listen on events of a given type. See {@link angular.module.ng.$rootScope.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).
- * - `cancelled` - {boolean}: Whether the event was cancelled.
- */
- $on: function(name, listener) {
- var namedListeners = this.$$listeners[name];
- if (!namedListeners) {
- this.$$listeners[name] = namedListeners = [];
- }
- namedListeners.push(listener);
-
- return function() {
- arrayRemove(namedListeners, listener);
- };
- },
-
-
- /**
- * @ngdoc function
- * @name angular.module.ng.$rootScope.Scope#$emit
- * @methodOf angular.module.ng.$rootScope.Scope
- * @function
- *
- * @description
- * Dispatches an event `name` upwards through the scope hierarchy notifying the
- * registered {@link angular.module.ng.$rootScope.Scope#$on} listeners.
- *
- * The event life cycle starts at the scope on which `$emit` was called. All
- * {@link angular.module.ng.$rootScope.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.module.ng.$rootScope.Scope#$on listeners} will be passed
- * onto the {@link angular.module.ng.$exceptionHandler $exceptionHandler} service.
- *
- * @param {string} name Event name to emit.
- * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
- * @return {Object} Event object, see {@link angular.module.ng.$rootScope.Scope#$on}
- */
- $emit: function(name, args) {
- var empty = [],
- namedListeners,
- scope = this,
- event = {
- name: name,
- targetScope: scope,
- cancel: function() {event.cancelled = true;},
- cancelled: false
- },
- listenerArgs = concat([event], arguments, 1),
- i, length;
-
- do {
- namedListeners = scope.$$listeners[name] || empty;
- event.currentScope = scope;
- for (i=0, length=namedListeners.length; i