/** * 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 com == "undefined") var com = {};if (typeof com.asual == "undefined") com.asual = {};if (typeof com.asual.util == "undefined") com.asual.util = {};   /** * @class Utility class that provides detailed browser information. * @static * @ignore */com.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 * @ignore */com.asual.util.Events = new function() {    var _cache = [];    var _browser = com.asual.util.Browser;    var _dcl = 'DOMContentLoaded';    if (_browser.isIE() || _browser.isSafari()) {        (function(){            try {                if (_browser.isIE() || !/loaded|complete/.test(document.readyState))                    document.documentElement.doScroll('left');            } catch(e) {                return setTimeout(arguments.callee, 0);            }            for (var i = 0, e; e = _cache[i]; i++) {                if (e.t == _dcl) e.l.call(null);            }        })();    }    /**     * 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)                com.asual.util.Events.removeListener(evt.o, evt.t, evt.l);        }    }    this.addListener(window, 'unload', _unload);}/** * Creates a new SWFAddress event. * @class Event class for SWFAddress. * @param {String} type Type of the event. */SWFAddressEvent = function(type) {        /**     * String representation of this object.     * @ignore     */    this.toString = function() {        return '[object SWFAddressEvent]';    }    /**     * 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 The SWFAddress class can be configured with query parameters using the following format: * swfaddress.js?html=false&history=1&tracker=pageTracker._trackPageview&strict=1.<br />  * The list of supported options include:<br /><br /> * <code>history:Boolean</code> - Enables or disables the creation of history entries.<br /> * <code>html:Boolean</code> - Enables or disables the usage of swfaddress.html.<br /> * <code>strict:Boolean</code> - Enables or disables the strict mode.<br /> * <code>tracker:String</code> - Sets a function for page view tracking.<br /> * @static  */ SWFAddress = new function() {    var _browser = com.asual.util.Browser;    var _supported = _browser.isSupported();        var _d = top.document;    var _h = top.history;    var _l = top.location;    var _iframe, _form, _url, _js = 'swfaddress.js';    var _title = _d.title;    var _length = _h.length;    var _silent = false;    var _listeners = {};    var _stack = [];    var _ids = [];    var _opts = [];    _opts['history'] = true;    _opts['html'] = false;    _opts['strict'] = true;    _opts['tracker'] = 'urchinTracker';        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 _value = _getHash();    var _strictCheck = function(value, force) {        if (_opts['strict']) {            if (force) {                if (value.substr(0, 1) != '/') value = '/' + value;                value = value.replace(/^([^\?.]*[^\/])(\?|$)/, '$1/$2').replace(/\/\//, '/');            } else {                if (value == '') value = '/';            }        }        return value;    }    var _titleCheck = function() {        if (_browser.isIE() && _d.title != _title) {            SWFAddress.setTitle(_title);        }    }    var _listen = function() {        if (!_silent) {            if (_browser.isIE()) {                if (_value != _getHash()) {                    if (_browser.getVersion() < 7) {                        _l.reload();                    } else {                        SWFAddress.setValue(_getHash());                    }                }            } else if (_browser.isSafari()) {                if (_length != _h.length) {                    _length = _h.length;                    if (typeof _stack[_length - 1] != 'undefined') {                        _value = _stack[_length - 1];                    }                    _update();                }            } else if (_value != _getHash()) {                _value = _getHash();                _update();            }            _titleCheck();        }    }    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, id; id = _ids[i]; i++) {            var obj = document.getElementById(id);            if (obj) {                if (obj.parentNode && typeof obj.parentNode.so != 'undefined') {                    obj.parentNode.so.call('setSWFAddressValue', SWFAddress.getValue());                } else {                    obj = (obj && typeof obj.setSWFAddressValue != 'undefined') ?                         obj : ((obj.getElementsByTagName('object')[0] &&                         typeof obj.getElementsByTagName('object')[0].setSWFAddressValue != 'undefined') ?                         obj.getElementsByTagName('object')[0] : ((obj.getElementsByTagName('embed')[0] &&                         typeof obj.getElementsByTagName('embed')[0].setSWFAddressValue != 'undefined') ?                         obj.getElementsByTagName('embed')[0] : null));                    if (obj) {                        obj.setSWFAddressValue(SWFAddress.getValue());                    }                }            }        }    }    var _update = function() {        _swfChange();        _jsChange();    }    var _track = function() {        if (typeof _opts['tracker'] != 'undefined' && eval('typeof ' + _opts['tracker'] + ' != "undefined"')){            var fn = eval(_opts['tracker']);            if (typeof fn == 'function') {                fn((_l.pathname + SWFAddress.getValue()).replace(/\/\//, '/').replace(/^\/$/, ''));            }        }    }        var _htmlWrite = function() {        var doc = _iframe.contentWindow.document;        doc.open();        doc.write('<script>var swfaddress = "' + _getHash() + '";</script>');        doc.close();    }    var _htmlLoad = function() {        if (_opts['html']) {            var src = _iframe.contentWindow.location.href;            _value = (src.indexOf('?') > -1) ?                 src.substring(src.indexOf('?') + 1) : '';        } else {            _value = (typeof _iframe.contentWindow.swfaddress != 'undefined') ?                 _iframe.contentWindow.swfaddress : '';        }        if (_value != _getHash()) {            _update();            _l.hash = _value;        }    }    var _load = function() {        var attr = 'id="swfaddress" style="position:absolute;top:-9999px;"';        if (_browser.isIE()) {            document.body.appendChild(document.createElement('div')).innerHTML = '<iframe ' + attr + ' src="' +                 (_opts['html'] ? _url.replace(/\.js(\?.*)?$/, '.html') + '?' + _getHash() : 'javascript:false;') +                 '"></iframe>';            _iframe = document.getElementById('swfaddress');            setTimeout(function() {                if (!_opts['html'] && typeof _iframe.contentWindow.swfaddress == 'undefined') _htmlWrite();                com.asual.util.Events.addListener(_iframe, 'load', _htmlLoad);            }, 10);        } else if (_browser.isSafari()) {            if (_browser.getVersion() < 412) {                document.body.innerHTML += '<form ' + attr + ' method="get"></form>';                _form = document.getElementById('swfaddress');            }            if (typeof _l.swfaddress == 'undefined') _l.swfaddress = {};            if (typeof _l.swfaddress[_l.pathname] != 'undefined') _stack = _l.swfaddress[_l.pathname].split(',');        } else if (_browser.isOpera() && _ids.length == 0) {            document.body.innerHTML += '<embed ' + attr + ' src="' + _url.replace(/\.js(\?.*)?$/, '.swf') +                 '" type="application/x-shockwave-flash" />';        }        setTimeout(_jsInit, 1);        setTimeout(_jsChange, 2);        setTimeout(_track, 10);        setInterval(_listen, 50);    }    /**     * 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);    }    /**     * 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':                 _l.href = url;                 break;                            case '_blank':                window.open(url);                 break;             default:                top.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 JavaScript code for popup handling.         * @return {void}     * @static     */    this.popup = function(url, name, options, handler) {        var popup = window.open(url, name, eval(options));        eval(handler);    }    /**     * 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 {Boolean}     * @static     */    this.dispatchEvent = function (event) {        if (typeof _listeners[event.type] != 'undefined' && _listeners[event.type].length) {            event.target = this;            for (var i = 0, l; l = _listeners[event.type][i]; i++) {                l(event);            }            return true;                   }        return false;    }    /**     * 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 strict mode setting.      * @return {Boolean}     * @static     */    this.getStrict = function() {        return _opts['strict'];    }    /**     * Enables or disables the strict mode.     * @param {Boolean} strict Strict mode state.     * @return {void}     * @static     */    this.setStrict = function(strict) {        _opts['strict'] = enabled;    }    /**     * Provides the state of the history setting.      * @return {Boolean}     * @static     */    this.getHistory = function() {        return _opts['history'];    }    /**     * Enables or disables the creation of history entries.     * @param {Boolean} history History state.     * @return {void}     * @static     */    this.setHistory = function(history) {        _opts['history'] = history;    }    /**     * Provides the tracker function.     * @return {String}     * @static     */    this.getTracker = function() {        return _opts['tracker'];    }    /**     * Sets a function for page view tracking. The default value is 'urchinTracker'.     * @param {String} tracker Tracker function.     * @return {void}     * @static     */    this.setTracker = function(tracker) {        _opts['tracker'] = tracker;    }    /**     * Provides a list of all the Flash objects registered.      * @return {Array}     * @static     */    this.getIds = function() {        return _ids;    }    /**     * Provides the id the first and probably the only Flash object registered.      * @return {String}     * @static     */    this.getId = function(index) {        return _ids[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) {        _ids[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);        _ids.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 = _ids[i]; i++) {            if (id == swfid) {                _ids.splice(i, 1);                break;            }        }    }    /**     * 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 (typeof title == 'undefined') return;        if (title == 'null') title = '';        _title = _d.title = title;        if (_iframe && _iframe.contentWindow)            _iframe.contentWindow.document.title = title;    }    /**     * Provides the status of the browser window.     * @return {String}     * @static     */    this.getStatus = function() {        return top.status;    }    /**     * Sets the status of the browser window.     * @param {String} status Status value.     * @return {void}     * @static     */    this.setStatus = function(status) {        if (!_supported) return null;        if (typeof status == 'undefined') return;        if (!_browser.isSafari()) {            if (status == 'null') status = '';            status = _strictCheck(status, true);            if (status == '/') status = '';            if (!(/http(s)?:\/\//.test(status))) {                var index = _l.href.indexOf('#');                status = (index == -1 ? _l.href : _l.href.substr(0, index)) + '#' + status;            }            top.status = status;        }    }    /**     * Resets the status of the browser window.     * @return {void}     * @static     */    this.resetStatus = function() {        top.status = '';    }    /**     * Provides the current deep linking value.     * @return {String}     * @static     */    this.getValue = function() {        if (!_supported) return null;        return _strictCheck(_value, false);    }    /**     * 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 (typeof value == 'undefined') return;        if (value == 'null') value = ''        value = _strictCheck(value, true);        if (value == '/') value = '';        if (_value == value) return;        _value = value;        _silent = true;        _update();        _stack[_h.length] = _value;        if (_browser.isSafari()) {            if (_opts['history']) {                _l.swfaddress[_l.pathname] = _stack.toString();                _length = _h.length + 1;                if (_browser.getVersion() < 412) {                    if (_l.search == '') {                        _form.action = '#' + _value;                        _form.submit();                    }                } else {                    var evt = document.createEvent('MouseEvents');                    evt.initEvent('click', true, true);                    var anchor = document.createElement('a');                    anchor.href = '#' + _value;                    anchor.dispatchEvent(evt);                }            } else {                _l.replace('#' + _value);            }        } else if (_value != _getHash()) {            if (_opts['history']) {                _l.hash = '#' + _value;            } else {                _l.replace('#' + _value);            }        }        if (_browser.isIE() && _opts['history']) {            if (_opts['html']) {                _iframe.contentWindow.location.assign(_iframe.contentWindow.location.pathname +                     '?' + _getHash());            } else {                _htmlWrite();            }        }        setTimeout(_track, 10);        _silent = 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 < _length; i++) {        _stack.push('');    }    _stack.push(_l.hash.replace(/^#/g, ''));    if (_browser.isIE() && _l.hash != _getHash()) {        _l.hash = '#' + _getHash();    }    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('=');            if (/^(history|html|strict)$/.test(param[0])) {                _opts[param[0]] = (isNaN(param[1]) ? eval(param[1]) : (parseFloat(param[1]) > 0));            }            if (/^tracker$/.test(param[0])) {                _opts[param[0]] = param[1];            }        }    }    if (/file:\/\//.test(_l.href)) _opts['html'] = false;    _titleCheck();    com.asual.util.Events.addListener(document, 'DOMContentLoaded', _load);}/* Flash embedding hooks */if (typeof swfobject != 'undefined') SWFObject = swfobject;if (typeof FlashObject != 'undefined') SWFObject = FlashObject;if (typeof SWFObject != 'undefined') {    if (SWFObject.prototype && SWFObject.prototype.write) {        com.asual.SWFObjectWrite = SWFObject.prototype.write;        /**         * @ignore         */        SWFObject.prototype.write = function() {            if (this.getAttribute('version').major < 8) {                this.addVariable('$swfaddress', SWFAddress.getValue());                ((typeof arguments[0] == 'string') ?                     document.getElementById(arguments[0]) : arguments[0]).so = this;            }            if (success = com.asual.SWFObjectWrite.apply(this, arguments))                SWFAddress.addId(this.getAttribute('id'));            return success;        }    } else {        com.asual.SWFObjectRegisterObject = SWFObject.registerObject;        SWFObject.registerObject = function() {            com.asual.SWFObjectRegisterObject.apply(this, arguments);            SWFAddress.addId(arguments[0]);                    }        com.asual.SWFObjectCreateSWF = SWFObject.createSWF;        SWFObject.createSWF = function() {            com.asual.SWFObjectCreateSWF.apply(this, arguments);            SWFAddress.addId(arguments[0].id);                    }        com.asual.SWFObjectEmbedSWF = SWFObject.embedSWF;        SWFObject.embedSWF = function() {            com.asual.SWFObjectEmbedSWF.apply(this, arguments);            SWFAddress.addId(arguments[8].id);                    }    }}if (typeof UFO != 'undefined') {    com.asual.UFOCreate = UFO.create;    UFO.create = function() {        com.asual.UFOCreate.apply(this, arguments);        SWFAddress.addId(arguments[0].id);            }}if (typeof AC_FL_RunContent != 'undefined') {    com.asual.AC_FL_RunContent = AC_FL_RunContent;    AC_FL_RunContent = function() {        com.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;            }        }    }}
