crossbrowdy
Version:
A Multimedia JavaScript framework to create real cross-platform and hybrid game engines, games, emulators, multimedia libraries and apps.
703 lines (619 loc) • 17.8 kB
JavaScript
(function (window, document, location, navigator, undefined, f, t) {
"use strict";
var proto,
ready = f,
docDomain = document.domain,
protocol = location.protocol || document.protocol,
bodyElem = document.body || document.getElementsByTagName("body")[0],
objectPrototype = Object.prototype,
name = "name",
object = "object",
local = "local",
host = "host",
domain = "domain",
onunload = "onunload",
script = "script",
body = "body",
html = "html",
title = "title",
head = "head",
div = "div",
type = "type",
none = "none",
param = "param",
value = "value",
string = "String",
func = "Function",
number = "Number",
userData = "UserData",
flash = "Flash",
cookie = "Cookie",
storage = "Storage",
quotaExceeded = "QuotaExceeded",
outOfMemory = " is out of memory",
localStorage = "localStorage",
flashMime = "application/x-shockwave-flash",
flashAox = "ShockwaveFlash.ShockwaveFlash",
flashPlugin = "Shockwave Flash",
isUndefined = function (_arg) {
return _arg === undefined;
},
isIE = function () {
var result = f;
/* jshint ignore:start */
result = new Function("return/*@cc_on!@*/!1")() ||
( isNumber(document.documentMode) &&
document.documentMode <= 10 );
/* jshint ignore:end */
return result;
},
fixKey = function (_key) {
var forbidden = new RegExp(
"[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g"
);
return _key.replace(/^d/, "___$&").replace(forbidden, "___");
},
each = function (_array, _callback) {
var length = _array.length;
while (length) {
length -= 1;
if ( !isUndefined(_array.key) ) {
_callback.call(this, _array.key(length), length);
} else {
_callback.call(this, _array[length], length);
}
}
},
forEach = function (_object, _callback) {
var key = null;
for (key in _object) {
if (_object.hasOwnProperty(key)) {
_callback.call(this, _object[key], key);
}
}
},
attribute = function (_element, _key, _value) {
var att;
if ( !!_element.setAttribute ) {
// Supported by most browsers.
_element.setAttribute(_key, _value);
} else if ( !!_element.attributes ) {
// Another way of applying attributes.
_element.attributes[_key] = _value;
} else if ( !!_element.createAttribute ) {
// Yet another way supported by DOM1
att = document.createAttribute(_key);
att.value = _value;
_element.setAttributeNode(att);
} else {
// Last option.
_element[_key] = _value;
}
},
element = function (_arg) {
return document.createElement(_arg);
},
toInt = function (_arg) {
return parseInt(_arg, 10);
},
hasFlash = function () {
var flash,
description;
try {
flash = new ActiveXObject(flashAox);
if ( flash ) {
description = flash.GetVariable("$version");
if ( description &&
toInt(description.split(" ")[1].split(",")[0]) >= 9 ) {
return t;
}
}
return f;
} catch (ignore) {
if ( isObject(navigator.plugins[flashPlugin]) &&
!isUndefined(navigator.mimeTypes) &&
!isUndefined(navigator.mimeTypes[flashMime]) ) {
description = navigator.plugins[flashPlugin].description;
if ( navigator.mimeTypes[flashMime].enabledPlugin &&
!isUndefined(description) ) {
description = description.replace(
/^.*\s+(\S+\s+\S+$)/,
"$1"
);
if ( toInt(description.replace(/^(.*)\..*$/, "$1")) >= 9 ) {
return t;
}
}
}
return f;
}
},
isObject = function (_arg) {
return _arg === Object(_arg);
},
isString = function (_arg) {
return typeof _arg === string.toLowerCase() ||
objectPrototype.toString.call(_arg) === "[" + object + " " + string + "]";
},
isFunction = function (_arg) {
return typeof _arg === func.toLowerCase() ||
objectPrototype.toString.call(_arg) === "[" + object + " " + func + "]";
},
isNumber = function (_arg) {
return typeof _arg === number.toLowerCase() ||
objectPrototype.toString.call(_arg) === "[" + object + " " + number + "]";
},
appendChild = function (_parent, _child) {
_parent.insertBefore(
_child,
_parent.lastChild ?
_parent.lastChild.nextSibling :
_parent.lastChild
);
},
swfURL = (function() {
var scripts = document.scripts ||
document.getElementsByTagName("script"),
source = scripts[scripts.length-1].src.split("?"),
url = null;
if (source[1]) {
each(source[1].split("&"), function (_arg) {
var data = _arg.split("=");
if (data[0] === "swfURL") {
url = decodeURIComponent(data[1].replace(/\+/g, " "));
return url;
}
});
}
return url;
})();
// Inspired by the solution from John Resig
// http://ejohn.org/blog/simple-javascript-inheritance/#postcomment
function Class(){}
Class.extend = function(_values) {
var Self = this,
superClass = Self.prototype,
protoClass = new Self(Class),
superMethod = function () {
return (function (name, fn) {
return function() {
var res,
temp = this.$super;
// Add a new super method that is the same method
// but on the super-class
this.$super = superClass[name];
res = fn.apply(this, arguments);
this.$super = temp;
return res;
};
}(arguments[0], arguments[1]));
};
// Copy the properties over onto the new prototype
forEach(_values, function (_value, _name) {
// Check if we're overwriting an existing function
protoClass[_name] = ( isFunction(_value) &&
isFunction(superClass[_name]) ) ?
superMethod.call(Self, _name, _value) :
_value;
});
function Persistent () {
var self = this;
if ( !(self instanceof Persistent) ) {
return new Persistent(arguments[0]);
}
if ( arguments[0] !== Class && self.init ) {
self.init.apply(self, arguments);
}
}
Persistent.prototype = protoClass;
Persistent.prototype.constructor = Persistent;
Persistent.extend = Self.extend;
return Persistent;
};
var GlobalStorage = Class.extend({
"init" : function () {
var self = this;
if ( location.hostname === local + host ) {
self.__storage__ = window.globalStorage[
local + host + "." + local + domain
];
} else {
self.__storage__ = window.globalStorage[location.hostname];
}
self.length = self.__storage__.length;
},
"key" : function (_index) {
var self = this;
return (_index+1 > self.length || _index < 0) ?
null : self.__storage__.key(_index);
},
"getItem" : function (_key) {
var self = this,
object = self.__storage__.getItem(_key);
if ( isObject(object) ) {
return object.value;
}
return object;
},
"setItem" : function (_key, _data) {
var self = this;
self.__storage__.setItem(_key, _data);
self.length = self.__storage__.length;
},
"removeItem" : function (_key) {
var self = this;
self.__storage__.removeItem(_key);
self.length = self.__storage__.length;
},
"clear" : function () {
var self = this;
each(self.__storage__, function (_key) {
self.removeItem(_key);
});
},
"isLoaded" : function () {
return t;
}
});
GlobalStorage.prototype.constructor = GlobalStorage;
window.GlobalStorage = GlobalStorage;
var UserDataStorage = Class.extend({
"init" : function () {
var self = this,
AXO,
owner,
garbage = function () {
window.detachEvent(onunload, garbage);
AXO = owner = self.__storage__ = null;
/* jshint ignore:start */
if ( isFunction(CollectGarbage) ) {
CollectGarbage();
}
/* jshint ignore:end */
};
try {
AXO = new ActiveXObject("htmlfile");
AXO.open();
AXO.write(
"<" + html + "><" + head + "><" + title + ">" + localStorage + "</" + title + ">" +
"<" + script + " " + type + "=\"text/javascript\">" +
"document." + domain + " = '" + protocol + "//" + docDomain + "';" +
"</" + script + ">" +
"</" + head + "><" + body + "></" + body + "></" + html + ">"
);
AXO.close();
owner = AXO.body;
self.__storage__ = AXO.createElement(div);
window.attachEvent(onunload, garbage);
} catch (ignore) {
owner = bodyElem;
self.__storage__ = element(div);
}
appendChild(owner, self.__storage__);
self.__storage__.style.display = none;
self.__storage__.addBehavior("#default#userData");
self.__storage__.load(localStorage + "_" + docDomain);
self.__attributes__ =
self.__storage__.XMLDocument.documentElement.attributes;
self.length = self.__attributes__.length;
},
"key" : function (_index) {
var self = this,
result = null;
try {
result = _index >= self.length ?
null : self.__attributes__[_index].name;
} catch (ignore) {}
return result;
},
"getItem" : function (_key) {
var self = this;
return self.__storage__.getAttribute(fixKey(_key));
},
"setItem" : function (_key, _data) {
var self = this;
try {
self.__storage__.setAttribute(fixKey(_key), _data);
self.__storage__.save(localStorage + "_" + docDomain);
self.length = self.__attributes__.length;
} catch (e) {
throw {
"name" : userData + quotaExceeded,
"message" : userData + storage + outOfMemory
};
}
},
"removeItem" : function (_key) {
var self = this;
self.__storage__.removeAttribute(fixKey(_key));
self.__storage__.save(localStorage + "_" + docDomain);
self.length = self.__attributes__.length;
},
"clear" : function () {
var self = this;
each(self.__attributes__, function (_attr) {
self.removeItem(_attr.name);
});
},
"isLoaded" : function () {
return t;
}
});
UserDataStorage.prototype.constructor = UserDataStorage;
window.UserDataStorage = UserDataStorage;
var FlashStorage = Class.extend({
"init" : function (onerror) {
var self = this,
owner,
url = swfURL || localStorage + ".swf",
timeout = 2000,
attrs = "",
attributes = {
"id" : localStorage,
"name" : localStorage,
"width" : 1,
"height" : 1
},
parameters = {
allowScriptAccess : "always",
wmode : "transparent",
flashvars : "readyFn=window._swfReady"
},
swfLoaded = function (_object, _callback, _error) {
var cTimer = null,
eTimer = null,
clear = function () {
clearInterval(cTimer);
clearTimeout(eTimer);
eTimer = cTimer = null;
};
cTimer = setInterval(function () {
if ( ( objectPrototype.hasOwnProperty.call(_object, "PercentLoaded") &&
_object.PercentLoaded() === 100 ) ||
ready ) {
clear.call(self);
_callback.call(self);
}
}, 10);
eTimer = setTimeout(function () {
clear.call(self);
if ( isFunction(_error) ) {
_error.call(self);
}
}, timeout);
}, unload = function () {
var timer = null;
window.detachEvent(onunload, unload);
owner.style.display = none;
timer = setInterval(function () {
if (owner.readyState === 4) {
clearInterval(timer);
each(owner, function (_arg) {
if ( isFunction(_arg) ) {
_arg = null;
}
});
owner.parentNode.removeChild(owner);
}
}, 10);
};
window._swfReady = function (_bool) {
ready = _bool;
};
try {
attributes.classid = "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000";
parameters.movie = url;
forEach(attributes, function (_value, _key) {
attrs += _key + "=\"" + _value + "\" ";
});
owner = element(
"<" + object + " " + attrs + ">"
);
forEach(parameters, function (_value, _key) {
var par = element(
"<" + param + " " + name + "='" + _key + "' " + value + "='" + _value + "'>"
);
appendChild(owner, par);
});
window.attachEvent(onunload, unload);
} catch (ignore) {
if ( !isIE() ) {
delete attributes.classid;
delete parameters.movie;
}
owner = element(object);
forEach(parameters, function (_value, _key) {
var par = element(param);
attribute(par, name, _key);
attribute(par, value, _value);
appendChild(owner, par);
});
if ( !isIE() ) {
attribute(owner, type, flashMime);
attribute(owner, "data", url);
}
forEach(attributes, function (_value, _key) {
attribute(owner, _key, _value);
});
}
appendChild(bodyElem, owner);
swfLoaded.call(self, owner, function () {
self.__storage__ = document[localStorage] ||
document.getElementById(localStorage) ||
document.embeds[localStorage];
self.length = self.__storage__.length();
self.key = function (_index) {
return self.__storage__.key(_index);
};
self.getItem = function (_key) {
return self.__storage__.getItem(_key);
};
self.setItem = function (_key, _data) {
if ( !self.__storage__.setItem(_key, _data) ) {
throw {
"name" : flash + quotaExceeded,
"message" : flash + storage + outOfMemory
};
}
self.length = self.__storage__.length();
};
self.removeItem = function (_key) {
self.__storage__.removeItem(_key);
self.length = self.__storage__.length();
};
self.clear = function () {
self.__storage__.clear();
self.length = self.__storage__.length();
};
self.isLoaded = function () {
return t;
};
}, onerror);
},
"isLoaded" : function () {
return f;
}
});
FlashStorage.prototype.constructor = FlashStorage;
window.FlashStorage = FlashStorage;
var CookieStorage = Class.extend({
"length" : (function () {
var count = document.cookie.match(/\=/g);
return count && count.length || 0;
}()),
"key" : function (_index) {
var key = window.unescape(
document.cookie.replace(
/\s*\=(?:.(?!;))*$/,
""
).split(/\s*\=(?:[^;](?!;))*[^;]?;\s*/).sort()[_index]
);
return key === "" ? null : key;
},
"getItem" : function (_key) {
var item = document.cookie.indexOf(_key + "=") === -1 ?
"" : window.unescape(
document.cookie.replace(
new RegExp(
"(?:^|.*;\\s*)" +
window.escape(_key).replace(/[\-\.\+\*]/g, "\\$&") +
"\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*"
),
"$1"
)
);
return item === "" ? null : item;
},
"setItem" : function (_key, _data) {
var self = this,
count = 0,
cook = window.escape(_key) + "=" + window.escape(_data) +
"; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
if (cook.length > 4093) {
throw {
"name" : cookie + quotaExceeded,
"message" : cookie + storage + outOfMemory
};
}
document.cookie = cook;
count = document.cookie.match(/\=/g);
self.length = count && count.length || 0;
},
"removeItem" : function (_key) {
var self = this,
count = 0;
document.cookie = window.escape(_key) + "=" +
"; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
count = document.cookie.match(/\=/g);
self.length = count && count.length || 0;
},
"clear" : function () {
var self = this;
each(self, function (_key) {
self.removeItem(_key);
});
},
"isLoaded" : function () {
return t;
}
});
CookieStorage.prototype.constructor = CookieStorage;
window.CookieStorage = CookieStorage;
try {
window.localStorage.setItem(localStorage, localStorage);
window.localStorage.removeItem(localStorage);
} catch (ignore) {
if ( window.globalStorage ) {
proto = GlobalStorage;
} else if ( document.documentElement &&
document.documentElement.addBehavior ) {
proto = UserDataStorage;
} else if ( hasFlash() ) {
proto = FlashStorage;
} else if ( navigator.cookieEnabled ) {
proto = CookieStorage;
}
var Storage = proto.extend({
"key" : function (_index) {
var self = this;
if ( isNumber(_index) &&
_index < self.length &&
_index >= 0 ) {
return self.$super(_index);
}
return null;
},
"getItem" : function (_key) {
var self = this;
if ( isString(_key) ) {
return self.$super(_key);
}
return null;
},
"setItem" : function (_key, _value) {
var self = this,
value = isString(_value) ? _value :
( !(_value === null || isUndefined(_value)) &&
objectPrototype.hasOwnProperty.call(_value, "toString") ?
_value.toString() : objectPrototype.toString.call(_value));
if ( isString(_key) ) {
self.$super(
_key,
value
);
}
},
"removeItem" : function (_key) {
var self = this;
if ( isString(_key) ) {
self.$super(_key);
}
},
"isLoaded" : function (_callback) {
var self = this,
timer = null;
if ( !isFunction(_callback) ) {
return;
}
if ( self.$super() ) {
return _callback.call(self);
}
timer = setInterval(function () {
if ( self.$super() ) {
clearInterval(timer);
timer = null;
_callback.call(self);
}
}, 10);
}
});
Storage.prototype.constructor = Storage;
window.Storage = Storage;
window.localStorage = new Storage(
function () {
window.localStorage = new CookieStorage();
}
);
}
}(window, window.document, window.location, window.navigator, void(0), false,
true));