From c9c176a53b1632ca2b1c6ed27382ab72ac21d45d Mon Sep 17 00:00:00 2001 From: Adam Abrons Date: Tue, 5 Jan 2010 16:36:58 -0800 Subject: angular.js --- src/Scope.js | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 src/Scope.js (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js new file mode 100644 index 00000000..45dd15a4 --- /dev/null +++ b/src/Scope.js @@ -0,0 +1,198 @@ +// Copyright (C) 2009 BRAT Tech LLC + +nglr.Scope = function(initialState, name) { + this.widgets = []; + this.watchListeners = {}; + this.name = name; + initialState = initialState || {}; + var State = function(){}; + State.prototype = initialState; + this.state = new State(); + this.state.$parent = initialState; + if (name == "ROOT") { + this.state.$root = this.state; + } +}; + +nglr.Scope.expressionCache = {}; + +nglr.Scope.prototype.updateView = function() { + var self = this; + this.fireWatchers(); + _.each(this.widgets, function(widget){ + self.evalWidget(widget, "", {}, function(){ + this.updateView(self); + }); + }); +}; + +nglr.Scope.prototype.addWidget = function(controller) { + if (controller) this.widgets.push(controller); +}; + +nglr.Scope.prototype.isProperty = function(exp) { + for ( var i = 0; i < exp.length; i++) { + var ch = exp.charAt(i); + if (ch!='.' && !nglr.Lexer.prototype.isIdent(ch)) { + return false; + } + } + return true; +}; + +nglr.Scope.getter = function(instance, path) { + if (!path) return instance; + var element = path.split('.'); + var key; + var lastInstance = instance; + var len = element.length; + for ( var i = 0; i < len; i++) { + key = element[i]; + if (!key.match(/^[\$\w][\$\w\d]*$/)) + throw "Expression '" + path + "' is not a valid expression for accesing variables."; + if (instance) { + lastInstance = instance; + instance = instance[key]; + } + if (_.isUndefined(instance) && key.charAt(0) == '$') { + var type = angular.Global.typeOf(lastInstance); + type = angular[type.charAt(0).toUpperCase()+type.substring(1)]; + var fn = type ? type[[key.substring(1)]] : undefined; + if (fn) { + instance = _.bind(fn, lastInstance, lastInstance); + return instance; + } + } + } + if (typeof instance === 'function' && !instance.$$factory) { + return nglr.bind(lastInstance, instance); + } + return instance; +}; + +nglr.Scope.prototype.get = function(path) { + return nglr.Scope.getter(this.state, path); +}; + +nglr.Scope.prototype.set = function(path, value) { + var element = path.split('.'); + var instance = this.state; + for ( var i = 0; element.length > 1; i++) { + var key = element.shift(); + var newInstance = instance[key]; + if (!newInstance) { + newInstance = {}; + instance[key] = newInstance; + } + instance = newInstance; + } + instance[element.shift()] = value; + return value; +}; + +nglr.Scope.prototype.setEval = function(expressionText, value) { + this.eval(expressionText + "=" + nglr.toJson(value)); +}; + +nglr.Scope.prototype.eval = function(expressionText, context) { + var expression = nglr.Scope.expressionCache[expressionText]; + if (!expression) { + var parser = new nglr.Parser(expressionText); + expression = parser.statements(); + parser.assertAllConsumed(); + nglr.Scope.expressionCache[expressionText] = expression; + } + context = context || {}; + context.scope = this; + return expression(context); +}; + +//TODO: Refactor. This function needs to be an execution closure for widgets +// move to widgets +// remove expression, just have inner closure. +nglr.Scope.prototype.evalWidget = function(widget, expression, context, onSuccess, onFailure) { + try { + var value = this.eval(expression, context); + if (widget.hasError) { + widget.hasError = false; + jQuery(widget.view). + removeClass('ng-exception'). + removeAttr('ng-error'); + } + if (onSuccess) { + value = onSuccess.apply(widget, [value]); + } + return true; + } catch (e){ + console.error('Eval Widget Error:', e); + var jsonError = nglr.toJson(e, true); + widget.hasError = true; + jQuery(widget.view). + addClass('ng-exception'). + attr('ng-error', jsonError); + if (onFailure) { + onFailure.apply(widget, [e, jsonError]); + } + return false; + } +}; + +nglr.Scope.prototype.validate = function(expressionText, value) { + var expression = nglr.Scope.expressionCache[expressionText]; + if (!expression) { + expression = new nglr.Parser(expressionText).validator(); + nglr.Scope.expressionCache[expressionText] = expression; + } + var self = {scope:this}; + return expression(self)(self, value); +}; + +nglr.Scope.prototype.entity = function(entityDeclaration) { + var expression = new nglr.Parser(entityDeclaration).entityDeclaration(); + return expression({scope:this}); +}; + +nglr.Scope.prototype.markInvalid = function(widget) { + this.state.$invalidWidgets.push(widget); +}; + +nglr.Scope.prototype.watch = function(declaration) { + var self = this; + new nglr.Parser(declaration).watch()({ + scope:this, + addListener:function(watch, exp){ + self.addWatchListener(watch, function(n,o){ + try { + return exp({scope:self}, n, o); + } catch(e) { + nglr.alert(e); + } + }); + } + }); +}; + +nglr.Scope.prototype.addWatchListener = function(watchExpression, listener) { + var watcher = this.watchListeners[watchExpression]; + if (!watcher) { + watcher = {listeners:[], expression:watchExpression}; + this.watchListeners[watchExpression] = watcher; + } + watcher.listeners.push(listener); +}; + +nglr.Scope.prototype.fireWatchers = function() { + var self = this; + var fired = false; + jQuery.each(this.watchListeners, function(name, watcher) { + var value = self.eval(watcher.expression); + if (value !== watcher.lastValue) { + jQuery.each(watcher.listeners, function(i, listener){ + listener(value, watcher.lastValue); + fired = true; + }); + watcher.lastValue = value; + } + }); + return fired; +}; -- cgit v1.2.3 From 9b9a0dadcce82ae42ac09ad396d647739af20a06 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sat, 9 Jan 2010 15:02:43 -0800 Subject: removed nglr namespace --- src/Scope.js | 62 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 45dd15a4..e3634cee 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -1,6 +1,6 @@ // Copyright (C) 2009 BRAT Tech LLC -nglr.Scope = function(initialState, name) { +Scope = function(initialState, name) { this.widgets = []; this.watchListeners = {}; this.name = name; @@ -14,9 +14,9 @@ nglr.Scope = function(initialState, name) { } }; -nglr.Scope.expressionCache = {}; +Scope.expressionCache = {}; -nglr.Scope.prototype.updateView = function() { +Scope.prototype.updateView = function() { var self = this; this.fireWatchers(); _.each(this.widgets, function(widget){ @@ -26,21 +26,21 @@ nglr.Scope.prototype.updateView = function() { }); }; -nglr.Scope.prototype.addWidget = function(controller) { +Scope.prototype.addWidget = function(controller) { if (controller) this.widgets.push(controller); }; -nglr.Scope.prototype.isProperty = function(exp) { +Scope.prototype.isProperty = function(exp) { for ( var i = 0; i < exp.length; i++) { var ch = exp.charAt(i); - if (ch!='.' && !nglr.Lexer.prototype.isIdent(ch)) { + if (ch!='.' && !Lexer.prototype.isIdent(ch)) { return false; } } return true; }; -nglr.Scope.getter = function(instance, path) { +Scope.getter = function(instance, path) { if (!path) return instance; var element = path.split('.'); var key; @@ -65,16 +65,16 @@ nglr.Scope.getter = function(instance, path) { } } if (typeof instance === 'function' && !instance.$$factory) { - return nglr.bind(lastInstance, instance); + return bind(lastInstance, instance); } return instance; }; -nglr.Scope.prototype.get = function(path) { - return nglr.Scope.getter(this.state, path); +Scope.prototype.get = function(path) { + return Scope.getter(this.state, path); }; -nglr.Scope.prototype.set = function(path, value) { +Scope.prototype.set = function(path, value) { var element = path.split('.'); var instance = this.state; for ( var i = 0; element.length > 1; i++) { @@ -90,17 +90,17 @@ nglr.Scope.prototype.set = function(path, value) { return value; }; -nglr.Scope.prototype.setEval = function(expressionText, value) { - this.eval(expressionText + "=" + nglr.toJson(value)); +Scope.prototype.setEval = function(expressionText, value) { + this.eval(expressionText + "=" + toJson(value)); }; -nglr.Scope.prototype.eval = function(expressionText, context) { - var expression = nglr.Scope.expressionCache[expressionText]; +Scope.prototype.eval = function(expressionText, context) { + var expression = Scope.expressionCache[expressionText]; if (!expression) { - var parser = new nglr.Parser(expressionText); + var parser = new Parser(expressionText); expression = parser.statements(); parser.assertAllConsumed(); - nglr.Scope.expressionCache[expressionText] = expression; + Scope.expressionCache[expressionText] = expression; } context = context || {}; context.scope = this; @@ -110,7 +110,7 @@ nglr.Scope.prototype.eval = function(expressionText, context) { //TODO: Refactor. This function needs to be an execution closure for widgets // move to widgets // remove expression, just have inner closure. -nglr.Scope.prototype.evalWidget = function(widget, expression, context, onSuccess, onFailure) { +Scope.prototype.evalWidget = function(widget, expression, context, onSuccess, onFailure) { try { var value = this.eval(expression, context); if (widget.hasError) { @@ -125,7 +125,7 @@ nglr.Scope.prototype.evalWidget = function(widget, expression, context, onSucces return true; } catch (e){ console.error('Eval Widget Error:', e); - var jsonError = nglr.toJson(e, true); + var jsonError = toJson(e, true); widget.hasError = true; jQuery(widget.view). addClass('ng-exception'). @@ -137,42 +137,42 @@ nglr.Scope.prototype.evalWidget = function(widget, expression, context, onSucces } }; -nglr.Scope.prototype.validate = function(expressionText, value) { - var expression = nglr.Scope.expressionCache[expressionText]; +Scope.prototype.validate = function(expressionText, value) { + var expression = Scope.expressionCache[expressionText]; if (!expression) { - expression = new nglr.Parser(expressionText).validator(); - nglr.Scope.expressionCache[expressionText] = expression; + expression = new Parser(expressionText).validator(); + Scope.expressionCache[expressionText] = expression; } var self = {scope:this}; return expression(self)(self, value); }; -nglr.Scope.prototype.entity = function(entityDeclaration) { - var expression = new nglr.Parser(entityDeclaration).entityDeclaration(); +Scope.prototype.entity = function(entityDeclaration) { + var expression = new Parser(entityDeclaration).entityDeclaration(); return expression({scope:this}); }; -nglr.Scope.prototype.markInvalid = function(widget) { +Scope.prototype.markInvalid = function(widget) { this.state.$invalidWidgets.push(widget); }; -nglr.Scope.prototype.watch = function(declaration) { +Scope.prototype.watch = function(declaration) { var self = this; - new nglr.Parser(declaration).watch()({ + new Parser(declaration).watch()({ scope:this, addListener:function(watch, exp){ self.addWatchListener(watch, function(n,o){ try { return exp({scope:self}, n, o); } catch(e) { - nglr.alert(e); + alert(e); } }); } }); }; -nglr.Scope.prototype.addWatchListener = function(watchExpression, listener) { +Scope.prototype.addWatchListener = function(watchExpression, listener) { var watcher = this.watchListeners[watchExpression]; if (!watcher) { watcher = {listeners:[], expression:watchExpression}; @@ -181,7 +181,7 @@ nglr.Scope.prototype.addWatchListener = function(watchExpression, listener) { watcher.listeners.push(listener); }; -nglr.Scope.prototype.fireWatchers = function() { +Scope.prototype.fireWatchers = function() { var self = this; var fired = false; jQuery.each(this.watchListeners, function(name, watcher) { -- cgit v1.2.3 From 1aba6b53b88c70b61a0cc991b1371739305d117b Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sun, 10 Jan 2010 08:58:57 -0800 Subject: basic calculator works with minified.js, lots of references still broken --- src/Scope.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index e3634cee..dff3bfbd 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -55,7 +55,7 @@ Scope.getter = function(instance, path) { instance = instance[key]; } if (_.isUndefined(instance) && key.charAt(0) == '$') { - var type = angular.Global.typeOf(lastInstance); + var type = angular['Global']['typeOf'](lastInstance); type = angular[type.charAt(0).toUpperCase()+type.substring(1)]; var fn = type ? type[[key.substring(1)]] : undefined; if (fn) { -- cgit v1.2.3 From 1a42a3fab99ca02af0476f5a87175c53104aa2e3 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 11 Jan 2010 16:15:12 -0800 Subject: green --- src/Scope.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index dff3bfbd..f4b34c3c 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -124,7 +124,7 @@ Scope.prototype.evalWidget = function(widget, expression, context, onSuccess, on } return true; } catch (e){ - console.error('Eval Widget Error:', e); + error('Eval Widget Error:', e); var jsonError = toJson(e, true); widget.hasError = true; jQuery(widget.view). @@ -184,10 +184,10 @@ Scope.prototype.addWatchListener = function(watchExpression, listener) { Scope.prototype.fireWatchers = function() { var self = this; var fired = false; - jQuery.each(this.watchListeners, function(name, watcher) { + foreach(this.watchListeners, function(watcher) { var value = self.eval(watcher.expression); if (value !== watcher.lastValue) { - jQuery.each(watcher.listeners, function(i, listener){ + foreach(watcher.listeners, function(listener){ listener(value, watcher.lastValue); fired = true; }); -- cgit v1.2.3 From 6d5471c9bea9671dec7900a7bc548aea8ddd5a3e Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 11 Jan 2010 17:32:33 -0800 Subject: all files converted to prototype= {} --- src/Scope.js | 295 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 147 insertions(+), 148 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index f4b34c3c..dcc50007 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -1,6 +1,4 @@ -// Copyright (C) 2009 BRAT Tech LLC - -Scope = function(initialState, name) { +function Scope(initialState, name) { this.widgets = []; this.watchListeners = {}; this.name = name; @@ -15,31 +13,6 @@ Scope = function(initialState, name) { }; Scope.expressionCache = {}; - -Scope.prototype.updateView = function() { - var self = this; - this.fireWatchers(); - _.each(this.widgets, function(widget){ - self.evalWidget(widget, "", {}, function(){ - this.updateView(self); - }); - }); -}; - -Scope.prototype.addWidget = function(controller) { - if (controller) this.widgets.push(controller); -}; - -Scope.prototype.isProperty = function(exp) { - for ( var i = 0; i < exp.length; i++) { - var ch = exp.charAt(i); - if (ch!='.' && !Lexer.prototype.isIdent(ch)) { - return false; - } - } - return true; -}; - Scope.getter = function(instance, path) { if (!path) return instance; var element = path.split('.'); @@ -70,129 +43,155 @@ Scope.getter = function(instance, path) { return instance; }; -Scope.prototype.get = function(path) { - return Scope.getter(this.state, path); -}; - -Scope.prototype.set = function(path, value) { - var element = path.split('.'); - var instance = this.state; - for ( var i = 0; element.length > 1; i++) { - var key = element.shift(); - var newInstance = instance[key]; - if (!newInstance) { - newInstance = {}; - instance[key] = newInstance; +Scope.prototype = { + updateView: function() { + var self = this; + this.fireWatchers(); + _.each(this.widgets, function(widget){ + self.evalWidget(widget, "", {}, function(){ + this.updateView(self); + }); + }); + }, + + addWidget: function(controller) { + if (controller) this.widgets.push(controller); + }, + + isProperty: function(exp) { + for ( var i = 0; i < exp.length; i++) { + var ch = exp.charAt(i); + if (ch!='.' && !Lexer.prototype.isIdent(ch)) { + return false; + } } - instance = newInstance; - } - instance[element.shift()] = value; - return value; -}; - -Scope.prototype.setEval = function(expressionText, value) { - this.eval(expressionText + "=" + toJson(value)); -}; - -Scope.prototype.eval = function(expressionText, context) { - var expression = Scope.expressionCache[expressionText]; - if (!expression) { - var parser = new Parser(expressionText); - expression = parser.statements(); - parser.assertAllConsumed(); - Scope.expressionCache[expressionText] = expression; - } - context = context || {}; - context.scope = this; - return expression(context); -}; - -//TODO: Refactor. This function needs to be an execution closure for widgets -// move to widgets -// remove expression, just have inner closure. -Scope.prototype.evalWidget = function(widget, expression, context, onSuccess, onFailure) { - try { - var value = this.eval(expression, context); - if (widget.hasError) { - widget.hasError = false; - jQuery(widget.view). - removeClass('ng-exception'). - removeAttr('ng-error'); + return true; + }, + + get: function(path) { + return Scope.getter(this.state, path); + }, + + set: function(path, value) { + var element = path.split('.'); + var instance = this.state; + for ( var i = 0; element.length > 1; i++) { + var key = element.shift(); + var newInstance = instance[key]; + if (!newInstance) { + newInstance = {}; + instance[key] = newInstance; + } + instance = newInstance; } - if (onSuccess) { - value = onSuccess.apply(widget, [value]); + instance[element.shift()] = value; + return value; + }, + + setEval: function(expressionText, value) { + this.eval(expressionText + "=" + toJson(value)); + }, + + eval: function(expressionText, context) { + var expression = Scope.expressionCache[expressionText]; + if (!expression) { + var parser = new Parser(expressionText); + expression = parser.statements(); + parser.assertAllConsumed(); + Scope.expressionCache[expressionText] = expression; } - return true; - } catch (e){ - error('Eval Widget Error:', e); - var jsonError = toJson(e, true); - widget.hasError = true; - jQuery(widget.view). - addClass('ng-exception'). - attr('ng-error', jsonError); - if (onFailure) { - onFailure.apply(widget, [e, jsonError]); + context = context || {}; + context.scope = this; + return expression(context); + }, + + //TODO: Refactor. This function needs to be an execution closure for widgets + // move to widgets + // remove expression, just have inner closure. + evalWidget: function(widget, expression, context, onSuccess, onFailure) { + try { + var value = this.eval(expression, context); + if (widget.hasError) { + widget.hasError = false; + jQuery(widget.view). + removeClass('ng-exception'). + removeAttr('ng-error'); + } + if (onSuccess) { + value = onSuccess.apply(widget, [value]); + } + return true; + } catch (e){ + error('Eval Widget Error:', e); + var jsonError = toJson(e, true); + widget.hasError = true; + jQuery(widget.view). + addClass('ng-exception'). + attr('ng-error', jsonError); + if (onFailure) { + onFailure.apply(widget, [e, jsonError]); + } + return false; } - return false; - } -}; - -Scope.prototype.validate = function(expressionText, value) { - var expression = Scope.expressionCache[expressionText]; - if (!expression) { - expression = new Parser(expressionText).validator(); - Scope.expressionCache[expressionText] = expression; - } - var self = {scope:this}; - return expression(self)(self, value); -}; - -Scope.prototype.entity = function(entityDeclaration) { - var expression = new Parser(entityDeclaration).entityDeclaration(); - return expression({scope:this}); -}; - -Scope.prototype.markInvalid = function(widget) { - this.state.$invalidWidgets.push(widget); -}; - -Scope.prototype.watch = function(declaration) { - var self = this; - new Parser(declaration).watch()({ - scope:this, - addListener:function(watch, exp){ - self.addWatchListener(watch, function(n,o){ - try { - return exp({scope:self}, n, o); - } catch(e) { - alert(e); - } - }); + }, + + validate: function(expressionText, value) { + var expression = Scope.expressionCache[expressionText]; + if (!expression) { + expression = new Parser(expressionText).validator(); + Scope.expressionCache[expressionText] = expression; } - }); -}; - -Scope.prototype.addWatchListener = function(watchExpression, listener) { - var watcher = this.watchListeners[watchExpression]; - if (!watcher) { - watcher = {listeners:[], expression:watchExpression}; - this.watchListeners[watchExpression] = watcher; - } - watcher.listeners.push(listener); -}; - -Scope.prototype.fireWatchers = function() { - var self = this; - var fired = false; - foreach(this.watchListeners, function(watcher) { - var value = self.eval(watcher.expression); - if (value !== watcher.lastValue) { - foreach(watcher.listeners, function(listener){ - listener(value, watcher.lastValue); - fired = true; - }); - watcher.lastValue = value; + var self = {scope:this}; + return expression(self)(self, value); + }, + + entity: function(entityDeclaration) { + var expression = new Parser(entityDeclaration).entityDeclaration(); + return expression({scope:this}); + }, + + markInvalid: function(widget) { + this.state.$invalidWidgets.push(widget); + }, + + watch: function(declaration) { + var self = this; + new Parser(declaration).watch()({ + scope:this, + addListener:function(watch, exp){ + self.addWatchListener(watch, function(n,o){ + try { + return exp({scope:self}, n, o); + } catch(e) { + alert(e); + } + }); + } + }); + }, + + addWatchListener: function(watchExpression, listener) { + var watcher = this.watchListeners[watchExpression]; + if (!watcher) { + watcher = {listeners:[], expression:watchExpression}; + this.watchListeners[watchExpression] = watcher; } - }); - return fired; -}; + watcher.listeners.push(listener); + }, + + fireWatchers: function() { + var self = this; + var fired = false; + foreach(this.watchListeners, function(watcher) { + var value = self.eval(watcher.expression); + if (value !== watcher.lastValue) { + foreach(watcher.listeners, function(listener){ + listener(value, watcher.lastValue); + fired = true; + }); + watcher.lastValue = value; + } + }); + return fired; + } +}; \ No newline at end of file -- cgit v1.2.3 From efad9ec5be8da442af5fb3dffc08510f7a71e10f Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sun, 24 Jan 2010 17:10:58 -0800 Subject: changes to make it closure compiler compatible --- src/Scope.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index dcc50007..3b1f3930 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -6,9 +6,9 @@ function Scope(initialState, name) { var State = function(){}; State.prototype = initialState; this.state = new State(); - this.state.$parent = initialState; + this.state['$parent'] = initialState; if (name == "ROOT") { - this.state.$root = this.state; + this.state['$root'] = this.state; } }; @@ -37,7 +37,7 @@ Scope.getter = function(instance, path) { } } } - if (typeof instance === 'function' && !instance.$$factory) { + if (typeof instance === 'function' && !instance['$$factory']) { return bind(lastInstance, instance); } return instance; @@ -69,10 +69,12 @@ Scope.prototype = { }, get: function(path) { +// log('SCOPE.get', path, Scope.getter(this.state, path)); return Scope.getter(this.state, path); }, set: function(path, value) { +// log('SCOPE.set', path, value); var element = path.split('.'); var instance = this.state; for ( var i = 0; element.length > 1; i++) { @@ -145,9 +147,9 @@ Scope.prototype = { return expression(self)(self, value); }, - entity: function(entityDeclaration) { + entity: function(entityDeclaration, datastore) { var expression = new Parser(entityDeclaration).entityDeclaration(); - return expression({scope:this}); + return expression({scope:this, datastore:datastore}); }, markInvalid: function(widget) { -- cgit v1.2.3 From 0f42fa2930f5827ac9f1eac2ce09ea3bf9533563 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sun, 24 Jan 2010 19:33:04 -0800 Subject: fix closure compiler issues --- src/Scope.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 3b1f3930..9be6bc3f 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -153,7 +153,7 @@ Scope.prototype = { }, markInvalid: function(widget) { - this.state.$invalidWidgets.push(widget); + this.state['$invalidWidgets'].push(widget); }, watch: function(declaration) { -- cgit v1.2.3 From 473e57e22532f9b85fc9dcc1bcc53e12a10154c2 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sun, 24 Jan 2010 20:44:17 -0800 Subject: bindRootId configuration option --- src/Scope.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 9be6bc3f..7e477ec5 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -95,6 +95,7 @@ Scope.prototype = { }, eval: function(expressionText, context) { + log('Scope.eval', expressionText); var expression = Scope.expressionCache[expressionText]; if (!expression) { var parser = new Parser(expressionText); -- cgit v1.2.3 From f5055c6530ffdb94436b52afe8c52ab6c2f2f14a Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Tue, 26 Jan 2010 15:59:46 -0800 Subject: remove uneeded log --- src/Scope.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 7e477ec5..b8fadfa0 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -95,7 +95,7 @@ Scope.prototype = { }, eval: function(expressionText, context) { - log('Scope.eval', expressionText); +// log('Scope.eval', expressionText); var expression = Scope.expressionCache[expressionText]; if (!expression) { var parser = new Parser(expressionText); -- cgit v1.2.3 From 9f919c42f0885e39870195fab8ce2a22621119b7 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 4 Feb 2010 14:02:20 -0800 Subject: better handling of $invalidWidgets --- src/Scope.js | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index b8fadfa0..cedb0542 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -153,6 +153,11 @@ Scope.prototype = { return expression({scope:this, datastore:datastore}); }, + clearInvalid: function() { + var invalid = this.state['$invalidWidgets']; + while(invalid.length > 0) {invalid.pop();} + }, + markInvalid: function(widget) { this.state['$invalidWidgets'].push(widget); }, -- cgit v1.2.3 From 6cc946413622f1cef97997849e73a06a00f876fd Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 12 Feb 2010 14:16:33 -0800 Subject: Fixed negation grouping bug Make 'this' of validation be scope --- src/Scope.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index cedb0542..c0998168 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -138,13 +138,13 @@ Scope.prototype = { } }, - validate: function(expressionText, value) { + validate: function(expressionText, value, element) { var expression = Scope.expressionCache[expressionText]; if (!expression) { expression = new Parser(expressionText).validator(); Scope.expressionCache[expressionText] = expression; } - var self = {scope:this}; + var self = {scope:this, self:this.state, '$element':element}; return expression(self)(self, value); }, -- cgit v1.2.3 From 7e14dff90516a41ff1903cc44fe3389710f15556 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Wed, 17 Feb 2010 16:05:26 -0800 Subject: fix this on filter to point to scope --- src/Scope.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index c0998168..4de57dd2 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -105,6 +105,7 @@ Scope.prototype = { } context = context || {}; context.scope = this; + context.self = this.state; return expression(context); }, -- cgit v1.2.3 From cc71b745c3c821f5e012a363ae3267252a81fddb Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 15 Mar 2010 14:36:50 -0700 Subject: added resources; removed compiled code --- src/Scope.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 4de57dd2..daf4b36c 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -53,11 +53,11 @@ Scope.prototype = { }); }); }, - + addWidget: function(controller) { if (controller) this.widgets.push(controller); }, - + isProperty: function(exp) { for ( var i = 0; i < exp.length; i++) { var ch = exp.charAt(i); @@ -67,12 +67,12 @@ Scope.prototype = { } return true; }, - + get: function(path) { // log('SCOPE.get', path, Scope.getter(this.state, path)); return Scope.getter(this.state, path); }, - + set: function(path, value) { // log('SCOPE.set', path, value); var element = path.split('.'); @@ -89,11 +89,11 @@ Scope.prototype = { instance[element.shift()] = value; return value; }, - + setEval: function(expressionText, value) { this.eval(expressionText + "=" + toJson(value)); }, - + eval: function(expressionText, context) { // log('Scope.eval', expressionText); var expression = Scope.expressionCache[expressionText]; @@ -108,7 +108,7 @@ Scope.prototype = { context.self = this.state; return expression(context); }, - + //TODO: Refactor. This function needs to be an execution closure for widgets // move to widgets // remove expression, just have inner closure. @@ -126,8 +126,8 @@ Scope.prototype = { } return true; } catch (e){ - error('Eval Widget Error:', e); var jsonError = toJson(e, true); + error('Eval Widget Error:', jsonError); widget.hasError = true; jQuery(widget.view). addClass('ng-exception'). @@ -138,7 +138,7 @@ Scope.prototype = { return false; } }, - + validate: function(expressionText, value, element) { var expression = Scope.expressionCache[expressionText]; if (!expression) { @@ -148,21 +148,21 @@ Scope.prototype = { var self = {scope:this, self:this.state, '$element':element}; return expression(self)(self, value); }, - + entity: function(entityDeclaration, datastore) { var expression = new Parser(entityDeclaration).entityDeclaration(); return expression({scope:this, datastore:datastore}); }, - + clearInvalid: function() { var invalid = this.state['$invalidWidgets']; while(invalid.length > 0) {invalid.pop();} }, - + markInvalid: function(widget) { this.state['$invalidWidgets'].push(widget); }, - + watch: function(declaration) { var self = this; new Parser(declaration).watch()({ @@ -178,7 +178,7 @@ Scope.prototype = { } }); }, - + addWatchListener: function(watchExpression, listener) { var watcher = this.watchListeners[watchExpression]; if (!watcher) { @@ -187,7 +187,7 @@ Scope.prototype = { } watcher.listeners.push(listener); }, - + fireWatchers: function() { var self = this; var fired = false; @@ -203,4 +203,4 @@ Scope.prototype = { }); return fired; } -}; \ No newline at end of file +}; -- cgit v1.2.3 From 7634a3ed5227f8bc2a2ba83752d0e2c78adb6051 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 18 Mar 2010 12:20:06 -0700 Subject: initial revision of new plugable compiler --- src/Scope.js | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index daf4b36c..442477b4 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -10,6 +10,7 @@ function Scope(initialState, name) { if (name == "ROOT") { this.state['$root'] = this.state; } + this.set('$watch', bind(this, this.addWatchListener)); }; Scope.expressionCache = {}; @@ -202,5 +203,9 @@ Scope.prototype = { } }); return fired; + }, + + apply: function(fn) { + fn.apply(this.state, slice(arguments, 0, arguments.length)); } }; -- cgit v1.2.3 From df607da0d1b9726bce6584238fe3ad7e9b65a966 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 18 Mar 2010 14:43:49 -0700 Subject: support for templates --- src/Scope.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 442477b4..3633f960 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -1,5 +1,6 @@ function Scope(initialState, name) { this.widgets = []; + this.evals = []; this.watchListeners = {}; this.name = name; initialState = initialState || {}; @@ -11,6 +12,7 @@ function Scope(initialState, name) { this.state['$root'] = this.state; } this.set('$watch', bind(this, this.addWatchListener)); + this.set('$eval', bind(this, this.addEval)); }; Scope.expressionCache = {}; @@ -48,17 +50,23 @@ Scope.prototype = { updateView: function() { var self = this; this.fireWatchers(); - _.each(this.widgets, function(widget){ + foreach(this.widgets, function(widget){ self.evalWidget(widget, "", {}, function(){ this.updateView(self); }); }); + foreach(this.evals, bind(this, this.apply)); }, addWidget: function(controller) { if (controller) this.widgets.push(controller); }, + addEval: function(fn, listener) { + // todo: this should take a function/string and a listener + this.evals.push(fn); + }, + isProperty: function(exp) { for ( var i = 0; i < exp.length; i++) { var ch = exp.charAt(i); @@ -190,8 +198,7 @@ Scope.prototype = { }, fireWatchers: function() { - var self = this; - var fired = false; + var self = this, fired = false; foreach(this.watchListeners, function(watcher) { var value = self.eval(watcher.expression); if (value !== watcher.lastValue) { @@ -206,6 +213,6 @@ Scope.prototype = { }, apply: function(fn) { - fn.apply(this.state, slice(arguments, 0, arguments.length)); + fn.apply(this.state, slice.call(arguments, 1, arguments.length)); } }; -- cgit v1.2.3 From 84552f7f8ac3f39c4dbd7d946ae2938d63302840 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 22 Mar 2010 13:58:04 -0700 Subject: got few directives working --- src/Scope.js | 52 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 17 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 3633f960..d22604fd 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -1,18 +1,23 @@ function Scope(initialState, name) { - this.widgets = []; - this.evals = []; - this.watchListeners = {}; - this.name = name; + var self = this; + self.widgets = []; + self.evals = []; + self.watchListeners = {}; + self.name = name; initialState = initialState || {}; var State = function(){}; State.prototype = initialState; - this.state = new State(); - this.state['$parent'] = initialState; + self.state = new State(); + extend(self.state, { + '$parent': initialState, + '$watch': bind(self, self.addWatchListener), + '$eval': bind(self, self.eval), + // change name to onEval? + '$addEval': bind(self, self.addEval) + }); if (name == "ROOT") { - this.state['$root'] = this.state; + self.state['$root'] = self.state; } - this.set('$watch', bind(this, this.addWatchListener)); - this.set('$eval', bind(this, this.addEval)); }; Scope.expressionCache = {}; @@ -47,6 +52,7 @@ Scope.getter = function(instance, path) { }; Scope.prototype = { + // TODO: rename to update? or eval? updateView: function() { var self = this; this.fireWatchers(); @@ -64,7 +70,13 @@ Scope.prototype = { addEval: function(fn, listener) { // todo: this should take a function/string and a listener - this.evals.push(fn); + // todo: this is a hack, which will need to be cleaned up. + var self = this, + listenFn = listener || noop, + expr = bind(self, self.compile(fn), {scope: self, self: self.state}); + this.evals.push(function(){ + self.apply(listenFn, expr()); + }); }, isProperty: function(exp) { @@ -103,15 +115,21 @@ Scope.prototype = { this.eval(expressionText + "=" + toJson(value)); }, - eval: function(expressionText, context) { -// log('Scope.eval', expressionText); - var expression = Scope.expressionCache[expressionText]; - if (!expression) { - var parser = new Parser(expressionText); - expression = parser.statements(); + compile: function(exp) { + if (isFunction(exp)) return exp; + var expFn = Scope.expressionCache[exp]; + if (!expFn) { + var parser = new Parser(exp); + expFn = parser.statements(); parser.assertAllConsumed(); - Scope.expressionCache[expressionText] = expression; + Scope.expressionCache[exp] = expFn; } + return expFn; + }, + + eval: function(expressionText, context) { +// log('Scope.eval', expressionText); + var expression = this.compile(expressionText); context = context || {}; context.scope = this; context.self = this.state; -- cgit v1.2.3 From 6f8276a8e3735396999bd158005ca86bb1bb0978 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 22 Mar 2010 16:07:42 -0700 Subject: ng-watch directive --- src/Scope.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index d22604fd..7b1d2673 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -207,6 +207,10 @@ Scope.prototype = { }, addWatchListener: function(watchExpression, listener) { + // TODO: clean me up! + if (!isFunction(listener)) { + listener = bind(this, this.compile(listener), {scope: this, self: this.state}); + } var watcher = this.watchListeners[watchExpression]; if (!watcher) { watcher = {listeners:[], expression:watchExpression}; -- cgit v1.2.3 From a8227086748e37c31c1bb71dec50c96d63c45eef Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 22 Mar 2010 20:20:05 -0700 Subject: rudementary event bind and trigger for jqlite --- src/Scope.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 7b1d2673..a3e128b6 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -73,7 +73,7 @@ Scope.prototype = { // todo: this is a hack, which will need to be cleaned up. var self = this, listenFn = listener || noop, - expr = bind(self, self.compile(fn), {scope: self, self: self.state}); + expr = self.compile(fn); this.evals.push(function(){ self.apply(listenFn, expr()); }); @@ -117,23 +117,24 @@ Scope.prototype = { compile: function(exp) { if (isFunction(exp)) return exp; - var expFn = Scope.expressionCache[exp]; + var expFn = Scope.expressionCache[exp], self = this; if (!expFn) { var parser = new Parser(exp); expFn = parser.statements(); parser.assertAllConsumed(); Scope.expressionCache[exp] = expFn; } - return expFn; + return function(context){ + context = context || {}; + context.self = self.state; + context.scope = self; + return expFn.call(self, context); + }; }, eval: function(expressionText, context) { // log('Scope.eval', expressionText); - var expression = this.compile(expressionText); - context = context || {}; - context.scope = this; - context.self = this.state; - return expression(context); + return this.compile(expressionText)(context); }, //TODO: Refactor. This function needs to be an execution closure for widgets @@ -209,7 +210,7 @@ Scope.prototype = { addWatchListener: function(watchExpression, listener) { // TODO: clean me up! if (!isFunction(listener)) { - listener = bind(this, this.compile(listener), {scope: this, self: this.state}); + listener = this.compile(listener); } var watcher = this.watchListeners[watchExpression]; if (!watcher) { -- cgit v1.2.3 From bb98ae14f2aef74efbd8345e93f62ac67f460f7f Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Tue, 23 Mar 2010 14:57:11 -0700 Subject: markup now wroks, some refactorings --- src/Scope.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index a3e128b6..daafabb0 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -116,7 +116,7 @@ Scope.prototype = { }, compile: function(exp) { - if (isFunction(exp)) return exp; + if (isFunction(exp)) return bind(this.state, exp); var expFn = Scope.expressionCache[exp], self = this; if (!expFn) { var parser = new Parser(exp); -- cgit v1.2.3 From b814c79b58deeeeaa12b03261399ef80c0d6cc9f Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 25 Mar 2010 13:01:08 -0700 Subject: checkbox and radio now working --- src/Scope.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index daafabb0..5f1cfdda 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -12,8 +12,10 @@ function Scope(initialState, name) { '$parent': initialState, '$watch': bind(self, self.addWatchListener), '$eval': bind(self, self.eval), - // change name to onEval? - '$addEval': bind(self, self.addEval) + '$bind': bind(self, bind, self), + // change name to autoEval? + '$addEval': bind(self, self.addEval), + '$updateView': bind(self, self.updateView) }); if (name == "ROOT") { self.state['$root'] = self.state; -- cgit v1.2.3 From d934054cfc22325d817eb0643dc061f9d212804d Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 25 Mar 2010 22:03:11 -0700 Subject: major refactoring of scope --- src/Scope.js | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 178 insertions(+), 14 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 5f1cfdda..ccf55077 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -53,6 +53,21 @@ Scope.getter = function(instance, path) { return instance; }; +Scope.setter = function(instance, path, value){ + var element = path.split('.'); + for ( var i = 0; element.length > 1; i++) { + var key = element.shift(); + var newInstance = instance[key]; + if (!newInstance) { + newInstance = {}; + instance[key] = newInstance; + } + instance = newInstance; + } + instance[element.shift()] = value; + return value; +}; + Scope.prototype = { // TODO: rename to update? or eval? updateView: function() { @@ -98,19 +113,8 @@ Scope.prototype = { set: function(path, value) { // log('SCOPE.set', path, value); - var element = path.split('.'); var instance = this.state; - for ( var i = 0; element.length > 1; i++) { - var key = element.shift(); - var newInstance = instance[key]; - if (!newInstance) { - newInstance = {}; - instance[key] = newInstance; - } - instance = newInstance; - } - instance[element.shift()] = value; - return value; + return Scope.setter(instance, path, value); }, setEval: function(expressionText, value) { @@ -134,9 +138,9 @@ Scope.prototype = { }; }, - eval: function(expressionText, context) { + eval: function(exp, context) { // log('Scope.eval', expressionText); - return this.compile(expressionText)(context); + return this.compile(exp)(context); }, //TODO: Refactor. This function needs to be an execution closure for widgets @@ -241,3 +245,163 @@ Scope.prototype = { fn.apply(this.state, slice.call(arguments, 1, arguments.length)); } }; + +////////////////////////////// + +function getter(instance, path) { + if (!path) return instance; + var element = path.split('.'); + var key; + var lastInstance = instance; + var len = element.length; + for ( var i = 0; i < len; i++) { + key = element[i]; + if (!key.match(/^[\$\w][\$\w\d]*$/)) + throw "Expression '" + path + "' is not a valid expression for accesing variables."; + if (instance) { + lastInstance = instance; + instance = instance[key]; + } + if (_.isUndefined(instance) && key.charAt(0) == '$') { + var type = angular['Global']['typeOf'](lastInstance); + type = angular[type.charAt(0).toUpperCase()+type.substring(1)]; + var fn = type ? type[[key.substring(1)]] : undefined; + if (fn) { + instance = _.bind(fn, lastInstance, lastInstance); + return instance; + } + } + } + if (typeof instance === 'function' && !instance['$$factory']) { + return bind(lastInstance, instance); + } + return instance; +}; + +function setter(instance, path, value){ + var element = path.split('.'); + for ( var i = 0; element.length > 1; i++) { + var key = element.shift(); + var newInstance = instance[key]; + if (!newInstance) { + newInstance = {}; + instance[key] = newInstance; + } + instance = newInstance; + } + instance[element.shift()] = value; + return value; +}; + +var compileCache = {}; +function expressionCompile(exp){ + if (isFunction(exp)) return exp; + var expFn = compileCache[exp]; + if (!expFn) { + var parser = new Parser(exp); + expFn = parser.statements(); + parser.assertAllConsumed(); + compileCache[exp] = expFn; + } + // return expFn + // TODO(remove this hack) + return function(){ + return expFn({ + scope: { + set: this.$set, + get: this.$get + } + }); + }; +}; + +var NON_RENDERABLE_ELEMENTS = { + '#text': 1, '#comment':1, 'TR':1, 'TH':1 +}; + +function isRenderableElement(element){ + return element && element[0] && !NON_RENDERABLE_ELEMENTS[element[0].nodeName]; +} + +function rethrow(e) { throw e; } +function errorHandlerFor(element) { + while (!isRenderableElement(element)) { + element = element.parent() || jqLite(document.body); + } + return function(error) { + element.attr('ng-error', angular.toJson(error)); + element.addClass('ng-exception'); + }; +} + +function scope(parent, Class) { + function Parent(){} + function API(){} + function Behavior(){} + + var instance, behavior, api, watchList = [], evalList = []; + + Class = Class || noop; + parent = Parent.prototype = parent || {}; + api = API.prototype = new Parent(); + behavior = Behavior.prototype = extend(new API(), Class.prototype); + instance = new Behavior(); + + extend(api, { + $parent: parent, + $bind: bind(instance, bind, instance), + $get: bind(instance, getter, instance), + $set: bind(instance, setter, instance), + + $eval: function(exp) { + if (isDefined(exp)) { + return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length)); + } else { + foreach(evalList, function(eval) { + instance.$tryEval(eval.fn, eval.handler); + }); + foreach(watchList, function(watch) { + var value = instance.$tryEval(watch.watch, watch.handler); + if (watch.last !== value) { + instance.$tryEval(watch.listener, watch.handler, value, watch.last); + watch.last = value; + } + }); + } + }, + + $tryEval: function (expression, exceptionHandler) { + try { + return expressionCompile(expression).apply(instance, slice.call(arguments, 2, arguments.length)); + } catch (e) { + error(e); + if (isFunction(exceptionHandler)) { + exceptionHandler(e); + } else if (exceptionHandler) { + errorHandlerFor(exceptionHandler)(e); + } + } + }, + + $watch: function(watchExp, listener, exceptionHandler) { + var watch = expressionCompile(watchExp); + watchList.push({ + watch: watch, + last: watch.call(instance), + handler: exceptionHandler, + listener:expressionCompile(listener) + }); + }, + + $onEval: function(expr, exceptionHandler){ + evalList.push({ + fn: expressionCompile(expr), + handler: exceptionHandler + }); + } + }); + + Class.apply(instance, slice.call(arguments, 2, arguments.length)); + + return instance; +} -- cgit v1.2.3 From 258ca5f16581f0e8befa493644225a02ae2fc002 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 26 Mar 2010 16:27:18 -0700 Subject: moved all uneeded files out, widgets.html works, tests horribly broken --- src/Scope.js | 278 ++++------------------------------------------------------- 1 file changed, 15 insertions(+), 263 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index ccf55077..6ba6aa8e 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -1,253 +1,3 @@ -function Scope(initialState, name) { - var self = this; - self.widgets = []; - self.evals = []; - self.watchListeners = {}; - self.name = name; - initialState = initialState || {}; - var State = function(){}; - State.prototype = initialState; - self.state = new State(); - extend(self.state, { - '$parent': initialState, - '$watch': bind(self, self.addWatchListener), - '$eval': bind(self, self.eval), - '$bind': bind(self, bind, self), - // change name to autoEval? - '$addEval': bind(self, self.addEval), - '$updateView': bind(self, self.updateView) - }); - if (name == "ROOT") { - self.state['$root'] = self.state; - } -}; - -Scope.expressionCache = {}; -Scope.getter = function(instance, path) { - if (!path) return instance; - var element = path.split('.'); - var key; - var lastInstance = instance; - var len = element.length; - for ( var i = 0; i < len; i++) { - key = element[i]; - if (!key.match(/^[\$\w][\$\w\d]*$/)) - throw "Expression '" + path + "' is not a valid expression for accesing variables."; - if (instance) { - lastInstance = instance; - instance = instance[key]; - } - if (_.isUndefined(instance) && key.charAt(0) == '$') { - var type = angular['Global']['typeOf'](lastInstance); - type = angular[type.charAt(0).toUpperCase()+type.substring(1)]; - var fn = type ? type[[key.substring(1)]] : undefined; - if (fn) { - instance = _.bind(fn, lastInstance, lastInstance); - return instance; - } - } - } - if (typeof instance === 'function' && !instance['$$factory']) { - return bind(lastInstance, instance); - } - return instance; -}; - -Scope.setter = function(instance, path, value){ - var element = path.split('.'); - for ( var i = 0; element.length > 1; i++) { - var key = element.shift(); - var newInstance = instance[key]; - if (!newInstance) { - newInstance = {}; - instance[key] = newInstance; - } - instance = newInstance; - } - instance[element.shift()] = value; - return value; -}; - -Scope.prototype = { - // TODO: rename to update? or eval? - updateView: function() { - var self = this; - this.fireWatchers(); - foreach(this.widgets, function(widget){ - self.evalWidget(widget, "", {}, function(){ - this.updateView(self); - }); - }); - foreach(this.evals, bind(this, this.apply)); - }, - - addWidget: function(controller) { - if (controller) this.widgets.push(controller); - }, - - addEval: function(fn, listener) { - // todo: this should take a function/string and a listener - // todo: this is a hack, which will need to be cleaned up. - var self = this, - listenFn = listener || noop, - expr = self.compile(fn); - this.evals.push(function(){ - self.apply(listenFn, expr()); - }); - }, - - isProperty: function(exp) { - for ( var i = 0; i < exp.length; i++) { - var ch = exp.charAt(i); - if (ch!='.' && !Lexer.prototype.isIdent(ch)) { - return false; - } - } - return true; - }, - - get: function(path) { -// log('SCOPE.get', path, Scope.getter(this.state, path)); - return Scope.getter(this.state, path); - }, - - set: function(path, value) { -// log('SCOPE.set', path, value); - var instance = this.state; - return Scope.setter(instance, path, value); - }, - - setEval: function(expressionText, value) { - this.eval(expressionText + "=" + toJson(value)); - }, - - compile: function(exp) { - if (isFunction(exp)) return bind(this.state, exp); - var expFn = Scope.expressionCache[exp], self = this; - if (!expFn) { - var parser = new Parser(exp); - expFn = parser.statements(); - parser.assertAllConsumed(); - Scope.expressionCache[exp] = expFn; - } - return function(context){ - context = context || {}; - context.self = self.state; - context.scope = self; - return expFn.call(self, context); - }; - }, - - eval: function(exp, context) { -// log('Scope.eval', expressionText); - return this.compile(exp)(context); - }, - - //TODO: Refactor. This function needs to be an execution closure for widgets - // move to widgets - // remove expression, just have inner closure. - evalWidget: function(widget, expression, context, onSuccess, onFailure) { - try { - var value = this.eval(expression, context); - if (widget.hasError) { - widget.hasError = false; - jQuery(widget.view). - removeClass('ng-exception'). - removeAttr('ng-error'); - } - if (onSuccess) { - value = onSuccess.apply(widget, [value]); - } - return true; - } catch (e){ - var jsonError = toJson(e, true); - error('Eval Widget Error:', jsonError); - widget.hasError = true; - jQuery(widget.view). - addClass('ng-exception'). - attr('ng-error', jsonError); - if (onFailure) { - onFailure.apply(widget, [e, jsonError]); - } - return false; - } - }, - - validate: function(expressionText, value, element) { - var expression = Scope.expressionCache[expressionText]; - if (!expression) { - expression = new Parser(expressionText).validator(); - Scope.expressionCache[expressionText] = expression; - } - var self = {scope:this, self:this.state, '$element':element}; - return expression(self)(self, value); - }, - - entity: function(entityDeclaration, datastore) { - var expression = new Parser(entityDeclaration).entityDeclaration(); - return expression({scope:this, datastore:datastore}); - }, - - clearInvalid: function() { - var invalid = this.state['$invalidWidgets']; - while(invalid.length > 0) {invalid.pop();} - }, - - markInvalid: function(widget) { - this.state['$invalidWidgets'].push(widget); - }, - - watch: function(declaration) { - var self = this; - new Parser(declaration).watch()({ - scope:this, - addListener:function(watch, exp){ - self.addWatchListener(watch, function(n,o){ - try { - return exp({scope:self}, n, o); - } catch(e) { - alert(e); - } - }); - } - }); - }, - - addWatchListener: function(watchExpression, listener) { - // TODO: clean me up! - if (!isFunction(listener)) { - listener = this.compile(listener); - } - var watcher = this.watchListeners[watchExpression]; - if (!watcher) { - watcher = {listeners:[], expression:watchExpression}; - this.watchListeners[watchExpression] = watcher; - } - watcher.listeners.push(listener); - }, - - fireWatchers: function() { - var self = this, fired = false; - foreach(this.watchListeners, function(watcher) { - var value = self.eval(watcher.expression); - if (value !== watcher.lastValue) { - foreach(watcher.listeners, function(listener){ - listener(value, watcher.lastValue); - fired = true; - }); - watcher.lastValue = value; - } - }); - return fired; - }, - - apply: function(fn) { - fn.apply(this.state, slice.call(arguments, 1, arguments.length)); - } -}; - -////////////////////////////// - function getter(instance, path) { if (!path) return instance; var element = path.split('.'); @@ -262,12 +12,12 @@ function getter(instance, path) { lastInstance = instance; instance = instance[key]; } - if (_.isUndefined(instance) && key.charAt(0) == '$') { + if (isUndefined(instance) && key.charAt(0) == '$') { var type = angular['Global']['typeOf'](lastInstance); type = angular[type.charAt(0).toUpperCase()+type.substring(1)]; var fn = type ? type[[key.substring(1)]] : undefined; if (fn) { - instance = _.bind(fn, lastInstance, lastInstance); + instance = bind(fn, lastInstance, lastInstance); return instance; } } @@ -303,24 +53,26 @@ function expressionCompile(exp){ parser.assertAllConsumed(); compileCache[exp] = expFn; } - // return expFn - // TODO(remove this hack) + return parserNewScopeAdapter(expFn); +}; + +// return expFn +// TODO(remove this hack) +function parserNewScopeAdapter(fn) { return function(){ - return expFn({ + return fn({ scope: { set: this.$set, get: this.$get } }); }; -}; - -var NON_RENDERABLE_ELEMENTS = { - '#text': 1, '#comment':1, 'TR':1, 'TH':1 -}; +} -function isRenderableElement(element){ - return element && element[0] && !NON_RENDERABLE_ELEMENTS[element[0].nodeName]; +function isRenderableElement(element) { + var name = element && element[0] && element[0].nodeName; + return name && name.charAt(0) != '#' && + !includes(['TR', 'COL', 'COLGROUP', 'TBODY', 'THEAD', 'TFOOT'], name); } function rethrow(e) { throw e; } @@ -334,7 +86,7 @@ function errorHandlerFor(element) { }; } -function scope(parent, Class) { +function createScope(parent, Class) { function Parent(){} function API(){} function Behavior(){} -- cgit v1.2.3 From e55c97debaa0ef8487ece219b6eadbc147ece1f9 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 29 Mar 2010 20:25:42 -0700 Subject: dissabled a lot of tests, and made the core test set pass. --- src/Scope.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 6ba6aa8e..3e225653 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -61,6 +61,7 @@ function expressionCompile(exp){ function parserNewScopeAdapter(fn) { return function(){ return fn({ + state: this, scope: { set: this.$set, get: this.$get -- cgit v1.2.3 From d2d356918bd1c0c76673d22ff85c617fbd85d40e Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 29 Mar 2010 21:49:12 -0700 Subject: reenabled more tests --- src/Scope.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 3e225653..cd4eb8ea 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -106,20 +106,23 @@ function createScope(parent, Class) { $get: bind(instance, getter, instance), $set: bind(instance, setter, instance), - $eval: function(exp) { + $eval: function $eval(exp) { if (isDefined(exp)) { return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length)); } else { foreach(evalList, function(eval) { instance.$tryEval(eval.fn, eval.handler); }); + var dirty = false; foreach(watchList, function(watch) { var value = instance.$tryEval(watch.watch, watch.handler); if (watch.last !== value) { + dirty = true; instance.$tryEval(watch.listener, watch.handler, value, watch.last); watch.last = value; } }); + if (dirty) $eval(); } }, -- cgit v1.2.3 From a7d62dcb5533ceb9a7ae47ee27e2054400a0196b Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Tue, 30 Mar 2010 14:55:04 -0700 Subject: more tests fixed --- src/Scope.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index cd4eb8ea..dbb6c4aa 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -110,25 +110,26 @@ function createScope(parent, Class) { if (isDefined(exp)) { return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length)); } else { - foreach(evalList, function(eval) { - instance.$tryEval(eval.fn, eval.handler); - }); - var dirty = false; foreach(watchList, function(watch) { var value = instance.$tryEval(watch.watch, watch.handler); if (watch.last !== value) { - dirty = true; instance.$tryEval(watch.listener, watch.handler, value, watch.last); watch.last = value; } }); - if (dirty) $eval(); + foreach(evalList, function(eval) { + instance.$tryEval(eval.fn, eval.handler); + }); } }, $tryEval: function (expression, exceptionHandler) { try { - return expressionCompile(expression).apply(instance, slice.call(arguments, 2, arguments.length)); + var value = expressionCompile(expression).apply(instance, slice.call(arguments, 2, arguments.length)); + if (exceptionHandler) { + errorHandlerFor(exceptionHandler)(); + } + return value; } catch (e) { error(e); if (isFunction(exceptionHandler)) { -- cgit v1.2.3 From b5b8f63e1ebc75d09c6faf8dbad6497880deed47 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Tue, 30 Mar 2010 15:39:51 -0700 Subject: more tests passing --- src/Scope.js | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index dbb6c4aa..42e7d5e5 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -77,14 +77,11 @@ function isRenderableElement(element) { } function rethrow(e) { throw e; } -function errorHandlerFor(element) { +function errorHandlerFor(element, error) { while (!isRenderableElement(element)) { element = element.parent() || jqLite(document.body); } - return function(error) { - element.attr('ng-error', angular.toJson(error)); - element.addClass('ng-exception'); - }; + elementError(element, 'ng-exception', isDefined(error) ? toJson(error) : error); } function createScope(parent, Class) { @@ -125,17 +122,13 @@ function createScope(parent, Class) { $tryEval: function (expression, exceptionHandler) { try { - var value = expressionCompile(expression).apply(instance, slice.call(arguments, 2, arguments.length)); - if (exceptionHandler) { - errorHandlerFor(exceptionHandler)(); - } - return value; + return expressionCompile(expression).apply(instance, slice.call(arguments, 2, arguments.length)); } catch (e) { error(e); if (isFunction(exceptionHandler)) { exceptionHandler(e); } else if (exceptionHandler) { - errorHandlerFor(exceptionHandler)(e); + errorHandlerFor(exceptionHandler, e); } } }, -- cgit v1.2.3 From 35a91085004e31f786df1e0011bc26ed0142ab4d Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Wed, 31 Mar 2010 13:57:25 -0700 Subject: all tests green, some dissabled --- src/Scope.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 42e7d5e5..4144d456 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -81,7 +81,7 @@ function errorHandlerFor(element, error) { while (!isRenderableElement(element)) { element = element.parent() || jqLite(document.body); } - elementError(element, 'ng-exception', isDefined(error) ? toJson(error) : error); + elementError(element, NG_EXCEPTION, isDefined(error) ? toJson(error) : error); } function createScope(parent, Class) { -- cgit v1.2.3 From 861bac1d2808b15abb867e761ded8144bf5f7e94 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Wed, 31 Mar 2010 17:56:16 -0700 Subject: started to add services --- src/Scope.js | 55 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 17 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 4144d456..ba86e24f 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -89,7 +89,11 @@ function createScope(parent, Class) { function API(){} function Behavior(){} - var instance, behavior, api, watchList = [], evalList = []; + var instance, behavior, api, evalLists = {}; + if (isFunction(parent)) { + Class = parent; + parent = {}; + } Class = Class || noop; parent = Parent.prototype = parent || {}; @@ -107,15 +111,10 @@ function createScope(parent, Class) { if (isDefined(exp)) { return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length)); } else { - foreach(watchList, function(watch) { - var value = instance.$tryEval(watch.watch, watch.handler); - if (watch.last !== value) { - instance.$tryEval(watch.listener, watch.handler, value, watch.last); - watch.last = value; - } - }); - foreach(evalList, function(eval) { - instance.$tryEval(eval.fn, eval.handler); + foreachSorted(evalLists, function(list) { + foreach(list, function(eval) { + instance.$tryEval(eval.fn, eval.handler); + }); }); } }, @@ -134,16 +133,24 @@ function createScope(parent, Class) { }, $watch: function(watchExp, listener, exceptionHandler) { - var watch = expressionCompile(watchExp); - watchList.push({ - watch: watch, - last: watch.call(instance), - handler: exceptionHandler, - listener:expressionCompile(listener) + var watch = expressionCompile(watchExp), + last = watch.call(instance); + instance.$onEval(PRIORITY_WATCH, function(){ + var value = watch.call(instance); + if (last !== value) { + instance.$tryEval(listener, exceptionHandler, value, last); + last = value; + } }); }, - $onEval: function(expr, exceptionHandler){ + $onEval: function(priority, expr, exceptionHandler){ + if (!isNumber(priority)) { + exceptionHandler = expr; + expr = priority; + priority = 0; + } + var evalList = evalLists[priority] || (evalLists[priority] = []); evalList.push({ fn: expressionCompile(expr), handler: exceptionHandler @@ -151,7 +158,21 @@ function createScope(parent, Class) { } }); + if (isUndefined(instance.$root)) { + behavior.$root = instance; + behavior.$parent = instance; + } + Class.apply(instance, slice.call(arguments, 2, arguments.length)); return instance; } + +function serviceAdapter(services) { + return function(){ + var self = this; + foreach(services, function(service, name){ + self[name] = service.call(self); + }); + }; +}; -- cgit v1.2.3 From 11a6431f8926c557f3c58408dacc98466e76cde1 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Wed, 31 Mar 2010 17:56:16 -0700 Subject: started to add services --- src/Scope.js | 55 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 17 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 4144d456..ba86e24f 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -89,7 +89,11 @@ function createScope(parent, Class) { function API(){} function Behavior(){} - var instance, behavior, api, watchList = [], evalList = []; + var instance, behavior, api, evalLists = {}; + if (isFunction(parent)) { + Class = parent; + parent = {}; + } Class = Class || noop; parent = Parent.prototype = parent || {}; @@ -107,15 +111,10 @@ function createScope(parent, Class) { if (isDefined(exp)) { return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length)); } else { - foreach(watchList, function(watch) { - var value = instance.$tryEval(watch.watch, watch.handler); - if (watch.last !== value) { - instance.$tryEval(watch.listener, watch.handler, value, watch.last); - watch.last = value; - } - }); - foreach(evalList, function(eval) { - instance.$tryEval(eval.fn, eval.handler); + foreachSorted(evalLists, function(list) { + foreach(list, function(eval) { + instance.$tryEval(eval.fn, eval.handler); + }); }); } }, @@ -134,16 +133,24 @@ function createScope(parent, Class) { }, $watch: function(watchExp, listener, exceptionHandler) { - var watch = expressionCompile(watchExp); - watchList.push({ - watch: watch, - last: watch.call(instance), - handler: exceptionHandler, - listener:expressionCompile(listener) + var watch = expressionCompile(watchExp), + last = watch.call(instance); + instance.$onEval(PRIORITY_WATCH, function(){ + var value = watch.call(instance); + if (last !== value) { + instance.$tryEval(listener, exceptionHandler, value, last); + last = value; + } }); }, - $onEval: function(expr, exceptionHandler){ + $onEval: function(priority, expr, exceptionHandler){ + if (!isNumber(priority)) { + exceptionHandler = expr; + expr = priority; + priority = 0; + } + var evalList = evalLists[priority] || (evalLists[priority] = []); evalList.push({ fn: expressionCompile(expr), handler: exceptionHandler @@ -151,7 +158,21 @@ function createScope(parent, Class) { } }); + if (isUndefined(instance.$root)) { + behavior.$root = instance; + behavior.$parent = instance; + } + Class.apply(instance, slice.call(arguments, 2, arguments.length)); return instance; } + +function serviceAdapter(services) { + return function(){ + var self = this; + foreach(services, function(service, name){ + self[name] = service.call(self); + }); + }; +}; -- cgit v1.2.3 From d717020911a350a5ea3c0a985c57d56c8fcad607 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 2 Apr 2010 11:10:36 -0700 Subject: widgets now work properly --- src/Scope.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index ba86e24f..ae5bd384 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -102,6 +102,7 @@ function createScope(parent, Class) { instance = new Behavior(); extend(api, { + 'this': instance, $parent: parent, $bind: bind(instance, bind, instance), $get: bind(instance, getter, instance), @@ -162,7 +163,7 @@ function createScope(parent, Class) { behavior.$root = instance; behavior.$parent = instance; } - + (parent.$onEval || noop)(instance.$eval); Class.apply(instance, slice.call(arguments, 2, arguments.length)); return instance; -- cgit v1.2.3 From 35ca4fcb9c49e505e28669e951e01ddedb01d7db Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 2 Apr 2010 11:49:48 -0700 Subject: radio now works with repeaters --- src/Scope.js | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 2b2db189..26a3f85b 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -84,6 +84,7 @@ function errorHandlerFor(element, error) { elementError(element, NG_EXCEPTION, isDefined(error) ? toJson(error) : error); } +var scopeId = 0; function createScope(parent, Class) { function Parent(){} function API(){} @@ -103,6 +104,7 @@ function createScope(parent, Class) { extend(api, { 'this': instance, + $id: (scopeId++), $parent: parent, $bind: bind(instance, bind, instance), $get: bind(instance, getter, instance), -- cgit v1.2.3 From a80a61839a66d244c8bb14bbe2975746e02516c8 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sat, 3 Apr 2010 17:04:36 -0700 Subject: injection is now working --- src/Scope.js | 53 +++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 26a3f85b..52ab3ed7 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -26,7 +26,7 @@ function getter(instance, path) { return bind(lastInstance, instance); } return instance; -}; +} function setter(instance, path, value){ var element = path.split('.'); @@ -41,7 +41,7 @@ function setter(instance, path, value){ } instance[element.shift()] = value; return value; -}; +} var compileCache = {}; function expressionCompile(exp){ @@ -54,7 +54,7 @@ function expressionCompile(exp){ compileCache[exp] = expFn; } return parserNewScopeAdapter(expFn); -}; +} // return expFn // TODO(remove this hack) @@ -85,21 +85,16 @@ function errorHandlerFor(element, error) { } var scopeId = 0; -function createScope(parent, Class) { +function createScope(parent, services, existing) { function Parent(){} function API(){} function Behavior(){} - var instance, behavior, api, evalLists = {}; - if (isFunction(parent)) { - Class = parent; - parent = {}; - } + var instance, behavior, api, evalLists = {}, servicesCache = extend({}, existing); - Class = Class || noop; - parent = Parent.prototype = parent || {}; + parent = Parent.prototype = (parent || {}); api = API.prototype = new Parent(); - behavior = Behavior.prototype = extend(new API(), Class.prototype); + behavior = Behavior.prototype = new API(); instance = new Behavior(); extend(api, { @@ -161,22 +156,28 @@ function createScope(parent, Class) { } }); - if (isUndefined(instance.$root)) { - behavior.$root = instance; - behavior.$parent = instance; + if (!parent.$root) { + api.$root = instance; + api.$parent = instance; } - (parent.$onEval || noop)(instance.$eval); - Class.apply(instance, slice.call(arguments, 2, arguments.length)); + function inject(name){ + var service = getter(servicesCache, name), factory, args = []; + if (isUndefined(service)) { + factory = services[name]; + if (!isFunction(factory)) + throw "Don't know how to inject '" + name + "'."; + foreach(factory.inject, function(dependency){ + args.push(inject(dependency)); + }); + setter(servicesCache, name, service = factory.apply(instance, args)); + } + return service; + } + + foreach(services, function(_, name){ + instance[name] = inject(name); + }); return instance; } - -function serviceAdapter(services) { - return function(){ - var self = this; - foreach(services, function(service, name){ - self[name] = service.call(self); - }); - }; -}; -- cgit v1.2.3 From 7a4b48020688060debe9cb0f9c17615d7585cbe7 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 5 Apr 2010 11:46:53 -0700 Subject: added ng:switch widget --- src/Scope.js | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 52ab3ed7..562dfbd8 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -70,17 +70,8 @@ function parserNewScopeAdapter(fn) { }; } -function isRenderableElement(element) { - var name = element && element[0] && element[0].nodeName; - return name && name.charAt(0) != '#' && - !includes(['TR', 'COL', 'COLGROUP', 'TBODY', 'THEAD', 'TFOOT'], name); -} - function rethrow(e) { throw e; } function errorHandlerFor(element, error) { - while (!isRenderableElement(element)) { - element = element.parent() || jqLite(document.body); - } elementError(element, NG_EXCEPTION, isDefined(error) ? toJson(error) : error); } @@ -132,14 +123,16 @@ function createScope(parent, services, existing) { $watch: function(watchExp, listener, exceptionHandler) { var watch = expressionCompile(watchExp), - last = watch.call(instance); - instance.$onEval(PRIORITY_WATCH, function(){ + last; + function watcher(){ var value = watch.call(instance); if (last !== value) { instance.$tryEval(listener, exceptionHandler, value, last); last = value; } - }); + } + instance.$onEval(PRIORITY_WATCH, watcher); + watcher(); }, $onEval: function(priority, expr, exceptionHandler){ -- cgit v1.2.3 From e6460685869e16b5016de975fd0ba15a7e436951 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 5 Apr 2010 21:26:52 -0700 Subject: added ng-controller directive --- src/Scope.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 562dfbd8..b41f7436 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -1,4 +1,4 @@ -function getter(instance, path) { +function getter(instance, path, unboundFn) { if (!path) return instance; var element = path.split('.'); var key; @@ -22,7 +22,7 @@ function getter(instance, path) { } } } - if (typeof instance === 'function' && !instance['$$factory']) { + if (!unboundFn && isFunction(instance) && !instance['$$factory']) { return bind(lastInstance, instance); } return instance; @@ -146,7 +146,17 @@ function createScope(parent, services, existing) { fn: expressionCompile(expr), handler: exceptionHandler }); + }, + + $become: function(Class) { + // remove existing + foreach(behavior, function(value, key){ delete behavior[key]; }); + foreach((Class || noop).prototype, function(fn, name){ + behavior[name] = bind(instance, fn); + }); + (Class || noop).call(instance); } + }); if (!parent.$root) { -- cgit v1.2.3 From 0df93fd49c1687b2eddaa79faa1c0adbef82bf72 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Wed, 7 Apr 2010 10:17:15 -0700 Subject: clean up, fixes for app --- src/Scope.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index b41f7436..0bc551c4 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -17,7 +17,7 @@ function getter(instance, path, unboundFn) { type = angular[type.charAt(0).toUpperCase()+type.substring(1)]; var fn = type ? type[[key.substring(1)]] : undefined; if (fn) { - instance = bind(fn, lastInstance, lastInstance); + instance = bind(lastInstance, fn, lastInstance); return instance; } } -- cgit v1.2.3 From 843bd355d25ebf2369aec79f98cb6704d38497e9 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 9 Apr 2010 16:20:15 -0700 Subject: various bug fixes --- src/Scope.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 0bc551c4..7529d726 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -179,7 +179,10 @@ function createScope(parent, services, existing) { } foreach(services, function(_, name){ - instance[name] = inject(name); + var service = inject(name); + if (service) { + instance[name] = service; + } }); return instance; -- cgit v1.2.3 From 70e401ef100614295fc808e32f0142f07c315461 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 15 Apr 2010 14:17:33 -0700 Subject: added $route service --- src/Scope.js | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 7529d726..8d44f4ef 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -117,6 +117,8 @@ function createScope(parent, services, existing) { exceptionHandler(e); } else if (exceptionHandler) { errorHandlerFor(exceptionHandler, e); + } else if (isFunction(instance.$exceptionHandler)) { + instance.$exceptionHandler(e); } } }, -- cgit v1.2.3 From deb86fe357a901889bc4289087f0b9e69cb8a302 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 16 Apr 2010 14:01:29 -0700 Subject: lots of small fixes --- src/Scope.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 8d44f4ef..54e75dbd 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -81,7 +81,7 @@ function createScope(parent, services, existing) { function API(){} function Behavior(){} - var instance, behavior, api, evalLists = {}, servicesCache = extend({}, existing); + var instance, behavior, api, evalLists = {sorted:[]}, servicesCache = extend({}, existing); parent = Parent.prototype = (parent || {}); api = API.prototype = new Parent(); @@ -100,7 +100,7 @@ function createScope(parent, services, existing) { if (isDefined(exp)) { return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length)); } else { - foreachSorted(evalLists, function(list) { + foreach(evalLists.sorted, function(list) { foreach(list, function(eval) { instance.$tryEval(eval.fn, eval.handler); }); @@ -143,7 +143,13 @@ function createScope(parent, services, existing) { expr = priority; priority = 0; } - var evalList = evalLists[priority] || (evalLists[priority] = []); + var evalList = evalLists[priority]; + if (!evalList) { + evalList = evalLists[priority] = []; + evalList.priority = priority; + evalLists.sorted.push(evalList); + evalLists.sorted.sort(function(a,b){return a.priority-b.priority;}); + } evalList.push({ fn: expressionCompile(expr), handler: exceptionHandler -- cgit v1.2.3 From c7913a4b7a3f5ffb0ea6bb1e636ac9d4a0e75c32 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 29 Apr 2010 17:28:33 -0700 Subject: added $xhr service with bulk and cache, hooked up $resource --- src/Scope.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 54e75dbd..1b93418f 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -173,7 +173,7 @@ function createScope(parent, services, existing) { } function inject(name){ - var service = getter(servicesCache, name), factory, args = []; + var service = getter(servicesCache, name, true), factory, args = []; if (isUndefined(service)) { factory = services[name]; if (!isFunction(factory)) @@ -189,7 +189,7 @@ function createScope(parent, services, existing) { foreach(services, function(_, name){ var service = inject(name); if (service) { - instance[name] = service; + setter(instance, name, service); } }); -- cgit v1.2.3 From 038a743e6f49c347a38edc0e54dcbb175905a475 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 7 May 2010 12:09:14 -0700 Subject: xhr bulk fixes --- src/Scope.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 1b93418f..9a20c214 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -97,7 +97,7 @@ function createScope(parent, services, existing) { $set: bind(instance, setter, instance), $eval: function $eval(exp) { - if (isDefined(exp)) { + if (exp) { return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length)); } else { foreach(evalLists.sorted, function(list) { @@ -129,8 +129,8 @@ function createScope(parent, services, existing) { function watcher(){ var value = watch.call(instance); if (last !== value) { - instance.$tryEval(listener, exceptionHandler, value, last); last = value; + instance.$tryEval(listener, exceptionHandler, value, last); } } instance.$onEval(PRIORITY_WATCH, watcher); -- cgit v1.2.3 From 0305b6746e2c50960b042c5d687794e030930f8b Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Fri, 7 May 2010 13:43:54 -0700 Subject: change everything over to jasmine --- src/Scope.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 9a20c214..687d3628 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -127,10 +127,11 @@ function createScope(parent, services, existing) { var watch = expressionCompile(watchExp), last; function watcher(){ - var value = watch.call(instance); + var value = watch.call(instance), + lastValue = last; if (last !== value) { last = value; - instance.$tryEval(listener, exceptionHandler, value, last); + instance.$tryEval(listener, exceptionHandler, value, lastValue); } } instance.$onEval(PRIORITY_WATCH, watcher); -- cgit v1.2.3 From 22d1464d7abc284dd56d6beaf47e8d85088e01c5 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 13 May 2010 13:57:39 -0700 Subject: fixed issue with radio view clobering model if radio was checked. --- src/Scope.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 687d3628..7bcf7380 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -97,7 +97,7 @@ function createScope(parent, services, existing) { $set: bind(instance, setter, instance), $eval: function $eval(exp) { - if (exp) { + if (exp !== undefined) { return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length)); } else { foreach(evalLists.sorted, function(list) { -- cgit v1.2.3 From 0f73084e9d21cea99f0535e6ca30a1341b7047dc Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Wed, 19 May 2010 11:51:17 -0700 Subject: added error handler to xhr requests --- src/Scope.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 7bcf7380..fe0b6ce3 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -174,7 +174,7 @@ function createScope(parent, services, existing) { } function inject(name){ - var service = getter(servicesCache, name, true), factory, args = []; + var service = servicesCache[name], factory, args = []; if (isUndefined(service)) { factory = services[name]; if (!isFunction(factory)) @@ -182,7 +182,7 @@ function createScope(parent, services, existing) { foreach(factory.inject, function(dependency){ args.push(inject(dependency)); }); - setter(servicesCache, name, service = factory.apply(instance, args)); + servicesCache[name] = service = factory.apply(instance, args); } return service; } -- cgit v1.2.3 From 0e88e35e5c76420c48a487718558d33e452ea1eb Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sun, 30 May 2010 15:45:33 -0700 Subject: remove the uneeded call to createScope when evaluating expressions --- src/Scope.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index fe0b6ce3..70869b3b 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -60,11 +60,12 @@ function expressionCompile(exp){ // TODO(remove this hack) function parserNewScopeAdapter(fn) { return function(){ + var self = this; return fn({ - state: this, + state: self, scope: { - set: this.$set, - get: this.$get + set: function(key, value){ return setter(self, key, value);}, + get: function(key) { return getter(self, key); } } }); }; -- cgit v1.2.3 From 0d87208553af7a9ad6c6c1c73bd3a4105062eafa Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sun, 30 May 2010 16:11:00 -0700 Subject: remove the relience of parser an special self object, now passing generic self --- src/Scope.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 70869b3b..ac07c7a4 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -60,14 +60,7 @@ function expressionCompile(exp){ // TODO(remove this hack) function parserNewScopeAdapter(fn) { return function(){ - var self = this; - return fn({ - state: self, - scope: { - set: function(key, value){ return setter(self, key, value);}, - get: function(key) { return getter(self, key); } - } - }); + return fn(this); }; } -- cgit v1.2.3 From c7d64f6d124f10c66309042c2d77896215ed43b8 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sun, 30 May 2010 16:34:59 -0700 Subject: improve error handling with elements --- src/Scope.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index ac07c7a4..6d68eeed 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -53,14 +53,8 @@ function expressionCompile(exp){ parser.assertAllConsumed(); compileCache[exp] = expFn; } - return parserNewScopeAdapter(expFn); -} - -// return expFn -// TODO(remove this hack) -function parserNewScopeAdapter(fn) { return function(){ - return fn(this); + return expFn(this); }; } -- cgit v1.2.3 From ad18fe144263b966f8930edb672e08b9926e00a1 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sun, 30 May 2010 16:45:35 -0700 Subject: compiler exposos both self and this function calling convention --- src/Scope.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 6d68eeed..bed0ff6d 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -46,16 +46,16 @@ function setter(instance, path, value){ var compileCache = {}; function expressionCompile(exp){ if (isFunction(exp)) return exp; - var expFn = compileCache[exp]; - if (!expFn) { + var fn = compileCache[exp]; + if (!fn) { var parser = new Parser(exp); - expFn = parser.statements(); + var fnSelf = parser.statements(); parser.assertAllConsumed(); - compileCache[exp] = expFn; + fn = compileCache[exp] = extend( + function(){ return fnSelf(this);}, + {fnSelf: fnSelf}); } - return function(){ - return expFn(this); - }; + return fn; } function rethrow(e) { throw e; } -- cgit v1.2.3 From 2e33e89a77d115ff17f5841ec328b1c1e4228161 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Sun, 30 May 2010 19:42:21 -0700 Subject: added compiled getterFN for better performance --- src/Scope.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index bed0ff6d..1c223130 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -43,6 +43,41 @@ function setter(instance, path, value){ return value; } +/////////////////////////////////// + +var getterFnCache = {}; +function getterFn(path){ + var fn = getterFnCache[path]; + if (fn) return fn; + + var code = 'function (self){\n'; + code += ' var last, fn, type;\n'; + foreach(path.split('.'), function(key) { + code += ' if(!self) return self;\n'; + code += ' last = self;\n'; + code += ' self = self.' + key + ';\n'; + code += ' if(typeof self == "function") \n'; + code += ' self = function(){ return last.'+key+'.apply(last, arguments); };\n'; + if (key.charAt(0) == '$') { + // special code for super-imposed functions + var name = key.substr(1); + code += ' if(!self) {\n'; + code += ' type = angular.Global.typeOf(last);\n'; + code += ' fn = (angular[type.charAt(0).toUpperCase() + type.substring(1)]||{})["' + name + '"];\n'; + code += ' if (fn)\n'; + code += ' self = function(){ return fn.apply(last, [last].concat(slice.call(arguments, 0, arguments.length))); };\n'; + code += ' }\n'; + } + }); + code += ' return self;\n}'; + fn = eval('(' + code + ')'); + fn.toString = function(){ return code; }; + + return getterFnCache[path] = fn; +} + +/////////////////////////////////// + var compileCache = {}; function expressionCompile(exp){ if (isFunction(exp)) return exp; -- cgit v1.2.3 From 6143b04384680d17f38c2d5894a9b9961ea33288 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 31 May 2010 00:58:29 -0700 Subject: removed few key foreach and replaced thime with for loop for performance. --- src/Scope.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 1c223130..637fc25e 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -53,14 +53,15 @@ function getterFn(path){ var code = 'function (self){\n'; code += ' var last, fn, type;\n'; foreach(path.split('.'), function(key) { + key = (key == 'this') ? '["this"]' : '.' + key; code += ' if(!self) return self;\n'; code += ' last = self;\n'; - code += ' self = self.' + key + ';\n'; + code += ' self = self' + key + ';\n'; code += ' if(typeof self == "function") \n'; - code += ' self = function(){ return last.'+key+'.apply(last, arguments); };\n'; - if (key.charAt(0) == '$') { + code += ' self = function(){ return last'+key+'.apply(last, arguments); };\n'; + if (key.charAt(1) == '$') { // special code for super-imposed functions - var name = key.substr(1); + var name = key.substr(2); code += ' if(!self) {\n'; code += ' type = angular.Global.typeOf(last);\n'; code += ' fn = (angular[type.charAt(0).toUpperCase() + type.substring(1)]||{})["' + name + '"];\n'; @@ -123,11 +124,13 @@ function createScope(parent, services, existing) { if (exp !== undefined) { return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length)); } else { - foreach(evalLists.sorted, function(list) { - foreach(list, function(eval) { - instance.$tryEval(eval.fn, eval.handler); - }); - }); + for ( var i = 0, iSize = evalLists.sorted.length; i < iSize; i++) { + for ( var queue = evalLists.sorted[i], + jSize = queue.length, + j= 0; j < jSize; j++) { + instance.$tryEval(queue[j].fn, queue[j].handler); + } + } } }, -- cgit v1.2.3 From a29c5e4c7fd5e708c28e70e974bf873621d5277c Mon Sep 17 00:00:00 2001 From: Shyam Seshadri Date: Wed, 2 Jun 2010 15:04:26 -0700 Subject: Revert "removed few key foreach and replaced thime with for loop for performance." This reverts commit 6143b04384680d17f38c2d5894a9b9961ea33288. --- src/Scope.js | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 637fc25e..1c223130 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -53,15 +53,14 @@ function getterFn(path){ var code = 'function (self){\n'; code += ' var last, fn, type;\n'; foreach(path.split('.'), function(key) { - key = (key == 'this') ? '["this"]' : '.' + key; code += ' if(!self) return self;\n'; code += ' last = self;\n'; - code += ' self = self' + key + ';\n'; + code += ' self = self.' + key + ';\n'; code += ' if(typeof self == "function") \n'; - code += ' self = function(){ return last'+key+'.apply(last, arguments); };\n'; - if (key.charAt(1) == '$') { + code += ' self = function(){ return last.'+key+'.apply(last, arguments); };\n'; + if (key.charAt(0) == '$') { // special code for super-imposed functions - var name = key.substr(2); + var name = key.substr(1); code += ' if(!self) {\n'; code += ' type = angular.Global.typeOf(last);\n'; code += ' fn = (angular[type.charAt(0).toUpperCase() + type.substring(1)]||{})["' + name + '"];\n'; @@ -124,13 +123,11 @@ function createScope(parent, services, existing) { if (exp !== undefined) { return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length)); } else { - for ( var i = 0, iSize = evalLists.sorted.length; i < iSize; i++) { - for ( var queue = evalLists.sorted[i], - jSize = queue.length, - j= 0; j < jSize; j++) { - instance.$tryEval(queue[j].fn, queue[j].handler); - } - } + foreach(evalLists.sorted, function(list) { + foreach(list, function(eval) { + instance.$tryEval(eval.fn, eval.handler); + }); + }); } }, -- cgit v1.2.3 From 39312d1fe3a27b248f98f6f26577fcd7e2c64f85 Mon Sep 17 00:00:00 2001 From: Shyam Seshadri Date: Wed, 2 Jun 2010 15:05:34 -0700 Subject: Revert "Revert "removed few key foreach and replaced thime with for loop for performance."" This reverts commit a29c5e4c7fd5e708c28e70e974bf873621d5277c. --- src/Scope.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'src/Scope.js') diff --git a/src/Scope.js b/src/Scope.js index 1c223130..637fc25e 100644 --- a/src/Scope.js +++ b/src/Scope.js @@ -53,14 +53,15 @@ function getterFn(path){ var code = 'function (self){\n'; code += ' var last, fn, type;\n'; foreach(path.split('.'), function(key) { + key = (key == 'this') ? '["this"]' : '.' + key; code += ' if(!self) return self;\n'; code += ' last = self;\n'; - code += ' self = self.' + key + ';\n'; + code += ' self = self' + key + ';\n'; code += ' if(typeof self == "function") \n'; - code += ' self = function(){ return last.'+key+'.apply(last, arguments); };\n'; - if (key.charAt(0) == '$') { + code += ' self = function(){ return last'+key+'.apply(last, arguments); };\n'; + if (key.charAt(1) == '$') { // special code for super-imposed functions - var name = key.substr(1); + var name = key.substr(2); code += ' if(!self) {\n'; code += ' type = angular.Global.typeOf(last);\n'; code += ' fn = (angular[type.charAt(0).toUpperCase() + type.substring(1)]||{})["' + name + '"];\n'; @@ -123,11 +124,13 @@ function createScope(parent, services, existing) { if (exp !== undefined) { return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length)); } else { - foreach(evalLists.sorted, function(list) { - foreach(list, function(eval) { - instance.$tryEval(eval.fn, eval.handler); - }); - }); + for ( var i = 0, iSize = evalLists.sorted.length; i < iSize; i++) { + for ( var queue = evalLists.sorted[i], + jSize = queue.length, + j= 0; j < jSize; j++) { + instance.$tryEval(queue[j].fn, queue[j].handler); + } + } } }, -- cgit v1.2.3