﻿/*!
 * jQuery history plugin v0.1
 * (c) 2011 Joris van der Burgh
 * 
 * https://bitbucket.org/nxt/jquery-history
 * 
 */
(function ($) {
    var h,
		html5Enabled = (typeof window.history.pushState !== 'undefined'),
		listeners = {},
		initialized = false,
    //the initial url, used to make url's absolute
		initialRootWithHash = window.location.href,
		initialRoot = initialRootWithHash,
		docRoot = initialRoot.substring(0, initialRoot.indexOf('/', initialRoot.indexOf('://') + 3));
    //remove anything after the hash
    if (initialRoot.indexOf('#') != -1) {
        initialRoot = initialRoot.substr(0, initialRoot.indexOf('#'));
    }

    h = {
        bind: function (type, handler) {
            var list = listeners[type] = listeners[type] || [];
            list.push(handler);
            return this;
        },
        unbind: function (type, handler) {
            var list = listeners[type];
            if (list) {
                for (var i = 0; i < list.length; i++) {
                    if (list[i] === handler) {
                        list.splice(i, 1);
                        break;
                    }
                }
            }
            return this;
        },
        trigger: function (type, data) {
            var list = listeners[type];
            if (list) {
                var args = [];
                for (var i = 1; i < arguments.length; i++) {
                    args.push(arguments[i]);
                }
                for (var i = 0; i < list.length; i++) {
                    if (list[i].apply(list[i], args) === false) {
                        break;
                    }
                }
            }
            return this;
        },
        // navigate to the url
        navigateTo: function (url, title) {
            url = normalizeUrl(url);
            if (!html5Enabled) {
                //document.location.hash = "#" + encodeURIComponent('!' + url);
                document.location.hash = "#!" + url;
            } else {
                //history.pushState(data[title], title, event.target.href);
                var state = {};
                window.history.pushState(state, title, url);
                //trigger the url changed event manually 
                h.handleUrlChange(url);
            }
        },
        //initialize, add listeners, etc
        init: function () {
            if (initialized) { return; }
            initialized = true;
            $.History.currentRoot = normalizeUrl("./"); 
            //if(!html5Enabled) {
            if ("onhashchange" in window) {
                $(window).bind('hashchange', function () {
                    if (!html5Enabled || $.History.alwaysMonitorHashChanges) {
                        h.handleHashChange();
                    }
                });
                //handle first hash? 
                if ($.History.alwaysMonitorHashChanges && document.location.hash != '' && document.location.hash != '#') {
                    h.handleHashChange();
                }
            } else {
                var hash = ''; //document.location.hash;
                if (document.location.hash == '#') {
                    hash = '#';
                }
                setInterval(function () {
                    if (!html5Enabled || $.History.alwaysMonitorHashChanges) {
                        if (document.location.hash != hash) {
                            //console.log(hash + " != " + document.location.hash);

                            hash = document.location.hash;
                            h.handleHashChange();
                        }
                    }
                }, parseInt($.History.monitorInterval, 10) || 100);
            }
            //} 
            if (html5Enabled) {
                //listen for url changes
                var isFirst = true;
                $(window).bind('popstate', function (e) {
                    if (isFirst) {
                        isFirst = false;
                        //skip the first event if it points to the active page
                        if (document.location.href == initialRootWithHash) {
                            return;
                        }
                    }
                    //alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
                    h.handleUrlChange(document.location.href);
                });
            }
        },
        //convert the hash into an url and call handleUrlChange
        handleHashChange: function () {
            var hash = document.location.hash;
            if (hash.indexOf('#') === 0) hash = hash.substr(1);
            hash = decodeURIComponent(hash);
            if (hash.indexOf('!') === 0) hash = hash.substr(1);
            //handle url 
            if (html5Enabled) {
                this.handleUrlChange(hash, 'hashchange');
            } else {
                this.handleUrlChange(hash);
            }
        },

        //handle change, fire event, ...
        handleUrlChange: function (url, eventType) { 
            url = normalizeUrl(url);
            if (h.currentUrl != url) {
                h.currentUrl = url; 

                //console.log(" URL = '" + url + "'");
                var relativeUrl = url;

                if ($.History.currentRoot && relativeUrl.indexOf($.History.currentRoot) === 0) {
                    relativeUrl = relativeUrl.substr($.History.currentRoot.length);
                }
                h.trigger(eventType || 'change', url, relativeUrl);
            }
        }
    };



    function normalizeUrl(url) {
        if (url.indexOf(docRoot) == 0) {
            return url.substr(docRoot.length);
        }
        if (url.indexOf('/') !== 0) {
            //make absolute

            var r = initialRoot.substr(docRoot.length);
            var parts = r.split('/');
            //remove the last part wich contains the filename or an empty string if the url ended with a slash 
            parts.splice(parts.length - 1, 1);
            //now get the url parts
            var urlParts = url.split('/');
            for (var i = 0; i < urlParts.length; i++) {
                if (urlParts[i] == '..') {
                    if (parts.length > 0) {
                        //remove the last part
                        parts.splice(parts.length - 1, 1);
                    }
                } else if (urlParts[i] == '.') {
                    //continue
                    continue;
                } else {
                    //add this part
                    parts.push(urlParts[i]);
                }
            }
            url = parts.join('/');
            if (url.indexOf('/') !== 0) {
                url = '/' + url;
            }
        }
        return url;
    }

    $.History = {
        monitorInterval: 50,
        alwaysMonitorHashChanges: false,
        bind: h.bind,
        unbind: h.unbind,
        navigateTo: h.navigateTo
    };
    /**
    * Listen for click events on the matched elements
    * and use the "href" attribute for the url
    */
    $.fn.history = function (config) {

        this.bind('click', function (e) {
            e.preventDefault();
            var me = $(this);
            var url = me.attr('href');
            h.navigateTo(url, me.attr('title') || '');
            return false;
        });
        if (config && config.listeners) {
            if ($.isArray(config.listeners)) {
                for (var i = 0; i < config.listeners.length; i++) {
                    h.unbind('change', config.listeners[i]);
                    h.bind('change', config.listeners[i]);
                }
            } else {
                h.unbind('change', config.listeners);
                h.bind('change', config.listeners);
            }
        }
        h.init();
        return this;
    };

    //$.history = h;
})(jQuery);




