JSONimal – Elegant DOM Contruction with jQuery
Occasionally for Javascript projects, I found myself building a lot of HTML programatically, and I wasn't satisfied with any of the techniques available, so I built JSONimal. I was originally going to just call it JSONML, but that was taken.
What's it do? This example should demonstrate my goal fairly well.
$(function() {
$.mktag("#demo").jsonimal([
["h1", {text: "JSONimal!"}],
["table",{style: 'border: 1px solid black'},[
["thead",[
["tr",{style: 'text-transform: uppercase'},[
["th", {text: "one"}],
["th", {text: "two"}],
["th", {text: "three"}]
]]
]],
["tbody", [
["tr",[
["td", {html: "<u>a</u>"}],
["td", {text: "b"}],
["td", {text: "c"}]
]],
["tr",[
["td",[
["a", {href: "http://www.google.ca", text: "Google"}]
]],
["td", {text: "b"}],
["td", {text: "c"}]
]],
["tr",[
["td", {text: "a"}],
["td", {text: "b"}],
["td", {text: "c"}]
]]
]]
]]
]).appendTo("body");
});
Which will add this to the body:
JSONimal!
| one | two | three |
|---|---|---|
| a | b | c |
| b | c | |
| a | b | c |
For more information and examples, check out the github page: JSONimal @ github.
I also posted it as on the jQuery plugins page - but that just points to the github page anyway. JSONimal @ plugins.jquery.com
AJAX Method Callbacks and Omegle Voyeur Update
I finally got back around to updating Omegle Voyeur with the ability to interfere, and decided to re-implement the whole thing in jQuery while I'm at it. Since jQuery doesn't come with a built-in method of building classes, I used lowpro for jQuery. It's a port of a class building scheme from Prototype. It doesn't do everything I could have hoped for, but it served most of my needs.
The other thing I implemented was a way of knowing when Omegle is blocking requests. They have a more robust form of detection now - it isn't just manual IP ban. Once you request too many things from them too fast, they start requesting a captcha. Locally, this isn't a problem - I simply embed an iframe with Omegle in it and provide instructions to the user. Hosted, this is a more troublesome problem, since the captcha is directed towards an IP, so it must be responded to from that IP. I have no solution to this problem at the moment, but I'm going to look into implementing the whole thing using Greasemonkey so this isn't an issue at all.
For now, you can see the latest version here: Omegle Voyeur. Don't be surprised if it's down, and please go grab your own copy: Omegle-Voyeur @ github.
Now on to the customary technical concept to go along with my own self promotion.
AJAX Method Callbacks
While passing functions as arguments is a pretty standard thing among almost all languages, attempting to pass methods of specific instances as arguments in Javascript presents an interesting problem. Consider the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function car(price) { this.price = price; this.setPrice = function(price) { this.price = price; }; } function pass666(func) { func(666); } var redcar = new car(2000); alert(redcar.price); redcar.setPrice(123); alert(redcar.price); pass666(redcar.setPrice); alert(redcar.price); |
As you might expect, the first two alerts will say 2000 and 123 respectively. But the last one also says 123. Why? It all has to do with what "this" refers to. Both in the initialization of redcar and the modifier call redcar.setPrice, "this" refers to the instance of the function car given the identifier name "redcar". In the pass666 version, "this" refers to the function pass666. As a result, it does nothing to modify the properties of the car because it isn't told anything about redcar.
One way to fix this is to use a placeholder variable. I used "self". Change the definition of car to the following yields the desired result.
1 2 3 4 5 6 7 8 | function car(price) { this.price = price; var self = this; this.setPrice = function(price) { self.price = price; }; } |
In this example, it's difficult to see why you would ever want to use this in the first place. The reason I encountered this problem is my need to use instance methods as callback functions for AJAX calls. Here's an excerpt of the jQuery version of Omegle Voyeur to see what I'm talking about.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | sendQuery: function(target,respFunc) { // Send a query to the omegle server //log('sending'); var self = this; if (respFunc == null) { respFunc = function(self,data) {} } $.ajax({ url: 'omegle.php?'+target, type: 'GET', dataType: 'json', success: function(data) { respFunc(self,data); } }); }, |
Sending a request to the Omegle server is a very common task in Omegle Voyeur, so I wanted all the AJAX requests leaving from the same method. This means I have to accept the callback function as a parameter. I've written all the callback methods to accept a parameter "self" which will refer to the instance of interest.
This aspect is one of the many things that makes Prototype's class system superior to jQuery's. However, since jQuery makes a lot of other things nicer and the two libraries don't play together very well, I decided to port over to jQuery nonetheless. In Prototype, there's a function called bind (not to be confused with jQuery's bind which does something completely different,) which solves this problem elegantly.
To fix the redcar problem with the aid of Prototype without having to use a placeholder variable, you can use bind like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function car(price) { this.price = price; this.setPrice = function(price) { this.price = price; }; } function pass666(func) { func(666); } var redcar = new car(2000); alert(redcar.price); redcar.setPrice(123); alert(redcar.price); pass666(redcar.setPrice.bind(redcar)); alert(redcar.price); |
The line
18 | pass666(redcar.setPrice.bind(redcar)); |
is what makes this work out. We're explicitly saying that we want setPrice executed from the scope of the instance.
If I ever have to hire someone for a web development job, I'll be sure to ask something about this.
Jobmine Improved (Greasemonkey & jQuery)

I, like many (most) Waterloo Co-op students, am forced to use Jobmine and am extremely dissatisfied with its functionality. So I decided to kill three birds with one stone: improve Jobmine, learn Greasemonkey and learn jQuery all at the same time.
The result is, unsurprisingly, a Greasemonkey script written using jQuery that improves on some features of Jobmine.
Features
- Table sorting - all major tables are now sortable (Interviews, Job Short List, Applications)
- Improved navigation - no more Student -> Use ridiculousness
- No more frames - you can refresh and it will stay on the same page!
- Colour highlighting for tables - pictured above, you see the applications page with various statuses highlighted. Selected is green, not selected is red.
- No more spacers - the Jobmine page is riddled with spacer images just sitting there, stealing screen real estate
How to Install You'll either need Firefox & Greasemonkey, or a recent build of Chrome (Windows only?). You can get Greasemonkey here: Greasemonkey @ addons.mozilla.org
Once you've done that, navigate to the script and click install. You can get the script here: Jobmine Upgrade @ userscripts.org
Now for the part where I explain the tech I used.
Greasemonkey
Greasemonkey is a tool for customizing the way a web page displays and interacts using javascript. More or less, it overlays javascript you write on top of pages you specify by URLs with wildcards (*). It doesn't overlay it directly, but wraps it in some way as to prevent it from messing things up in the global scope. It also seems to run once the page is done loading, not when the page head is loaded. There are plenty of tutorials out there for doing cool stuff with Greasemonkey, but I started here: Dive into Greasemonkey. I know it says it's hideously outdated, but the metadata information it provides is still good enough. If you want more up to date information, go here: GreaseSpot (Greasemonkey Wiki).
jQuery
jQuery is a javascript framework specifically designed for doing things involving the DOM tree absurdly quickly. Example: highlighting alternating rows of a table (zebra-striping).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // Standard Javascript method: var tables = document.getElementsByTagName("table"); for (var i = 0; i < tables.length; i++) { var rows = tables[i].tBodies[0].rows; for (var j = 0; j < rows.length; j++) { var rowColor; if (j % 2 == 1) { rowColor = "#eef"; } else { rowColor = "#fff"; } var cells = rows[j].cells; for (var k = 0; k < cells.length; k++) { cells[k].style.backgroundColor = rowColor; cells[k].style.borderBottom = "1px solid #ccc"; } } } // jQuery way: $("td").css("border-bottom","1px solid #ccc"); $("tr:even > td").css("background-color","#fff"); $("tr:odd > td").css("background-color","#eef"); |
Now before someone says it, I know usually you can set the background-color for the whole row, and the cells will inherit it. But since, for some crazy reason, each cell is assigned a background colour on Jobmine, each cell needs to be set individually. In any case, you can see that things are made substantially easier with jQuery. I figured out jQuery mostly just using the API and looking at other people's code, but this is a decent place to start: Getting Started with jQuery.
For the table sorting functionality, I decided to use a jQuery plugin as opposed to write my own (I'd rather be able to distribute this sooner). You can read all about it here: jQuery Plugin: Tablesorter 2.0
What features do you want to see in this? By the way, the source is all available on the userscripts site, so feel free to tinker with it yourself.
EDIT: As Trevor points out, the script in its current state won't work in Chrome due to the @require. You can grab his fix to make it work in chrome here: Jobmine Improved (Chrome)