Archive for the ‘JavaScript’ Category

* PhoneGap Native Bridge

Posted on August 13th, 2010 by Dave Johnson. Filed under JavaScript, mobile, phonegap.


The “native bridge” is the secret sauce of PhoneGap and is what allows JavaScript in an embedded browser talk to native code and vice-versa.

On every platform we do this differently depending on what features that native browser has. Here is the list of platforms and how we do it.

iPhone: To communicate from JavaScript to native we call window.location = “gap://Class.method/args” and then intercept the url in native code and parse our the parameters. The class / method is then dynamically loaded / called. To call JavaScript from native we use UIWebView.stringByEvaluatingJavaScriptFromString.

Android: Communication from JavaScript to native takes advantage of the native WebView.addJavascriptInterface to expose Java objects directly to JavaScript. To call JavaScript from native we currently use WebView.loadUrl(”javascript:…”) but that has some problems so we are soon moving over to polling a Java message queue calling a local HTTP server via a long-lived XHR connection.

BlackBerry 4.x: document.cookie is the only way to talk between JavaScript and native. JavaScript sets the cookie for native to read and JavaScript polls the cookie for messages from native. Fucking elegant!

BlackBerry Widgets: Astoundingly the new BlackBerry Widgets SDK is pretty damn nice. You can expose Java objects to JavaScript with ScriptEngine.addExtension and you can call JavaScript from native with ScriptEngine.executeScript. The context for the JavaScript execution can even be specified. Seriously great work there.

QT: This one is not quite ready but it will use the QWebFrame.addToJavaScriptWindowObject to expose native objects to JavaScript and will likely use polling of those exposed native objects to get data back into JavaScript - much like the Android approach

Windows Phone 7: There is something called window.external.Notify in the browser (mapped to a native object through the ScriptNotify event) on Windows Phone 7 that we use to send messages into native code. Going the other way there is WebBrowser.InvokeScript.

webOS, WRT: The platforms that are just JavaScript don’t have any native code. Well, we might look into the native side of webOS one day but no time soon.

In an attempt to clean up the PhoneGap JavaScript API a bit, I have isolated all the places that we communicate from JavaScript to native code and put it into a single PhoneGap class. I am now in the process of converting over all the JavaScript to use this new PhoneGap interface and then most of the PhoneGap JavaScript will be completely cross platform. Any call to native code now has to go through the PhoneGap.exec() JavaScript method. The new code is up on Github and with any luck all the platforms will be using it soon!

Image by hb2

Tags: , , .



* JavaScript Event Merging

Posted on July 14th, 2010 by Dave Johnson. Filed under JavaScript.


In a recent project I finally decided to write something to help with JavaScript event merging. There are often cases in JavaScript where you want some code to run but only after certain events have fired or other code run - in my case I wanted to execute a JavaScript function only after two different bits of code had executed. The most common use case for event merging I have come across has got to be on page load / DOM ready where you may need several conditions to be true before executing some JavaScript code.

Event merging generally helps you to better separate your concerns and not have unwieldy if conditions strewn throughout your code checking if certain condi.

If you have a basic JavaScript object called the “Subject” that has subscribe, subscribeOnce (events that auto-unsubscribe themselves after being fired the first time), and notify methods on them. You can use the following merge function to have all subscribed code executed only after each of the events passed to the merge function are fired. In this case I have explicitly used the subscribeOnce method on the event.

1
2
3
4
5
6
7
8
9
10
11
function merge(handler, events) {
       var i = events.length;
       var f = function() {
           if (!(--i)) handler();
       }
       for (var j=0; j<i; j++) {
           var e = events[j];
           (!e.fired?e.subscribeOnce(f):i--);
       }
       if (!i) handler();
}

When the merge function is called it iterates over all the events in the event array argument and checks if that event has already been fired or not by checking the “fired” property on the event - note that this makes it so that it doesn’t matter if merge is called before or after the events have fired. If the event has not been fired yet then a handler is attached using subscribeOnce where the handler checks a counter indicating how many of the events have been fired, once the counter hits 0 then the final handler for the merged events is called.

I have put up an entire event merging code on Github here.

