Posts Tagged ‘JavaScript’

* 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: .



* PhoneGap Desktop

Posted on April 20th, 2010 by Dave Johnson. Filed under phonegap.


So if PhoneGap was running on the desktop, what would you call it? Well I have not come up with a good name yet but after a few nights of hacking we threw together a version of PhoneGap for Mac OS http://github.com/shazron/phonegap-mac and a version for Windows http://github.com/davejohnson/phonegap-windows.

@shazron has implemented the sound API on the Mac version and I did Geolocation on the Windows version using a simple GeoIP lookup.

Check it out, write some code, and let us know what you think!

For the Windows version I have used the awesome WebKit .NET project written by Peter Nelson. If you use the Visual Studio 2008 solution file, you will have to download the source or binary versions of WebKit .NET and setup the references correctly. I have so far used the 0.3 release of WebKit .NET. It is pretty cool being able to write a native Windows app (or Mac OS) in Canvas using all free and open source code :)

One other caveat on the Windows side is that you might need to install some Visual Studio C++ redistributables for building it … check the WebKit .NET forum on SourceForge for all the details.

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: , , , .



* Work

Posted on January 11th, 2010 by Dave Johnson. Filed under phonegap.


Crap it has been busy at work the past few months!

More to come soon though since I am working on a few small JavaScript libraries and two services that I will be releasing soon!

There has of course also been a tonne of amazing work being done on PhoneGap (tests, Palm, Nokia, simulator) - though not by me so much :)

Check out the latest at GitHub http://github.com/phonegap

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: , , , .



* BlackBerry PhoneGap Progress Report

Posted on December 6th, 2008 by Dave Johnson. Filed under phonegap.


BlackBerry PhoneGap
We had a PhoneGap sprint just over a week ago which was pretty successful for me and my BlackBerry ambitions as well as everyone else. Through that sprint and over the past week, despite some setbacks, I got the OS v4.5 installed on my phone and the simulator on my computer giving me access to a few new things but I was sad to find that a few other things were still sorely lacking that are pretty important for something like PhoneGap. Just so you know, OS v4.5 is the latest OS that will run on my Curve 8310 - 4.6 will run on the Bold, Pearl Flip and newer Curves while 4.7 works on the Storm. The two biggest gaffs by RIM are in the BlackBerry web browser for OS v4.5 where that the following rather important features are missing:

  1. You can’t pass function pointers to setTimeout.
  2. You can’t access DOM Nodes in any way shape or form (aside from form fields). So there is no getElementById or innerHTML on the resulting nodes. This make web application development a little bit difficult.
  3. There is no XMLHttpRequest object.
  4. While not really expected, there is no SQLite support
    anywhere on the phone as of yet, let alone the browser.

Anyhow, despite those setbacks on the v4.5 OS I did get the communication between the BlackBerry device and the web page all dialed now. Not only that but I have implemented the W3C geolocation API and am going to follow that same pattern for the other APIs. Check out the geolocation JavaScript interface as well as the platform specific implementation.

In the actual BlackBerry code there is lots of boiler plate stuff. The main hurdle was figuring what the best (or any) way to embed the browser in the application was and enable communication between JavaScript in the browser and the BlackBerry Java code. In the end I pretty much had to take the route of implementing the browser myself through the BrowserContentManager. This means that I have to implement lots of functionality, but it also means that I am in control of cookies and responsible for accepting them from JavaScript in the web page through the implementation of the browser fields RenderingApplication.eventOccurred method when the event type is EVENT_SET_HTTP_COOKIE and returning them to JavaScript by implementing the RenderingApplication.GetHTTPCookie method.

When the set cookie event occurs I parse out the cookies looking for one named bb_command and expect it to contain some JSON object (that is parsed with the J2ME port of a Java JSON lib) with a command property (like for opening maps or getting the GPS location) and some arguments (like points to plot on the map or how long to vibrate for). The case statement just looks like this:

switch (command)
{
  case 0:
    this._getLocation = true;
    this.startLocationUpdate();
    break;
  case 1:
    Invoke.invokeApplication(
      Invoke.APP_TYPE_MAPS,
      new MapsArguments(MapsArguments.ARG_LOCATION_DOCUMENT,
      getLocationDocument(args))
    );
    break;
  case 2:
    Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA,
      new CameraArguments()
    );
    break;
  case 3:
    if (Alert.isVibrateSupported())
      Alert.startVibrate(getVibrateDuration(args));
    break;
  case 4:
    Invoke.invokeApplication(Invoke.APP_TYPE_PHONE,
      new PhoneArguments(PhoneArguments.ARG_CALL,
        getPhoneNumber(args)
      )
    );
    break;
  default:
}

where args is just a JSON string that the various methods like getPhoneNumber parse to get the args they want.

I will post some more specific code snippets like how to send text messages and so on very soon.

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: , , , , , , , .