Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Tuesday, April 8, 2008

My wishlist for a great Ajax API

Coming back from The Highland Fling it was interesting to see that people seem not to be quite convinced yet about the necessity of APIs and the large part they are playing in the next few years of web development. I guess this is partly based on experiences with APIs that aren’t properly explained to non-geeks and inconsistent or hard to use. There is just not much fun in trying to find information bit by bit if all you want to do is write some code (unless you have the old school hacker/cracker mind and didn’t consider spending hours looking at hexdumps trying to find a way to get endless lives in a games a waste of time).



During my interview with Paul Boag at I pointed out that designing a good API is as important as designing any other user interface – including your web page. Gareth Rushgrove agreed in his splendid talk How to be a first class web citizen. I also pointed out that there is a lack of clear and easy tutorials and articles on the matter, so I decided to have a go at it now.



Designing a great Ajax API



As an example I will use the recently released Google translation API, point out its good parts and list things I consider missing. I will not go into the part of actually writing the API but instead explain why I consider the missing parts important. This is not an attack towards Google, I just really liked working with this API and wanted to have it a bit easier to use, so no hard feelings, I really take off my hat that you offer an API like that!



Here are the points I consider important when we’re talking about Ajax APIs in JavaScript (Ajax implies that but you’d be surprised how often a REST API is advertised as Ajax):




  • Good documentation

  • Usage examples to copy + paste

  • Modularity

  • Link results to entries

  • Offer flexible input

  • Allow for custom object transportation

  • Cover usability basics



Documentation and presentation



Let’s start with a positive: the documentation of the Google Ajax Language API is great. You have all the information you need on one page including copy and paste examples. This allows you to work through the API online, read it offline and even print it out to read it on a crowded bus without having to take out your laptop.



Tip: If you are offering copy and paste examples – which by all means you should as this is what people do as a first step – make sure they work! I learnt the hard way in my book Beginning JavaScript with DOM Scripting and Ajax that there is nothing more dangerous than showcasing code snippets instead of full examples – people will copy and paste parts of a script, try to run it and either email you that your code is broken or – even worse – complain in book reviews on Amazon. If you offer copy and paste examples make sure all of them work independently.



Google offer explanations what the API is, what you can do with it, a list of all the parameters and what they mean. This is great for a first-glance user. For the hard-core audience they also offer a class reference.



Usage example



The first code example is quite good, you can copy and paste it and if your computer is connected to the Internet it will work – or it would, if the HTML got some fixes.



First of all it lacks a DOCTYPE, which is a bit annoying as it is a very important part of an HTML document. The more important bit is that the encoding is not set. The live example version has both – bit of a nuisance, as especially when we talk about different languages and using traditional Chinese as the example, the correct encoding is a must.



(Note: the irony, seems like wordpress doesn’t do this right for some reason …)


<html>
<head>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">

google.load("language", "1");

function initialize() {
var text = document.getElementById("text").innerHTML;
google.language.detect(text, function(result) {
if (!result.error && result.language) {
google.language.translate(text, result.language, "en",
function(result) {
var translated = document.getElementById("translation");
if (result.translation) {
translated.innerHTML = result.translation;
}
});
}
});
}
google.setOnLoadCallback(initialize);

</script>
</head>
<body>
<div id="text">??????????</div>
<div id="translation"></div>
</body>
</html>


Tip: make sure you explain to people that your code examples need an internet connection and other dependencies (like requiring HTTP and thus having to run on a local server). JavaScript historically didn’t have any other dependency than a browser, this is changing lately and can be confusing, especially when you use Ajax behind the scenes like some Flash/Ajax APIs do!



Modularity is good!



The first bit that threw me off to a certain degree was the google.load("langage","1") line, but there is an immediate explanation what it means.



The first script include loads a generic Google Ajax API that has a load() method to add other, smaller APIs build on top of this one. In this case the line means you want to load the language API with the version number 1.



This appears clunky and you will get bad feedback for it (it seems there is nothing better the woo the masses to have a one script include solution) but is actually rather clever.



By modularizing the Ajax code in a base library changes to the core functionality will be easy and by asking the implementer to include the APIs he needs with a version number you can make it the choice of the implementer to upgrade instead of breaking older implementations or having to carry the weight of full backwards compatibility.



Yes, the perfect world scenario is that you’ll never have to change the functionality of your API - just add new features – but in the real world there are constant changes that will make it necessary for you to mess with the original API. There is no such thing as perfect code that is built for eternity. Using a loader function in the base API is also pretty clever, as it means that implementers don’t need to change URLs.



