aboutsummaryrefslogtreecommitdiffstats
path: root/src/directives.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/directives.js')
-rw-r--r--src/directives.js308
1 files changed, 155 insertions, 153 deletions
diff --git a/src/directives.js b/src/directives.js
index eb35addb..dc0a986f 100644
--- a/src/directives.js
+++ b/src/directives.js
@@ -58,10 +58,14 @@
</doc:scenario>
</doc:example>
*/
-angularDirective("ng:init", function(expression){
- return function(element){
- this.$eval(expression);
- };
+var ngInitDirective = valueFn({
+ compile: function() {
+ return {
+ pre: function(scope, element, attrs) {
+ scope.$eval(attrs.ngInit);
+ }
+ }
+ }
});
/**
@@ -158,16 +162,24 @@ angularDirective("ng:init", function(expression){
</doc:scenario>
</doc:example>
*/
-angularDirective("ng:controller", function(expression) {
- this.scope(true);
- return ['$controller', '$window', function($controller, $window) {
- var scope = this,
- Controller = getter(scope, expression, true) || getter($window, expression, true);
-
- assertArgFn(Controller, expression);
- $controller(Controller, scope);
- }];
-});
+var ngControllerDirective = ['$controller', '$window', function($controller, $window) {
+ return {
+ scope: true,
+ compile: function() {
+ return {
+ pre: function(scope, element, attr) {
+ var expression = attr.ngController,
+ Controller = getter(scope, expression, true) || getter($window, expression, true);
+
+ assertArgFn(Controller, expression);
+ $controller(Controller, scope);
+ }
+ };
+ }
+ }
+}];
+
+
/**
* @ngdoc directive
@@ -208,55 +220,30 @@ angularDirective("ng:controller", function(expression) {
</doc:scenario>
</doc:example>
*/
-angularDirective("ng:bind", function(expression, element){
- element.addClass('ng-binding');
- return ['$exceptionHandler', '$parse', '$element', function($exceptionHandler, $parse, element) {
- var exprFn = $parse(expression),
- lastValue = Number.NaN,
- scope = this;
+var ngBindDirective = valueFn(function(scope, element, attr) {
+ element.addClass('ng-binding').data('$binding', attr.ngBind);
+ scope.$watch(attr.ngBind, function(value) {
+ element.text(value == undefined ? '' : value);
+ });
+});
- scope.$watch(function() {
- // TODO(misko): remove error handling https://github.com/angular/angular.js/issues/347
- var value, html, isHtml, isDomElement,
- hadOwnElement = scope.hasOwnProperty('$element'),
- oldElement = scope.$element;
- // TODO(misko): get rid of $element https://github.com/angular/angular.js/issues/348
- scope.$element = element;
- try {
- value = exprFn(scope);
- // If we are HTML than save the raw HTML data so that we don't recompute sanitization since
- // it is expensive.
- // TODO(misko): turn this into a more generic way to compute this
- if ((isHtml = (value instanceof HTML)))
- value = (html = value).html;
- if (lastValue === value) return;
- isDomElement = isElement(value);
- if (!isHtml && !isDomElement && isObject(value)) {
- value = toJson(value, true);
- }
- if (value != lastValue) {
- lastValue = value;
- if (isHtml) {
- element.html(html.get());
- } else if (isDomElement) {
- element.html('');
- element.append(value);
- } else {
- element.text(value == undefined ? '' : value);
- }
- }
- } catch (e) {
- $exceptionHandler(e);
- } finally {
- if (hadOwnElement) {
- scope.$element = oldElement;
- } else {
- delete scope.$element;
- }
+var ngBindHtmlUnsafeDirective = valueFn(function(scope, element, attr) {
+ element.addClass('ng-binding').data('$binding', attr.ngBindHtmlUnsafe);
+ scope.$watch(attr.ngBindHtmlUnsafe, function(value) {
+ element.html(value == undefined ? '' : value);
+ });
+});
+
+var ngBindHtmlDirective = ['$sanitize', function($sanitize) {
+ return function(scope, element, attr) {
+ element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
+ scope.$watch(attr.ngBindHtml, function(value) {
+ if (value = $sanitize(value)) {
+ element.html(value);
}
});
- }];
-});
+ }
+}];
/**
@@ -292,32 +279,29 @@ angularDirective("ng:bind", function(expression, element){
</doc:source>
<doc:scenario>
it('should check ng:bind', function() {
- expect(using('.doc-example-live').binding('{{salutation}} {{name}}')).
- toBe('Hello World!');
+ expect(using('.doc-example-live').binding('salutation')).
+ toBe('Hello');
+ expect(using('.doc-example-live').binding('name')).
+ toBe('World');
using('.doc-example-live').input('salutation').enter('Greetings');
using('.doc-example-live').input('name').enter('user');
- expect(using('.doc-example-live').binding('{{salutation}} {{name}}')).
- toBe('Greetings user!');
+ expect(using('.doc-example-live').binding('salutation')).
+ toBe('Greetings');
+ expect(using('.doc-example-live').binding('name')).
+ toBe('user');
});
</doc:scenario>
</doc:example>
*/
-angularDirective("ng:bind-template", function(expression, element){
- element.addClass('ng-binding');
- var templateFn = compileBindTemplate(expression);
- return function(element) {
- var lastValue,
- scope = this;
-
- scope.$watch(function() {
- var value = templateFn(scope, element, true);
- if (value != lastValue) {
- element.text(value);
- lastValue = value;
- }
+var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
+ return function(scope, element, attr) {
+ var interpolateFn = $interpolate(attr.ngBindTemplate);
+ element.addClass('ng-binding').data('$binding', interpolateFn);
+ scope.$watch(interpolateFn, function(value) {
+ element.text(value);
});
- };
-});
+ }
+}];
/**
* @ngdoc directive
@@ -392,23 +376,25 @@ angularDirective("ng:bind-template", function(expression, element){
</doc:scenario>
</doc:example>
*/
-angularDirective("ng:bind-attr", function(expression){
- return function(element){
- var lastValue = {},
- scope = this;
+var ngBindAttrDirective = ['$interpolate', function($interpolate) {
+ return function(scope, element, attr) {
+ var lastValue = {};
+ var interpolateFns = {};
scope.$watch(function() {
- var values = scope.$eval(expression);
+ var values = scope.$eval(attr.ngBindAttr);
for(var key in values) {
- var value = compileBindTemplate(values[key])(scope, element);
+ var exp = values[key],
+ fn = (interpolateFns[exp] ||
+ (interpolateFns[values[key]] = $interpolate(exp))),
+ value = fn(scope);
if (lastValue[key] !== value) {
- lastValue[key] = value;
- element.attr(key, BOOLEAN_ATTR[lowercase(key)] ? toBoolean(value) : value);
+ attr.$set(key, lastValue[key] = value);
}
}
});
- };
-});
+ }
+}];
/**
@@ -448,19 +434,33 @@ angularDirective("ng:bind-attr", function(expression){
*
* TODO: maybe we should consider allowing users to control event propagation in the future.
*/
-angularDirective("ng:click", function(expression, element){
- return function(element){
- var self = this;
- element.bind('click', function(event){
- self.$apply(expression);
+var ngEventDirectives = {};
+forEach('click dblclick mousedown mouseup mouseover mousemove'.split(' '), function(name) {
+ var directiveName = camelCase('ng-' + name);
+ ngEventDirectives[directiveName] = valueFn(function(scope, element, attr) {
+ element.bind(lowercase(name), function(event) {
+ scope.$apply(attr[directiveName]);
event.stopPropagation();
});
- };
+ });
});
/**
* @ngdoc directive
+ * @name angular.directive.ng:dblclick
+ *
+ * @description
+ * The ng:dblclick allows you to specify custom behavior when
+ * element is double-clicked.
+ *
+ * @element ANY
+ * @param {expression} expression {@link guide/dev_guide.expressions Expression} to evaluate upon
+ * double-click.
+ */
+
+/**
+ * @ngdoc directive
* @name angular.directive.ng:submit
*
* @description
@@ -496,48 +496,42 @@ angularDirective("ng:click", function(expression, element){
</doc:source>
<doc:scenario>
it('should check ng:submit', function() {
- expect(binding('list')).toBe('list=[]');
+ expect(binding('list')).toBe('[]');
element('.doc-example-live #submit').click();
- expect(binding('list')).toBe('list=["hello"]');
+ expect(binding('list')).toBe('["hello"]');
expect(input('text').val()).toBe('');
});
it('should ignore empty strings', function() {
- expect(binding('list')).toBe('list=[]');
+ expect(binding('list')).toBe('[]');
element('.doc-example-live #submit').click();
element('.doc-example-live #submit').click();
- expect(binding('list')).toBe('list=["hello"]');
+ expect(binding('list')).toBe('["hello"]');
});
</doc:scenario>
</doc:example>
*/
-angularDirective("ng:submit", function(expression, element) {
- return function(element) {
- var self = this;
- element.bind('submit', function() {
- self.$apply(expression);
- });
- };
+var ngSubmitDirective = valueFn(function(scope, element, attrs) {
+ element.bind('submit', function() {
+ scope.$apply(attrs.ngSubmit);
+ });
});
-function ngClass(selector) {
- return function(expression, element) {
- return function(element) {
- var scope = this;
- scope.$watch(expression, function(newVal, oldVal) {
- if (selector(scope.$index)) {
- if (oldVal && (newVal !== oldVal)) {
- if (isObject(oldVal) && !isArray(oldVal))
- oldVal = map(oldVal, function(v, k) { if (v) return k });
- element.removeClass(isArray(oldVal) ? oldVal.join(' ') : oldVal);
- }
- if (isObject(newVal) && !isArray(newVal))
+function classDirective(name, selector) {
+ name = 'ngClass' + name;
+ return valueFn(function(scope, element, attr) {
+ scope.$watch(attr[name], function(newVal, oldVal) {
+ if (selector === true || scope.$index % 2 === selector) {
+ if (oldVal && (newVal !== oldVal)) {
+ if (isObject(oldVal) && !isArray(oldVal))
+ oldVal = map(oldVal, function(v, k) { if (v) return k });
+ element.removeClass(isArray(oldVal) ? oldVal.join(' ') : oldVal);
+ }
+ if (isObject(newVal) && !isArray(newVal))
newVal = map(newVal, function(v, k) { if (v) return k });
- if (newVal) element.addClass(isArray(newVal) ? newVal.join(' ') : newVal);
- }
- });
- };
- };
+ if (newVal) element.addClass(isArray(newVal) ? newVal.join(' ') : newVal); }
+ });
+ });
}
/**
@@ -584,7 +578,7 @@ function ngClass(selector) {
</doc:scenario>
</doc:example>
*/
-angularDirective("ng:class", ngClass(function() {return true;}));
+var ngClassDirective = classDirective('', true);
/**
* @ngdoc directive
@@ -624,7 +618,7 @@ angularDirective("ng:class", ngClass(function() {return true;}));
</doc:scenario>
</doc:example>
*/
-angularDirective("ng:class-odd", ngClass(function(i){return i % 2 === 0;}));
+var ngClassOddDirective = classDirective('Odd', 0);
/**
* @ngdoc directive
@@ -663,7 +657,7 @@ angularDirective("ng:class-odd", ngClass(function(i){return i % 2 === 0;}));
</doc:scenario>
</doc:example>
*/
-angularDirective("ng:class-even", ngClass(function(i){return i % 2 === 1;}));
+var ngClassEvenDirective = classDirective('Even', 1);
/**
* @ngdoc directive
@@ -697,13 +691,11 @@ angularDirective("ng:class-even", ngClass(function(i){return i % 2 === 1;}));
</doc:scenario>
</doc:example>
*/
-angularDirective("ng:show", function(expression, element){
- return function(element) {
- var scope = this;
- scope.$watch(expression, function(value) {
- element.css('display', toBoolean(value) ? '' : 'none');
- });
- };
+//TODO(misko): refactor to remove element from the DOM
+var ngShowDirective = valueFn(function(scope, element, attr){
+ scope.$watch(attr.ngShow, function(value){
+ element.css('display', toBoolean(value) ? '' : 'none');
+ });
});
/**
@@ -738,13 +730,11 @@ angularDirective("ng:show", function(expression, element){
</doc:scenario>
</doc:example>
*/
-angularDirective("ng:hide", function(expression, element){
- return function(element) {
- var scope = this;
- scope.$watch(expression, function(value) {
- element.css('display', toBoolean(value) ? 'none' : '');
- });
- };
+//TODO(misko): refactor to remove element from the DOM
+var ngHideDirective = valueFn(function(scope, element, attr){
+ scope.$watch(attr.ngHide, function(value){
+ element.css('display', toBoolean(value) ? 'none' : '');
+ });
});
/**
@@ -779,16 +769,13 @@ angularDirective("ng:hide", function(expression, element){
</doc:scenario>
</doc:example>
*/
-angularDirective("ng:style", function(expression, element) {
- return function(element) {
- var scope = this;
- scope.$watch(expression, function(newStyles, oldStyles) {
- if (oldStyles && (newStyles !== oldStyles)) {
- forEach(oldStyles, function(val, style) { element.css(style, '');});
- }
- if (newStyles) element.css(newStyles);
- });
- };
+var ngStyleDirective = valueFn(function(scope, element, attr) {
+ scope.$watch(attr.ngStyle, function(newStyles, oldStyles) {
+ if (oldStyles && (newStyles !== oldStyles)) {
+ forEach(oldStyles, function(val, style) { element.css(style, '');});
+ }
+ if (newStyles) element.css(newStyles);
+ });
});
@@ -845,7 +832,22 @@ angularDirective("ng:style", function(expression, element) {
</doc:example>
*
*/
-angularDirective("ng:cloak", function(expression, element) {
- element.removeAttr('ng:cloak');
- element.removeClass('ng-cloak');
+var ngCloakDirective = valueFn({
+ compile: function(element, attr) {
+ attr.$set(attr.$attr.ngCloak, undefined);
+ element.removeClass('ng-cloak');
+ }
});
+
+function ngAttributeAliasDirective(propName, attrName) {
+ ngAttributeAliasDirectives[camelCase('ng-' + attrName)] = ['$interpolate', function($interpolate) {
+ return function(scope, element, attr) {
+ scope.$watch($interpolate(attr[camelCase('ng-' + attrName)]), function(value) {
+ attr.$set(attrName, value);
+ });
+ }
+ }];
+}
+var ngAttributeAliasDirectives = {};
+forEach(BOOLEAN_ATTR, ngAttributeAliasDirective);
+ngAttributeAliasDirective(null, 'src');