diff --git a/CHANGELOG b/CHANGELOG index ee5c7053e..09e99c83b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Ensure `Element#update` works with string content that includes a LINK tag in Internet Explorer. [#264 state:resolved] (Tobias H. Michaelsen, Andrew Dupont) + * Treat a 304 HTTP status as a successful response. [#331 state:resolved] (Kenneth Kin Lum, Andrew Dupont) * Handle sparse arrays properly in `Array#_each` to match behavior with browsers' built-in `Array#forEach` (and ES5). [#790 state:resolved] (Andriy Tyurnikov, Yaffle, Andrew Dupont) diff --git a/src/dom/dom.js b/src/dom/dom.js index 962b39637..713826f32 100644 --- a/src/dom/dom.js +++ b/src/dom/dom.js @@ -568,6 +568,21 @@ Element.Methods = { return true; } })(); + + var LINK_ELEMENT_INNERHTML_BUGGY = (function() { + try { + var el = document.createElement('div'); + el.innerHTML = ""; + var isBuggy = (el.childNodes.length === 0); + el = null; + return isBuggy; + } catch(e) { + return true; + } + })(); + + var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY || + TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY; var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { var s = document.createElement("script"), @@ -582,6 +597,7 @@ Element.Methods = { s = null; return isBuggy; })(); + function update(element, content) { element = $(element); @@ -610,7 +626,7 @@ Element.Methods = { return element; } - if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) { + if (ANY_INNERHTML_BUGGY) { if (tagName in Element._insertionTranslations.tags) { while (element.firstChild) { element.removeChild(element.firstChild); @@ -619,6 +635,16 @@ Element.Methods = { .each(function(node) { element.appendChild(node) }); + } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf(' -1) { + // IE barfs when inserting a string that beings with a LINK + // element. The workaround is to add any content to the beginning + // of the string; we'll be inserting a text node (see + // Element._getContentFromAnonymousElement below). + while (element.firstChild) { + element.removeChild(element.firstChild); + } + var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true); + nodes.each(function(node) { element.appendChild(node) }); } else { element.innerHTML = content.stripScripts(); @@ -2966,11 +2992,22 @@ Element._returnOffset = function(l, t) { return result; }; -Element._getContentFromAnonymousElement = function(tagName, html) { +Element._getContentFromAnonymousElement = function(tagName, html, force) { var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; - if (t) { - div.innerHTML = t[0] + html + t[1]; + + var workaround = false; + if (t) workaround = true; + else if (force) { + workaround = true; + t = ['', '', 0]; + } + + if (workaround) { + // Adding a text node to the beginning of the string (then removing it) + // fixes an issue in Internet Explorer. See Element#update above. + div.innerHTML = ' ' + t[0] + html + t[1]; + div.removeChild(div.firstChild); for (var i = t[2]; i--; ) { div = div.firstChild; } diff --git a/test/unit/dom_test.js b/test/unit/dom_test.js index 82bf714e6..db4f4d12d 100644 --- a/test/unit/dom_test.js +++ b/test/unit/dom_test.js @@ -362,6 +362,23 @@ new Test.Unit.Runner({ select.update(''); this.assertEqual('option 4', select.getValue()); }, + + testElementUpdateWithLinkTag: function() { + var div = new Element('div'); + div.update(''); + this.assertEqual(1, div.childNodes.length); + var link = div.down('link'); + this.assert(link); + this.assert(link.rel === 'stylesheet'); + + div.update('

') + this.assertEqual(1, div.childNodes.length); + this.assertEqual(1, div.firstChild.childNodes.length); + + var link = div.down('link'); + this.assert(link); + this.assert(link.rel === 'stylesheet'); + }, testElementUpdateWithDOMNode: function() { $('testdiv').update(new Element('div').insert('bla'));