What goes in should come out.



This is where Google created a problem. Both the google.language.detect() and the google.language.translate() methods are quite cool insofar they offer you to send a string and define a callback method when the API returned a value. However, the returning object in both cases gives a result and a status code, but not what was entered. You get all kind of other information (described in the class documentation) but having the original entry would be very useful.



Why? Well the great thing about Ajax is that it is asynchronous, and that is also its weakness. It means that I can send lots of requests in the background in parallel and wait for the results. However, this does not mean that the requests also return in the right order!



This means that if you want to loop through an array of texts to translate, the following is an unsafe way of doing it:



var translations = [ 'one','two','three','four','five','six','seven','eight','nine','ten'];
var gtl = google.language.translate;
for(var i=0,j=translations.length;i<j;i++){
gtl(translations[i],'en','de',function(result) {
if (!result.error) {
var container = document.getElementById('translation');
container.innerHTML += result.translation;
}
});
}


Instead you need to wrap the incrementation of the array counter in a recursive function:



var translations = [ 'one','two','three','four','five','six','seven','eight','nine','ten'];
var gtl = google.language.translate;
var i=0;
function doTranslation(){
var gtl = google.language.translate;
if(translations[i]){
gtl(translations[i], 'en', 'de', function(result) {
if (!result.error) {
var container = document.getElementById('translation');
container.innerHTML += result.translation;
i++;
doTranslation();
}
});
}
}
doTranslation();


This is safer, but we lost the opportunity to have several connections running in parallel and thus getting results faster. If the result of the API call had the original text in it, things would be easier, as we could for example populate a result object and match the right request with the right result that way:



var translations = [ 'one','two','three','four','five','six','seven','eight','nine','ten'];
var gtl = google.language.translate;
var results = {};
for(var i=0,j=translations.length;i<j;i++){
gtl(translations[i],'en','de',function(result) {
if (!result.error) {
results[result.input] = result.translation;
}
});
}


Even easier would be a transaction ID to pass in which could be the counter of the loop. Another option of course would be to allow more flexibility in the data that goes in.



Offering flexible input



Both the matching of the input text with the result and a transaction ID still would mean a lot of requests to the API, which is not really nice as it costs money and clobbers the server and the client alike. An easier option would be to not only allow a string as the text parameter but also an array of strings. The return then would also become an array and a lot of the overhead of calling the translation engine would be done on the server in a single call instead of lots and lots of API calls.



This is not hard to do and most JavaScript framework methods work that way, by checking the type of the first argument and branching accordingly. You can even go further and allow the implementers to send an own bespoke object as a third parameter.



Transporting a custom object allows implementers write a lot less code



The benefit of a custom object going out and in is that you can add more parameters to the API call that are only specific to the implementation. Most likely this could be a reference to a namespace to avoid having to repeat long method names or global variables. You could start by providing parameters that make sense to any Ajax call in terms of usability.



Thinking Ajax usability



The main thing any Ajax call should offer a user is a timeout. There is nothing more disappointing than getting the promise of a brave new Ajax world with much more interactive interfaces and then getting stuck looking at spinning wheels or worse hitting a link and getting nothing. Right now the language API has nothing like this, and you’d have to roll a solution by hand. You’d also have to check the error status code to see if the data could not be retrieved and call a failure case of the connection that way.



A nice API would offer me these options, most likely all rolled in one parameters object.



My dream translation API



Taking all these into consideration it would be perfect to get the API to offer these options:



google.language.translate(input,parameters);


The parameters would be:




input // string or array
parameters // object with the following properties
sourceLanguage:string,
targetLanguage:string,
transactionId:string,
customparameters:object, // to transport
timeout:integer, // (in milliseconds)
failure:function(result,params), // (method to call when there is a timeout or an error)
success:function(result,params), // (method to call when all is fine)


The returned data from the API should have both the result and the parameters provided. This would make the life of implementers dead easy.



Summary



In summary, here’s what I expect from a great Ajax API:




  • Have a good documentation with immediate copy and paste examples backed up by a full class documentation

  • Build your APIs modular and allow the implementer to choose the version they want to have

  • Provide a hook to link the result of the API methods to the initial data entered. The easiest way is to repeat this data, more sophisticated is to allow for a connection ID.

  • Allow for multiple values to be sent through, it’ll save you API calls and the implementer hacking around the problem of unreliable order of returns.

  • Allow implementers to add an own object to send and get back to allow for namespacing and other data state retention.

  • Allow for a timeout, connections are not to be trusted.



