aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/.jshintrc1
-rw-r--r--src/Angular.js22
-rw-r--r--src/ng/compile.js132
-rw-r--r--src/ng/directive/ngClass.js35
4 files changed, 93 insertions, 97 deletions
diff --git a/src/.jshintrc b/src/.jshintrc
index 2467d667..f32caa45 100644
--- a/src/.jshintrc
+++ b/src/.jshintrc
@@ -100,7 +100,6 @@
"assertNotHasOwnProperty": false,
"getter": false,
"getBlockElements": false,
- "tokenDifference": false,
/* AngularPublic.js */
"version": false,
diff --git a/src/Angular.js b/src/Angular.js
index b27f4b06..11222118 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -81,7 +81,6 @@
-assertNotHasOwnProperty,
-getter,
-getBlockElements,
- -tokenDifference
*/
@@ -1351,24 +1350,3 @@ function getBlockElements(block) {
return jqLite(elements);
}
-
-/**
- * Return the string difference between tokens of the original string compared to the old string
- * @param {str1} string original string value
- * @param {str2} string new string value
- */
-function tokenDifference(str1, str2) {
- var values = '',
- tokens1 = str1.split(/\s+/),
- tokens2 = str2.split(/\s+/);
-
- outer:
- for(var i=0;i<tokens1.length;i++) {
- var token = tokens1[i];
- for(var j=0;j<tokens2.length;j++) {
- if(token == tokens2[j]) continue outer;
- }
- values += (values.length > 0 ? ' ' : '') + token;
- }
- return values;
-}
diff --git a/src/ng/compile.js b/src/ng/compile.js
index ce3d0514..d977f173 100644
--- a/src/ng/compile.js
+++ b/src/ng/compile.js
@@ -673,6 +673,24 @@ function $CompileProvider($provide) {
},
/**
+ * @ngdoc function
+ * @name ng.$compile.directive.Attributes#$updateClass
+ * @methodOf ng.$compile.directive.Attributes
+ * @function
+ *
+ * @description
+ * Adds and removes the appropriate CSS class values to the element based on the difference
+ * between the new and old CSS class values (specified as newClasses and oldClasses).
+ *
+ * @param {string} newClasses The current CSS className value
+ * @param {string} oldClasses The former CSS className value
+ */
+ $updateClass : function(newClasses, oldClasses) {
+ this.$removeClass(tokenDifference(oldClasses, newClasses));
+ this.$addClass(tokenDifference(newClasses, oldClasses));
+ },
+
+ /**
* Set a normalized attribute on the element in a way such that all directives
* can share the attribute. This function properly handles boolean attributes.
* @param {string} key Normalized key. (ie ngAttribute)
@@ -682,59 +700,53 @@ function $CompileProvider($provide) {
* @param {string=} attrName Optional none normalized name. Defaults to key.
*/
$set: function(key, value, writeAttr, attrName) {
- //special case for class attribute addition + removal
- //so that class changes can tap into the animation
- //hooks provided by the $animate service
- if(key == 'class') {
- value = value || '';
- var current = this.$$element.attr('class') || '';
- this.$removeClass(tokenDifference(current, value));
- this.$addClass(tokenDifference(value, current));
- } else {
- var booleanKey = getBooleanAttrName(this.$$element[0], key),
- normalizedVal,
- nodeName;
+ // TODO: decide whether or not to throw an error if "class"
+ //is set through this function since it may cause $updateClass to
+ //become unstable.
- if (booleanKey) {
- this.$$element.prop(key, value);
- attrName = booleanKey;
- }
+ var booleanKey = getBooleanAttrName(this.$$element[0], key),
+ normalizedVal,
+ nodeName;
- this[key] = value;
+ if (booleanKey) {
+ this.$$element.prop(key, value);
+ attrName = booleanKey;
+ }
- // translate normalized key to actual key
- if (attrName) {
- this.$attr[key] = attrName;
- } else {
- attrName = this.$attr[key];
- if (!attrName) {
- this.$attr[key] = attrName = snake_case(key, '-');
- }
+ this[key] = value;
+
+ // translate normalized key to actual key
+ if (attrName) {
+ this.$attr[key] = attrName;
+ } else {
+ attrName = this.$attr[key];
+ if (!attrName) {
+ this.$attr[key] = attrName = snake_case(key, '-');
}
+ }
- nodeName = nodeName_(this.$$element);
-
- // sanitize a[href] and img[src] values
- if ((nodeName === 'A' && key === 'href') ||
- (nodeName === 'IMG' && key === 'src')) {
- // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
- if (!msie || msie >= 8 ) {
- normalizedVal = urlResolve(value).href;
- if (normalizedVal !== '') {
- if ((key === 'href' && !normalizedVal.match(aHrefSanitizationWhitelist)) ||
- (key === 'src' && !normalizedVal.match(imgSrcSanitizationWhitelist))) {
- this[key] = value = 'unsafe:' + normalizedVal;
- }
+ nodeName = nodeName_(this.$$element);
+
+ // sanitize a[href] and img[src] values
+ if ((nodeName === 'A' && key === 'href') ||
+ (nodeName === 'IMG' && key === 'src')) {
+ // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
+ if (!msie || msie >= 8 ) {
+ normalizedVal = urlResolve(value).href;
+ if (normalizedVal !== '') {
+ if ((key === 'href' && !normalizedVal.match(aHrefSanitizationWhitelist)) ||
+ (key === 'src' && !normalizedVal.match(imgSrcSanitizationWhitelist))) {
+ this[key] = value = 'unsafe:' + normalizedVal;
}
}
}
+ }
- if (writeAttr !== false) {
- if (value === null || value === undefined) {
- this.$$element.removeAttr(attrName);
- } else {
- this.$$element.attr(attrName, value);
- }
+ if (writeAttr !== false) {
+ if (value === null || value === undefined) {
+ this.$$element.removeAttr(attrName);
+ } else {
+ this.$$element.attr(attrName, value);
}
}
@@ -1816,9 +1828,19 @@ function $CompileProvider($provide) {
attr[name] = interpolateFn(scope);
($$observers[name] || ($$observers[name] = [])).$$inter = true;
(attr.$$observers && attr.$$observers[name].$$scope || scope).
- $watch(interpolateFn, function interpolateFnWatchAction(value) {
- attr.$set(name, value);
- });
+ $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
+ //special case for class attribute addition + removal
+ //so that class changes can tap into the animation
+ //hooks provided by the $animate service. Be sure to
+ //skip animations when the first digest occurs (when
+ //both the new and the old values are the same) since
+ //the CSS classes are the non-interpolated values
+ if(name === 'class' && newValue != oldValue) {
+ attr.$updateClass(newValue, oldValue);
+ } else {
+ attr.$set(name, newValue);
+ }
+ });
}
};
}
@@ -1958,3 +1980,19 @@ function directiveLinkingFn(
/* Element */ rootElement,
/* function(Function) */ boundTranscludeFn
){}
+
+function tokenDifference(str1, str2) {
+ var values = '',
+ tokens1 = str1.split(/\s+/),
+ tokens2 = str2.split(/\s+/);
+
+ outer:
+ for(var i = 0; i < tokens1.length; i++) {
+ var token = tokens1[i];
+ for(var j = 0; j < tokens2.length; j++) {
+ if(token == tokens2[j]) continue outer;
+ }
+ values += (values.length > 0 ? ' ' : '') + token;
+ }
+ return values;
+}
diff --git a/src/ng/directive/ngClass.js b/src/ng/directive/ngClass.js
index 10ef7fd1..21316c57 100644
--- a/src/ng/directive/ngClass.js
+++ b/src/ng/directive/ngClass.js
@@ -20,11 +20,10 @@ function classDirective(name, selector) {
// jshint bitwise: false
var mod = $index & 1;
if (mod !== old$index & 1) {
- if (mod === selector) {
- addClass(flattenClasses(scope.$eval(attr[name])));
- } else {
- removeClass(flattenClasses(scope.$eval(attr[name])));
- }
+ var classes = flattenClasses(scope.$eval(attr[name]));
+ mod === selector ?
+ attr.$addClass(classes) :
+ attr.$removeClass(classes);
}
});
}
@@ -33,34 +32,16 @@ function classDirective(name, selector) {
function ngClassWatchAction(newVal) {
if (selector === true || scope.$index % 2 === selector) {
var newClasses = flattenClasses(newVal || '');
- if (oldVal && !equals(newVal,oldVal)) {
- var oldClasses = flattenClasses(oldVal);
- var toRemove = tokenDifference(oldClasses, newClasses);
- if(toRemove.length > 0) {
- removeClass(toRemove);
- }
-
- var toAdd = tokenDifference(newClasses, oldClasses);
- if(toAdd.length > 0) {
- addClass(toAdd);
- }
- } else {
- addClass(newClasses);
+ if(!oldVal) {
+ attr.$addClass(newClasses);
+ } else if(!equals(newVal,oldVal)) {
+ attr.$updateClass(newClasses, flattenClasses(oldVal));
}
}
oldVal = copy(newVal);
}
- function removeClass(classVal) {
- attr.$removeClass(classVal);
- }
-
-
- function addClass(classVal) {
- attr.$addClass(classVal);
- }
-
function flattenClasses(classVal) {
if(isArray(classVal)) {
return classVal.join(' ');