<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="http://archie.blogr.com/metaTags/html/rss2html.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>archie.blogr.com - Tag &apos;html&apos; (RSS 2.0)</title>
<link>http://archie.blogr.com/metaTags/html/</link>
<description>XML Feed</description>
<language>en</language>
<pubDate>Thu, 05 Apr 2007 18:02:48 +0200</pubDate>
<image><url>http://static.blogr.com/tenants/com/modSiteIcon/tdy-dummy-site-icon.icon.jpg</url>
<title>archie</title>
<link>http://archie.blogr.com/metaTags/html/</link>
<width>48</width>
<height>48</height>
</image>
<item><title>Workarounds for IE: Disabled Options</title>
<link>http://archie.blogr.com/stories/1057864/</link>
<description>&lt;h1&gt;How it all started...&lt;/h1&gt; &lt;p&gt;Yes, I admit, I am one of those post-modern programmers who search the Web for solutions and code. Time to refund something.&lt;/p&gt; &lt;p&gt;One task I often come across at work is to find workarounds for Internet Explorer HTML, CSS, or JavaScript - &lt;em&gt;um&lt;/em&gt; - deficiencies. As you can imagine, this task can consume lots of time and would often not be possible without post-modern programming techniques.&lt;/p&gt; &lt;p&gt;Today&amp;#39;s topic is IE&amp;#39;s lack of supporting the &lt;code&gt;disabled&lt;/code&gt; attribute for &lt;code&gt;option&lt;/code&gt; elements. It simply ignores the attribute: a disabled option is still selectable. This is &lt;a href=&quot;http://blogs.msdn.com/ie/archive/2006/01/17/514076.aspx#514760&quot;&gt;not even fixed in IE7&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Several solutions can be found on the Web, which fall mainly into two categories:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;Complicated JavaScript solutions that try to change the selection afterwards when detecting that the selected item is actually disabled (e.g. by &lt;a href=&quot;http://www.lattimore.id.au/2005/07/01/select-option-disabled-and-the-javascript-solution/&quot;&gt;Alistair Lattimore&lt;/a&gt; and by &lt;a href=&quot;http://toserveman.kalebwalton.com/articles/2006/08/03/ie-select-option-disabled-javascript-workaround&quot;&gt;Kaleb Walton&lt;/a&gt;).&lt;/li&gt;&lt;li&gt;The idea to simply replace a disabled option by an &lt;code&gt;optgroup&lt;/code&gt;, as described by &lt;a href=&quot;http://www.inquirium.net/blog/entry_157.php#body&quot;&gt;Ben&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;I like the second approach much better, &lt;em&gt;not&lt;/em&gt; because it refrains from using JavaScript, but because the behavior in the browser is as intended and it does not interfere with other event handlers. But what I do not like about the second solution is that one has to care about the IE bug during rendering the HTML code.&lt;/p&gt; &lt;p&gt;For the first solution, some posts suggested to use &lt;a href=&quot;http://msdn.microsoft.com/workshop/author/behaviors/howto/creating.asp&quot;&gt;DHTML Behaviors&lt;/a&gt;. Although this is an IE-prorietary feature, it is really okay to use it here, namely as a workaround for an IE-specific problem.&lt;/p&gt; &lt;p&gt;So my idea was to combine the HTML of the second approach with the &amp;quot;JavaScript will take care of it&amp;quot; attitude of the first approach and came up with the following solution which did not seem to be available on the Web before. (In fact, this idea became the missing push to eventually get me blogging.)&lt;/p&gt;  &lt;h1&gt;Fables of the Reconstruction&lt;/h1&gt;  &lt;p&gt;To cite from &lt;a href=&quot;http://www.inquirium.net/blog/entry_157.php#body&quot;&gt;Ben&amp;#39;s solution&lt;/a&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;The key is to replace your disabled &lt;code&gt;option&lt;/code&gt;s with an &lt;code&gt;optgroup&lt;/code&gt;.  Why does this work?&lt;/p&gt; &lt;ul&gt;&lt;li&gt;&lt;code&gt;optgroup&lt;/code&gt;s are already &lt;code&gt;disabled&lt;/code&gt; — you can’t select them, so you get immediate feedback.&lt;/li&gt;&lt;li&gt;&lt;code&gt;optgroup&lt;/code&gt;s don’t look disabled, but you can use CSS to change the look.&lt;/li&gt;&lt;/ul&gt; &lt;/blockquote&gt; &lt;p&gt;As I said, the only real drawback of Ben&amp;#39;s solution is, as he mentions, that you have to care about constructing the IE-specific HTML yourself. So why not have JavaScript do the reconstruction inside the browser? All the JavaScript has to do is scan all &lt;code&gt;option&lt;/code&gt; elements for the &lt;code&gt;disabled&lt;/code&gt; attribute and replace them by &lt;code&gt;optgroup&lt;/code&gt;s. Matters become a bit more complicated when disabled options inside optgroups are also supposed to work, but we&amp;#39;ll also cover that use case.&lt;/p&gt; &lt;p&gt;For the following code fragment, let&amp;#39;s assume there is a variable &lt;code&gt;element&lt;/code&gt; refering to an &lt;code&gt;option&lt;/code&gt; element. We have to check its &lt;code&gt;disabled&lt;/code&gt; property and, to make sure we produce no nested &lt;code&gt;optgroup&lt;/code&gt;s, the parent node not to be an &lt;code&gt;optgroup&lt;/code&gt;. Then, we retrieve the label of the &lt;code&gt;option&lt;/code&gt; element, which is its &lt;code&gt;innerHTML&lt;/code&gt;, and replace it by a newly constructed &lt;code&gt;optgroup&lt;/code&gt; with that label and the style suggested by Ben:&lt;/p&gt; &lt;pre&gt;  if (element.disabled &amp;amp;&amp;amp; element.parentNode.nodeName!=&amp;quot;OPTGROUP&amp;quot;) {&lt;br /&gt;    var label = element.innerHTML;&lt;br /&gt;    var optgroup = document.createElement(&amp;quot;&amp;lt;optgroup label=&amp;#39;&amp;quot;&lt;br /&gt;      + label&lt;br /&gt;      + &amp;quot;&amp;#39; style=&amp;#39;color:graytext; font-style:normal;&amp;#39;/&amp;gt;&amp;quot;);&lt;br /&gt;    element.parentNode.replaceChild(optgroup,element);&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt; &lt;p&gt;I could have used a simple external JavaScript file that adds an onload event handler and scans the whole document for &lt;code&gt;option&lt;/code&gt; elements. Instead, I chose to use &lt;a href=&quot;http://msdn.microsoft.com/workshop/author/behaviors/howto/creating.asp&quot;&gt;DHTML Behaviors&lt;/a&gt;, which leads to an elegant and concise solution and is &amp;quot;allowed&amp;quot; in this case for the reasons explained above.&lt;/p&gt; &lt;p&gt;For problems like this one, where you just want to execute some JavaScript code on all elements that match some CSS rule, DHTML Behaviors are really easy to handle. Just define an IE-specific CSS rule like this:&lt;/p&gt; &lt;pre&gt;option { behavior: url(&amp;quot;disabled-option.htc&amp;quot;); }&lt;br /&gt;&lt;/pre&gt; &lt;p&gt;Because this rule is IE-specific and standard-compliant browsers may complain about it (at least Firefox issues a warning in its console), it should go into an IE &lt;a href=&quot;http://msdn.microsoft.com/workshop/author/dhtml/overview/ccomment_ovw.asp&quot;&gt;conditional comment&lt;/a&gt;:&lt;/p&gt; &lt;pre&gt;&amp;lt;!--[if IE]&amp;gt;&lt;br /&gt;  &amp;lt;style&amp;gt;&lt;br /&gt;    option { behavior: url(&amp;quot;disabled-option.htc&amp;quot;); }&lt;br /&gt;  &amp;lt;/style&amp;gt;&lt;br /&gt;&amp;lt;![endif]--&amp;gt;&lt;br /&gt;&lt;/pre&gt; &lt;p&gt;An HTC file is essentially a JavaScript source code file wrapped with some meta information. In this case, the meta information is trivial, and the current element is handed in as a parameter named &lt;code&gt;element&lt;/code&gt; (what coincidence and surprise!), so that we just have to wrap the JavaScript code fragment given above with&lt;/p&gt; &lt;pre&gt;&amp;lt;public:component&amp;gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;  ...&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/public:component&amp;gt;&lt;br /&gt;&lt;/pre&gt; &lt;p&gt;and put it into a file called &amp;quot;disabled-option.htc&amp;quot;.&lt;/p&gt;  &lt;h1&gt;Group Pressure&lt;/h1&gt;  &lt;p&gt;Ben points out that since you cannot nest &lt;code&gt;optgroup&lt;/code&gt; elements, it requires a bit more tricks to find a workaround for disabled options inside an option group. He suggests the following:&lt;/p&gt;  &lt;blockquote&gt; &lt;ul&gt;&lt;li&gt;Use non-breaking spaces to indent the menu items as a way to emulate a nested optgroup.&lt;/li&gt;&lt;li&gt;Use other empty &lt;code&gt;optgroup&lt;/code&gt; items (with no extra CSS formatting) to serve as the group headings.&lt;/li&gt;&lt;/ul&gt; &lt;/blockquote&gt;  &lt;p&gt;That means we need another Behavior for &lt;code&gt;optgroup&lt;/code&gt;s that checks whether the group contains a disabled option, and if so, moves all options to the top level, adding non-breakable spaces to emulate indention, and converts disabled options to optgroups on the fly. Let&amp;#39;s call this Behavior &amp;quot;optgroup-with-disabled-options.htc&amp;quot;. If you need this feature, add a corresponding CSS rule to the style that is only visible for IE (see above):&lt;/p&gt; &lt;pre&gt;    optgroup { behavior: url(&amp;quot;optgroup-with-disabled-options.htc&amp;quot;); }&lt;br /&gt;&lt;/pre&gt;  &lt;p&gt;The contents of &amp;quot;optgroup-with-disabled-options.htc&amp;quot; looks like this:&lt;/p&gt; &lt;pre&gt;&amp;lt;public:component&amp;gt;&lt;br /&gt;&amp;lt;script&amp;gt;&lt;br /&gt;  // check whether it contains a disabled option:&lt;br /&gt;  for (var i=0; i&amp;lt;element.childNodes.length; ++i) {&lt;br /&gt;    if (element.childNodes[i].nodeName==&amp;quot;OPTION&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;        element.childNodes[i].disabled) {&lt;br /&gt;      // move all options one level up, adding non-breakable&lt;br /&gt;      // spaces to indent and converting disabled options:&lt;br /&gt;      var parent = element.parentNode;&lt;br /&gt;      var insertionPoint = element.nextSibling;&lt;br /&gt;      for (var i=element.childNodes.length-1; i&amp;gt;=0; --i) {&lt;br /&gt;        var option = element.childNodes[i];&lt;br /&gt;        if (option.nodeName==&amp;quot;OPTION&amp;quot;) {&lt;br /&gt;          var label = option.innerHTML;&lt;br /&gt;          if (option.disabled) {&lt;br /&gt;            element.removeChild(option);&lt;br /&gt;            option = document.createElement(&amp;quot;&amp;lt;optgroup label=&amp;#39;    &amp;quot;&lt;br /&gt;              +label&lt;br /&gt;              +&amp;quot;&amp;#39; style=&amp;#39;color:graytext; font-style:normal;&amp;#39;/&amp;gt;&amp;quot;);&lt;br /&gt;          } else {&lt;br /&gt;            option.firstChild.data = &amp;quot;      &amp;quot;+label;&lt;br /&gt;          }&lt;br /&gt;          insertionPoint = parent.insertBefore(option,insertionPoint);&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;      break;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/public:component&amp;gt;&lt;br /&gt;&lt;/pre&gt; &lt;p&gt;Note that to emulate IE&amp;#39;s standard indention depth, you need six spaces for normal options, but only four spaces for option groups that simulate disabled options (probably because the option group is bold?).&lt;/p&gt;  &lt;h1&gt;Conclusion&lt;/h1&gt;  &lt;p&gt;Putting it all together, you can now use the &lt;code&gt;disabled&lt;/code&gt; attribute on &lt;code&gt;option&lt;/code&gt; elements, and the following happens:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;All non-IE browsers take the conditional comment as a comment and do nothing special. Disabled options work, anyway.&lt;/li&gt;&lt;li&gt;IE uses the style inside the conditional comment and thus defines the given Behaviors for all &lt;code&gt;option&lt;/code&gt; and &lt;code&gt;optgroup&lt;/code&gt; elements.   &lt;ul&gt;&lt;li&gt;For each &lt;code&gt;option&lt;/code&gt; element, the JavaScript code defined in &amp;quot;disabled-option.htc&amp;quot; is executed and replaces disabled options by optgroups.&lt;/li&gt;&lt;li&gt;For each &lt;code&gt;optgroup&lt;/code&gt; element, the JavaScript code defined in &amp;quot;optgroup-with-disabled-options.htc&amp;quot; is executed, moves all &lt;code&gt;options&lt;/code&gt; inside an &lt;code&gt;optgroup&lt;/code&gt; that contains any disabled option to top level, indents them, and again replaces disabled options by optgroups.&lt;/li&gt;&lt;/ul&gt; &lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The result looks like this:&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;http://archie.blogr.com/photos/1070396/&quot;&gt;&lt;img class=&quot;entry-inline-image&quot; src=&quot;http://static.blogr.com/tenants/com/sites/ar/archie/media/Disabled-Option-in-IE.story.jpg&quot; alt=&quot;Disabled Option in IE&quot; title=&quot;Disabled Option in IE&quot; width=&quot;400&quot; height=&quot;384&quot; /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;The advantages of this new solution:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;You only have to include a few lines in the &lt;code&gt;head&lt;/code&gt; of an HTML page which are treated as comment by any validator and any standard-compliant browser.&lt;/li&gt;&lt;li&gt;Then, you can use the standard-compliant way for disabling options and it will work even in IE.&lt;/li&gt;&lt;li&gt;All usual event handlers defined on the select element work as before.&lt;/li&gt;&lt;li&gt;For the anti-JavaScript-lurkers: If JavaScript is turned off, the situation isn&amp;#39;t any worse than before: simply, the IE bug is still present.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The only disadvantages I could think of:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;The DOM is manipulated at run-time. If for example another script is manipulating the options (quite a common use case), it may have to be adapted to be aware of the disabled-option Behavior.&lt;/li&gt;&lt;li&gt;Maybe a small rendering performance impact if you have many many options on a page.&lt;/li&gt;&lt;li&gt;IE ignores most CSS style on options. Luckily, the font &lt;code&gt;color&lt;/code&gt; can be changed to &lt;code&gt;graytext&lt;/code&gt;, but &lt;code&gt;font-style&lt;/code&gt; and &lt;code&gt;font-weight&lt;/code&gt; do not seem to have any effect; the text is always bold and italic. I think this minor design deviation is bearable.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Please let me know if you found this solution useful!&lt;/p&gt;</description>
<guid isPermaLink="true">http://archie.blogr.com/stories/1057864/</guid>
<pubDate>Thu, 05 Apr 2007 16:53:01 +0200</pubDate>
<dc:creator>archie</dc:creator>
</item>
</channel>
</rss>
