angular.js/src/Scope.js

184 lines
5 KiB
JavaScript
Raw Normal View History

2010-03-26 05:03:11 +00:00
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) == '$') {
2010-03-26 05:03:11 +00:00
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);
2010-03-26 05:03:11 +00:00
return instance;
}
}
}
if (typeof instance === 'function' && !instance['$$factory']) {
return bind(lastInstance, instance);
}
return instance;
2010-04-04 00:04:36 +00:00
}
2010-03-26 05:03:11 +00:00
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;
2010-04-04 00:04:36 +00:00
}
2010-03-26 05:03:11 +00:00
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 parserNewScopeAdapter(expFn);
2010-04-04 00:04:36 +00:00
}
// return expFn
// TODO(remove this hack)
function parserNewScopeAdapter(fn) {
2010-03-26 05:03:11 +00:00
return function(){
return fn({
state: this,
2010-03-26 05:03:11 +00:00
scope: {
set: this.$set,
get: this.$get
}
});
};
}
2010-03-26 05:03:11 +00:00
function isRenderableElement(element) {
var name = element && element[0] && element[0].nodeName;
return name && name.charAt(0) != '#' &&
!includes(['TR', 'COL', 'COLGROUP', 'TBODY', 'THEAD', 'TFOOT'], name);
2010-03-26 05:03:11 +00:00
}
function rethrow(e) { throw e; }
2010-03-30 22:39:51 +00:00
function errorHandlerFor(element, error) {
2010-03-26 05:03:11 +00:00
while (!isRenderableElement(element)) {
element = element.parent() || jqLite(document.body);
}
2010-03-31 20:57:25 +00:00
elementError(element, NG_EXCEPTION, isDefined(error) ? toJson(error) : error);
2010-03-26 05:03:11 +00:00
}
2010-04-02 18:49:48 +00:00
var scopeId = 0;
2010-04-04 00:04:36 +00:00
function createScope(parent, services, existing) {
2010-03-26 05:03:11 +00:00
function Parent(){}
function API(){}
function Behavior(){}
2010-04-04 00:04:36 +00:00
var instance, behavior, api, evalLists = {}, servicesCache = extend({}, existing);
2010-03-26 05:03:11 +00:00
2010-04-04 00:04:36 +00:00
parent = Parent.prototype = (parent || {});
2010-03-26 05:03:11 +00:00
api = API.prototype = new Parent();
2010-04-04 00:04:36 +00:00
behavior = Behavior.prototype = new API();
2010-03-26 05:03:11 +00:00
instance = new Behavior();
extend(api, {
2010-04-02 18:10:36 +00:00
'this': instance,
2010-04-02 18:49:48 +00:00
$id: (scopeId++),
2010-03-26 05:03:11 +00:00
$parent: parent,
$bind: bind(instance, bind, instance),
$get: bind(instance, getter, instance),
$set: bind(instance, setter, instance),
2010-03-30 04:49:12 +00:00
$eval: function $eval(exp) {
2010-03-26 05:03:11 +00:00
if (isDefined(exp)) {
return expressionCompile(exp).apply(instance, slice.call(arguments, 1, arguments.length));
} else {
2010-04-01 00:56:16 +00:00
foreachSorted(evalLists, function(list) {
foreach(list, function(eval) {
instance.$tryEval(eval.fn, eval.handler);
});
2010-03-30 21:55:04 +00:00
});
2010-03-26 05:03:11 +00:00
}
},
$tryEval: function (expression, exceptionHandler) {
try {
2010-03-30 22:39:51 +00:00
return expressionCompile(expression).apply(instance, slice.call(arguments, 2, arguments.length));
2010-03-26 05:03:11 +00:00
} catch (e) {
error(e);
if (isFunction(exceptionHandler)) {
exceptionHandler(e);
} else if (exceptionHandler) {
2010-03-30 22:39:51 +00:00
errorHandlerFor(exceptionHandler, e);
2010-03-26 05:03:11 +00:00
}
}
},
$watch: function(watchExp, listener, exceptionHandler) {
2010-04-01 00:56:16 +00:00
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;
}
2010-03-26 05:03:11 +00:00
});
},
2010-04-01 00:56:16 +00:00
$onEval: function(priority, expr, exceptionHandler){
if (!isNumber(priority)) {
exceptionHandler = expr;
expr = priority;
priority = 0;
}
var evalList = evalLists[priority] || (evalLists[priority] = []);
2010-03-26 05:03:11 +00:00
evalList.push({
fn: expressionCompile(expr),
handler: exceptionHandler
});
}
});
2010-04-04 00:04:36 +00:00
if (!parent.$root) {
api.$root = instance;
api.$parent = instance;
2010-04-01 00:56:16 +00:00
}
2010-04-01 00:56:16 +00:00
2010-04-04 00:04:36 +00:00
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);
});
2010-03-26 05:03:11 +00:00
return instance;
}