Skinny JavaScript — Fast!

Tweet

JavaScript programs launched from your Web browser’s favorite bookmarks can achieve amazing special effects. You can enlarge fonts, change colors, and even reveal hidden form field values. These "bookmarklets" can be as long as 2000 characters in some browsers (IE5), yet barely 500 in others (IE6). The most impressive bookmarklets dynamically build their own HTML, CSS and JavaScript right in your browser. I used to lament that HTML is so bulky… Until I finally did something about it!

I wrote a JavaScript library that enables you to render large HTML and CSS constructs using extremely tight JavaScript code. Although there are literally hundreds of supporting functions jammed into this compact library (which weighs in at under 5K when www.brainjar.com‘s "crunchinator" removes the comments and white space), all are named after the HTML tags, attributes and cascading style sheet (CSS) properties you already know. Truly, there are only six categories to learn:

  1. Conveniences (write, status, alert…)
  2. Containers (DIV, SPAN…) that enclose content
  3. Tags (IMG, INPUT…) that are "empty"
  4. Attributes (NAME, TYPE…)
  5. Properties (color, font…) inline or embedded styles
  6. Entities (nbsp, quot…)

The HTML generators (#2-4) return xml-ready code for you with lowercase tag/attribute names and quoted literals. The examples cited above use their corresponding JavaScript names.

Containers (#2) are called on strings just like JavaScript’s built-in bold function. Tags (#3) and attributes (#4) are implicitly called on the window object, and thus need no dot notation at all.

HREF('http://www.yahoo.com')
yields:
href="http://www.yahoo.com"

TITLE('Yahoo!')
yields:
title="Yahoo!"

The leading space is not a typo. It just anticipates concatenation with other attributes for easy inclusion into tags and containers (#3-4).

'Yahoo!'.A(HREF('http://www.yahoo.com')+TITLE('Yahoo!'))  
yields:
<a href="http://www.yahoo.com" title="Yahoo!">Yahoo!</a>

At this point, you might be thinking, "The JavaScript code is exactly the same size as the intended HTML!" I’ll get to that, but first…

IMG(SRC('images/yahoo.gif')+ALT('Yahoo!'))     
yields:
<img src="images/yahoo.gif" alt="Yahoo!" />
HR()
yields:
<hr />

"Big deal!" you say. "Saving only one or two characters?" Yes, but container (and tag*) functions can also be called on arrays. This encloses each array element. And chained functions can wrap earlier constructs.

[1,2,3].TD().TR().TABLE()     
yields:
<table><tr><td>1</td><td>2</td><td>3</td></tr></table>

Combine this with a few variables, and you can see why it works so well.

b=INPUT(TYPE('button')+NAME('day')); 
w=[b,b,b,b,b,b,b].TD();
c=[w,w,w,w,w,w].TR().TABLE();


This construct is actually the basis of a JavaScript calendar component I built. In just three statements, c gets assigned 1875 characters of HTML!

"Is TITLE a link attribute (#4) or is it a document title (#2)?" Well, it's both!

TITLE('hint')
yields:
title="hint"

'home'.TITLE()
yields:
<title>home</title>

Similarly, STYLE can define an inline style attribute (#4) or contain embedded CSS code (#2). And, speaking of CSS code...

Both the capitalized attribute functions (#4) and lowercase property functions (#5) are called implicitly on window. To avoid confusion with subtraction, the hyphenated property names employ underscores in their JavaScript function names (caveat: since top is a pre-existing browser object, I use _top as a kludge for this critical css property).

color('red')      
yields:
color: red;

width(25)
yields:
width: 25;

In the earlier calendar example, the buttons may not be square. Using attribute-like css support, it's easy to inline the exact button dimensions.

x=25;  
s=WIDTH(x)+HEIGHT(x)+STYLE(width(x)+height(x));  
b=INPUT(TYPE('button')+NAME('day')+s);  
w=[b,b,b,b,b,b,b].TD();  
c=[w,w,w,w,w,w].TR().TABLE();


This bit of JavaScript now generates 4185 characters of flawless HTML! Some browsers will accept the WIDTH and HEIGHT attributes right inside of the button's INPUT tag (NS4.x), yet others require the width and height in an inline STYLE. Having both makes this code cross-browser. Also, variable x makes it trivial to resize the buttons. You might prefer x=30.
Alternatively, these styles could be embedded. A style function called on a css selector string (or array) accepts a properties parameter.

x=25;  
s='table tr td input'.style(width(x)+height(x)).STYLE();    yields  
<style>table tr td input{ width: 25; height: 25; }</style>

If important, this will reduce the size of the generated output. But be sure to embed stylesheet s before rendering calendar c! Or would you prefer an external stylesheet?

LINK(REL('stylesheet')+TYPE('text/css')+HREF('cal.css'))    yields  
<link rel="stylesheet" type="text/css" href="cal.css" />

Inline, embedded, or external. However you develop it, I support it.

The HTML entities (#6) are not actually functions. Regard them as string constants. You'll find that quot and acute can help you build those syntactically "challenging" content strings.

muse='Francis Edward Smedley: '.B();
muse+=(quot+'All'+acute+'s fair in love and war.'+quot).I();

XML enthusiasts will be glad to know that additional functions can be added simply by invoking the HTML() constructor as seen in the library's final statement. Its three parameters are specified quite simply: In the first parameter, CONTAINER/Tag/attribute items (delimited by spaces) are cased upper, proper or lower to produce the appropriate functions. In the second parameter, css property families (delimited by semicolons) are appended with colons and their dependents (delimited by commas). Finally, the third parameter lists named entities (delimited by spaces).

HTML('LANGUAGE COPYRIGHT DESCRIPTION LINK');
HTML('URL IMAGE ITEM CHANNEL RSS version');
rss='My Blog'.TITLE();
rss+='en-us'.LANGUAGE();
rss+='Copyright 2003 by Richard Renfrow.'.COPYRIGHT();
rss+='Favorite RSS feeds'.DESCRIPTION();
rss+='list.rss'.LINK();
img='Me!'.TITLE()+'myPic.jpg'.URL()+'home.html'.LINK();
rss+=img.IMAGE();
itm='Blog'.TITLE()+'RSS'.DESCRIPTION()+'blog.rss'.LINK();
rss+=itm.ITEM();
rss=rss.CHANNEL().RSS(VERSION(0.92));

Last but not least, the convenience functions (#1) make it very easy to write a string, display it in the status line or popped up as an alert. During development, you might insert several .alert() calls into your JavaScript code to see exactly how your constructs are built. For greater interactivity, you can prompt for content or simply confirm intermediary constructs. The last three lines above could be augmented thus...

do {  
itm='Blog'.prompt('Blog title?').status().TITLE();  
itm+='RSS'.prompt('Blog description?').DESCRIPTION();  
itm+='blog.rss'.prompt('Blog feed url?').LINK();  
rss+=itm.ITEM().confirm();  
} while (confirm('Add another?'));  
rss=rss.CHANNEL().RSS(VERSION(0.92)).prompt('paste as list.rss');

* When a tag function is called on an array, the desired tag precedes each array element. I elected to do this for simplicity in labeling a horizontal radio button group.

['daily','weekly','monthly'].INPUT(TYPE('radio')+NAME('frequency'))

Enjoy!!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments