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();
   }

Reply via email to