aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMisko Hevery2011-02-03 16:35:51 -0800
committerMisko Hevery2011-02-04 13:44:22 -0800
commit46d690ff0188836688811dda9af1b99c44750c48 (patch)
treef2253031ba3c8574ec93f03a18bb9fb2667aef51
parent882f412d578e4f01394847fa5fde21b6b4096de2 (diff)
downloadangular.js-46d690ff0188836688811dda9af1b99c44750c48.tar.bz2
smarter normalization of value on option, and htmlParser fixes
-rw-r--r--src/Angular.js2
-rw-r--r--src/markups.js33
-rw-r--r--src/sanitizer.js35
-rw-r--r--test/markupSpec.js14
-rw-r--r--test/sanitizerSpec.js15
-rw-r--r--test/testabilityPatch.js4
-rw-r--r--test/widgetsSpec.js2
7 files changed, 63 insertions, 42 deletions
diff --git a/src/Angular.js b/src/Angular.js
index de2de30d..aea1dd3f 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -719,7 +719,7 @@ function elementError(element, type, error) {
element[0]['$NG_ERROR'] = error;
if (error) {
element.addClass(type);
- element.attr(type, error);
+ element.attr(type, error.message || error);
} else {
element.removeClass(type);
element.removeAttr(type);
diff --git a/src/markups.js b/src/markups.js
index 0aa7170e..89cc0d05 100644
--- a/src/markups.js
+++ b/src/markups.js
@@ -57,21 +57,26 @@ angularTextMarkup('{{}}', function(text, textNode, parentElement) {
}
});
-// TODO: this should be widget not a markup
-angularTextMarkup('OPTION', function(text, textNode, parentElement){
- if (nodeName_(parentElement) == "OPTION") {
- var select = jqLite('<select>');
- select.append(parentElement.clone());
- htmlParser(select.html(), {
- start: function(tag, attrs) {
- if (isUndefined(attrs.value)) {
- parentElement.attr('value', text);
+/**
+ * This tries to normalize the behavior of value attribute across browsers. If value attribute is
+ * not specified, then specify it to be that of the text.
+ */
+angularTextMarkup('option', function(text, textNode, parentElement){
+ if (lowercase(nodeName_(parentElement)) == 'option') {
+ if (msie <= 7) {
+ // In IE7 The issue is that there is no way to see if the value was specified hence
+ // we have to resort to parsing HTML;
+ htmlParser(parentElement[0].outerHTML, {
+ start: function(tag, attrs) {
+ if (isUndefined(attrs.value)) {
+ parentElement.attr('value', text);
+ }
}
- },
- chars: noop,
- end: noop,
- comment: noop
- });
+ });
+ } else if (parentElement[0].getAttribute('value') == null) {
+ // jQuery does normalization on 'value' so we have to bypass it.
+ parentElement.attr('value', text);
+ }
}
});
diff --git a/src/sanitizer.js b/src/sanitizer.js
index 8f4b87a6..7bd26455 100644
--- a/src/sanitizer.js
+++ b/src/sanitizer.js
@@ -42,15 +42,12 @@ var closeSelfElements = makeMap("colgroup,dd,dt,li,p,td,tfoot,th,thead,tr");
var specialElements = makeMap("script,style");
var validElements = extend({}, emptyElements, blockElements, inlineElements, closeSelfElements);
-//see: http://www.w3.org/TR/html4/index/attributes.html
-//Attributes that have their values filled in disabled="disabled"
-var fillAttrs = makeMap("compact,ismap,nohref,nowrap");
//Attributes that have href and hence need to be sanitized
var uriAttrs = makeMap("background,href,longdesc,src,usemap");
-var validAttrs = extend({}, fillAttrs, uriAttrs, makeMap(
+var validAttrs = extend({}, uriAttrs, makeMap(
'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'+
- 'color,cols,colspan,coords,dir,face,headers,height,hreflang,hspace,'+
- 'lang,language,rel,rev,rows,rowspan,rules,'+
+ 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'+
+ 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'+
'scope,scrolling,shape,span,start,summary,target,title,type,'+
'valign,value,vspace,width'));
@@ -81,8 +78,7 @@ function htmlParser( html, handler ) {
index = html.indexOf("-->");
if ( index >= 0 ) {
- if ( handler.comment )
- handler.comment( html.substring( 4, index ) );
+ if (handler.comment) handler.comment( html.substring( 4, index ) );
html = html.substring( index + 3 );
chars = false;
}
@@ -114,7 +110,7 @@ function htmlParser( html, handler ) {
var text = index < 0 ? html : html.substring( 0, index );
html = index < 0 ? "" : html.substring( index );
- handler.chars( decodeEntities(text) );
+ if (handler.chars) handler.chars( decodeEntities(text) );
}
} else {
@@ -123,7 +119,7 @@ function htmlParser( html, handler ) {
replace(COMMENT_REGEXP, "$1").
replace(CDATA_REGEXP, "$1");
- handler.chars( decodeEntities(text) );
+ if (handler.chars) handler.chars( decodeEntities(text) );
return "";
});
@@ -159,16 +155,15 @@ function htmlParser( html, handler ) {
var attrs = {};
- rest.replace(ATTR_REGEXP, function(match, name) {
- var value = arguments[2] ? arguments[2] :
- arguments[3] ? arguments[3] :
- arguments[4] ? arguments[4] :
- fillAttrs[name] ? name : "";
+ rest.replace(ATTR_REGEXP, function(match, name, doubleQuotedValue, singleQoutedValue, unqoutedValue) {
+ var value = doubleQuotedValue
+ || singleQoutedValue
+ || unqoutedValue
+ || '';
- attrs[name] = decodeEntities(value); //value.replace(/(^|[^\\])"/g, '$1\\\"') //"
+ attrs[name] = decodeEntities(value);
});
-
- handler.start( tagName, attrs, unary );
+ if (handler.start) handler.start( tagName, attrs, unary );
}
function parseEndTag( tag, tagName ) {
@@ -183,7 +178,7 @@ function htmlParser( html, handler ) {
if ( pos >= 0 ) {
// Close all the open elements, up the stack
for ( i = stack.length - 1; i >= pos; i-- )
- handler.end( stack[ i ] );
+ if (handler.end) handler.end( stack[ i ] );
// Remove the open elements from the stack
stack.length = pos;
@@ -210,7 +205,7 @@ function makeMap(str){
var hiddenPre=document.createElement("pre");
function decodeEntities(value) {
hiddenPre.innerHTML=value.replace(/</g,"&lt;");
- return hiddenPre.innerText || hiddenPre.textContent;
+ return hiddenPre.innerText || hiddenPre.textContent || '';
}
/**
diff --git a/test/markupSpec.js b/test/markupSpec.js
index f629378d..16efba55 100644
--- a/test/markupSpec.js
+++ b/test/markupSpec.js
@@ -46,10 +46,18 @@ describe("markups", function(){
this.addMatchers({
toHaveValue: function(expected){
this.message = function(){
- return 'Expected "' + sortedHtml(this.actual) + '" to have value="' + expected + '".';
+ return 'Expected "' + this.actual.html() + '" to have value="' + expected + '".';
};
- return this.actual.html().indexOf('value="' + expected + '"') != -1;
+ var value;
+ htmlParser(this.actual.html(), {
+ start:function(tag, attrs){
+ value = attrs.value;
+ },
+ end:noop,
+ chars:noop
+ });
+ return trim(value) == trim(expected);
}
});
});
@@ -70,6 +78,8 @@ describe("markups", function(){
});
it('should set value even if self closing HTML', function(){
+ // IE removes the \n from option, which makes this test pointless
+ if (msie) return;
compile('<select name="x"><option>\n</option></select>');
expect(element).toHaveValue('\n');
});
diff --git a/test/sanitizerSpec.js b/test/sanitizerSpec.js
index 7158fbee..787ce84c 100644
--- a/test/sanitizerSpec.js
+++ b/test/sanitizerSpec.js
@@ -14,6 +14,11 @@ describe('HTML', function(){
attrs: attrs,
unary: unary
};
+ // Since different browsers handle newlines differenttly we trim
+ // so that it is easier to write tests.
+ forEach(attrs, function(value, key){
+ attrs[key] = trim(value);
+ });
},
chars: function(text_){
text = text_;
@@ -38,16 +43,22 @@ describe('HTML', function(){
it('should parse newlines in attributes', function(){
htmlParser('<tag attr="\nvalue\n">text</tag>', handler);
- expect(start).toEqual({tag:'tag', attrs:{attr:'\nvalue\n'}, unary:false});
+ expect(start).toEqual({tag:'tag', attrs:{attr:'value'}, unary:false});
expect(text).toEqual('text');
});
it('should parse namespace', function(){
htmlParser('<ns:t-a-g ns:a-t-t-r="\nvalue\n">text</ns:t-a-g>', handler);
- expect(start).toEqual({tag:'ns:t-a-g', attrs:{'ns:a-t-t-r':'\nvalue\n'}, unary:false});
+ expect(start).toEqual({tag:'ns:t-a-g', attrs:{'ns:a-t-t-r':'value'}, unary:false});
expect(text).toEqual('text');
});
+ it('should parse empty value attribute of node', function(){
+ htmlParser('<OPTION selected value="">abc</OPTION>', handler);
+ expect(start).toEqual({tag:'option', attrs:{selected:'', value:''}, unary:false});
+ expect(text).toEqual('abc');
+ });
+
});
it('should echo html', function(){
diff --git a/test/testabilityPatch.js b/test/testabilityPatch.js
index 76033ab2..e0086b8a 100644
--- a/test/testabilityPatch.js
+++ b/test/testabilityPatch.js
@@ -70,7 +70,7 @@ beforeEach(function(){
expected = toJson(this.actual);
}
return "Expected " + expected + " to be an Error with message " + toJson(message);
- }
+ };
return this.actual.name == 'Error' && this.actual.message == message;
},
@@ -83,7 +83,7 @@ beforeEach(function(){
expected = toJson(this.actual);
}
return "Expected " + expected + " to match an Error with message " + toJson(messageRegexp);
- }
+ };
return this.actual.name == 'Error' && messageRegexp.test(this.actual.message);
}
});
diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js
index ee339e89..6bff5a36 100644
--- a/test/widgetsSpec.js
+++ b/test/widgetsSpec.js
@@ -475,7 +475,7 @@ describe("widget", function(){
scope.$eval();
expect(scope.$element.text()).toBe('foobarC');
- })
+ });
});