This is the complete text of the presentation titled "jQuery and The Last Mile" given by Ken Downs to Boston PHP on March 11, 2009.
Tonight we will see how jQuery alowed us to complete the "Last Mile" of the x6 desktop-in-browser interface for the Andromeda Project, giving us workable auto-generated database maintenance screens and tools for custom screens.
jQuery allows for vastly improved productivity in browser programming. It touches nearly every subroutine in our Javascript library.
This page: http://www.andromeda-project.org/bostonphp2009-03-11.html
The demo we will see: http://dhost1.secdat.com/time_003.
The Javascript Library: http://dhost1.secdat.com/time_003/clib/x6.js.
PHP source code is available with these links:
The Demo program is an Andromeda application, this project exemplifies what Andromeda is all about.
The original version of Andromeda had no Ajax and no more than 50 lines of Javascript. When we wanted to go Ajax for a full desktop-in-browser experience, it was an absolute requirement that DOM manipulation be painless, that we be able to program at the speed of thought, which is nigh-on impossible with straight Javascript. P.S.: jQuery's effects were simply a bonus.
Tonight's presentation will make heavy use of Firebug, which fits hand-in-glove with jQuery.
Using Firebug and a demo screen, we will see all get on the same page on how to use jQuery commands.
Bring up the demo and go to customers screen.
Some simple ideas that flow from jQuery's core function:
All of the examples of Javascript we will see are in the x6.js file referenced at the top of the page. To start out, we want to see some isolated examples of how jQuery is sprinkled throughout the program:
For this example, you must navigate to a page that is not on the menu. After logging in, go to this page: http://www.andromeda-project.org/?x6page=states When the search grid comes up, hit '*', then hit PageDown a few times.
The code that supports this behavior begins at line 3987 of x6.js and is almost pure jQuery. Among the features we use are:
For this example, go to projects, detail, NEW. On the Project type field type '*'.
The entire behavior of the auto-complete field is controlled by an object x6inputs.x6select which is riddled through with jQuery. Some relevant lines when you hit '*' are:
For this exaple, go to Customers, type '*' and pick the first customer. Then click on the tab at the bottom "4: Projects", and click [NEW] inside the tab. A modal pops up that lets you create a project.
The sizing and placement of this modal are controlled by a routine of almost pure jQuery beginning at line 6569.
Note from Ken: This is the most recent feature I added to Andromeda as of this writing, and it is the most purely jQuery. I find the longer I use it, the more I use it for everything, it tends to crowd out all other techniques.
Basic HTML habits become more important: id's for unique items, classes for non-unique.
Using your own custom attributes can give you lots of power in your Javascript code.
Debugging strategy, reduce your core logic to finding the jQuery selector, which you can manually tweak in Firebug before putting it into the code. See the example at line 3738 and line 3740.
When you've gone all the way, you end up with all DOM access through jQuery, all other logic in native Javascript.
At this point it is worth bringing up cross-browser compatibility. The demo we are looking at works well in IE6, IE7, and Firefox.
jQuery could not do much for us in the way of CSS incompatibilities, that was our own nightmare we had to solve.
In very late drafts of x6.js Ken was still using code that treated the "value" attribute of inputs as if it were a property. This works fine in Firefox, but broke completely in IE. Switching over to .val() solved that entire problem nicely.
The menu page (not the top menu) makes use of the fade effect and custom attributes. Most of the code is in x6menu.php.
When a user clicks on a module on the left side, the code at line 128 turns off keyboard responses to the right side just before beginning the fade.
At line 136 the fadeOut() of the old module begins, an then simultaneously at line 142 the new module begins fading in. Only when the new module is faded in do we activate keystroke responses again at line 144.
This example also illustrates the use of Custom Attributes to control behavior. We respond to letter keystrokes by finding a menu entry with the attribute 'xkey' that equals the letter. But how do we keep straight the sub-menus for all of the modules? We add another attribute 'xActive', which is only set to 'Y' for the active submenu. Line 210 shows the code that receives the keystroke and picks the menu entry to select. The fact that jQuery returns an empty set w/o error is a big help here.
jQuery has a nice feature, the $(document).ready() function which lets you add code that is executed when the page has loaded.
Since much of our HTML is generated by PHP, it stands to reason that the commands we put in here will vary according to what HTML we have generated.
This is our first example of a case where we need PHP to generate jQuery-specific items. One very flexible way to do this is to make up a function like 'jqDocReady()' which accepts a string fragment for later output to the browser. Our own function is at line 11235 of androLib.php
Some type of routine must then spit this all out, so our own code for this is at the bottom of androHTMLFoot.php, beginning at line 90.
Idea 1: PHP exists to generate HTML, so keep it that way, just because jQuery (and other libraries) can render HTML easily, does not mean they do it quickly.
As an example, view the source of the customers page, it contains the entire HTML for anything that might be visible at any time. It is all generated by PHP, jQuery is only used to manipulate it.
Idea 2: jQuery (and Javascript generally) can be put to best use manipulating the DOM, this is all that is left if the HTML still originates from the server.
All jQuery plugins are not created equal, and they are not always compatible. But we've all found this out the hard way, right?
All events are not created equal, if you want to capture arrow keys it is the keyDown event in IE, but keyPress in Firefox. See Line 530 of x6.js.
Unless I am completely missing something, jQuery does not provide a uniform way to prevent event propagation/bubbling, so I had to write my own, see line 60 of x6.js.