aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMisko Hevery2010-03-30 14:55:04 -0700
committerMisko Hevery2010-03-30 14:55:04 -0700
commita7d62dcb5533ceb9a7ae47ee27e2054400a0196b (patch)
tree4c3702dbf899a8c669b833157b86a883c55d77ba /src
parentd2d356918bd1c0c76673d22ff85c617fbd85d40e (diff)
downloadangular.js-a7d62dcb5533ceb9a7ae47ee27e2054400a0196b.tar.bz2
more tests fixed
Diffstat (limited to 'src')
-rw-r--r--src/Angular.js15
-rw-r--r--src/Compiler.js102
-rw-r--r--src/Scope.js15
-rw-r--r--src/Widgets.js5
-rw-r--r--src/directives.js46
5 files changed, 98 insertions, 85 deletions
diff --git a/src/Angular.js b/src/Angular.js
index e49eb9a9..4443890a 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -23,10 +23,6 @@ var consoleNode,
});
angular['copy'] = copy;
-var isVisible = isVisible || function (element) {
- return jQuery(element).is(":visible");
-};
-
function foreach(obj, iterator, context) {
var key;
if (obj) {
@@ -81,9 +77,11 @@ function isString(value){ return typeof value == 'string';}
function isNumber(value){ return typeof value == 'number';}
function isArray(value) { return value instanceof Array; }
function isFunction(value){ return typeof value == 'function';}
+function isTextNode(node) { return nodeName(node) == '#text'; }
function lowercase(value){ return isString(value) ? value.toLowerCase() : value; }
function uppercase(value){ return isString(value) ? value.toUpperCase() : value; }
function trim(value) { return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value; };
+function nodeName(element) { return (element[0] || element || {}).nodeName; }
function map(obj, iterator, context) {
var results = [];
foreach(obj, function(value, index, list) {
@@ -261,10 +259,13 @@ function outerHTML(node) {
}
function toBoolean(value) {
- var v = ("" + value).toLowerCase();
- if (v == 'f' || v == '0' || v == 'false' || v == 'no')
+ if (value && value.length !== 0) {
+ var v = lowercase("" + value);
+ value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == '[]');
+ } else {
value = false;
- return !!value;
+ }
+ return value;
}
function merge(src, dst) {
diff --git a/src/Compiler.js b/src/Compiler.js
index e97fb112..361d6946 100644
--- a/src/Compiler.js
+++ b/src/Compiler.js
@@ -50,37 +50,6 @@ Template.prototype = {
///////////////////////////////////
//Compiler
//////////////////////////////////
-function isTextNode(node) {
- return node.nodeName == '#text';
-}
-
-function eachTextNode(element, fn){
- var i, chldNodes = element[0].childNodes || [], size = chldNodes.length, chld;
- for (i = 0; i < size; i++) {
- if(isTextNode(chld = chldNodes[i])) {
- fn(jqLite(chld), i);
- }
- }
-}
-
-function eachNode(element, fn){
- var i, chldNodes = element[0].childNodes || [], size = chldNodes.length, chld;
- for (i = 0; i < size; i++) {
- if(!isTextNode(chld = chldNodes[i])) {
- fn(jqLite(chld), i);
- }
- }
-}
-
-function eachAttribute(element, fn){
- var i, attrs = element[0].attributes || [], size = attrs.length, chld, attr, attrValue = {};
- for (i = 0; i < size; i++) {
- var attr = attrs[i];
- attrValue[attr.name] = attr.value;
- }
- foreach(attrValue, fn);
-}
-
function Compiler(textMarkup, attrMarkup, directives, widgets){
this.textMarkup = textMarkup;
this.attrMarkup = attrMarkup;
@@ -110,24 +79,38 @@ Compiler.prototype = {
templatize: function(element){
var self = this,
- widget = self.widgets[element[0].nodeName],
- directives = self.directives,
+ widget,
+ directiveFns = self.directives,
descend = true,
- exclusive = false,
- directiveQueue = [],
+ directives = true,
template = new Template(),
selfApi = {
compile: bind(self, self.compile),
comment:function(text) {return jqLite(document.createComment(text));},
element:function(type) {return jqLite(document.createElement(type));},
text:function(text) {return jqLite(document.createTextNode(text));},
- descend: function(value){ if(isDefined(value)) descend = value; return descend;}
+ descend: function(value){ if(isDefined(value)) descend = value; return descend;},
+ directives: function(value){ if(isDefined(value)) directives = value; return directives;}
};
+ eachAttribute(element, function(value, name){
+ if (!widget) {
+ if (widget = self.widgets['@' + name]) {
+ widget = bind(selfApi, widget, value, element);
+ }
+ }
+ });
+ if (!widget) {
+ if (widget = self.widgets[nodeName(element)]) {
+ widget = bind(selfApi, widget, element);
+ }
+ }
if (widget) {
descend = false;
+ directives = false;
template.addInit(widget.call(selfApi, element));
- } else {
+ }
+ if (descend){
// process markup for text nodes only
eachTextNode(element, function(textNode){
var text = textNode.text();
@@ -135,7 +118,9 @@ Compiler.prototype = {
markup.call(selfApi, text, textNode, element);
});
});
+ }
+ if (directives) {
// Process attributes/directives
eachAttribute(element, function(value, name){
foreach(self.attrMarkup, function(markup){
@@ -143,21 +128,8 @@ Compiler.prototype = {
});
});
eachAttribute(element, function(value, name){
- var directive = directives[name];
- if (!exclusive && directive) {
- if (directive.exclusive) {
- exclusive = true;
- directiveQueue = [];
- }
- directiveQueue.push(bind(selfApi, directive, value, element));
- }
+ template.addInit((directiveFns[name]||noop).call(selfApi, value, element));
});
-
- // Execute directives
- foreach(directiveQueue, function(directive){
- template.addInit(directive());
- });
-
}
// Process non text child nodes
if (descend) {
@@ -168,3 +140,31 @@ Compiler.prototype = {
return template.empty() ? null : template;
}
};
+
+function eachTextNode(element, fn){
+ var i, chldNodes = element[0].childNodes || [], size = chldNodes.length, chld;
+ for (i = 0; i < size; i++) {
+ if(isTextNode(chld = chldNodes[i])) {
+ fn(jqLite(chld), i);
+ }
+ }
+}
+
+function eachNode(element, fn){
+ var i, chldNodes = element[0].childNodes || [], size = chldNodes.length, chld;
+ for (i = 0; i < size; i++) {
+ if(!isTextNode(chld = chldNodes[i])) {
+ fn(jqLite(chld), i);
+ }
+ }
+}
+
+function eachAttribute(element, fn){
+ var i, attrs = element[0].attributes || [], size = attrs.length, chld, attr, attrValue = {};
+ for (i = 0; i < size; i++) {
+ var attr = attrs[i];
+ attrValue[attr.name] = attr.value;
+ }
+ foreach(attrValue, fn);
+}
+
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)) {
diff --git a/src/Widgets.js b/src/Widgets.js
index 870468d3..d9d72535 100644
--- a/src/Widgets.js
+++ b/src/Widgets.js
@@ -9,7 +9,7 @@ function modelAccessor(scope, element) {
return formatter['format'](scope.$eval(expr));
},
set: function(value) {
- scope.$eval(expr + '=' + toJson(formatter['parse'](value)));
+ scope.$tryEval(expr + '=' + toJson(formatter['parse'](value)), element);
}
};
}
@@ -112,7 +112,7 @@ function inputWidget(events, modelAccessor, viewAccessor, initValue) {
view = viewAccessor(scope, element),
action = element.attr('ng-action') || '',
value = view.get() || copy(initValue);
- if (isDefined(value)) model.set(value);
+ if (isUndefined(model.get()) && isDefined(value)) model.set(value);
this.$eval(element.attr('ng-init')||'');
element.bind(events, function(){
model.set(view.get());
@@ -127,6 +127,7 @@ function inputWidget(events, modelAccessor, viewAccessor, initValue) {
}
function inputWidgetSelector(element){
+ this.directives(true);
return INPUT_TYPE[lowercase(element[0].type)] || noop;
}
diff --git a/src/directives.js b/src/directives.js
index c54c89e9..291bea11 100644
--- a/src/directives.js
+++ b/src/directives.js
@@ -66,18 +66,21 @@ angularDirective("ng-bind-template", function(expression){
angularDirective("ng-bind-attr", function(expression){
return function(element){
this.$onEval(function(){
- foreach(this.$eval(expression), function(value, key){
- element.attr(key, compileBindTemplate(value).call(this));
+ foreach(this.$eval(expression), function(bindExp, key) {
+ var value = compileBindTemplate(bindExp).call(this);
+ if (key == 'disabled' && !toBoolean(value)) {
+ element.removeAttr('disabled');
+ } else {
+ element.attr(key, value);
+ }
}, this);
}, element);
};
});
-angularDirective("ng-non-bindable", function(){
- this.descend(false);
-});
+angularWidget("@ng-non-bindable", noop);
-angularDirective("ng-repeat", function(expression, element){
+angularWidget("@ng-repeat", function(expression, element){
element.removeAttr('ng-repeat');
element.replaceWith(this.comment("ng-repeat: " + expression));
var template = this.compile(element);
@@ -98,24 +101,28 @@ angularDirective("ng-repeat", function(expression, element){
valueIdent = match[3] || match[1];
keyIdent = match[2];
+ if (isUndefined(this.$eval(rhs))) this.$set(rhs, []);
+
var children = [], currentScope = this;
this.$onEval(function(){
var index = 0, childCount = children.length, childScope, lastElement = reference;
foreach(this.$tryEval(rhs, reference), function(value, key){
+ function assign(scope) {
+ scope[valueIdent] = value;
+ if (keyIdent) scope[keyIdent] = key;
+ }
if (index < childCount) {
// reuse existing child
- childScope = children[index];
+ assign(childScope = children[index]);
} else {
// grow children
- childScope = template(element.clone(), currentScope);
+ assign(childScope = template(element.clone(), currentScope));
lastElement.after(childScope.$element);
childScope.$index = index;
- childScope.$element.attr('ng-index', index);
+ childScope.$element.attr('ng-repeat-index', index);
childScope.$init();
children.push(childScope);
}
- childScope[valueIdent] = value;
- if (keyIdent) childScope[keyIdent] = key;
childScope.$eval();
lastElement = childScope.$element;
index ++;
@@ -126,7 +133,7 @@ angularDirective("ng-repeat", function(expression, element){
}
}, reference);
};
-}, {exclusive: true});
+});
angularDirective("ng-action", function(expression, element){
return function(element){
@@ -139,13 +146,16 @@ angularDirective("ng-action", function(expression, element){
});
angularDirective("ng-watch", function(expression, element){
- var match = expression.match(/^([^.]*):(.*)$/);
return function(element){
- if (!match) {
- throw "Expecting watch expression 'ident_to_watch: watch_statement' got '"
- + expression + "'";
- }
- this.$watch(match[1], match[2], element);
+ var self = this;
+ new Parser(expression).watch()({
+ scope:{get: self.$get, set: self.$set},
+ addListener:function(watch, exp){
+ self.$watch(watch, function(){
+ return exp({scope:{get: self.$get, set: self.$set}, state:self});
+ }, element);
+ }
+ });
};
});