24
Dec

Modular JavaScript Architecture

Update: This example has now grown into a full fledged, much better project, that you can check out on the Google Code page.

These days web development, and in particular JavaScript applications, are becoming more and more sophisticated and cumbersome. In addition to plenty of boilerplate code (I suggest you take a look at the HTML 5 Boilerplate), JavaScript programmers often find themselves copying over code they’ve written elsewhere into a new project, and integrating it with other code particular to that project. Managing these separate pieces of code that one finds themselves using in a project (or across multiple projects) can be trying at times. However, there is a solution.

A little while back, Nicholas Zakas from Yahoo! did a very interesting presentation on Scalable JavaScript Application Architecture. In it he described an architecture that separate pieces of a JavaScript application into separate modules based on the part of the HTML document that they interact with. Each module is only allowed to interact with that piece of markup, and has no direct link with the other modules. Modules are able to communicate indirectly with signals, sending a named signal containing data to modules that are listening for that signal.

The past two days I worked on my own architecture, based on his proposition, but with one major difference. His theoretical architecture has five layers of abstraction: library, base, core, sandbox, and modules. It also abstracts away the JavaScript library specific code, so that you can switch between different libraries like jQuery, YUI, Prototype, etc. His architecture is designed to not assume things. I decided that I could afford to do so, so I to take out the middleman, and created three layers of abstraction: jQuery, core, and modules. You sacrifice some of the scalability (being able to easily change JavaScript libraries without changing module code) for increased performance and ease of implementation.

I have an example of what the architecture is easily capable of here (with some Sammy.js thrown in for fun).

There are likely still some ways which I can improve, add to, and optimize this framework, but so far it seems to be working brilliantly.

Architecture Core


/*
 *************************************************************
 *
 * Title: Architecture Core
 * Author: Corey Schram
 *
 * Description: JavaScript Architecture Core. jQuery version.
 * This Application Architecture is designed to make developing
 * scalable, modular JavaScript applications easy and quicker.
 *
 * It uses jQuery for it's base.
 *
 * Created: 12/24/2010
 * Modified: 12/24/2010
 *
 *************************************************************
 */
// Self-Invoking Anonymous Function to create the Core Object
var Core = (function() {
    // Container for all loaded Modules
    var modules = {};
    // Signal Handlers
    var signals = {};
    /*
     * Summary: Send a signal to listening modules
     * Arguments: Signal object with the attributes 'type' and 'data'
     */
    function sendSignal(type, data) {
        if (signals.hasOwnProperty(type)) {
            for (var i = 0; i < signals[type].length; i++) {
                signals[type][i](data);
            }
        }
    }
    /*
     * Summary: Register a signal listener.
     * Arguments: Signal type and handler function
     */
    function registerSignal(type, handle) {
        if (signals.hasOwnProperty(type)) {
            signals[type].append(handle);
        } else {
            signals[type] = [handle];
        }
    }
    /*
     * Core Object
     */
    return {
        /*
         * Summary: Initialize the core. Initializes all Modules.
         */
        init : function () {
            for (var name in modules) {
                modules[name].init();
            }
        },
        /*
         * Summary: Create a new Module
         * Arguments: Module name (and id of the root element) and module object
         */
        createModule : function (name, obj) {
            var module = jQuery.extend($('#' + name), obj);
            module.send = sendSignal;
            module.register = registerSignal;
            modules[name] = module;
        },
        /*
         * Summary: Remove a module
         * Arguments: Module name and flag whether the root html element should
         * be deleted as well.
         */
        removeModule : function (name, deleteElem) {
            if (deleteElem) {
                modules[name].container.hide();
            }
            modules[name].destroy();
            delete modules[name];
        }
    };
}());

Module Example


/*
 *******************************************************
 *
 * Title: Test Module
 * Author: Corey Schram
 *
 * Description: Test JavaScript module for a test JavaScript Application
 * Architecture.
 *
 * Created: 12/23/2010
 * Modified: 12/23/2010
 *
 *******************************************************
 */
Core.createModule('header', {
    init : function (sammy) {
        var that = this;
        this.register('toggled', function (data) {
            if (data) {
                that.html('Closed');
            } else {
                that.html('Open');
            }
        });
    }
});
Core.createModule('test-module', {
    /*
     * Summary: Initiazer method. Called when the module is
     * initialized by the Core.
     */
    init : function () {
        this.collapsed = false;
        var that = this;
        this.find('.toggle-bar').click(function (event) {
            that.onToggle(event);
        });
    },
    /*
     * Summary: Destructor method. Called when the module is destroyed
     * by the core.
     */
    destroy : function () {
        this.unbind('click', this.onToggle);
    },
    /*
     * Summary: Event handler for when the toggle bar is pressed.
     */
    onToggle : function (event) {
        var content = this.find('.content');
        if (this.collapsed) {
            this.collapsed = false;
            content.slideDown(500);
            content.find('.inner').fadeIn(400);
        } else {
            this.collapsed = true;
            content.slideUp(500);
            content.find('.inner').fadeOut(250);
        }
        // Send a signal of the type 'toggled'
        this.send('toggled', this.collapsed);
    }
});
9
Oct

