Reviewers: MikeSamuel,

Description:
this fixes http://code.google.com/p/google-caja/issues/detail?id=1171

YUI was failing on IE[67] when trying to create
a YUI button using an existing <button>,
because it was trying to setAttribute("type", "button")
and that normally just fails silently on IE[67],
but throws an exception when using bridal.

Please review this at http://codereview.appspot.com/159053

Affected files:
  M     src/com/google/caja/plugin/bridal.js
  M     tests/com/google/caja/plugin/domita_test_untrusted.html


Index: tests/com/google/caja/plugin/domita_test_untrusted.html
===================================================================
--- tests/com/google/caja/plugin/domita_test_untrusted.html     (revision 3858)
+++ tests/com/google/caja/plugin/domita_test_untrusted.html     (working copy)
@@ -435,6 +435,10 @@

 <p class="testcontainer" id="test-for-attribute">for attribute</p>

+<p class="testcontainer" id="test-button-mutation">
+<button id="test-button-mutation-1">test-button-mutation</button>
+</p>
+
 <div class="testcontainer" id="test-row-cell">
 Test row cell
   <table id="test-row-cell-1">
@@ -3068,6 +3072,17 @@
   pass('test-for-attribute');
 });

+jsunitRegister('testButtonMutation', function testButtonMutation() {
+  var el = document.getElementById('test-button-mutation-1');
+  // this never works on IE[67], but it shouldn't throw an error.
+  try {
+    el.setAttribute('type', 'reset');
+    pass('testButtonMutation');
+  } catch (e) {
+    fail('testButtonMutation got error: ' + e.message);
+  }
+});
+
 jsunitRegister('testRowCell',
                function testRowCell() {
   var table = document.getElementById('test-row-cell-1');
Index: src/com/google/caja/plugin/bridal.js
===================================================================
--- src/com/google/caja/plugin/bridal.js        (revision 3858)
+++ src/com/google/caja/plugin/bridal.js        (working copy)
@@ -393,19 +393,48 @@
    * @param {string} value the value of an attribute.
    */
   function setAttribute(element, name, value) {
-    // In IE[67], element.style.cssText seems to be the only way to set the
-    // style.  This unfortunately fails when element.style is an input
-    // element instead of the style object.
-    if (name === 'style') {
-      if (typeof element.style.cssText === 'string') {
-        element.style.cssText = value;
-        return value;
-      }
+    /*
+      Hazards:
+
+        - In IE[67], el.setAttribute doesn't work for attributes like
+          'class' or 'for'.  IE[67] expects you to set 'className' or
+          'htmlFor'.  Using setAttributeNode solves this problem.
+
+        - In IE[67], <input> elements can shadow attributes.  If el is a
+          form that contains an <input> named x, then el.setAttribute(x, y)
+          will set x's value rather than setting el's attribute.  Using
+          setAttributeNode solves this problem.
+
+        - In IE[67], the style attribute can only be modified by setting
+          el.style.cssText.  Neither setAttribute nor setAttributeNode will
+          work.  el.style.cssText isn't bullet-proof, since it can be
+          shadowed by <input> elements.
+
+        - In IE[67], you can never change the type of an <button> element.
+          setAttribute('type') silently fails, but setAttributeNode
+          throws an exception.  We want the silent failure.
+
+        - In IE[67], you can never change the type of an <input> element.
+          setAttribute('type') throws an exception.  We want the exception.
+
+        - In IE[67], setAttribute is case-sensitive, unless you pass 0 as a
+          3rd argument.  setAttributeNode is case-insensitive.
+
+        - Trying to set an invalid name like ":" is supposed to throw an
+          error.  In IE[678] and Opera 10, it fails without an error.
+    */
+    if (name === 'style' && typeof element.style.cssText === 'string') {
+      element.style.cssText = value;
+      return value;
     }
-    var node = element.ownerDocument.createAttribute(name);
-    node.value = value;
-    element.setAttributeNode(node);
-    return value;
+    var attr = element.ownerDocument.createAttribute(name);
+    attr.value = value;
+    try {
+      element.setAttributeNode(attr);
+      return value;
+    } catch (e) {}
+    // It's a real failure only if setAttribute also fails.
+    return element.setAttribute(name, value, 0);
   }

   /**


Reply via email to