<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Julien Lecomte&#039;s Blog &#187; Web Development</title>
	<atom:link href="http://www.julienlecomte.net/blog/category/web-development/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.julienlecomte.net/blog</link>
	<description>Web Development, Operating System Programming and Amateur Astronomy</description>
	<lastBuildDate>Mon, 19 Jul 2010 16:11:13 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>O’Reilly Book &#8220;High Performance JavaScript&#8221; Now Available For Preorder</title>
		<link>http://www.julienlecomte.net/blog/2010/02/404/</link>
		<comments>http://www.julienlecomte.net/blog/2010/02/404/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 16:02:11 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/?p=404</guid>
		<description><![CDATA[
Last year, I was honored to be asked by Yahoo! engineer Nicholas Zakas whether I would be interested in contributing a chapter to an upcoming book about JavaScript performance. Well, after many months of hard labor by an impressive line up of talented engineers, this book, appropriately titled &#8220;High Performance JavaScript&#8221;, is now available for [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.amazon.com/dp/059680279X/" target="_blank"><img src="/blogfiles/20100203/high-performance-javascript-book-cover.gif" style="width:180px;height:236px;float:right;margin-left:10px;"></a></p>
<p>Last year, I was honored to be asked by Yahoo! engineer Nicholas Zakas whether I would be interested in contributing a chapter to an upcoming book about JavaScript performance. Well, after many months of hard labor by an impressive line up of talented engineers, this book, appropriately titled &#8220;High Performance JavaScript&#8221;, is now available for preorder on <a href="http://www.amazon.com/dp/059680279X/" target="_blank">amazon.com</a> (the book will be available on March 15<sup>th</sup> according to amazon). Here is the list of chapters:</p>
<ul>
<li>Loading and Execution</li>
<li>Data Access</li>
<li>DOM Scripting (<a href="http://www.phpied.com/">Stoyan Stefanov</a>)</li>
<li>Algorithms and Flow Control</li>
<li>Strings and Regular Expressions (<a href="http://blog.stevenlevithan.com/">Steven Levithan</a>)</li>
<li>Responsive Interfaces</li>
<li>Ajax (<a href="http://techfoolery.com/">Ross Harmes</a>)</li>
<li>Programming Practices</li>
<li>Build and Deployment (<a href="http://www.julienlecomte.net/">Julien Lecomte</a>)</li>
<li>Tools (Matt Sweeney)</li>
</ul>
<p><br style="clear:both;line-height:0;"/></p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2010/02/404/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>A Better Implementation Of The Input Prompt Pattern</title>
		<link>http://www.julienlecomte.net/blog/2009/09/314/</link>
		<comments>http://www.julienlecomte.net/blog/2009/09/314/#comments</comments>
		<pubDate>Mon, 14 Sep 2009 18:43:01 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/?p=314</guid>
		<description><![CDATA[The Input Prompt pattern consists in prefilling a text field with a prompt as a way of supplying help information for controls whose purpose or format may not be immediately clear. In the browser, this pattern is most often implemented by dynamically modifying the value property of a text field element via the focus and [...]]]></description>
			<content:encoded><![CDATA[<p>The Input Prompt pattern consists in prefilling a text field with a prompt as a way of supplying help information for controls whose purpose or format may not be immediately clear. In the browser, this pattern is most often implemented by dynamically modifying the <code>value</code> property of a text field element via the <code>focus</code> and <code>blur</code> event handlers attached to the text field, as shown in this example (<a href="/blogfiles/20090914/test-search-label-accessibility1.html">live demo</a>):</p>
<p>CSS:</p>
<pre class="prettyprint"><code>.hint {
  color: #999;
}</code></pre>
<p>Markup:</p>
<pre class="prettyprint"><code>&#60;input type="text" id="sbx"&#62;</code></pre>
<p>JavaScript (based on YUI 3.0.0):</p>
<pre class="prettyprint"><code>YUI().use('node', function (Y) {

    var sbx = Y.get('#sbx');

    Y.on('domready', function () {

        sbx.set('value', 'Search');
        sbx.addClass('hint');

        Y.on('focus', function () {
            if (this.get('value') === 'Search') {
                this.set('value', '');
                this.removeClass('hint');
            }
        }, sbx);

        Y.on('blur', function () {
            if (this.get('value') === '') {
                this.set('value', 'Search');
                this.addClass('hint');
            }
        }, sbx);

    });
});</code></pre>
<p><strong>Note:</strong> the code is intentionally implemented inside a <code>domready</code> event handler to work around issues related to form field caching.</p>
<p>The main problem with implementing this pattern using the <code>value</code> property is that the default text is used if the form is submitted while the input prompt is showing. Trying to work around this by testing the content of the text field when the form is submitted makes the default text impossible to use as a value. Another side effect of this implementation is that most developers will forget to attach a <code>&lt;label&gt;</code> element to the text field, leading to a confusing experience for screen reader users as they lack the necessary context to understand the purpose of the control.</p>
<p>A better implementation of this pattern consists in using a <code>&lt;label&gt;</code> element and positioning it on top of the text field it is attached to. Here is an example of this implementation (<a href="/blogfiles/20090914/test-search-label-accessibility2.html">live demo</a>):</p>
<p>CSS:</p>
<pre class="prettyprint"><code>#container {
    position: relative;
}

#container label {
    position: absolute;
    top: 4px; *top: 6px; left: 3px;
    color: #999;
    cursor: text;
}

#container label.offscreen {
    left: -9999px;
}</code></pre>
<p>Markup:</p>
<pre class="prettyprint"><code>&#60;div id="container"&#62;
    &#60;label for="sbx" class="offscreen">Search&#60;/label&#62;
    &#60;input type="text" id="sbx"&#62;
&#60;/div&#62;</code></pre>
<p>JavaScript (based on YUI 3.0.0):</p>
<pre class="prettyprint"><code>YUI().use('node', function (Y) {

    var sbx = Y.get('#sbx'),
        lbl = Y.get('#container label');

    Y.on('domready', function () {

        sbx.set('value', '');
        lbl.removeClass('offscreen');

        Y.on('mousedown', function () {
            setTimeout(function () {
                sbx.focus();
            }, 0);
        }, lbl);

        Y.on('focus', function () {
            lbl.addClass('offscreen');
        }, sbx);

        Y.on('blur', function () {
            if (sbx.get('value') === '') {
                sbx.set('value', '');
                lbl.removeClass('offscreen');
            }
        }, sbx);

    });
});</code></pre>
<p>As always, I am looking forward to reading your comments and answering your questions in the comments section of this blog.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2009/09/314/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>YUI Compressor now hosted on GitHub</title>
		<link>http://www.julienlecomte.net/blog/2009/07/273/</link>
		<comments>http://www.julienlecomte.net/blog/2009/07/273/#comments</comments>
		<pubDate>Fri, 10 Jul 2009 17:09:57 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/?p=273</guid>
		<description><![CDATA[I am pleased to announce that the YUI Compressor is now hosted on GitHub. Hopefully, this move will make the external contribution process more streamlined. Have fun coding!
]]></description>
			<content:encoded><![CDATA[<p>I am pleased to announce that the YUI Compressor is now <a href="http://github.com/yui/yuicompressor/tree/master">hosted on GitHub</a>. Hopefully, this move will make the external contribution process more streamlined. Have fun coding!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2009/07/273/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The YUI library source code is now hosted on GitHub</title>
		<link>http://www.julienlecomte.net/blog/2009/01/156/</link>
		<comments>http://www.julienlecomte.net/blog/2009/01/156/#comments</comments>
		<pubDate>Thu, 15 Jan 2009 06:09:30 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/?p=156</guid>
		<description><![CDATA[If you haven&#8217;t done so already, head over to the YUI Blog for the official announcement. I am proud to have made a (very modest) recent contribution to the library by porting the browser history utility to YUI3 (take a look at the source code) By the way, this new version of the browser history [...]]]></description>
			<content:encoded><![CDATA[<p>If you haven&#8217;t done so already, head over to the YUI Blog for the <a href="http://yuiblog.com/blog/2009/01/14/github/">official announcement</a>. I am proud to have made a (very modest) recent contribution to the library by porting the browser history utility to YUI3 (take a look at the <a href="http://github.com/yui/yui3/blob/master/src/history/js/history.js">source code</a>) By the way, this new version of the browser history utility supports Opera and IE8 (in both quirks mode and IE7 standards mode) Moreover, it has more features than the YUI2 version, should be easier to use, and weighs a few hundred bytes less (after minification with the YUI Compressor) I&#8217;ll try to find some time in the next few weeks/months to write a bit more about YUI3 in general, and the new browser history utility and the YUI Compressor. Stay tuned!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2009/01/156/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>YUI Compressor and Java Class Loader</title>
		<link>http://www.julienlecomte.net/blog/2008/10/80/</link>
		<comments>http://www.julienlecomte.net/blog/2008/10/80/#comments</comments>
		<pubDate>Wed, 22 Oct 2008 00:16:32 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/?p=80</guid>
		<description><![CDATA[The YUI Compressor uses a slightly modified version of the parser used in the Rhino JavaScript engine. The reason for modifying the parser came from the need to support JScript conditional comments, unescaped forward slashes in regular expressions &#8212; which all browsers support and many people use &#8212; and a few micro optimizations. The problem [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://www.julienlecomte.net/blog/2007/08/11/">YUI Compressor</a> uses a slightly modified version of the parser used in the <a href="http://www.mozilla.org/rhino/">Rhino</a> JavaScript engine. The reason for modifying the parser came from the need to support JScript conditional comments, unescaped forward slashes in regular expressions &#8212; which all browsers support and many people use &#8212; and a few micro optimizations. The problem is that many users had the original Rhino Jar file somewhere on their system, either in their classpath, or in their JRE extension directory (&lt;JRE_HOME&gt;/lib/ext) This caused many headaches because the wrong classes were being loaded, leading to many weird bugs.</p>
<p>Today, I finally decided to do something about it. This meant writing a custom class loader to load the modified classes directly from the YUI Compressor Jar file. You can download the source and binary package here:</p>
<p style="margin:30px 0;text-align:center;"><a href="/yuicompressor/" target="_blank" style="padding:8px;border:1px solid #bbb;font-weight:bold;text-decoration:underline;">Download version 2.4 of the YUI Compressor</a></p>
<p>The skeleton of the custom class loader is pretty straightforward:</p>
<pre class="prettyprint">
package com.yahoo.platform.yui.compressor;

public class JarClassLoader extends ClassLoader
{
    public Class loadClass(String name) throws ClassNotFoundException
    {
        // First check if the class is already loaded
        Class c = findLoadedClass(name);
        if (c == null) {
            // Try to load the class ourselves
            c = findClass(name);
        }

        if (c == null) {
            // Fall back to the system class loader
            c = ClassLoader.getSystemClassLoader().loadClass(name);
        }

        return c;
    }

    protected Class findClass(String name)
    {
        // Most of the heavy lifting takes place here
    }
}
</pre>
<p>The role of the <code>findClass</code> method is to first locate the YUI Compressor Jar file. To do that, we look in the classpath for a Jar file that contains the <code>com.yahoo.platform.yui.compressor.JarClassLoader</code> class:</p>
<pre class="prettyprint">
private static String jarPath;

private static String getJarPath()
{
    if (jarPath != null) {
        return jarPath;
    }

    String classname = JarClassLoader.class.getName().replace('.', '/') + ".class";
    String classpath = System.getProperty("java.class.path");
    String classpaths[] = classpath.split(System.getProperty("path.separator"));
    for (int i = 0; i < classpaths.length; i++) {
        String path = classpaths[i];
        JarFile jarFile = new JarFile(path);
        JarEntry jarEntry = findJarEntry(jarFile, classname);
        if (jarEntry != null) {
            jarPath = path;
            break;
        }
    }

    return jarPath;
}

private static JarEntry findJarEntry(JarFile jarFile, String entryName)
{
    Enumeration entries = jarFile.entries();
    while (entries.hasMoreElements()) {
        JarEntry entry = (JarEntry) entries.nextElement();
        if (entry.getName().equals(entryName)) {
            return entry;
        }
    }
    return null;
}
</pre>
<p>Once we know where the YUI Compressor Jar file is, we can load the appropriate class from that file. Note the need to define the package the class belongs to before calling <code>defineClass</code>!</p>
<pre class="prettyprint">
protected Class findClass(String name)
{
    Class c = null;
    String jarPath = getJarPath();
    if (jarPath != null) {
        JarFile jarFile = new JarFile(jarPath);
        c = loadClassData(jarFile, name);
    }
    return c;
}

private Class loadClassData(JarFile jarFile, String className)
{
    String entryName = className.replace('.', '/') + ".class";
    JarEntry jarEntry = findJarEntry(jarFile, entryName);
    if (jarEntry == null) {
        return null;
    }

    // Create the necessary package if needed...
    int index = className.lastIndexOf('.');
    if (index >= 0) {
        String packageName = className.substring(0, index);
        if (getPackage(packageName) == null) {
            definePackage(packageName, "", "", "", "", "", "", null);
        }
    }

    // Read the Jar File entry and define the class...
    InputStream is = jarFile.getInputStream(jarEntry);
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    copy(is, os);
    byte[] bytes = os.toByteArray();
    return defineClass(className, bytes, 0, bytes.length);
}

private void copy(InputStream in, OutputStream out)
{
    byte[] buf = new byte[1024];
    while (true) {
        int len = in.read(buf);
        if (len < 0) break;
        out.write(buf, 0, len);
    }
}
</pre>
<p>The last thing we need to do is bootstrap the application. In order to do that, we simply load the main class (<code>YUICompressor</code>) using our new custom class loader. All the classes that will be needed at runtime will use the same class loader:</p>
<pre class="prettyprint">
package com.yahoo.platform.yui.compressor;

public class Bootstrap
{
    public static void main(String args[]) throws Exception
    {
        ClassLoader loader = new JarClassLoader();
        Thread.currentThread().setContextClassLoader(loader);
        Class c = loader.loadClass(YUICompressor.class.getName());
        Method main = c.getMethod("main", new Class[]{String[].class});
        main.invoke(null, new Object[]{args});
    }
}
</pre>
<p>As you can see, it's not terribly complicated to write a custom class loader. Note: I left out all the exception handling code and the import statements for clarity. The final code can be found in the downloadable archive. Cheers!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2008/10/80/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Velocity Conference 2008</title>
		<link>http://www.julienlecomte.net/blog/2008/06/50/</link>
		<comments>http://www.julienlecomte.net/blog/2008/06/50/#comments</comments>
		<pubDate>Sat, 21 Jun 2008 01:45:55 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/?p=50</guid>
		<description><![CDATA[
I will be speaking at the Velocity Conference 2008 alongside my buddies and former co-workers Steve Souders and Bill Scott. The conference takes place on Monday, June 23 in Burlingame, CA. The topic of my presentation is High Performance Ajax Applications. I am also looking forward to attending all the other interesting talks.
Hope to see [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://en.oreilly.com/velocity2008/public/content/home"><img src="/blogfiles/images/velocity-conference-2008.jpg" style="width:240px;height:161px;padding:0;border:none;float:left;" alt="Velocity Conference 2008 Logo"></a></p>
<p>I will be speaking at the <a href="http://en.oreilly.com/velocity2008/public/content/home">Velocity Conference 2008</a> alongside my buddies and former co-workers <a href="http://www.souders.org/">Steve Souders</a> and <a href="http://looksgoodworkswell.blogspot.com/">Bill Scott</a>. The conference takes place on Monday, June 23 in Burlingame, CA. The topic of my presentation is <a href="http://en.oreilly.com/velocity2008/public/schedule/detail/1544">High Performance Ajax Applications</a>. I am also looking forward to attending all the other interesting talks.</p>
<p>Hope to see you all there!</p>
<div style="clear:both;"></div>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2008/06/50/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>JavaScript: The Good Parts</title>
		<link>http://www.julienlecomte.net/blog/2008/04/44/</link>
		<comments>http://www.julienlecomte.net/blog/2008/04/44/#comments</comments>
		<pubDate>Wed, 16 Apr 2008 18:59:32 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/2008/04/44/</guid>
		<description><![CDATA[
Douglas Crockford just published his first book titled JavaScript: The Good Parts. After reading this book, some of you may be left with the impression that Douglas is always complaining about some aspect of this very popular programming language. However, having been a user of the JavaScript language for about 7 years, and having used [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.oreilly.com/catalog/9780596517748/"><img src="/blogfiles/images/js-the-good-parts-cover.png" alt="JavaScript: The Good Parts (Book Cover)" style="width:180px;height:236px;float:left;margin-right:15px;border:none;padding:0;"></a></p>
<p><a href="http://www.crockford.com/">Douglas Crockford</a> just published his first book titled <a href="http://www.oreilly.com/catalog/9780596517748/">JavaScript: The Good Parts</a>. After reading this book, some of you may be left with the impression that Douglas is always complaining about some aspect of this very popular programming language. However, having been a user of the JavaScript language for about 7 years, and having used it extensively in small web sites and large web applications, all I can tell you is that I could not agree more with the author.</p>
<p>It is really unfortunate that we live in an imperfect world. As such, there is no perfect programming language, and there will probably never be. However, by gaining a deep understanding of the philosophy and the inner workings of a programming language, and by sticking to a subset of that language (what the author refers to as the &#8220;good parts&#8221;), we can all become better programmers by constructing more reliable and more maintainable programs.</p>
<p>In <a href="http://www.oreilly.com/catalog/9780596517748/">JavaScript: The Good Parts</a>, Douglas extensively describes that good subset of the JavaScript language, occasionally warning to avoid the bad. I consider Douglas&#8217; book a must-buy for anybody who&#8217;s serious about developing professional applications for the web. It&#8217;s definitely well worth the read!</p>
<div style="clear:both;"></div>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2008/04/44/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>YUI Compressor Version 2.3 Now Available</title>
		<link>http://www.julienlecomte.net/blog/2008/01/42/</link>
		<comments>http://www.julienlecomte.net/blog/2008/01/42/#comments</comments>
		<pubDate>Mon, 28 Jan 2008 22:17:30 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/2008/01/42/</guid>
		<description><![CDATA[This new version of the compressor fixes a few bugs and implements a few additional micro optimizations. Please refer to the CHANGELOG file for a complete list of changes, and don&#8217;t hesitate to report any issue you may experience with this version of the YUI Compressor.
Download version 2.3 of the YUI Compressor
]]></description>
			<content:encoded><![CDATA[<p>This new version of the compressor fixes a few bugs and implements a few additional micro optimizations. Please refer to the <a href="/yuicompressor/CHANGELOG" target="_blank">CHANGELOG</a> file for a complete list of changes, and don&#8217;t hesitate to report any issue you may experience with this version of the YUI Compressor.</p>
<p style="margin:30px 0;text-align:center;"><a href="/yuicompressor/" target="_blank" style="padding:8px;border:1px solid #bbb;font-weight:bold;text-decoration:underline;">Download version 2.3 of the YUI Compressor</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2008/01/42/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>High Performance Ajax Applications &#8211; Video Presentation</title>
		<link>http://www.julienlecomte.net/blog/2007/12/39/</link>
		<comments>http://www.julienlecomte.net/blog/2007/12/39/#comments</comments>
		<pubDate>Sat, 22 Dec 2007 12:07:06 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/2007/12/39/</guid>
		<description><![CDATA[
A few days ago, I gave a talk at Yahoo! about High Performance Ajax Applications. Eric Miraglia, from the YUI team, and Ricky Montalvo, from the Yahoo! Developer Network, were kind enough to shoot the video, edit it, and put it on the YUI Blog. In this talk, I cover the following topics:

Developing for high [...]]]></description>
			<content:encoded><![CDATA[<p><img src="/blogfiles/performance/video-snapshot.jpg" width="150" height="112" style="float:right;" alt="Video snapshot"></p>
<p style="margin-right:180px;">A few days ago, I gave a talk at Yahoo! about High Performance Ajax Applications. Eric Miraglia, from the YUI team, and Ricky Montalvo, from the Yahoo! Developer Network, were kind enough to shoot the video, edit it, and put it on the <a href="http://yuiblog.com/blog/2007/12/20/video-lecomte/" target="_blank">YUI Blog</a>. In this talk, I cover the following topics:</p>
<ul>
<li>Developing for high performance</li>
<li>High performance page load</li>
<li>High performance JavaScript</li>
<li>High performance DHTML</li>
<li>High performance layout and CSS</li>
<li>High performance Ajax</li>
<li>Performance measurement tools</li>
</ul>
<p>Follow along by downloading the <a href="/blogfiles/performance/ajax-perf.ppt">PowerPoint slides</a>, or by looking at the <a href="http://www.slideshare.net/julien.lecomte/high-performance-ajax-applications/" target="_blank">slides on Slideshare</a>. I&#8217;m looking forward to reading your comments and answering your questions in the comments section of this blog!</p>
<p><embed src="http://cosmos.bcst.yahoo.com/up/fop/embedflv/swf/fop_wrapper.swf?sv=0&amp;id=5557209&amp;autoStart=0&amp;infoEnable=1&amp;shareEnable=1&amp;prepanelEnable=1&amp;carouselEnable=0&amp;postpanelEnable=1" width="400" height="300" type="application/x-shockwave-flash"></embed></p>
<p><div class="blog-post-ad"><script type="text/javascript"><!--
google_ad_client = "pub-3574095397411323";
google_ad_slot = "4476010593";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
</div></p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2007/12/39/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>The Problem With innerHTML</title>
		<link>http://www.julienlecomte.net/blog/2007/12/38/</link>
		<comments>http://www.julienlecomte.net/blog/2007/12/38/#comments</comments>
		<pubDate>Thu, 13 Dec 2007 01:24:15 +0000</pubDate>
		<dc:creator>Julien Lecomte</dc:creator>
				<category><![CDATA[Web Development]]></category>

		<guid isPermaLink="false">http://www.julienlecomte.net/blog/2007/12/38/</guid>
		<description><![CDATA[The innerHTML property is extremely popular because it provides a simple way to completely replace the contents of an HTML element. Another way to do that is to use the DOM Level 2 API (removeChild, createElement, appendChild) but using innerHTML is by far the easiest and most efficient way to modify the DOM tree. However, [...]]]></description>
			<content:encoded><![CDATA[<p>The <code>innerHTML</code> property is extremely popular because it provides a simple way to completely replace the contents of an HTML element. Another way to do that is to use the DOM Level 2 API (<code>removeChild</code>, <code>createElement</code>, <code>appendChild</code>) but using <code>innerHTML</code> is by far the easiest and most efficient way to modify the DOM tree. However, <code>innerHTML</code> has few problems of its own that you need to be aware of:</p>
<ul>
<li>Improper handling of the <code>innerHTML</code> property can enable script-injection attacks on Internet Explorer when the HTML string contains a script tag marked as deffered: <code>&#60;script defer&#62;...&#60;script&#62;</code></li>
<li>Setting <code>innerHTML</code> will destroy existing HTML elements that have event handlers attached to them, potentially creating a memory leak on some browsers.</li>
</ul>
<p>There are a few other minor drawbacks worth mentioning:</p>
<ul>
<li>You don&#8217;t get back a reference to the element(s) you just created, forcing you to add code to retrieve those references manually (using the DOM APIs&hellip;)</li>
<li>You can&#8217;t set the <code>innerHTML</code> property on all HTML elements on all browsers (for instance, Internet Explorer won&#8217;t let you set the <code>innerHTML</code> property of a table row element)</li>
</ul>
<p>I am more concerned with the security and memory issues associated with using the <code>innerHTML</code> property. Obviously, this problem is nothing new, and very bright people have already figured out ways to work around some of these problems.</p>
<p><div class="blog-post-ad"><script type="text/javascript"><!--
google_ad_client = "pub-3574095397411323";
google_ad_slot = "4476010593";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
</div></p>
<p><a href="http://www.crockford.com/" target="_blank">Douglas Crockford</a> wrote a <a href="http://www.crockford.com/javascript/memory/leak.html" target="_blank"><code>purge</code></a> function that takes care of breaking some circular references caused by attaching event handlers to HTML elements, allowing the garbage collector to release all the memory associated with these HTML elements.</p>
<p>Removing the script tags from the HTML string is not as easy as it seems. A regular expression should do the trick, although it&#8217;s hard to know whether it covers all possible cases. Here is the one I came up with:</p>
<pre>
/&#60;script[^&#62;]*&#62;[\S\s]*?&#60;\/script[^&#62;]*&#62;/ig
</pre>
<p>Now, let&#8217;s put these two techniques together in a single <code>setInnerHTML</code> function (<strong>Update:</strong> Thanks to those who commented on this article. I fixed the errors/holes you mentioned, and also decided to bind the <code>setInnerHTML</code> function to <code>YAHOO.util.Dom</code>)</p>
<pre class="prettyprint">
YAHOO.util.Dom.setInnerHTML = function (el, html) {
    el = YAHOO.util.Dom.get(el);
    if (!el || typeof html !== 'string') {
        return null;
    }

    // Break circular references.
    (function (o) {

        var a = o.attributes, i, l, n, c;
        if (a) {
            l = a.length;
            for (i = 0; i < l; i += 1) {
                n = a[i].name;
                if (typeof o[n] === 'function') {
                    o[n] = null;
                }
            }
        }

        a = o.childNodes;

        if (a) {
            l = a.length;
            for (i = 0; i < l; i += 1) {
                c = o.childNodes[i];

                // Purge child nodes.
                arguments.callee(c);

                // Removes all listeners attached to the element via YUI's addListener.
                YAHOO.util.Event.purgeElement(c);
            }
        }

    })(el);

    // Remove scripts from HTML string, and set innerHTML property
    el.innerHTML = html.replace(/&#60;script[^&#62;]*&#62;[\S\s]*?&#60;\/script[^&#62;]*&#62;/ig, "");

    // Return a reference to the first child
    return el.firstChild;
};
</pre>
<p>Voila! Let me know if there is anything else that should be part of this function, or if I missed anything obvious in the regular expression.</p>
<p><div class="blog-post-ad"><script type="text/javascript"><!--
google_ad_client = "pub-3574095397411323";
google_ad_slot = "4476010593";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
</div></p>
<p><strong>Update:</strong> There are obviously many more ways to inject malicious code in a web page. The <code>setInnerHTML</code> function barely normalizes the <code>&#60;script&#62;</code> tag execution behavior across all A-grade browsers. If you are going to inject HTML code that cannot be trusted, make sure you sanitize it first on the server side. There are many libraries available for this.</p>
<p><strong>Update:</strong> IE8 has a new <code>toStaticHTML</code> function attached to the window object that removes any potentially executable content from an HTML string!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.julienlecomte.net/blog/2007/12/38/feed/</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
	</channel>
</rss>
