Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Efficient outerHTML polyfill that doesn't use cloneNode(true)
/*
* outerHTML.js
* Cross-browser full HTMLElement.outerHTML implementation.
*
* 2011-11-14
*
* By Eli Grey, http://eligrey.com
* Public Domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
if (typeof document !== "undefined" && !("outerHTML" in document.createElementNS("http://www.w3.org/1999/xhtml", "_"))) {
(function(view) {
"use strict";
var
container = document.createElementNS("http://www.w3.org/1999/xhtml", "_")
, elem_proto = (view.HTMLElement || view.Element).prototype
, xml_serializer = new XMLSerializer
, outerHTML_getter = function() {
var
node = this
, html
;
if (document.xmlVersion) {
return xml_serializer.serializeToString(node);
} else {
container.appendChild(node.cloneNode(false));
html = container.innerHTML.replace("><", ">" + node.innerHTML + "<");
container.innerHTML = "";
return html;
}
}
, outerHTML_setter = function(html) {
var
node = this
, parent = node.parentNode
, child
;
if (parent === null) {
DOMException.code = DOMException.NOT_FOUND_ERR;
throw DOMException;
}
container.innerHTML = html;
while ((child = container.firstChild)) {
parent.insertBefore(child, node);
}
parent.removeChild(node);
}
;
if (Object.defineProperty) {
var outerHTML_prop_desc = {
get: outerHTML_getter
, set: outerHTML_setter
, enumerable: true
, configurable: true
};
try {
Object.defineProperty(elem_proto, "outerHTML", outerHTML_prop_desc);
} catch (ex) { // IE 8 doesn't support enumerable:true
if (ex.number === -0x7FF5EC54) {
outerHTML_prop_desc.enumerable = false;
Object.defineProperty(elem_proto, "outerHTML", outerHTML_prop_desc);
}
}
} else if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) {
elem_proto.__defineGetter__("outerHTML", outerHTML_getter);
elem_proto.__defineSetter__("outerHTML", outerHTML_setter);
}
}(self));
}
@mathiasbynens
Copy link

mathiasbynens commented Jun 24, 2011

T-shirt idea: “0x7FF5EC54 is just a fancy way of saying 2146823252.”

Loading

@LeaVerou
Copy link

LeaVerou commented Sep 24, 2011

Wouldn't it be more efficient if you cached container instead of creating a new element every time?

Loading

@eligrey
Copy link
Author

eligrey commented Sep 24, 2011

Not every element is in the same document, as you can see by my use of node.ownerDocument.createElement.

Loading

@sashasklar
Copy link

sashasklar commented Nov 14, 2011

Have you tested this in a recent version of Firefox? FF 6.0 on OS X seems to be removing the node without replacing it: http://jsfiddle.net/M27UA/

Loading

@eligrey
Copy link
Author

eligrey commented Nov 14, 2011

Fixed. For some reason I had parent.removeChild(child); in there, and I probably should have at least tested the script once I added the setter :P

Loading

@sashasklar
Copy link

sashasklar commented Nov 14, 2011

Nice, thanks for the quick fix!

Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment