/** * SWFAddress 2.4: Deep linking for Flash and Ajax * * SWFAddress is (c) 2006-2009 Rostislav Hristov and contributors * This software is released under the MIT License * */ import flash.external.ExternalInterface; import mx.events.EventDispatcher; import SWFAddressEvent; /** * @author Rostislav Hristov * @author Ma Bingyao */ class SWFAddress { private static var _init:Boolean = false; private static var _initChange:Boolean = false; private static var _initChanged:Boolean = false; private static var _strict:Boolean = true; private static var _value:String = ''; private static var _queue:Array = new Array(); private static var _queueInterval:Number; private static var _initInterval:Number; private static var _availability:Boolean = ExternalInterface.available; private static var _dispatcher:EventDispatcher = new EventDispatcher(); private static var _initializer:Boolean = _initialize(); public static var onInit:Function; public static var onChange:Function; public static var onInternalChange:Function; public static var onExternalChange:Function; private function SWFAddress() {} private static function _initialize():Boolean { if (_availability) { try { _availability = Boolean(ExternalInterface.call('function() { return (typeof SWFAddress != "undefined"); }')); ExternalInterface.addCallback('getSWFAddressValue', SWFAddress, function():String {return this._value}); ExternalInterface.addCallback('setSWFAddressValue', SWFAddress, SWFAddress._setValue); } catch (e:Error) { _availability = false; } } if (typeof _level0.$swfaddress != 'undefined') { SWFAddress._value = _level0.$swfaddress; _availability = true; } _initInterval = setInterval(SWFAddress._check, 10); return true; } private static function _check():Void { if ((typeof SWFAddress.onInit == 'function' || typeof _dispatcher['__q_init'] != 'undefined') && !_init) { SWFAddress._setValueInit(_getValue()); SWFAddress._init = true; } if (typeof SWFAddress.onChange == 'function' || typeof _dispatcher['__q_change'] != 'undefined' || typeof SWFAddress.onExternalChange == 'function' || typeof _dispatcher['__q_externalChange'] != 'undefined') { clearInterval(_initInterval); SWFAddress._init = true; SWFAddress._setValueInit(_getValue()); } } private static function _strictCheck(value:String, force:Boolean):String { if (SWFAddress.getStrict()) { if (force) { if (value.substr(0, 1) != '/') value = '/' + value; } else { if (value == '') value = '/'; } } return value; } private static function _getValue():String { var value:String, ids:String = 'null'; if (_availability) { value = String(ExternalInterface.call('SWFAddress.getValue')); ids = String(ExternalInterface.call('SWFAddress.getIds')); } if (ids == 'undefined' || ids == 'null' || !_availability || _initChanged) { value = SWFAddress._value; } else if (value == 'undefined' || value == 'null') { value = ''; } return _strictCheck(value || '', false); } private static function _setValueInit(value:String):Void { SWFAddress._value = value; if (!_init) { _dispatchEvent(SWFAddressEvent.INIT); } else { _dispatchEvent(SWFAddressEvent.CHANGE); _dispatchEvent(SWFAddressEvent.EXTERNAL_CHANGE); } _initChange = true; } private static function _setValue(value:String):Void { if (value == 'undefined' || value == 'null') value = ''; if (SWFAddress._value == value && SWFAddress._init) return; if (!SWFAddress._initChange) return; SWFAddress._value = value; if (!_init) { SWFAddress._init = true; if (typeof SWFAddress.onInit == 'function' || typeof _dispatcher['__q_init'] != 'undefined') { _dispatchEvent(SWFAddressEvent.INIT); } } _dispatchEvent(SWFAddressEvent.CHANGE); _dispatchEvent(SWFAddressEvent.EXTERNAL_CHANGE); } private static function _dispatchEvent(type:String):Void { if (typeof _dispatcher['__q_' + type] != 'undefined') { _dispatcher.dispatchEvent(new SWFAddressEvent(type)); } type = type.substr(0, 1).toUpperCase() + type.substring(1); if (typeof SWFAddress['on' + type] == 'function') { SWFAddress['on' + type](); } } private static function _callQueue():Void { if (_queue.length != 0) { var script:String = ''; for (var i:Number = 0, obj:Object; obj = _queue[i]; i++) { if (typeof obj.param == 'string') obj.param = '"' + obj.param + '"'; script += obj.fn + '(' + obj.param + ');'; } _queue = new Array(); getURL('javascript:' + script + 'void(0);'); } else { clearInterval(_queueInterval); } } private static function _call(fn:String, param:Object):Void { if (typeof param == 'undefined') param = ''; if (_availability) { if (System.capabilities.os.indexOf('Mac') != -1) { if (_queue.length == 0) { _queueInterval = setInterval(SWFAddress._callQueue, 10); } _queue.push({fn: fn, param: param}); } else { ExternalInterface.call(fn, param); } } } public static function toString():String { return '[class SWFAddress]'; } /** * Ported from iecompat.js */ public static function encodeURI(str:String):String { var l:Array = ['%00', '%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0A', '%0B', '%0C', '%0D', '%0E', '%0F', '%10', '%11', '%12', '%13', '%14', '%15', '%16', '%17', '%18', '%19', '%1A', '%1B', '%1C', '%1D', '%1E', '%1F', '%20', '!', '%22', '#', '$', '%25', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '%3C', '=', '%3E', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '%5B', '%5C', '%5D', '%5E', '_', '%60', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '%7B', '%7C', '%7D', '~', '%7F']; var out:Array = [], i:Number, j:Number, len:Number = str.length, c:Number, c2:Number; for (i = 0, j = 0; i < len; i++) { c = str.charCodeAt(i); if (c <= 0x007F) { out[j++] = l[c]; continue; } else if (c <= 0x7FF) { out[j++] = '%' + (0xC0 | ((c >> 6) & 0x1F)).toString(16).toUpperCase(); out[j++] = '%' + (0x80 | (c & 0x3F)).toString(16).toUpperCase(); continue; } else if (c < 0xD800 || c > 0xDFFF) { out[j++] = '%' + (0xE0 | ((c >> 12) & 0x0F)).toString(16).toUpperCase(); out[j++] = '%' + (0x80 | ((c >> 6) & 0x3F)).toString(16).toUpperCase(); out[j++] = '%' + (0x80 | (c & 0x3F)).toString(16).toUpperCase(); continue; } else { if (++i < len) { c2 = str.charCodeAt(i); if (c <= 0xDBFF && 0xDC00 <= c2 && c2 <= 0xDFFF) { c = ((c & 0x03FF) << 10 | (c2 & 0x03FF)) + 0x010000; if (0x010000 <= c && c <= 0x10FFFF) { out[j++] = '%' + (0xF0 | ((c >>> 18) & 0x3F)).toString(16).toUpperCase(); out[j++] = '%' + (0x80 | ((c >>> 12) & 0x3F)).toString(16).toUpperCase(); out[j++] = '%' + (0x80 | ((c >>> 6) & 0x3F)).toString(16).toUpperCase(); out[j++] = '%' + (0x80 | (c & 0x3F)).toString(16).toUpperCase(); continue; } } } } return null; } return out.join(''); } /** * Ported from iecompat.js */ public static function decodeURI(str:String):String { var out:Array = [], i:Number = 0, j:Number = 0, len:Number = str.length; var c:Number, c2:Number, c3:Number, c4:Number, s:Number; var checkcode:Function = function (strcc:String, i2:Number, i1:Number):Number { var d1 = strcc.charAt(i1), d2 = strcc.charAt(i2); if (isNaN(parseInt(d1, 16)) || isNaN(parseInt(d2, 16))) { return null; } return parseInt(d1 + d2, 16); } var checkutf8:Function = function (strcu:String, i3:Number, i2:Number, i1:Number):Number { var ccu = strcu.charCodeAt(i1); if (ccu == 37) { if ((ccu = checkcode(strcu, i3, i2)) == null) return null; } if ((ccu >> 6) != 2) { return null; } return ccu; } while(i < len) { c = str.charCodeAt(i++); if (c == 37) { if ((c = checkcode(str, i++, i++)) == null) return null; } else { out[j++] = String.fromCharCode(c); continue; } switch(c) { case 35: case 36: case 38: case 43: case 44: case 47: case 58: case 59: case 61: case 63: case 64: { if (str.charCodeAt(i - 3) == 37) { out[j++] = str.substr(i - 3, 3); } else { out[j++] = str.substr(i - 1, 1); } break; } default: { switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: { // 0xxxxxxx out[j++] = String.fromCharCode(c); break; } case 12: case 13: { // 110x xxxx 10xx xxxx if ((c2 = checkutf8(str, i++, i++, i++)) == null) return null; out[j++] = String.fromCharCode(((c & 0x1F) << 6) | (c2 & 0x3F)); break; } case 14: { // 1110 xxxx 10xx xxxx 10xx xxxx if ((c2 = checkutf8(str, i++, i++, i++)) == null) return null; if ((c3 = checkutf8(str, i++, i++, i++)) == null) return null; out[j++] = String.fromCharCode(((c & 0x0F) << 12) | ((c2 & 0x3F) << 6) | ((c3 & 0x3F) << 0)); break; } default: { switch (c & 0xf) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: { // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx if ((c2 = checkutf8(str, i++, i++, i++)) == null) return null; if ((c3 = checkutf8(str, i++, i++, i++)) == null) return null; if ((c4 = checkutf8(str, i++, i++, i++)) == null) return null; s = ((c & 0x07) << 18) | ((c2 & 0x3f) << 12) | ((c3 & 0x3f) << 6) | (c4 & 0x3f) - 0x10000; if (0 <= s && s <= 0xfffff) { out[j++] = String.fromCharCode(((s >>> 10) & 0x03ff) | 0xd800, (s & 0x03ff) | 0xdc00); } else { return null; } break; } default: { return null; } } } } } } } return out.join(''); } public static function back():Void { _call('SWFAddress.back'); } public static function forward():Void { _call('SWFAddress.forward'); } public static function up():Void { var path:String = SWFAddress.getPath(); SWFAddress.setValue(path.substr(0, path.lastIndexOf('/', path.length - 2) + (path.substr(path.length - 1) == '/' ? 1 : 0))); } public static function go(delta:Number):Void { _call('SWFAddress.go', delta); } public static function href(url:String, target:String):Void { target = (typeof target != 'undefined') ? target : '_self'; if (_availability && System.capabilities.playerType == 'ActiveX') { ExternalInterface.call('SWFAddress.href', url, target); return; } getURL(url, target); } public static function popup(url:String, name:String, options:String, handler:String):Void { name = (typeof name != 'undefined') ? name : 'popup'; options = (typeof options != 'undefined') ? options : '""'; handler = (typeof handler != 'undefined') ? handler : ''; if (_availability && System.capabilities.playerType == 'ActiveX') { ExternalInterface.call('SWFAddress.popup', url, name, options, handler); return; } getURL('javascript:popup=window.open("' + url + '","' + name + '",' + options + ');' + handler + ';void(0);'); } public static function addEventListener(type:String, listener:Function):Void { _dispatcher.addEventListener(type, listener); } public static function removeEventListener(type:String, listener:Function):Void { _dispatcher.removeEventListener(type, listener); } public static function dispatchEvent(event:Object):Void { _dispatcher.dispatchEvent(event); } public static function hasEventListener(type:String):Boolean { return (typeof _dispatcher['__q_' + type] != 'undefined'); } public static function getBaseURL():String { var url:String = 'null'; if (_availability) url = String(ExternalInterface.call('SWFAddress.getBaseURL')); return (url == 'undefined' || url == 'null' || !_availability) ? '' : url; } public static function getStrict():Boolean { var strict:String = 'null'; if (_availability) strict = String(ExternalInterface.call('SWFAddress.getStrict')); return (strict == 'null' || strict == 'undefined') ? _strict : (strict == 'true'); } public static function setStrict(strict:Boolean):Void { _call('SWFAddress.setStrict', strict); _strict = strict; } public static function getHistory():Boolean { return Boolean((_availability) ? ExternalInterface.call('SWFAddress.getHistory') : false); } public static function setHistory(history:Boolean):Void { _call('SWFAddress.setHistory', history); } public static function getTracker():String { return (_availability) ? String(ExternalInterface.call('SWFAddress.getTracker')) : ''; } public static function setTracker(tracker:String):Void { _call('SWFAddress.setTracker', tracker); } public static function getTitle():String { var title:String = (_availability) ? String(ExternalInterface.call('SWFAddress.getTitle')) : ''; if (title == 'undefined' || title == 'null') title = ''; return decodeURI(title); } public static function setTitle(title:String):Void { _call('SWFAddress.setTitle', encodeURI(decodeURI(title))); } public static function getStatus():String { var status:String = (_availability) ? String(ExternalInterface.call('SWFAddress.getStatus')) : ''; if (status == 'undefined' || status == 'null') status = ''; return decodeURI(status); } public static function setStatus(status:String):Void { _call('SWFAddress.setStatus', encodeURI(decodeURI(status))); } public static function resetStatus():Void { _call('SWFAddress.resetStatus'); } public static function getValue():String { return decodeURI(_strictCheck(_value || '', false)); } public static function setValue(value:String):Void { if (value == 'undefined' || value == 'null') value = ''; value = encodeURI(decodeURI(_strictCheck(value, true))); if (SWFAddress._value == value) return; SWFAddress._value = value; _call('SWFAddress.setValue', value); if (SWFAddress._init) { _dispatchEvent(SWFAddressEvent.CHANGE); _dispatchEvent(SWFAddressEvent.INTERNAL_CHANGE); } else { _initChanged = true; } } public static function getPath():String { var value:String = SWFAddress.getValue(); if (value.indexOf('?') != -1) { return value.split('?')[0]; } else if (value.indexOf('#') != -1) { return value.split('#')[0]; } else { return value; } } public static function getPathNames():Array { var path:String = SWFAddress.getPath(); var names:Array = path.split('/'); if (path.substr(0, 1) == '/' || path.length == 0) names.splice(0, 1); if (path.substr(path.length - 1, 1) == '/') names.splice(names.length - 1, 1); return names; } public static function getQueryString():String { var value:String = SWFAddress.getValue(); var index:Number = value.indexOf('?'); if (index != -1 && index < value.length) { return value.substr(index + 1); } } public static function getParameter(param:String):String { var value:String = SWFAddress.getValue(); var index:Number = value.indexOf('?'); if (index != -1) { value = value.substr(index + 1); var params:Array = value.split('&'); var p:Array; var i:Number = params.length; var r:Array = new Array(); while(i--) { p = params[i].split('='); if (p[0] == param) { r.push(p[1]); } } if (r.length != 0) { return r.length != 1 ? r : r[0]; } } } public static function getParameterNames():Array { var value:String = SWFAddress.getValue(); var index:Number = value.indexOf('?'); var names:Array = new Array(); if (index != -1) { value = value.substr(index + 1); if (value != '' && value.indexOf('=') != -1) { var params:Array = value.split('&'); var i:Number = 0; while(i < params.length) { names.push(params[i].split('=')[0]); i++; } } } return names; } }