<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://weblogs.asp.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Tales from the Evil Empire : Internet Explorer</title><link>http://weblogs.asp.net/bleroy/archive/tags/Internet+Explorer/default.aspx</link><description>Tags: Internet Explorer</description><dc:language>en</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><item><title>querySelectorAll on old IE versions: something that doesn’t work</title><link>http://weblogs.asp.net/bleroy/archive/2009/08/31/queryselectorall-on-old-ie-versions-something-that-doesn-t-work.aspx</link><pubDate>Tue, 01 Sep 2009 01:03:13 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7187174</guid><dc:creator>Bertrand Le Roy</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/bleroy/rsscomments.aspx?PostID=7187174</wfw:commentRss><comments>http://weblogs.asp.net/bleroy/archive/2009/08/31/queryselectorall-on-old-ie-versions-something-that-doesn-t-work.aspx#comments</comments><description>&lt;p&gt;&lt;img style="border-bottom: 0px; border-left: 0px; margin: 0px 0px 10px 10px; display: inline; border-top: 0px; border-right: 0px" title="(c) Bertrand Le Roy 2005" border="0" alt="(c) Bertrand Le Roy 2005" align="right" src="http://weblogs.asp.net/blogs/bleroy/WallDoor_7CF5A223.jpg" width="224" height="244" /&gt; In today’s post, I’m going to show an interesting technique to solve a problem and then I will tear it to pieces and explain why it is actually useless. I believe that negative results should also be published so that we can save other people from wasting time trying the same thing. So here goes…&lt;/p&gt;  &lt;p&gt;A few days ago, &lt;a href="http://ajaxian.com/archives/creating-a-queryselector-for-ie-that-runs-at-native-speed"&gt;a post on Ajaxian&lt;/a&gt; proposed a new version of a somewhat old technique to implement &lt;a href="http://www.w3.org/TR/2007/WD-selectors-api-20071221/"&gt;querySelectorAll&lt;/a&gt; on old versions of IE, using the browser’s native CSS engine. That sounds like a great idea at first, and the hack is quite clever. The idea is to dynamically add a CSS rule to the document that has the selector that you want to evaluate, and an expression that adds the matched elements to a global array.&lt;/p&gt;  &lt;p&gt;When I read this, it reminded me of a similar approach that I had tried a few years ago. At the time, we were considering implementing our own selector engine (we had not yet decided to integrate jQuery to our Ajax offerings, which in the end made the whole effort moot) so we explored a number of approaches.&lt;/p&gt;  &lt;p&gt;My idea was different in that it doesn’t use expressions at all. It does dynamically create a style rule, but instead of an expression, it just sets a non-existing “foo” style property to the equally arbitrary value of “bar”. It then scans the whole document (using the much decried and IE-specific but very fast document.all) and gets the computed style for each of the elements. We then look for the foo property on the resulting object and check whether it evaluates as “bar”. For each element that matches, we add to an array.&lt;/p&gt;  &lt;p&gt;Here’s the code:&lt;/p&gt;  &lt;pre class="code"&gt;(&lt;span style="color: blue"&gt;function&lt;/span&gt;() {
    &lt;span style="color: blue"&gt;var &lt;/span&gt;style = document.styleSheets[0] ||&lt;br /&gt;                document.createStyleSheet();
    window.select = &lt;span style="color: blue"&gt;function&lt;/span&gt;(selector) {
        style.addRule(selector, &lt;span style="color: #a31515"&gt;&amp;quot;foo:bar&amp;quot;&lt;/span&gt;);
        &lt;span style="color: blue"&gt;var &lt;/span&gt;all = document.all, resultSet = [];
        &lt;span style="color: blue"&gt;for &lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;i = 0, l = all.length; i &amp;lt; l; i++) {
            &lt;span style="color: blue"&gt;if &lt;/span&gt;(all[i].currentStyle.foo === &lt;span style="color: #a31515"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;) {
                resultSet[resultSet.length] = all[i];
            }
        }
        style.removeRule(0);
        &lt;span style="color: blue"&gt;return &lt;/span&gt;resultSet;
    }
})();&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;or, in minimized form:&lt;/p&gt;