This is a work in progress



I hope you found something here to agree with and if you know things to add, just drop a comment.



Technorati Tags: , , , ,


Wednesday, March 12, 2008

Video captioning made easy with the YouTube JavaScript API

One thing that has been annoying me for ages is that no video player on the web allows you to write comments for a specific time in the video that get displayed as plain text. Viddler allows you to comment at a certain time and it appears in the video, but the benefits of time based captioning both in terms of accessibility and SEO didn’t quite transpire to any video site maintainers yet. Edit: Darn, I hadn’t looked at Viddler for a long time, it actually does this now, well done!



Google just released a JavaScript API for YouTube which makes it dead easy to control a video with JavaScript. You can start, stop and jump to a certain time of the video but more importantly – you have events firing when something happens to the player. This made it easy for me to whip up a proof of concept how time-based captioning might work as an interface. Click the screenshot to see it in action.



Screenshot of video with timed captions created with a small JavaScript



Start the video and hit the pause button to add a new caption. You can delete captions by hitting the x links and you can jump back to the section of the video by clicking the time stamp.



Check the source for how it is done. In order to make this a service, all you need to do is have a backend script that gets all the form fields and store it in a DB.



Technorati Tags: , , , , ,


Wednesday, February 6, 2008

Five things to do to a script before handing it over to the next developer

Let’s face fact folks: not too many developers plan their JavaScripts. Instead we quickly write something that works, and submit it. We come up with variable and function names as we go along and in the end know that we’ll never have to see this little bit of script ever again.



The problems start when we do see our script again, or we get scripts from other developers, that were built the same way. That’s why it is good to keep a few extra steps in mind when it comes to saying “this is done, I can go on”.



Let’s say the job was to add small link to every DIV in a document with the class collapsible that would show and hide the DIV. The first thing to do would be to use a library to get around the issues of cross-browser event handling. Let’s not concentrate on that for the moment but go for oldschool onevent handlers as we’re talking about different things here. Using a module pattern we can create functionality like that with a few lines of code:





collapser = function(){


var secs = document.getElementsByTagName('div');
for(var i=0;i<secs.length;i++){
if(secs[i].className.indexOf('collapsible')!==-1){
var p = document.createElement('p');
var a = document.createElement('a');
a.setAttribute('href','#');
a.onclick = function(){
var sec = this.parentNode.nextSibling;
if(sec.style.display === 'none'){
sec.style.display = 'block';
this.firstChild.nodeValue = 'collapse'
} else {
sec.style.display = 'none';
this.firstChild.nodeValue = 'expand'
}
return false;
};
a.appendChild(document.createTextNode('expand'));
p.appendChild(a);
secs[i].style.display = 'none';
secs[i].parentNode.insertBefore(p,secs[i]);
}
}
}();



This is already rather clean (I am sure you’ve seen innerHTML solutions with javascript: links) and unobtrusive, but there are some things that should not be there.



Step 1: Remove look and feel



The first thing to do is not to manipulate the style collection in JavaScript but leave the look and feel to where it belongs: the CSS. This allows for ease of skinning and changing the way of hiding the sections without having to mess around in the JavaScript. We can do this by assigning a CSS class and removing it:



collapser = function(){
var secs = document.getElementsByTagName('div');
for(var i=0;i<secs.length;i++){
if(secs[i].className.indexOf('collapsible')!==-1){
secs[i].className += ' ' + 'collapsed';
var p = document.createElement('p');
var a = document.createElement('a');
a.setAttribute('href','#');
a.onclick = function(){
var sec = this.parentNode.nextSibling;
if(sec.className.indexOf('collapsed')!==-1){
sec.className = sec.className.replace(' collapsed','');
this.firstChild.nodeValue = 'collapse'
} else {
sec.className += ' ' + 'collapsed';
this.firstChild.nodeValue = 'expand'
}
return false;
}
a.appendChild(document.createTextNode('expand'));
p.appendChild(a);
secs[i].parentNode.insertBefore(p,secs[i]);
}
}
}();


Step 2: Remove obvious speed issues



There are not many issues in this script, but two things are obvious: the for loop reads out the length attribute of the secs collection on every iteration and we create the same anonymous function for each link to show and hide the section. Caching the length in another variable and creating a named function that gets re-used makes more sense:




