Skip to content

Commit d782231

Browse files
gonzaloruizdevillaGonzalo Ruiz de Villa
authored and
Gonzalo Ruiz de Villa
committed
fix(jqLite): IE8 no longer replaces link text content with href mailto value
fixes angular#1949 IE bug: http://webbugtrack.blogspot.com.es/2008/07/bug-140-changing-mailto-links-error-in.html Only happens when: 1. content has an @ but not ends with it. Regexp: /.*\S.*@.+/ 2. href new value is like a URI or email (more or less) Regexp: /^((ftp|https?):\/\/|mailto:|.*@.+)/ To prevent IE from replacing the text content, the text nodes must be detached before setting the href value and reattached afterwards. Signed-off-by: Gonzalo Ruiz de Villa <gonzaloruizdevilla@gmail.com>
1 parent 649b892 commit d782231

File tree

2 files changed

+64
-2
lines changed

2 files changed

+64
-2
lines changed

src/jqLite.js

+35-2
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,23 @@ function getBooleanAttrName(element, name) {
369369
return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
370370
}
371371

372+
var IE_SPECIFIC_SET_ATTRIBUTE_CONTENT_PATTERN = /.*\S.*@.+/;
373+
var IE_SPECIFIC_SET_ATTRIBUTE_VALUE_PATTERN = /^((ftp|https?):\/\/|mailto:|.*@.+)/;
374+
function useIESpecificSetAttribute(element, name, value){
375+
//when setting href value of a link with a text that contains a word with
376+
//the pattern above will replace the content with the href value
377+
//if the href value is URL like (pattern above)
378+
var linkElement;
379+
380+
return msie <= 8
381+
&& element.nodeName === "A"
382+
&& name === "href"
383+
&& IE_SPECIFIC_SET_ATTRIBUTE_VALUE_PATTERN.test(value)
384+
&& (linkElement = angular.element(element))
385+
&& linkElement.children().length === 0
386+
&& IE_SPECIFIC_SET_ATTRIBUTE_CONTENT_PATTERN.test(linkElement.text());
387+
}
388+
372389
forEach({
373390
data: JQLiteData,
374391
inheritedData: JQLiteInheritedData,
@@ -415,7 +432,9 @@ forEach({
415432
},
416433

417434
attr: function(element, name, value){
418-
var lowercasedName = lowercase(name);
435+
var textNodes,
436+
lowercasedName = lowercase(name);
437+
419438
if (BOOLEAN_ATTR[lowercasedName]) {
420439
if (isDefined(value)) {
421440
if (!!value) {
@@ -432,7 +451,21 @@ forEach({
432451
: undefined;
433452
}
434453
} else if (isDefined(value)) {
435-
element.setAttribute(name, value);
454+
// IE7 and IE8 in some conditions replaces links text content with href
455+
// value. To prevent this, content must be detached and attached after setting the new
456+
// href value
457+
if (useIESpecificSetAttribute(element, lowercasedName, value)) {
458+
textNodes = [];
459+
while(element.firstChild){
460+
textNodes.push(element.removeChild(element.firstChild));
461+
}
462+
element.setAttribute(name, value);
463+
while (textNodes.length) {
464+
element.appendChild(textNodes.shift());
465+
}
466+
} else {
467+
element.setAttribute(name, value);
468+
}
436469
} else if (element.getAttribute) {
437470
// the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
438471
// some elements (e.g. Document) don't have get attribute, so return undefined

test/jqLiteSpec.js

+29
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,35 @@ describe('jqLite', function() {
406406
expect(elm.attr('readOnly')).toBeUndefined();
407407
expect(elm.attr('disabled')).toBeUndefined();
408408
});
409+
410+
it('should prevent IE for changing text content when setting attribute', function(){
411+
var unchanged = true,
412+
values = ["http:/","http://","https://","ftp://","mailto:","mailto","@","a@b"],
413+
contents = [
414+
"text with @arroba starting word",
415+
"text with @ arroba starting word",
416+
"text with @",
417+
"text with (space at end) @ ",
418+
"@ empty before",
419+
" @ space before",
420+
"- @ dash before",
421+
"\n @ line feed before"
422+
];
423+
424+
function testValueWithTextContent(value, textContent){
425+
var link = angular.element("<a>" + textContent + "</a>")
426+
linkText = link.text();
427+
link.attr("href", value);
428+
unchanged = unchanged && (linkText == link.text());
429+
}
430+
431+
forEach(values, function (value) {
432+
forEach(contents, function (content) {
433+
testValueWithTextContent(value, content);
434+
});
435+
});
436+
expect(unchanged).toBe(true);
437+
});
409438
});
410439

411440

0 commit comments

Comments
 (0)