Skip to content

Instantly share code, notes, and snippets.

@usmonster
Forked from eligrey/textContent.js
Last active April 11, 2024 06:18
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save usmonster/d15e4475e3983bd35dba to your computer and use it in GitHub Desktop.
Save usmonster/d15e4475e3983bd35dba to your computer and use it in GitHub Desktop.
Updated Node.prototype.textContent shim for IE8 ONLY
(function() {
// inspired by Eli Grey's shim @ http://eligrey.com/blog/post/textcontent-in-ie8
// heavily modified to better match the spec:
// http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-textContent
if (Object.defineProperty && Object.getOwnPropertyDescriptor &&
Object.getOwnPropertyDescriptor(Element.prototype, 'textContent') &&
!Object.getOwnPropertyDescriptor(Element.prototype, 'textContent').get) {
// NOTE: Neither of these "drop-in" patterns would work:
// Object.defineProperty(..., ..., descriptor); // nope!
// Object.defineProperty(..., ..., { get: descriptor.get, set: descriptor.set }); // nope!
// So must use function-wrapped descriptor.fn.call pattern.
// "Normal" Elements
// NOTE: textContent is different from innerText, so its use would be incorrect:
//var innerText = Object.getOwnPropertyDescriptor(Element.prototype, "innerText"); // nope!
var getTextContent = function(x) {
if (this.tagName === 'BR') { return '\n'; }
var c = this.firstChild;
var tc=[];
// append the textContent of its children
while(!!c) {
if (c.nodeType !== 8 && c.nodeType !== 7) { // skip comments
tc.push(c.textContent);
}
c = c.nextSibling;
}
// a <br> Element should show as a newline
c = null;
tc = tc.join('');
return tc;
};
var setTextContent = function(x) {
var c;
while(!!(c=this.lastChild)) {
this.removeChild(c);
}
if (x!==null) {
c=document.createTextNode(x);
this.appendChild(c);
}
};
Object.defineProperty(Element.prototype, 'textContent', {
get: function() {
// return innerText.get.call(this); // not good enough!
return getTextContent.call(this);
},
set: function(x) {
// return innerText.set.call(this, x); // not good enough!
setTextContent.call(this, x);
},
configurable: true
});
// <script> Elements
var scriptText = Object.getOwnPropertyDescriptor(HTMLScriptElement.prototype, 'text');
Object.defineProperty(HTMLScriptElement.prototype, 'textContent', {
get: function() {
return scriptText.get.call(this);
},
set: function(x) {
scriptText.set.call(this, x);
},
configurable: true
});
// <style> Elements
var cssText = Object.getOwnPropertyDescriptor(CSSStyleSheet.prototype, 'cssText');
Object.defineProperty(HTMLStyleElement.prototype, 'textContent', {
get: function() {
return cssText.get.call(this.styleSheet);
},
set: function(x) {
cssText.set.call(this.styleSheet, x);
},
configurable: true
});
// <title> Elements
var titleText = Object.getOwnPropertyDescriptor(HTMLTitleElement.prototype, 'text');
Object.defineProperty(HTMLTitleElement.prototype, 'textContent', {
get: function() {
return titleText.get.call(this);
},
set: function(x) {
titleText.set.call(this, x);
},
configurable: true
});
// Text nodes
var textNodeValue = Object.getOwnPropertyDescriptor(Text.prototype, 'nodeValue');
Object.defineProperty(Text.prototype, 'textContent', {
get: function() {
return textNodeValue.get.call(this);
},
set: function(x) {
textNodeValue.set.call(this, x);
},
configurable: true
});
// Comments (and possibly other weird Node types that are treated as comments in IE)
var elementNodeValue = Object.getOwnPropertyDescriptor(Element.prototype, 'nodeValue');
Object.defineProperty(HTMLCommentElement.prototype, 'textContent', {
get: function() {
return elementNodeValue.get.call(this);
},
set: function(x) {
elementNodeValue.set.call(this, x);
},
configurable: true
});
// Document and DocumentFragment Nodes
// NOTE: IE8 seems to reuse HTMLDocument for both, so have to check nodeType explicitly
var documentNodeValue = Object.getOwnPropertyDescriptor(HTMLDocument.prototype, 'nodeValue');
Object.defineProperty(HTMLDocument.prototype, 'textContent', {
get: function() {
// document fragments have textContent
if (this.nodeType === 11) {
return getTextContent.call(this);
}
// a true Document's textContent is always null
return null; // === documentNodeValue.get.call(this);
},
set: function(x) {
if (this.nodeType === 11) {
setTextContent.call(this, x);
}
// setting a Document's textContent has no side effects
// else { documentNodeValue.set.call(this, x); }
},
configurable: true
});
// other Node types are either deprecated or don't matter in HTML5/IE standards mode
}
})();
@usmonster
Copy link
Author

TODO:

  • setters shouldn't return anything (could be misleading, and nothing is done with the value anyway)
  • research whether or not these particular descriptors should also include configurable: true (apparently neither configurable nor enumerable are used by IE, though configurable: true generates an error)
  • check for CDATA nodes, in case we care about X[HT]ML? (unless shim will be HTML5-only?)

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