collapser = function(){
var secs = document.getElementsByTagName('div');
for(var i=0,j=secs.length;i<j;i++){
if(secs[i].className.indexOf('collapsible')!==-1){
secs[i].className += ' ' + 'collapsed';
var p = document.createElement('p');
var a = document.createElement('a');
a.setAttribute('href','#');
a.onclick = toggle;
a.appendChild(document.createTextNode('expand'));
p.appendChild(a);
secs[i].parentNode.insertBefore(p,secs[i]);
}
}
function toggle(){
var sec = this.parentNode.nextSibling;
if(sec.className.indexOf('collapsed')!==-1){
sec.className = sec.className.replace(' collapsed','');
this.firstChild.nodeValue = 'collapse'
} else {
sec.className += ' ' + 'collapsed';
this.firstChild.nodeValue = 'expand'
}
return false;
}
}();


Step 3: Removing every label and name from the functional code



This makes a lot of sense in terms of maintenance. Of course it is easy to do a quick search + replace when the label names or class names have to change, but it is not really necessary. By moving everything human readable into an own config object you won’t have to hunt through the code and suffer search + replace errors, but instead keep all the changing bits and bobs in one place:




collapser = function(){
var config = {
indicatorClass : 'collapsible',
collapsedClass : 'collapsed',
collapseLabel : 'collapse',
expandLabel : 'expand'
}
var secs = document.getElementsByTagName('div');
for(var i=0,j=secs.length;i<j;i++){
if(secs[i].className.indexOf(config.indicatorClass)!==-1){
secs[i].className += ' ' + config.collapsedClass;
var p = document.createElement('p');
var a = document.createElement('a');
a.setAttribute('href','#');
a.onclick = toggle;
a.appendChild(document.createTextNode(config.expandLabel));
p.appendChild(a);
secs[i].parentNode.insertBefore(p,secs[i]);
}
}
function toggle(){
var sec = this.parentNode.nextSibling;
if(sec.className.indexOf(config.collapsedClass)!==-1){
sec.className = sec.className.replace(' ' + config.collapsedClass,'');
this.firstChild.nodeValue = config.collapseLabel
} else {
sec.className += ' ' + config.collapsedClass;
this.firstChild.nodeValue = config.expandLabel
}
return false;
}
}();


Step 4: Use human-readable variable and method names



This is probably the most useful step when it comes to increasing the maintainability of your code. Sure, during development sec made a lot of sense, but doesn’t section make it easier to grasp what is going on? What about a, and especially when it needs to be changed to a button later on? Will the maintainer rename it to button?




collapser = function(){
var config = {
indicatorClass : 'collapsible',
collapsedClass : 'collapsed',
collapseLabel : 'collapse',
expandLabel : 'expand'
}
var sections = document.getElementsByTagName('div');
for(var i=0,j=sections.length;i<j;i++){
if(sections[i].className.indexOf(config.indicatorClass) !== -1){
sections[i].className += ' ' + config.collapsedClass;
var paragraph = document.createElement('p');
var trigger = document.createElement('a');
trigger.setAttribute('href','#');
trigger.onclick = toggleSection;
trigger.appendChild(document.createTextNode(config.expandLabel));
paragraph.appendChild(trigger);
sections[i].parentNode.insertBefore(paragraph,sections[i]);
}
}
function toggleSection(){
var section = this.parentNode.nextSibling;
if(section.className.indexOf(config.collapsedClass) !== -1){
section.className = section.className.replace(' ' + config.collapsedClass,'');
this.firstChild.nodeValue = config.collapseLabel
} else {
section.className += ' ' + config.collapsedClass;
this.firstChild.nodeValue = config.expandLabel
}
return false;
}
}();


Step 5: Comment, sign and possibly eliminate the last remaining clash with other scripts



The last step is to add comments where they are really needed, give your name and date (so people can ask questions and know when this was done), and to be really safe we can even get rid of the name of the script and keep it an anonymous pattern.




