LoJAX (Low-technology AJAX)
12th June 2006
is a re-creation of the
window.XMLHttpRequest object, designed for
low-specification and legacy browsers.
It can also be used in browsers that already have support, to provide additional functionality not available in any native implementation.
LoJAX uses a combination of client-side and server-side code to make real HTTP requests, which have the same context and permissions as regular XHR requests, and return proper headers and status information.
supports GET, POST and HEAD,
and provides all of the principle methods and events,
However it doesn't support synchronous requests,
and more notably, there's no support for
responseText is supported fine,
allowing data to be received as plain text,
(or any text-based format), and although individual requests are
always asynchronous, LoJAX
has the ability to synchronize multiple
requests on the same or multiple object instances, to
ensure that each request is returned in the order it was made.
Since the actual HTTP request is made server-side, LoJAX also has the ability to retrieve data from external domains.
- Browser support
- Get the script
- Client-side configuration
- Server-side configuration
- What's the point?
The script is known to work in the following browsers:
- Sony PSP (Version 2.00 or later)
- Opera 5, 6 and 7 (Versions 5.0 to 7.5 inclusive)
- Mac/IE5 (Version 5.0 or later)
- Konqueror 3.1
- OmniWeb 4.5 and 5.0
- Espial Escape 5.1
This is in addition to being supported in all browsers
which natively support
XMLHttpRequest, and when used in these
browsers it can be configured either to have a different function name,
or to have same name and hence over-write the native object (except in Safari and IE7;
please see the additional browser notes for details).
Get the script
Download the zipfile [18K] and unzip it; it contains all the script files you need, along with three test files for demonstration which you don't need to keep.
The core components of LoJAX are a JS
"lojax.js", and a
PHP script called
"lojax.js" is compressed so that it loads faster,
but there's also a fully-commented version included in the zipfile,
for reference or further development.)
The script can go anywhere on the page, and its functionality will be immediately available to any scripting that comes after it:
For maximum usefulness overall, the optimum place to put the script
is at the very top of the
However, since it uses procedural code to generate a
(which act as a data courier),
it would actually invalidate the
DOM on the fly
to have it in the
I could argue on a purely pragmatic level, that isn't really so bad. The validator won't know the difference, and real people aren't affected - because crucially, the elements are generated in such a way that they can only be accessed programatically by the script - users can't reach them manually.
But a script-aware validating parser would be affected, so therefore,
the script can only be safely used like this on pages served as
text/html (because on pages in
a validating parser may throw a DOM
exception and abandon the output).
Otherwise - the script will generate fully valid output if
it's used in the
<body> section of a page,
having a doctype of
1.0 Transitional or earlier.
But if the files are in different directories, or if you're using the script in different places within a site or application's heirarchy, you will need to define an absolute or web-root path to the PHP script. (This also means you can write your own server-side component in another language, and then specify the path to that.)
You can define the path using the optional client-side configuration
"lojax-settings.js"; this must be added
"lojax.js" in the source code:
Then you can configure it. The path to the server-side script is the most significant setting, but there are four other options as well:
- path to server-side script
The script works by submitting a form to a server-side script, and this value defines the path. The default value is a local path to the same directory, but if you're using the script in different places throughout a site or application, it's simplest to set a web-root path like
"/lojax.php", or an absolute value like
You could also vary a local path on a per-instance basis, by having multiple copies of
"lojax-settings.js"in different places.
- what kind of implementation to use
The script's default behavior is to attempt to implement the re-creation only if a native
XMLHttpRequestobject is not found; this behavior is defined with the value
You can also set the value
"lojax", which means to use the re-creation for all browsers irrespective of native support; or the value
"none"to disable this script entirely.
- client time-out for abandoning a request (seconds)
Specify a value in seconds, for how long the script should wait before abandoning a request.
- expose the courier mechanism
falsefor whether to expose the generated
<iframe>. This is a development setting and should always have the value
falsein production use.
- try to negate iframe history events
Every time the script makes a data request through the courier
<iframe>, a history event may be generated. Whether or not it actually is generated varies widely by browser and circumstances, and so the script attempts to find a safe path through these quirks and negate as many history events as it can.
The purpose of this is so that when a user presses the Back button, the top-level page will go back, rather than it stepping through pages in the hidden
But the negation errs on the side of caution - if an event is not known to be safe, it will not be negated, and in this case "not safe" means there's a possibility the top-level page will go back, instead of the
<iframe>page; this is clearly not acceptable, hence the need to be cautious.
So even if with this setting enabled (set to
true) it's possible that residual events are still generated, resulting in the occasional need for users to click the back button twice, to go back to the previous page.
- lojax function name
You can specify the function name which is used for the re-creation object. The default value is obviously
"XMLHttpRequest", but you can call it anything you like.
This might be useful if you wish to separate scripted functionality between devices using this implementation and those using the native object, or if you wish to implement the framework for all browsers without over-writing their native object.
It's also necessary if you want to implement the framework in later builds of Safari (1.2 or later), or in Internet Explorer 7, in which it's not possible to over-write the native object, and therefore it will only work if the object has a different name (see additional browser notes).
By default, the PHP script is configured to reject requests outside its host domain. This is necessary for security, because an open framework would amount to a free proxy for spammers.
But you can specify additional hosts using the optional server-side
"lojax-hosts.php". If this file exists
in the same directory
"lojax.php", and contains
$lojax_hosts array of one or more host names,
then the script will be allowed to make requests
to any of the specified hosts. For example:
<?php //list host names or IP addresses //to which the script is allowed to make requests $lojax_hosts = array( 'www.mysite.com', 'www.myothersite.com' ); ?>
What's the point?
That's a good question!
I originally wrote this because I wanted the animated songpointer in my iTunes web interface to work on the Sony PSP; yet in that specific case I still haven't succeeded, due to the severe limitations of DOM scripting generally in that browser.
And that's the rub - what's the point of extending AJAX functionality to devices which don't have the complementary DOM support?
Clearly in many cases,
the answer is
none at all, and I'm certainly not suggesting that
everyone should start trying to making all their applications work in these
ancient and low-tech devices!
But it's nice to have the option, and it's for niche applications that this script really comes into its own. Maybe you need to support the PSP, Mac/IE5 or Opera 7, for whatever reason. Maybe you need data from several domains, or you'd like a managed solution that provides control over the order in which requests are returned. The LoJAX framework:
- opens up AJAX-based scripting to a wider range of devices
- can be configured to retrieve data from anywhere on the internet
- provides a platform for synchronising multiple requests
There's nothing revolutionary in all of this - there are plenty of
alternative RPC techniques,
that can be used in browsers which don't
XMLHttpRequest, or to bypass its normal limitations.
The implementation is based on the retro-specification drafted by the W3C, which itself appears to be largely based on what Firefox does. However there are missing features, as well as additional features, and there are deviations from the letter of the specification in places.
Core features supported
onreadystatechangeevents per request (one each of states
307redirects are followed (up to five per request)
- username and password authorization (but see the security note below)
- same-origin security restrictions apply by default
Unique features in LoJAX
- same-origin security restrictions can be overridden on a per-host basis
- browser progress bar is always shown when a request is made
- multiple requests are buffered to return in the same order they were made
open()..send()commands can be made without re-instantiating the request object
two custom error codes may be returned:
466 (Host Not Allowed)when attempting to make a request outside the current host or list of allowed hosts; and
467 (Unsupported Protocol)when attempting to make a request using an unsupported protocol (such as
Features not supported but safe to use
setRequestHeader()method exists so that it can be used without errors where native implementations require it for
POSTrequests, but it doesn't actually do anything
responseXMLis not supported (it's always
abort()cannot physically stop a request, it merely resets and stops watching the current request object - the server-side process is uncontrollably asynchronous at this point, and data may be subsequently returned, but it will be ignored
binary submission using
multipart/form-datais not supported
headers are only available if the
no support for sending an XML
document with the
readyStateis an inappropriate value, will return
nullinstead of raising a DOM exception
the challenge/response behavior for password protected resources
is not exactly the same - if you don't send the right details
in the original request, the browser won't prompt you to enter them,
you'll just get a
Other varations from native XHR
- requests made from the server-side script are HTTP 1.0
the returned headers may not be identical to those of a native
for example, they won't include
"TE"because the connection type will be
"keep-alive"; and additional values may be present, such as
If a request includes username and password authorization,
this information will be sent unencoded to the
Base 64 encoding, the process requires bit-shifting, which many of the older supported
browsers can't handle (such as Mac/IE5).
Additional browser notes
LoJAX is not supported
in Safari 1.0 or 1.1. Although the core scripting works, the interface
breaks the back button (pressing Back reloads
instead of going back).
I don't know of any way to fix this, so the script has
to be specifically disabled.
In Safari 1.2 or later and Internet Explorer 7
(both of which already support
the script cannot over-write the native object; so if you wish to
use the LoJAX framework for these browsers,
you will need to define a
function name other than
Discuss this page
Comments? Suggestions? Join the discussion!