Tags: .



* Crockford Facts

Posted on March 18th, 2010 by Dave Johnson. Filed under JavaScript.


Everything that you want to know (or not) about Douglas Crockford.

Or following things live on Twitter.

I contributed a few of my own like:

“Crockford doesn’t throw errors, he roundhouse kicks them.”

Andrew Lunny also directed me to this site with some Resig facts … hilarity!

Tags: .



* QUnit Server

Posted on March 1st, 2010 by Dave Johnson. Filed under Components, JavaScript, Testing.


QUnit is a great little JavaScript test framework written by none other than John Resig of jQuery fame.

I love how easy it is to write tests, especially asynchronous ones, with QUnit and so was quick to start using it for my JavaScript tests.

The one thing that I found it lacked was support for continuous integration products like Hudson, CruiseControl or Continuum. So I figured that I would change that.

For a long time I have been using JsUnit along with JsUnit Server to merge in client side JavaScript test results with a server side test integration workflow. Essentially, JsUnit Server is a Jetty server and JsUnit posts back a form with test results to that server, which logs the results to standard JUnit formatted test results files. Those files can then be read by most continuous integration products and included in their reporting.

What I decided to do was hack QUnit so that it too could submit test results back to the JsUnit Server in the same format that JsUnit submits results and could therefore continue using the same JsUnit Server workflow and simply change the client JavaScript test framework to QUnit. It worked like a charm!

I wrote a couple of simple function that in the background dynamically create an HTML form in the QUnit test page and add the results to the form as each test is run. When the tests are complete the page submits back to the JsUnit Server and the test results are logged as they were when I was using JsUnit.

It is some pretty simple changes but does make using QUnit that much better, especially if you were hesitant to switch just because the continuous integration support was not there for QUnit.

Check it out on GitHub.

Tags: , , , .



* HTML 5 and sessionStorage

Posted on February 19th, 2010 by Dave Johnson. Filed under JavaScript, quirks.


We came across a strange bug today that was being caused by our recent addition of sessionStorage to our application.

The Mozilla Developer Center says this about sessionStorage:

This is a global object (sessionStorage) that maintains a storage area that’s available for the duration of the page session. A page session lasts for as long as the browser is open and survives over page reloads and restores. Opening a page in a new tab or window will cause a new session to be initiated.

Emphasis mine.

What we found was that of the three different browsers that currently “support” sessionStorage, there are three different implementations. Go figure.

I looked at a few different ways of opening new windows or tabs and those included anchor tags with target values of “” and “_blank”, window.open() JavaScript calls with different targets, and context menu open in new window or tab.

Internet Explorer 8 is furthest from the spec, as one might expect. No matter how you opened a new window from the page, the sessionStorage is preserved in the new window.

Firefox is only slightly better in that it does not preserve the sessionStorage in new windows when the new window is created by choosing open in new window / tab from the context menu on an anchor.

Safari is more or less like Firefox except that it does not preserve the sessionStorage when the target on an anchor is “_blank”.

In short, if you are expecting that sessionStorage is tied to a single browser window then think again.

Tags: , .



* JavaScript Pub Sub

Posted on April 28th, 2009 by Dave Johnson. Filed under JavaScript, Uncategorized.


I was talking to someone the other day about the observer pattern in JavaScript and I was reminded about this JavaScript method that is part of Complete UI.

nitobi.Event.prototype.subscribeOnce = function(method, context) {
  var guid = null;
  var _this = this;
  var func1 = function() {
    method.apply(context || null, arguments);
    _this.unSubscribe(guid);
  }
  guid = this.subscribe(func1);
  return guid;
}

subscribeOnce is a special sort of event subscription that rather than being being executed every time the event fires, the handler function is only executed once and then automatically unsubscribed from the event. It is obviously most useful for initialization stuff in JavaScript. There is some more info on JavaScript pub sub over on Ajaxian too.

Tags: , , , .



* 13 Tips For A More Accessible Web

Posted on November 17th, 2008 by Dave Johnson. Filed under AJAX, Accessibility, JavaScript.