// Collapse and expand section of the page with a certain class
// written by Christian Heilmann, 07/01/08
(function(){

// Configuration, change CSS class names and labels here
var config = {
indicatorClass : 'collapsible',
collapsedClass : 'collapsed',
collapseLabel : 'collapse',
expandLabel : 'expand'
}

var sections = document.getElementsByTagName('div');
for(var i=0,j=sections.length;i<j;i++){
if(sections[i].className.indexOf(config.indicatorClass)!==-1){
sections[i].className += ' ' + config.collapsedClass;
var paragraph = document.createElement('p');
var triggerLink = document.createElement('a');
triggerLink.setAttribute('href','#');
triggerLink.onclick = toggleSection;
triggerLink.appendChild(document.createTextNode(config.expandLabel));
paragraph.appendChild(triggerLink);
sections[i].parentNode.insertBefore(paragraph,sections[i]);
}
}
function toggleSection(){
var section = this.parentNode.nextSibling;
if(section.className.indexOf(config.collapsedClass)!==-1){
section.className = section.className.replace(' ' + config.collapsedClass,'');
this.firstChild.nodeValue = config.collapseLabel
} else {
section.className += ' ' + config.collapsedClass;
this.firstChild.nodeValue = config.expandLabel
}
return false;
}
})();


All very obvious things, and I am sure we’ve all done them before, but let’s be honest: how often do we forget them and how often do you have to alter code where it’d have been nice if someone had taken these steps?



Technorati Tags: , , , , , , ,


Friday, January 25, 2008

Facebook releases JavaScript Client Library

Wei Zhu seems to be cooking with gas recently, and has released the JavaScript Client Library for Facebook API, which is a client side JavaScript library that mimics the other language client libraries (PHP, Python, Java, Ruby, etc):



An application that uses this client library should be registered as an iframe type. This applies to either iframe Facebook apps that users access through the Facebook web site or apps that users access directly on the app’s own web sites.


The solution uses a cross domain receiver:



HTML:





  1.  



  2. <html xmlns="http://www.w3.org/1999/xhtml">






  3.     <title>cross domain receiver page</title>



  4. </head>



  5. <body style="background-color:Green;">



  6.     <script src="http://static.ak.facebook.com/js/api_lib/XdCommReceiver.debug.js" type="text/javascript"></script>



  7.     <script type="text/javascript">



  8.         FB_ReceiverApp$main();



  9.     </script>



  10. </body>



  11. </html>



  12.  






Then, with a few script src's you can talk to Facebook:



JAVASCRIPT:





  1.  



  2. // Create an ApiClient object, passing app’s api key and



  3. // a site relative url to xd_receiver.htm



  4. var api = new FB.ApiClient('<insert_your_app_key_here', '/xd_receiver.htm', null);



  5.        



  6. // require user to login



  7. api.requireLogin(function(exception) {



  8.     window.alert(“Current user id is “ + api.get_session().uid);



  9.  



  10.     // Get friends list 



  11.     api.friends_get(function(result, exception) {



  12.       Debug.dump(result, 'friendsResult from non-batch execution ')



  13.     });       



  14. });



  15.  






It is good to see a JavaScript API like this. Now you can stay in JavaScript land and write code that works with OpenSocial, Facebook, and more. NOTE: If you live in FBML? No cigar.





Thursday, January 17, 2008

Triggit: WYSIWYG Content Insertion Tool and Platform

Triggit has created a very interesting tool. The problem they are trying to solve is that many people want to muck around with their websites, but don't want to grok HTML. They want to integrate with services (mash them up in a manual one off way) such as insert their videos from YouTube, photos from Flickr, and other publishing items. One big one is being able to add advertising to the site.


As techies we often think that things are easy enough, "What? You just put in some embed code.... how hard is that!" Triggit allows you to go meta and put in only one embed code, and then offer a toolbar for users to add content in WYSIWYG style.


How does this all work?


When you put in that script code on your site, it has a hook back to the Triggit platform. Say you want to add a photo from Flickr: In the tool you find the photo and place it on the screen and hit save. The action is saved back to Triggit 'add this photo to that location with this style'. Then when a visitor hits the site, the page is loaded, the JavaScript is run, and the action is sent down to the browser and the DOM is changed to add this image. Zach said that one of the biggest challenges was getting this working across the various browsers, so when you put an image at some place using Firefox (the first browser that is supported for the editor side), it ends up in the right place no matter which browser is used from the visitor perspective.


This means that you now have a logical page, but content is split between you real backend, and the Triggit servers. The advantage to this method is that you can integrate with anything. You don't need to have special code that groks a particular backend service, it is all generic.


So, this is a little out there. You are balancing between making it incredibly easy to update pages, and adding complexity by having content in separate places. The page could jump a little depending on the amount of information coming down, if Triggit gets dugg, or what have you. If successful though, you can see as developers that you could write plugins for the system and allow John Doe to easily tie in your content. That is the future promise.


