Archive for the 'Web Development' Category

Feb 03 2010

O’Reilly Book “High Performance JavaScript” Now Available For Preorder

Published by Julien Lecomte under Web Development

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 “High Performance JavaScript”, is now available for preorder on amazon.com (the book will be available on March 15th according to amazon). Here is the list of chapters:


One response so far

Sep 14 2009

A Better Implementation Of The Input Prompt Pattern

Published by Julien Lecomte under Web Development

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 blur event handlers attached to the text field, as shown in this example (live demo):

CSS:

.hint {
  color: #999;
}

Markup:

<input type="text" id="sbx">

JavaScript (based on YUI 3.0.0):

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);

    });
});

Note: the code is intentionally implemented inside a domready event handler to work around issues related to form field caching.

The main problem with implementing this pattern using the value 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 <label> 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.

A better implementation of this pattern consists in using a <label> element and positioning it on top of the text field it is attached to. Here is an example of this implementation (live demo):

CSS:

#container {
    position: relative;
}

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

#container label.offscreen {
    left: -9999px;
}

Markup:

<div id="container">
    <label for="sbx" class="offscreen">Search</label>
    <input type="text" id="sbx">
</div>

JavaScript (based on YUI 3.0.0):

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);

    });
});

As always, I am looking forward to reading your comments and answering your questions in the comments section of this blog.

8 responses so far

Jul 10 2009

YUI Compressor now hosted on GitHub

Published by Julien Lecomte under Web Development

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!

Comments Off

Jan 14 2009

The YUI library source code is now hosted on GitHub

Published by Julien Lecomte under Web Development

If you haven’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 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’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!

One response so far

Oct 21 2008

YUI Compressor and Java Class Loader

Published by Julien Lecomte under Web Development

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 — which all browsers support and many people use — 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 (<JRE_HOME>/lib/ext) This caused many headaches because the wrong classes were being loaded, leading to many weird bugs.

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:

Download version 2.4 of the YUI Compressor

The skeleton of the custom class loader is pretty straightforward:

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
    }
}

The role of the findClass 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 com.yahoo.platform.yui.compressor.JarClassLoader class:

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;
}

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 defineClass!

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);
    }
}

The last thing we need to do is bootstrap the application. In order to do that, we simply load the main class (YUICompressor) using our new custom class loader. All the classes that will be needed at runtime will use the same class loader:

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});
    }
}

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!

14 responses so far

Jun 20 2008

Velocity Conference 2008

Published by Julien Lecomte under Web Development

Velocity Conference 2008 Logo

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 you all there!

4 responses so far

Apr 16 2008

JavaScript: The Good Parts

Published by Julien Lecomte under Web Development

JavaScript: The Good Parts (Book Cover)

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 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.

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 “good parts”), we can all become better programmers by constructing more reliable and more maintainable programs.

In JavaScript: The Good Parts, Douglas extensively describes that good subset of the JavaScript language, occasionally warning to avoid the bad. I consider Douglas’ book a must-buy for anybody who’s serious about developing professional applications for the web. It’s definitely well worth the read!

One response so far

Jan 28 2008

YUI Compressor Version 2.3 Now Available

Published by Julien Lecomte under Web Development

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’t hesitate to report any issue you may experience with this version of the YUI Compressor.

Download version 2.3 of the YUI Compressor

19 responses so far

Dec 22 2007

High Performance Ajax Applications – Video Presentation

Published by Julien Lecomte under Web Development

Video snapshot

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 performance
  • High performance page load
  • High performance JavaScript
  • High performance DHTML
  • High performance layout and CSS
  • High performance Ajax
  • Performance measurement tools

Follow along by downloading the PowerPoint slides, or by looking at the slides on Slideshare. I’m looking forward to reading your comments and answering your questions in the comments section of this blog!

7 responses so far

Dec 12 2007

The Problem With innerHTML

Published by Julien Lecomte under Web Development

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, innerHTML has few problems of its own that you need to be aware of:

  • Improper handling of the innerHTML property can enable script-injection attacks on Internet Explorer when the HTML string contains a script tag marked as deffered: <script defer>...<script>
  • Setting innerHTML will destroy existing HTML elements that have event handlers attached to them, potentially creating a memory leak on some browsers.

There are a few other minor drawbacks worth mentioning:

  • You don’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…)
  • You can’t set the innerHTML property on all HTML elements on all browsers (for instance, Internet Explorer won’t let you set the innerHTML property of a table row element)

I am more concerned with the security and memory issues associated with using the innerHTML property. Obviously, this problem is nothing new, and very bright people have already figured out ways to work around some of these problems.

Douglas Crockford wrote a purge 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.

Removing the script tags from the HTML string is not as easy as it seems. A regular expression should do the trick, although it’s hard to know whether it covers all possible cases. Here is the one I came up with:

/<script[^>]*>[\S\s]*?<\/script[^>]*>/ig

Now, let’s put these two techniques together in a single setInnerHTML function (Update: Thanks to those who commented on this article. I fixed the errors/holes you mentioned, and also decided to bind the setInnerHTML function to YAHOO.util.Dom)

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(/<script[^>]*>[\S\s]*?<\/script[^>]*>/ig, "");

    // Return a reference to the first child
    return el.firstChild;
};

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.

Update: There are obviously many more ways to inject malicious code in a web page. The setInnerHTML function barely normalizes the <script> 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.

Update: IE8 has a new toStaticHTML function attached to the window object that removes any potentially executable content from an HTML string!

30 responses so far

Next »