Hi list,

In one of my previous projects I had to satisfy the requirement of handling browser back- and forward calls within an Ajax application. Thus I didn't get an urge to switch the JS part of this project to an other framework like dojo (which supports Browser history handling out-of-the-box), I had to come up with an idea of doing this with prototype/scriptaculous.

The arisen source code:

Ajax.History = {
    initialize: function(options) {
        this.options = Object.extend({
            interval: 200
        },options||{});
        this.callback = this.options.callback || Prototype.emtpyFunction;
        if(navigator.userAgent.toLowerCase ().indexOf('msie') > 0)
            this.locator = new Ajax.History.Iframe('ajaxHistoryHandler', this.options.iframeSrc);
        else
            this.locator = new Ajax.History.Hash();
        this.currentHash = '';
        this.locked = false;
       
    },
    add: function(hash) {
        this.locked = true;
        clearTimeout(this.timer);
        this.currentHash = hash;
        this.locator.setHash(hash);
        this.timer = setTimeout(this.checkHash.bind(this), this.options.interval);
        this.locked = false;
    },
    checkHash: function(){
        if(!locked){
            var check = this.locator.getHash();
   
            if(check != this.currentHash){
                this.callback(check);
                this.currentHash = check;
            }
        }
        this.timer = setTimeout(this.checkHash.bind(this), this.options.interval);
    },
    getBookmark: function(){
        return this.locator.getBookmark();
    }
}
// Hash Handler for IE (Tested with IE6)
Ajax.History.Iframe = Class.create();
Ajax.History.Iframe.prototype = {
    initialize: function(id, src) {
        this.url = '';
        this.id = id || 'ajaxHistoryHandler';
        this.src = "" || '';
        document.write('<iframe src="" id="'+this.id+'" name="'+this.id+'" style="display: none;" ></iframe>');
    },
    setHash: function(hash){
        try {
            $( this.id).setAttribute('src', this.src + '?' + hash);
        }catch(e) {}
        window.location.href = "" + '#' + hash;
    },
    getHash: function(){
        try {
            return (document.frames[this.id].location.href||'?').split('?')[1];
        }catch(e){ return ''; }
    },
    getBookmark: function(){
        try{
            return window.location.href.split('#')[1]||'';
        }catch(e){ return ''; }
    }
}
// Hash Handler for a modern browser (tested with firefox 1.5)
Ajax.History.Hash = Class.create();
Ajax.History.Hash.prototype = {
    initialize: function(){
       
    },
    setHash: function(hash){
        window.location.hash = hash;
    },
    getHash: function(){
        return window.location.hash.substring(1)||'';
    },
    getBookmark: function(){
        try{
            return window.location.hash.substring(1)||'';
        }catch(e){ return ''; }
    }
}


Sample Usage:

first you have to define a callback method for the history handler which replays a previous ajax request:

var historyUpdate = function(hash) {
    new Ajax.Request(
       ....
}

in the onSuccess/onComplete of a Ajax.Request or Ajax.Updater (etc) you have to add an history point:

var handleSuccess = function(request){
     //... update DOM or smth like that
     Ajax.History.add(request.options.parameters)
     //...
}
(might also be done an Ajax.Responder or something like that)

and in the foot of your html page you have to insert smth like:

    <script type="text/_javascript_">
        // <![CDATA[
            var historyHandler = Ajax.History.initialize({
                callback: historyUpdate,
                iframeSrc: ' http://url.of.an/empty/page.html'
            });
        // ]]>
    </script>



Explanation:
The Ajax.History object periodically (defined by the option intervall) checks the hash object for a change. There are currently 2 implementations for this hash object. iframe based for IE and window.location.hash based for firefox/mozilla. When the hash changes the callback function gets called with the changed hash as arguement. History entries are added with Ajax.History.add('a_new_hash').

This is a very simple implementation of history support and needs to be radically extended to be usefull ;)

So any ideas, proposals, hints or something like that are greaty appreceated

I will set up a test page and unit tests when I can spare some time for it...

best regards


--
Mit freundlichen Grüßen

Siegfried Puchbauer
_______________________________________________
Rails-spinoffs mailing list
Rails-spinoffs@lists.rubyonrails.org
http://lists.rubyonrails.org/mailman/listinfo/rails-spinoffs

Reply via email to