&lt;pre class="code"&gt;(&lt;span style="color: blue"&gt;function&lt;/span&gt;(){&lt;span style="color: blue"&gt;var &lt;/span&gt;d=document;&lt;span style="color: blue"&gt;var &lt;/span&gt;a=d.styleSheets[0]||&lt;br /&gt;d.createStyleSheet();window.select=&lt;span style="color: blue"&gt;function&lt;/span&gt;(e){&lt;br /&gt;a.addRule(e,&lt;span style="color: #a31515"&gt;&amp;quot;f:b&amp;quot;&lt;/span&gt;);&lt;span style="color: blue"&gt;var &lt;/span&gt;l=d.all,c=[];&lt;br /&gt;&lt;span style="color: blue"&gt;for&lt;/span&gt;(&lt;span style="color: blue"&gt;var &lt;/span&gt;b=0,f=l.length;b&amp;lt;f;b++)&lt;span style="color: blue"&gt;if&lt;/span&gt;(l[b].currentStyle.f)&lt;br /&gt;c[c.length]=l[b];a.removeRule(0);&lt;span style="color: blue"&gt;return &lt;/span&gt;c}})()&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;That’s 235 characters, which is not too bad (although not quite #twitcode small).&lt;/p&gt;

&lt;p&gt;The first problem with that approach though is that because it’s using the native CSS selection engine in IE, it has the same limitations and quirks. That means no fancy CSS 3 (or even 2) selectors. It also means any IE bug will surface into the result set.&lt;/p&gt;

&lt;p&gt;In other words, if you want more selectors than that, you will need to parse the selector string and branch off the code to another, more complete engine whenever something not supported is used. It also means that you need to know what is supported and what isn’t. That could be done through some dynamic discovery but doing so, we are getting into much complexity.&lt;/p&gt;

&lt;p&gt;So limited as it is, how does it perform?&lt;/p&gt;

&lt;p&gt;I ran the code in a &lt;a href="http://code.google.com/p/slickspeed/"&gt;SlickSpeed&lt;/a&gt; test (where I removed the selectors that it couldn’t handle) on IE6 and the good news is that despite the document.all scan and the current style computation, it’s more than three times faster than &lt;a href="http://ajaxian.com/archives/creating-a-queryselector-for-ie-that-runs-at-native-speed"&gt;Paul Young’s implementation that got featured on Ajaxian&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But the bad news is that it’s also &lt;strong&gt;six times slower than jQuery:&lt;img style="border-bottom: 0px; border-left: 0px; margin: 5px auto; display: block; float: none; border-top: 0px; border-right: 0px" title="SlickSpeedResults" border="0" alt="SlickSpeedResults" src="http://weblogs.asp.net/blogs/bleroy/SlickSpeedResults_62B538FF.png" width="540" height="484" /&gt; &lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’m afraid a hack to use the native CSS selection engine of the browser is always going to be slower than an optimized pure JavaScript implementation (to be clear, I’m not talking about native implementations of querySelectorAll, but about hacks such as this which try to surface the feature on older IE versions that don’t have querySelectorAll). Somewhat counter-intuitive, but true.&lt;/p&gt;

&lt;p&gt;End of story. Just use jQuery. :)&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7187174" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/bleroy/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Microsoft+AJAX+Library/default.aspx">Microsoft AJAX Library</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Internet+Explorer/default.aspx">Internet Explorer</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/jQuery/default.aspx">jQuery</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/CSS/default.aspx">CSS</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/TwitCode/default.aspx">TwitCode</category></item><item><title>Why is ASP.NET encoding &amp;’s in script URLs? A tale of looking at entirely the wrong place for a cause to a non-existing bug.</title><link>http://weblogs.asp.net/bleroy/archive/2009/06/05/why-is-asp-net-encoding-amp-s-in-script-urls-a-tale-of-looking-at-entirely-the-wrong-place-for-a-cause-to-a-non-existing-bug.aspx</link><pubDate>Sat, 06 Jun 2009 00:27:15 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7109236</guid><dc:creator>Bertrand Le Roy</dc:creator><slash:comments>7</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/bleroy/rsscomments.aspx?PostID=7109236</wfw:commentRss><comments>http://weblogs.asp.net/bleroy/archive/2009/06/05/why-is-asp-net-encoding-amp-s-in-script-urls-a-tale-of-looking-at-entirely-the-wrong-place-for-a-cause-to-a-non-existing-bug.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://weblogs.asp.net/blogs/bleroy/Bug_50FD5922.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; margin: 0px 10px 0px 0px; display: inline; border-top: 0px; border-right: 0px" title="(c) Bertrand Le Roy 2003" border="0" alt="(c) Bertrand Le Roy 2003" align="left" src="http://weblogs.asp.net/blogs/bleroy/Bug_thumb_774F16A0.jpg" width="254" height="184" /&gt;&lt;/a&gt; Several people have &lt;a href="http://ajaxcontroltoolkit.codeplex.com/WorkItem/View.aspx?WorkItemId=13134"&gt;reported&lt;/a&gt; seeing errors in their logs that seem to be due to requests such as this:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;/ScriptResource.axd?d=     &lt;br /&gt;[lots of junk]&lt;strong&gt;&amp;amp;amp;       &lt;br /&gt;&lt;/strong&gt;t=ffffffffee24147c&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;The important part here is the HTML-encoded “&amp;amp;amp;” sequence, which stands for “&amp;amp;” of course. &lt;em&gt;If&lt;/em&gt; this exact URL is sent to the server, the server won’t know what to do with the escape sequence (URLs are not supposed to be HTML-encoded on the wire) so the parameters won’t get separated as expected, potentially resulting in a server error. This bug in the toolkit is an example of that: &lt;a href="http://ajaxcontroltoolkit.codeplex.com/WorkItem/View.aspx?WorkItemId=13134"&gt;http://ajaxcontroltoolkit.codeplex.com/WorkItem/View.aspx?WorkItemId=13134&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Of course, when people see 500 errors popping up in their server logs, they immediately assume the application is failing for some users. Or that some idiot at Microsoft did something incredibly stupid (that’s what we idiots at Microsoft do after all).&lt;/p&gt;  &lt;p&gt;Case in point, a quick peek into the source code of the application’s pages immediately reveals that the script tags generated by ScriptManager do indeed generate these URLs:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;&amp;lt;script src=&amp;quot;/ScriptResource.axd?d=[lots of junk]&amp;amp;amp;t=ffffffff8824ac28&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;So that’s where it came from! See? &lt;strong&gt;When I copy this URL into the browser’s URL bar, I do get the same error!&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Then ensue various more or less rational reactions such as:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Correlate the user agent to the faulty requests (which correlates more or less with normal browser usage, i.e. lots of IE and then lots of Firefox, when there is a large enough sample).&lt;/li&gt;    &lt;li&gt;Blame IE6 (lots of these requests come from IE6, hence it must be responsible: IE6 sucks).&lt;/li&gt;    &lt;li&gt;“Fix” ScriptManager and remove the HTML encoding.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Well, by copying the URL from the source view into the URL bar, you did indeed reproduce the problem. A little too well. Better than you realize.&lt;/p&gt;  &lt;p&gt;This is why. &lt;strong&gt;All of the errors in your server logs come from people doing precisely what you just did&lt;/strong&gt;: copy the URL from the source view into the browser’s URL bar. They do it for various reasons: look at the source code for the scripts, understand what these weird URLs are, who knows?&lt;/p&gt;  &lt;p&gt;But the point is, you will never be able to reproduce these errors during normal use of the application. There is nothing to fix here. The value that gets sent to the server never has the “&amp;amp;amp;” sequence. You can verify it in IE6, you can verify it in any browser on any OS, it will just work.&lt;/p&gt;  &lt;p&gt;When putting a URL in an HTML attribute, you should &lt;strong&gt;*always*&lt;/strong&gt; HTML-encode it. It’s the standard, and for good reason (it enables the browser to tell between “&amp;amp;”, “&amp;amp;amp;” and “&amp;amp;amp;amp;”, it enables quotes to be embedded into attributes, etc.).&lt;/p&gt;  &lt;p&gt;A consequence of that is that if you’re going to copy the value of one of these attributes from the source view, you should do what the browser does when parsing the HTML: decode the value first (in other words, replace “&amp;amp;amp;” with “&amp;amp;”).&lt;/p&gt;  &lt;p&gt;So yes, people do fail to do that and copy the URL without decoding. Well, they are not supposed to do that, nor do they need to do it. The error is normal, it results from a bad URL having been entered manually. Nobody would be surprised to get an error when querying foo.aspx?somenumber=thisisnotanumber for example. Same thing here. Pretty much.&lt;/p&gt;  &lt;p&gt;Of course, this is not entirely trivial to figure out and I did pull my remaining hair a bit trying to understand what was going on, and you tend to trust people when they tell you there is a problem, especially when the description seems to make sense. There is some sort of confirmation bias going on there. But the more I looked at the different pieces of evidence, the more this explanation looked like the most likely, by far.&lt;/p&gt;  &lt;p&gt;But of course, I may be missing something…&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=7109236" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/bleroy/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Atlas/default.aspx">Atlas</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Microsoft+AJAX+Library/default.aspx">Microsoft AJAX Library</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/HTML/default.aspx">HTML</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Internet+Explorer/default.aspx">Internet Explorer</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Ajax+Control+Toolkit/default.aspx">Ajax Control Toolkit</category></item><item><title>asp:menu fix for IE8 problem available</title><link>http://weblogs.asp.net/bleroy/archive/2009/03/23/asp-menu-fix-for-ie8-problem-available.aspx</link><pubDate>Mon, 23 Mar 2009 21:20:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6995426</guid><dc:creator>Bertrand Le Roy</dc:creator><slash:comments>51</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/bleroy/rsscomments.aspx?PostID=6995426</wfw:commentRss><comments>http://weblogs.asp.net/bleroy/archive/2009/03/23/asp-menu-fix-for-ie8-problem-available.aspx#comments</comments><description>&lt;p&gt;&lt;img style="border-bottom: 0px; border-left: 0px; margin: 0px 10px 0px 0px; display: inline; border-top: 0px; border-right: 0px" title="(c) 2003 Bertrand Le Roy" border="0" alt="(c) 2003 Bertrand Le Roy" align="left" src="http://weblogs.asp.net/blogs/bleroy/dscn22991_47AB4CCA.jpg" width="244" height="184" /&gt; Internet Explorer 8 is a unique release in the history of Internet Explorer in more than one way, but the decision to make standards mode the default means that authors of existing sites are impacted by it, if only to set the compatibility mode to IE7.&lt;/p&gt;  &lt;p&gt;But what if your site is built using components that render out markup and script over which you have little control, such as ASP.NET WebControls? Well, if one of the controls fails in IE8 standards mode, you need to either switch to compatibility mode (ouch!) or you need the component developer to ship an updated version.&lt;/p&gt;  &lt;p&gt;During the whole IE8 development cycle, we monitored the behavior of existing controls. Most ASP.NET built-in controls have been doing just fine in IE8, or the faulty behavior was actually due to an IE bug that we reported and that got fixed.&lt;/p&gt;  &lt;p&gt;All except asp:menu. It so happens that the menu control is making a bad assumption on what the default value for z-index should be. We debated this at length with the IE team, but it became clear as we did so that they were right and that we were wrong. We had to fix that.&lt;/p&gt;  &lt;p&gt;So here it is, the patch for menu is out and you can apply it to build IE8-compatible ASP.NET WebForms sites…&lt;/p&gt;  &lt;p&gt;Windows 2000, XP, Server 2003:   &lt;br /&gt;&lt;a href="http://code.msdn.microsoft.com/KB962351/Release/ProjectReleases.aspx?ReleaseId=2294"&gt;http://code.msdn.microsoft.com/KB962351/Release/ProjectReleases.aspx?ReleaseId=2294&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Windows Vista, Server 2008:   &lt;br /&gt;&lt;a href="http://code.msdn.microsoft.com/KB967535/Release/ProjectReleases.aspx?ReleaseId=2328"&gt;http://code.msdn.microsoft.com/KB967535/Release/ProjectReleases.aspx?ReleaseId=2328&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;b&gt;UPDATE:&lt;/b&gt; the KB article can now be found here:&lt;br/&gt;&lt;a href="http://support.microsoft.com/kb/962351"&gt;http://support.microsoft.com/kb/962351&lt;/a&gt;&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6995426" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/bleroy/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/HTML/default.aspx">HTML</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Microsoft/default.aspx">Microsoft</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Internet+Explorer/default.aspx">Internet Explorer</category></item><item><title>How to choose a client template engine</title><link>http://weblogs.asp.net/bleroy/archive/2009/02/05/how-to-choose-a-client-template-engine.aspx</link><pubDate>Thu, 05 Feb 2009 08:03:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6884165</guid><dc:creator>Bertrand Le Roy</dc:creator><slash:comments>10</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/bleroy/rsscomments.aspx?PostID=6884165</wfw:commentRss><comments>http://weblogs.asp.net/bleroy/archive/2009/02/05/how-to-choose-a-client-template-engine.aspx#comments</comments><description>&lt;p&gt;&lt;strong&gt;&lt;img style="border-right-width: 0px; margin: 0px 10px 0px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Water lenses, (c) 2007 Bertrand Le Roy" border="0" alt="Water lenses, (c) 2007 Bertrand Le Roy" align="left" src="http://weblogs.asp.net/blogs/bleroy/WaterLenses_40562071.jpg" width="244" height="164" /&gt; Disclaimer:&lt;/strong&gt; I worked on the &lt;a href="http://www.codeplex.com/aspnet/Wiki/View.aspx?title=AJAX"&gt;Microsoft Ajax 4.0&lt;/a&gt; template engine, so my criteria are of course heavily influenced by our own design.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Templates are a data rendering method that server-side developers have enjoyed since the old days of classic ASP and PHP. The idea was quite simple (add code blocks and dynamic expressions directly into HTML markup) but it revolutionized web development, which before that relied on the opposite method (spitting HTML from CGI code).&lt;/p&gt;  &lt;p&gt;On the client-side, the browser provides two ways to generate HTML: innerHTML and the DOM API. Template rendering is of course possible, but only using a JavaScript library. To be honest, one should mention XSLT here, which is standard and widely supported but whose somewhat unusual syntax has had limited success convincing web developers.&lt;/p&gt;  &lt;p&gt;There are literally dozens of template engines available today, using many different markup conventions and algorithms. Template engines are not equal, they have different levels of complexity, different feature sets, different security models. It can be quite hard to pick one, and it really depends on the requirements of your application and also on taste.&lt;/p&gt;  &lt;p&gt;I’ll try to go over a few things that you might want to check on a template engine. You will want to cherry-pick what’s important to you and what’s not so that you can pick the tool that’s best adapted to your problem.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1. Expression delimiter&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;A template system is adding new semantics to an existing language. This is not completely harmless as you have to give a new meaning to sequences of characters that were understood before as plain literals. That means that an escaping mechanism must exist to express the literal contents that were given a new meaning. For example, if the expression delimiters are &amp;lt;%= and %&amp;gt;, how do you express the “&amp;lt;%=” and “%&amp;gt;” sequences of characters as literals?&lt;/p&gt;  &lt;p&gt;&amp;lt;%= and %&amp;gt; are by far the most common and familiar delimiters (they have been used by ASP, PHP, JSP, ASP.NET and many others), but they have one flaw that couldn’t be seen back in 1996: XHTML compliance. Granted, you may not care at all about XHTML. If you don’t, just skip this. But if you do, any template engine that uses &amp;lt;%= %&amp;gt; simply can’t have template code that is XHTML-compliant. Now this may still not be a big deal if you don’t care that the template code is compliant, but only care about the generated markup.&lt;/p&gt;  &lt;p&gt;But there is another reason why &amp;lt;%= %&amp;gt; is a bad choice: it’s conflicting with the server-side. A client-side engine must be able to coexist peacefully with whatever server-side technology you’re using. If your server technology of choice is using &amp;lt;%= %&amp;gt; like it very likely does, it will be conflicting with your client templates. The server-side engine will kick in when it sees these delimiters and will fail one way or another.&lt;/p&gt;  &lt;p&gt;We chose {{ }} as the expression delimiter (and also {expr } for extensible markup expressions such as {binding }), which happens to be the same choice that Django made (and Dojo, as they implement Django on&amp;#160; the client-side, and by the way I don’t know how they manage conflict with server-side Django; if you know, drop me a comment). It works fine with XHTML and it doesn’t conflict with ASP or PHP. If you want to express the “{{“ literal, we don’t provide an escape sequence per se, but you can still do it by writing {{ “{{“ }}.&lt;/p&gt;  &lt;p&gt;On a final note, there are a few template engines that do not have expression delimiters but instead rely on microformats. While this absolutely preserves the HTML semantics, it’s often clumsier to use and quite limiting. It’s a matter of taste, but microformats also can look like markup within markup.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;2. Expression language&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In the simplest cases, you’ll want to inject a simple data field into the template, like {{ Price }}. But many times, you’ll want to go beyond those simple cases and embed a more complex expression into the markup. For example, you might want to display that price with two decimal places, like $42.00. In order to handle that case and more complex ones, it is necessary to have a full expression language.&lt;/p&gt;  &lt;p&gt;In the same way, if the template engine allows for code blocks to introduce control structures such as conditional execution or loops, it needs a full programming language.&lt;/p&gt;  &lt;p&gt;Some template engines, such as Django, introduce their own new language. Others, such as ours, just use what’s already available and familiar: JavaScript. In addition to being familiar, it eliminates the need to write a parser and interpreter, which reduces library code size and gives better performance.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;3. Protection against injection attacks&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;If you don’t know what an injection attack is… wow. Just wow. Go read &lt;a href="http://weblogs.asp.net/bleroy/archive/2004/08/18/please-please-please-learn-about-injection-attacks.aspx"&gt;this&lt;/a&gt;, now. Seriously.     &lt;br /&gt;&lt;a href="http://weblogs.asp.net/bleroy/archive/2004/08/18/please-please-please-learn-about-injection-attacks.aspx"&gt;http://weblogs.asp.net/bleroy/archive/2004/08/18/please-please-please-learn-about-injection-attacks.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The frightening thing about almost any single one of the client template engines out there is that they have no mechanism in place to protect against injection attacks, which puts the responsibility to encode and check contents in the hands of the application developer. That’s you.&lt;/p&gt;  &lt;p&gt;Most of the engines out there are using a very simple algorithm to build HTML: array joining, and then injecting the result using innerHTML. This is very similar to building SQL by concatenating strings: in a nutshell, you shouldn’t do that. In the same way that SQL is better built using parameterized queries, HTML is more securely built using the DOM API which just eliminates the need for encoding.&lt;/p&gt;  &lt;p&gt;Even when using encoding or the DOM API, there is a number of attributes that still present a fair amount of danger if user data gets injected in them. For example, if you bind the href attribute of a link to a piece of user data, no amount of encoding will protect the application against a user injecting “javascript:doSomeEvil();”.&lt;/p&gt;  &lt;p&gt;To prevent that kind of attack, we white-list the protocols in all known URL attributes to relative URLs, http and https. It is possible for the application to extend this white list as needed (available in Microsoft Ajax 4.0 Preview 4 and later).&lt;/p&gt;  &lt;p&gt;One thing to understand is that the dangerous contents here is the &lt;em&gt;data&lt;/em&gt;, not the template itself, which is trusted as application code is.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;4. Template location&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Depending on the library, the template can be embedded in comments, in script tags or just be part of the DOM. It can also be included from a separate file.&lt;/p&gt;  &lt;p&gt;Putting the template in comments or script tags easily hides its markup from initial rendering, but it makes it harder to design with existing tools and puts it out of the reach of markup validation tools.&lt;/p&gt;  &lt;p&gt;Including from a separate file adds one more request to the server, which might be a problem or not: it might also improve performance by allowing partial caching. The best is to have a choice here, so I’d reject an engine where external files is the only possibility, knowing that all other engines allow external files with minimal effort by feeding a simple XHR’s result into the system.&lt;/p&gt;  &lt;p&gt;Instead of using script tags or comments, we chose to embed the template as real HTML contents anywhere in the document and just hide it from initial rendering using CSS. This makes the code designable using any existing tool, and enables us to use the browser’s native HTML parser to understand the structure of the markup.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;5. Hooking up events and instantiating components&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;In a modern Web application, you won’t just create plain HTML, you’ll want to hook up events and instantiate components. The template engine might let you do this inline, which is obtrusive but convenient, or it might require you to enrich the DOM after template instantiation through code, or it might give you a choice between the two.&lt;/p&gt;  &lt;p&gt;One thing to look for is how much knowledge of the template markup’s shape must be injected into the code in order to enrich the DOM.&lt;/p&gt;  &lt;p&gt;For a picture of the different possibilities using our engine, read this post:    &lt;br /&gt;&lt;a href="http://weblogs.asp.net/bleroy/archive/2008/11/28/instantiating-components-on-template-markup.aspx"&gt;http://weblogs.asp.net/bleroy/archive/2008/11/28/instantiating-components-on-template-markup.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;6. Live bindings&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;One big advantage of client rendering is that the data remains under raw data form until it reaches the template engine. That means that you have a representation of the data on the client. This in turn means there is an opportunity to monitor changes to the data and to bind UI directly to it, eliminating round-trips to the server along the way.&lt;/p&gt;  &lt;p&gt;We call this ability live bindings and it makes for very responsive applications that are still easy to build.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;7. Constraints on markup shape&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;One thing you should try with any template engine is to repeat a row in a table, using IE. This may sound trivial, but innerHTML doesn’t work on IE in a number of places, which puts a constraint on the markup that you need to write to render certain shapes of HTML. There is almost always a workaround but it can be more or less painful to implement. Try and compare, see what you find reasonable.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;8. Ease of data field access&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This one is quite simple. Some template engines force you to access the current data item’s field through some special syntax such as “$T.price”. In our engine and several others, you just write “price”.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;9. Readability&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This one is quite subjective, but when choosing a template engine, just look at a few samples. Does the code hurt your eyes? Can you understand it right away?&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;10. Performance&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;A template engine must be able to render a reasonable number of data items with a reasonably complex template under the perception threshold. What’s “reasonable” pretty much depends on your application design, but I’d say a hundred items in a typical grid layout should be hardly noticeable. So before you choose, do a mock-up of your design and data and try it. Increase the number of items and see where rendering starts to get noticeable. Usually rendering performance is not linear so this should give you a good idea of how far you can go with each engine. Better to determine that before you invest heavily in one engine.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;11. XHTML compliance&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;As I said above, this is one you might not care about. Don’t leave yet, it actually goes both ways, as an engine, by enforcing XHTML compliance, might potentially get in the way of writing HTML the way you want.&lt;/p&gt;  &lt;p&gt;The lowest level of compliance is that the rendered output is compliant. Being template engines, most if not all engines enable you to create compliant or horribly broken markup, depending on your own style. What it must absolutely not do is &lt;em&gt;prevent&lt;/em&gt; you from generating compliant markup.&lt;/p&gt;  &lt;p&gt;The second level of compliance is that the template code itself, before data is injected, is compliant. This is much less common. Even less common is that the compliance requirement does not impose too strong a constraint on the markup you have to write.&lt;/p&gt;  &lt;p&gt;In other words, a good template engine lets you write XHTML but doesn’t force you to.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;12. Nested templates&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Rendering a template within a template might look like a whacky scenario at first if the engine understands control structures such as loops. In reality, if you include something like live bindings into the mix, you will want for example an inner template to be re-drawn when the outer data item changes. This will be much easier to achieve with nested templates.&lt;/p&gt;  &lt;p&gt;So if this is a scenario that you care about, make sure that your engine handles that case gracefully.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;In conclusion&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;There are many engines to choose from, and many criteria to check. I’m quite convinced that &lt;a href="http://www.codeplex.com/aspnet/Wiki/View.aspx?title=AJAX"&gt;our own offering is pretty solid&lt;/a&gt; for all these criteria and offers a good compromise of features against simplicity and performance.&lt;/p&gt;  &lt;p&gt;There is another engine that I quite like because it’s an impressively small bit of code that remains useful, and that is John Resig’s micro-template engine, which is only 20 lines of code. Like our own engine, it “compiles” the template into a reusable function that takes the data as a parameter. But unlike ours, it has no security mechanism and has issues with some markup, which may or may not be an issue for you. It’s a different kind of compromise that puts code size and simplicity before any other consideration.&lt;/p&gt;  &lt;p&gt;I hope this helps in making a choice.&lt;/p&gt;  &lt;p&gt;A good resource on client templates:    &lt;br /&gt;&lt;a href="http://ajaxpatterns.org/Browser-Side_Templating"&gt;http://ajaxpatterns.org/Browser-Side_Templating&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;John Resig’s micro-templates:    &lt;br /&gt;&lt;a href="http://ejohn.org/blog/javascript-micro-templating/"&gt;http://ejohn.org/blog/javascript-micro-templating/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;ASP.NET 4.0 Ajax Preview 3:    &lt;br /&gt;&lt;a title="http://www.codeplex.com/aspnet/Wiki/View.aspx?title=AJAX" href="http://www.codeplex.com/aspnet/Wiki/View.aspx?title=AJAX"&gt;http://www.codeplex.com/aspnet/Wiki/View.aspx?title=AJAX&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;UPDATE: &lt;/strong&gt;added performance and XHTML compliance to the list from Dave Reed’s feedback, and nested templates from Keith’s.&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6884165" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/bleroy/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Atlas/default.aspx">Atlas</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Microsoft+AJAX+Library/default.aspx">Microsoft AJAX Library</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/HTML/default.aspx">HTML</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Internet+Explorer/default.aspx">Internet Explorer</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Security/default.aspx">Security</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Injection/default.aspx">Injection</category></item><item><title>JavaScript Behavior Sheets: an experiment</title><link>http://weblogs.asp.net/bleroy/archive/2009/01/18/javascript-behavior-sheets-an-experiment.aspx</link><pubDate>Sun, 18 Jan 2009 08:53:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6843536</guid><dc:creator>Bertrand Le Roy</dc:creator><slash:comments>18</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/bleroy/rsscomments.aspx?PostID=6843536</wfw:commentRss><comments>http://weblogs.asp.net/bleroy/archive/2009/01/18/javascript-behavior-sheets-an-experiment.aspx#comments</comments><description>&lt;P&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; MARGIN: 0px 7px 0px 0px; DISPLAY: inline; BORDER-TOP: 0px; BORDER-RIGHT: 0px" title="(c) Bertrand Le Roy 2004" border=0 alt="(c) Bertrand Le Roy 2004" align=left src="http://weblogs.asp.net/blogs/bleroy/ZenShadows_7A57622D.jpg" width=164 height=244 mce_src="http://weblogs.asp.net/blogs/bleroy/ZenShadows_7A57622D.jpg"&gt; Here’s a little experiment. I’m really after feedback on this one as I’m trying to decide whether this is a good idea. It’s also entirely possible somebody else did this before. That would be good feedback too. Anyway, here it is.&lt;/P&gt;
&lt;P&gt;Despite its shortcomings, CSS has a number of features that make it very compelling. First, it decouples styling from markup. Second, its selector syntax is simple, yet reasonably powerful.&lt;/P&gt;
&lt;P&gt;So we have semantic markup on the one hand, and styles on the other hand, and the only coupling between the two is the selectors in the stylesheet.&lt;/P&gt;
&lt;P&gt;In Ajax applications, there is a third kind of entity in the mix, JavaScript behavior. There are of course ways to decouple the script behavior from the markup, which are usually referred to as &lt;A href="http://en.wikipedia.org/wiki/Unobtrusive_JavaScript" mce_href="http://en.wikipedia.org/wiki/Unobtrusive_JavaScript"&gt;unobtrusive JavaScript&lt;/A&gt;. &lt;A href="http://www.jquery.com/" mce_href="http://www.jquery.com"&gt;jQuery&lt;/A&gt; &lt;FONT face="Courier New"&gt;also &lt;/FONT&gt;introduced back in 2005 a way to associate script behavior with the DOM using the same selector syntax that CSS uses.&lt;/P&gt;
&lt;P&gt;But way before &lt;A href="http://jquery.com/" mce_href="http://jquery.com/"&gt;jQuery&lt;/A&gt;, &lt;A href="http://msdn.microsoft.com/en-us/library/ms532147.aspx" mce_href="http://msdn.microsoft.com/en-us/library/ms532147.aspx"&gt;Internet Explorer 5 enabled developers to specify behavior in stylesheets&lt;/A&gt;. You could do this for example:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: #a31515"&gt;.hilite &lt;/SPAN&gt;{ &lt;SPAN style="COLOR: red"&gt;behavior&lt;/SPAN&gt;:&lt;SPAN style="COLOR: blue"&gt;url(hilite.htc) &lt;/SPAN&gt;}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;This was a pretty neat idea at the time despite the challenges that came with it (in terms of performance for example), but it was never adopted by the other browsers despite having been &lt;A href="http://www.w3.org/TR/1999/WD-becss-19990804.html" mce_href="http://www.w3.org/TR/1999/WD-becss-19990804.html"&gt;submitted to W3C&lt;/A&gt;. The feature was never very widely used. There *is* &lt;A href="http://dean.edwards.name/moz-behaviors/overview/" mce_href="http://dean.edwards.name/moz-behaviors/overview/"&gt;a Firefox implementation of HTC behaviors&lt;/A&gt; but it doesn’t seem to have helped much in terms of adoption of this feature.&lt;/P&gt;
&lt;P&gt;And one thing that bothers me with that idea is that while it does decouple behavior from markup, it also &lt;EM&gt;couples&lt;/EM&gt; behavior to styling at least in location. Putting styles and behavior in the same file, in retrospect, looks like one step forward, and one step backwards. Sure, you could always use two separate files but the system did nothing to encourage you to do that.&lt;/P&gt;
&lt;P&gt;What I’m trying to do here is separate styling, markup *and* behavior, leverage selectors in a nice, declarative way &lt;EM&gt;à la&lt;/EM&gt; CSS and still work on all modern browsers. The coupling mechanism between style and markup (CSS selectors), is reasonably good and is already known by all Web developers so it remains a natural choice as jQuery showed clearly. Let’s see if one can express behavior in a way that is close to the already well-known CSS pattern.&lt;/P&gt;
&lt;P&gt;In this implementation, it is possible to add event handlers and Microsoft Ajax behaviors from a “JavaScript Behavior Sheet” which can be embedded in the page or be loaded from a separate file using a modified script tag:&lt;/P&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;script &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="text/behavior" &lt;/SPAN&gt;&lt;SPAN style="COLOR: red"&gt;src&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;="BehaviorSheet.jss"&amp;gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;script&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;The contents of the tag or file is in the simple JSON notation for an object, omitting the curly braces:&lt;/P&gt;&lt;PRE class=code&gt;"input[type=text].nomorethanfive": {
    click: function(e) {
        alert("You clicked input #" + e.target.id);
    },
    "Bleroy.Sample.CharCount": {
        maxLength: 5,
        overflow: function(source, args) {
            $(source.get_element()).jFade({
                 property: 'background',
                 start: 'FFFF00',
                 end: 'FFFFFF',
                 steps: 25,
                 duration: 30
            });
        }
    }
}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;The top-level entities that can be found in there are the CSS selectors (note the quotes that &lt;EM&gt;are&lt;/EM&gt; a departure from CSS notation but made the prototyping so much simpler). Each selector is associated with an object that contains event and object definitions.&lt;/P&gt;
&lt;P&gt;The event definitions consist in the event name and the handler to associate with it:&lt;/P&gt;&lt;PRE class=code&gt;click: function(e) {
    alert("You clicked input #" + e.target.id);
},&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;The implementation of this feature uses the new &lt;A href="http://docs.jquery.com/Events/live#typefn" mce_href="http://docs.jquery.com/Events/live#typefn"&gt;live events from jQuery&lt;/A&gt;. The result of that definition is that clicking on any input of type text with the class “nomorethanfive” will display an alert giving the id of the input that was clicked. That is a pretty efficient way to hook up events to multiple elements…&lt;/P&gt;
&lt;P&gt;The behavior instantiation specifies the class to instantiate, “Bleroy.Sample.CharCount” and lists the properties, fields and events to set (here, the maxLength property is set to 5 and the overflow event is hooked to a function that flashes the element’s background yellow):&lt;/P&gt;&lt;PRE class=code&gt;"Bleroy.Sample.CharCount": {
    maxLength: 5,
    overflow: function(source, args) {
        $(source.get_element()).jFade({
             property: 'background',
             start: 'FFFF00',
             end: 'FFFFFF',
             steps: 25,
             duration: 30
        });
    }
}&lt;/PRE&gt;
&lt;P&gt;Here’s what the page looks like: &lt;BR&gt;&lt;/P&gt;
&lt;DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; FLOAT: none; PADDING-TOP: 0px" id=scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:beb84b52-ccf2-4861-9ec4-3bb1f8e468bc class=wlWriterEditableSmartContent&gt;
&lt;DIV style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; DISPLAY: inline; PADDING-TOP: 0px" id=4314ce20-b9b6-441e-9466-068510fa6144&gt;
&lt;DIV&gt;&lt;A href="http://video.msn.com/video.aspx?vid=bd271e94-33e0-46fd-a09f-17c5ebe09f11" target=_new&gt;&lt;IMG style="BORDER-BOTTOM-STYLE: none; BORDER-RIGHT-STYLE: none; BORDER-TOP-STYLE: none; BORDER-LEFT-STYLE: none" alt="" src="http://weblogs.asp.net/blogs/bleroy/videofbd13523437b_5803F39D.jpg" onload="var downlevelDiv = document.getElementById('4314ce20-b9b6-441e-9466-068510fa6144'); downlevelDiv.innerHTML = &amp;quot;&lt;div&gt;&lt;embed src=\&amp;quot;http://images.video.msn.com/flash/soapbox1_1.swf\&amp;quot; quality=\&amp;quot;high\&amp;quot; width=\&amp;quot;432\&amp;quot; height=\&amp;quot;364\&amp;quot; wmode=\&amp;quot;transparent\&amp;quot; type=\&amp;quot;application/x-shockwave-flash\&amp;quot; pluginspage=\&amp;quot;http://macromedia.com/go/getflashplayer\&amp;quot; flashvars=\&amp;quot;c=v&amp;amp;v=bd271e94-33e0-46fd-a09f-17c5ebe09f11&amp;amp;from=writer&amp;amp;mkt=en-US\&amp;quot; &gt;&lt;\/embed&gt;&lt;\/div&gt;&amp;quot;;" galleryimg="no"&gt;&lt;/A&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;I should point out that while the events will handle DOM mutations (such as adding new elements that match the selector) just fine, component instantiation won’t in this implementation, which is a limitation that is quite hard to work around in current browsers.&lt;/P&gt;
&lt;P&gt;So here it is. All the code for this is &lt;A href="http://weblogs.asp.net/blogs/bleroy/Samples/BehaviorSheet.zip" mce_href="http://weblogs.asp.net/blogs/bleroy/Samples/BehaviorSheet.zip"&gt;available from the link below&lt;/A&gt; (contains &lt;A href="http://www.gimiti.com/kltan/wordpress/?p=43" mce_href="http://www.gimiti.com/kltan/wordpress/?p=43"&gt;jFade&lt;/A&gt;, code licensed under &lt;A href="http://opensource.org/licenses/mit-license.php" mce_href="http://opensource.org/licenses/mit-license.php"&gt;MIT&lt;/A&gt;: &lt;A href="http://jquery.com/" mce_href="http://jquery.com/"&gt;jQuery&lt;/A&gt;, and code under &lt;A href="http://opensource.org/licenses/ms-pl.html" mce_href="http://opensource.org/licenses/ms-pl.html"&gt;MS-PL&lt;/A&gt;: &lt;A href="http://www.asp.net/ajax/" mce_href="http://www.asp.net/ajax/"&gt;Microsoft Ajax&lt;/A&gt; and my own code), with some tests written with &lt;A href="http://weblogs.asp.net/bleroy/archive/2008/12/09/really-simple-testing-for-javascript.aspx" mce_href="http://weblogs.asp.net/bleroy/archive/2008/12/09/really-simple-testing-for-javascript.aspx"&gt;RST.js&lt;/A&gt;. So what do you think?&lt;/P&gt;
&lt;P&gt;&lt;A title=http://weblogs.asp.net/blogs/bleroy/Samples/BehaviorSheet.zip href="http://weblogs.asp.net/blogs/bleroy/Samples/BehaviorSheet.zip" mce_href="http://weblogs.asp.net/blogs/bleroy/Samples/BehaviorSheet.zip"&gt;http://weblogs.asp.net/blogs/bleroy/Samples/BehaviorSheet.zip&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;UPDATE:&lt;/STRONG&gt; interestingly, the intent behind &lt;A href="http://code.google.com/p/reglib/"&gt;Reglib&lt;/A&gt; by &lt;A href="http://blogs.sun.com/greimer/"&gt;Greg Reimer&lt;/A&gt; is pretty close to this and he even uses the words “Behavior Sheets”.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;UPDATE:&lt;/STRONG&gt; Stuart Langridge did &lt;A href="http://www.kryogenix.org/code/browser/jses/" mce_href="http://www.kryogenix.org/code/browser/jses/"&gt;something very close to declarative events as they are done here&lt;/A&gt; &lt;EM&gt;back in November 2003&lt;/EM&gt;. Thanks to Clayton for pointing that out. One should note that the limitations of the time are no longer preventing the technique from reaching its full potential.&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6843536" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/bleroy/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Atlas/default.aspx">Atlas</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Microsoft+AJAX+Library/default.aspx">Microsoft AJAX Library</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/HTML/default.aspx">HTML</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/JSON/default.aspx">JSON</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Internet+Explorer/default.aspx">Internet Explorer</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Firefox/default.aspx">Firefox</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/jQuery/default.aspx">jQuery</category></item><item><title>IE8: now with search that doesn't suck</title><link>http://weblogs.asp.net/bleroy/archive/2008/08/27/ie8-now-with-search-that-doesn-t-suck.aspx</link><pubDate>Wed, 27 Aug 2008 23:43:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6572682</guid><dc:creator>Bertrand Le Roy</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/bleroy/rsscomments.aspx?PostID=6572682</wfw:commentRss><comments>http://weblogs.asp.net/bleroy/archive/2008/08/27/ie8-now-with-search-that-doesn-t-suck.aspx#comments</comments><description>&lt;P&gt;I installed &lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyID=6ef71415-646f-4279-8b6b-193435ab2d80&amp;amp;DisplayLang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=6ef71415-646f-4279-8b6b-193435ab2d80&amp;amp;DisplayLang=en"&gt;IE8 Beta 2&lt;/A&gt; and tried CTRL+F this morning and here's what I got:&lt;/P&gt;
&lt;P&gt;&lt;A target=_blank href="http://weblogs.asp.net/blogs/bleroy/WindowsLiveWriter/IE8nowwithsearchthatdoesntsuck_EB44/SearchThatDoesntSuck.png" mce_href="http://weblogs.asp.net/blogs/bleroy/WindowsLiveWriter/IE8nowwithsearchthatdoesntsuck_EB44/SearchThatDoesntSuck.png"&gt;&lt;IMG style="BORDER-BOTTOM: 0px; BORDER-LEFT: 0px; BORDER-TOP: 0px; BORDER-RIGHT: 0px" border=0 alt="Search now well integrated in IE" src="http://weblogs.asp.net/blogs/bleroy/WindowsLiveWriter/IE8nowwithsearchthatdoesntsuck_EB44/SearchThatDoesntSuck_thumb.png" width=504 height=423 mce_src="http://weblogs.asp.net/blogs/bleroy/WindowsLiveWriter/IE8nowwithsearchthatdoesntsuck_EB44/SearchThatDoesntSuck_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Finally.&lt;/P&gt;
&lt;P&gt;Quite a lot of nice things in this beta actually... &lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6572682" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/bleroy/archive/tags/Internet+Explorer/default.aspx">Internet Explorer</category></item><item><title>Web development best practices finally made fun</title><link>http://weblogs.asp.net/bleroy/archive/2008/04/02/web-development-best-practices-finally-made-fun.aspx</link><pubDate>Wed, 02 Apr 2008 23:23:18 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6062044</guid><dc:creator>Bertrand Le Roy</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/bleroy/rsscomments.aspx?PostID=6062044</wfw:commentRss><comments>http://weblogs.asp.net/bleroy/archive/2008/04/02/web-development-best-practices-finally-made-fun.aspx#comments</comments><description>&lt;div style="padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px; display: inline" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:4a6f3336-310a-4593-ad21-d643da0091f6" class="wlWriterSmartContent"&gt;&lt;div id="1fc433ba-3388-459d-80da-ea7325f3f7b9" style="margin: 0px; padding: 0px; display: inline;"&gt;&lt;div&gt;&lt;a href="http://www.youtube.com/watch?v=a0qMe7Z3EYg&amp;amp;hl=en" target="_new"&gt;&lt;img src="http://weblogs.asp.net/blogs/bleroy/WindowsLiveWriter/Webdevelopmentbestpracticesfinallymadefu_E672/videob0b9f54899c6.jpg" galleryimg="no" onload="var downlevelDiv = document.getElementById('1fc433ba-3388-459d-80da-ea7325f3f7b9'); downlevelDiv.innerHTML = &amp;quot;&amp;lt;div&amp;gt;&amp;lt;object width=\&amp;quot;425\&amp;quot; height=\&amp;quot;350\&amp;quot;&amp;gt;&amp;lt;param name=\&amp;quot;movie\&amp;quot; value=\&amp;quot;http://www.youtube.com/v/a0qMe7Z3EYg&amp;amp;hl=en\&amp;quot;&amp;gt;&amp;lt;\/param&amp;gt;&amp;lt;param name=\&amp;quot;wmode\&amp;quot; value=\&amp;quot;transparent\&amp;quot;&amp;gt;&amp;lt;\/param&amp;gt;&amp;lt;embed src=\&amp;quot;http://www.youtube.com/v/a0qMe7Z3EYg&amp;amp;hl=en\&amp;quot; type=\&amp;quot;application/x-shockwave-flash\&amp;quot; wmode=\&amp;quot;transparent\&amp;quot; width=\&amp;quot;425\&amp;quot; height=\&amp;quot;350\&amp;quot;&amp;gt;&amp;lt;\/embed&amp;gt;&amp;lt;\/object&amp;gt;&amp;lt;\/div&amp;gt;&amp;quot;;" alt=""&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6062044" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/bleroy/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/HTML/default.aspx">HTML</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Safari/default.aspx">Safari</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Opera/default.aspx">Opera</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Internet+Explorer/default.aspx">Internet Explorer</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Firefox/default.aspx">Firefox</category></item><item><title>OpenAjax requests comments on browser wishlist</title><link>http://weblogs.asp.net/bleroy/archive/2008/04/01/openajax-requests-comments-on-browser-wishlist.aspx</link><pubDate>Tue, 01 Apr 2008 17:13:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:6057153</guid><dc:creator>Bertrand Le Roy</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/bleroy/rsscomments.aspx?PostID=6057153</wfw:commentRss><comments>http://weblogs.asp.net/bleroy/archive/2008/04/01/openajax-requests-comments-on-browser-wishlist.aspx#comments</comments><description>&lt;P mce_keep="true"&gt;The OpenAjax Alliance has been working with&amp;nbsp;some of the top Ajax developers&amp;nbsp;on a wishlist that aims at gathering and prioritizing the development features that we need the most from next generation browsers. The process is completely open and Wiki-based, so feel free to contribute.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;U&gt;&lt;FONT color=#800080&gt;&lt;A href="http://www.openajax.org/blogs/wp-trackback.php?p=53"&gt;http://www.openajax.org/blogs/wp-trackback.php?p=53&lt;/A&gt;&lt;/FONT&gt;&lt;/U&gt;&lt;A href="http://www.openajax.org/blogs/?p=53" mce_href="http://www.openajax.org/blogs/?p=53"&gt;&lt;/A&gt;&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=6057153" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/bleroy/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Microsoft+AJAX+Library/default.aspx">Microsoft AJAX Library</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/HTML/default.aspx">HTML</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/OpenAjax/default.aspx">OpenAjax</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Safari/default.aspx">Safari</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Opera/default.aspx">Opera</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Internet+Explorer/default.aspx">Internet Explorer</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Firefox/default.aspx">Firefox</category></item><item><title>IE8 to look forward: the Evil Empire listened</title><link>http://weblogs.asp.net/bleroy/archive/2008/03/03/ie8-to-look-forward-the-evil-empire-listened.aspx</link><pubDate>Tue, 04 Mar 2008 01:24:57 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:5909153</guid><dc:creator>Bertrand Le Roy</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/bleroy/rsscomments.aspx?PostID=5909153</wfw:commentRss><comments>http://weblogs.asp.net/bleroy/archive/2008/03/03/ie8-to-look-forward-the-evil-empire-listened.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://weblogs.asp.net/bleroy/archive/2008/01/25/a-honest-recap-of-the-ie8-meta-tag-controversy.aspx"&gt;I've said some time ago that I personally would have preferred if IE8 was in standard mode by default&lt;/a&gt;, that it made more sense in the long run at the price of moderate suffering in the short term.&lt;/p&gt;  &lt;p&gt;Well, it seems like announcing the &amp;quot;meta-tag&amp;quot; user agent switch well before the first public release of the new browser wasn't a random decision. The idea really was to stir up the debate well in advance and make it possible to revert their decision if the community reached a consensus that it was a bad one.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/ie/archive/2008/03/03/microsoft-s-interoperability-principles-and-ie8.aspx"&gt;And they just did&lt;/a&gt;. A few months later, the community almost unanimously rejected the idea more or less strongly and the IE team decided to follow that consensus and make the browser use the potentially breaking standard mode the default. It could be argued that the community really is the most vocal part of the developer audience and that they may and do have different opinions and preoccupations from the silent, real-world developers out there.&lt;/p&gt;  &lt;p&gt;Still, I think the IE team showed vision in announcing this enough in advance that they could act on the feedback, and great courage on potentially alienating some of their customers, just so they could do The Right Thing.&lt;/p&gt;  &lt;p&gt;Kudos, I'm impressed and glad that you guys are in command of the fate of IE.&lt;/p&gt;  &lt;p&gt;&lt;a title="http://blogs.msdn.com/ie/archive/2008/03/03/microsoft-s-interoperability-principles-and-ie8.aspx" href="http://blogs.msdn.com/ie/archive/2008/03/03/microsoft-s-interoperability-principles-and-ie8.aspx"&gt;http://blogs.msdn.com/ie/archive/2008/03/03/microsoft-s-interoperability-principles-and-ie8.aspx&lt;/a&gt;&lt;/p&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=5909153" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/bleroy/archive/tags/Internet+Explorer/default.aspx">Internet Explorer</category></item><item><title>Getting absolute coordinates from a DOM element</title><link>http://weblogs.asp.net/bleroy/archive/2008/01/29/getting-absolute-coordinates-from-a-dom-element.aspx</link><pubDate>Wed, 30 Jan 2008 01:51:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:5673801</guid><dc:creator>Bertrand Le Roy</dc:creator><slash:comments>20</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/bleroy/rsscomments.aspx?PostID=5673801</wfw:commentRss><comments>http://weblogs.asp.net/bleroy/archive/2008/01/29/getting-absolute-coordinates-from-a-dom-element.aspx#comments</comments><description>&lt;P&gt;For some reason, there is no standard API to get the pixel coordinates of a DOM element relative to the upper-left corner of the document. APIs only exist to get coordinates relative to the offset parent. Problem is, it's very important to get those coordinates for applications such as drag and drop, or whenever you need to compare coordinates of elements that may be in completely different parts of the document.&lt;/P&gt;
&lt;P&gt;In Microsoft Ajax, &lt;A class="" href="http://www.asp.net/AJAX/Documentation/Live/ClientReference/Sys.UI/DomElementClass/SysUIDomElementGetLocationMethod.aspx" mce_href="http://www.asp.net/AJAX/Documentation/Live/ClientReference/Sys.UI/DomElementClass/SysUIDomElementGetLocationMethod.aspx"&gt;we implemented such a function&lt;/A&gt;&amp;nbsp;(&lt;A class="" href="http://www.asp.net/AJAX/Documentation/Live/ClientReference/Sys.UI/DomElementClass/SysUIDomElementGetLocationMethod.aspx" mce_href="http://www.asp.net/AJAX/Documentation/Live/ClientReference/Sys.UI/DomElementClass/SysUIDomElementGetLocationMethod.aspx"&gt;Sys.UI.DomElement.getLocation&lt;/A&gt;) but it proved to be one of the most difficult problems we had to solve. Not so surprisingly, every single browser has its own coordinate quirks that make it almost impossible to get the right results with just capability detection. This is one of the very rare cases where we reluctantly had to use browser sniffing and implement a completely different version of the function for each browser.&lt;/P&gt;
&lt;P&gt;We also had to implement a pretty complex test suite to verify our algorithms for thousands of combinations of block or inline elements, offsets, scroll positions, frame containment, borders, etc., and run those on each browser that we support. The test suite in itself is quite interesting: it renders an element with the constraints to test, gets its coordinates from the API, creates a top-level semi-transparent element that is absolutely positioned and check that both overlap exactly to pixel precision. To do so, it takes a screen shot and analyses the image to find the rectangles and check their color.&lt;/P&gt;
&lt;P&gt;The simplest runtime implementation is the IE one, thanks to a little-known API that does almost exactly what we want: &lt;A href="http://msdn2.microsoft.com/en-us/library/ms536433.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms536433.aspx"&gt;getBoundingClientRect&lt;/A&gt;. &lt;EM&gt;Almost&lt;/EM&gt; exactly as we quickly discovered it has a weird 2-pixel offset except on IE6 if the HTML element has a border (which is a "feature" that was removed in IE7 and which we chose not to support). It also doesn't include the document's scroll position. Finally, if the element is in a frame, the frame border should be subtracted. This actually was the cause for &lt;A href="http://weblogs.asp.net/bleroy/archive/2007/01/31/how-to-work-around-the-quot-access-denied-quot-cross-domain-frame-issue-in-asp-net-ajax-1-0.aspx" mce_href="http://weblogs.asp.net/bleroy/archive/2007/01/31/how-to-work-around-the-quot-access-denied-quot-cross-domain-frame-issue-in-asp-net-ajax-1-0.aspx"&gt;a bug&lt;/A&gt; that we unfortunately discovered after we shipped 1.0 but which is now fixed in ASP.NET 3.5 as the parent frame may not be in the same domain, in which case attempting to get its frame border will result in an access denied error. So you need to do this in a try-catch and just accept the bad offset in that fringe scenario.&lt;/P&gt;
&lt;P&gt;In all other browsers, you currently need to recurse through the offset parents of the element and sum the offset coordinates.&lt;/P&gt;
&lt;P&gt;In Safari 2, though, the body's offset gets counted twice for absolutely-positioned elements that are direct children of body. Something you don't just guess, you need the thousands of test cases I mentioned earlier to discover something like that...&lt;/P&gt;
&lt;P&gt;In both Safari and Firefox, you must subtract to the coordinates the scroll positions of all &lt;STRONG&gt;parent nodes&lt;/STRONG&gt; (and not the offset parents like before). Well, except if the element is absolutely positioned (this last restriction doesn't apply to Opera). Or if the parent is the body or html element. Confused yet? Wait, there's more.&lt;/P&gt;
&lt;P&gt;In Firefox, non-absolutely positioned elements that are direct children of body get the body offset counted twice.&lt;/P&gt;
&lt;P&gt;In both IE and Firefox (but you don't care for IE as it has &lt;A href="http://msdn2.microsoft.com/en-us/library/ms536433.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/ms536433.aspx"&gt;getBoundingClientRect&lt;/A&gt;), the border of a table gets counted in both the border of the table and in the td's offset.&lt;/P&gt;
&lt;P&gt;Finally, on Opera, there are scroll values on elements that are not scrolled so you need to explicitly check for the overflow mode before you subtract scroll positions. Opera also includes the scrolling into the offsets, except for positioned contents.&lt;/P&gt;
&lt;P&gt;The worst part in all this is that we don't even know for sure that we nailed it, and we know that future browsers will require adjustments.&lt;/P&gt;
&lt;P&gt;Speaking of which... &lt;A href="http://developer.mozilla.org/en/docs/DOM:element.getBoundingClientRect" mce_href="http://developer.mozilla.org/en/docs/DOM:element.getBoundingClientRect"&gt;Firefox 3 will implement getBoundingClientRect&lt;/A&gt;. I haven't tried &lt;A href="https://bugzilla.mozilla.org/show_bug.cgi?id=174397" mce_href="https://bugzilla.mozilla.org/show_bug.cgi?id=174397"&gt;their implementation&lt;/A&gt; yet and checked whether it has the IE quirks, but it should be a lot simpler than what we have to work around today to do the same thing and we'll definitely have to rely on less undocumented quirks. By the way, if you were thinking of using the undocumented getBoxObjectFor, &lt;A href="https://bugzilla.mozilla.org/show_bug.cgi?id=340571" mce_href="https://bugzilla.mozilla.org/show_bug.cgi?id=340571"&gt;forget it, it was designed for XUL elements and will probably get removed from non-XUL elements in future versions&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;There is &lt;A href="http://bugs.webkit.org/show_bug.cgi?id=15897" mce_href="http://bugs.webkit.org/show_bug.cgi?id=15897"&gt;a bug open against WebKit to get that in Safari but it's currently without an owner&lt;/A&gt;. Here's to hoping this gets into the next version. Vote for it.&lt;/P&gt;
&lt;P&gt;Opera apparently also &lt;A href="http://www.opera.com/docs/changelogs/windows/950b1/index.dml" mce_href="http://www.opera.com/docs/changelogs/windows/950b1/index.dml"&gt;implements that in 9.5&lt;/A&gt;, referencing a &lt;A href="http://dev.w3.org/csswg/cssom/Overview.html#elementlayout-getclientrects" mce_href="http://dev.w3.org/csswg/cssom/Overview.html#elementlayout-getclientrects"&gt;W3C draft&lt;/A&gt; which curiously doesn't contain any references to getBoundingClientRect.&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=5673801" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/bleroy/archive/tags/Atlas/default.aspx">Atlas</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Microsoft+AJAX+Library/default.aspx">Microsoft AJAX Library</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/HTML/default.aspx">HTML</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Safari/default.aspx">Safari</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Opera/default.aspx">Opera</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Internet+Explorer/default.aspx">Internet Explorer</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Firefox/default.aspx">Firefox</category></item><item><title>A honest recap of the IE8 meta-tag controversy</title><link>http://weblogs.asp.net/bleroy/archive/2008/01/25/a-honest-recap-of-the-ie8-meta-tag-controversy.aspx</link><pubDate>Fri, 25 Jan 2008 20:43:00 GMT</pubDate><guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:5651996</guid><dc:creator>Bertrand Le Roy</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/bleroy/rsscomments.aspx?PostID=5651996</wfw:commentRss><comments>http://weblogs.asp.net/bleroy/archive/2008/01/25/a-honest-recap-of-the-ie8-meta-tag-controversy.aspx#comments</comments><description>&lt;P mce_keep="true"&gt;This will affect all Web developers, which is precisely why the debate is very heated. Anyway, here's a honest recap of the issue. I tend to agree with the author's conclusion although that is obvisouly not the position of Microsoft...&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;A href="http://arstechnica.com/articles/paedia/ie8-super-standards-mode.ars"&gt;http://arstechnica.com/articles/paedia/ie8-super-standards-mode.ars&lt;/A&gt;&lt;BR&gt;&lt;A href="http://arstechnica.com/articles/paedia/ie8-super-standards-mode.ars/2"&gt;http://arstechnica.com/articles/paedia/ie8-super-standards-mode.ars/2&lt;/A&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;STRONG&gt;Note:&lt;/STRONG&gt; at the smallest signs of a flame war, I will close the comments on this post. Ars has a good forum and comment system where your voice is much more likely to be heard and endlessly contradicted. ;)&lt;/P&gt;&lt;img src="http://weblogs.asp.net/aggbug.aspx?PostID=5651996" width="1" height="1"&gt;</description><category domain="http://weblogs.asp.net/bleroy/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/HTML/default.aspx">HTML</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Microsoft/default.aspx">Microsoft</category><category domain="http://weblogs.asp.net/bleroy/archive/tags/Internet+Explorer/default.aspx">Internet Explorer</category></item></channel></rss>