aboutsummaryrefslogtreecommitdiffstats
path: root/src/Scope.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/Scope.js')
-rw-r--r--src/Scope.js198
1 files changed, 198 insertions, 0 deletions
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;
+};