Revision: 4229
Author: [email protected]
Date: Fri Aug 6 22:04:29 2010
Log: [?1034hFixes issue 1228: support for innerText and textContent to
domita.js
http://codereview.appspot.com/1689062
http://code.google.com/p/google-caja/issues/detail?id=1228
Adds to domita.js handlers setters and getters for textContent and
innerText for TameTextNode and TameElement.
[email protected]
http://code.google.com/p/google-caja/source/detail?r=4229
Modified:
/trunk/src/com/google/caja/plugin/domita.js
/trunk/tests/com/google/caja/plugin/domita_test.html
/trunk/tests/com/google/caja/plugin/domita_test_untrusted.html
=======================================
--- /trunk/src/com/google/caja/plugin/domita.js Fri Aug 6 13:44:11 2010
+++ /trunk/src/com/google/caja/plugin/domita.js Fri Aug 6 22:04:29 2010
@@ -424,7 +424,7 @@
/**
* Add a tamed document implementation to a Gadget's global scope.
*
- * Has the side effect of adding the classes "vdoc-body___" and
+ * Has the side effect of adding the classes "vdoc-body___" and
* idSuffix.substring(1) to the pseudoBodyNode.
*
* @param {string} idSuffix a string suffix appended to all node IDs.
@@ -1163,6 +1163,7 @@
throw 'Internal: Attr nodes cannot be generically wrapped';
break;
case 3: // Text
+ case 4: // CDATA Section Node
tamed = new TameTextNode(node, editable);
break;
case 8: // Comment
@@ -1449,7 +1450,7 @@
var UNSAFE_TAGNAME = "Unsafe tag name.";
var UNKNOWN_TAGNAME = "Unknown tag name.";
var INDEX_SIZE_ERROR = "Index size error.";
-
+
// Implementation of EventTarget::addEventListener
function tameAddEventListener(name, listener, useCapture) {
if (!this.editable___) { throw new Error(NOT_EDITABLE); }
@@ -2085,7 +2086,8 @@
}
TameBackedNode.call(this, node, editable, editable);
- classUtils.exportFields(this, ['nodeValue', 'data']);
+ classUtils.exportFields(
+ this, ['nodeValue', 'data', 'textContent', 'innerText']);
}
inertCtor(TameTextNode, TameBackedNode, 'Text');
TameTextNode.prototype.setNodeValue = function (value) {
@@ -2093,8 +2095,10 @@
this.node___.nodeValue = String(value || '');
return value;
};
- TameTextNode.prototype.getData = TameTextNode.prototype.getNodeValue;
- TameTextNode.prototype.setData = TameTextNode.prototype.setNodeValue;
+ TameTextNode.prototype.getTextContent =
TameTextNode.prototype.getInnerText
+ = TameTextNode.prototype.getData =
TameTextNode.prototype.getNodeValue;
+ TameTextNode.prototype.setTextContent =
TameTextNode.prototype.setInnerText
+ = TameTextNode.prototype.setData =
TameTextNode.prototype.setNodeValue;
TameTextNode.prototype.toString = function () {
return '#text';
};
@@ -2211,7 +2215,7 @@
classUtils.exportFields(
this,
['className', 'id', 'innerHTML', 'tagName', 'style',
- 'offsetParent', 'title', 'dir']);
+ 'offsetParent', 'title', 'dir', 'innerText', 'textContent']);
classUtils.applyAccessors(this, commonElementPropertyHandlers);
registerElementScriptAttributeHandlers(this);
}
@@ -2345,6 +2349,46 @@
if (!this.editable___) { throw new Error(NOT_EDITABLE); }
return this.setAttribute('dir', String(classes));
};
+ function innerTextOf(rawNode, out) {
+ switch (rawNode.nodeType) {
+ case 1: // Element
+ var tagName = rawNode.tagName.toLowerCase();
+ if (html4.ELEMENTS.hasOwnProperty(tagName)
+ && !(html4.ELEMENTS[tagName] & html4.eflags.UNSAFE)) {
+ // Not an opaque node.
+ for (var c = rawNode.firstChild; c; c = c.nextSibling) {
+ innerTextOf(c, out);
+ }
+ }
+ break;
+ case 3: // Text Node
+ case 4: // CDATA Section Node
+ out[out.length] = rawNode.data;
+ break;
+ case 11: // Document Fragment
+ for (var c = rawNode.firstChild; c; c = c.nextSibling) {
+ innerTextOf(c, out);
+ }
+ break;
+ }
+ }
+ TameElement.prototype.getTextContent =
TameElement.prototype.getInnerText
+ = function () {
+ var text = [];
+ innerTextOf(this.node___, text);
+ return text.join('');
+ };
+ TameElement.prototype.setTextContent =
TameElement.prototype.setInnerText
+ = function (newText) {
+ if (!this.editable___) { throw new Error(NOT_EDITABLE); }
+ var newTextStr = newText != null ? String(newText) : '';
+ var el = this.node___;
+ for (var c; (c = el.firstChild);) { el.removeChild(c); }
+ if (newTextStr) {
+ el.appendChild(el.ownerDocument.createTextNode(newTextStr));
+ }
+ return newText;
+ };
TameElement.prototype.getTagName =
TameBackedNode.prototype.getNodeName;
TameElement.prototype.getInnerHTML = function () {
var tagName = this.node___.tagName.toLowerCase();
@@ -4184,7 +4228,7 @@
var imports = ___.getImports(pluginId);
var node = imports.tameNode___(thisNode, true);
return plugin_dispatchToHandler___(
- pluginId, handler, [ node, imports.tameEvent___(event), node ]);
+ pluginId, handler, [ node, imports.tameEvent___(event), node ]);
}
function plugin_dispatchToHandler___(pluginId, handler, args) {
=======================================
--- /trunk/tests/com/google/caja/plugin/domita_test.html Thu Jul 29
17:32:52 2010
+++ /trunk/tests/com/google/caja/plugin/domita_test.html Fri Aug 6
22:04:29 2010
@@ -140,7 +140,7 @@
<div class="testcontainer" id="test-opaque-nodes-xyz___"
><!-- Comment -->a<script id="howdy-script-xyz___">/* Howdy
*/</script
- >b<object></object>c</div>
+ >b<object>obj</object>c</div>
<!-- http://www.google.com/favicon.ico has been visited
by the above IMG tag -->
=======================================
--- /trunk/tests/com/google/caja/plugin/domita_test_untrusted.html Thu Aug
5 13:23:18 2010
+++ /trunk/tests/com/google/caja/plugin/domita_test_untrusted.html Fri Aug
6 22:04:29 2010
@@ -524,6 +524,8 @@
></map
><img usemap="#foo" src="mappic.gif"></p>
+<p class="testcontainer" id="test-inner-text">Hello, <b>World!</b></p>
+
<p class="testcontainer" id="test-document-body-appendChild"
>I should be the last element until something is appended to
document.body</p>
@@ -3274,6 +3276,40 @@
pass('test-usemap');
});
+jsunitRegister('testInnerText',
+ function testInnerText() {
+ var testInnerTextNode = document.getElementById('test-inner-text');
+ assertEquals('IT1', 'Hello, World!', testInnerTextNode.innerText);
+ assertEquals('TC1', 'Hello, World!', testInnerTextNode.textContent);
+ assertEquals('IT1T', 'Hello, ', testInnerTextNode.firstChild.innerText);
+ assertEquals('TC1T', 'Hello, ',
testInnerTextNode.firstChild.textContent);
+ assertEquals('IH1', 'Hello, <b>World!<\/b>',
testInnerTextNode.innerHTML);
+
+ testInnerTextNode.innerText = 'Goodbye cruel plain <b>text<\/b>!';
+ assertEquals(
+ 'IH2', 'Goodbye cruel plain <b>text</b>!',
+ testInnerTextNode.innerHTML);
+ assertEquals(
+ 'IT2', 'Goodbye cruel plain <b>text</b>!',
+ testInnerTextNode.firstChild.innerText);
+ assertEquals('CL2', 1, testInnerTextNode.childNodes.length);
+ testInnerTextNode.innerText = '';
+ assertEquals('CL3', 0, testInnerTextNode.childNodes.length);
+ assertEquals('IT3', '', testInnerTextNode.innerText);
+ testInnerTextNode.innerText = null;
+ assertEquals('CL4', 0, testInnerTextNode.childNodes.length);
+ testInnerTextNode.innerText = 42;
+ assertEquals('CL5', 1, testInnerTextNode.childNodes.length);
+ assertEquals('IT5', '42', testInnerTextNode.innerText);
+
+ // Opaque nodes appear to be empty.
+ assertEquals(
+ 'ITON', 'abc',
+ document.getElementById('test-opaque-nodes').innerText);
+
+ pass('test-inner-text');
+});
+
jsunitRegister('testDocumentBodyAppendChild',
function testDocumentBodyAppendChild() {
var notWhitespaceRe = new RegExp('\\S');