IE 6 Must Die

Any web developer will tell you that IE 6 is the bane of their existence. Despite being 9 years old, predating a large majority of the common practices and uses of the web today, it still has a firm grasp in the browser market share. In fact, it lost it’s place as the most widely used browser only eight months ago. This is a huge problem.

As you all are aware, we’ve come a long way since 2001. Since then JavaScript has become one of the most popular programming languages, finding it’s way onto nearly every website in the world; AJAX (Asynchronous Javascript and XML, used to load new content onto a page without reloading the whole page) was invented and has gained enormous popularity, with huge websites like Facebook basing their entire site architecture on it; HTML and CSS have evolved significantly, now with us arriving at HTML 5 and CSS 3 with more incredible features than ever; oh, did I mention that since 2001 this little company called Google has become one of the biggest companies in the world?

But we could have so much more. Even the advances we have made can’t be used as much as we’d like because some users just won’t update their ancient browsers. Use web developers have to spent a significant amount of time and effort writing workarounds, hacks, alternate stylesheets, etc, for browsers like IE 6. It’s bad enough that we have to make tweaks so that our sites look the same on all the latest versions of the major browsers (although the differences between rendering engines is getting smaller, thankfully), but we have to support browsers like IE 6 that don’t support half the features we use and don’t support the other half correctly. If users updated their browsers (or used browsers like Chrome and Firefox that will update for you, or at least alert you that you should) we could use all the current features as freely as we wanted. In fact, without that hindrance, we’d be much farther along in web advancement than we are now.

So, what should we do? Well, if you’re reading this in a browser that is not it’s latest version, upgrade. If your company uses older versions of browsers (usually IE 6 or 7), try to push for your company to use IE 8, or Firefox 3.6, or (my personal favorite) Google Chrome 6. Tell your friends to do the same. It’s for everyone’s benefit, not just the developers; newer browsers are faster, have more features, display websites better, and support more web features.

If you’re a web developer, what should you do? Douglas Crockford, in the talks he gave earlier this year, decreed that when all the major browsers support the latest JavaScript standard (ES5) that IE 6 MUST DIE. I’ll take it a step further: stop support IE 6 now. From now on, don’t try to support IE 6, make a redirect for users of older browsers, specifically IE 6, that will tell them to upgrade their browsers. Now, of course if a client requests IE 6 support and you can’t talk them out of it, you should do so, but otherwise it is up to us to faze IE 6 out of existence. Do your part, or we will forever be stuck in the stone age of the world wide web.

5
Oct

Use Sass to speed up your CSS

Lately I’ve been using Sass (Syntatically Awesome Stylesheets) to speed up my CSS work. With additions like nesting, variables, math operators, mixins (think C/C++ macro functions), inheritance, and built in helper functions, CSS is made even easier.

It’s syntax is simple enough. Any CSS file is also a valid Sass file, the additions are built on top of the CSS standard syntax.


@mixin rounded($radius: 6px) {
    border-radius: $radius;
    -moz-border-radius: $radius;
    -webkit-border-radius: $radius;
}
@mixin shadow($x, $y, $blur, $color) {
    -moz-box-shadow: $x $y $blur $color;
    -webkit-box-shadow: $x $y $blur $color;
    box-shadow: $x $y $blur $color;
}
.journalPost {
    width: 1000px;
    margin-bottom: 15px;
    .inner {
        @include rounded(5px);
        @include shadow(3px, 3px, 3px, #cccccc);
        width: 860px;
        color: #202020;
        padding: 5px 10px;
        text-shadow: #dddddd 0px 1px 1px;
        background-color: #ffffff;
        a {
            font-weight: bold;
            color: #ee5397;
            text-decoration: none;
        }
        img {
            position: relative;
            top: 20px;
            left: 650px;
        }
        p {
            width: 820px;
            padding: 10px 0px 0px 5px;
        }
    }
    .userimg {
        float: right;
        margin-top: 5px;
    }
}

I’ve made it a part of my workflow, with a batch script running while I work to automatically convert Sass CSS files (.scss extension) to normal CSS files. I keep a folder called scss/ and of course a css/ folder, and run this batch script while working:


sass --watch scss:css

That one line will automatically convert Sass files in the scss/ directory into css files in the css/ directory whenever they are updated.

Easy, right? I don’t think I’m ever going back to normal CSS again!

2
Oct

Tuts+ Network

Over the past few months I’ve been falling more and more in love with the Tuts+ Network, particularly the NetTuts+ site. They have some of the best tutorials, articles, and screen casts from some of the most knowledgeable people in the business. I think I can safely say I’ve doubled my abilities as a web developer over the past months thanks to NetTuts+.

I recently subscribed to their premium program, to get access to some of their better tutorials. It’s pretty cheap, only $9 a month to get access to all nine of their tutorial sites. It’s money well spent, I suggest you check out what they have to offer (quite a bit) and sign up.

Celadon theme by the Themes Boutique

Page optimized by WP Minify WordPress Plugin