mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-28 04:00:23 +00:00
smarter normalization of value on option, and htmlParser fixes
This commit is contained in:
parent
882f412d57
commit
46d690ff01
7 changed files with 63 additions and 42 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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,"<");
|
||||
return hiddenPre.innerText || hiddenPre.textContent;
|
||||
return hiddenPre.innerText || hiddenPre.textContent || '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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(){
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -475,7 +475,7 @@ describe("widget", function(){
|
|||
scope.$eval();
|
||||
|
||||
expect(scope.$element.text()).toBe('foobarC');
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue