The Roll Your Own Series From JSMag

I finally put together a page to host my articles published in JSMag for those of you who might have missed them. The articles, titled “Roll Your Own” and dealing with the proposition of creating a custom JavaScript library from scratch, will run about a month or so behind the magazine’s releases so if you like the columns go pick up the current issue here.

The ‘Roll Your Own’ columns.

Added Crockford’s JSLint to the ‘javascript-tools’ Textmate Bundle

The other day I forked the excellent javascript-tools Textmate bundle in order to add Douglas Crockford’s JSLint as an option to go along with JavaScriptLint and the Closure Compiler. You can find it here. I want to look at using Safari’s compiler in order to alleviate the Rhino dependancy, ad possibly include the newest jslint.js with a config file but, unfortunately, don’t have time at the moment. I will soon, but until then this early version at least fits in functionally and aesthetically with the rest of the bundle. Rhino is expected to be installed, as well as jslint,js to be located in ‘~/Library/JSLint’.

The enterprising can just open the bundle contents and hack away at the dclint.rb file to change any paths or dependencies. Hey look, screenshots!

Lint Menu

Added entry into the lint options menu

Jslint output

Fits into the bundle aesthetics

RML.post(#2)

Quick example of a header section of a web page that contains a few form elements done with RML:

  markup: {
    header: function() {
      var $header = RML.div({
        id:'header',
        content: RML.h1('The Chat') +
        RML.hr() +
        RML.div({
          class:'message-form',
          content: RML.textarea({
          name:'txt-message',
          id:'txt-message',
          rows:'4',
          cols:'60'
        }) + RML.input({
          type:'button',
          id:'btn-send-message',
          name:'btn-send-message',
          value:'Send Message',
        }) + RML.input({
          type:'button',
          id:'btn-clear-message',
          name:'btn-clear-message',
          value:'Clear Message',
        }) + RML.input({
          type:'button',
          id:'btn-logout',
          name:'btn-logout',
          value:'Log Out',
        })
      })
    });
    return $header;
    } //end header
  }

I’m using it here in a larger object literal method which can be called with a refinement like so:

HTML rendered by the RML methods
The rendered HTML

Get the code at github or here on the RML page. I’ll post more later this week…

Generate Markup with JavaScript

I am going to blog more in depth this weekend about this little markup generating JavaScript that I’m working on. I know there are others, but what fun is that? Basically, RML will generate tag-based markup like HTML and XML from JavaScript. I have been using it for templating alone and within a larger Ext.js application with pleasing results. I just need to add more tag shortcuts to the object, but it is very usable now. Get it here or at my github repo.

JSLint, Vim, and Windows XP

Just a quick post about integrating JSLint with Vim on a Windows XP machine. I had posted awhile back about integrating JavascriptLint with Vim on XP, but while re-reading The Good Parts I got the urge to revisit JSLint just to revel in the Crockfordness of it all…

First off, get Jesse Hallett’s excellent jslint.vim plugin here. I installed this on my Fedora box without a hitch (well, the only hitch was figuring out the name of the Spidermonkey package for Fedora 12, ‘js-devel’ I believe it was) but my work XP machine would spit this out when attempting a :jslint command:

Error detected while processing function <SNR>17_JSLint:
line  43:
E484: Con't open file C:\...\...\...\...\VIo1F3B.tmp

It’s obvious that some paths (literally, figuratively) were getting crossed somewhere (*Note you may also want to attempt to use cscript from the command line just to make sure it is, in fact, installed and working. I did, and mine was*.)

In my experience the first place to check for errors with Vim plugins is the PATH so I opened up Jesse’s plugin and focused on this section (lines 41-59 on his github repo version):

  let s:plugin_path = '"' . expand("~/") . '"'
  if has("win32")
    let s:cmd = 'cscript /NoLogo '
    let s:plugin_path = s:plugin_path . "vimfiles"
    let s:runjslint_ext = 'wsf'
  else
    if has("gui_macvim") && filereadable('/System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc')
      let s:cmd = '/System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc'
    else
      let s:cmd = 'js'
    endif
    let s:plugin_path = s:plugin_path . ".vim"
    let s:runjslint_ext = 'js'
  endif
  let s:plugin_path = s:plugin_path . "/plugin/jslint/"
  let s:cmd = "cd " . s:plugin_path . " && " . s:cmd . " " . s:plugin_path
               \ . "runjslint." . s:runjslint_ext
  let s:jslintrc_file = expand('~/.jslintrc')

Here’s the version I ended up with after experimenting for awhile:

let s:plugin_path = '"' . expand("C:/Program Files/Vim/vimfiles") . '"'
  let s:cmd = 'cscript /NoLogo '
  let s:runjslint_ext = 'wsf'
let s:plugin_path = s:plugin_path . "/plugin/jslint/"
let s:cmd = "cd " . s:plugin_path . " && " . s:cmd . " " . s:plugin_path
       \ . "runjslint." . s:runjslint_ext
let s:jslintrc_file = expand('C:/Program Files/Vim/_jslintrc')

So, I ended up changing 3 things:

  • Remove tests for which OS is being used
  • Explicitly state the plugin path
  • Changed the name and path of the jslintrc file

First, since we know this is for XP, the tests for Win32, Mac and ‘Nix are not needed. Second, there are more compact and portable ways to specify this path, but posting it this way makes it easy to adapt to your system path. Third, On my XP system my .vimrc is actually _vimrc and I keep it here in the vimfiles directory so it made sense to me to do the same with a jslintrc.

Speaking of the _jslintrc, it looks like the ‘fulljslint.js’ file is updated quite a bit on the jslint.com website, and allows for more options in the jslintrc file. I need to experiment with that next

X JavaScript: Detecting, Adding and Removing Class Names

I want to post a quick bit here about three methods I use in the X library which make use of element classnames. First a method to detect if an element has a given class:

X.hasClass = function(element, $class) {
    var pattern = new RegExp("(^| )" + $class + "( |$)");
    //ternary to choose
    return pattern.test(element.className) ? true : false;
};

Breaking that down, you have the function taking two arguments. One, the element to check for the presence of the class name and two, the class name itself. Next, a RegEx is defined which will attempt to match the class name you passed in. The RexEx itself is made so that a portion of a string can be matched because of the way that classnames are applied to elements on the DOM, i.e. “spam eggs vikings”. Last, the ternary (return pattern.test…) executes depending on what the test() method returns. Remember, test() is a function of the RegEx object which returns a bool depending on a positive(or lack of) match. Test() is going to return a ‘true’ of the class name is found, ‘false’ if not.If you are unfamiliar with ternary operators, let’s explain by looking at what an if/else doing the same thing would look like.

if (pattern.test(element.className)) {
    return true;
}
else {
    return false;
}

That works, but it’s not the lean and mean js machine we are going for here. Now, the one line of the ternary:

return pattern.test(element.className) ? true : false;

And it works like this:
an action -something to evaluate- ? do if true : do if false

So, in practice you could check if an element had a class name by calling:

X.hasClass(myElement, 'myClass');

hasClass is going to return a Bool though, so usually you will use it as part of an expression:

if(X.hasClass(myElement, 'myClass') {
    do stuff if true
}

I rarely use hasClass outright, but the next function does.

To add a class to a single element or a collection of elements we have this:

X.addClass = function(element, $class) {
    var i;
    //is the element array-like?
    if(element.length) {
        for (i = 0; i < element.length; i++) {
            if (!X.hasClass(element[i], $class)) {
                element[i].className += element[i].className === "" ?
                $class : " "+$class;
            }
        }
    }
    else { //not array-like
        if (!X.hasClass(element, $class)) {
            element.className += element.className === "" ?
                $class : " "+$class;
        }
    }
    return element;
};

In Summary, addClass takes 2 arguments, an element and a class name, checks to see if the element passed in is a single element or a collection of elements, then checks the element(s) to see if they have the passed in class name (via hasClass). If not, element is then checked for the presence of any other classes. Why? If there is another class name already assigned to the element(s) you need to insert a space in front of the new class being appended. Finally the class name you passed in is appended (as long as it’s not already there) and the element is returned. Let’s combine the get method with this in a couple of practical examples:

Say you have an HTML page with these four divs contained in a fifth div:

<div id="stripes">
    <div id="div1"></div>
    <div id="div2"></div>
    <div id="div3"></div>
    <div id="div4"></div>
</div>

And maybe some styles to go with them:

#div1, #div2, #div3, #div4 {
    height: 50px;
    margin-top:10px;
    border-bottom: 1px solid #000;
}
.green {
    background-color: #7f9e7b;
}
.slate {
    background-color: #424242;
}
.grey {
    background-color: #888;
}

So, on a goofy little test page you might have this:

Classless divs

Classless divs


Since the get method returns either a single element or a collection of them, and since our new addClass function can handle either scenario you could grab all those divs and set their background to say, green, in one pass:

X.addClass(X.get('div', X.get('#stripes')), 'green');

Giving you this:

Now with some class (green to be exact)

Now with some class (green to be exact)

Breaking that expression down, recall that the get method will allow you to pass in a ‘context’ to restrain searching. Because I only wanted the divs inside of the div with the id of “stripes” I passed it (‘#stripes’) in along with the search for the generic ‘div’ tagname:

var divs = X.get('div', X.get('#stripes'));

You can break this up into 2 expressions if you want:

var stripes = X.get('#stripes');
var divs = X.get('div', stripes);

After getting the elements, I sent them to addClass. If you used the more verbose code above you would have:

var stripes = X.get('#stripes');
var divs = X.get('div', stripes);
X.addclass(divs, 'green');

In these examples the fact that addClass returns the element passed in is of no consequence. JavaScript functions always return a value, even if one is not specified (undefined in that case), so specifying element as the return value could just be ignored, but we are going to use it next to combine with removeClass.

Here is that removeClass function:

X.removeClass = function(element, $class) {
    var pattern = new RegExp("(^| )" + $class + "( |$)"),
    i;
    //is element array-like?
    if(element.length) {
        for (i = 0; i < element.length; i++) {
            element[i].className = element[i].className.replace(pattern, "$1");
            element[i].className = element[i].className.replace(/ $/, "");            
        }
    }
    else { //nope
        element.className = element.className.replace(pattern, "$1");
        element.className = element.className.replace(/ $/, "");
    }
    return element;
};

Before doing something pedestrian like just removing the ‘green’ classnames from the divs inside of ‘stripes’ let’s swing for the fence and remove the classnames, then add new ones all in one go. weeee!:

X.removeClass(X.addClass(X.get('div', X.get('#stripes')), 'slate'), 'green');

Now that test page would look like:

Class changed to 'slate'

Class changed to 'slate'

This works because of the fact that addClass is returning the element list containing all of the divs we want removeClass to operate on. If you look close you’ll notice that all you needed to do was to take the previous expression we used for adding the green classes at once:

X.addClass(X.get('div', X.get('#stripes')), 'green');

and wrapping it with the removeClass call:

X.removeClass([--previous expression--], 'slate');

There’s more to breakdown, but not too much. The removeClass function just uses the same methodology that addClass does for checking if element is an array-like object (has a length?) then looks for the passed in classname with a RegExp which will replace a match with an empty string using the ‘$1′ backreference (the second call to replace makes sure no whitespace is left over). Finally the element is returned, just like addClass. And, yes, you could invert the order to addClass(removeClass()), it doesn’t matter

All of these examples could have, obviously, been used on single elements. X.get, X.addClass and X.removeClass will take care of that for you. So if you wanted to change the second div back to green you would go:

X.removeClass(X.addClass(X.get('#div2'), 'green'), 'slate');

Notice there is no need to specify a context when using an id (it should be unique).

Emacs, CEDET, Windows and GIT. Success!

Quick post here because I’ll probably need this myself later. I didn’t have any problems getting Emacs, CEDET, and ECB up and running on my Fedora box but my WinXP machine refused to byte-compile the cedet-build.el lisp file. This looks to be a common problem for folks using Emacs on Win with CEDET’s latest files from Sourceforge. After seeing that some people had success after getting the newest CVS repository files for CEDET I immediately searched for a git mirror (not wanting to have to use CVS) and found it here

The instructions on CEDET’s website are:
“If you are on Windows, and or don’t have make for some reason, you can use CEDET’s built in project management system to force CEDET to bootstrap itself. You can initiate the build process like this:”

    cd path/to/cedetdirectory
    emacs -Q -l cedet-build.el -f cedet-build

Since the Windows version of Emacs is in a self contained directory (mine is emacs-23.1/) with an executable named ‘runemacs.exe’ in the folder ‘emacs-23.1/bin/’ on my Desktop, I just changed the command to fit the environment properly. Opening a Cygwin bash prompt I did this:

$ cd ~/Desktop/cedet/
$ ~/Desktop/emacs-23.1/bin/runemacs.exe -Q -l cedet-build.el -f cedet-build

AND the freezing on step 6, setting up EDE goes away. ECB can now be setup

Integrating JavaScriptLint With Vim On Windows

I use Vim to code JavaScript on my work machine, a PC running WinXp. Looking around for a way to integrate a good lint program to catch typical .js errors I found JavaScriptLint.vim. The instructions there are simple, drop the script in your vim/plugins folder after the jsl.exe program has been installed. That executable, the javascriptlint program itself, has good documentation for Vim integration on Linux (which works well btw) but none for Windows. Here is what I did:

  • First, download the version for windows here
  • Extract that .zip anywhere, doesn’t matter
  • From the extracted folder grab the jsl.exe and jsl.default.conf files and put them in your C:\Program Files\Vim\Vim72 folder (If you’re using Vim 7.2, I would assume other versions have a similar folder structure. It’s the same directory the gvim.exe, vim.exe and others are in).
  • Drop the JavaScriptLint.vim file in C:\Program Files\Vim\vim72\plugin

Now, you’re almost done. Open up the jsl.default.conf file in a text editor and in the ‘Defining Identifiers’ section enable ‘always_use_option_explicit’ like so:

### Defining identifiers
# By default, "option explicit" is enabled on a per-file basis.
# To enable this for all files, use "+always_use_option_explicit"
+always_use_option_explicit

Also, just below the ‘common uses for webpages might be: line I added these, a la Ken Guest:

# Common uses for webpages might be:
+define ActiveXObject
+define addEventListener
+define alert
+define attributes
+define blur
+define childNodes
+define click
+define clearTimeout
+define dispatchEvent
+define document
+define firstChild
+define focus
+define Image
+define item
+define lastChild
+define localName
+define namespaceURI
+define navigator
+define nextSibling
+define nodeName
+define nodeType
+define nodeValue
+define ownerDocument
+define parent
+define parentNode
+define prefix
+define previousSibling
+define removeEventListener
+define screen
+define scrollIntoView
+define setTimeout
+define tagName
+define window
+define XMLHttpRequest

The last thing I did, and this just because it looked like the correct thing to do, was I commented out the ‘files’ section test file since Vim is sending the file for me (and since I didn’t drop that file in from the extracted folder anyway…):

### Files
# Specify which files to lint
# Use "+recurse" to enable recursion (disabled by default).
# To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
# or "+process Folder\Path\*.htm".
#
#+process jsl-test.js

Now, Action! Let’s say I just hacked together this object literal (which, I just did…) and saved it, seems OK, no errors reported:

Not triggering the .js lint error messages

Not triggering the .js lint error messages


Now, what if I had forgot to put a semicolon after the loadMap() function call in the objects init: and then saved?
Error warning triggered

Error warning triggered


The ‘quickfix’ window opens with the error highlighted. The line number here seems to be incorrect as line 23 is where the closing brace is, the actual missing semicolon should be on line 21. This is, however, the first run and may be a matter of configuration. Still a great start I think

QueryString Manipulation With The X JavaScript Library

I’ve spent a couple of days lately coding against the Microsoft Bing maps api at work. I just put together a little method this morning to mimic .Net’s ‘Request.Querystring’ functionality because I am needing to grab either a zip code or a latitude/longitude from the URL. The function, named requestQueryString(), expects a string to be passed in which should be a ‘key’ part in one of the key:value pairs located in the url of the page being viewed. In other words, if the URL is

www.apage.aspx?zip=85226&lat=33.372154&lon=-111.754322

the ‘keys’ are ‘zip’, ‘lat’ and ‘lon’, while the values are ’85226′, ’33.372154′ and ‘-111.754322′. To fetch the value associated with zip you would do:

var zipcode = X.requestQueryString('zip');

This will return ’85226′ given the previous URL. For ‘lat’ or ‘lon’ it would be pretty much the same:

var latitude = X.requestQueryString('lat'),
longitude = X.requestQueryString('lat');

Here is the method itself. I’ll update the x.js page with the new code as well.

X.requestQueryString = function(key) {
    //get the whole qs minus the ?
    var qs = window.location.search.substring(1),
    //split at the '&'
    splitArr = qs.split('&'),
    //to hold what we really want
    keys = [],
    values = [],
    //the key passed in to get the value for
    patt = new RegExp("(^| )" + key + "( |$)");
    //remove any whitespace TODO do a bool to see if the qs has any %20's
    for (var i = 0; i < splitArr.length; i++) {
        var trimArr = splitArr[i].split('%');
        //dont want the '%20s'
        splitArr[i] = trimArr[0];
    }
    //split the arr into key & value arrays
    for (var j = 0; j < splitArr.length; j++) {
        keys[j] = splitArr[j].slice(0,splitArr[j].indexOf("="));
        values[j] = splitArr[j].slice(splitArr[j].indexOf("=")+1);
    }
    //look for a match for passed in key, if so...
    for (var k = 0; k < keys.length; k++) {
        //if key is matched, return its value
        if (patt.test(keys[k])) {
            return values[k];
        }
    }
};

It’s an early implementation and a couple of things are worth noting. I had an issue with whitespace because I get the lat/lon numbers from a webservice maintained elsewhere in my company, and elsewhere is not properly constraining the input. You could remove this:

for (var i = 0; i < splitArr.length; i++) {
        var trimArr = splitArr[i].split('%');
        //dont want the '%20s'
        splitArr[i] = trimArr[0];
}

if you know that whitespace will not be an issue. Leaving it in place doesn’t add much of any overhead as the split command will just do nothing as it won’t see any ‘%’.

X: Pt4. Object Literals, Convenience Methods, And Go!

Now that we have a shiny new object created called ‘X’, Let’s use it. I like to organize all of my JavaScripts by incorporating object literals (see Rebecca Murphey’s talk on the closely related object lateral [that's a joke btw, it was a misprint at jconf], the excellent book Simply Javascript, and of course The Good Parts ). Here’s a ‘stub’ for the objects we could use:

    var ObjectName = {
   
        cache: {},
        config: {},
        init: function() {},
        otherThing: function() {}
    }

I will typically use the ObjectName.cache{} to hold a snapshot of the page, or areas of the page that I don’t want to have to re-query the DOM for. If my page is not going to change via AJAX I can store fetched results there for further use/manipulation. The ObjectName.config{} has the same functionality as .cache{}, it’s just my way of seperating out more important info than the generic .cache{}. You could use one, both, or neither, really just a matter of taste.

For this to be of use we need a way to load it once the dom is ready. Let’s add a ‘ready’ type event to the X library then:

X.go = function(obj) {
    X.addEventHandler(window,"load",obj.init);
};

You’ll pass your object literal to the .go() method which will, after the page has loaded, call the init() method of the object you passed to it:

    X.go(ObjectName);

Where this goes depends on how you are constructing your site. For now, we’ll put this line just below each object literal created. Later we’ll look at a site-wide answer to automating the loading of scripts, see Paul Irish’s blogs for more on that…

With a way to bind event handlers, object literals to hold the handlers, and a method to load the scripts, now we can just write some really basic JavaScript to utilize this stuff. So maybe there’s a button that lives on a page:

    <html>
        <head>
            <script src='x.js' type='text/javascript'></script>
        </head>
        <body>
            <input type='button' id='say-hi'>Click Me</input>
            <!--your external .js file linked to this page-->
            <script src="objectName.js" type="text/javascript"></script>
        </body>
    </html>

We need to set an event handler on that button to fire when the user clicks it. In the init() function of objectName do something like:

init: function() {
    var button = X.get("#say-hi");
    X.addEventHandler(button, "click", ObjectName.doClick);
}

I’ll get to the ‘doClick’ function in a moment. First, I want to write myself a convenience method to shorten the verbosity of adding event handlers. This is optional, of course.

    X.$click = function(element, handler) {
        X.addEventHandler(element, 'click', handler);

Now, with the convenience method added to the X library we can revisit what we wrote earlier:

var button = X.get('#say-hi');
X.$click(button, objectName.doClick);

That’s getting better, but we can combine those 2 statements down to:

X.$click(X.get("#say-hi"), objectName.doClick);

I am using a ‘$’ as a sigil in front of the name of the convenience methods throughout ‘X’. I do this to keep any conflicts with keywords like ‘submit’, ‘blur’ or ‘focus’ from happening. Plus all the cool kids are using $…

OK, so about the doClick handler. Remember that X.addEventHandler takes a target element, an event, and a function to call when that event happens on that element. The doClick function call is in object literal notation here, it is an attribute of the object you have made. I’ve been using ObjectName as the object so far (the observant among you may have noticed that the file is objectName.js. I do this in the development phase of a project as I will usually have many separate objects, all of them their own individual .js files. So objectName.js will have one object defined in it, ObjectName. At deploy time, I’ll combine them into one .js file and minify it). ObjectName will have this named function as an attribute:

doClick: function(event) {
    alert("Hi!");
}

The event handler calls ObjectName.doClick() because you bound it to that element. Here’s the whole object then:

var ObjectName = {

    init: function() {
        X.$click(X.get("#say-hi"), objectName.doClick);
    },

    doClick: function(event) {
        alert("Hi!");
    }
};

X.go(ObjectName);

Don’t forget to include the call to the go() method, outside of the variable which passes in ObjectName and tells the browser to call ObjectName’s init() method when the DOM fires the ‘load’ event. The cool thing about an object like this is re-usability. If your site was littered with buttons which needed to say “Hi” when pressed (it could happen) you would only need to attach this object to a master page and it would attach the event to any button with an id of “say-hi”. Now, it is an id so there should only be one per page. If there are going to be multiple instances per page, use a class instead, and iterate over the nodelist that get returns with a for loop to attach events. Assuming there are multiple buttons on the page with a class=”say-hi” attribute you would do:

var ObjectName = {

    config: {
        say: "Hi!"
    },

    init: function() {
        var buttons = X.get(".say-hi");
        for (var i = 0;  i > buttons.length; i++) {
            X.$click(buttons[i], ObjectName.doClick);
        }
    },

    doClick: function(event) {
        alert(ObjectName.config.say);
    }
};

with this you wouldn’t have to worry about the number of elements with a class of “say-hi”, as all of them would be fitted with a click event handler that will call ObjectName.doClick(). Note the use of the config object which is an attribute of ObjectName. You can manipulate this attribute if you wanted, changing it during the page lifecycle, like say adding a toggle-type command in the doClick() function:

doClick: function(event) {
        alert(ObjectName.config.say);
        ObjectName.config.say === "Hi!" ? ObjectName.config.say = "Hi Again!" : ObjectName.config.say = "Hi!";
    }

Now the alert will alternate between “Hi!” and “Hi Again!”. Silly, but you get the idea.

Next, we’ll do a continuation of the object literal using more of the config and cache functionality, I need to get away from this keyboard now!

Return top