There are few web projects that I have worked on of late where accessibility has been a high priority. Of course having worked on the Complete UI Ajax framework that is generally used to build internal web applications we were always trying to make our components as accessible as possible, particularly through the use of the keyboard.

In general through there are a few simple things that you can do to make you web applications far more accessible to your users that may use screen readers like JAWS or have to divert from normal computer settings like just using larger than normal fonts or even using high contrast mode.

  1. Remember if something can get focus through the tab key, users with screen readers will find it and the screen reader will describe it to them.
  2. The first is something that I am sure you have heard a thousand times and may or may not have listened. Don’t use tables for layout. I think that I saw this great site about it through Dion. Amongst the many arguments against using tables for your layout is that they have semantic meaning for
    screen readers - that meaning is course that there is some tabular data to follow. So you can imagine it can be confusing when tables are found without any tabular data!

  3. When a screen reader finds a table, users generally assume that is has a header row with column headings - so use the <th> tag to specify the column headers and maybe even put that entire row in a <thead> element.
  4. Use the unordered (<ul>) and ordered lists (<ol>) when appropriate. Unordered lists should even be used for things like menus by setting the display to inline and the list-style-image to something to get rid of the normal bullet.
  5. Always set the alt attribute on <img> tags. When the image is inside of an anchor this attribute should describe the image as the anchor will bring focus to that HTML. If it is just an ornamental image then leave the value of the alt attribute empty rather than ignoring it (this was demanded by a client due to bugs in certain browsers / screen readers).
  6. Use CSS for all images. The previous issue with image tags that are purely ornamental should not happen since you should be using CSS to set background images on your HTML elements. Not to mention the fact that those images should be sprited using something like SmartSprite and so you have to use CSS.
  7. Form elements should always have an associated <label> element with the for attribute pointing to the element that the label is for.
  8. Try to put dynamic HTML (drop down menus etc) into the HTML tree where they appear
    visually such that tab index for focusable elements is maintained. If you generate a drop down but append it to the bottom of the HTML page and position so that it appears visually at the top of the page, you would have to set the tabIndex attribute on anchors in the menu to get the correct tabbing effect.

  9. Don’t use tabIndex.
  10. Any element that has an onclick event on it should be an <a> tag (or at least enclosed in one). This will ensure that it is focusable and the user can then use the enter key to activate the click event. This is also a good reason not to use onmousedown or onmouseup events since those will not be captured by the keyboard. Similarly, if you use onmouseover and onmouseout to do anything that is not visual then you may consider having onfocus and onblur to do the same thing.
  11. If you have headings then use the heading tags! Semantics, semantics, semantics.
  12. Use relative sizings like em for your fonts and other dimensions and check out how the site looks as you change the font size.
  13. Put in a hidden anchor (position absolute, x,y -5000px) near the top of the HTML that contains a message like “Skip navigation” with an href pointing to an another anchor that will skip down to the actual contents of the page such that screen reader users can skip any redundant links and header information.

If you follow that simple list you should make your web sites and applications much more accessible.

For Firefox users I recommend the Firefox Accessibility Extension, which makes testing your pages pretty easy.

Anything to add? Please leave a comment below!

Tags: , , , .



* Surfin’ Safari

Posted on October 9th, 2008 by Dave Johnson. Filed under AJAX, CSS, JavaScript, XML, completeui, quirks, safari.


For the past little while I have been busy fixing up Complete UI to work in Safari. The big problem for us in getting Complete UI working in the WebKit powered browser was that there was no client side XSLT JavaScript API until Safari 3.

So there were a few things I had to update to get things all working properly - and this more or less applies to Chrome now as well but I need to check on a few things.

XMLDocument::selectNodes

The first problem I came across was using the XMLDocument::selectNodes method. To get selectNodes working I had to implement my own NamespaceResolver which is usually handled for you by the browser.

I had to change the call to the XMLDocument:evaluate method a bit to look like this:

var oResult = this.evaluate(
  sExpr,
  (oContextNode?oContextNode:this),
  new MyNSResolver(),
  XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
  null);

Where the MyNSResolver class essentially implements the lookupNamespaceURI method through a switch statement returning the appropriate URI for the specified namespace prefix. Pretty easy but kinda annoying to figure out!


