Revision: 3866
Author: felix8a
Date: Mon Nov 23 15:51:54 2009
Log: fix spurious exception from button.setAttribute("type", x)
http://codereview.appspot.com/159053

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.

[email protected]

http://code.google.com/p/google-caja/source/detail?r=3866

Modified:
 /trunk/src/com/google/caja/plugin/bridal.js
 /trunk/tests/com/google/caja/plugin/domita_test_untrusted.html

=======================================
--- /trunk/src/com/google/caja/plugin/bridal.js Thu Nov 19 23:47:53 2009
+++ /trunk/src/com/google/caja/plugin/bridal.js Mon Nov 23 15:51:54 2009
@@ -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;
-      }
-    }
-    var node = element.ownerDocument.createAttribute(name);
-    node.value = value;
-    element.setAttributeNode(node);
-    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 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);
   }

   /**
=======================================
--- /trunk/tests/com/google/caja/plugin/domita_test_untrusted.html Mon Nov 23 14:00:01 2009 +++ /trunk/tests/com/google/caja/plugin/domita_test_untrusted.html Mon Nov 23 15:51:54 2009
@@ -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">
@@ -3069,6 +3073,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');
+  } catch (e) {
+    fail('testButtonMutation got error: ' + e.message);
+  }
+  pass('testButtonMutation');
+});
+
 jsunitRegister('testRowCell',
                function testRowCell() {
   var table = document.getElementById('test-row-cell-1');

Reply via email to