Wednesday, October 7, 2009

History Utility

An ideal Ajax Application for me will be Gmail. A solid back-end and an interactive front-end. The features come in abundance and the user interaction is the smoothest. The most interesting aspect is how Gmail manages browser url,back button and screen content using the Fragment URL a.k.a the Hashtag. 

Lot of utilities are available for this such as Real Simple History, YUI History and jquery.address plugin. RSH is kinda weird to use in development, YUI is the coolest. jQuery Address was pretty reliable in the initial tinkerings but definitely not half as cool to work with as YUI.

But my biggest hiccup is most projects demand that we work on jQuery. Also if I use YUI just for History management using #tag 'I be Damned'. So I sat down on a 3 day code-sprint, coded something that works as a jQuery plugin and behaves like YUI in terms of events exposed. Here is the link to the small development environment I used to build it.




HUtil is the global singleton instance for this utiliity. HUtil exposes a HUtil.initialize() method which can be used to init the HUtil in your screen. 

In the demo index.html the same is called inside $(document).ready has been fired by jQuery. It is advisable to init the HUtil only after you have determined the state of the screen in your code using the Utility methods available in HUtil  

For getting the current bookmarked state of the application use 
HUtil.getBookmarkedState(module_name);  

Also available is a utility method to get the value of a param in the search string of the URL
HUtil.getQueryStringParameter(module_name);  
You can also use this utility method as 
HUtil.getQueryStringParameter(module_name, href );  

For registering a module use this API 
HUtil.registerModule(module_name, initSection).notify('HUtil:moduleStateChange', callback);  

Please note that the notify() method is currently chained to the module being registered. 

The registerModule API returns reference to the module object instance created. HUtil will fire the callback method for any change in the state of module registered with it, with the name of section returned as a param. 
To navigate the url to a particular section state use something like 
HUtil.navigate(smodule_name , new_value);  

There is an option to multi-navigate the URL also 
HUtil.multiNavigate(module_state_array); 

For example the module_state_array [{"navbar":"multi"},{"status":""}] defines new states for two sections navbar and status. 
Please note module_name is a string value. 

For every module update the HUtil will fire the registered methods for that section. You can handle your screen content here(similar to YUI). Also if the browser URL changes due to back button click these registered methods will be fired.  
The sample usage code is found in the index.html file. Feel free to do any tinkering with it. It is a lot similar to YUI API for their History Utility.

Its in dev phase so am not adding any acknowledgements and licenses etc just yet. Will be posting details regarding documentation and usage in near future.  
Do give Feedback, nothing like it. Cheers Guys!!!  :)

HERE IS THE DOWNLOAD LINK AGAIN

11 comments:

YuriKolovsky said...

excellent, I have been looking for a simplified version of ajax history managment, but i suggest a broad simplification for the end user, currently the example is pretty bloated where all that is really needed is this

$(document).ready(function(){
jQuery.history(callback,config);//detects change in hash and runs callback function (config is optional for whatever you might think of)
function callback(){
var hash = window.location.hash;
/*the rest is decided by user, what will be done with the new hash*/
}
});

i haven't done this yet, just writing whatever comes to mind :)


and considering that browsers are adding native support for #hash history it should become even simpler.

Moha said...

Thanks.
What you are suggesting is an ideal solution.

Thats very well possible if you use any existing solution which just inform you whats the new hash value and leaves the rest to you.

But I found that this approach as I saw in YUI was more usable in a Object Oriented environment for the developer using the utility. Not only it leaves the head ache out for tackling each every scenario at one place but also lets your code aware of any state change in a module or sub module independently and work accordingly.

But then Javascript has always let us work using our imagination :)

night-fairy-tales said...

Great plugin. Thanks

night-fairy-tales said...

Thoughts of a rumor:)

1. Must still make API documentation
2. You can merge the method of "navigate" and "multiNavigate". For example, you can analyze the type of the parameters obtained in the method.
3. Not thought through the situation when you need to simultaneously monitor changes in two or more parameters.

Moha said...

Thanks for your feedback.
This utility definitely does need a proper API documentation.

I am aware of a few drawbacks but I haven't been able to devote time to it lately.
Yeah... I think navigate and multinavigate can be merged. Maybe on the basis of an extra param config.... hmmmm....

The need for monitoring changes in more than one param was an edge case scenario I imagined, when a user action on the screen will lead to a major change.

This javascript needs a major second wind. :)

Thanks for all your feedback.

night-fairy-tales.com said...

Here's a draft version of the library with a redesigned mechanism of call events. Now, when you track the two options will occur one function call. But I am a little changed the format of the returned data.

Redisigned library

If you reduce all this to the general appearance and laid out the sources, for example, on Google Code, I am pleased to write about this wonderful library in my blog.

Code that is not used often die Unidentified

Moha said...

I see the change in params... I will give a more thorough look to the changes once :)

Its a fair enough change I will be happy to incorporate this. I was thinking if I can extend the functionality such that when you register a listener on a section then you get an option to pass optional return params that can be returned in the hash change you made for returned data.

Let me tinker more. I will definitely get back. Thanks for this. This kind of approach had totally skipped me when I wrote this.

Moha said...

Hi Sergey
I made some changes in my version and incorporated the concept of registering multiple modules. However I did not handle them in the way you did by creating an array inside each module and majorly changing the code.
I created another data structure in case of registering multiple modules.

This led to minimal changes on how modules were being handled in _modules[]

I also went ahead and added a feature to add arguments to the registered module.

These arguments are now returned to the listener.

How a listener gets info on the module changed has also been improved. Now I am passing a hash with module name and current state with arguments(if any);

I have also changed the index.html to showcase these changes. There are a couple of consoles in there so might not run on IE. You might wanna use firefox with firebug for this.

Also I came across a bug (pre existing or not- I didnt verify) that made the moduleEvent to be fired for all modules currently being tracked in the url hash. I have added a fix for the same.You will see the comments added if you a diff on the prev version and this one.

To download follow this link
NEW CHANGES and FIXES


Awaiting your feedback and comments on this.

Thanks :)

Moha said...

Oh and just in case if you find any issues or bugs do let me know. I would like that a lot. Thanks :)

night-fairy-tales.com said...

Hi, Anuraag.

I have a bit of free time and decided to try the modified code.

You can add tracking 2 parameters in the modified example (miraculously!). But will be called handler for each parameter when I simultaneously change 2 parameters.

For example:
Have the url - index.html # status = ys & navbar = multi & test1 = file_name
Changed to url - index.html # status = ys & navbar = multi_new & test1 = file_name_new

Will be called 2 times function "loadSection". Although, if I keep tracking 2 parameters, I need one calling function. :(

That was the main feature in the example that I implemented.

P.S. It is better to put the code on http://code.google.com/intl/en/projecthosting/

Moha said...

I will look into what you are suggesting most probably tonight after work. Meanwhile it would be great, if I could see the sample you created it would be great. You can mail me the script and html files on moha297@gmail.com if you feel comfortable.

I also thought of putting the code on Google Code earlier, but somehow never got about doing it. Will do it soon.

:)