Exactly the kind of thing I don't think is necessary or even good. You should port that idea over to a user control that acts as an undo/redo control, and does not mess around with the history hash. Not knocking your work, it's good code (except maybe for the document.write stuff -- use Builder instead)... but for a community that is so centered on standards and not breaking known conventions, I really don't understand this mentality of breaking the back button to try to use it as an undo control for a rich internet application. If your page is using Ajax and has thus become an application in domain of the DOM, treat it as an application and add the necessary application level controls (including undo/redo) and stop hijacking the browser. When I see a link on a news site for the latest and greatest Ajax site and I go to it to check it out, and I do a few things in it and then I'm done and I want to go back to that news site, I darn well expect to hit the back button ONCE (one time, uno, 1) to get there. I don't want to see every little operation I performed in that app undo itself before I can get back to the news site.

On 7/7/06, Siegfried Puchbauer <[EMAIL PROTECTED]> wrote:
Hey guys,

Some time ago I investigated some time on this topic and implemented a small solution based on prototype. It's tested in Firefox and IE6 (IMHO there is no working solution for Safari).

Here is the mail I allready send to the 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 ;)



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



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

Reply via email to