/** * SWFAddress 2.0: Deep linking for Flash and Ajax - http://www.asual.com/swfaddress/ * * SWFAddress is (c) 2006-2007 Rostislav Hristov and is released under the MIT License: * http://www.opensource.org/licenses/mit-license.php * */if (typeof asual == "undefined") var asual = {};if (typeof asual.util == "undefined") asual.util = {};   /** * @class Utility class that provides detailed browser information. * @static */asual.util.Browser = new function() {    var supported = false;    var version = -1;    var agent = navigator.userAgent;    var ie = false;    var camino = false;    var safari = false;    var opera = false;    var mozilla = false;    if (/MSIE/.test(agent)) {        ie = true;        version = parseFloat(agent.substring(agent.indexOf('MSIE') + 4));        supported = version >= 6;    } else if (/AppleWebKit/.test(agent)) {        safari = true;        version = parseFloat(agent.substring(agent.indexOf('Safari') + 7));        supported = version >= 312;    } else if (/Opera/.test(agent)) {        opera = true;        version = parseFloat(navigator.appVersion);        supported = version >= 9.02;    } else if (/Camino/.test(agent)) {        camino = true;        version = parseFloat(agent.substring(agent.indexOf('Camino') + 7));        supported = version >= 1;    } else if (/Firefox/.test(agent)) {        mozilla = true;        version = parseFloat(agent.substring(agent.indexOf('Firefox') + 8));        supported = version >= 1;    } else if (/Netscape/.test(agent)) {        mozilla = true;        version = parseFloat(agent.substring(agent.indexOf('Netscape') + 9));        supported = version >= 8;    } else if (/Mozilla/.test(agent) && /rv:/.test(agent)) {        mozilla = true;        version = parseFloat(agent.substring(agent.indexOf('rv:') + 3));        supported = version >= 1.8;    }    /**     * Detects if the browser is supported.     * @return {Boolean}     * @static     */    this.isSupported = function() {        return supported;    }    /**     * Detects the version of the browser.     * @return {Number}     * @static     */    this.getVersion = function() {        return version;    }    /**     * Detects if the browser is Internet Explorer.     * @return {Boolean}     * @static     */    this.isIE = function() {        return ie;    }    /**     * Detects if the browser is Safari.     * @return {Boolean}     * @static     */    this.isSafari = function() {        return safari;    }    /**     * Detects if the browser is Opera.     * @return {Boolean}     * @static     */    this.isOpera = function() {        return opera;    }    /**     * Detects if the browser is Camino.     * @return {Boolean}     * @static     */    this.isCamino = function() {        return camino;    }    /**     * Detects if the browser is Mozilla.     * @return {Boolean}     * @static     */    this.isMozilla = function() {        return mozilla;    }}/** * @class Utility class that provides event helpers. * @static */asual.util.Events = new function() {    var cache = [];    var browser = asual.util.Browser;    var dcl = 'DOMContentLoaded';    if (browser.isIE()) {        document.write('<script id=swfaddress-dcl defer=true src=//:></script>');        document.getElementById('swfaddress-dcl').onreadystatechange = function() {            if (this.readyState == 'complete') {                 this.parentNode.removeChild(this);                for (var i = 0, e; e = cache[i]; i++) {                    if (e.t == dcl) e.l.call(null);                }            }        };    } else if (browser.isSafari()) {        var timer = setInterval(function() {            if (/loaded|complete/.test(document.readyState)) {                clearInterval(timer);                 for (var i = 0, e; e = cache[i]; i++) {                    if (e.t == dcl) e.l.call(null);                }            }        }, 10);    }    /**     * Adds an event listener to an object.     * @param {Object} obj The object that provides events.     * @param {String} type The type of the event.     * @param {Function} listener The event listener function.     * @return {void}     * @static     */    this.addListener = function(obj, type, listener) {        cache.push({o: obj, t: type, l: listener});        if (type == dcl && (browser.isIE() || browser.isSafari()))            return;        if (obj.addEventListener){            obj.addEventListener(type, listener, false);        } else if (obj.attachEvent){            obj.attachEvent('on' + type, listener);        }    }    /**     * Removes an event listener from an object.     * @param {Object} obj The object that provides events.     * @param {String} type The type of the event.     * @param {Function} listener The event listener function.     * @return {void}          * @static     */    this.removeListener = function(obj, type, listener) {        for (var i = 0, e; e = cache[i]; i++) {            if (e.o == obj && e.t == type && e.l == listener) {                cache.splice(i, 1);                break;            }        }        if (type == dcl && (browser.isIE() || browser.isSafari()))            return;        if (obj.removeEventListener){            obj.removeEventListener(type, listener, false);        } else if (obj.detachEvent){            obj.detachEvent('on' + type, listener);        }    }    var unload = function() {        for (var i = 0, evt; evt = cache[i]; i++) {            if (evt.t != dcl)                asual.util.Events.removeListener(evt.o, evt.t, evt.l);        }    }    this.addListener(window, 'unload', unload);}/** * Creates a new SWFAddress event. * @class An event class for SWFAddress. * @param {String} type Type of the event. */SWFAddressEvent = function(type) {    /**     * The type of this event.     * @type String     */    this.type = type;    /**     * The target of this event.     * @type Function     */    this.target = [SWFAddress][0];    /**     * The value of this event.     * @type String     */    this.value = SWFAddress.getValue();    /**     * The path of this event.     * @type String     */    this.path = SWFAddress.getPath();    /**     * The parameters of this event.     * @type Object     */    this.parameters = {};    var names = SWFAddress.getParameterNames();    for (var i = 0, n; n = names[i]; i++) {        this.parameters[n] = SWFAddress.getParameter(n);    }}/** * Init event. * @type String * @memberOf SWFAddressEvent * @static */SWFAddressEvent.INIT = 'init';/** * Change event. * @type String * @memberOf SWFAddressEvent * @static  */SWFAddressEvent.CHANGE = 'change';/** * @class Deep linking for Flash and Ajax. * @static */ SWFAddress = new function() {    var d = top.document;    var h = top.history;    var l = top.location;    var s = top.status;        var tracking = true;    var history = true;    var html = false;    var browser = asual.util.Browser;    var iframe, form, supported = browser.isSupported();    var swfaddr, swfobj, swfupdate = false;    var swftitle = d.title;    var swflength = h.length;    var swfhistory = [];       var swfids = [];    var listeners = {};        var url, js = 'swfaddress.js';        if ((!supported && l.href.indexOf('#') != -1) ||         (browser.isSafari() && browser.getVersion() < 412 && l.href.indexOf('#') != -1 && l.search != '')){        d.open();        d.write('<html><head><meta http-equiv="refresh" content="0;url=' + l.href.substr(0, l.href.indexOf('#')) + '" /></head></html>');        d.close();    }    var getHash = function() {        var index = l.href.indexOf('#');        if (index != -1) {            return l.href.substring(index).replace(/^#/g, '');        }        return '';    }    var hash = getHash();    var titleListener = function() {        if (browser.isIE() && d.title != swftitle) {            SWFAddress.setTitle(swftitle);        }    }    var listen = function() {        if (!swfupdate) {            if (browser.isIE()) {                if (hash != getHash()) {                    if (browser.getVersion() < 7) {                        l.reload();                    } else {                        SWFAddress.setValue(getHash());                    }                }            } else if (browser.isSafari()) {                if (swflength != h.length) {                    swflength = h.length;                    if (typeof swfhistory[swflength - 1] != 'undefined') {                        hash = swfhistory[swflength - 1];                    }                    update();                }            } else if (hash != getHash()) {                hash = getHash();                /* Experimental fix for the buggy manual addressbar editing */                /*                if (browser.isMozilla() && browser.getVersion() >= 2) {                    var hcheck = false;                    for (var i = 0; i < swfhistory.length; i++) {                        if (swfhistory[i] == hash) {                            hcheck = true; break;                        }                    }                    if (!hcheck) {                        l.reload(); return;                    }                }*/                update();            }            titleListener();        }    }    var jsDispatch = function(type) {        if (SWFAddress.hasEventListener(type)) {            SWFAddress.dispatchEvent(new SWFAddressEvent(type));        }        type = type.substr(0, 1).toUpperCase() + type.substring(1);        if(typeof SWFAddress['on' + type] == 'function') {            SWFAddress['on' + type]();        }    }    var jsInit = function() {        jsDispatch('init');    }    var jsChange = function() {        jsDispatch('change');    }    var swfChange = function() {        for (var i = 0, swfid; swfid = swfids[i]; i++) {            var obj = document.getElementById(swfid);            if (obj) {                if (obj.parentNode && typeof obj.parentNode.so != 'undefined') {                    obj.parentNode.so.call('setSWFAddressValue', swfaddr);                } else {                    obj = (typeof obj != 'undefined' && typeof obj.setSWFAddressValue != 'undefined') ?                         obj : ((typeof obj.getElementsByTagName('object')[0] != 'undefined' &&                         typeof obj.getElementsByTagName('object')[0].setSWFAddressValue != 'undefined') ?                         obj.getElementsByTagName('object')[0] : ((typeof obj.getElementsByTagName('embed')[0] != 'undefined' &&                         typeof obj.getElementsByTagName('embed')[0].setSWFAddressValue != 'undefined') ?                         obj.getElementsByTagName('embed')[0] : null));                    if (obj) {                        obj.setSWFAddressValue(swfaddr);                    }                }            }        }    }    var update = function() {        if (swfaddr != hash) {            swfaddr = hash;            swfChange();            jsChange();        }    }    var track = function() {        if (tracking && typeof urchinTracker != 'undefined'){            var path = l.pathname + SWFAddress.getValue();            path = path.replace(/\/\//, '/');            path = path.replace(/^\/$/, '');            urchinTracker(path);        }    }        var htmlFrame = function() {        var doc = iframe.contentWindow.document;        doc.open();        doc.write('<script type="text/javascript">var swfaddress = "' + getHash() + '";</script>');        doc.close();    }    var loadSuccess = function() {        if (html) {            var src = iframe.contentWindow.location.href;            hash = (src.indexOf('?') > -1) ? src.substring(src.indexOf('?') + 1) : '';        } else {            if (typeof iframe.contentWindow.swfaddress != 'undefined')                hash = iframe.contentWindow.swfaddress;            else                hash = '';        }        if (hash != getHash()) {            update();            l.hash = '#' + hash;        }    }    var load = function() {        var scripts = document.getElementsByTagName('script');        for (var i = 0, s; s = scripts[i]; i++) {            if (s.src.indexOf(js) > -1) {                url = String(s.src);                break;            }        }        if ((qi = url.indexOf('?')) > -1) {            var param, params = url.substr(qi + 1).split('&');            for (var j = 0, p; p = params[j]; j++) {                param = p.split('=');                param[1] = isNaN(param[1]) ? param[1] : (param[1] == '1');                eval(param[0] + ' = ' + param[1]);            }        }        if (/file:\/\//.test(l.href)) html = false;        var el;        if (browser.isIE()) {            if (!html && document.getElementById('swfaddress')) {                iframe = el = document.getElementById('swfaddress');            } else {                iframe = document.createElement('iframe');                el = document.body.appendChild(iframe);            }            if (html) iframe.src = url.replace(/\.js(\?.*)?$/, '.html') + '?' + getHash();            if (browser.isIE()) {                setTimeout(function() {                    if (!html && typeof iframe.contentWindow.swfaddress == 'undefined') htmlFrame();                    asual.util.Events.addListener(iframe, 'load', loadSuccess);                }, 10);            }        }        if (browser.isSafari()) {            if (browser.getVersion() < 412) {                form = document.createElement('form');                form.method = 'get';                el = document.body.appendChild(form);            }            if (typeof l.swfaddress == 'undefined') {                l.swfaddress = {};            }            if (typeof l.swfaddress.history != 'undefined') {                swfhistory = l.swfaddress.history.split(',');            }        }        if (browser.isOpera() && swfids.length == 0) {            var embed = document.createElement('embed');            el = document.body.appendChild(embed);            el.outerHTML = el.outerHTML.replace(/embed/i, 'embed src="' + url.replace(/\.js(\?.*)?$/, '.swf') + '" type="application/x-shockwave-flash"');        }        if (el) {            el.id = 'swfaddress';            el.style.position = 'absolute';            el.style.top = '-9999px';        }        setTimeout(jsInit, 1);        setTimeout(jsChange, 2);        setInterval(listen, 50);        track();    }    /**     * Init event.     * @type Function     * @event     * @static     */    this.onInit = null;        /**     * Change event.     * @type Function     * @event     * @static     */    this.onChange = null;        /**     * String representation of this class.     * @ignore     */    this.toString = function() {        return '[class SWFAddress]';    }    /**     * Loads the previous URL in the history list.     * @return {void}     * @static     */    this.back = function() {        h.back();    }    /**     * Loads the next URL in the history list.     * @return {void}     * @static     */    this.forward = function() {        h.forward();    }    /**     * Loads a URL from the history list.     * @param {Number} delta An integer representing a relative position in the history list.     * @return {void}     * @static     */    this.go = function(delta) {        h.go(delta);    }    /**     * Registers an event listener..     * @param {String} type Event type.     * @param {Function} listener Event listener.     * @return {void}     * @static     */    this.addEventListener = function (type, listener) {        if (typeof listeners[type] == 'undefined') {            listeners[type] = [];        }        listeners[type].push(listener);    }    /**     * Removes an event listener.     * @param {String} type Event type.     * @param {Function} listener Event listener.     * @return {void}     * @static          */    this.removeEventListener = function (type, listener) {        if (typeof listeners[type] != 'undefined') {            for (var i = 0, l; l = listeners[type][i]; i++) {                if (l == listener) break;            }            listeners[type].splice(i, 1);        }    }    /**     * Dispatches an event to all the registered listeners.      * @param {Object} event Event object.     * @return {void}     * @static     */    this.dispatchEvent = function (event) {        if (typeof listeners[event.type] != 'undefined') {            event.target = this;            for (var i = 0, l; l = listeners[event.type][i]; i++) {                l(event);            }        }    }    /**     * Checks the existance of any listeners registered for a specific type of event.      * @param {String} event Event type.     * @return {Boolean}     * @static     */    this.hasEventListener = function (type) {        return (typeof listeners[type] != 'undefined' && listeners[type].length > 0);    }    /**     * Provides the state of the history setting.      * @return {Boolean}     * @static     */    this.getHistoryEnabled = function() {        return history;    }    /**     * Enables or disables the creation of history entries.     * @param {Boolean} enabled History state.     * @return {void}     * @static     */    this.setHistoryEnabled = function(enabled) {        history = enabled;    }    /**     * Provides the state of the tracking state.     * @return {Boolean}     * @static     */    this.getTrackingEnabled = function() {        return tracking;    }    /**     * Enables or disables the page views tracking.     * @param {Boolean} enabled Tracking state.     * @return {void}     * @static     */    this.setTrackingEnabled = function(enabled) {        tracking = enabled;    }    /**     * Opens a new URL in the browser.      * @param {String} url The resource to be opened.     * @param {String} target Target window.     * @return {void}     * @static     */    this.href = function(url, target) {        target = typeof target != 'undefined' ? target : '_self';             switch(target) {            case '_self':                 self.location.href = url;                 break;            case '_top':                 top.location.href = url;                 break;                            case '_blank':                window.open(url);                 break;             default:                document.frames[target].location.href = url;                 break;         }    }    /**     * Opens a browser popup window.      * @param {String} url Resource location.     * @param {String} name Name of the popup window.     * @param {String} options Options which get evaluted and passed to the window.open() method.     * @param [String] handler Optional JavsScript handler code for popup handling.         * @return {void}     * @static     */    this.popup = function(url, name, options, handler) {        var popup = window.open(url, name, eval(options));        eval(handler);    }    /**     * Provides a list of all the Flash objects registered.      * @return {Array}     * @static     */    this.getIds = function() {        return swfids;    }    /**     * Provides the id the first and probably the only Flash object registered.      * @return {String}     * @static     */    this.getId = function(index) {        return swfids[0];    }    /**     * Sets the id of a single Flash object which will be registered for deep linking.     * @param {String} id ID of the object.     * @return {void}     * @static     */    this.setId = function(id) {        swfids[0] = id;    }    /**     * Adds an id to the list of Flash object registered for deep linking.     * @param {String} id ID of the object.     * @return {void}     * @static     */    this.addId = function(id) {        this.removeId(id);        swfids.push(id);    }    /**     * Removes an id from the list of Flash object registered for deep linking.     * @param {String} id ID of the object.     * @return {void}     * @static     */    this.removeId = function(id) {        for (var i = 0, swfid; swfid = swfids[i]; i++) {            if (id == swfid) {                swfids.splice(i, 1);                return;            }        }    }    /**     * Provides the title of the HTML document.     * @return {String}     * @static     */    this.getTitle = function() {        return d.title;    }    /**     * Sets the title of the HTML document.     * @param {String} title Title value.     * @return {void}     * @static     */    this.setTitle = function(title) {        if (!supported) return null;        if (title == 'null') {            title = '';        }                if (typeof title != 'undefined') {            setTimeout(function() {                swftitle = title;                d.title = swftitle;            }, 10);        }    }    /**     * Provides the status of the browser window.     * @return {String}     * @static     */    this.getStatus = function() {        return s;    }    /**     * Sets the status of the browser window.     * @param {String} status Status value.     * @return {void}     * @static     */    this.setStatus = function(status) {        if (!supported) return null;        if (!browser.isSafari()) {            if (status == 'null' || typeof status == 'undefined') {                status = '';            }                    if (/http(s)?:\/\//.test(status) == false) {                var index = l.href.indexOf('#');                status = (index == -1 ? l.href : l.href.substr(0, index)) + '#' + status;            }            s = status;        }    }    /**     * Resets the status of the browser window.     * @return {void}     * @static     */    this.resetStatus = function() {        s = '';    }    /**     * Provides the current deep linking value.     * @return {String}     * @static     */    this.getValue = function() {        if (!supported) return null;        return hash;    }    /**     * Sets the current deep linking value.     * @param {String} value A value which will be appended to the base link of the HTML document.     * @return {void}     * @static     */    this.setValue = function(value) {        if (!supported) return null;        if (value == 'null') {            value = '';        }        if (swfaddr == value) {            return;        }        swfupdate = true;        hash = value;        update();        if (swfaddr != value) {            return;        }        swfhistory[h.length] = hash;        if (browser.isSafari()) {            if (history) {                l.swfaddress.history = swfhistory.toString();                swflength = h.length + 1;                if (browser.getVersion() < 412) {                    if (l.search == '') {                        form.action = '#' + hash;                        form.submit();                    }                } else {                    var evt = document.createEvent('MouseEvents');                    evt.initEvent('click', true, true);                    var anchor = document.createElement('a');                    anchor.href = '#' + hash;                    anchor.dispatchEvent(evt);                }            } else {                l.hash = '#' + hash;            }        } else if (hash != getHash()) {            if (history) {                l.hash = '#' + hash;            } else {                l.replace('#' + hash);            }        }        if (browser.isIE() && history) {            if (html) {                iframe.contentWindow.location.assign(iframe.contentWindow.location.pathname + '?' + getHash());            } else {                htmlFrame();            }        }        track();        swfupdate = false;    }    /**     * Provides the deep linking value without the query string.     * @return {String}     * @static     */    this.getPath = function() {        var value = this.getValue();        if (value.indexOf('?') != -1) {            return value.split('?')[0];        } else {            return value;           }    }    /**     * Provides the query string part of the deep linking value.     * @return {String}     * @static     */    this.getQueryString = function() {        var value = this.getValue();        var index = value.indexOf('?');        if (index != -1 && index < value.length) {            return value.substr(index + 1);        }        return '';    }    /**     * Provides the value of a specific query parameter.     * @param {String} param Parameter name.     * @return {String}     * @static     */    this.getParameter = function(param) {        var value = this.getValue();        var index = value.indexOf('?');        if (index != -1) {            value = value.substr(index + 1);            var params = value.split('&');            var p, i = params.length;            while(i--) {                p = params[i].split('=');                if (p[0] == param) {                    return p[1];                }            }        }        return '';    }    /**     * Provides a list of all the query parameter names.     * @return {Array}     * @static     */    this.getParameterNames = function() {        var value = this.getValue();        var index = value.indexOf('?');        var names = [];        if (index != -1) {            value = value.substr(index + 1);            if (value != '' && value.indexOf('=') != -1) {                var params = value.split('&');                var i = 0;                while(i < params.length) {                    names.push(params[i].split('=')[0]);                    i++;                }            }        }        return names;    }    if (!supported) return;        for (var i = 1; i < swflength; i++) {        swfhistory.push('');    }    swfhistory.push(l.hash.replace(/^#/g, ''));    if (browser.isIE() && l.hash != getHash()) {        l.hash = '#' + getHash();    }    swfaddr = this.getValue();    titleListener();    asual.util.Events.addListener(document, 'DOMContentLoaded', load);}/* Flash embedding hooks */if (typeof swfobject != 'undefined') SWFObject = swfobject;if (typeof SWFObject != 'undefined') {    if (SWFObject.prototype && SWFObject.prototype.write) {        asual.SWFObjectWrite = SWFObject.prototype.write;        /**         * @ignore         */        SWFObject.prototype.write = function(elementId) {            if (this.getAttribute('version').major < 8) {                this.addVariable('$swfaddress', SWFAddress.getValue());                ((typeof elementId == 'string') ? document.getElementById(elementId) : elementId).so = this;            }            asual.SWFObjectWrite.apply(this, arguments);            SWFAddress.addId(this.getAttribute('id'));        }    } else {        asual.SWFObjectRegisterObject = SWFObject.registerObject;        SWFObject.registerObject = function(objectIdStr, swfVersionStr, xiSwfUrlStr) {            asual.SWFObjectRegisterObject.apply(this, arguments);            SWFAddress.addId(objectIdStr);        }        asual.SWFObjectCreateSWF = SWFObject.createSWF;        SWFObject.createSWF = function(attObj, parObj, el) {            asual.SWFObjectCreateSWF.apply(this, arguments);            SWFAddress.addId(attObj.id);        }        asual.SWFObjectEmbedSWF = SWFObject.embedSWF;        SWFObject.embedSWF = function(swfUrlStr, replaceElemIdStr, widthStr, heightStr,             swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj) {            asual.SWFObjectEmbedSWF.apply(this, arguments);            SWFAddress.addId(attObj.id);        }    }}if (typeof UFO != 'undefined') {    asual.UFOCreate = UFO.create;    UFO.create = function(FO, id) {        asual.UFOCreate.apply(this, arguments);        SWFAddress.addId(id);    }}if (typeof AC_FL_RunContent != 'undefined') {    asual.AC_FL_RunContent = AC_FL_RunContent;    AC_FL_RunContent = function() {        asual.AC_FL_RunContent.apply(this, arguments);        for (var i = 0, a; a = arguments[i]; i++) {            if (a == 'id') {                SWFAddress.addId(arguments[i+1]);                break;            }        }    }}