Revision: 4794
Author: [email protected]
Date: Tue Feb 28 15:48:15 2012
Log: fixes for IE8
http://codereview.appspot.com/5700063
These changes fix most of the playground demos for IE8.
The Flash demos still fail.
The canvas demo still fails.
IE7 support is improved, but has a few more problems than IE8.
[email protected]
http://code.google.com/p/google-caja/source/detail?r=4794
Added:
/trunk/src/com/google/caja/demos/playground/examples/unboxed/bomb.png
Modified:
/trunk/src/com/google/caja/demos/playground/client/ui/PlaygroundView.java
/trunk/src/com/google/caja/demos/playground/examples/cajalife.html
/trunk/src/com/google/caja/gwtbeans/shared/Caja.java
/trunk/src/com/google/caja/plugin/bridal.js
/trunk/src/com/google/caja/plugin/domado.js
/trunk/src/com/google/caja/plugin/es53-frame-group.js
/trunk/src/com/google/caja/plugin/html-emitter.js
/trunk/src/com/google/caja/plugin/templates/SafeHtmlMaker.java
/trunk/tests/com/google/caja/plugin/HtmlEmitterTest.java
/trunk/tests/com/google/caja/plugin/PipelineCacheTest.java
/trunk/tests/com/google/caja/plugin/templates/TemplateCompilerTest.java
/trunk/tests/com/google/caja/plugin/templates/template-compiler-golden1-dynamic.js
/trunk/tests/com/google/caja/plugin/templates/template-compiler-golden1-nulluripol.js
/trunk/tests/com/google/caja/plugin/templates/template-compiler-golden1-static.js
=======================================
--- /dev/null
+++ /trunk/src/com/google/caja/demos/playground/examples/unboxed/bomb.png
Tue Feb 28 15:48:15 2012
Binary file, no diff available.
=======================================
---
/trunk/src/com/google/caja/demos/playground/client/ui/PlaygroundView.java
Wed Feb 22 16:46:46 2012
+++
/trunk/src/com/google/caja/demos/playground/client/ui/PlaygroundView.java
Tue Feb 28 15:48:15 2012
@@ -284,16 +284,22 @@
playgroundUI.mode.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
+ // Need an absolute URL for IE<=8
+ String base =
+ Window.Location.getProtocol() + "//" +
+ Window.Location.getHost() +
+ Window.Location.getPath();
+ String hash = Window.Location.getHash();
int s = playgroundUI.mode.getSelectedIndex();
switch (s) {
case 1:
- Window.Location.assign("?es5=true" +
Window.Location.getHash());
+ Window.Location.assign(base + "?es5=true" + hash);
break;
case 2:
- Window.Location.assign("?es5=false" +
Window.Location.getHash());
+ Window.Location.assign(base + "?es5=false" + hash);
break;
default:
- Window.Location.assign("?es5=auto" +
Window.Location.getHash());
+ Window.Location.assign(base + "?es5=auto" + hash);
break;
}
}
=======================================
--- /trunk/src/com/google/caja/demos/playground/examples/cajalife.html Mon
Feb 6 16:10:26 2012
+++ /trunk/src/com/google/caja/demos/playground/examples/cajalife.html Tue
Feb 28 15:48:15 2012
@@ -89,7 +89,7 @@
}
str += "\n";
}
- ta.innerHTML = str;
+ ta.value = str;
}
// Update loop
=======================================
--- /trunk/src/com/google/caja/gwtbeans/shared/Caja.java Mon Feb 6
08:31:01 2012
+++ /trunk/src/com/google/caja/gwtbeans/shared/Caja.java Tue Feb 28
15:48:15 2012
@@ -35,6 +35,7 @@
public static native void initialize(String cajaServer, boolean debug,
boolean forceES5Mode) /*-{
+ $wnd.caja.initFeralFrame(window); // note 'window' not '$wnd'
$wnd.caja.initialize({
cajaServer: cajaServer,
debug: debug,
=======================================
--- /trunk/src/com/google/caja/plugin/bridal.js Sat Feb 25 13:31:59 2012
+++ /trunk/src/com/google/caja/plugin/bridal.js Tue Feb 28 15:48:15 2012
@@ -36,8 +36,10 @@
* @param {HTMLDocument} document
*/
var bridalMaker = function (makeDOMAccessible, document) {
+ document = makeDOMAccessible(document);
+ var docEl = makeDOMAccessible(document.documentElement);
var window = makeDOMAccessible(
- bridalMaker.getWindow(document.documentElement));
+ bridalMaker.getWindow(docEl, makeDOMAccessible));
var navigator = makeDOMAccessible(window.navigator);
var XMLHttpRequest = makeDOMAccessible(window.XMLHttpRequest);
var ActiveXObject = makeDOMAccessible(window.ActiveXObject);
@@ -413,6 +415,7 @@
}
function initCanvasElement(el) {
+ // TODO(felix8a): need to whitelist G_vmlCanvasManager
if (window.G_vmlCanvasManager) {
window.G_vmlCanvasManager.initElement(el);
}
@@ -769,8 +772,9 @@
/**
* Returns the window containing this element.
*/
-bridalMaker.getWindow = function(element) {
- var doc = element.ownerDocument;
+// mda = makeDOMAccessible
+bridalMaker.getWindow = function(element, mda) {
+ var doc = mda(mda(element).ownerDocument);
// IE
if (doc.parentWindow) { return doc.parentWindow; }
// Everything else
@@ -780,8 +784,9 @@
// Just in case
var s = doc.createElement('script');
s.innerHTML = "document.parentWindow = window;";
- doc.body.appendChild(s);
- doc.body.removeChild(s);
+ var body = mda(doc.body);
+ body.appendChild(s);
+ body.removeChild(s);
return doc.parentWindow;
};
=======================================
--- /trunk/src/com/google/caja/plugin/domado.js Mon Feb 27 09:52:24 2012
+++ /trunk/src/com/google/caja/plugin/domado.js Tue Feb 28 15:48:15 2012
@@ -1232,7 +1232,8 @@
var style = makeDOMAccessible(element.currentStyle);
if (!style) {
style = makeDOMAccessible(
- bridalMaker.getWindow(element).getComputedStyle(element, void
0));
+ bridalMaker.getWindow(element, makeDOMAccessible)
+ .getComputedStyle(element, void 0));
}
makeDOMAccessible(element.style);
@@ -1307,19 +1308,19 @@
if (!optPseudoWindowLocation) {
optPseudoWindowLocation = {};
}
-
+
var domicile = {
isProcessingEvent: false
};
var pluginId;
-
+
pseudoBodyNode = makeDOMAccessible(pseudoBodyNode);
var document = pseudoBodyNode.ownerDocument;
document = makeDOMAccessible(document);
- makeDOMAccessible(document.documentElement);
+ var docEl = makeDOMAccessible(document.documentElement);
var bridal = bridalMaker(makeDOMAccessible, document);
- var window = bridalMaker.getWindow(pseudoBodyNode);
+ var window = bridalMaker.getWindow(pseudoBodyNode,
makeDOMAccessible);
window = makeDOMAccessible(window);
var elementPolicies = {};
@@ -2581,7 +2582,8 @@
evt = TameEventT.coerce(evt);
bridal.dispatchEvent(np(this).feral, TameEventConf.p(evt).feral);
});
- if (document.documentElement.contains) { // typeof is 'object' on IE
+
+ if (docEl.contains) { // typeof is 'object' on IE
TameBackedNode.prototype.contains = nodeMethod(function (other) {
other = TameNodeT.coerce(other);
var otherNode = np(other).feral;
@@ -2589,7 +2591,7 @@
});
}
if ('function' ===
- typeof document.documentElement.compareDocumentPosition) {
+ typeof docEl.compareDocumentPosition) {
/**
* Speced in <a
href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition">DOM-Level-3</a>.
*/
@@ -3077,7 +3079,7 @@
});
// IE-specific method. Sets the element that will have focus when
the
// window has focus, without focusing the window.
- if (document.documentElement.setActive) {
+ if (docEl.setActive) {
TameElement.prototype.setActive = nodeMethod(function () {
if (domicile.isProcessingEvent) {
np(this).feral.setActive();
@@ -3085,7 +3087,7 @@
});
}
// IE-specific method.
- if (document.documentElement.hasFocus) {
+ if (docEl.hasFocus) {
TameElement.prototype.hasFocus = nodeMethod(function () {
return np(this).feral.hasFocus();
});
@@ -3392,6 +3394,7 @@
// support canvas, so we don't either; skip registering the canvas
// element
// class.
+ // TODO(felix8a): need to call bridal.initCanvasElement
var e = makeDOMAccessible(document.createElement('canvas'));
if (typeof e.getContext !== 'function')
return;
@@ -4967,7 +4970,7 @@
function buildTameStyle() {
- var aStyleForCPC = document.documentElement.style;
+ var aStyleForCPC = docEl.style;
aStyleForCPC = makeDOMAccessible(aStyleForCPC);
var allCssProperties = domitaModules.CssPropertiesCollection(
aStyleForCPC);
@@ -5594,7 +5597,8 @@
* Function called from rewritten event handlers to dispatch an event
safely.
*/
function plugin_dispatchEvent(thisNode, event, pluginId, handler) {
- event = makeDOMAccessible(event ||
bridalMaker.getWindow(thisNode).event);
+ event = makeDOMAccessible(
+ event || bridalMaker.getWindow(thisNode,
makeDOMAccessible).event);
// support currentTarget on IE[678]
if (!event.currentTarget) {
event.currentTarget = thisNode;
@@ -5648,3 +5652,4 @@
});
};
})();
+
=======================================
--- /trunk/src/com/google/caja/plugin/es53-frame-group.js Mon Feb 27
09:52:24 2012
+++ /trunk/src/com/google/caja/plugin/es53-frame-group.js Tue Feb 28
15:48:15 2012
@@ -450,8 +450,12 @@
if ((typeof o === 'object' || typeof o === 'function')
&& o !== null
&& !Object.prototype.hasOwnProperty.call(o, 'v___')) {
- // IE<=8 needs wrappers
- if (ie8nodes) { o = {}; }
+ // IE<=8 needs wrappers for text nodes and attribute nodes. Note, we
+ // make no effort to return the same wrapper for the same node.
+ // TODO(felix8a): verify the contract violation is unimportant.
+ if (ie8nodes && node.nodeType && node.nodeType !== 1) {
+ o = { node___: node };
+ }
o.v___ = function (p) {
return node[p];
};
@@ -470,7 +474,7 @@
if (typeof method === 'object' &&
(method+'').substr(0, 10) === '\nfunction ') {
// IE<=8 DOM methods lack .apply
- return Function.prototype.apply.call(method, node, as);
+ return Function.prototype.apply.call(method, node,
unwrapNodes(as));
}
}
throw new TypeError('Not a function: ' + p);
@@ -479,6 +483,19 @@
}
return o;
}
+
+ // This does shallow unwrapping of IE<=8 wrapped nodes, which is
+ // sufficient to handle guest code calling DOM functions like
+ // removeChild. This may not be sufficient if a caja environment has
+ // tamed functions that expect to receive arrays of nodes or structures
+ // containing nodes.
+ function unwrapNodes(as) {
+ var o = [];
+ for (var i = 0; i < as.length; as++) {
+ o[i] = as[i].node___ || as[i];
+ }
+ return o;
+ }
function FeralTwinStub() {}
}
=======================================
--- /trunk/src/com/google/caja/plugin/html-emitter.js Mon Feb 27 09:52:24
2012
+++ /trunk/src/com/google/caja/plugin/html-emitter.js Tue Feb 28 15:48:15
2012
@@ -35,6 +35,8 @@
* objects cannot be touched. makeDOMAccessible should be idempotent.
Note
* that the contract here is stronger than for bridalMaker, in that
* this makeDOMAccessible may not return a different object.
+ * Except, this contract may be impossible to satisfy on IE<=8.
+ * TODO(felix8a): check all the implications of violating the contract.
* @param base a node that is the ancestor of all statically generated
HTML.
* @param opt_domicile the domado instance that will receive a load event
when
* the html-emitter is closed, and which will have the {@code
writeHook}
@@ -312,6 +314,7 @@
this.finish = finish;
this.signalLoaded = signalLoaded;
this.setAttr = bridal.setAttribute;
+ this.rmAttr = function(el, attr) { return el.removeAttribute(attr); };
this.addBodyClasses = addBodyClasses;
this.handleEmbed = handleEmbed;
=======================================
--- /trunk/src/com/google/caja/plugin/templates/SafeHtmlMaker.java Mon Nov
28 01:31:08 2011
+++ /trunk/src/com/google/caja/plugin/templates/SafeHtmlMaker.java Tue Feb
28 15:48:15 2012
@@ -526,7 +526,7 @@
safe.setAttributeNS(ID.ns.uri, ID.localName, dynId);
if (id == null) {
emitStatement(
- quasiStmt("el___./*@synthetic*/removeAttribute('id');"),
+ quasiStmt("emitter___./*@synthetic*/rmAttr(el___, 'id');"),
bone.source);
}
}
=======================================
--- /trunk/tests/com/google/caja/plugin/HtmlEmitterTest.java Tue Nov 8
13:07:39 2011
+++ /trunk/tests/com/google/caja/plugin/HtmlEmitterTest.java Tue Feb 28
15:48:15 2012
@@ -91,7 +91,7 @@
" var emitter___ = IMPORTS___.htmlEmitter___;",
" el___ = emitter___.byId('id_1___');",
" emitter___.attach('id_1___');",
- " el___.removeAttribute('id');",
+ " emitter___.rmAttr(el___, 'id');",
"} /* End translated code */",
"try {",
" { a(); }",
@@ -119,7 +119,7 @@
" var emitter___ = IMPORTS___.htmlEmitter___;",
" el___ = emitter___.byId('id_3___');",
" emitter___.attach('id_3___');",
- " el___.removeAttribute('id');",
+ " emitter___.rmAttr(el___, 'id');",
"} /* End translated code */",
"try {",
" { c(); }",
=======================================
--- /trunk/tests/com/google/caja/plugin/PipelineCacheTest.java Tue Feb 14
14:47:05 2012
+++ /trunk/tests/com/google/caja/plugin/PipelineCacheTest.java Tue Feb 28
15:48:15 2012
@@ -263,7 +263,7 @@
+ "(this, event, ___.getId(IMPORTS___),"),
" c_2___);",
" };",
- " el___.removeAttribute('id');")
+ " emitter___.rmAttr(el___, 'id');")
+ JS_MODULE_SUFFIX;
private static final String REWRITTEN_HELLO_WORLD_HTML_HELPER_JS_NO_LOAD
@@ -537,7 +537,7 @@
" return ___.plugin_dispatchEvent___(this, event,
___.getId(IMPORTS___),",
" c_1___);",
" };",
- " el___.removeAttribute('id');")
+ " emitter___.rmAttr(el___, 'id');")
+ JS_MODULE_SUFFIX, ContentType.JS)
};
=======================================
--- /trunk/tests/com/google/caja/plugin/templates/TemplateCompilerTest.java
Tue Jan 24 11:04:08 2012
+++ /trunk/tests/com/google/caja/plugin/templates/TemplateCompilerTest.java
Tue Feb 28 15:48:15 2012
@@ -180,7 +180,7 @@
+ " el___ = emitter___.byId('id_1___');"
+ " emitter___.setAttr("
+ " el___, 'name', 'hi-' + IMPORTS___.getIdClass___());"
- + " el___.removeAttribute('id');"
+ + " emitter___.rmAttr(el___, 'id');"
+ " el___ = emitter___.finish();"
+ " emitter___.signalLoaded();"
+ " }"
@@ -238,7 +238,7 @@
+ " return ___.plugin_dispatchEvent___("
+ " this, event, ___.getId(IMPORTS___), c_1___);"
+ " };"
- + " el___.removeAttribute('id');"
+ + " emitter___.rmAttr(el___, 'id');"
+ " el___ = emitter___.finish();"
+ " emitter___.signalLoaded();"
+ " }"
@@ -268,7 +268,7 @@
+ " 'try{void ___.plugin_dispatchToHandler___('"
+ " + ___.getId(IMPORTS___) + ',' + c_1___"
+ " + ',[{}])}catch(_){}'));"
- + " el___.removeAttribute('id');"
+ + " emitter___.rmAttr(el___, 'id');"
+ " el___ = emitter___.finish();"
+ " emitter___.signalLoaded();"
+ " }"
@@ -299,7 +299,7 @@
+ " 'try{void ___.plugin_dispatchToHandler___('"
+ " + ___.getId(IMPORTS___) + ',' + c_1___"
+ " + ',[{}])}catch(_){}'));"
- + " el___.removeAttribute('id');"
+ + " emitter___.rmAttr(el___, 'id');"
+ " el___ = emitter___.finish();"
+ " emitter___.signalLoaded();"
+ " }"
@@ -692,7 +692,7 @@
+ " emitter___.setAttr(el___, 'headers',"
+ " 'a-' + IMPORTS___.getIdClass___()"
+ " + ' b-' + IMPORTS___.getIdClass___());"
- + " el___.removeAttribute('id');"
+ + " emitter___.rmAttr(el___, 'id');"
+ " el___ = emitter___.finish();"
+ " emitter___.signalLoaded();"
+ " }"
=======================================
---
/trunk/tests/com/google/caja/plugin/templates/template-compiler-golden1-dynamic.js
Tue Dec 13 15:05:45 2011
+++
/trunk/tests/com/google/caja/plugin/templates/template-compiler-golden1-dynamic.js
Tue Feb 28 15:48:15 2012
@@ -20,7 +20,7 @@
return ___.plugin_dispatchEvent___(this, event,
___.getId(IMPORTS___), c_1___);
};
// Remove the manufactured ID
- el___.removeAttribute('id');
+ emitter___.rmAttr(el___, 'id');
}
}
function module() { // The first script.
@@ -62,7 +62,7 @@
el___.onclick = function (event) {
return ___.plugin_dispatchEvent___(this, event,
___.getId(IMPORTS___), c_1___);
};
- el___.removeAttribute('id');
+ emitter___.rmAttr(el___, 'id');
el___ = emitter___.byId('id_6___');
emitter___.setAttr(el___, 'id', 'zag-' + IMPORTS___.getIdClass___());
el___ = emitter___.finish();
=======================================
---
/trunk/tests/com/google/caja/plugin/templates/template-compiler-golden1-nulluripol.js
Tue Dec 13 15:05:45 2011
+++
/trunk/tests/com/google/caja/plugin/templates/template-compiler-golden1-nulluripol.js
Tue Feb 28 15:48:15 2012
@@ -20,7 +20,7 @@
return ___.plugin_dispatchEvent___(this, event,
___.getId(IMPORTS___), c_1___);
};
// Remove the manufactured ID
- el___.removeAttribute('id');
+ emitter___.rmAttr(el___, 'id');
}
}
function module() { // The first script.
@@ -64,7 +64,7 @@
el___.onclick = function (event) {
return ___.plugin_dispatchEvent___(this, event,
___.getId(IMPORTS___), c_1___);
};
- el___.removeAttribute('id');
+ emitter___.rmAttr(el___, 'id');
el___ = emitter___.byId('id_6___');
emitter___.setAttr(el___, 'id', 'zag-' + IMPORTS___.getIdClass___());
el___ = emitter___.finish();
=======================================
---
/trunk/tests/com/google/caja/plugin/templates/template-compiler-golden1-static.js
Tue Dec 13 15:05:45 2011
+++
/trunk/tests/com/google/caja/plugin/templates/template-compiler-golden1-static.js
Tue Feb 28 15:48:15 2012
@@ -15,7 +15,7 @@
return ___.plugin_dispatchEvent___(this, event,
___.getId(IMPORTS___), c_1___);
};
// Remove the manufactured ID
- el___.removeAttribute('id');
+ emitter___.rmAttr(el___, 'id');
}
}
function module() {
@@ -59,7 +59,7 @@
el___.onclick = function (event) {
return ___.plugin_dispatchEvent___(this, event,
___.getId(IMPORTS___), c_1___);
};
- el___.removeAttribute('id');
+ emitter___.rmAttr(el___, 'id');
el___ = emitter___.finish();
emitter___.signalLoaded();
}