Fancy giving it a go? Zach gave Ajaxian readers 300 invites (as the product IS in beta!). Head over to the signup page and use the code "ajaxian" and if you are in the first 300 you should be good to go. Oh, and for coolness factor, I believe that Rails, Erlang, and crazy JavaScript skills were used to make this happen.


I got to sit down with Zach Coelius and he discusses the product, and gives us a walk through:








I also have a short demo of it running on my own blog:








And, finally, they have their own screencast of the tool at work.


Press Release



Triggit, a San Francisco based startup, with the aim of making life a lot simpler for web publishers, today announced the beta launch of the first ever WYSIWYG web application for integrating third party elements into websites.


With Triggit, any web publisher can now drag and drop advertisements, Flickr pictures, YouTube videos and more, directly into their site without any skills in web programming. Triggit is free to use, and works on any site that accepts JavaScript. It does not require any downloads, access to FTP, or APIs, and installs easily by pasting one small piece of code in the site.


“Triggit is here to help anyone who would like to take full advantage of the resources of the web for their site who isn’t a programmer and who doesn’t think in code,” says Susan Coelius-Keplinger, Triggit’s COO.


At a time when more and more non-technical publishers are coming online, Triggit is focused on removing the complexity of using code to add third party objects to a page. Whether it is widget, a video of a dog skateboarding, or a banner ad, current technology still requires the use of embedded code to integrate these elements into a website. For publishers accustomed to using graphical user interfaces for all their computing, it can be a daunting task to modify and integrate code into their websites. One area where this is a particular problem is for online advertising networks who continue to lose hundreds of millions of dollars of potential earnings annually to web publishers who can’t integrate and optimize their ad units.


Triggit’s goal is to serve as a feature-rich tool whereby publishers can quickly and easily integrate all manner of widgets, content, advertising units, APIs and data from third party sites. In doing so, it operates as a distribution arm for companies seeking to spread the reach of their advertisements, widgets, content and data on the web. By making it easier for web publishers to integrate these objects into their websites, Triggit helps to expand the ability of these companies to reach larger online audiences and add new revenue streams. Ryan Tecco, Triggit’s CTO says “It is really early days for this technology. There are a lot of things waiting in the wings that we haven’t yet put into the tool. We are very excited to see where this goes”.





Wednesday, January 16, 2008

Brian Klug of the PBwiki team wanted to learn more about

Brian Klug of the PBwiki team wanted to learn more about JavaScript serving, so they created a JavaScript Library Test which tests the loading time of Dojo, jQuery, Prototype, YUI, and Protoculous.


The test compares packed vs. minified, gzipped vs not, cached, etc. with some interesting results (hint: don’t used packed!). You can use your browser to help test, or see the combined results of thousands of testers.


JavaScript Library Results





Monday, February 26, 2007

Dojo Offline Demo and Release

Brad Neuberg keeps sprinting with his offline work for Dojo. He has just released a demo of an offline aware editor, and a release of the code itself:



We’ve finished the JavaScript layer of Dojo Offline. Dojo Offline consists of two major pieces: a JavaScript API that is included with a web application, and which helps with syncing, on/offline status notification, caching of data and resources, etc.; and a local small web proxy download that is cross-platform and cross-browser and which is web application independent. The JavaScript API is now finished, and can actually be used even though we have not finished the local web proxy yet. This is done by having the JavaScript layer be able to use the browser’s native cache if no offline cache is available. This means you can start playing with Dojo Offline right now, with the download link included in this blog post below. Note that using the browser cache instead of the web proxy is only suitable for prototyping and should not be deployed on production applications; it will work with varying degrees of success on Internet Explorer and Firefox, but not consistently on Safari. Higher levels of reliability will only come when we deliver the local web proxy component.


To start using Dojo Offline now in conjunction with the browser cache, you must have the following in your JavaScript code: dojo.off.requireOfflineCache = false. You must also turn on HTTP caching headers on your web server; how to turn on these HTTP headers and which ones to turn on are explained in the Dojo Storage FAQ. See the Moxie code links below for more examples of how to use the API. Note that the Dojo Offline JavaScript API has changed, especially for syncing, since our API blog post about a month ago and has become much simpler — see the Moxie source for details.


The demo of Moxie shown in the screencast can also be played with right in your browser. Please note that both Moxie and Dojo Offline are still alpha; you are literally seeing Dojo Offline being developed in front of your eyes, and glitches remain in both of them. Please debug and provide test cases for errors you find to help development.



Info



Moxie Offline Demo