function MyNSResolver() {};
MyNSResolver.prototype.lookupNamespaceURI = function(prefix) {
  switch (prefix) {
    case "xsl":
      return "http://www.w3.org/1999/XSL/Transform";
      break;
    case "ntb":
      return "http://www.nitobi.com";
      break;
    default:
      return null;
  }
}

XSLT Transformations

Then there was the actual act of performing an XSLT transformation. Doing the transformations was fine but getting the output node or string from the transformations - depending on if the <xsl:output /> was text, html or xml - was rather different than both Firefox and Internet Explorer. Go figure.

For transforming to an XMLDocument here is what I found to be the output of an XML transformation for the various output methods.

Text:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title></title>
  </head>
  <body>
    <pre>innerText</pre>
  </body>
</html>

XML:

<output>innerText</output>

HTML:

<html>
  <body>
    <output>innerText</output>
  </body>
</html>

XSLT Parameters

There is also one difference in how the Safari XSLT processor deals with parameters. Rather than casting true / false to 1 / 0 the Safari XSLT processor does not recognize true or false values and requires the inputs to be 1 / 0. I have started setting all my XSLT params like this:


oXsltProc.addParameter("paramName", val+0, "");

Events and Focus

There were some other small issues that I came across regarding implementing rich keyboard navigation and events in general.

For example, in our Grid component I had to change the HTML element that we used to “focus” the Grid so that we could capture key presses from a <DIV> to an <INPUT>. Apparently you can’t call Element:focus on a <DIV> element from JavaScript but you can on an <INPUT> (even with a tabIndex set but I try to avoid those for accessibility reasons anyhow).

However, that was not my only problem with keyboard navigation. The other problem was that the focusable element (the newly created <INPUT> in this case) was still not getting focus due to a small code snippet like this:


oMyInput.focus();
cancelEvent(evt);

That second line where I cancel the event (wrapped nicely in a cross browser library call) somehow prevents the <INPUT> from getting the focus. Never figured out a workaround aside from a browser check before calling cancelEvent.

CSS

Finally, in some of our components we also generate CSS using XSTL and dynamically insert it into the page. For example, the developer defined column widths in a Grid produce dynamically generated CSS. However, WebKit does not seem to support the bulk creation of stylesheets neither using the document.createStylesheet method of Internet Explorer nor the hacky way of doing in Firefox by creating a <STYLE&gt element and setting the innerText. Instead Safari requires that you use the uber slow DOM API for adding rules to stylesheets :(

Miscellany

You will often see the “xml namespace prefix mapped to wrong URI” error when working with XSLT in Safari.

Be careful that you are using double quotes in your XSLT for attributes etc and only use single quotes in attribute values.

Of course you also have to be very careful about the nodes that you are transforming / selecting as you are also likely to get the “WRONG_DOCUMENT_ERR” fairly frequently.

Oh yah and depending on the application expect a lot of random “Stack overflow” errors!

Tags: , , , , , , , .



* Complete UI Q4

Posted on September 26th, 2008 by Dave Johnson. Filed under AJAX, JavaScript, Nitobi, completeui.


Some big changes are coming in the Q4 release of Complete UI. Big!

Of course there is a slew of JavaScript bug fixes for all the components with Grid receiving the most attention for IE 8, Safari 3, Firefox 3 and Chrome.

There are a bunch of changes to the Java side of Complete UI with more great JSP and JSF code to make it even easier to use Complete UI in your Java project.

Finally, we have also made huge changes to the ASP.NET Grid and Combo code - and are working on the rest of the components as I am writing this! I think that anyone using ASP.NET will be very happy with the new direction of the ASP.NET code :)
We are shooting for an on time Oct 1 release but there is so much we are trying to fit in it might be a bit late - but it will be well worth waiting for!

Tags: , , , , , , , .



* CommunityOne Presentation

Posted on May 8th, 2008 by Dave Johnson. Filed under AJAX, JavaScript, Patterns, communityone.


In addition to my slides, Andre recorded my CommunityOne presentation and put it on Blip. Check it out!

Tags: .