diff --git a/ajax/libs/qooxdoo/2.1.2/q.js b/ajax/libs/qooxdoo/2.1.2/q.js
new file mode 100644
index 000000000..b32bdc940
--- /dev/null
+++ b/ajax/libs/qooxdoo/2.1.2/q.js
@@ -0,0 +1,28498 @@
+/** qooxdoo v.2.1.2 | (c) 2012 1&1 Internet AG 1und1.de | qooxdoo.org/license */
+(function(){
+if (!window.qx) window.qx = {};
+var qx = window.qx;
+
+if (!qx.$$environment) qx.$$environment = {};
+var envinfo = {"json":true,"qx.application":"library.Application","qx.debug":false,"qx.debug.databinding":false,"qx.debug.dispose":false,"qx.debug.io":false,"qx.debug.ui.queue":false,"qx.optimization.variants":true,"qx.revision":"","qx.theme":"qx.theme.Modern","qx.version":"2.1.2"};
+for (var k in envinfo) qx.$$environment[k] = envinfo[k];
+
+qx.$$packageData = {};
+
+/** qooxdoo v.2.1.2 | (c) 2012 1&1 Internet AG 1und1.de | qooxdoo.org/license */
+qx.$$packageData['0']={"locales":{},"resources":{},"translations":{"C":{},"en":{}}};
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Sebastian Werner (wpbasti)
+ * Andreas Ecker (ecker)
+ * Martin Wittemann (martinwittemann)
+
+************************************************************************ */
+/* ************************************************************************
+
+#ignore(qx.data)
+#ignore(qx.data.IListData)
+#ignore(qx.util.OOUtil)
+
+************************************************************************ */
+/**
+ * Create namespace
+ */
+if(!window.qx){
+
+ window.qx = {
+ };
+};
+/**
+ * Bootstrap qx.Bootstrap to create myself later
+ * This is needed for the API browser etc. to let them detect me
+ */
+qx.Bootstrap = {
+ genericToString : function(){
+
+ return "[Class " + this.classname + "]";
+ },
+ createNamespace : function(name, object){
+
+ var splits = name.split(".");
+ var parent = window;
+ var part = splits[0];
+ for(var i = 0,len = splits.length - 1;i < len;i++,part = splits[i]){
+
+ if(!parent[part]){
+
+ parent = parent[part] = {
+ };
+ } else {
+
+ parent = parent[part];
+ };
+ };
+ // store object
+ parent[part] = object;
+ // return last part name (e.g. classname)
+ return part;
+ },
+ setDisplayName : function(fcn, classname, name){
+
+ fcn.displayName = classname + "." + name + "()";
+ },
+ setDisplayNames : function(functionMap, classname){
+
+ for(var name in functionMap){
+
+ var value = functionMap[name];
+ if(value instanceof Function){
+
+ value.displayName = classname + "." + name + "()";
+ };
+ };
+ },
+ define : function(name, config){
+
+ if(!config){
+
+ var config = {
+ statics : {
+ }
+ };
+ };
+ var clazz;
+ var proto = null;
+ qx.Bootstrap.setDisplayNames(config.statics, name);
+ if(config.members || config.extend){
+
+ qx.Bootstrap.setDisplayNames(config.members, name + ".prototype");
+ clazz = config.construct || new Function;
+ if(config.extend){
+
+ this.extendClass(clazz, clazz, config.extend, name, basename);
+ };
+ var statics = config.statics || {
+ };
+ // use keys to include the shadowed in IE
+ for(var i = 0,keys = qx.Bootstrap.keys(statics),l = keys.length;i < l;i++){
+
+ var key = keys[i];
+ clazz[key] = statics[key];
+ };
+ proto = clazz.prototype;
+ var members = config.members || {
+ };
+ // use keys to include the shadowed in IE
+ for(var i = 0,keys = qx.Bootstrap.keys(members),l = keys.length;i < l;i++){
+
+ var key = keys[i];
+ proto[key] = members[key];
+ };
+ } else {
+
+ clazz = config.statics || {
+ };
+ };
+ // Create namespace
+ var basename = name ? this.createNamespace(name, clazz) : "";
+ // Store names in constructor/object
+ clazz.name = clazz.classname = name;
+ clazz.basename = basename;
+ // Store type info
+ clazz.$$type = "Class";
+ // Attach toString
+ if(!clazz.hasOwnProperty("toString")){
+
+ clazz.toString = this.genericToString;
+ };
+ // Execute defer section
+ if(config.defer){
+
+ config.defer(clazz, proto);
+ };
+ // Store class reference in global class registry
+ qx.Bootstrap.$$registry[name] = clazz;
+ return clazz;
+ }
+};
+/**
+ * Internal class that is responsible for bootstrapping the qooxdoo
+ * framework at load time.
+ *
+ * Does support:
+ *
+ * * Construct
+ * * Statics
+ * * Members
+ * * Extend
+ * * Defer
+ *
+ * Does not support:
+ *
+ * * Super class calls
+ * * Mixins, Interfaces, Properties, ...
+ */
+qx.Bootstrap.define("qx.Bootstrap", {
+ statics : {
+ /** Timestamp of qooxdoo based application startup */
+ LOADSTART : qx.$$start || new Date(),
+ /**
+ * Mapping for early use of the qx.debug environment setting.
+ */
+ DEBUG : (function(){
+
+ // make sure to reflect all changes here to the environment class!
+ var debug = true;
+ if(qx.$$environment && qx.$$environment["qx.debug"] === false){
+
+ debug = false;
+ };
+ return debug;
+ })(),
+ /**
+ * Minimal accessor API for the environment settings given from the
+ * generator.
+ *
+ * WARNING: This method only should be used if the
+ * {@link qx.core.Environment} class is not loaded!
+ *
+ * @param key {String} The key to get the value from.
+ * @return {var} The value of the setting or undefined.
+ */
+ getEnvironmentSetting : function(key){
+
+ if(qx.$$environment){
+
+ return qx.$$environment[key];
+ };
+ },
+ /**
+ * Minimal mutator for the environment settings given from the generator.
+ * It checks for the existance of the environment settings and sets the
+ * key if its not given from the generator. If a setting is available from
+ * the generator, the setting will be ignored.
+ *
+ * WARNING: This method only should be used if the
+ * {@link qx.core.Environment} class is not loaded!
+ *
+ * @param key {String} The key of the setting.
+ * @param value {var} The value for the setting.
+ */
+ setEnvironmentSetting : function(key, value){
+
+ if(!qx.$$environment){
+
+ qx.$$environment = {
+ };
+ };
+ if(qx.$$environment[key] === undefined){
+
+ qx.$$environment[key] = value;
+ };
+ },
+ /**
+ * Creates a namespace and assigns the given object to it.
+ *
+ * @internal
+ * @param name {String} The complete namespace to create. Typically, the last part is the class name itself
+ * @param object {Object} The object to attach to the namespace
+ * @return {Object} last part of the namespace (typically the class name)
+ * @throws {Error} when the given object already exists.
+ */
+ createNamespace : qx.Bootstrap.createNamespace,
+ /**
+ * Define a new class using the qooxdoo class system.
+ * Lightweight version of {@link qx.Class#define} only used during bootstrap phase.
+ *
+ * @internal
+ * @signature function(name, config)
+ * @param name {String?} Name of the class. If null, the class will not be
+ * attached to a namespace.
+ * @param config {Map ? null} Class definition structure.
+ * @return {Class} The defined class
+ */
+ define : qx.Bootstrap.define,
+ /**
+ * Sets the display name of the given function
+ *
+ * @signature function(fcn, classname, name)
+ * @param fcn {Function} the function to set the display name for
+ * @param classname {String} the name of the class the function is defined in
+ * @param name {String} the function name
+ */
+ setDisplayName : qx.Bootstrap.setDisplayName,
+ /**
+ * Set the names of all functions defined in the given map
+ *
+ * @signature function(functionMap, classname)
+ * @param functionMap {Object} a map with functions as values
+ * @param classname {String} the name of the class, the functions are
+ * defined in
+ */
+ setDisplayNames : qx.Bootstrap.setDisplayNames,
+ /**
+ * This method will be attached to all classes to return
+ * a nice identifier for them.
+ *
+ * @internal
+ * @signature function()
+ * @return {String} The class identifier
+ */
+ genericToString : qx.Bootstrap.genericToString,
+ /**
+ * Inherit a clazz from a super class.
+ *
+ * This function differentiates between class and constructor because the
+ * constructor written by the user might be wrapped and the base
+ * property has to be attached to the constructor, while the superclass
+ * property has to be attached to the wrapped constructor.
+ *
+ * @param clazz {Function} The class's wrapped constructor
+ * @param construct {Function} The unwrapped constructor
+ * @param superClass {Function} The super class
+ * @param name {Function} fully qualified class name
+ * @param basename {Function} the base name
+ */
+ extendClass : function(clazz, construct, superClass, name, basename){
+
+ var superproto = superClass.prototype;
+ // Use helper function/class to save the unnecessary constructor call while
+ // setting up inheritance.
+ var helper = new Function();
+ helper.prototype = superproto;
+ var proto = new helper();
+ // Apply prototype to new helper instance
+ clazz.prototype = proto;
+ // Store names in prototype
+ proto.name = proto.classname = name;
+ proto.basename = basename;
+ /*
+ - Store base constructor to constructor-
+ - Store reference to extend class
+ */
+ construct.base = superClass;
+ clazz.superclass = superClass;
+ /*
+ - Store statics/constructor onto constructor/prototype
+ - Store correct constructor
+ - Store statics onto prototype
+ */
+ construct.self = clazz.constructor = proto.constructor = clazz;
+ },
+ /**
+ * Find a class by its name
+ *
+ * @param name {String} class name to resolve
+ * @return {Class} the class
+ */
+ getByName : function(name){
+
+ return qx.Bootstrap.$$registry[name];
+ },
+ /** {Map} Stores all defined classes */
+ $$registry : {
+ },
+ /*
+ ---------------------------------------------------------------------------
+ OBJECT UTILITY FUNCTIONS
+ ---------------------------------------------------------------------------
+ */
+ /**
+ * Get the number of own properties in the object.
+ *
+ * @param map {Object} the map
+ * @return {Integer} number of objects in the map
+ * @lint ignoreUnused(key)
+ */
+ objectGetLength : function(map){
+
+ return qx.Bootstrap.keys(map).length;
+ },
+ /**
+ * Inserts all keys of the source object into the
+ * target objects. Attention: The target map gets modified.
+ *
+ * @param target {Object} target object
+ * @param source {Object} object to be merged
+ * @param overwrite {Boolean ? true} If enabled existing keys will be overwritten
+ * @return {Object} Target with merged values from the source object
+ */
+ objectMergeWith : function(target, source, overwrite){
+
+ if(overwrite === undefined){
+
+ overwrite = true;
+ };
+ for(var key in source){
+
+ if(overwrite || target[key] === undefined){
+
+ target[key] = source[key];
+ };
+ };
+ return target;
+ },
+ /**
+ * IE does not return "shadowed" keys even if they are defined directly
+ * in the object.
+ *
+ * @internal
+ */
+ __shadowedKeys : ["isPrototypeOf", "hasOwnProperty", "toLocaleString", "toString", "valueOf", "propertyIsEnumerable", "constructor"],
+ /**
+ * Get the keys of a map as array as returned by a "for ... in" statement.
+ *
+ * @deprecated {2.1.} Please use Object.keys instead.
+ * @param map {Object} the map
+ * @return {Array} array of the keys of the map
+ */
+ getKeys : function(map){
+
+ if(qx.Bootstrap.DEBUG){
+
+ qx.Bootstrap.warn("'qx.Bootstrap.getKeys' is deprecated. " + "Please use the native 'Object.keys()' instead.");
+ };
+ return qx.Bootstrap.keys(map);
+ },
+ /**
+ * Get the keys of a map as array as returned by a "for ... in" statement.
+ *
+ * @signature function(map)
+ * @internal
+ * @param map {Object} the map
+ * @return {Array} array of the keys of the map
+ */
+ keys : ({
+ "ES5" : Object.keys,
+ "BROKEN_IE" : function(map){
+
+ if(map === null || (typeof map != "object" && typeof map != "function")){
+
+ throw new TypeError("Object.keys requires an object as argument.");
+ };
+ var arr = [];
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
+ for(var key in map){
+
+ if(hasOwnProperty.call(map, key)){
+
+ arr.push(key);
+ };
+ };
+ // IE does not return "shadowed" keys even if they are defined directly
+ // in the object. This is incompatible with the ECMA standard!!
+ // This is why this checks are needed.
+ var shadowedKeys = qx.Bootstrap.__shadowedKeys;
+ for(var i = 0,a = shadowedKeys,l = a.length;i < l;i++){
+
+ if(hasOwnProperty.call(map, a[i])){
+
+ arr.push(a[i]);
+ };
+ };
+ return arr;
+ },
+ "default" : function(map){
+
+ if(map === null || (typeof map != "object" && typeof map != "function")){
+
+ throw new TypeError("Object.keys requires an object as argument.");
+ };
+ var arr = [];
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
+ for(var key in map){
+
+ if(hasOwnProperty.call(map, key)){
+
+ arr.push(key);
+ };
+ };
+ return arr;
+ }
+ })[typeof (Object.keys) == "function" ? "ES5" : (function(){
+
+ for(var key in {
+ toString : 1
+ }){
+
+ return key;
+ };
+ })() !== "toString" ? "BROKEN_IE" : "default"],
+ /**
+ * Get the keys of a map as string
+ *
+ * @param map {Object} the map
+ * @deprecated {2.1} Object.keys(map).join('\", "').
+ * @return {String} String of the keys of the map
+ * The keys are separated by ", "
+ */
+ getKeysAsString : function(map){
+
+ {
+ };
+ var keys = qx.Bootstrap.keys(map);
+ if(keys.length == 0){
+
+ return "";
+ };
+ return '"' + keys.join('\", "') + '"';
+ },
+ /**
+ * Mapping from JavaScript string representation of objects to names
+ * @internal
+ */
+ __classToTypeMap : {
+ "[object String]" : "String",
+ "[object Array]" : "Array",
+ "[object Object]" : "Object",
+ "[object RegExp]" : "RegExp",
+ "[object Number]" : "Number",
+ "[object Boolean]" : "Boolean",
+ "[object Date]" : "Date",
+ "[object Function]" : "Function",
+ "[object Error]" : "Error"
+ },
+ /*
+ ---------------------------------------------------------------------------
+ FUNCTION UTILITY FUNCTIONS
+ ---------------------------------------------------------------------------
+ */
+ /**
+ * Returns a function whose "this" is altered.
+ *
+ * *Syntax*
+ *
+ *
qx.Bootstrap.bind(myFunction, [self, [varargs...]]);+ * + * *Example* + * + *
+ * function myFunction()
+ * {
+ * this.setStyle('color', 'red');
+ * // note that 'this' here refers to myFunction, not an element
+ * // we'll need to bind this function to the element we want to alter
+ * };
+ *
+ * var myBoundFunction = qx.Bootstrap.bind(myFunction, myElement);
+ * myBoundFunction(); // this will make the element myElement red.
+ *
+ *
+ * @param func {Function} Original function to wrap
+ * @param self {Object ? null} The object that the "this" of the function will refer to.
+ * @param varargs {arguments ? null} The arguments to pass to the function.
+ * @return {Function} The bound function.
+ */
+ bind : function(func, self, varargs){
+
+ var fixedArgs = Array.prototype.slice.call(arguments, 2, arguments.length);
+ return function(){
+
+ var args = Array.prototype.slice.call(arguments, 0, arguments.length);
+ return func.apply(self, fixedArgs.concat(args));
+ };
+ },
+ /*
+ ---------------------------------------------------------------------------
+ STRING UTILITY FUNCTIONS
+ ---------------------------------------------------------------------------
+ */
+ /**
+ * Convert the first character of the string to upper case.
+ *
+ * @param str {String} the string
+ * @return {String} the string with an upper case first character
+ */
+ firstUp : function(str){
+
+ return str.charAt(0).toUpperCase() + str.substr(1);
+ },
+ /**
+ * Convert the first character of the string to lower case.
+ *
+ * @param str {String} the string
+ * @return {String} the string with a lower case first character
+ */
+ firstLow : function(str){
+
+ return str.charAt(0).toLowerCase() + str.substr(1);
+ },
+ /*
+ ---------------------------------------------------------------------------
+ TYPE UTILITY FUNCTIONS
+ ---------------------------------------------------------------------------
+ */
+ /**
+ * Get the internal class of the value. See
+ * http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
+ * for details.
+ *
+ * @param value {var} value to get the class for
+ * @return {String} the internal class of the value
+ */
+ getClass : function(value){
+
+ var classString = Object.prototype.toString.call(value);
+ return (qx.Bootstrap.__classToTypeMap[classString] || classString.slice(8, -1));
+ },
+ /**
+ * Whether the value is a string.
+ *
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is a string.
+ */
+ isString : function(value){
+
+ // Added "value !== null" because IE throws an exception "Object expected"
+ // by executing "value instanceof String" if value is a DOM element that
+ // doesn't exist. It seems that there is an internal different between a
+ // JavaScript null and a null returned from calling DOM.
+ // e.q. by document.getElementById("ReturnedNull").
+ return (value !== null && (typeof value === "string" || qx.Bootstrap.getClass(value) == "String" || value instanceof String || (!!value && !!value.$$isString)));
+ },
+ /**
+ * Whether the value is an array.
+ *
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is an array.
+ */
+ isArray : function(value){
+
+ // Added "value !== null" because IE throws an exception "Object expected"
+ // by executing "value instanceof Array" if value is a DOM element that
+ // doesn't exist. It seems that there is an internal different between a
+ // JavaScript null and a null returned from calling DOM.
+ // e.q. by document.getElementById("ReturnedNull").
+ return (value !== null && (value instanceof Array || (value && qx.data && qx.data.IListData && qx.util.OOUtil.hasInterface(value.constructor, qx.data.IListData)) || qx.Bootstrap.getClass(value) == "Array" || (!!value && !!value.$$isArray)));
+ },
+ /**
+ * Whether the value is an object. Note that built-in types like Window are
+ * not reported to be objects.
+ *
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is an object.
+ */
+ isObject : function(value){
+
+ return (value !== undefined && value !== null && qx.Bootstrap.getClass(value) == "Object");
+ },
+ /**
+ * Whether the value is a function.
+ *
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is a function.
+ */
+ isFunction : function(value){
+
+ return qx.Bootstrap.getClass(value) == "Function";
+ },
+ /*
+ ---------------------------------------------------------------------------
+ LOGGING UTILITY FUNCTIONS
+ ---------------------------------------------------------------------------
+ */
+ $$logs : [],
+ /**
+ * Sending a message at level "debug" to the logger.
+ *
+ * @param object {Object} Contextual object (either instance or static class)
+ * @param message {var} Any number of arguments supported. An argument may
+ * have any JavaScript data type. All data is serialized immediately and
+ * does not keep references to other objects.
+ */
+ debug : function(object, message){
+
+ qx.Bootstrap.$$logs.push(["debug", arguments]);
+ },
+ /**
+ * Sending a message at level "info" to the logger.
+ *
+ * @param object {Object} Contextual object (either instance or static class)
+ * @param message {var} Any number of arguments supported. An argument may
+ * have any JavaScript data type. All data is serialized immediately and
+ * does not keep references to other objects.
+ */
+ info : function(object, message){
+
+ qx.Bootstrap.$$logs.push(["info", arguments]);
+ },
+ /**
+ * Sending a message at level "warn" to the logger.
+ *
+ * @param object {Object} Contextual object (either instance or static class)
+ * @param message {var} Any number of arguments supported. An argument may
+ * have any JavaScript data type. All data is serialized immediately and
+ * does not keep references to other objects.
+ */
+ warn : function(object, message){
+
+ qx.Bootstrap.$$logs.push(["warn", arguments]);
+ },
+ /**
+ * Sending a message at level "error" to the logger.
+ *
+ * @param object {Object} Contextual object (either instance or static class)
+ * @param message {var} Any number of arguments supported. An argument may
+ * have any JavaScript data type. All data is serialized immediately and
+ * does not keep references to other objects.
+ */
+ error : function(object, message){
+
+ qx.Bootstrap.$$logs.push(["error", arguments]);
+ },
+ /**
+ * Prints the current stack trace at level "info"
+ *
+ * @param object {Object} Contextual object (either instance or static class)
+ */
+ trace : function(object){
+ }
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2005-2011 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (martinwittemann)
+
+************************************************************************ */
+/**
+ * This class is the single point to access all settings that may be different
+ * in different environments. This contains e.g. the browser name, engine
+ * version but also qooxdoo or application specific settings.
+ *
+ * Its public API can be found in its four main methods. One pair of methods
+ * is used to check the synchronous values of the environment. The other pair
+ * of methods is used for asynchronous checks.
+ *
+ * The most often used method should be {@link #get}, which returns the
+ * current value for a given environment check.
+ *
+ * All qooxdoo settings can be changed via the generator's config. See the manual
+ * for more details about the environment key in the config. As you can see
+ * from the methods API, there is no way to override an existing key. So if you
+ * need to change a qooxdoo setting, you have to use the generator to do so.
+ *
+ * The following table shows the available checks. If you are
+ * interested in more details, check the reference to the implementation of
+ * each check. Please do not use those check implementations directly, as the
+ * Environment class comes with a smart caching feature.
+ *
+ * Synchronous checks+ * |
+ * |||
Key |
+ * Type |
+ * Example |
+ * Details |
+ *
|---|---|---|---|
| browser | + *|||
| browser.documentmode | Integer | 0 |
+ * {@link qx.bom.client.Browser#getDocumentMode} | + *
| browser.name | String | chrome |
+ * {@link qx.bom.client.Browser#getName} | + *
| browser.quirksmode | Boolean | false |
+ * {@link qx.bom.client.Browser#getQuirksMode} | + *
| browser.version | String | 11.0 |
+ * {@link qx.bom.client.Browser#getVersion} | + *
| runtime | + *|||
| runtime.name | String | node.js |
+ * {@link qx.bom.client.Runtime#getName} | + *
| css | + *|||
| css.borderradius | String or null | borderRadius |
+ * {@link qx.bom.client.Css#getBorderRadius} | + *
| css.borderimage | String or null | WebkitBorderImage |
+ * {@link qx.bom.client.Css#getBorderImage} | + *
| css.borderimage.standardsyntax | Boolean or null | true |
+ * {@link qx.bom.client.Css#getBorderImageSyntax} | + *
| css.boxmodel | String | content |
+ * {@link qx.bom.client.Css#getBoxModel} | + *
| css.boxshadow | String or null | boxShadow |
+ * {@link qx.bom.client.Css#getBoxShadow} | + *
| css.gradient.linear | String or null | -moz-linear-gradient |
+ * {@link qx.bom.client.Css#getLinearGradient} | + *
| css.gradient.filter | Boolean | true |
+ * {@link qx.bom.client.Css#getFilterGradient} | + *
| css.gradient.radial | String or null | -moz-radial-gradient |
+ * {@link qx.bom.client.Css#getRadialGradient} | + *
| css.gradient.legacywebkit | Boolean | false |
+ * {@link qx.bom.client.Css#getLegacyWebkitGradient} | + *
| css.placeholder | Boolean | true |
+ * {@link qx.bom.client.Css#getPlaceholder} | + *
| css.textoverflow | String or null | textOverflow |
+ * {@link qx.bom.client.Css#getTextOverflow} | + *
| css.rgba | Boolean | true |
+ * {@link qx.bom.client.Css#getRgba} | + *
| css.usermodify | String or null | WebkitUserModify |
+ * {@link qx.bom.client.Css#getUserModify} | + *
| css.appearance | String or null | WebkitAppearance |
+ * {@link qx.bom.client.Css#getAppearance} | + *
| css.float | String or null | cssFloat |
+ * {@link qx.bom.client.Css#getFloat} | + *
| css.userselect | String or null | WebkitUserSelect |
+ * {@link qx.bom.client.Css#getUserSelect} | + *
| css.userselect.none | String or null | -moz-none |
+ * {@link qx.bom.client.Css#getUserSelectNone} | + *
| css.boxsizing | String or null | boxSizing |
+ * {@link qx.bom.client.Css#getBoxSizing} | + *
| css.animation | Object or null | {end-event: "webkitAnimationEnd", keyframes: "@-webkit-keyframes", play-state: null, name: "WebkitAnimation"} |
+ * {@link qx.bom.client.CssAnimation#getSupport} | + *
| css.animation.requestframe | String or null | mozRequestAnimationFrame |
+ * {@link qx.bom.client.CssAnimation#getRequestAnimationFrame} | + *
| css.transform | Object or null | {3d: true, origin: "WebkitTransformOrigin", name: "WebkitTransform", style: "WebkitTransformStyle", perspective: "WebkitPerspective", perspective-origin: "WebkitPerspectiveOrigin", backface-visibility: "WebkitBackfaceVisibility"} |
+ * {@link qx.bom.client.CssTransform#getSupport} | + *
| css.transform.3d | Boolean | false |
+ * {@link qx.bom.client.CssTransform#get3D} | + *
| css.inlineblock | String or null | inline-block |
+ * {@link qx.bom.client.Css#getInlineBlock} | + *
| css.opacity | Boolean | true |
+ * {@link qx.bom.client.Css#getOpacity} | + *
| deprecated since 2.1: css.overflowxy | Boolean | true |
+ * {@link qx.bom.client.Css#getOverflowXY} | + *
| css.textShadow | Boolean | true |
+ * {@link qx.bom.client.Css#getTextShadow} | + *
| css.textShadow.filter | Boolean | true |
+ * {@link qx.bom.client.Css#getFilterTextShadow} | + *
| device | + *|||
| device.name | String | pc |
+ * {@link qx.bom.client.Device#getName} | + *
| device.type | String | mobile |
+ * {@link qx.bom.client.Device#getType} | + *
| ecmascript | + *|||
| ecmascript.error.stacktrace | String or null | stack |
+ * {@link qx.bom.client.EcmaScript#getStackTrace} | + *
| ecmascript.array.indexof | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getArrayIndexOf} | + *
| ecmascript.array.lastindexof | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getArrayLastIndexOf} | + *
| ecmascript.array.foreach | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getArrayForEach} | + *
| ecmascript.array.filter | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getArrayFilter} | + *
| ecmascript.array.map | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getArrayMap} | + *
| ecmascript.array.some | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getArraySome} | + *
| ecmascript.array.every | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getArrayEvery} | + *
| ecmascript.array.reduce | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getArrayReduce} | + *
| ecmascript.array.reduceright | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getArrayReduceRight} | + *
| ecmascript.function.bind | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getFunctionBind} | + *
| ecmascript.object.keys | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getObjectKeys} | + *
| ecmascript.date.now | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getDateNow} | + *
| ecmascript.error.toString | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getErrorToString} | + *
| ecmascript.string.trim | Boolean | true |
+ * {@link qx.bom.client.EcmaScript#getStringTrim} | + *
| engine | + *|||
| engine.name | String | webkit |
+ * {@link qx.bom.client.Engine#getName} | + *
| engine.version | String | 534.24 |
+ * {@link qx.bom.client.Engine#getVersion} | + *
| event | + *|||
| event.pointer | Boolean | true |
+ * {@link qx.bom.client.Event#getPointer} | + *
| event.mspointer | Boolean | true |
+ * {@link qx.bom.client.Event#getMsPointer} | + *
| event.touch | Boolean | false |
+ * {@link qx.bom.client.Event#getTouch} | + *
| event.help | Boolean | false |
+ * {@link qx.bom.client.Event#getHelp} | + *
| event.hashchange | Boolean | true |
+ * {@link qx.bom.client.Event#getHashChange} | + *
| html | + *|||
| html.audio | Boolean | true |
+ * {@link qx.bom.client.Html#getAudio} | + *
| html.audio.mp3 | String | "" |
+ * {@link qx.bom.client.Html#getAudioMp3} | + *
| html.audio.ogg | String | "maybe" |
+ * {@link qx.bom.client.Html#getAudioOgg} | + *
| html.audio.wav | String | "probably" |
+ * {@link qx.bom.client.Html#getAudioWav} | + *
| html.audio.au | String | "maybe" |
+ * {@link qx.bom.client.Html#getAudioAu} | + *
| html.audio.aif | String | "probably" |
+ * {@link qx.bom.client.Html#getAudioAif} | + *
| html.canvas | Boolean | true |
+ * {@link qx.bom.client.Html#getCanvas} | + *
| html.classlist | Boolean | true |
+ * {@link qx.bom.client.Html#getClassList} | + *
| html.geolocation | Boolean | true |
+ * {@link qx.bom.client.Html#getGeoLocation} | + *
| html.storage.local | Boolean | true |
+ * {@link qx.bom.client.Html#getLocalStorage} | + *
| html.storage.session | Boolean | true |
+ * {@link qx.bom.client.Html#getSessionStorage} | + *
| html.storage.userdata | Boolean | true |
+ * {@link qx.bom.client.Html#getUserDataStorage} | + *
| html.svg | Boolean | true |
+ * {@link qx.bom.client.Html#getSvg} | + *
| html.video | Boolean | true |
+ * {@link qx.bom.client.Html#getVideo} | + *
| html.video.h264 | String | "probably" |
+ * {@link qx.bom.client.Html#getVideoH264} | + *
| html.video.ogg | String | "" |
+ * {@link qx.bom.client.Html#getVideoOgg} | + *
| html.video.webm | String | "maybe" |
+ * {@link qx.bom.client.Html#getVideoWebm} | + *
| html.vml | Boolean | false |
+ * {@link qx.bom.client.Html#getVml} | + *
| html.webworker | Boolean | true |
+ * {@link qx.bom.client.Html#getWebWorker} | + *
| html.filereader | Boolean | true |
+ * {@link qx.bom.client.Html#getFileReader} | + *
| html.xpath | Boolean | true |
+ * {@link qx.bom.client.Html#getXPath} | + *
| html.xul | Boolean | true |
+ * {@link qx.bom.client.Html#getXul} | + *
| html.console | Boolean | true |
+ * {@link qx.bom.client.Html#getConsole} | + *
| html.element.contains | Boolean | true |
+ * {@link qx.bom.client.Html#getContains} | + *
| html.element.compareDocumentPosition | Boolean | true |
+ * {@link qx.bom.client.Html#getCompareDocumentPosition} | + *
| html.element.textContent | Boolean | true |
+ * {@link qx.bom.client.Html#getTextContent} | + *
| html.image.naturaldimensions | Boolean | true |
+ * {@link qx.bom.client.Html#getNaturalDimensions} | + *
| html.history.state | Boolean | true |
+ * {@link qx.bom.client.Html#getHistoryState} | + *
| html.selection | String | getSelection |
+ * {@link qx.bom.client.Html#getSelection} | + *
| XML | + *|||
| xml.implementation | Boolean | true |
+ * {@link qx.bom.client.Xml#getImplementation} | + *
| xml.domparser | Boolean | true |
+ * {@link qx.bom.client.Xml#getDomParser} | + *
| xml.selectsinglenode | Boolean | false |
+ * {@link qx.bom.client.Xml#getSelectSingleNode} | + *
| xml.selectnodes | Boolean | false |
+ * {@link qx.bom.client.Xml#getSelectNodes} | + *
| xml.getelementsbytagnamens | Boolean | true |
+ * {@link qx.bom.client.Xml#getElementsByTagNameNS} | + *
| xml.domproperties | Boolean | false |
+ * {@link qx.bom.client.Xml#getDomProperties} | + *
| xml.attributens | Boolean | true |
+ * {@link qx.bom.client.Xml#getAttributeNS} | + *
| xml.createelementns | Boolean | true |
+ * {@link qx.bom.client.Xml#getCreateElementNS} | + *
| xml.createnode | Boolean | false |
+ * {@link qx.bom.client.Xml#getCreateNode} | + *
| xml.getqualifieditem | Boolean | false |
+ * {@link qx.bom.client.Xml#getQualifiedItem} | + *
| Stylesheets | + *|||
| html.stylesheet.createstylesheet | Boolean | false |
+ * {@link qx.bom.client.Stylesheet#getCreateStyleSheet} | + *
| html.stylesheet.insertrule | Boolean | true |
+ * {@link qx.bom.client.Stylesheet#getInsertRule} | + *
| html.stylesheet.deleterule | Boolean | true |
+ * {@link qx.bom.client.Stylesheet#getDeleteRule} | + *
| html.stylesheet.addimport | Boolean | false |
+ * {@link qx.bom.client.Stylesheet#getAddImport} | + *
| html.stylesheet.removeimport | Boolean | false |
+ * {@link qx.bom.client.Stylesheet#getRemoveImport} | + *
| io | + *|||
| io.maxrequests | Integer | 4 |
+ * {@link qx.bom.client.Transport#getMaxConcurrentRequestCount} | + *
| io.ssl | Boolean | false |
+ * {@link qx.bom.client.Transport#getSsl} | + *
| io.xhr | String | xhr |
+ * {@link qx.bom.client.Transport#getXmlHttpRequest} | + *
| locale | + *|||
| locale | String | de |
+ * {@link qx.bom.client.Locale#getLocale} | + *
| locale.variant | String | de |
+ * {@link qx.bom.client.Locale#getVariant} | + *
| os | + *|||
| os.name | String | osx |
+ * {@link qx.bom.client.OperatingSystem#getName} | + *
| os.version | String | 10.6 |
+ * {@link qx.bom.client.OperatingSystem#getVersion} | + *
| os.scrollBarOverlayed | Boolean | false |
+ * {@link qx.bom.client.Scroll#scrollBarOverlayed} | + *
| phonegap | + *|||
| phonegap | Boolean | false |
+ * {@link qx.bom.client.PhoneGap#getPhoneGap} | + *
| phonegap.notification | Boolean | false |
+ * {@link qx.bom.client.PhoneGap#getNotification} | + *
| plugin | + *|||
| plugin.divx | Boolean | false |
+ * {@link qx.bom.client.Plugin#getDivX} | + *
| plugin.divx.version | String | + * | {@link qx.bom.client.Plugin#getDivXVersion} | + *
| plugin.flash | Boolean | true |
+ * {@link qx.bom.client.Flash#isAvailable} | + *
| plugin.flash.express | Boolean | true |
+ * {@link qx.bom.client.Flash#getExpressInstall} | + *
| plugin.flash.strictsecurity | Boolean | true |
+ * {@link qx.bom.client.Flash#getStrictSecurityModel} | + *
| plugin.flash.version | String | 10.2.154 |
+ * {@link qx.bom.client.Flash#getVersion} | + *
| plugin.gears | Boolean | false |
+ * {@link qx.bom.client.Plugin#getGears} | + *
| plugin.activex | Boolean | false |
+ * {@link qx.bom.client.Plugin#getActiveX} | + *
| plugin.skype | Boolean | false |
+ * {@link qx.bom.client.Plugin#getSkype} | + *
| plugin.pdf | Boolean | false |
+ * {@link qx.bom.client.Plugin#getPdf} | + *
| plugin.pdf.version | String | + * | {@link qx.bom.client.Plugin#getPdfVersion} | + *
| plugin.quicktime | Boolean | true |
+ * {@link qx.bom.client.Plugin#getQuicktime} | + *
| plugin.quicktime.version | String | 7.6 |
+ * {@link qx.bom.client.Plugin#getQuicktimeVersion} | + *
| plugin.silverlight | Boolean | false |
+ * {@link qx.bom.client.Plugin#getSilverlight} | + *
| plugin.silverlight.version | String | + * | {@link qx.bom.client.Plugin#getSilverlightVersion} | + *
| plugin.windowsmedia | Boolean | false |
+ * {@link qx.bom.client.Plugin#getWindowsMedia} | + *
| plugin.windowsmedia.version | String | + * | {@link qx.bom.client.Plugin#getWindowsMediaVersion} | + *
| qx | + *|||
| qx.allowUrlSettings | Boolean | true |
+ * default: false |
+ *
| qx.allowUrlVariants | Boolean | true |
+ * default: false |
+ *
| qx.application | String | name.space |
+ * default: <<application name>> |
+ *
| qx.aspects | Boolean | false |
+ * default: false |
+ *
| qx.debug | Boolean | true |
+ * default: true |
+ *
| qx.debug.databinding | Boolean | false |
+ * default: false |
+ *
| qx.debug.dispose | Boolean | false |
+ * default: false |
+ *
| qx.debug.dispose.level | Integer | 0 |
+ * default: 0 |
+ *
| qx.debug.io | Boolean | true |
+ * default: false |
+ *
| qx.debug.io.remote | Boolean | true |
+ * default: false |
+ *
| qx.debug.io.remote.data | Boolean | true |
+ * default: false |
+ *
| qx.debug.property.level | Integer | 0 |
+ * default: 0 |
+ *
| qx.debug.ui.queue | Boolean | true |
+ * default: true |
+ *
| qx.dynamicmousewheel | Boolean | true |
+ * default: true |
+ *
| qx.dynlocale | Boolean | true |
+ * default: true |
+ *
| qx.globalErrorHandling | Boolean | true |
+ * default: true |
+ *
| qx.mobile.emulatetouch | Boolean | false |
+ * default: false |
+ *
| qx.mobile.nativescroll | Boolean | false |
+ * default: false |
+ *
| qx.optimization.basecalls | Boolean | true |
+ * true if the corresp. optimize key is set in the config | + *
| qx.optimization.comments | Boolean | true |
+ * true if the corresp. optimize key is set in the config | + *
| qx.optimization.privates | Boolean | true |
+ * true if the corresp. optimize key is set in the config | + *
| qx.optimization.strings | Boolean | true |
+ * true if the corresp. optimize key is set in the config | + *
| qx.optimization.variables | Boolean | true |
+ * true if the corresp. optimize key is set in the config | + *
| qx.optimization.variants | Boolean | true |
+ * true if the corresp. optimize key is set in the config | + *
| qx.revision | String | 27348 |
+ * |
| qx.theme | String | qx.theme.Modern |
+ * default: <<initial theme name>> |
+ *
| qx.version | String | ${qxversion} |
+ * |
| qx.blankpage | String | URI to blank.html page |
+ * |
| module | + *|||
| module.databinding | Boolean | true |
+ * default: true |
+ *
| module.logger | Boolean | true |
+ * default: true |
+ *
| module.property | Boolean | true |
+ * default: true |
+ *
| module.events | Boolean | true |
+ * default: true |
+ *
Asynchronous checks+ * |
+ * |||
| html.dataurl | Boolean | true |
+ * {@link qx.bom.client.Html#getDataUrl} | + *
true. This is especially handy for conditional
+ * includes of mixins.
+ * @param map {Map} A map containing check names as keys and values.
+ * @return {Array} An array containing the values.
+ */
+ filter : function(map){
+
+ var returnArray = [];
+ for(var check in map){
+
+ if(this.get(check)){
+
+ returnArray.push(map[check]);
+ };
+ };
+ return returnArray;
+ },
+ /**
+ * Invalidates the cache for the given key.
+ *
+ * @param key {String} The key of the check.
+ */
+ invalidateCacheKey : function(key){
+
+ delete this.__cache[key];
+ },
+ /**
+ * Add a check to the environment class. If there is already a check
+ * added for the given key, the add will be ignored.
+ *
+ * @param key {String} The key for the check e.g. html.featurexyz.
+ * @param check {var} It could be either a function or a simple value.
+ * The function should be responsible for the check and should return the
+ * result of the check.
+ */
+ add : function(key, check){
+
+ // ignore already added checks.
+ if(this._checks[key] == undefined){
+
+ // add functions directly
+ if(check instanceof Function){
+
+ this._checks[key] = check;
+ } else {
+
+ this._checks[key] = this.__createCheck(check);
+ };
+ };
+ },
+ /**
+ * Adds an asynchronous check to the environment. If there is already a check
+ * added for the given key, the add will be ignored.
+ *
+ * @param key {String} The key of the check e.g. html.featureabc
+ * @param check {Function} A function which should check for a specific
+ * environment setting in an asynchronous way. The method should take two
+ * arguments. First one is the callback and the second one is the context.
+ */
+ addAsync : function(key, check){
+
+ if(this._checks[key] == undefined){
+
+ this._asyncChecks[key] = check;
+ };
+ },
+ /**
+ * Returns all currently defined synchronous checks.
+ *
+ * @internal
+ * @return {Map} The map of synchronous checks
+ */
+ getChecks : function(){
+
+ return this._checks;
+ },
+ /**
+ * Returns all currently defined asynchronous checks.
+ *
+ * @internal
+ * @return {Map} The map of asynchronous checks
+ */
+ getAsyncChecks : function(){
+
+ return this._asyncChecks;
+ },
+ /**
+ * Initializer for the default values of the framework settings.
+ */
+ _initDefaultQxValues : function(){
+
+ // an always-true key (e.g. for use in qx.core.Environment.filter() calls)
+ this.add("true", function(){
+
+ return true;
+ });
+ // old settings
+ this.add("qx.allowUrlSettings", function(){
+
+ return false;
+ });
+ this.add("qx.allowUrlVariants", function(){
+
+ return false;
+ });
+ this.add("qx.debug.property.level", function(){
+
+ return 0;
+ });
+ // old variants
+ // make sure to reflect all changes to qx.debug here in the bootstrap class!
+ this.add("qx.debug", function(){
+
+ return true;
+ });
+ this.add("qx.debug.ui.queue", function(){
+
+ return true;
+ });
+ this.add("qx.aspects", function(){
+
+ return false;
+ });
+ this.add("qx.dynlocale", function(){
+
+ return true;
+ });
+ this.add("qx.mobile.emulatetouch", function(){
+
+ return false;
+ });
+ this.add("qx.mobile.nativescroll", function(){
+
+ return false;
+ });
+ this.add("qx.blankpage", function(){
+
+ return "qx/static/blank.html";
+ });
+ this.add("qx.dynamicmousewheel", function(){
+
+ return true;
+ });
+ this.add("qx.debug.databinding", function(){
+
+ return false;
+ });
+ this.add("qx.debug.dispose", function(){
+
+ return false;
+ });
+ // generator optimization vectors
+ this.add("qx.optimization.basecalls", function(){
+
+ return false;
+ });
+ this.add("qx.optimization.comments", function(){
+
+ return false;
+ });
+ this.add("qx.optimization.privates", function(){
+
+ return false;
+ });
+ this.add("qx.optimization.strings", function(){
+
+ return false;
+ });
+ this.add("qx.optimization.variables", function(){
+
+ return false;
+ });
+ this.add("qx.optimization.variants", function(){
+
+ return false;
+ });
+ // qooxdoo modules
+ this.add("module.databinding", function(){
+
+ return true;
+ });
+ this.add("module.logger", function(){
+
+ return true;
+ });
+ this.add("module.property", function(){
+
+ return true;
+ });
+ this.add("module.events", function(){
+
+ return true;
+ });
+ this.add("qx.nativeScrollBars", function(){
+
+ return false;
+ });
+ },
+ /**
+ * Import checks from global qx.$$environment into the Environment class.
+ */
+ __importFromGenerator : function(){
+
+ // import the environment map
+ if(qx && qx.$$environment){
+
+ for(var key in qx.$$environment){
+
+ var value = qx.$$environment[key];
+ this._checks[key] = this.__createCheck(value);
+ };
+ };
+ },
+ /**
+ * Checks the URL for environment settings and imports these into the
+ * Environment class.
+ */
+ __importFromUrl : function(){
+
+ if(window.document && window.document.location){
+
+ var urlChecks = window.document.location.search.slice(1).split("&");
+ for(var i = 0;i < urlChecks.length;i++){
+
+ var check = urlChecks[i].split(":");
+ if(check.length != 3 || check[0] != "qxenv"){
+
+ continue;
+ };
+ var key = check[1];
+ var value = decodeURIComponent(check[2]);
+ // implicit type conversion
+ if(value == "true"){
+
+ value = true;
+ } else if(value == "false"){
+
+ value = false;
+ } else if(/^(\d|\.)+$/.test(value)){
+
+ value = parseFloat(value);
+ };;
+ this._checks[key] = this.__createCheck(value);
+ };
+ };
+ },
+ /**
+ * Internal helper which creates a function returning the given value.
+ *
+ * @param value {var} The value which should be returned.
+ * @return {Function} A function which could be used by a test.
+ */
+ __createCheck : function(value){
+
+ return qx.Bootstrap.bind(function(value){
+
+ return value;
+ }, null, value);
+ }
+ },
+ defer : function(statics){
+
+ // create default values for the environment class
+ statics._initDefaultQxValues();
+ // load the checks from the generator
+ statics.__importFromGenerator();
+ // load the checks from the url
+ if(statics.get("qx.allowUrlSettings") === true){
+
+ statics.__importFromUrl();
+ };
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Sebastian Werner (wpbasti)
+ * Martin Wittemann (martinwittemann)
+
+ ======================================================================
+
+ This class contains code from:
+
+ Copyright:
+ 2011 Pocket Widget S.L., Spain, http://www.pocketwidget.com
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+
+ Authors:
+ * Javier Martinez Villacampa
+
+************************************************************************ */
+/**
+ * This class comes with all relevant information regarding
+ * the client's engine.
+ *
+ * This class is used by {@link qx.core.Environment} and should not be used
+ * directly. Please check its class comment for details how to use it.
+ *
+ * @internal
+ */
+qx.Bootstrap.define("qx.bom.client.Engine", {
+ // General: http://en.wikipedia.org/wiki/Browser_timeline
+ // Webkit: https://developer.apple.com/internet/safari/uamatrix.html
+ // Firefox: http://en.wikipedia.org/wiki/History_of_Mozilla_Firefox
+ // Maple: http://www.scribd.com/doc/46675822/2011-SDK2-0-Maple-Browser-Specification-V1-00
+ statics : {
+ /**
+ * Returns the version of the engine.
+ *
+ * @return {String} The version number of the current engine.
+ * @internal
+ */
+ getVersion : function(){
+
+ var agent = window.navigator.userAgent;
+ var version = "";
+ if(qx.bom.client.Engine.__isOpera()){
+
+ // Opera has a special versioning scheme, where the second part is combined
+ // e.g. 8.54 which should be handled like 8.5.4 to be compatible to the
+ // common versioning system used by other browsers
+ if(/Opera[\s\/]([0-9]+)\.([0-9])([0-9]*)/.test(agent)){
+
+ // opera >= 10 has as a first verison 9.80 and adds the proper version
+ // in a separate "Version/" postfix
+ // http://my.opera.com/chooseopera/blog/2009/05/29/changes-in-operas-user-agent-string-format
+ if(agent.indexOf("Version/") != -1){
+
+ var match = agent.match(/Version\/(\d+)\.(\d+)/);
+ // ignore the first match, its the whole version string
+ version = match[1] + "." + match[2].charAt(0) + "." + match[2].substring(1, match[2].length);
+ } else {
+
+ version = RegExp.$1 + "." + RegExp.$2;
+ if(RegExp.$3 != ""){
+
+ version += "." + RegExp.$3;
+ };
+ };
+ };
+ } else if(qx.bom.client.Engine.__isWebkit()){
+
+ if(/AppleWebKit\/([^ ]+)/.test(agent)){
+
+ version = RegExp.$1;
+ // We need to filter these invalid characters
+ var invalidCharacter = RegExp("[^\\.0-9]").exec(version);
+ if(invalidCharacter){
+
+ version = version.slice(0, invalidCharacter.index);
+ };
+ };
+ } else if(qx.bom.client.Engine.__isGecko() || qx.bom.client.Engine.__isMaple()){
+
+ // Parse "rv" section in user agent string
+ if(/rv\:([^\);]+)(\)|;)/.test(agent)){
+
+ version = RegExp.$1;
+ };
+ } else if(qx.bom.client.Engine.__isMshtml()){
+
+ var isTrident = /Trident\/([^\);]+)(\)|;)/.test(agent);
+ if(/MSIE\s+([^\);]+)(\)|;)/.test(agent)){
+
+ version = RegExp.$1;
+ // If the IE8 or IE9 is running in the compatibility mode, the MSIE value
+ // is set to an older version, but we need the correct version. The only
+ // way is to compare the trident version.
+ if(version < 8 && isTrident){
+
+ if(RegExp.$1 == "4.0"){
+
+ version = "8.0";
+ } else if(RegExp.$1 == "5.0"){
+
+ version = "9.0";
+ };
+ };
+ } else if(isTrident){
+
+ // IE 11 dropped the "MSIE" string
+ var match = /\brv\:(\d+?\.\d+?)\b/.exec(agent);
+ if(match){
+
+ version = match[1];
+ };
+ };
+ } else {
+
+ var failFunction = window.qxFail;
+ if(failFunction && typeof failFunction === "function"){
+
+ version = failFunction().FULLVERSION;
+ } else {
+
+ version = "1.9.0.0";
+ qx.Bootstrap.warn("Unsupported client: " + agent + "! Assumed gecko version 1.9.0.0 (Firefox 3.0).");
+ };
+ };;;
+ return version;
+ },
+ /**
+ * Returns the name of the engine.
+ *
+ * @return {String} The name of the current engine.
+ * @internal
+ */
+ getName : function(){
+
+ var name;
+ if(qx.bom.client.Engine.__isOpera()){
+
+ name = "opera";
+ } else if(qx.bom.client.Engine.__isWebkit()){
+
+ name = "webkit";
+ } else if(qx.bom.client.Engine.__isGecko() || qx.bom.client.Engine.__isMaple()){
+
+ name = "gecko";
+ } else if(qx.bom.client.Engine.__isMshtml()){
+
+ name = "mshtml";
+ } else {
+
+ // check for the fallback
+ var failFunction = window.qxFail;
+ if(failFunction && typeof failFunction === "function"){
+
+ name = failFunction().NAME;
+ } else {
+
+ name = "gecko";
+ qx.Bootstrap.warn("Unsupported client: " + window.navigator.userAgent + "! Assumed gecko version 1.9.0.0 (Firefox 3.0).");
+ };
+ };;;
+ return name;
+ },
+ /**
+ * Internal helper for checking for opera.
+ * @return {Boolean} true, if its opera.
+ */
+ __isOpera : function(){
+
+ return window.opera && Object.prototype.toString.call(window.opera) == "[object Opera]";
+ },
+ /**
+ * Internal helper for checking for webkit.
+ * @return {Boolean} true, if its webkit.
+ */
+ __isWebkit : function(){
+
+ return window.navigator.userAgent.indexOf("AppleWebKit/") != -1;
+ },
+ /**
+ * Internal helper for checking for Maple .
+ * Maple is used in Samsung SMART TV 2010-2011 models. It's based on Gecko
+ * engine 1.8.1.11.
+ * @return {Boolean} true, if its maple.
+ */
+ __isMaple : function(){
+
+ return window.navigator.userAgent.indexOf("Maple") != -1;
+ },
+ /**
+ * Internal helper for checking for gecko.
+ * @return {Boolean} true, if its gecko.
+ */
+ __isGecko : function(){
+
+ return window.controllers && window.navigator.product === "Gecko" && window.navigator.userAgent.indexOf("Maple") == -1 && window.navigator.userAgent.indexOf("Trident") == -1;
+ },
+ /**
+ * Internal helper to check for MSHTML.
+ * @return {Boolean} true, if its MSHTML.
+ */
+ __isMshtml : function(){
+
+ return window.navigator.cpuClass && (/MSIE\s+([^\);]+)(\)|;)/.test(window.navigator.userAgent) || /Trident\/\d+?\.\d+?/.test(window.navigator.userAgent));
+ }
+ },
+ defer : function(statics){
+
+ qx.core.Environment.add("engine.version", statics.getVersion);
+ qx.core.Environment.add("engine.name", statics.getName);
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2011 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (martinwittemann)
+
+************************************************************************ */
+/**
+ * The main purpose of this class to hold all checks about ECMAScript.
+ *
+ * This class is used by {@link qx.core.Environment} and should not be used
+ * directly. Please check its class comment for details how to use it.
+ *
+ * @internal
+ */
+qx.Bootstrap.define("qx.bom.client.EcmaScript", {
+ statics : {
+ /**
+ * Returns the name of the Error object property that holds stack trace
+ * information or null if the client does not provide any.
+ *
+ * @internal
+ * @return {String|null} stack, stacktrace or
+ * null
+ */
+ getStackTrace : function(){
+
+ var propName;
+ var e = new Error("e");
+ propName = e.stack ? "stack" : e.stacktrace ? "stacktrace" : null;
+ // only thrown errors have the stack property in IE10 and PhantomJS
+ if(!propName){
+
+ try{
+
+ throw e;
+ } catch(ex) {
+
+ e = ex;
+ };
+ };
+ return e.stacktrace ? "stacktrace" : e.stack ? "stack" : null;
+ },
+ /**
+ * Checks if 'indexOf' is supported on the Array object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getArrayIndexOf : function(){
+
+ return !!Array.prototype.indexOf;
+ },
+ /**
+ * Checks if 'lastIndexOf' is supported on the Array object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getArrayLastIndexOf : function(){
+
+ return !!Array.prototype.lastIndexOf;
+ },
+ /**
+ * Checks if 'forEach' is supported on the Array object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getArrayForEach : function(){
+
+ return !!Array.prototype.forEach;
+ },
+ /**
+ * Checks if 'filter' is supported on the Array object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getArrayFilter : function(){
+
+ return !!Array.prototype.filter;
+ },
+ /**
+ * Checks if 'map' is supported on the Array object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getArrayMap : function(){
+
+ return !!Array.prototype.map;
+ },
+ /**
+ * Checks if 'some' is supported on the Array object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getArraySome : function(){
+
+ return !!Array.prototype.some;
+ },
+ /**
+ * Checks if 'every' is supported on the Array object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getArrayEvery : function(){
+
+ return !!Array.prototype.every;
+ },
+ /**
+ * Checks if 'reduce' is supported on the Array object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getArrayReduce : function(){
+
+ return !!Array.prototype.reduce;
+ },
+ /**
+ * Checks if 'reduceRight' is supported on the Array object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getArrayReduceRight : function(){
+
+ return !!Array.prototype.reduceRight;
+ },
+ /**
+ * Checks if 'toString' is supported on the Error object and
+ * its working as expected.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getErrorToString : function(){
+
+ return typeof Error.prototype.toString == "function" && Error.prototype.toString() !== "[object Error]";
+ },
+ /**
+ * Checks if 'bind' is supported on the Function object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getFunctionBind : function(){
+
+ return typeof Function.prototype.bind === "function";
+ },
+ /**
+ * Checks if 'keys' is supported on the Object object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getObjectKeys : function(){
+
+ return !!Object.keys;
+ },
+ /**
+ * Checks if 'now' is supported on the Date object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getDateNow : function(){
+
+ return !!Date.now;
+ },
+ /**
+ * Checks if 'trim' is supported on the String object.
+ * @internal
+ * @return {Boolean} true, if the method is available.
+ */
+ getStringTrim : function(){
+
+ return typeof String.prototype.trim === "function";
+ }
+ },
+ defer : function(statics){
+
+ // array polyfill
+ qx.core.Environment.add("ecmascript.array.indexof", statics.getArrayIndexOf);
+ qx.core.Environment.add("ecmascript.array.lastindexof", statics.getArrayLastIndexOf);
+ qx.core.Environment.add("ecmascript.array.foreach", statics.getArrayForEach);
+ qx.core.Environment.add("ecmascript.array.filter", statics.getArrayFilter);
+ qx.core.Environment.add("ecmascript.array.map", statics.getArrayMap);
+ qx.core.Environment.add("ecmascript.array.some", statics.getArraySome);
+ qx.core.Environment.add("ecmascript.array.every", statics.getArrayEvery);
+ qx.core.Environment.add("ecmascript.array.reduce", statics.getArrayReduce);
+ qx.core.Environment.add("ecmascript.array.reduceright", statics.getArrayReduceRight);
+ // date polyfill
+ qx.core.Environment.add("ecmascript.date.now", statics.getDateNow);
+ // error bugfix
+ qx.core.Environment.add("ecmascript.error.toString", statics.getErrorToString);
+ qx.core.Environment.add("ecmascript.error.stacktrace", statics.getStackTrace);
+ // function polyfill
+ qx.core.Environment.add("ecmascript.function.bind", statics.getFunctionBind);
+ // object polyfill
+ qx.core.Environment.add("ecmascript.object.keys", statics.getObjectKeys);
+ // string polyfill
+ qx.core.Environment.add("ecmascript.string.trim", statics.getStringTrim);
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2011 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (wittemann)
+
+************************************************************************ */
+/**
+ * This class takes care of the normalization of the native 'Array' object.
+ * Therefore it checks the availability of the following methods and appends
+ * it, if not available. This means you can use the methods during
+ * development in every browser. For usage samples, check out the attached links.
+ *
+ * *indexOf*:
+ * MDN documentation |
+ * Annotated ES5 Spec
+ *
+ * *lastIndexOf*:
+ * MDN documentation |
+ * Annotated ES5 Spec
+ *
+ * *forEach*:
+ * MDN documentation |
+ * Annotated ES5 Spec
+ *
+ * *filter*:
+ * MDN documentation |
+ * Annotated ES5 Spec
+ *
+ * *map*:
+ * MDN documentation |
+ * Annotated ES5 Spec
+ *
+ * *some*:
+ * MDN documentation |
+ * Annotated ES5 Spec
+ *
+ * *every*:
+ * MDN documentation |
+ * Annotated ES5 Spec
+ *
+ * *reduce*:
+ * MDN documentation |
+ * Annotated ES5 Spec
+ *
+ * *reduceRight*:
+ * MDN documentation |
+ * Annotated ES5 Spec
+ *
+ * Here is a little sample of how to use indexOf e.g.
+ * var a = ["a", "b", "c"];
+ * a.indexOf("b"); // returns 1
+ */
+qx.Bootstrap.define("qx.lang.normalize.Array", {
+ defer : function(){
+
+ // fix indexOf
+ if(!qx.core.Environment.get("ecmascript.array.indexof")){
+
+ Array.prototype.indexOf = function(searchElement, fromIndex){
+
+ if(fromIndex == null){
+
+ fromIndex = 0;
+ } else if(fromIndex < 0){
+
+ fromIndex = Math.max(0, this.length + fromIndex);
+ };
+ for(var i = fromIndex;i < this.length;i++){
+
+ if(this[i] === searchElement){
+
+ return i;
+ };
+ };
+ return -1;
+ };
+ };
+ // lastIndexOf
+ if(!qx.core.Environment.get("ecmascript.array.lastindexof")){
+
+ Array.prototype.lastIndexOf = function(searchElement, fromIndex){
+
+ if(fromIndex == null){
+
+ fromIndex = this.length - 1;
+ } else if(fromIndex < 0){
+
+ fromIndex = Math.max(0, this.length + fromIndex);
+ };
+ for(var i = fromIndex;i >= 0;i--){
+
+ if(this[i] === searchElement){
+
+ return i;
+ };
+ };
+ return -1;
+ };
+ };
+ // forEach
+ if(!qx.core.Environment.get("ecmascript.array.foreach")){
+
+ Array.prototype.forEach = function(callback, obj){
+
+ var l = this.length;
+ for(var i = 0;i < l;i++){
+
+ var value = this[i];
+ if(value !== undefined){
+
+ callback.call(obj || window, value, i, this);
+ };
+ };
+ };
+ };
+ // filter
+ if(!qx.core.Environment.get("ecmascript.array.filter")){
+
+ Array.prototype.filter = function(callback, obj){
+
+ var res = [];
+ var l = this.length;
+ for(var i = 0;i < l;i++){
+
+ var value = this[i];
+ if(value !== undefined){
+
+ if(callback.call(obj || window, value, i, this)){
+
+ res.push(this[i]);
+ };
+ };
+ };
+ return res;
+ };
+ };
+ // map
+ if(!qx.core.Environment.get("ecmascript.array.map")){
+
+ Array.prototype.map = function(callback, obj){
+
+ var res = [];
+ var l = this.length;
+ for(var i = 0;i < l;i++){
+
+ var value = this[i];
+ if(value !== undefined){
+
+ res[i] = callback.call(obj || window, value, i, this);
+ };
+ };
+ return res;
+ };
+ };
+ // some
+ if(!qx.core.Environment.get("ecmascript.array.some")){
+
+ Array.prototype.some = function(callback, obj){
+
+ var l = this.length;
+ for(var i = 0;i < l;i++){
+
+ var value = this[i];
+ if(value !== undefined){
+
+ if(callback.call(obj || window, value, i, this)){
+
+ return true;
+ };
+ };
+ };
+ return false;
+ };
+ };
+ // every
+ if(!qx.core.Environment.get("ecmascript.array.every")){
+
+ Array.prototype.every = function(callback, obj){
+
+ var l = this.length;
+ for(var i = 0;i < l;i++){
+
+ var value = this[i];
+ if(value !== undefined){
+
+ if(!callback.call(obj || window, value, i, this)){
+
+ return false;
+ };
+ };
+ };
+ return true;
+ };
+ };
+ // reduce
+ if(!qx.core.Environment.get("ecmascript.array.reduce")){
+
+ Array.prototype.reduce = function(callback, init){
+
+ if(typeof callback !== "function"){
+
+ throw new TypeError("First argument is not callable");
+ };
+ if(init === undefined && this.length === 0){
+
+ throw new TypeError("Length is 0 and no second argument given");
+ };
+ var ret = init === undefined ? this[0] : init;
+ for(var i = init === undefined ? 1 : 0;i < this.length;i++){
+
+ if(i in this){
+
+ ret = callback.call(undefined, ret, this[i], i, this);
+ };
+ };
+ return ret;
+ };
+ };
+ // reduceRight
+ if(!qx.core.Environment.get("ecmascript.array.reduceright")){
+
+ Array.prototype.reduceRight = function(callback, init){
+
+ if(typeof callback !== "function"){
+
+ throw new TypeError("First argument is not callable");
+ };
+ if(init === undefined && this.length === 0){
+
+ throw new TypeError("Length is 0 and no second argument given");
+ };
+ var ret = init === undefined ? this[this.length - 1] : init;
+ for(var i = init === undefined ? this.length - 2 : this.length - 1;i >= 0;i--){
+
+ if(i in this){
+
+ ret = callback.call(undefined, ret, this[i], i, this);
+ };
+ };
+ return ret;
+ };
+ };
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2007-2009 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Sebastian Werner (wpbasti)
+ * Fabian Jakobs (fjakobs)
+
+ ======================================================================
+
+ This class uses ideas and code snipplets presented at
+ http://webreflection.blogspot.com/2008/05/habemus-array-unlocked-length-in-ie8.html
+ http://webreflection.blogspot.com/2008/05/stack-and-arrayobject-how-to-create.html
+
+ Author:
+ Andrea Giammarchi
+
+ License:
+ MIT: http://www.opensource.org/licenses/mit-license.php
+
+ ======================================================================
+
+ This class uses documentation of the native Array methods from the MDC
+ documentation of Mozilla.
+
+ License:
+ CC Attribution-Sharealike License:
+ http://creativecommons.org/licenses/by-sa/2.5/
+
+************************************************************************ */
+/* ************************************************************************
+
+#require(qx.bom.client.Engine)
+#require(qx.lang.normalize.Array)
+
+************************************************************************ */
+/**
+ * This class is the common superclass for most array classes in
+ * qooxdoo. It supports all of the shiny 1.6 JavaScript array features
+ * like forEach and map.
+ *
+ * This class may be instantiated instead of the native Array if
+ * one wants to work with a feature-unified Array instead of the native
+ * one. This class uses native features whereever possible but fills
+ * all missing implementations with custom ones.
+ *
+ * Through the ability to extend from this class one could add even
+ * more utility features on top of it.
+ */
+qx.Bootstrap.define("qx.type.BaseArray", {
+ extend : Array,
+ /*
+ *****************************************************************************
+ CONSTRUCTOR
+ *****************************************************************************
+ */
+ /**
+ * Creates a new Array with the given length or the listed elements.
+ *
+ * + * var arr1 = new qx.type.BaseArray(arrayLength); + * var arr2 = new qx.type.BaseArray(item0, item1, ..., itemN); + *+ * + * *
arrayLength: The initial length of the array. You can access
+ * this value using the length property. If the value specified is not a
+ * number, an array of length 1 is created, with the first element having
+ * the specified value. The maximum length allowed for an
+ * array is 2^32-1, i.e. 4,294,967,295.
+ * * itemN: A value for the element in that position in the
+ * array. When this form is used, the array is initialized with the specified
+ * values as its elements, and the array's length property is set to the
+ * number of arguments.
+ *
+ * @param length_or_items {Integer|var?null} The initial length of the array
+ * OR an argument list of values.
+ */
+ construct : function(length_or_items){
+ },
+ /*
+ *****************************************************************************
+ MEMBERS
+ *****************************************************************************
+ */
+ members : {
+ /**
+ * Converts a base array to a native Array
+ *
+ * @signature function()
+ * @return {Array} The native array
+ */
+ toArray : null,
+ /**
+ * Returns the current number of items stored in the Array
+ *
+ * @signature function()
+ * @return {Integer} number of items
+ */
+ valueOf : null,
+ /**
+ * Removes the last element from an array and returns that element.
+ *
+ * This method modifies the array.
+ *
+ * @signature function()
+ * @return {var} The last element of the array.
+ */
+ pop : null,
+ /**
+ * Adds one or more elements to the end of an array and returns the new length of the array.
+ *
+ * This method modifies the array.
+ *
+ * @signature function(varargs)
+ * @param varargs {var} The elements to add to the end of the array.
+ * @return {Integer} The new array's length
+ */
+ push : null,
+ /**
+ * Reverses the order of the elements of an array -- the first becomes the last, and the last becomes the first.
+ *
+ * This method modifies the array.
+ *
+ * @signature function()
+ * @return {Array} Returns the modified array (works in place)
+ */
+ reverse : null,
+ /**
+ * Removes the first element from an array and returns that element.
+ *
+ * This method modifies the array.
+ *
+ * @signature function()
+ * @return {var} The first element of the array.
+ */
+ shift : null,
+ /**
+ * Sorts the elements of an array.
+ *
+ * This method modifies the array.
+ *
+ * @signature function(compareFunction)
+ * @param compareFunction {Function?null} Specifies a function that defines the sort order. If omitted,
+ * the array is sorted lexicographically (in dictionary order) according to the string conversion of each element.
+ * @return {Array} Returns the modified array (works in place)
+ */
+ sort : null,
+ /**
+ * Adds and/or removes elements from an array.
+ *
+ * @signature function(index, howMany, varargs)
+ * @param index {Integer} Index at which to start changing the array. If negative, will begin
+ * that many elements from the end.
+ * @param howMany {Integer} An integer indicating the number of old array elements to remove.
+ * If howMany is 0, no elements are removed. In this case, you should specify
+ * at least one new element.
+ * @param varargs {var?null} The elements to add to the array. If you don't specify any elements,
+ * splice simply removes elements from the array.
+ * @return {BaseArray} New array with the removed elements.
+ */
+ splice : null,
+ /**
+ * Adds one or more elements to the front of an array and returns the new length of the array.
+ *
+ * This method modifies the array.
+ *
+ * @signature function(varargs)
+ * @param varargs {var} The elements to add to the front of the array.
+ * @return {Integer} The new array's length
+ */
+ unshift : null,
+ /**
+ * Returns a new array comprised of this array joined with other array(s) and/or value(s).
+ *
+ * This method does not modify the array and returns a modified copy of the original.
+ *
+ * @signature function(varargs)
+ * @param varargs {Array|var} Arrays and/or values to concatenate to the resulting array.
+ * @return {qx.type.BaseArray} New array built of the given arrays or values.
+ */
+ concat : null,
+ /**
+ * Joins all elements of an array into a string.
+ *
+ * @signature function(separator)
+ * @param separator {String} Specifies a string to separate each element of the array. The separator is
+ * converted to a string if necessary. If omitted, the array elements are separated with a comma.
+ * @return {String} The stringified values of all elements divided by the given separator.
+ */
+ join : null,
+ /**
+ * Extracts a section of an array and returns a new array.
+ *
+ * @signature function(begin, end)
+ * @param begin {Integer} Zero-based index at which to begin extraction. As a negative index, start indicates
+ * an offset from the end of the sequence. slice(-2) extracts the second-to-last element and the last element
+ * in the sequence.
+ * @param end {Integer?length} Zero-based index at which to end extraction. slice extracts up to but not including end.
+ * slice(1,4) extracts the second element through the fourth element (elements indexed 1, 2, and 3).
+ * As a negative index, end indicates an offset from the end of the sequence. slice(2,-1) extracts the third element through the second-to-last element in the sequence.
+ * If end is omitted, slice extracts to the end of the sequence.
+ * @return {BaseArray} An new array which contains a copy of the given region.
+ */
+ slice : null,
+ /**
+ * Returns a string representing the array and its elements. Overrides the Object.prototype.toString method.
+ *
+ * @signature function()
+ * @return {String} The string representation of the array.
+ */
+ toString : null,
+ /**
+ * Returns the first (least) index of an element within the array equal to the specified value, or -1 if none is found.
+ *
+ * @signature function(searchElement, fromIndex)
+ * @param searchElement {var} Element to locate in the array.
+ * @param fromIndex {Integer?0} The index at which to begin the search. Defaults to 0, i.e. the
+ * whole array will be searched. If the index is greater than or equal to the length of the
+ * array, -1 is returned, i.e. the array will not be searched. If negative, it is taken as
+ * the offset from the end of the array. Note that even when the index is negative, the array
+ * is still searched from front to back. If the calculated index is less than 0, the whole
+ * array will be searched.
+ * @return {Integer} The index of the given element
+ */
+ indexOf : null,
+ /**
+ * Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found.
+ *
+ * @signature function(searchElement, fromIndex)
+ * @param searchElement {var} Element to locate in the array.
+ * @param fromIndex {Integer?length} The index at which to start searching backwards. Defaults to
+ * the array's length, i.e. the whole array will be searched. If the index is greater than
+ * or equal to the length of the array, the whole array will be searched. If negative, it
+ * is taken as the offset from the end of the array. Note that even when the index is
+ * negative, the array is still searched from back to front. If the calculated index is
+ * less than 0, -1 is returned, i.e. the array will not be searched.
+ * @return {Integer} The index of the given element
+ */
+ lastIndexOf : null,
+ /**
+ * Executes a provided function once per array element.
+ *
+ * forEach executes the provided function (callback) once for each
+ * element present in the array. callback is invoked only for indexes of the array
+ * which have assigned values; it is not invoked for indexes which have been deleted or which
+ * have never been assigned values.
+ *
+ * callback is invoked with three arguments: the value of the element, the index
+ * of the element, and the Array object being traversed.
+ *
+ * If a obj parameter is provided to forEach, it will be used
+ * as the this for each invocation of the callback. If it is not
+ * provided, or is null, the global object associated with callback
+ * is used instead.
+ *
+ * forEach does not mutate the array on which it is called.
+ *
+ * The range of elements processed by forEach is set before the first invocation of
+ * callback. Elements which are appended to the array after the call to
+ * forEach begins will not be visited by callback. If existing elements
+ * of the array are changed, or deleted, their value as passed to callback will be
+ * the value at the time forEach visits them; elements that are deleted are not visited.
+ *
+ * @signature function(callback, obj)
+ * @param callback {Function} Function to execute for each element.
+ * @param obj {Object} Object to use as this when executing callback.
+ */
+ forEach : null,
+ /**
+ * Creates a new array with all elements that pass the test implemented by the provided
+ * function.
+ *
+ * filter calls a provided callback function once for each
+ * element in an array, and constructs a new array of all the values for which
+ * callback returns a true value. callback is invoked only
+ * for indexes of the array which have assigned values; it is not invoked for indexes
+ * which have been deleted or which have never been assigned values. Array elements which
+ * do not pass the callback test are simply skipped, and are not included
+ * in the new array.
+ *
+ * callback is invoked with three arguments: the value of the element, the
+ * index of the element, and the Array object being traversed.
+ *
+ * If a obj parameter is provided to filter, it will
+ * be used as the this for each invocation of the callback.
+ * If it is not provided, or is null, the global object associated with
+ * callback is used instead.
+ *
+ * filter does not mutate the array on which it is called. The range of
+ * elements processed by filter is set before the first invocation of
+ * callback. Elements which are appended to the array after the call to
+ * filter begins will not be visited by callback. If existing
+ * elements of the array are changed, or deleted, their value as passed to callback
+ * will be the value at the time filter visits them; elements that are deleted
+ * are not visited.
+ *
+ * @signature function(callback, obj)
+ * @param callback {Function} Function to test each element of the array.
+ * @param obj {Object} Object to use as this when executing callback.
+ * @return {BaseArray} The newly created array with all matching elements
+ */
+ filter : null,
+ /**
+ * Creates a new array with the results of calling a provided function on every element in this array.
+ *
+ * map calls a provided callback function once for each element in an array,
+ * in order, and constructs a new array from the results. callback is invoked only for
+ * indexes of the array which have assigned values; it is not invoked for indexes which have been
+ * deleted or which have never been assigned values.
+ *
+ * callback is invoked with three arguments: the value of the element, the index of the
+ * element, and the Array object being traversed.
+ *
+ * If a obj parameter is provided to map, it will be used as the
+ * this for each invocation of the callback. If it is not provided, or is
+ * null, the global object associated with callback is used instead.
+ *
+ * map does not mutate the array on which it is called.
+ *
+ * The range of elements processed by map is set before the first invocation of
+ * callback. Elements which are appended to the array after the call to map
+ * begins will not be visited by callback. If existing elements of the array are changed,
+ * or deleted, their value as passed to callback will be the value at the time
+ * map visits them; elements that are deleted are not visited.
+ *
+ * @signature function(callback, obj)
+ * @param callback {Function} Function produce an element of the new Array from an element of the current one.
+ * @param obj {Object} Object to use as this when executing callback.
+ * @return {BaseArray} A new array which contains the return values of every item executed through the given function
+ */
+ map : null,
+ /**
+ * Tests whether some element in the array passes the test implemented by the provided function.
+ *
+ * some executes the callback function once for each element present in
+ * the array until it finds one where callback returns a true value. If such an element
+ * is found, some immediately returns true. Otherwise, some
+ * returns false. callback is invoked only for indexes of the array which
+ * have assigned values; it is not invoked for indexes which have been deleted or which have never
+ * been assigned values.
+ *
+ * callback is invoked with three arguments: the value of the element, the index of the
+ * element, and the Array object being traversed.
+ *
+ * If a obj parameter is provided to some, it will be used as the
+ * this for each invocation of the callback. If it is not provided, or is
+ * null, the global object associated with callback is used instead.
+ *
+ * some does not mutate the array on which it is called.
+ *
+ * The range of elements processed by some is set before the first invocation of
+ * callback. Elements that are appended to the array after the call to some
+ * begins will not be visited by callback. If an existing, unvisited element of the array
+ * is changed by callback, its value passed to the visiting callback will
+ * be the value at the time that some visits that element's index; elements that are
+ * deleted are not visited.
+ *
+ * @signature function(callback, obj)
+ * @param callback {Function} Function to test for each element.
+ * @param obj {Object} Object to use as this when executing callback.
+ * @return {Boolean} Whether at least one elements passed the test
+ */
+ some : null,
+ /**
+ * Tests whether all elements in the array pass the test implemented by the provided function.
+ *
+ * every executes the provided callback function once for each element
+ * present in the array until it finds one where callback returns a false value. If
+ * such an element is found, the every method immediately returns false.
+ * Otherwise, if callback returned a true value for all elements, every
+ * will return true. callback is invoked only for indexes of the array
+ * which have assigned values; it is not invoked for indexes which have been deleted or which have
+ * never been assigned values.
+ *
+ * callback is invoked with three arguments: the value of the element, the index of
+ * the element, and the Array object being traversed.
+ *
+ * If a obj parameter is provided to every, it will be used as
+ * the this for each invocation of the callback. If it is not provided,
+ * or is null, the global object associated with callback is used instead.
+ *
+ * every does not mutate the array on which it is called. The range of elements processed
+ * by every is set before the first invocation of callback. Elements which
+ * are appended to the array after the call to every begins will not be visited by
+ * callback. If existing elements of the array are changed, their value as passed
+ * to callback will be the value at the time every visits them; elements
+ * that are deleted are not visited.
+ *
+ * @signature function(callback, obj)
+ * @param callback {Function} Function to test for each element.
+ * @param obj {Object} Object to use as this when executing callback.
+ * @return {Boolean} Whether all elements passed the test
+ */
+ every : null
+ }
+});
+(function(){
+
+ function createStackConstructor(stack){
+
+ // In IE don't inherit from Array but use an empty object as prototype
+ // and copy the methods from Array
+ if((qx.core.Environment.get("engine.name") == "mshtml")){
+
+ Stack.prototype = {
+ length : 0,
+ $$isArray : true
+ };
+ var args = "pop.push.reverse.shift.sort.splice.unshift.join.slice".split(".");
+ for(var length = args.length;length;){
+
+ Stack.prototype[args[--length]] = Array.prototype[args[length]];
+ };
+ };
+ // Remember Array's slice method
+ var slice = Array.prototype.slice;
+ // Fix "concat" method
+ Stack.prototype.concat = function(){
+
+ var constructor = this.slice(0);
+ for(var i = 0,length = arguments.length;i < length;i++){
+
+ var copy;
+ if(arguments[i] instanceof Stack){
+
+ copy = slice.call(arguments[i], 0);
+ } else if(arguments[i] instanceof Array){
+
+ copy = arguments[i];
+ } else {
+
+ copy = [arguments[i]];
+ };
+ constructor.push.apply(constructor, copy);
+ };
+ return constructor;
+ };
+ // Fix "toString" method
+ Stack.prototype.toString = function(){
+
+ return slice.call(this, 0).toString();
+ };
+ // Fix "toLocaleString"
+ Stack.prototype.toLocaleString = function(){
+
+ return slice.call(this, 0).toLocaleString();
+ };
+ // Fix constructor
+ Stack.prototype.constructor = Stack;
+ // Add JS 1.6 Array features
+ Stack.prototype.indexOf = Array.prototype.indexOf;
+ Stack.prototype.lastIndexOf = Array.prototype.lastIndexOf;
+ Stack.prototype.forEach = Array.prototype.forEach;
+ Stack.prototype.some = Array.prototype.some;
+ Stack.prototype.every = Array.prototype.every;
+ var filter = Array.prototype.filter;
+ var map = Array.prototype.map;
+ // Fix methods which generates a new instance
+ // to return an instance of the same class
+ Stack.prototype.filter = function(){
+
+ var ret = new this.constructor;
+ ret.push.apply(ret, filter.apply(this, arguments));
+ return ret;
+ };
+ Stack.prototype.map = function(){
+
+ var ret = new this.constructor;
+ ret.push.apply(ret, map.apply(this, arguments));
+ return ret;
+ };
+ Stack.prototype.slice = function(){
+
+ var ret = new this.constructor;
+ ret.push.apply(ret, Array.prototype.slice.apply(this, arguments));
+ return ret;
+ };
+ Stack.prototype.splice = function(){
+
+ var ret = new this.constructor;
+ ret.push.apply(ret, Array.prototype.splice.apply(this, arguments));
+ return ret;
+ };
+ // Add new "toArray" method for convert a base array to a native Array
+ Stack.prototype.toArray = function(){
+
+ return Array.prototype.slice.call(this, 0);
+ };
+ // Add valueOf() to return the length
+ Stack.prototype.valueOf = function(){
+
+ return this.length;
+ };
+ // Return final class
+ return Stack;
+ };
+ function Stack(length){
+
+ if(arguments.length === 1 && typeof length === "number"){
+
+ this.length = -1 < length && length === length >> .5 ? length : this.push(length);
+ } else if(arguments.length){
+
+ this.push.apply(this, arguments);
+ };
+ };
+ function PseudoArray(){
+ };
+ PseudoArray.prototype = [];
+ Stack.prototype = new PseudoArray;
+ Stack.prototype.length = 0;
+ qx.type.BaseArray = createStackConstructor(Stack);
+})();
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2012 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (wittemann)
+
+************************************************************************ */
+/* ************************************************************************
+#ignore(q)
+************************************************************************ */
+/**
+ * The Core module's responsibility is to query the DOM for elements and offer
+ * these elements as a collection. The Core module itself does not offer any methods to
+ * work with the collection. These methods are added by the other included modules,
+ * such as Manipulating or Attributes.
+ *
+ * Core also provides the plugin API which allows modules to attach either
+ * static functions to the global q object or define methods on the
+ * collection it returns.
+ *
+ * By default, the core module is assigned to a global module named q.
+ * In case q is already defined, the name qxWeb
+ * is used instead.
+ *
+ * For further details, take a look at the documentation in the
+ * user manual.
+ */
+qx.Bootstrap.define("qxWeb", {
+ extend : qx.type.BaseArray,
+ statics : {
+ // internal storage for all initializers
+ __init : [],
+ // internal reference to the used qx namespace
+ $$qx : qx,
+ /**
+ * Internal helper to initialize collections.
+ *
+ * @param arg {var} An array of Elements which will
+ * be initialized as {@link q}. All items in the array which are not
+ * either a window object or a node object will be ignored.
+ * @return {q} A new initialized collection.
+ */
+ $init : function(arg){
+
+ var clean = [];
+ for(var i = 0;i < arg.length;i++){
+
+ var isNode = !!(arg[i] && arg[i].nodeType != null);
+ if(isNode){
+
+ clean.push(arg[i]);
+ continue;
+ };
+ var isWindow = !!(arg[i] && arg[i].history && arg[i].location && arg[i].document);
+ if(isWindow){
+
+ clean.push(arg[i]);
+ };
+ };
+ // check for node or window object
+ var col = qx.lang.Array.cast(clean, qxWeb);
+ for(var i = 0;i < qxWeb.__init.length;i++){
+
+ qxWeb.__init[i].call(col);
+ };
+ return col;
+ },
+ /**
+ * This is an API for module development and can be used to attach new methods
+ * to {@link q}.
+ *
+ * @param module {Map} A map containing the methods to attach.
+ */
+ $attach : function(module){
+
+ for(var name in module){
+
+ {
+ };
+ qxWeb.prototype[name] = module[name];
+ };
+ },
+ /**
+ * This is an API for module development and can be used to attach new methods
+ * to {@link q}.
+ *
+ * @param module {Map} A map containing the methods to attach.
+ */
+ $attachStatic : function(module){
+
+ for(var name in module){
+
+ {
+ };
+ qxWeb[name] = module[name];
+ };
+ },
+ /**
+ * This is an API for module development and can be used to attach new initialization
+ * methods to {@link q} which will be called when a new collection is
+ * created.
+ *
+ * @param init {Function} The initialization method for a module.
+ */
+ $attachInit : function(init){
+
+ this.__init.push(init);
+ },
+ /**
+ * Define a new class using the qooxdoo class system.
+ *
+ * @signature function(name, config)
+ * @param name {String?} Name of the class. If null, the class will not be
+ * attached to a namespace.
+ * @param config {Map} Class definition structure.
+ * @return {Function} The defined class.
+ */
+ define : function(name, config){
+
+ if(config == undefined){
+
+ config = name;
+ name = null;
+ };
+ return qx.Bootstrap.define.call(qx.Bootstrap, name, config);
+ }
+ },
+ /**
+ * Accepts a selector string and returns a set of found items. The optional context
+ * element can be used to reduce the amount of found elements to children of the
+ * context element.
+ *
+ * Sizzle is used as selector engine.
+ * Check out the documentation
+ * for more details.
+ *
+ * @param selector {String|Element|Array} Valid selector (CSS3 + extensions)
+ * or DOM element or Array of DOM Elements.
+ * @param context {Element} Only the children of this element are considered.
+ * @return {q} A collection of DOM elements.
+ */
+ construct : function(selector, context){
+
+ if(!selector && this instanceof qxWeb){
+
+ return this;
+ };
+ if(qx.Bootstrap.isString(selector)){
+
+ selector = qx.bom.Selector.query(selector, context);
+ } else if(!(qx.Bootstrap.isArray(selector))){
+
+ selector = [selector];
+ };
+ return qxWeb.$init(selector);
+ },
+ members : {
+ /**
+ * Gets a new collection containing only those elements that passed the
+ * given filter. This can be either a selector expression or a filter
+ * function.
+ *
+ * @param selector {String|Function} Selector expression or filter function
+ * @return {q} New collection containing the elements that passed the filter
+ */
+ filter : function(selector){
+
+ if(qx.lang.Type.isFunction(selector)){
+
+ return qxWeb.$init(Array.prototype.filter.call(this, selector));
+ };
+ return qxWeb.$init(qx.bom.Selector.matches(selector, this));
+ },
+ /**
+ * Returns a copy of the collection within the given range.
+ *
+ * @param begin {Number} The index to begin.
+ * @param end {Number?} The index to end.
+ * @return {q} A new collection containing a slice of the original collection.
+ */
+ slice : function(begin, end){
+
+ // Old IEs return an empty array if the second argument is undefined
+ if(end){
+
+ return qxWeb.$init(Array.prototype.slice.call(this, begin, end));
+ } else {
+
+ return qxWeb.$init(Array.prototype.slice.call(this, begin));
+ };
+ },
+ /**
+ * Removes the given number of items and returns the removed items as a new collection.
+ * This method can also add items. Take a look at the
+ * documentation of MDN for more details.
+ *
+ * @param index {Number} The index to begin.
+ * @param howMany {Number} the amount of items to remove.
+ * @param varargs {var} As many items as you want to add.
+ * @return {q} A new collection containing the removed items.
+ */
+ splice : function(index, howMany, varargs){
+
+ return qxWeb.$init(Array.prototype.splice.apply(this, arguments));
+ },
+ /**
+ * Returns a new collection containing the modified elements. For more details, check out the
+ * MDN documentation.
+ *
+ * @param callback {Function} Function which produces the new element.
+ * @param thisarg {var} Context of the callback.
+ * @return {q} New collection containing the elements that passed the filter
+ */
+ map : function(callback, thisarg){
+
+ return qxWeb.$init(Array.prototype.map.apply(this, arguments));
+ },
+ /**
+ * Returns a copy of the collection including the given elements.
+ *
+ * @param varargs {var} As many items as you want to add.
+ * @return {q} A new collection containing all items.
+ */
+ concat : function(varargs){
+
+ var clone = Array.prototype.slice.call(this, 0);
+ for(var i = 0;i < arguments.length;i++){
+
+ if(arguments[i] instanceof qxWeb){
+
+ clone = clone.concat(Array.prototype.slice.call(arguments[i], 0));
+ } else {
+
+ clone.push(arguments[i]);
+ };
+ };
+ return qxWeb.$init(clone);
+ }
+ },
+ /**
+ * @lint ignoreUndefined(q)
+ */
+ defer : function(statics){
+
+ if(window.q == undefined){
+
+ q = statics;
+ };
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2012 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (wittemann)
+
+************************************************************************ */
+/**
+ * This class takes care of the normalization of the native 'Date' object.
+ * Therefore it checks the availability of the following methods and appends
+ * it, if not available. This means you can use the methods during
+ * development in every browser. For usage samples, check out the attached links.
+ *
+ * *now*:
+ * MDN documentation |
+ * Annotated ES5 Spec
+ */
+qx.Bootstrap.define("qx.lang.normalize.Date", {
+ defer : function(){
+
+ // Date.now
+ if(!qx.core.Environment.get("ecmascript.date.now")){
+
+ Date.now = function(){
+
+ return +new Date();
+ };
+ };
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Sebastian Werner (wpbasti)
+ * Andreas Ecker (ecker)
+
+ ======================================================================
+
+ This class contains code based on the following work:
+
+ * jQuery
+ http://jquery.com
+ Version 1.3.1
+
+ Copyright:
+ 2009 John Resig
+
+ License:
+ MIT: http://www.opensource.org/licenses/mit-license.php
+
+************************************************************************ */
+/* ************************************************************************
+
+#ignore(qx.data.IListData)
+#ignore(qx.Class)
+#require(qx.lang.normalize.Date)
+
+************************************************************************ */
+/**
+ * Static helper functions for arrays with a lot of often used convenience
+ * methods like remove or contains.
+ *
+ * The native JavaScript Array is not modified by this class. However,
+ * there are modifications to the native Array in {@link qx.lang.normalize.Array} for
+ * browsers that do not support certain JavaScript features natively .
+ */
+qx.Bootstrap.define("qx.lang.Array", {
+ statics : {
+ /**
+ * Converts array like constructions like the argument object,
+ * node collections like the ones returned by getElementsByTagName
+ * or extended array objects like qx.type.BaseArray to an
+ * native Array instance.
+ *
+ * @deprecated {2.1} Please use cast with 'Array' as constructor.
+ * @param object {var} any array like object
+ * @param offset {Integer?0} position to start from
+ * @return {Array} New array with the content of the incoming object
+ */
+ toArray : function(object, offset){
+
+ {
+ };
+ return this.cast(object, Array, offset);
+ },
+ /**
+ * Converts an array like object to any other array like
+ * object.
+ *
+ * Attention: The returned array may be same
+ * instance as the incoming one if the constructor is identical!
+ *
+ * @param object {var} any array-like object
+ * @param constructor {Function} constructor of the new instance
+ * @param offset {Integer?0} position to start from
+ * @return {Array} the converted array
+ */
+ cast : function(object, constructor, offset){
+
+ if(object.constructor === constructor){
+
+ return object;
+ };
+ if(qx.data && qx.data.IListData){
+
+ if(qx.Class && qx.Class.hasInterface(object, qx.data.IListData)){
+
+ var object = object.toArray();
+ };
+ };
+ // Create from given constructor
+ var ret = new constructor;
+ // Some collections in mshtml are not able to be sliced.
+ // These lines are a special workaround for this client.
+ if((qx.core.Environment.get("engine.name") == "mshtml")){
+
+ if(object.item){
+
+ for(var i = offset || 0,l = object.length;i < l;i++){
+
+ ret.push(object[i]);
+ };
+ return ret;
+ };
+ };
+ // Copy over items
+ if(Object.prototype.toString.call(object) === "[object Array]" && offset == null){
+
+ ret.push.apply(ret, object);
+ } else {
+
+ ret.push.apply(ret, Array.prototype.slice.call(object, offset || 0));
+ };
+ return ret;
+ },
+ /**
+ * Convert an arguments object into an array.
+ *
+ * @param args {arguments} arguments object
+ * @param offset {Integer?0} position to start from
+ * @return {Array} a newly created array (copy) with the content of the arguments object.
+ */
+ fromArguments : function(args, offset){
+
+ return Array.prototype.slice.call(args, offset || 0);
+ },
+ /**
+ * Convert a (node) collection into an array
+ *
+ * @param coll {var} node collection
+ * @return {Array} a newly created array (copy) with the content of the node collection.
+ */
+ fromCollection : function(coll){
+
+ // The native Array.slice cannot be used with some Array-like objects
+ // including NodeLists in older IEs
+ if((qx.core.Environment.get("engine.name") == "mshtml")){
+
+ if(coll.item){
+
+ var arr = [];
+ for(var i = 0,l = coll.length;i < l;i++){
+
+ arr[i] = coll[i];
+ };
+ return arr;
+ };
+ };
+ return Array.prototype.slice.call(coll, 0);
+ },
+ /**
+ * Expand shorthand definition to a four element list.
+ * This is an utility function for padding/margin and all other shorthand handling.
+ *
+ * @param input {Array} arr with one to four elements
+ * @return {Array} an arr with four elements
+ */
+ fromShortHand : function(input){
+
+ var len = input.length;
+ var result = qx.lang.Array.clone(input);
+ // Copy Values (according to the length)
+ switch(len){case 1:
+ result[1] = result[2] = result[3] = result[0];
+ break;case 2:
+ result[2] = result[0];// no break here
+ case 3:
+ result[3] = result[1];};
+ // Return list with 4 items
+ return result;
+ },
+ /**
+ * Return a copy of the given array
+ *
+ * @param arr {Array} the array to copy
+ * @return {Array} copy of the array
+ */
+ clone : function(arr){
+
+ return arr.concat();
+ },
+ /**
+ * Insert an element at a given position into the array
+ *
+ * @param arr {Array} the array
+ * @param obj {var} the element to insert
+ * @param i {Integer} position where to insert the element into the array
+ * @return {Array} the array
+ */
+ insertAt : function(arr, obj, i){
+
+ arr.splice(i, 0, obj);
+ return arr;
+ },
+ /**
+ * Insert an element into the array before a given second element.
+ *
+ * @param arr {Array} the array
+ * @param obj {var} object to be inserted
+ * @param obj2 {var} insert obj1 before this object
+ * @return {Array} the array
+ */
+ insertBefore : function(arr, obj, obj2){
+
+ var i = arr.indexOf(obj2);
+ if(i == -1){
+
+ arr.push(obj);
+ } else {
+
+ arr.splice(i, 0, obj);
+ };
+ return arr;
+ },
+ /**
+ * Insert an element into the array after a given second element.
+ *
+ * @param arr {Array} the array
+ * @param obj {var} object to be inserted
+ * @param obj2 {var} insert obj1 after this object
+ * @return {Array} the array
+ */
+ insertAfter : function(arr, obj, obj2){
+
+ var i = arr.indexOf(obj2);
+ if(i == -1 || i == (arr.length - 1)){
+
+ arr.push(obj);
+ } else {
+
+ arr.splice(i + 1, 0, obj);
+ };
+ return arr;
+ },
+ /**
+ * Remove an element from the array at the given index
+ *
+ * @param arr {Array} the array
+ * @param i {Integer} index of the element to be removed
+ * @return {var} The removed element.
+ */
+ removeAt : function(arr, i){
+
+ return arr.splice(i, 1)[0];
+ },
+ /**
+ * Remove all elements from the array
+ *
+ * @param arr {Array} the array
+ * @return {Array} empty array
+ */
+ removeAll : function(arr){
+
+ arr.length = 0;
+ return this;
+ },
+ /**
+ * Append the elements of an array to the array
+ *
+ * @param arr1 {Array} the array
+ * @param arr2 {Array} the elements of this array will be appended to other one
+ * @return {Array} The modified array.
+ * @throws {Error} if one of the arguments is not an array
+ */
+ append : function(arr1, arr2){
+
+ {
+ };
+ Array.prototype.push.apply(arr1, arr2);
+ return arr1;
+ },
+ /**
+ * Modifies the first array as it removes all elements
+ * which are listed in the second array as well.
+ *
+ * @param arr1 {Array} the array
+ * @param arr2 {Array} the elements of this array will be excluded from the other one
+ * @return {Array} The modified array.
+ * @throws {Error} if one of the arguments is not an array
+ */
+ exclude : function(arr1, arr2){
+
+ {
+ };
+ for(var i = 0,il = arr2.length,index;i < il;i++){
+
+ index = arr1.indexOf(arr2[i]);
+ if(index != -1){
+
+ arr1.splice(index, 1);
+ };
+ };
+ return arr1;
+ },
+ /**
+ * Remove an element from the array.
+ *
+ * @param arr {Array} the array
+ * @param obj {var} element to be removed from the array
+ * @return {var} the removed element
+ */
+ remove : function(arr, obj){
+
+ var i = arr.indexOf(obj);
+ if(i != -1){
+
+ arr.splice(i, 1);
+ return obj;
+ };
+ },
+ /**
+ * Whether the array contains the given element
+ *
+ * @param arr {Array} the array
+ * @param obj {var} object to look for
+ * @return {Boolean} whether the arr contains the element
+ */
+ contains : function(arr, obj){
+
+ return arr.indexOf(obj) !== -1;
+ },
+ /**
+ * Check whether the two arrays have the same content. Checks only the
+ * equality of the arrays' content.
+ *
+ * @param arr1 {Array} first array
+ * @param arr2 {Array} second array
+ * @return {Boolean} Whether the two arrays are equal
+ */
+ equals : function(arr1, arr2){
+
+ var length = arr1.length;
+ if(length !== arr2.length){
+
+ return false;
+ };
+ for(var i = 0;i < length;i++){
+
+ if(arr1[i] !== arr2[i]){
+
+ return false;
+ };
+ };
+ return true;
+ },
+ /**
+ * Returns the sum of all values in the given array. Supports
+ * numeric values only.
+ *
+ * @param arr {Number[]} Array to process
+ * @return {Number} The sum of all values.
+ */
+ sum : function(arr){
+
+ var result = 0;
+ for(var i = 0,l = arr.length;i < l;i++){
+
+ result += arr[i];
+ };
+ return result;
+ },
+ /**
+ * Returns the highest value in the given array. Supports
+ * numeric values only.
+ *
+ * @param arr {Number[]} Array to process
+ * @return {Number | null} The highest of all values or undefined if array is empty.
+ */
+ max : function(arr){
+
+ {
+ };
+ var i,len = arr.length,result = arr[0];
+ for(i = 1;i < len;i++){
+
+ if(arr[i] > result){
+
+ result = arr[i];
+ };
+ };
+ return result === undefined ? null : result;
+ },
+ /**
+ * Returns the lowest value in the given array. Supports
+ * numeric values only.
+ *
+ * @param arr {Number[]} Array to process
+ * @return {Number | null} The lowest of all values or undefined if array is empty.
+ */
+ min : function(arr){
+
+ {
+ };
+ var i,len = arr.length,result = arr[0];
+ for(i = 1;i < len;i++){
+
+ if(arr[i] < result){
+
+ result = arr[i];
+ };
+ };
+ return result === undefined ? null : result;
+ },
+ /**
+ * Recreates an array which is free of all duplicate elements from the original.
+ *
+ * This method do not modifies the original array!
+ *
+ * Keep in mind that this methods deletes undefined indexes.
+ *
+ * @param arr {Array} Incoming array
+ * @return {Array} Returns a copy with no duplicates or the original array if no duplicates were found
+ */
+ unique : function(arr){
+
+ var ret = [],doneStrings = {
+ },doneNumbers = {
+ },doneObjects = {
+ };
+ var value,count = 0;
+ var key = "qx" + Date.now();
+ var hasNull = false,hasFalse = false,hasTrue = false;
+ // Rebuild array and omit duplicates
+ for(var i = 0,len = arr.length;i < len;i++){
+
+ value = arr[i];
+ // Differ between null, primitives and reference types
+ if(value === null){
+
+ if(!hasNull){
+
+ hasNull = true;
+ ret.push(value);
+ };
+ } else if(value === undefined){
+ } else if(value === false){
+
+ if(!hasFalse){
+
+ hasFalse = true;
+ ret.push(value);
+ };
+ } else if(value === true){
+
+ if(!hasTrue){
+
+ hasTrue = true;
+ ret.push(value);
+ };
+ } else if(typeof value === "string"){
+
+ if(!doneStrings[value]){
+
+ doneStrings[value] = 1;
+ ret.push(value);
+ };
+ } else if(typeof value === "number"){
+
+ if(!doneNumbers[value]){
+
+ doneNumbers[value] = 1;
+ ret.push(value);
+ };
+ } else {
+
+ var hash = value[key];
+ if(hash == null){
+
+ hash = value[key] = count++;
+ };
+ if(!doneObjects[hash]){
+
+ doneObjects[hash] = value;
+ ret.push(value);
+ };
+ };;;;;
+ };
+ // Clear object hashs
+ for(var hash in doneObjects){
+
+ try{
+
+ // TODO: The following delete seems to fail in IE7
+ delete doneObjects[hash][key];
+ } catch(ex) {
+
+ try{
+
+ doneObjects[hash][key] = null;
+ } catch(ex1) {
+
+ throw new Error("Cannot clean-up map entry doneObjects[" + hash + "][" + key + "]");
+ };
+ };
+ };
+ return ret;
+ }
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2008-2010 Sebastian Werner, http://sebastian-werner.net
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Sebastian Werner (wpbasti)
+ * Fabian Jakobs (fjakobs)
+ * Andreas Ecker (ecker)
+
+ ======================================================================
+
+ This class contains code based on the following work:
+
+ * Sizzle CSS Selector Engine - v1.8.2
+
+ Homepage:
+ http://sizzlejs.com/
+
+ Documentation:
+ http://wiki.github.com/jeresig/sizzle
+
+ Discussion:
+ http://groups.google.com/group/sizzlejs
+
+ Code:
+ http://github.com/jeresig/sizzle/tree
+
+ Copyright:
+ (c) 2009, The Dojo Foundation
+
+ License:
+ MIT: http://www.opensource.org/licenses/mit-license.php
+
+ ----------------------------------------------------------------------
+
+ Copyright (c) 2009 John Resig
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+ ----------------------------------------------------------------------
+
+ Version:
+ Snapshot taken on 2012-10-02, latest Sizzle commit on 2012-09-20:
+ commit 41a7c2ce9be6c66e0c9b8b15e0a29c8e3ca6fb31
+
+************************************************************************ */
+/**
+ * The selector engine supports virtually all CSS 3 Selectors – this even
+ * includes some parts that are infrequently implemented such as escaped
+ * selectors (.foo\\+bar), Unicode selectors, and results returned
+ * in document order. There are a few notable exceptions to the CSS 3 selector
+ * support:
+ *
+ * * :root
+ * * :target
+ * * :nth-last-child
+ * * :nth-of-type
+ * * :nth-last-of-type
+ * * :first-of-type
+ * * :last-of-type
+ * * :only-of-type
+ * * :lang()
+ *
+ * In addition to the CSS 3 Selectors the engine supports the following
+ * additional selectors or conventions.
+ *
+ * *Changes*
+ *
+ * * :not(a.b): Supports non-simple selectors in :not() (most browsers only support :not(a), for example).
+ * * :not(div > p): Supports full selectors in :not().
+ * * :not(div, p): Supports multiple selectors in :not().
+ * * [NAME=VALUE]: Doesn't require quotes around the specified value in an attribute selector.
+ *
+ * *Additions*
+ *
+ * * [NAME!=VALUE]: Finds all elements whose NAME attribute doesn't match the specified value. Is equivalent to doing :not([NAME=VALUE]).
+ * * :contains(TEXT): Finds all elements whose textual context contains the word TEXT (case sensitive).
+ * * :header: Finds all elements that are a header element (h1, h2, h3, h4, h5, h6).
+ * * :parent: Finds all elements that contains another element.
+ *
+ * *Positional Selector Additions*
+ *
+ * * :first/:last: Finds the first or last matching element on the page. (e.g. div:first would find the first div on the page, in document order)
+ * * :even/:odd: Finds every other element on the page (counting begins at 0, so :even would match the first element).
+ * * :eq/:nth: Finds the Nth element on the page (e.g. :eq(5) finds the 6th element on the page).
+ * * :lt/:gt: Finds all elements at positions less than or greater than the specified positions.
+ *
+ * *Form Selector Additions*
+ *
+ * * :input: Finds all input elements (includes textareas, selects, and buttons).
+ * * :text, :checkbox, :file, :password, :submit, :image, :reset, :button: Finds the input element with the specified input type (:button also finds button elements).
+ *
+ * Based on Sizzle by John Resig, see:
+ *
+ * * http://sizzlejs.com/
+ *
+ * For further usage details also have a look at the wiki page at:
+ *
+ * * https://github.com/jquery/sizzle/wiki/Sizzle-Home
+ */
+qx.Bootstrap.define("qx.bom.Selector", {
+ statics : {
+ /**
+ * Queries the document for the given selector. Supports all CSS3 selectors
+ * plus some extensions as mentioned in the class description.
+ *
+ * @signature function(selector, context)
+ * @param selector {String} Valid selector (CSS3 + extensions)
+ * @param context {Element} Context element (result elements must be children of this element)
+ * @return {Array} Matching elements
+ */
+ query : null,
+ /**
+ * Returns an reduced array which only contains the elements from the given
+ * array which matches the given selector
+ *
+ * @signature function(selector, set)
+ * @param selector {String} Selector to filter given set
+ * @param set {Array} List to filter according to given selector
+ * @return {Array} New array containing matching elements
+ */
+ matches : null
+ }
+});
+/**
+ * Below is the original Sizzle code. Snapshot date is mentioned in the head of
+ * this file.
+ * @lint ignoreUnused(j, rnot, rendsWithNot)
+ */
+/*!
+ * Sizzle CSS Selector Engine
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://sizzlejs.com/
+ */
+(function(window, undefined){
+
+ var cachedruns,assertGetIdNotName,Expr,getText,isXML,contains,compile,sortOrder,hasDuplicate,outermostContext,baseHasDuplicate = true,strundefined = "undefined",expando = ("sizcache" + Math.random()).replace(".", ""),Token = String,document = window.document,docElem = document.documentElement,dirruns = 0,done = 0,pop = [].pop,push = [].push,slice = [].slice,// Use a stripped-down indexOf if a native one is unavailable
+ indexOf = [].indexOf || function(elem){
+
+ var i = 0,len = this.length;
+ for(;i < len;i++){
+
+ if(this[i] === elem){
+
+ return i;
+ };
+ };
+ return -1;
+ },// Augment a function for special use by Sizzle
+ markFunction = function(fn, value){
+
+ fn[expando] = value == null || value;
+ return fn;
+ },createCache = function(){
+
+ var cache = {
+ },keys = [];
+ return markFunction(function(key, value){
+
+ // Only keep the most recent entries
+ if(keys.push(key) > Expr.cacheLength){
+
+ delete cache[keys.shift()];
+ };
+ return (cache[key] = value);
+ }, cache);
+ },classCache = createCache(),tokenCache = createCache(),compilerCache = createCache(),// Regex
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",// http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",// Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors)
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace("w", "w#"),// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
+ operators = "([*^$|!~]?=)",attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",// Prefer arguments not in parens/brackets,
+ // then attribute selectors and non-pseudos (denoted by :),
+ // then anything else
+ // These preferences are here to reduce the number of selectors
+ // needing tokenize in the PSEUDO preFilter
+ pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)",// For matchExpr.POS and matchExpr.needsContext
+ pos = ":(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)",// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rtrim = new RegExp("^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g"),rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*"),rcombinators = new RegExp("^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*"),rpseudo = new RegExp(pseudos),// Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,rnot = /^:not/,rsibling = /[\x20\t\r\n\f]*[+~]/,rendsWithNot = /:not\($/,rheader = /h\d/i,rinputs = /input|select|textarea|button/i,rbackslash = /\\(?!\\)/g,matchExpr = {
+ "ID" : new RegExp("^#(" + characterEncoding + ")"),
+ "CLASS" : new RegExp("^\\.(" + characterEncoding + ")"),
+ "NAME" : new RegExp("^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]"),
+ "TAG" : new RegExp("^(" + characterEncoding.replace("w", "w*") + ")"),
+ "ATTR" : new RegExp("^" + attributes),
+ "PSEUDO" : new RegExp("^" + pseudos),
+ "POS" : new RegExp(pos, "i"),
+ "CHILD" : new RegExp("^:(only|nth|first|last)-child(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i"),
+ // For use in libraries implementing .is()
+ "needsContext" : new RegExp("^" + whitespace + "*[>+~]|" + pos, "i")
+ },// Support
+ // Used for testing something on an element
+ assert = function(fn){
+
+ var div = document.createElement("div");
+ try{
+
+ return fn(div);
+ } catch(e) {
+
+ return false;
+ }finally{
+
+ // release memory in IE
+ div = null;
+ };
+ },// Check if getElementsByTagName("*") returns only elements
+ assertTagNameNoComments = assert(function(div){
+
+ div.appendChild(document.createComment(""));
+ return !div.getElementsByTagName("*").length;
+ }),// Check if getAttribute returns normalized href attributes
+ assertHrefNotNormalized = assert(function(div){
+
+ div.innerHTML = "";
+ return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && div.firstChild.getAttribute("href") === "#";
+ }),// Check if attributes should be retrieved by attribute nodes
+ assertAttributes = assert(function(div){
+
+ div.innerHTML = "";
+ var type = typeof div.lastChild.getAttribute("multiple");
+ // IE8 returns a string for some attributes even when not present
+ return type !== "boolean" && type !== "string";
+ }),// Check if getElementsByClassName can be trusted
+ assertUsableClassName = assert(function(div){
+
+ // Opera can't find a second classname (in 9.6)
+ div.innerHTML = "";
+ if(!div.getElementsByClassName || !div.getElementsByClassName("e").length){
+
+ return false;
+ };
+ // Safari 3.2 caches class attributes and doesn't catch changes
+ div.lastChild.className = "e";
+ return div.getElementsByClassName("e").length === 2;
+ }),// Check if getElementById returns elements by name
+ // Check if getElementsByName privileges form controls or returns elements by ID
+ assertUsableName = assert(function(div){
+
+ // Inject content
+ div.id = expando + 0;
+ div.innerHTML = "";
+ docElem.insertBefore(div, docElem.firstChild);
+ // Test
+ var pass = document.getElementsByName && // buggy browsers will return fewer than the correct 2
+ document.getElementsByName(expando).length === 2 + // buggy browsers will return more than the correct 0
+ document.getElementsByName(expando + 0).length;
+ assertGetIdNotName = !document.getElementById(expando);
+ // Cleanup
+ docElem.removeChild(div);
+ return pass;
+ });
+ // If slice is not available, provide a backup
+ try{
+
+ slice.call(docElem.childNodes, 0)[0].nodeType;
+ } catch(e) {
+
+ slice = function(i){
+
+ var elem,results = [];
+ for(;(elem = this[i]);i++){
+
+ results.push(elem);
+ };
+ return results;
+ };
+ };
+ function Sizzle(selector, context, results, seed){
+
+ results = results || [];
+ context = context || document;
+ var match,elem,xml,m,nodeType = context.nodeType;
+ if(!selector || typeof selector !== "string"){
+
+ return results;
+ };
+ if(nodeType !== 1 && nodeType !== 9){
+
+ return [];
+ };
+ xml = isXML(context);
+ if(!xml && !seed){
+
+ if((match = rquickExpr.exec(selector))){
+
+ // Speed-up: Sizzle("#ID")
+ if((m = match[1])){
+
+ if(nodeType === 9){
+
+ elem = context.getElementById(m);
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if(elem && elem.parentNode){
+
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if(elem.id === m){
+
+ results.push(elem);
+ return results;
+ };
+ } else {
+
+ return results;
+ };
+ } else {
+
+ // Context is not a document
+ if(context.ownerDocument && (elem = context.ownerDocument.getElementById(m)) && contains(context, elem) && elem.id === m){
+
+ results.push(elem);
+ return results;
+ };
+ };
+ } else if(match[2]){
+
+ push.apply(results, slice.call(context.getElementsByTagName(selector), 0));
+ return results;
+ } else if((m = match[3]) && assertUsableClassName && context.getElementsByClassName){
+
+ push.apply(results, slice.call(context.getElementsByClassName(m), 0));
+ return results;
+ };;
+ };
+ };
+ // All others
+ return select(selector.replace(rtrim, "$1"), context, results, seed, xml);
+ };
+ Sizzle.matches = function(expr, elements){
+
+ return Sizzle(expr, null, null, elements);
+ };
+ Sizzle.matchesSelector = function(elem, expr){
+
+ return Sizzle(expr, null, null, [elem]).length > 0;
+ };
+ // Returns a function to use in pseudos for input types
+ function createInputPseudo(type){
+
+ return function(elem){
+
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+ };
+ // Returns a function to use in pseudos for buttons
+ function createButtonPseudo(type){
+
+ return function(elem){
+
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+ };
+ // Returns a function to use in pseudos for positionals
+ function createPositionalPseudo(fn){
+
+ return markFunction(function(argument){
+
+ argument = +argument;
+ return markFunction(function(seed, matches){
+
+ var j,matchIndexes = fn([], seed.length, argument),i = matchIndexes.length;
+ // Match elements found at the specified indexes
+ while(i--){
+
+ if(seed[(j = matchIndexes[i])]){
+
+ seed[j] = !(matches[j] = seed[j]);
+ };
+ };
+ });
+ });
+ };
+ /**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+ getText = Sizzle.getText = function(elem){
+
+ var node,ret = "",i = 0,nodeType = elem.nodeType;
+ if(nodeType){
+
+ if(nodeType === 1 || nodeType === 9 || nodeType === 11){
+
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (see #11153)
+ if(typeof elem.textContent === "string"){
+
+ return elem.textContent;
+ } else {
+
+ // Traverse its children
+ for(elem = elem.firstChild;elem;elem = elem.nextSibling){
+
+ ret += getText(elem);
+ };
+ };
+ } else if(nodeType === 3 || nodeType === 4){
+
+ return elem.nodeValue;
+ };
+ } else {
+
+ // If no nodeType, this is expected to be an array
+ for(;(node = elem[i]);i++){
+
+ // Do not traverse comment nodes
+ ret += getText(node);
+ };
+ };
+ return ret;
+ };
+ isXML = Sizzle.isXML = function(elem){
+
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+ };
+ // Element contains another
+ contains = Sizzle.contains = docElem.contains ? function(a, b){
+
+ var adown = a.nodeType === 9 ? a.documentElement : a,bup = b && b.parentNode;
+ return a === bup || !!(bup && bup.nodeType === 1 && adown.contains && adown.contains(bup));
+ } : docElem.compareDocumentPosition ? function(a, b){
+
+ return b && !!(a.compareDocumentPosition(b) & 16);
+ } : function(a, b){
+
+ while((b = b.parentNode)){
+
+ if(b === a){
+
+ return true;
+ };
+ };
+ return false;
+ };
+ Sizzle.attr = function(elem, name){
+
+ var val,xml = isXML(elem);
+ if(!xml){
+
+ name = name.toLowerCase();
+ };
+ if((val = Expr.attrHandle[name])){
+
+ return val(elem);
+ };
+ if(xml || assertAttributes){
+
+ return elem.getAttribute(name);
+ };
+ val = elem.getAttributeNode(name);
+ return val ? typeof elem[name] === "boolean" ? elem[name] ? name : null : val.specified ? val.value : null : null;
+ };
+ Expr = Sizzle.selectors = {
+ // Can be adjusted by the user
+ cacheLength : 50,
+ createPseudo : markFunction,
+ match : matchExpr,
+ // IE6/7 return a modified href
+ attrHandle : assertHrefNotNormalized ? {
+ } : {
+ "href" : function(elem){
+
+ return elem.getAttribute("href", 2);
+ },
+ "type" : function(elem){
+
+ return elem.getAttribute("type");
+ }
+ },
+ find : {
+ "ID" : assertGetIdNotName ? function(id, context, xml){
+
+ if(typeof context.getElementById !== strundefined && !xml){
+
+ var m = context.getElementById(id);
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ };
+ } : function(id, context, xml){
+
+ if(typeof context.getElementById !== strundefined && !xml){
+
+ var m = context.getElementById(id);
+ return m ? m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? [m] : undefined : [];
+ };
+ },
+ "TAG" : assertTagNameNoComments ? function(tag, context){
+
+ if(typeof context.getElementsByTagName !== strundefined){
+
+ return context.getElementsByTagName(tag);
+ };
+ } : function(tag, context){
+
+ var results = context.getElementsByTagName(tag);
+ // Filter out possible comments
+ if(tag === "*"){
+
+ var elem,tmp = [],i = 0;
+ for(;(elem = results[i]);i++){
+
+ if(elem.nodeType === 1){
+
+ tmp.push(elem);
+ };
+ };
+ return tmp;
+ };
+ return results;
+ },
+ "NAME" : assertUsableName && function(tag, context){
+
+ if(typeof context.getElementsByName !== strundefined){
+
+ return context.getElementsByName(name);
+ };
+ },
+ "CLASS" : assertUsableClassName && function(className, context, xml){
+
+ if(typeof context.getElementsByClassName !== strundefined && !xml){
+
+ return context.getElementsByClassName(className);
+ };
+ }
+ },
+ relative : {
+ ">" : {
+ dir : "parentNode",
+ first : true
+ },
+ " " : {
+ dir : "parentNode"
+ },
+ "+" : {
+ dir : "previousSibling",
+ first : true
+ },
+ "~" : {
+ dir : "previousSibling"
+ }
+ },
+ preFilter : {
+ "ATTR" : function(match){
+
+ match[1] = match[1].replace(rbackslash, "");
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = (match[4] || match[5] || "").replace(rbackslash, "");
+ if(match[2] === "~="){
+
+ match[3] = " " + match[3] + " ";
+ };
+ return match.slice(0, 4);
+ },
+ "CHILD" : function(match){
+
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 3 xn-component of xn+y argument ([+-]?\d*n|)
+ 4 sign of xn-component
+ 5 x of xn-component
+ 6 sign of y-component
+ 7 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+ if(match[1] === "nth"){
+
+ // nth-child requires argument
+ if(!match[2]){
+
+ Sizzle.error(match[0]);
+ };
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[3] = +(match[3] ? match[4] + (match[5] || 1) : 2 * (match[2] === "even" || match[2] === "odd"));
+ match[4] = +((match[6] + match[7]) || match[2] === "odd");
+ } else if(match[2]){
+
+ Sizzle.error(match[0]);
+ };
+ return match;
+ },
+ "PSEUDO" : function(match){
+
+ var unquoted,excess;
+ if(matchExpr["CHILD"].test(match[0])){
+
+ return null;
+ };
+ if(match[3]){
+
+ match[2] = match[3];
+ } else if((unquoted = match[4])){
+
+ // Only check arguments that contain a pseudo
+ if(rpseudo.test(unquoted) && // Get excess from tokenize (recursively)
+ (excess = tokenize(unquoted, true)) && // advance to the next closing parenthesis
+ (excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)){
+
+ // excess is a negative index
+ unquoted = unquoted.slice(0, excess);
+ match[0] = match[0].slice(0, excess);
+ };
+ match[2] = unquoted;
+ };
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice(0, 3);
+ }
+ },
+ filter : {
+ "ID" : assertGetIdNotName ? function(id){
+
+ id = id.replace(rbackslash, "");
+ return function(elem){
+
+ return elem.getAttribute("id") === id;
+ };
+ } : function(id){
+
+ id = id.replace(rbackslash, "");
+ return function(elem){
+
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ return node && node.value === id;
+ };
+ },
+ "TAG" : function(nodeName){
+
+ if(nodeName === "*"){
+
+ return function(){
+
+ return true;
+ };
+ };
+ nodeName = nodeName.replace(rbackslash, "").toLowerCase();
+ return function(elem){
+
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+ "CLASS" : function(className){
+
+ var pattern = classCache[expando][className];
+ if(!pattern){
+
+ pattern = classCache(className, new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)"));
+ };
+ return function(elem){
+
+ return pattern.test(elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "");
+ };
+ },
+ "ATTR" : function(name, operator, check){
+
+ return function(elem, context){
+
+ var result = Sizzle.attr(elem, name);
+ if(result == null){
+
+ return operator === "!=";
+ };
+ if(!operator){
+
+ return true;
+ };
+ result += "";
+ return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf(check) === 0 : operator === "*=" ? check && result.indexOf(check) > -1 : operator === "$=" ? check && result.substr(result.length - check.length) === check : operator === "~=" ? (" " + result + " ").indexOf(check) > -1 : operator === "|=" ? result === check || result.substr(0, check.length + 1) === check + "-" : false;
+ };
+ },
+ "CHILD" : function(type, argument, first, last){
+
+ if(type === "nth"){
+
+ return function(elem){
+
+ var node,diff,parent = elem.parentNode;
+ if(first === 1 && last === 0){
+
+ return true;
+ };
+ if(parent){
+
+ diff = 0;
+ for(node = parent.firstChild;node;node = node.nextSibling){
+
+ if(node.nodeType === 1){
+
+ diff++;
+ if(elem === node){
+
+ break;
+ };
+ };
+ };
+ };
+ // Incorporate the offset (or cast to NaN), then check against cycle size
+ diff -= last;
+ return diff === first || (diff % first === 0 && diff / first >= 0);
+ };
+ };
+ return function(elem){
+
+ var node = elem;
+ switch(type){case "only":case "first":
+ while((node = node.previousSibling)){
+
+ if(node.nodeType === 1){
+
+ return false;
+ };
+ };
+ if(type === "first"){
+
+ return true;
+ };
+ node = elem;/* falls through */
+ case "last":
+ while((node = node.nextSibling)){
+
+ if(node.nodeType === 1){
+
+ return false;
+ };
+ };
+ return true;};
+ };
+ },
+ "PSEUDO" : function(pseudo, argument){
+
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,fn = Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] || Sizzle.error("unsupported pseudo: " + pseudo);
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if(fn[expando]){
+
+ return fn(argument);
+ };
+ // But maintain support for old signatures
+ if(fn.length > 1){
+
+ args = [pseudo, pseudo, "", argument];
+ return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ? markFunction(function(seed, matches){
+
+ var idx,matched = fn(seed, argument),i = matched.length;
+ while(i--){
+
+ idx = indexOf.call(seed, matched[i]);
+ seed[idx] = !(matches[idx] = matched[i]);
+ };
+ }) : function(elem){
+
+ return fn(elem, 0, args);
+ };
+ };
+ return fn;
+ }
+ },
+ pseudos : {
+ "not" : markFunction(function(selector){
+
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],results = [],matcher = compile(selector.replace(rtrim, "$1"));
+ return matcher[expando] ? markFunction(function(seed, matches, context, xml){
+
+ var elem,unmatched = matcher(seed, null, xml, []),i = seed.length;
+ // Match elements unmatched by `matcher`
+ while(i--){
+
+ if((elem = unmatched[i])){
+
+ seed[i] = !(matches[i] = elem);
+ };
+ };
+ }) : function(elem, context, xml){
+
+ input[0] = elem;
+ matcher(input, null, xml, results);
+ return !results.pop();
+ };
+ }),
+ "has" : markFunction(function(selector){
+
+ return function(elem){
+
+ return Sizzle(selector, elem).length > 0;
+ };
+ }),
+ "contains" : markFunction(function(text){
+
+ return function(elem){
+
+ return (elem.textContent || elem.innerText || getText(elem)).indexOf(text) > -1;
+ };
+ }),
+ "enabled" : function(elem){
+
+ return elem.disabled === false;
+ },
+ "disabled" : function(elem){
+
+ return elem.disabled === true;
+ },
+ "checked" : function(elem){
+
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+ "selected" : function(elem){
+
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if(elem.parentNode){
+
+ elem.parentNode.selectedIndex;
+ };
+ return elem.selected === true;
+ },
+ "parent" : function(elem){
+
+ return !Expr.pseudos["empty"](elem);
+ },
+ "empty" : function(elem){
+
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
+ // not comment, processing instructions, or others
+ // Thanks to Diego Perini for the nodeName shortcut
+ // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
+ var nodeType;
+ elem = elem.firstChild;
+ while(elem){
+
+ if(elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4){
+
+ return false;
+ };
+ elem = elem.nextSibling;
+ };
+ return true;
+ },
+ "header" : function(elem){
+
+ return rheader.test(elem.nodeName);
+ },
+ "text" : function(elem){
+
+ var type,attr;
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return elem.nodeName.toLowerCase() === "input" && (type = elem.type) === "text" && ((attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type);
+ },
+ // Input types
+ "radio" : createInputPseudo("radio"),
+ "checkbox" : createInputPseudo("checkbox"),
+ "file" : createInputPseudo("file"),
+ "password" : createInputPseudo("password"),
+ "image" : createInputPseudo("image"),
+ "submit" : createButtonPseudo("submit"),
+ "reset" : createButtonPseudo("reset"),
+ "button" : function(elem){
+
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+ "input" : function(elem){
+
+ return rinputs.test(elem.nodeName);
+ },
+ "focus" : function(elem){
+
+ var doc = elem.ownerDocument;
+ return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href);
+ },
+ "active" : function(elem){
+
+ return elem === elem.ownerDocument.activeElement;
+ },
+ // Positional types
+ "first" : createPositionalPseudo(function(matchIndexes, length, argument){
+
+ return [0];
+ }),
+ "last" : createPositionalPseudo(function(matchIndexes, length, argument){
+
+ return [length - 1];
+ }),
+ "eq" : createPositionalPseudo(function(matchIndexes, length, argument){
+
+ return [argument < 0 ? argument + length : argument];
+ }),
+ "even" : createPositionalPseudo(function(matchIndexes, length, argument){
+
+ for(var i = 0;i < length;i += 2){
+
+ matchIndexes.push(i);
+ };
+ return matchIndexes;
+ }),
+ "odd" : createPositionalPseudo(function(matchIndexes, length, argument){
+
+ for(var i = 1;i < length;i += 2){
+
+ matchIndexes.push(i);
+ };
+ return matchIndexes;
+ }),
+ "lt" : createPositionalPseudo(function(matchIndexes, length, argument){
+
+ for(var i = argument < 0 ? argument + length : argument;--i >= 0;){
+
+ matchIndexes.push(i);
+ };
+ return matchIndexes;
+ }),
+ "gt" : createPositionalPseudo(function(matchIndexes, length, argument){
+
+ for(var i = argument < 0 ? argument + length : argument;++i < length;){
+
+ matchIndexes.push(i);
+ };
+ return matchIndexes;
+ })
+ }
+ };
+ function siblingCheck(a, b, ret){
+
+ if(a === b){
+
+ return ret;
+ };
+ var cur = a.nextSibling;
+ while(cur){
+
+ if(cur === b){
+
+ return -1;
+ };
+ cur = cur.nextSibling;
+ };
+ return 1;
+ };
+ sortOrder = docElem.compareDocumentPosition ? function(a, b){
+
+ if(a === b){
+
+ hasDuplicate = true;
+ return 0;
+ };
+ return (!a.compareDocumentPosition || !b.compareDocumentPosition ? a.compareDocumentPosition : a.compareDocumentPosition(b) & 4) ? -1 : 1;
+ } : function(a, b){
+
+ // The nodes are identical, we can exit early
+ if(a === b){
+
+ hasDuplicate = true;
+ return 0;
+ } else if(a.sourceIndex && b.sourceIndex){
+
+ return a.sourceIndex - b.sourceIndex;
+ };
+ var al,bl,ap = [],bp = [],aup = a.parentNode,bup = b.parentNode,cur = aup;
+ // If the nodes are siblings (or identical) we can do a quick check
+ if(aup === bup){
+
+ return siblingCheck(a, b);
+ } else if(!aup){
+
+ return -1;
+ } else if(!bup){
+
+ return 1;
+ };;
+ // Otherwise they're somewhere else in the tree so we need
+ // to build up a full list of the parentNodes for comparison
+ while(cur){
+
+ ap.unshift(cur);
+ cur = cur.parentNode;
+ };
+ cur = bup;
+ while(cur){
+
+ bp.unshift(cur);
+ cur = cur.parentNode;
+ };
+ al = ap.length;
+ bl = bp.length;
+ // Start walking down the tree looking for a discrepancy
+ for(var i = 0;i < al && i < bl;i++){
+
+ if(ap[i] !== bp[i]){
+
+ return siblingCheck(ap[i], bp[i]);
+ };
+ };
+ // We ended someplace up the tree so do a sibling check
+ return i === al ? siblingCheck(a, bp[i], -1) : siblingCheck(ap[i], b, 1);
+ };
+ // Always assume the presence of duplicates if sort doesn't
+ // pass them to our comparison function (as in Google Chrome).
+ [0, 0].sort(sortOrder);
+ baseHasDuplicate = !hasDuplicate;
+ // Document sorting and removing duplicates
+ Sizzle.uniqueSort = function(results){
+
+ var elem,i = 1;
+ hasDuplicate = baseHasDuplicate;
+ results.sort(sortOrder);
+ if(hasDuplicate){
+
+ for(;(elem = results[i]);i++){
+
+ if(elem === results[i - 1]){
+
+ results.splice(i--, 1);
+ };
+ };
+ };
+ return results;
+ };
+ Sizzle.error = function(msg){
+
+ throw new Error("Syntax error, unrecognized expression: " + msg);
+ };
+ function tokenize(selector, parseOnly){
+
+ var matched,match,tokens,type,soFar,groups,preFilters,cached = tokenCache[expando][selector];
+ if(cached){
+
+ return parseOnly ? 0 : cached.slice(0);
+ };
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+ while(soFar){
+
+ // Comma and first run
+ if(!matched || (match = rcomma.exec(soFar))){
+
+ if(match){
+
+ soFar = soFar.slice(match[0].length);
+ };
+ groups.push(tokens = []);
+ };
+ matched = false;
+ // Combinators
+ if((match = rcombinators.exec(soFar))){
+
+ tokens.push(matched = new Token(match.shift()));
+ soFar = soFar.slice(matched.length);
+ // Cast descendant combinators to space
+ matched.type = match[0].replace(rtrim, " ");
+ };
+ // Filters
+ for(type in Expr.filter){
+
+ if((match = matchExpr[type].exec(soFar)) && (!preFilters[type] || // The last two arguments here are (context, xml) for backCompat
+ (match = preFilters[type](match, document, true)))){
+
+ tokens.push(matched = new Token(match.shift()));
+ soFar = soFar.slice(matched.length);
+ matched.type = type;
+ matched.matches = match;
+ };
+ };
+ if(!matched){
+
+ break;
+ };
+ };
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ? soFar.length : soFar ? Sizzle.error(selector) : // Cache the tokens
+ tokenCache(selector, groups).slice(0);
+ };
+ function addCombinator(matcher, combinator, base){
+
+ var dir = combinator.dir,checkNonElements = base && combinator.dir === "parentNode",doneName = done++;
+ return combinator.first ? // Check against closest ancestor/preceding element
+ function(elem, context, xml){
+
+ while((elem = elem[dir])){
+
+ if(checkNonElements || elem.nodeType === 1){
+
+ return matcher(elem, context, xml);
+ };
+ };
+ } : // Check against all ancestor/preceding elements
+ function(elem, context, xml){
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if(!xml){
+
+ var cache,dirkey = dirruns + " " + doneName + " ",cachedkey = dirkey + cachedruns;
+ while((elem = elem[dir])){
+
+ if(checkNonElements || elem.nodeType === 1){
+
+ if((cache = elem[expando]) === cachedkey){
+
+ return elem.sizset;
+ } else if(typeof cache === "string" && cache.indexOf(dirkey) === 0){
+
+ if(elem.sizset){
+
+ return elem;
+ };
+ } else {
+
+ elem[expando] = cachedkey;
+ if(matcher(elem, context, xml)){
+
+ elem.sizset = true;
+ return elem;
+ };
+ elem.sizset = false;
+ };
+ };
+ };
+ } else {
+
+ while((elem = elem[dir])){
+
+ if(checkNonElements || elem.nodeType === 1){
+
+ if(matcher(elem, context, xml)){
+
+ return elem;
+ };
+ };
+ };
+ };
+ };
+ };
+ function elementMatcher(matchers){
+
+ return matchers.length > 1 ? function(elem, context, xml){
+
+ var i = matchers.length;
+ while(i--){
+
+ if(!matchers[i](elem, context, xml)){
+
+ return false;
+ };
+ };
+ return true;
+ } : matchers[0];
+ };
+ function condense(unmatched, map, filter, context, xml){
+
+ var elem,newUnmatched = [],i = 0,len = unmatched.length,mapped = map != null;
+ for(;i < len;i++){
+
+ if((elem = unmatched[i])){
+
+ if(!filter || filter(elem, context, xml)){
+
+ newUnmatched.push(elem);
+ if(mapped){
+
+ map.push(i);
+ };
+ };
+ };
+ };
+ return newUnmatched;
+ };
+ function setMatcher(preFilter, selector, matcher, postFilter, postFinder, postSelector){
+
+ if(postFilter && !postFilter[expando]){
+
+ postFilter = setMatcher(postFilter);
+ };
+ if(postFinder && !postFinder[expando]){
+
+ postFinder = setMatcher(postFinder, postSelector);
+ };
+ return markFunction(function(seed, results, context, xml){
+
+ // Positional selectors apply to seed elements, so it is invalid to follow them with relative ones
+ if(seed && postFinder){
+
+ return;
+ };
+ var i,elem,postFilterIn,preMap = [],postMap = [],preexisting = results.length,// Get initial elements from seed or context
+ elems = seed || multipleContexts(selector || "*", context.nodeType ? [context] : context, [], seed),// Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && (seed || !selector) ? condense(elems, preMap, preFilter, context, xml) : elems,matcherOut = matcher ? // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || (seed ? preFilter : preexisting || postFilter) ? // ...intermediate processing is necessary
+ [] : // ...otherwise use results directly
+ results : matcherIn;
+ // Find primary matches
+ if(matcher){
+
+ matcher(matcherIn, matcherOut, context, xml);
+ };
+ // Apply postFilter
+ if(postFilter){
+
+ postFilterIn = condense(matcherOut, postMap);
+ postFilter(postFilterIn, [], context, xml);
+ // Un-match failing elements by moving them back to matcherIn
+ i = postFilterIn.length;
+ while(i--){
+
+ if((elem = postFilterIn[i])){
+
+ matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem);
+ };
+ };
+ };
+ // Keep seed and results synchronized
+ if(seed){
+
+ // Ignore postFinder because it can't coexist with seed
+ i = preFilter && matcherOut.length;
+ while(i--){
+
+ if((elem = matcherOut[i])){
+
+ seed[preMap[i]] = !(results[preMap[i]] = elem);
+ };
+ };
+ } else {
+
+ matcherOut = condense(matcherOut === results ? matcherOut.splice(preexisting, matcherOut.length) : matcherOut);
+ if(postFinder){
+
+ postFinder(null, results, matcherOut, xml);
+ } else {
+
+ push.apply(results, matcherOut);
+ };
+ };
+ });
+ };
+ function matcherFromTokens(tokens){
+
+ var checkContext,matcher,j,len = tokens.length,leadingRelative = Expr.relative[tokens[0].type],implicitRelative = leadingRelative || Expr.relative[" "],i = leadingRelative ? 1 : 0,// The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator(function(elem){
+
+ return elem === checkContext;
+ }, implicitRelative, true),matchAnyContext = addCombinator(function(elem){
+
+ return indexOf.call(checkContext, elem) > -1;
+ }, implicitRelative, true),matchers = [function(elem, context, xml){
+
+ return (!leadingRelative && (xml || context !== outermostContext)) || ((checkContext = context).nodeType ? matchContext(elem, context, xml) : matchAnyContext(elem, context, xml));
+ }];
+ for(;i < len;i++){
+
+ if((matcher = Expr.relative[tokens[i].type])){
+
+ matchers = [addCombinator(elementMatcher(matchers), matcher)];
+ } else {
+
+ // The concatenated values are (context, xml) for backCompat
+ matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches);
+ // Return special upon seeing a positional matcher
+ if(matcher[expando]){
+
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for(;j < len;j++){
+
+ if(Expr.relative[tokens[j].type]){
+
+ break;
+ };
+ };
+ return setMatcher(i > 1 && elementMatcher(matchers), i > 1 && tokens.slice(0, i - 1).join("").replace(rtrim, "$1"), matcher, i < j && matcherFromTokens(tokens.slice(i, j)), j < len && matcherFromTokens((tokens = tokens.slice(j))), j < len && tokens.join(""));
+ };
+ matchers.push(matcher);
+ };
+ };
+ return elementMatcher(matchers);
+ };
+ function matcherFromGroupMatchers(elementMatchers, setMatchers){
+
+ var bySet = setMatchers.length > 0,byElement = elementMatchers.length > 0,superMatcher = function(seed, context, xml, results, expandContext){
+
+ var elem,j,matcher,setMatched = [],matchedCount = 0,i = "0",unmatched = seed && [],outermost = expandContext != null,contextBackup = outermostContext,// We must always have either seed elements or context
+ elems = seed || byElement && Expr.find["TAG"]("*", expandContext && context.parentNode || context),// Nested matchers should use non-integer dirruns
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E);
+ if(outermost){
+
+ outermostContext = context !== document && context;
+ cachedruns = superMatcher.el;
+ };
+ // Add elements passing elementMatchers directly to results
+ for(;(elem = elems[i]) != null;i++){
+
+ if(byElement && elem){
+
+ for(j = 0;(matcher = elementMatchers[j]);j++){
+
+ if(matcher(elem, context, xml)){
+
+ results.push(elem);
+ break;
+ };
+ };
+ if(outermost){
+
+ dirruns = dirrunsUnique;
+ cachedruns = ++superMatcher.el;
+ };
+ };
+ // Track unmatched elements for set filters
+ if(bySet){
+
+ // They will have gone through all possible matchers
+ if((elem = !matcher && elem)){
+
+ matchedCount--;
+ };
+ // Lengthen the array for every element, matched or not
+ if(seed){
+
+ unmatched.push(elem);
+ };
+ };
+ };
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if(bySet && i !== matchedCount){
+
+ for(j = 0;(matcher = setMatchers[j]);j++){
+
+ matcher(unmatched, setMatched, context, xml);
+ };
+ if(seed){
+
+ // Reintegrate element matches to eliminate the need for sorting
+ if(matchedCount > 0){
+
+ while(i--){
+
+ if(!(unmatched[i] || setMatched[i])){
+
+ setMatched[i] = pop.call(results);
+ };
+ };
+ };
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense(setMatched);
+ };
+ // Add matches to results
+ push.apply(results, setMatched);
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if(outermost && !seed && setMatched.length > 0 && (matchedCount + setMatchers.length) > 1){
+
+ Sizzle.uniqueSort(results);
+ };
+ };
+ // Override manipulation of globals by nested matchers
+ if(outermost){
+
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ };
+ return unmatched;
+ };
+ superMatcher.el = 0;
+ return bySet ? markFunction(superMatcher) : superMatcher;
+ };
+ compile = Sizzle.compile = function(selector, group){
+
+ var i,setMatchers = [],elementMatchers = [],cached = compilerCache[expando][selector];
+ if(!cached){
+
+ // Generate a function of recursive functions that can be used to check each element
+ if(!group){
+
+ group = tokenize(selector);
+ };
+ i = group.length;
+ while(i--){
+
+ cached = matcherFromTokens(group[i]);
+ if(cached[expando]){
+
+ setMatchers.push(cached);
+ } else {
+
+ elementMatchers.push(cached);
+ };
+ };
+ // Cache the compiled function
+ cached = compilerCache(selector, matcherFromGroupMatchers(elementMatchers, setMatchers));
+ };
+ return cached;
+ };
+ function multipleContexts(selector, contexts, results, seed){
+
+ var i = 0,len = contexts.length;
+ for(;i < len;i++){
+
+ Sizzle(selector, contexts[i], results, seed);
+ };
+ return results;
+ };
+ function select(selector, context, results, seed, xml){
+
+ var i,tokens,token,type,find,match = tokenize(selector),j = match.length;
+ if(!seed){
+
+ // Try to minimize operations if there is only one group
+ if(match.length === 1){
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice(0);
+ if(tokens.length > 2 && (token = tokens[0]).type === "ID" && context.nodeType === 9 && !xml && Expr.relative[tokens[1].type]){
+
+ context = Expr.find["ID"](token.matches[0].replace(rbackslash, ""), context, xml)[0];
+ if(!context){
+
+ return results;
+ };
+ selector = selector.slice(tokens.shift().length);
+ };
+ // Fetch a seed set for right-to-left matching
+ for(i = matchExpr["POS"].test(selector) ? -1 : tokens.length - 1;i >= 0;i--){
+
+ token = tokens[i];
+ // Abort if we hit a combinator
+ if(Expr.relative[(type = token.type)]){
+
+ break;
+ };
+ if((find = Expr.find[type])){
+
+ // Search, expanding context for leading sibling combinators
+ if((seed = find(token.matches[0].replace(rbackslash, ""), rsibling.test(tokens[0].type) && context.parentNode || context, xml))){
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice(i, 1);
+ selector = seed.length && tokens.join("");
+ if(!selector){
+
+ push.apply(results, slice.call(seed, 0));
+ return results;
+ };
+ break;
+ };
+ };
+ };
+ };
+ };
+ // Compile and execute a filtering function
+ // Provide `match` to avoid retokenization if we modified the selector above
+ compile(selector, match)(seed, context, xml, results, rsibling.test(selector));
+ return results;
+ };
+ if(document.querySelectorAll){
+
+ (function(){
+
+ var disconnectedMatch,oldSelect = select,rescape = /'|\\/g,rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,// qSa(:focus) reports false when true (Chrome 21),
+ // A support test would require too much code (would include document ready)
+ rbuggyQSA = [":focus"],// matchesSelector(:focus) reports false when true (Chrome 21),
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ // A support test would require too much code (would include document ready)
+ // just skip matchesSelector for :active
+ rbuggyMatches = [":active", ":focus"],matches = docElem.matchesSelector || docElem.mozMatchesSelector || docElem.webkitMatchesSelector || docElem.oMatchesSelector || docElem.msMatchesSelector;
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function(div){
+
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explictly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ div.innerHTML = "";
+ // IE8 - Some boolean attributes are not treated correctly
+ if(!div.querySelectorAll("[selected]").length){
+
+ rbuggyQSA.push("\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)");
+ };
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here (do not put tests after this one)
+ if(!div.querySelectorAll(":checked").length){
+
+ rbuggyQSA.push(":checked");
+ };
+ });
+ assert(function(div){
+
+ // Opera 10-12/IE9 - ^= $= *= and empty values
+ // Should not select anything
+ div.innerHTML = "";
+ if(div.querySelectorAll("[test^='']").length){
+
+ rbuggyQSA.push("[*^$]=" + whitespace + "*(?:\"\"|'')");
+ };
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here (do not put tests after this one)
+ div.innerHTML = "";
+ if(!div.querySelectorAll(":enabled").length){
+
+ rbuggyQSA.push(":enabled", ":disabled");
+ };
+ });
+ // rbuggyQSA always contains :focus, so no need for a length check
+ rbuggyQSA = /* rbuggyQSA.length && */ new RegExp(rbuggyQSA.join("|"));
+ select = function(selector, context, results, seed, xml){
+
+ // Only use querySelectorAll when not filtering,
+ // when this is not xml,
+ // and when no QSA bugs apply
+ if(!seed && !xml && (!rbuggyQSA || !rbuggyQSA.test(selector))){
+
+ var groups,i,old = true,nid = expando,newContext = context,newSelector = context.nodeType === 9 && selector;
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if(context.nodeType === 1 && context.nodeName.toLowerCase() !== "object"){
+
+ groups = tokenize(selector);
+ if((old = context.getAttribute("id"))){
+
+ nid = old.replace(rescape, "\\$&");
+ } else {
+
+ context.setAttribute("id", nid);
+ };
+ nid = "[id='" + nid + "'] ";
+ i = groups.length;
+ while(i--){
+
+ groups[i] = nid + groups[i].join("");
+ };
+ newContext = rsibling.test(selector) && context.parentNode || context;
+ newSelector = groups.join(",");
+ };
+ if(newSelector){
+
+ try{
+
+ push.apply(results, slice.call(newContext.querySelectorAll(newSelector), 0));
+ return results;
+ } catch(qsaError) {
+ }finally{
+
+ if(!old){
+
+ context.removeAttribute("id");
+ };
+ };
+ };
+ };
+ return oldSelect(selector, context, results, seed, xml);
+ };
+ if(matches){
+
+ assert(function(div){
+
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ disconnectedMatch = matches.call(div, "div");
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ try{
+
+ matches.call(div, "[test!='']:sizzle");
+ rbuggyMatches.push("!=", pseudos);
+ } catch(e) {
+ };
+ });
+ // rbuggyMatches always contains :active and :focus, so no need for a length check
+ rbuggyMatches = /* rbuggyMatches.length && */ new RegExp(rbuggyMatches.join("|"));
+ Sizzle.matchesSelector = function(elem, expr){
+
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace(rattributeQuotes, "='$1']");
+ // rbuggyMatches always contains :active, so no need for an existence check
+ if(!isXML(elem) && !rbuggyMatches.test(expr) && (!rbuggyQSA || !rbuggyQSA.test(expr))){
+
+ try{
+
+ var ret = matches.call(elem, expr);
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if(ret || disconnectedMatch || // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11){
+
+ return ret;
+ };
+ } catch(e) {
+ };
+ };
+ return Sizzle(expr, null, null, [elem]).length > 0;
+ };
+ };
+ })();
+ };
+ // Deprecated
+ Expr.pseudos["nth"] = Expr.pseudos["eq"];
+ // Back-compat
+ function setFilters(){
+ };
+ Expr.filters = setFilters.prototype = Expr.pseudos;
+ Expr.setFilters = new setFilters();
+ // EXPOSE qooxdoo variant
+ qx.bom.Selector.query = function(selector, context){
+
+ return Sizzle(selector, context);
+ };
+ qx.bom.Selector.matches = function(selector, set){
+
+ return Sizzle(selector, null, null, set);
+ };
+})(window);
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2007-2008 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Fabian Jakobs (fjakobs)
+
+************************************************************************ */
+/**
+ * Utility class with type check for all native JavaScript data types.
+ */
+qx.Bootstrap.define("qx.lang.Type", {
+ statics : {
+ /**
+ * Get the internal class of the value. See
+ * http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
+ * for details.
+ *
+ * @signature function(value)
+ * @param value {var} value to get the class for
+ * @return {String} the internal class of the value
+ */
+ getClass : qx.Bootstrap.getClass,
+ /**
+ * Whether the value is a string.
+ *
+ * @signature function(value)
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is a string.
+ */
+ isString : qx.Bootstrap.isString,
+ /**
+ * Whether the value is an array.
+ *
+ * @signature function(value)
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is an array.
+ */
+ isArray : qx.Bootstrap.isArray,
+ /**
+ * Whether the value is an object. Note that built-in types like Window are
+ * not reported to be objects.
+ *
+ * @signature function(value)
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is an object.
+ */
+ isObject : qx.Bootstrap.isObject,
+ /**
+ * Whether the value is a function.
+ *
+ * @signature function(value)
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is a function.
+ */
+ isFunction : qx.Bootstrap.isFunction,
+ /**
+ * Whether the value is a regular expression.
+ *
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is a regular expression.
+ */
+ isRegExp : function(value){
+
+ return this.getClass(value) == "RegExp";
+ },
+ /**
+ * Whether the value is a number.
+ *
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is a number.
+ */
+ isNumber : function(value){
+
+ // Added "value !== null" because IE throws an exception "Object expected"
+ // by executing "value instanceof Number" if value is a DOM element that
+ // doesn't exist. It seems that there is an internal different between a
+ // JavaScript null and a null returned from calling DOM.
+ // e.q. by document.getElementById("ReturnedNull").
+ return (value !== null && (this.getClass(value) == "Number" || value instanceof Number));
+ },
+ /**
+ * Whether the value is a boolean.
+ *
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is a boolean.
+ */
+ isBoolean : function(value){
+
+ // Added "value !== null" because IE throws an exception "Object expected"
+ // by executing "value instanceof Boolean" if value is a DOM element that
+ // doesn't exist. It seems that there is an internal different between a
+ // JavaScript null and a null returned from calling DOM.
+ // e.q. by document.getElementById("ReturnedNull").
+ return (value !== null && (this.getClass(value) == "Boolean" || value instanceof Boolean));
+ },
+ /**
+ * Whether the value is a date.
+ *
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is a date.
+ */
+ isDate : function(value){
+
+ // Added "value !== null" because IE throws an exception "Object expected"
+ // by executing "value instanceof Date" if value is a DOM element that
+ // doesn't exist. It seems that there is an internal different between a
+ // JavaScript null and a null returned from calling DOM.
+ // e.q. by document.getElementById("ReturnedNull").
+ return (value !== null && (this.getClass(value) == "Date" || value instanceof Date));
+ },
+ /**
+ * Whether the value is a Error.
+ *
+ * @param value {var} Value to check.
+ * @return {Boolean} Whether the value is a Error.
+ */
+ isError : function(value){
+
+ // Added "value !== null" because IE throws an exception "Object expected"
+ // by executing "value instanceof Error" if value is a DOM element that
+ // doesn't exist. It seems that there is an internal different between a
+ // JavaScript null and a null returned from calling DOM.
+ // e.q. by document.getElementById("ReturnedNull").
+ return (value !== null && (this.getClass(value) == "Error" || value instanceof Error));
+ }
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2012 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (wittemann)
+
+************************************************************************ */
+/**
+ * This module offers a cross browser storage implementation. The API is aligned
+ * with the API of the HTML web storage (http://www.w3.org/TR/webstorage/) which is
+ * also the preferred implementation used. As fallback for IE < 8, we use user data.
+ * If both techniques are unsupported, we supply a in memory storage, which is
+ * of course, not persistent.
+ */
+qx.Bootstrap.define("qx.module.Storage", {
+ statics : {
+ /**
+ * Store an item in the storage.
+ *
+ * @attachStatic {qxWeb, localStorage.setItem}
+ * @param key {String} The identifier key.
+ * @param value {var} The data, which will be stored as JSON.
+ */
+ setLocalItem : function(key, value){
+
+ qx.bom.Storage.getLocal().setItem(key, value);
+ },
+ /**
+ * Returns the stored item.
+ *
+ * @attachStatic {qxWeb, localStorage.getItem}
+ * @param key {String} The identifier to get the data.
+ * @return {var} The stored data.
+ */
+ getLocalItem : function(key){
+
+ return qx.bom.Storage.getLocal().getItem(key);
+ },
+ /**
+ * Removes an item form the storage.
+ * @attachStatic {qxWeb, localStorage.removeItem}
+ * @param key {String} The identifier.
+ */
+ removeLocalItem : function(key){
+
+ qx.bom.Storage.getLocal().removeItem(key);
+ },
+ /**
+ * Returns the amount of key-value pairs stored.
+ * @attachStatic {qxWeb, localStorage.getLength}
+ * @return {Number} The length of the storage.
+ */
+ getLocalLength : function(){
+
+ return qx.bom.Storage.getLocal().getLength();
+ },
+ /**
+ * Returns the named key at the given index.
+ * @attachStatic {qxWeb, localStorage.getKey}
+ * @param index {Number} The index in the storage.
+ * @return {String} The key stored at the given index.
+ */
+ getLocalKey : function(index){
+
+ return qx.bom.Storage.getLocal().getKey(index);
+ },
+ /**
+ * Deletes every stored item in the storage.
+ * @attachStatic {qxWeb, localStorage.clear}
+ */
+ clearLocal : function(){
+
+ qx.bom.Storage.getLocal().clear();
+ },
+ /**
+ * Helper to access every stored item.
+ *
+ * @attachStatic {qxWeb, localStorage.forEach}
+ * @param callback {Function} A function which will be called for every item.
+ * The function will have two arguments, first the key and second the value
+ * of the stored data.
+ * @param scope {var} The scope of the function.
+ */
+ forEachLocal : function(callback, scope){
+
+ qx.bom.Storage.getLocal().forEach(callback, scope);
+ },
+ /**
+ * Store an item in the storage.
+ *
+ * @attachStatic {qxWeb, sessionStorage.setItem}
+ * @param key {String} The identifier key.
+ * @param value {var} The data, which will be stored as JSON.
+ */
+ setSessionItem : function(key, value){
+
+ qx.bom.Storage.getSession().setItem(key, value);
+ },
+ /**
+ * Returns the stored item.
+ *
+ * @attachStatic {qxWeb, sessionStorage.getItem}
+ * @param key {String} The identifier to get the data.
+ * @return {var} The stored data.
+ */
+ getSessionItem : function(key){
+
+ return qx.bom.Storage.getSession().getItem(key);
+ },
+ /**
+ * Removes an item form the storage.
+ * @attachStatic {qxWeb, sessionStorage.removeItem}
+ * @param key {String} The identifier.
+ */
+ removeSessionItem : function(key){
+
+ qx.bom.Storage.getSession().removeItem(key);
+ },
+ /**
+ * Returns the amount of key-value pairs stored.
+ * @attachStatic {qxWeb, sessionStorage.getLength}
+ * @return {Number} The length of the storage.
+ */
+ getSessionLength : function(){
+
+ return qx.bom.Storage.getSession().getLength();
+ },
+ /**
+ * Returns the named key at the given index.
+ * @attachStatic {qxWeb, sessionStorage.getKey}
+ * @param index {Number} The index in the storage.
+ * @return {String} The key stored at the given index.
+ */
+ getSessionKey : function(index){
+
+ return qx.bom.Storage.getSession().getKey(index);
+ },
+ /**
+ * Deletes every stored item in the storage.
+ * @attachStatic {qxWeb, sessionStorage.clear}
+ */
+ clearSession : function(){
+
+ qx.bom.Storage.getSession().clear();
+ },
+ /**
+ * Helper to access every stored item.
+ *
+ * @attachStatic {qxWeb, sessionStorage.forEach}
+ * @param callback {Function} A function which will be called for every item.
+ * The function will have two arguments, first the key and second the value
+ * of the stored data.
+ * @param scope {var} The scope of the function.
+ */
+ forEachSession : function(callback, scope){
+
+ qx.bom.Storage.getSession().forEach(callback, scope);
+ }
+ },
+ defer : function(statics){
+
+ qxWeb.$attachStatic({
+ "localStorage" : {
+ setItem : statics.setLocalItem,
+ getItem : statics.getLocalItem,
+ removeItem : statics.removeLocalItem,
+ getLength : statics.getLocalLength,
+ getKey : statics.getLocalKey,
+ clear : statics.clearLocal,
+ forEach : statics.forEachLocal
+ },
+ "sessionStorage" : {
+ setItem : statics.setSessionItem,
+ getItem : statics.getSessionItem,
+ removeItem : statics.removeSessionItem,
+ getLength : statics.getSessionLength,
+ getKey : statics.getSessionKey,
+ clear : statics.clearSession,
+ forEach : statics.forEachSession
+ }
+ });
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2011 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (wittemann)
+
+************************************************************************ */
+/**
+ * This is a cross browser storage implementation. The API is aligned with the
+ * API of the HTML web storage (http://www.w3.org/TR/webstorage/) which is also
+ * the preferred implementation used. As fallback for IE < 8, we use user data.
+ * If both techniques are unsupported, we supply a in memory storage, which is
+ * of course, not persistent.
+ */
+qx.Bootstrap.define("qx.bom.Storage", {
+ statics : {
+ __impl : null,
+ /**
+ * Get an instance of a local storage.
+ * @return {qx.bom.storage.Web|qx.bom.storage.UserData|qx.bom.storage.Memory}
+ * An instance of a storage implementation.
+ */
+ getLocal : function(){
+
+ // always use HTML5 web storage if available
+ if(qx.core.Environment.get("html.storage.local")){
+
+ return qx.bom.storage.Web.getLocal();
+ } else if(qx.core.Environment.get("html.storage.userdata")){
+
+ // IE <8 fallback
+ // as fallback,use the userdata storage for IE5.5 - 8
+ return qx.bom.storage.UserData.getLocal();
+ };
+ // as last fallback, use a in memory storage (this one is not persistent)
+ return qx.bom.storage.Memory.getLocal();
+ },
+ /**
+ * Get an instance of a session storage.
+ * @return {qx.bom.storage.Web|qx.bom.storage.UserData|qx.bom.storage.Memory}
+ * An instance of a storage implementation.
+ */
+ getSession : function(){
+
+ // always use HTML5 web storage if available
+ if(qx.core.Environment.get("html.storage.local")){
+
+ return qx.bom.storage.Web.getSession();
+ } else if(qx.core.Environment.get("html.storage.userdata")){
+
+ // IE <8 fallback
+ // as fallback,use the userdata storage for IE5.5 - 8
+ return qx.bom.storage.UserData.getSession();
+ };
+ // as last fallback, use a in memory storage (this one is not persistent)
+ return qx.bom.storage.Memory.getSession();
+ }
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2011 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (martinwittemann)
+
+************************************************************************ */
+/**
+ * Internal class which contains the checks used by {@link qx.core.Environment}.
+ * All checks in here are marked as internal which means you should never use
+ * them directly.
+ *
+ * This class should contain all checks about HTML.
+ *
+ * @internal
+ */
+qx.Bootstrap.define("qx.bom.client.Html", {
+ statics : {
+ /**
+ * Whether the client supports Web Workers.
+ *
+ * @internal
+ * @return {Boolean} true if webworkers are supported
+ */
+ getWebWorker : function(){
+
+ return window.Worker != null;
+ },
+ /**
+ * Whether the client supports File Readers
+ *
+ * @internal
+ * @return {Boolean} true if FileReaders are supported
+ */
+ getFileReader : function(){
+
+ return window.FileReader != null;
+ },
+ /**
+ * Whether the client supports Geo Location.
+ *
+ * @internal
+ * @return {Boolean} true if geolocation supported
+ */
+ getGeoLocation : function(){
+
+ return navigator.geolocation != null;
+ },
+ /**
+ * Whether the client supports audio.
+ *
+ * @internal
+ * @return {Boolean} true if audio is supported
+ */
+ getAudio : function(){
+
+ return !!document.createElement('audio').canPlayType;
+ },
+ /**
+ * Whether the client can play ogg audio format.
+ *
+ * @internal
+ * @return {String} "" or "maybe" or "probably"
+ */
+ getAudioOgg : function(){
+
+ if(!qx.bom.client.Html.getAudio()){
+
+ return "";
+ };
+ var a = document.createElement("audio");
+ return a.canPlayType("audio/ogg");
+ },
+ /**
+ * Whether the client can play mp3 audio format.
+ *
+ * @internal
+ * @return {String} "" or "maybe" or "probably"
+ */
+ getAudioMp3 : function(){
+
+ if(!qx.bom.client.Html.getAudio()){
+
+ return "";
+ };
+ var a = document.createElement("audio");
+ return a.canPlayType("audio/mpeg");
+ },
+ /**
+ * Whether the client can play wave audio wave format.
+ *
+ * @internal
+ * @return {String} "" or "maybe" or "probably"
+ */
+ getAudioWav : function(){
+
+ if(!qx.bom.client.Html.getAudio()){
+
+ return "";
+ };
+ var a = document.createElement("audio");
+ return a.canPlayType("audio/x-wav");
+ },
+ /**
+ * Whether the client can play au audio format.
+ *
+ * @internal
+ * @return {String} "" or "maybe" or "probably"
+ */
+ getAudioAu : function(){
+
+ if(!qx.bom.client.Html.getAudio()){
+
+ return "";
+ };
+ var a = document.createElement("audio");
+ return a.canPlayType("audio/basic");
+ },
+ /**
+ * Whether the client can play aif audio format.
+ *
+ * @internal
+ * @return {String} "" or "maybe" or "probably"
+ */
+ getAudioAif : function(){
+
+ if(!qx.bom.client.Html.getAudio()){
+
+ return "";
+ };
+ var a = document.createElement("audio");
+ return a.canPlayType("audio/x-aiff");
+ },
+ /**
+ * Whether the client supports video.
+ *
+ * @internal
+ * @return {Boolean} true if video is supported
+ */
+ getVideo : function(){
+
+ return !!document.createElement('video').canPlayType;
+ },
+ /**
+ * Whether the client supports ogg video.
+ *
+ * @internal
+ * @return {String} "" or "maybe" or "probably"
+ */
+ getVideoOgg : function(){
+
+ if(!qx.bom.client.Html.getVideo()){
+
+ return "";
+ };
+ var v = document.createElement("video");
+ return v.canPlayType('video/ogg; codecs="theora, vorbis"');
+ },
+ /**
+ * Whether the client supports mp4 video.
+ *
+ * @internal
+ * @return {String} "" or "maybe" or "probably"
+ */
+ getVideoH264 : function(){
+
+ if(!qx.bom.client.Html.getVideo()){
+
+ return "";
+ };
+ var v = document.createElement("video");
+ return v.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
+ },
+ /**
+ * Whether the client supports webm video.
+ *
+ * @internal
+ * @return {String} "" or "maybe" or "probably"
+ */
+ getVideoWebm : function(){
+
+ if(!qx.bom.client.Html.getVideo()){
+
+ return "";
+ };
+ var v = document.createElement("video");
+ return v.canPlayType('video/webm; codecs="vp8, vorbis"');
+ },
+ /**
+ * Whether the client supports local storage.
+ *
+ * @internal
+ * @return {Boolean} true if local storage is supported
+ */
+ getLocalStorage : function(){
+
+ try{
+
+ return window.localStorage != null;
+ } catch(exc) {
+
+ // Firefox Bug: Local execution of window.sessionStorage throws error
+ // see https://bugzilla.mozilla.org/show_bug.cgi?id=357323
+ return false;
+ };
+ },
+ /**
+ * Whether the client supports session storage.
+ *
+ * @internal
+ * @return {Boolean} true if session storage is supported
+ */
+ getSessionStorage : function(){
+
+ try{
+
+ return window.sessionStorage != null;
+ } catch(exc) {
+
+ // Firefox Bug: Local execution of window.sessionStorage throws error
+ // see https://bugzilla.mozilla.org/show_bug.cgi?id=357323
+ return false;
+ };
+ },
+ /**
+ * Whether the client supports user data to persist data. This is only
+ * relevant for IE < 8.
+ *
+ * @internal
+ * @return {Boolean} true if the user data is supported.
+ */
+ getUserDataStorage : function(){
+
+ var el = document.createElement("div");
+ el.style["display"] = "none";
+ document.getElementsByTagName("head")[0].appendChild(el);
+ var supported = false;
+ try{
+
+ el.addBehavior("#default#userdata");
+ el.load("qxtest");
+ supported = true;
+ } catch(e) {
+ };
+ document.getElementsByTagName("head")[0].removeChild(el);
+ return supported;
+ },
+ /**
+ * Whether the browser supports CSS class lists.
+ * https://developer.mozilla.org/en-US/docs/DOM/element.classList
+ *
+ * @internal
+ * @return {Boolean} true if class list is supported.
+ */
+ getClassList : function(){
+
+ return !!(document.documentElement.classList && qx.Bootstrap.getClass(document.documentElement.classList) === "DOMTokenList");
+ },
+ /**
+ * Checks if XPath could be used.
+ *
+ * @internal
+ * @return {Boolean} true if xpath is supported.
+ */
+ getXPath : function(){
+
+ return !!document.evaluate;
+ },
+ /**
+ * Checks if XUL could be used.
+ *
+ * @internal
+ * @return {Boolean} true if XUL is supported.
+ */
+ getXul : function(){
+
+ try{
+
+ document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "label");
+ return true;
+ } catch(e) {
+
+ return false;
+ };
+ },
+ /**
+ * Checks if SVG could be used
+ *
+ * @internal
+ * @return {Boolean} true if SVG is supported.
+ */
+ getSvg : function(){
+
+ return document.implementation && document.implementation.hasFeature && (document.implementation.hasFeature("org.w3c.dom.svg", "1.0") || document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
+ },
+ /**
+ * Checks if VML is supported
+ *
+ * @internal
+ * @return {Boolean} true if VML is supported.
+ */
+ getVml : function(){
+
+ var el = document.createElement("div");
+ document.body.appendChild(el);
+ el.innerHTML = 'true if canvas is supported.
+ */
+ getCanvas : function(){
+
+ return !!window.CanvasRenderingContext2D;
+ },
+ /**
+ * Asynchronous check for using data urls.
+ *
+ * @internal
+ * @param callback {Function} The function which should be executed as
+ * soon as the check is done.
+ */
+ getDataUrl : function(callback){
+
+ var data = new Image();
+ data.onload = data.onerror = function(){
+
+ // wrap that into a timeout because IE might execute it synchronously
+ window.setTimeout(function(){
+
+ callback.call(null, (data.width == 1 && data.height == 1));
+ }, 0);
+ };
+ data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
+ },
+ /**
+ * Checks if dataset could be used
+ *
+ * @internal
+ * @return {Boolean} true if dataset is supported.
+ */
+ getDataset : function(){
+
+ return !!document.documentElement.dataset;
+ },
+ /**
+ * Check for element.contains
+ *
+ * @internal
+ * @return {Boolean} true if element.contains is supported
+ */
+ getContains : function(){
+
+ // "object" in IE6/7/8, "function" in IE9
+ return (typeof document.documentElement.contains !== "undefined");
+ },
+ /**
+ * Check for element.compareDocumentPosition
+ *
+ * @internal
+ * @return {Boolean} true if element.compareDocumentPosition is supported
+ */
+ getCompareDocumentPosition : function(){
+
+ return (typeof document.documentElement.compareDocumentPosition === "function");
+ },
+ /**
+ * Check for element.textContent. Legacy IEs do not support this, use
+ * innerText instead.
+ *
+ * @internal
+ * @return {Boolean} true if textContent is supported
+ */
+ getTextContent : function(){
+
+ var el = document.createElement("span");
+ return (typeof el.textContent !== "undefined");
+ },
+ /**
+ * Check for a console object.
+ *
+ * @internal
+ * @return {Boolean} true if a console is available.
+ */
+ getConsole : function(){
+
+ return typeof window.console !== "undefined";
+ },
+ /**
+ * Check for the naturalHeight and naturalWidth
+ * image element attributes.
+ *
+ * @internal
+ * @return {Boolean} true if both attributes are supported
+ */
+ getNaturalDimensions : function(){
+
+ var img = document.createElement("img");
+ return typeof img.naturalHeight === "number" && typeof img.naturalWidth === "number";
+ },
+ /**
+ * Check for HTML5 history manipulation support.
+
+ * @internal
+ * @return {Boolean} true if the HTML5 history API is supported
+ */
+ getHistoryState : function(){
+
+ return (typeof window.onpopstate !== "undefined" && typeof window.history.replaceState !== "undefined" && typeof window.history.pushState !== "undefined");
+ },
+ /**
+ * Returns the name of the native object/function used to access the
+ * document's text selection.
+ *
+ * @return {String|null} getSelection if the standard window.getSelection
+ * function is available; selection if the MS-proprietary
+ * document.selection object is available; null if no known
+ * text selection API is available.
+ */
+ getSelection : function(){
+
+ if(typeof window.getSelection === "function"){
+
+ return "getSelection";
+ };
+ if(typeof document.selection === "object"){
+
+ return "selection";
+ };
+ return null;
+ }
+ },
+ defer : function(statics){
+
+ qx.core.Environment.add("html.webworker", statics.getWebWorker);
+ qx.core.Environment.add("html.filereader", statics.getFileReader);
+ qx.core.Environment.add("html.geolocation", statics.getGeoLocation);
+ qx.core.Environment.add("html.audio", statics.getAudio);
+ qx.core.Environment.add("html.audio.ogg", statics.getAudioOgg);
+ qx.core.Environment.add("html.audio.mp3", statics.getAudioMp3);
+ qx.core.Environment.add("html.audio.wav", statics.getAudioWav);
+ qx.core.Environment.add("html.audio.au", statics.getAudioAu);
+ qx.core.Environment.add("html.audio.aif", statics.getAudioAif);
+ qx.core.Environment.add("html.video", statics.getVideo);
+ qx.core.Environment.add("html.video.ogg", statics.getVideoOgg);
+ qx.core.Environment.add("html.video.h264", statics.getVideoH264);
+ qx.core.Environment.add("html.video.webm", statics.getVideoWebm);
+ qx.core.Environment.add("html.storage.local", statics.getLocalStorage);
+ qx.core.Environment.add("html.storage.session", statics.getSessionStorage);
+ qx.core.Environment.add("html.storage.userdata", statics.getUserDataStorage);
+ qx.core.Environment.add("html.classlist", statics.getClassList);
+ qx.core.Environment.add("html.xpath", statics.getXPath);
+ qx.core.Environment.add("html.xul", statics.getXul);
+ qx.core.Environment.add("html.canvas", statics.getCanvas);
+ qx.core.Environment.add("html.svg", statics.getSvg);
+ qx.core.Environment.add("html.vml", statics.getVml);
+ qx.core.Environment.add("html.dataset", statics.getDataset);
+ qx.core.Environment.addAsync("html.dataurl", statics.getDataUrl);
+ qx.core.Environment.add("html.element.contains", statics.getContains);
+ qx.core.Environment.add("html.element.compareDocumentPosition", statics.getCompareDocumentPosition);
+ qx.core.Environment.add("html.element.textcontent", statics.getTextContent);
+ qx.core.Environment.add("html.console", statics.getConsole);
+ qx.core.Environment.add("html.image.naturaldimensions", statics.getNaturalDimensions);
+ qx.core.Environment.add("html.history.state", statics.getHistoryState);
+ qx.core.Environment.add("html.selection", statics.getSelection);
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2011 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (wittemann)
+
+************************************************************************ */
+/* ************************************************************************
+#require(qx.bom.storage.Web#getLength)
+#require(qx.bom.storage.Web#setItem)
+#require(qx.bom.storage.Web#getItem)
+#require(qx.bom.storage.Web#removeItem)
+#require(qx.bom.storage.Web#clear)
+#require(qx.bom.storage.Web#getKey)
+#require(qx.bom.storage.Web#forEach)
+************************************************************************ */
+/**
+ * Storage implementation using HTML web storage:
+ * http://www.w3.org/TR/webstorage/
+ */
+qx.Bootstrap.define("qx.bom.storage.Web", {
+ statics : {
+ __local : null,
+ __session : null,
+ /**
+ * Static accessor for the local storage.
+ * @return {qx.bom.storage.Web} An instance of a local storage.
+ */
+ getLocal : function(){
+
+ if(this.__local){
+
+ return this.__local;
+ };
+ return this.__local = new qx.bom.storage.Web("local");
+ },
+ /**
+ * Static accessor for the session storage.
+ * @return {qx.bom.storage.Web} An instance of a session storage.
+ */
+ getSession : function(){
+
+ if(this.__session){
+
+ return this.__session;
+ };
+ return this.__session = new qx.bom.storage.Web("session");
+ }
+ },
+ /**
+ * Create a new instance. Usually, you should take the static
+ * accessors to get your instance.
+ *
+ * @param type {String} type of storage, either
+ * local or session.
+ */
+ construct : function(type){
+
+ this.__type = type;
+ },
+ members : {
+ __type : null,
+ /**
+ * Returns the internal used storage (the native object).
+ *
+ * @internal
+ * @return {Storage} The native storage implementation.
+ */
+ getStorage : function(){
+
+ return window[this.__type + "Storage"];
+ },
+ /**
+ * Returns the amount of key-value pairs stored.
+ * @return {Integer} The length of the storage.
+ */
+ getLength : function(){
+
+ return this.getStorage(this.__type).length;
+ },
+ /**
+ * Store an item in the storage.
+ *
+ * @param key {String} The identifier key.
+ * @param value {var} The data, which will be stored as JSON.
+ */
+ setItem : function(key, value){
+
+ value = qx.lang.Json.stringify(value);
+ try{
+
+ this.getStorage(this.__type).setItem(key, value);
+ } catch(e) {
+
+ throw new Error("Storage full.");
+ };
+ },
+ /**
+ * Returns the stored item.
+ *
+ * @param key {String} The identifier to get the data.
+ * @return {var} The stored data.
+ */
+ getItem : function(key){
+
+ var item = this.getStorage(this.__type).getItem(key);
+ if(qx.lang.Type.isString(item)){
+
+ item = qx.lang.Json.parse(item);
+ } else if(item && item.value && qx.lang.Type.isString(item.value)){
+
+ item = qx.lang.Json.parse(item.value);
+ };
+ return item;
+ },
+ /**
+ * Removes an item form the storage.
+ * @param key {String} The identifier.
+ */
+ removeItem : function(key){
+
+ this.getStorage(this.__type).removeItem(key);
+ },
+ /**
+ * Deletes every stored item in the storage.
+ */
+ clear : function(){
+
+ var storage = this.getStorage(this.__type);
+ if(!storage.clear){
+
+ for(var i = storage.length - 1;i >= 0;i--){
+
+ storage.removeItem(storage.key(i));
+ };
+ } else {
+
+ storage.clear();
+ };
+ },
+ /**
+ * Returns the named key at the given index.
+ * @param index {Integer} The index in the storage.
+ * @return {String} The key stored at the given index.
+ */
+ getKey : function(index){
+
+ return this.getStorage(this.__type).key(index);
+ },
+ /**
+ * Helper to access every stored item.
+ *
+ * @param callback {Function} A function which will be called for every item.
+ * The function will have two arguments, first the key and second the value
+ * of the stored data.
+ * @param scope {var} The scope of the function.
+ */
+ forEach : function(callback, scope){
+
+ var length = this.getLength();
+ for(var i = 0;i < length;i++){
+
+ var key = this.getKey(i);
+ callback.call(scope, key, this.getItem(key));
+ };
+ }
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Fabian Jakobs (fjakobs)
+ ________________________________________________________________________
+
+ This class contains code based on the following work:
+
+ http://www.JSON.org/json2.js
+ 2009-06-29
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+************************************************************************ */
+/**
+ * Pure JavaScript implementation of the EcmaScript 3.1 JSON object. This class
+ * is used, if the browser does not support it natively.
+ *
+ * @internal
+ */
+qx.Bootstrap.define("qx.lang.JsonImpl", {
+ extend : Object,
+ construct : function(){
+
+ // bind parse and stringify so they can be called without a context.
+ this.stringify = qx.lang.Function.bind(this.stringify, this);
+ this.parse = qx.lang.Function.bind(this.parse, this);
+ },
+ members : {
+ __gap : null,
+ __indent : null,
+ __rep : null,
+ __stack : null,
+ /**
+ * This method produces a JSON text from a JavaScript value.
+ *
+ * @param value {var} any JavaScript value, usually an object or array.
+ *
+ * @param replacer {Function?} an optional parameter that determines how
+ * object values are stringified for objects. It can be a function or an
+ * array of strings.
+ *
+ * @param space {String?} an optional parameter that specifies the
+ * indentation of nested structures. If it is omitted, the text will
+ * be packed without extra whitespace. If it is a number, it will specify
+ * the number of spaces to indent at each level. If it is a string
+ * (such as '\t' or ' '), it contains the characters used to indent
+ * at each level.
+ *
+ * @return {String} The JSON string of the value
+ */
+ stringify : function(value, replacer, space){
+
+ this.__gap = '';
+ this.__indent = '';
+ this.__stack = [];
+ if(qx.lang.Type.isNumber(space)){
+
+ // If the space parameter is a number, make an indent string containing that
+ // many spaces.
+ var space = Math.min(10, Math.floor(space));
+ for(var i = 0;i < space;i += 1){
+
+ this.__indent += ' ';
+ };
+ } else if(qx.lang.Type.isString(space)){
+
+ if(space.length > 10){
+
+ space = space.slice(0, 10);
+ };
+ // If the space parameter is a string, it will be used as the indent string.
+ this.__indent = space;
+ };
+ // If there is a replacer, it must be a function or an array.
+ // Otherwise, ignore it.
+ if(replacer && (qx.lang.Type.isFunction(replacer) || qx.lang.Type.isArray(replacer))){
+
+ this.__rep = replacer;
+ } else {
+
+ this.__rep = null;
+ };
+ // Make a fake root object containing our value under the key of ''.
+ // Return the result of stringifying the value.
+ return this.__str('', {
+ '' : value
+ });
+ },
+ /**
+ * Produce a string from holder[key].
+ *
+ * @param key {String} the map key
+ * @param holder {Object} an object with the given key
+ * @return {String} The string representation of holder[key]
+ */
+ __str : function(key, holder){
+
+ var mind = this.__gap,partial,value = holder[key];
+ // If the value has a toJSON method, call it to obtain a replacement value.
+ if(value && qx.lang.Type.isFunction(value.toJSON)){
+
+ value = value.toJSON(key);
+ } else if(qx.lang.Type.isDate(value)){
+
+ value = this.dateToJSON(value);
+ };
+ // If we were called with a replacer function, then call the replacer to
+ // obtain a replacement value.
+ if(typeof this.__rep === 'function'){
+
+ value = this.__rep.call(holder, key, value);
+ };
+ if(value === null){
+
+ return 'null';
+ };
+ if(value === undefined){
+
+ return undefined;
+ };
+ // What happens next depends on the value's type.
+ switch(qx.lang.Type.getClass(value)){case 'String':
+ return this.__quote(value);case 'Number':
+ // JSON numbers must be finite. Encode non-finite numbers as null.
+ return isFinite(value) ? String(value) : 'null';case 'Boolean':
+ // If the value is a boolean or null, convert it to a string. Note:
+ // typeof null does not produce 'null'. The case is included here in
+ // the remote chance that this gets fixed someday.
+ return String(value);case 'Array':
+ // Make an array to hold the partial results of stringifying this array value.
+ this.__gap += this.__indent;
+ partial = [];
+ if(this.__stack.indexOf(value) !== -1){
+
+ throw new TypeError("Cannot stringify a recursive object.");
+ };
+ this.__stack.push(value);
+ // The value is an array. Stringify every element. Use null as a placeholder
+ // for non-JSON values.
+ var length = value.length;
+ for(var i = 0;i < length;i += 1){
+
+ partial[i] = this.__str(i, value) || 'null';
+ };
+ this.__stack.pop();
+ // Join all of the elements together, separated with commas, and wrap them in
+ // brackets.
+ if(partial.length === 0){
+
+ var string = '[]';
+ } else if(this.__gap){
+
+ string = '[\n' + this.__gap + partial.join(',\n' + this.__gap) + '\n' + mind + ']';
+ } else {
+
+ string = '[' + partial.join(',') + ']';
+ };
+ this.__gap = mind;
+ return string;case 'Object':
+ // Make an array to hold the partial results of stringifying this object value.
+ this.__gap += this.__indent;
+ partial = [];
+ if(this.__stack.indexOf(value) !== -1){
+
+ throw new TypeError("Cannot stringify a recursive object.");
+ };
+ this.__stack.push(value);
+ // If the replacer is an array, use it to select the members to be stringified.
+ if(this.__rep && typeof this.__rep === 'object'){
+
+ var length = this.__rep.length;
+ for(var i = 0;i < length;i += 1){
+
+ var k = this.__rep[i];
+ if(typeof k === 'string'){
+
+ var v = this.__str(k, value);
+ if(v){
+
+ partial.push(this.__quote(k) + (this.__gap ? ': ' : ':') + v);
+ };
+ };
+ };
+ } else {
+
+ // Otherwise, iterate through all of the keys in the object.
+ for(var k in value){
+
+ if(Object.hasOwnProperty.call(value, k)){
+
+ var v = this.__str(k, value);
+ if(v){
+
+ partial.push(this.__quote(k) + (this.__gap ? ': ' : ':') + v);
+ };
+ };
+ };
+ };
+ this.__stack.pop();
+ // Join all of the member texts together, separated with commas,
+ // and wrap them in braces.
+ if(partial.length === 0){
+
+ var string = '{}';
+ } else if(this.__gap){
+
+ string = '{\n' + this.__gap + partial.join(',\n' + this.__gap) + '\n' + mind + '}';
+ } else {
+
+ string = '{' + partial.join(',') + '}';
+ };
+ this.__gap = mind;
+ return string;};
+ },
+ /**
+ * Convert a date to JSON
+ *
+ * @param date {Date} The date to convert
+ * @return {String} The JSON representation of the date
+ */
+ dateToJSON : function(date){
+
+ // Format integers to have at least two digits.
+ var f2 = function(n){
+
+ return n < 10 ? '0' + n : n;
+ };
+ var f3 = function(n){
+
+ var value = f2(n);
+ return n < 100 ? '0' + value : value;
+ };
+ return isFinite(date.valueOf()) ? date.getUTCFullYear() + '-' + f2(date.getUTCMonth() + 1) + '-' + f2(date.getUTCDate()) + 'T' + f2(date.getUTCHours()) + ':' + f2(date.getUTCMinutes()) + ':' + f2(date.getUTCSeconds()) + '.' + f3(date.getUTCMilliseconds()) + 'Z' : null;
+ },
+ /**
+ * If the string contains no control characters, no quote characters, and no
+ * backslash characters, then we can safely slap some quotes around it.
+ * Otherwise we must also replace the offending characters with safe escape
+ * sequences.
+ *
+ * @param string {String} The string to quote
+ * @return {String} The quoted string
+ */
+ __quote : function(string){
+
+ var meta = {
+ // table of character substitutions
+ '\b' : '\\b',
+ '\t' : '\\t',
+ '\n' : '\\n',
+ '\f' : '\\f',
+ '\r' : '\\r',
+ '"' : '\\"',
+ '\\' : '\\\\'
+ };
+ var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+ escapable.lastIndex = 0;
+ if(escapable.test(string)){
+
+ return '"' + string.replace(escapable, function(a){
+
+ var c = meta[a];
+ return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"';
+ } else {
+
+ return '"' + string + '"';
+ };
+ },
+ /**
+ * This method parses a JSON text to produce an object or array.
+ * It can throw a SyntaxError exception.
+ *
+ * @param text {String} JSON string to parse
+ *
+ * @param reviver {Function?} Optional reviver function to filter and
+ * transform the results
+ *
+ * @return {Object} The parsed JSON object
+ *
+ * @lint ignoreDeprecated(eval)
+ */
+ parse : function(text, reviver){
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+ cx.lastIndex = 0;
+ // Parsing happens in four stages. In the first stage, we replace certain
+ // Unicode characters with escape sequences. JavaScript handles many characters
+ // incorrectly, either silently deleting them, or treating them as line endings.
+ if(cx.test(text)){
+
+ text = text.replace(cx, function(a){
+
+ return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ };
+ // In the second stage, we run the text against regular expressions that look
+ // for non-JSON patterns. We are especially concerned with '()' and 'new'
+ // because they can cause invocation, and '=' because it can cause mutation.
+ // But just to be safe, we want to reject all unexpected forms.
+ // We split the second stage into 4 regexp operations in order to work around
+ // crippling inefficiencies in IE's and Safari's regexp engines. First we
+ // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+ // replace all simple value tokens with ']' characters. Third, we delete all
+ // open brackets that follow a colon or comma or that begin the text. Finally,
+ // we look to see that the remaining characters are only whitespace or ']' or
+ // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+ if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))){
+
+ // In the third stage we use the eval function to compile the text into a
+ // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+ // in JavaScript: it can begin a block or an object literal. We wrap the text
+ // in parens to eliminate the ambiguity.
+ var j = eval('(' + text + ')');
+ // In the optional fourth stage, we recursively walk the new structure, passing
+ // each name/value pair to a reviver function for possible transformation.
+ return typeof reviver === 'function' ? this.__walk({
+ '' : j
+ }, '', reviver) : j;
+ };
+ // If the text is not JSON parseable, then a SyntaxError is thrown.
+ throw new SyntaxError('JSON.parse');
+ },
+ /**
+ * The walk method is used to recursively walk the resulting structure so
+ * that modifications can be made.
+ *
+ * @param holder {Object} the root object
+ * @param key {String} walk holder[key]
+ * @param reviver {Function} callback, which is called on every node.
+ * @return {var} The reviver's return value
+ */
+ __walk : function(holder, key, reviver){
+
+ var value = holder[key];
+ if(value && typeof value === 'object'){
+
+ for(var k in value){
+
+ if(Object.hasOwnProperty.call(value, k)){
+
+ var v = this.__walk(value, k, reviver);
+ if(v !== undefined){
+
+ value[k] = v;
+ } else {
+
+ delete value[k];
+ };
+ };
+ };
+ };
+ return reviver.call(holder, key, value);
+ }
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Sebastian Werner (wpbasti)
+ * Andreas Ecker (ecker)
+
+ ======================================================================
+
+ This class contains code based on the following work:
+
+ * Mootools
+ http://mootools.net
+ Version 1.1.1
+
+ Copyright:
+ 2007 Valerio Proietti
+
+ License:
+ MIT: http://www.opensource.org/licenses/mit-license.php
+
+************************************************************************ */
+/* ************************************************************************
+
+#require(qx.lang.Array)
+#ignore(qx.core.Object)
+#ignore(qx.event.GlobalError)
+
+************************************************************************ */
+/**
+ * Collection of helper methods operating on functions.
+ */
+qx.Bootstrap.define("qx.lang.Function", {
+ statics : {
+ /**
+ * Extract the caller of a function from the arguments variable.
+ * This will not work in Opera < 9.6.
+ *
+ * @param args {arguments} The local arguments variable
+ * @return {Function} A reference to the calling function or "undefined" if caller is not supported.
+ */
+ getCaller : function(args){
+
+ return args.caller ? args.caller.callee : args.callee.caller;
+ },
+ /**
+ * Try to get a sensible textual description of a function object.
+ * This may be the class/mixin and method name of a function
+ * or at least the signature of the function.
+ *
+ * @param fcn {Function} function the get the name for.
+ * @return {String} Name of the function.
+ */
+ getName : function(fcn){
+
+ if(fcn.displayName){
+
+ return fcn.displayName;
+ };
+ if(fcn.$$original || fcn.wrapper || fcn.classname){
+
+ return fcn.classname + ".constructor()";
+ };
+ if(fcn.$$mixin){
+
+ //members
+ for(var key in fcn.$$mixin.$$members){
+
+ if(fcn.$$mixin.$$members[key] == fcn){
+
+ return fcn.$$mixin.name + ".prototype." + key + "()";
+ };
+ };
+ // statics
+ for(var key in fcn.$$mixin){
+
+ if(fcn.$$mixin[key] == fcn){
+
+ return fcn.$$mixin.name + "." + key + "()";
+ };
+ };
+ };
+ if(fcn.self){
+
+ var clazz = fcn.self.constructor;
+ if(clazz){
+
+ // members
+ for(var key in clazz.prototype){
+
+ if(clazz.prototype[key] == fcn){
+
+ return clazz.classname + ".prototype." + key + "()";
+ };
+ };
+ // statics
+ for(var key in clazz){
+
+ if(clazz[key] == fcn){
+
+ return clazz.classname + "." + key + "()";
+ };
+ };
+ };
+ };
+ var fcnReResult = fcn.toString().match(/function\s*(\w*)\s*\(.*/);
+ if(fcnReResult && fcnReResult.length >= 1 && fcnReResult[1]){
+
+ return fcnReResult[1] + "()";
+ };
+ return 'anonymous()';
+ },
+ /**
+ * Evaluates JavaScript code globally
+ *
+ * @lint ignoreDeprecated(eval)
+ *
+ * @param data {String} JavaScript commands
+ * @return {var} Result of the execution
+ */
+ globalEval : function(data){
+
+ if(window.execScript){
+
+ return window.execScript(data);
+ } else {
+
+ return eval.call(window, data);
+ };
+ },
+ /**
+ * empty function
+ * @deprecated {2.1} Please use a new empty function.
+ */
+ empty : function(){
+ },
+ /**
+ * Simply return true.
+ * @deprecated {2.1} Please use a custom function.
+ * @return {Boolean} Always returns true.
+ */
+ returnTrue : function(){
+
+ return true;
+ },
+ /**
+ * Simply return false.
+ * @deprecated {2.1} Please use a custom function.
+ * @return {Boolean} Always returns false.
+ */
+ returnFalse : function(){
+
+ return false;
+ },
+ /**
+ * Simply return null.
+ * @deprecated {2.1} Please use a custom function.
+ * @return {var} Always returns null.
+ */
+ returnNull : function(){
+
+ return null;
+ },
+ /**
+ * Return "this".
+ * @deprecated {2.1} Please use a custom function.
+ * @return {Object} Always returns "this".
+ */
+ returnThis : function(){
+
+ return this;
+ },
+ /**
+ * Simply return 0.
+ * @deprecated {2.1} Please use a custom function.
+ * @return {Number} Always returns 0.
+ */
+ returnZero : function(){
+
+ return 0;
+ },
+ /**
+ * Base function for creating functional closures which is used by most other methods here.
+ *
+ * *Syntax*
+ *
+ * var createdFunction = qx.lang.Function.create(myFunction, [options]);+ * + * @param func {Function} Original function to wrap + * @param options {Map?} Map of options + *
qx.lang.Function.bind(myFunction, [self, [varargs...]]);+ * + * *Example* + * + *
+ * function myFunction()
+ * {
+ * this.setStyle('color', 'red');
+ * // note that 'this' here refers to myFunction, not an element
+ * // we'll need to bind this function to the element we want to alter
+ * };
+ *
+ * var myBoundFunction = qx.lang.Function.bind(myFunction, myElement);
+ * myBoundFunction(); // this will make the element myElement red.
+ *
+ *
+ * If you find yourself using this static method a lot, you may be
+ * interested in the bindTo() method in the mixin qx.core.MBindTo.
+ *
+ * @see qx.core.MBindTo
+ *
+ * @param func {Function} Original function to wrap
+ * @param self {Object ? null} The object that the "this" of the function will refer to.
+ * @param varargs {arguments ? null} The arguments to pass to the function.
+ * @return {Function} The bound function.
+ */
+ bind : function(func, self, varargs){
+
+ return this.create(func, {
+ self : self,
+ args : arguments.length > 2 ? qx.lang.Array.fromArguments(arguments, 2) : null
+ });
+ },
+ /**
+ * Returns a function whose arguments are pre-configured.
+ *
+ * *Syntax*
+ *
+ * qx.lang.Function.curry(myFunction, [varargs...]);+ * + * *Example* + * + *
+ * function myFunction(elem) {
+ * elem.setStyle('color', 'red');
+ * };
+ *
+ * var myBoundFunction = qx.lang.Function.curry(myFunction, myElement);
+ * myBoundFunction(); // this will make the element myElement red.
+ *
+ *
+ * @param func {Function} Original function to wrap
+ * @param varargs {arguments} The arguments to pass to the function.
+ * @return {var} The pre-configured function.
+ */
+ curry : function(func, varargs){
+
+ return this.create(func, {
+ args : arguments.length > 1 ? qx.lang.Array.fromArguments(arguments, 1) : null
+ });
+ },
+ /**
+ * Returns a function which could be used as a listener for a native event callback.
+ *
+ * *Syntax*
+ *
+ * qx.lang.Function.listener(myFunction, [self, [varargs...]]);+ * + * @param func {Function} Original function to wrap + * @param self {Object ? null} The object that the "this" of the function will refer to. + * @param varargs {arguments ? null} The arguments to pass to the function. + * @return {var} The bound function. + */ + listener : function(func, self, varargs){ + + if(arguments.length < 3){ + + return function(event){ + + // Directly execute, but force first parameter to be the event object. + return func.call(self || this, event || window.event); + }; + } else { + + var optargs = qx.lang.Array.fromArguments(arguments, 2); + return function(event){ + + var args = [event || window.event]; + // Append static arguments + args.push.apply(args, optargs); + // Finally execute original method + func.apply(self || this, args); + }; + }; + }, + /** + * Tries to execute the function. + * + * *Syntax* + * + *
var result = qx.lang.Function.attempt(myFunction, [self, [varargs...]]);+ * + * *Example* + * + *
+ * var myObject = {
+ * 'cow': 'moo!'
+ * };
+ *
+ * var myFunction = function()
+ * {
+ * for(var i = 0; i < arguments.length; i++) {
+ * if(!this[arguments[i]]) throw('doh!');
+ * }
+ * };
+ *
+ * var result = qx.lang.Function.attempt(myFunction, myObject, 'pig', 'cow'); // false
+ *
+ *
+ * @param func {Function} Original function to wrap
+ * @param self {Object ? null} The object that the "this" of the function will refer to.
+ * @param varargs {arguments ? null} The arguments to pass to the function.
+ * @return {Boolean|var} false if an exception is thrown, else the function's return.
+ */
+ attempt : function(func, self, varargs){
+
+ return this.create(func, {
+ self : self,
+ attempt : true,
+ args : arguments.length > 2 ? qx.lang.Array.fromArguments(arguments, 2) : null
+ })();
+ },
+ /**
+ * Delays the execution of a function by a specified duration.
+ *
+ * *Syntax*
+ *
+ * var timeoutID = qx.lang.Function.delay(myFunction, [delay, [self, [varargs...]]]);+ * + * *Example* + * + *
+ * var myFunction = function(){ alert('moo! Element id is: ' + this.id); };
+ * //wait 50 milliseconds, then call myFunction and bind myElement to it
+ * qx.lang.Function.delay(myFunction, 50, myElement); // alerts: 'moo! Element id is: ... '
+ *
+ * // An anonymous function, example
+ * qx.lang.Function.delay(function(){ alert('one second later...'); }, 1000); //wait a second and alert
+ *
+ *
+ * @param func {Function} Original function to wrap
+ * @param delay {Integer} The duration to wait (in milliseconds).
+ * @param self {Object ? null} The object that the "this" of the function will refer to.
+ * @param varargs {arguments ? null} The arguments to pass to the function.
+ * @return {Integer} The JavaScript Timeout ID (useful for clearing delays).
+ */
+ delay : function(func, delay, self, varargs){
+
+ return this.create(func, {
+ delay : delay,
+ self : self,
+ args : arguments.length > 3 ? qx.lang.Array.fromArguments(arguments, 3) : null
+ })();
+ },
+ /**
+ * Executes a function in the specified intervals of time
+ *
+ * *Syntax*
+ *
+ * var intervalID = qx.lang.Function.periodical(myFunction, [period, [self, [varargs...]]]);+ * + * *Example* + * + *
+ * var Site = { counter: 0 };
+ * var addCount = function(){ this.counter++; };
+ * qx.lang.Function.periodical(addCount, 1000, Site); // will add the number of seconds at the Site
+ *
+ *
+ * @param func {Function} Original function to wrap
+ * @param interval {Integer} The duration of the intervals between executions.
+ * @param self {Object ? null} The object that the "this" of the function will refer to.
+ * @param varargs {arguments ? null} The arguments to pass to the function.
+ * @return {Integer} The Interval ID (useful for clearing a periodical).
+ */
+ periodical : function(func, interval, self, varargs){
+
+ return this.create(func, {
+ periodical : interval,
+ self : self,
+ args : arguments.length > 3 ? qx.lang.Array.fromArguments(arguments, 3) : null
+ })();
+ }
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Fabian Jakobs (fjakobs)
+ ________________________________________________________________________
+
+ This class contains code based on the following work:
+
+ http://www.JSON.org/json2.js
+ 2009-06-29
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+************************************************************************ */
+/**
+ * JSON (JavaScript Object Notation) parser, serializer for qooxdoo
+ *
+ * This class implements EcmaScript 3.1 JSON support.
+ *
+ * http://wiki.ecmascript.org/doku.php?id=es3.1:json_support
+ *
+ * If the browser supports native JSON the browser implementation is used.
+ */
+qx.Bootstrap.define("qx.lang.Json", {
+ statics : {
+ /**
+ * {JSON} The JSON object to use. If the browser has native JSON support
+ * this member points to window.JSON. Otherwise it points to
+ * the qooxdoo implementation {@link JsonImpl}.
+ */
+ JSON : true ? window.JSON : new qx.lang.JsonImpl(),
+ /**
+ * This method produces a JSON text from a JavaScript value.
+ *
+ * When an object value is found, if the object contains a toJSON
+ * method, its toJSON method will be called and the result will be
+ * stringified. A toJSON method does not serialize: it returns the
+ * value represented by the name/value pair that should be serialized,
+ * or undefined if nothing should be serialized. The toJSON method
+ * will be passed the key associated with the value, and this will be
+ * bound to the object holding the key.
+ *
+ * For example, this would serialize Dates as ISO strings.
+ *
+ *
+ * Date.prototype.toJSON = function (key) {
+ * function f(n) {
+ * // Format integers to have at least two digits.
+ * return n < 10 ? '0' + n : n;
+ * }
+ *
+ * return this.getUTCFullYear() + '-' +
+ * f(this.getUTCMonth() + 1) + '-' +
+ * f(this.getUTCDate()) + 'T' +
+ * f(this.getUTCHours()) + ':' +
+ * f(this.getUTCMinutes()) + ':' +
+ * f(this.getUTCSeconds()) + 'Z';
+ * };
+ *
+ *
+ * You can provide an optional replacer method. It will be passed the
+ * key and value of each member, with this bound to the containing
+ * object. The value that is returned from your method will be
+ * serialized. If your method returns undefined, then the member will
+ * be excluded from the serialization.
+ *
+ * If the replacer parameter is an array of strings, then it will be
+ * used to select the members to be serialized. It filters the results
+ * such that only members with keys listed in the replacer array are
+ * stringified.
+ *
+ * Values that do not have JSON representations, such as undefined or
+ * functions, will not be serialized. Such values in objects will be
+ * dropped; in arrays they will be replaced with null. You can use
+ * a replacer function to replace those with JSON values.
+ * JSON.stringify(undefined) returns undefined.
+ *
+ * The optional space parameter produces a stringification of the
+ * value that is filled with line breaks and indentation to make it
+ * easier to read.
+ *
+ * If the space parameter is a non-empty string, then that string will
+ * be used for indentation. If the space parameter is a number, then
+ * the indentation will be that many spaces.
+ *
+ * Example:
+ *
+ *
+ * text = JSON.stringify(['e', {pluribus: 'unum'}]);
+ * // text is '["e",{"pluribus":"unum"}]'
+ *
+ *
+ * text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ * // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+ *
+ * text = JSON.stringify([new Date()], function (key, value) {
+ * return this[key] instanceof Date ?
+ * 'Date(' + this[key] + ')' : value;
+ * });
+ * // text is '["Date(---current time---)"]'
+ *
+ *
+ * @signature function(value, replacer, space)
+ *
+ * @param value {var} any JavaScript value, usually an object or array.
+ *
+ * @param replacer {Function?} an optional parameter that determines how
+ * object values are stringified for objects. It can be a function or an
+ * array of strings.
+ *
+ * @param space {String?} an optional parameter that specifies the
+ * indentation of nested structures. If it is omitted, the text will
+ * be packed without extra whitespace. If it is a number, it will specify
+ * the number of spaces to indent at each level. If it is a string
+ * (such as '\t' or ' '), it contains the characters used to indent
+ * at each level.
+ *
+ * @return {String} The JSON string of the value
+ */
+ stringify : null,
+ // will be set in the defer block
+ /**
+ * This method parses a JSON text to produce an object or array.
+ * It can throw a SyntaxError exception.
+ *
+ * The optional reviver parameter is a function that can filter and
+ * transform the results. It receives each of the keys and values,
+ * and its return value is used instead of the original value.
+ * If it returns what it received, then the structure is not modified.
+ * If it returns undefined then the member is deleted.
+ *
+ * Example:
+ *
+ *
+ * // Parse the text. Values that look like ISO date strings will
+ * // be converted to Date objects.
+ *
+ * myData = JSON.parse(text, function (key, value)
+ * {
+ * if (typeof value === 'string')
+ * {
+ * var a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ * if (a) {
+ * return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]));
+ * }
+ * }
+ * return value;
+ * });
+ *
+ * myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ * var d;
+ * if (typeof value === 'string' &&
+ * value.slice(0, 5) === 'Date(' &&
+ * value.slice(-1) === ')') {
+ * d = new Date(value.slice(5, -1));
+ * if (d) {
+ * return d;
+ * }
+ * }
+ * return value;
+ * });
+ *
+ *
+ * @signature function(text, reviver)
+ *
+ * @param text {String} JSON string to parse
+ *
+ * @param reviver {Function?} Optional reviver function to filter and
+ * transform the results
+ *
+ * @return {Object} The parsed JSON object
+ */
+ parse : null
+ },
+ defer : function(statics){
+
+ statics.stringify = statics.JSON.stringify;
+ statics.parse = statics.JSON.parse;
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2012 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (wittemann)
+
+************************************************************************ */
+/* ************************************************************************
+#require(qx.bom.storage.UserData#getLength)
+#require(qx.bom.storage.UserData#setItem)
+#require(qx.bom.storage.UserData#getItem)
+#require(qx.bom.storage.UserData#removeItem)
+#require(qx.bom.storage.UserData#clear)
+#require(qx.bom.storage.UserData#getKey)
+#require(qx.bom.storage.UserData#forEach)
+************************************************************************ */
+/**
+ * Fallback storage implementation usable in IE browsers. It is recommended to use
+ * these implementation only in IE < 8 because IE >= 8 supports
+ * {@link qx.bom.storage.Web}.
+ */
+qx.Bootstrap.define("qx.bom.storage.UserData", {
+ statics : {
+ __local : null,
+ __session : null,
+ // global id used as key for the storage
+ __id : 0,
+ /**
+ * Returns an instance of {@link qx.bom.storage.UserData} used to store
+ * data persistent.
+ * @return {qx.bom.storage.UserData} A storage instance.
+ */
+ getLocal : function(){
+
+ if(this.__local){
+
+ return this.__local;
+ };
+ return this.__local = new qx.bom.storage.UserData("local");
+ },
+ /**
+ * Returns an instance of {@link qx.bom.storage.UserData} used to store
+ * data persistent.
+ * @return {qx.bom.storage.UserData} A storage instance.
+ */
+ getSession : function(){
+
+ if(this.__session){
+
+ return this.__session;
+ };
+ return this.__session = new qx.bom.storage.UserData("session");
+ }
+ },
+ /**
+ * Create a new instance. Usually, you should take the static
+ * accessors to get your instance.
+ *
+ * @param storeName {String} type of storage.
+ */
+ construct : function(storeName){
+
+ // create a dummy DOM element used for storage
+ this.__el = document.createElement("div");
+ this.__el.style["display"] = "none";
+ document.getElementsByTagName("head")[0].appendChild(this.__el);
+ this.__el.addBehavior("#default#userdata");
+ this.__storeName = storeName;
+ // load the inital data which might be stored
+ this.__el.load(this.__storeName);
+ // set up the internal reference maps
+ this.__storage = {
+ };
+ this.__reference = {
+ };
+ // initialize
+ var value = this.__el.getAttribute("qx" + qx.bom.storage.UserData.__id);
+ while(value != undefined){
+
+ value = qx.lang.Json.parse(value);
+ // save the data in the internal storage
+ this.__storage[value.key] = value.value;
+ // save the reference
+ this.__reference[value.key] = "qx" + qx.bom.storage.UserData.__id;
+ qx.bom.storage.UserData.__id++;
+ value = this.__el.getAttribute("qx" + qx.bom.storage.UserData.__id);
+ };
+ },
+ members : {
+ __el : null,
+ __storeName : "qxtest",
+ // storage which holds the key and the value
+ __storage : null,
+ // reference store which holds the key and the key used to store
+ __reference : null,
+ /**
+ * Returns the map used to keep a in memory copy of the stored data.
+ * @return {Map} The stored data.
+ * @internal
+ */
+ getStorage : function(){
+
+ return this.__storage;
+ },
+ /**
+ * Returns the amount of key-value pairs stored.
+ * @return {Integer} The length of the storage.
+ */
+ getLength : function(){
+
+ return Object.keys(this.__storage).length;
+ },
+ /**
+ * Store an item in the storage.
+ *
+ * @param key {String} The identifier key.
+ * @param value {var} The data, which will be stored as JSON.
+ */
+ setItem : function(key, value){
+
+ // override case
+ if(this.__reference[key]){
+
+ var storageKey = this.__reference[key];
+ } else {
+
+ var storageKey = "qx" + qx.bom.storage.UserData.__id;
+ qx.bom.storage.UserData.__id++;
+ };
+ // build and save the data used to store both, key and value
+ var storageValue = qx.lang.Json.stringify({
+ key : key,
+ value : value
+ });
+ this.__el.setAttribute(storageKey, storageValue);
+ this.__el.save(this.__storeName);
+ // also update the internal mappings
+ this.__storage[key] = value;
+ this.__reference[key] = storageKey;
+ },
+ /**
+ * Returns the stored item.
+ *
+ * @param key {String} The identifier to get the data.
+ * @return {var} The stored data.
+ */
+ getItem : function(key){
+
+ return this.__storage[key] || null;
+ },
+ /**
+ * Removes an item form the storage.
+ * @param key {String} The identifier.
+ */
+ removeItem : function(key){
+
+ // check if the item is availabel
+ var storageName = this.__reference[key];
+ if(storageName == undefined){
+
+ return;
+ };
+ // remove the item
+ this.__el.removeAttribute(storageName);
+ // decrease the id because we removed one item
+ qx.bom.storage.UserData.__id--;
+ // update the internal maps
+ delete this.__storage[key];
+ delete this.__reference[key];
+ // check if we have deleted the last item
+ var lastStoreName = "qx" + qx.bom.storage.UserData.__id;
+ if(this.__el.getAttribute(lastStoreName)){
+
+ // if not, move the last item to the deleted spot
+ var lastItem = this.__el.getAttribute("qx" + qx.bom.storage.UserData.__id);
+ this.__el.removeAttribute(lastStoreName);
+ this.__el.setAttribute(storageName, lastItem);
+ // update the reference map
+ var lastKey = qx.lang.Json.parse(lastItem).key;
+ this.__reference[lastKey] = storageName;
+ };
+ this.__el.save(this.__storeName);
+ },
+ /**
+ * Deletes every stored item in the storage.
+ */
+ clear : function(){
+
+ // delete all entries from the storage
+ for(var key in this.__reference){
+
+ this.__el.removeAttribute(this.__reference[key]);
+ };
+ this.__el.save(this.__storeName);
+ // reset the internal maps
+ this.__storage = {
+ };
+ this.__reference = {
+ };
+ },
+ /**
+ * Returns the named key at the given index.
+ * @param index {Integer} The index in the storage.
+ * @return {String} The key stored at the given index.
+ */
+ getKey : function(index){
+
+ return Object.keys(this.__storage)[index];
+ },
+ /**
+ * Helper to access every stored item.
+ *
+ * @param callback {Function} A function which will be called for every item.
+ * The function will have two arguments, first the key and second the value
+ * of the stored data.
+ * @param scope {var} The scope of the function.
+ */
+ forEach : function(callback, scope){
+
+ var length = this.getLength();
+ for(var i = 0;i < length;i++){
+
+ var key = this.getKey(i);
+ callback.call(scope, key, this.getItem(key));
+ };
+ }
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2012 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (wittemann)
+
+************************************************************************ */
+/* ************************************************************************
+#require(qx.bom.storage.Memory#getLength)
+#require(qx.bom.storage.Memory#setItem)
+#require(qx.bom.storage.Memory#getItem)
+#require(qx.bom.storage.Memory#removeItem)
+#require(qx.bom.storage.Memory#clear)
+#require(qx.bom.storage.Memory#getKey)
+#require(qx.bom.storage.Memory#forEach)
+************************************************************************ */
+/**
+ * Fallback storage implementation which offers the same API as every other storage
+ * but is not persistent. Basically, its just a storage API on a JavaScript map.
+ */
+qx.Bootstrap.define("qx.bom.storage.Memory", {
+ statics : {
+ __local : null,
+ __session : null,
+ /**
+ * Returns an instance of {@link qx.bom.storage.Memory} which is of course
+ * not persisted on reload.
+ * @return {qx.bom.storage.Memory} A memory storage.
+ */
+ getLocal : function(){
+
+ if(this.__local){
+
+ return this.__local;
+ };
+ return this.__local = new qx.bom.storage.Memory();
+ },
+ /**
+ * Returns an instance of {@link qx.bom.storage.Memory} which is of course
+ * not persisted on reload.
+ * @return {qx.bom.storage.Memory} A memory storage.
+ */
+ getSession : function(){
+
+ if(this.__session){
+
+ return this.__session;
+ };
+ return this.__session = new qx.bom.storage.Memory();
+ }
+ },
+ construct : function(){
+
+ this.__storage = {
+ };
+ },
+ members : {
+ __storage : null,
+ /**
+ * Returns the internal used map.
+ * @return {Map} The storage.
+ * @internal
+ */
+ getStorage : function(){
+
+ return this.__storage;
+ },
+ /**
+ * Returns the amount of key-value pairs stored.
+ * @return {Integer} The length of the storage.
+ */
+ getLength : function(){
+
+ return Object.keys(this.__storage).length;
+ },
+ /**
+ * Store an item in the storage.
+ *
+ * @param key {String} The identifier key.
+ * @param value {var} The data, which will be stored as JSON.
+ */
+ setItem : function(key, value){
+
+ value = qx.lang.Json.stringify(value);
+ this.__storage[key] = value;
+ },
+ /**
+ * Returns the stored item.
+ *
+ * @param key {String} The identifier to get the data.
+ * @return {var} The stored data.
+ */
+ getItem : function(key){
+
+ var item = this.__storage[key];
+ if(qx.lang.Type.isString(item)){
+
+ item = qx.lang.Json.parse(item);
+ };
+ return item;
+ },
+ /**
+ * Removes an item form the storage.
+ * @param key {String} The identifier.
+ */
+ removeItem : function(key){
+
+ delete this.__storage[key];
+ },
+ /**
+ * Deletes every stored item in the storage.
+ */
+ clear : function(){
+
+ this.__storage = {
+ };
+ },
+ /**
+ * Returns the named key at the given index.
+ * @param index {Integer} The index in the storage.
+ * @return {String} The key stored at the given index.
+ */
+ getKey : function(index){
+
+ var keys = Object.keys(this.__storage);
+ return keys[index];
+ },
+ /**
+ * Helper to access every stored item.
+ *
+ * @param callback {Function} A function which will be called for every item.
+ * The function will have two arguments, first the key and second the value
+ * of the stored data.
+ * @param scope {var} The scope of the function.
+ */
+ forEach : function(callback, scope){
+
+ var length = this.getLength();
+ for(var i = 0;i < length;i++){
+
+ var key = this.getKey(i);
+ callback.call(scope, key, this.getItem(key));
+ };
+ }
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2011-2012 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (wittemann)
+ * Daniel Wagner (danielwagner)
+
+************************************************************************ */
+/**
+ * CSS/Style property manipulation module
+ */
+qx.Bootstrap.define("qx.module.Css", {
+ statics : {
+ /**
+ * Modifies the given style property on all elements in the collection.
+ *
+ * @attach {qxWeb}
+ * @param name {String} Name of the style property to modify
+ * @param value {var} The value to apply
+ * @return {qxWeb} The collection for chaining
+ */
+ setStyle : function(name, value){
+
+ if(/\w-\w/.test(name)){
+
+ name = qx.lang.String.camelCase(name);
+ };
+ for(var i = 0;i < this.length;i++){
+
+ qx.bom.element.Style.set(this[i], name, value);
+ };
+ return this;
+ },
+ /**
+ * Returns the value of the given style property for the first item in the
+ * collection.
+ *
+ * @attach {qxWeb}
+ * @param name {String} Style property name
+ * @return {var} Style property value
+ */
+ getStyle : function(name){
+
+ if(this[0]){
+
+ if(/\w-\w/.test(name)){
+
+ name = qx.lang.String.camelCase(name);
+ };
+ return qx.bom.element.Style.get(this[0], name);
+ };
+ return null;
+ },
+ /**
+ * Sets multiple style properties for each item in the collection.
+ *
+ * @attach {qxWeb}
+ * @param styles {Map} A map of style property name/value pairs
+ * @return {qxWeb} The collection for chaining
+ */
+ setStyles : function(styles){
+
+ for(var name in styles){
+
+ this.setStyle(name, styles[name]);
+ };
+ return this;
+ },
+ /**
+ * Returns the values of multiple style properties for each item in the
+ * collection
+ *
+ * @attach {qxWeb}
+ * @param names {String[]} List of style property names
+ * @return {Map} Map of style property name/value pairs
+ */
+ getStyles : function(names){
+
+ var styles = {
+ };
+ for(var i = 0;i < names.length;i++){
+
+ styles[names[i]] = this.getStyle(names[i]);
+ };
+ return styles;
+ },
+ /**
+ * Adds a class name to each element in the collection
+ *
+ * @attach {qxWeb}
+ * @param name {String} Class name
+ * @return {qxWeb} The collection for chaining
+ */
+ addClass : function(name){
+
+ for(var i = 0;i < this.length;i++){
+
+ qx.bom.element.Class.add(this[i], name);
+ };
+ return this;
+ },
+ /**
+ * Adds multiple class names to each element in the collection
+ *
+ * @attach {qxWeb}
+ * @param names {String[]} List of class names to add
+ * @return {qxWeb} The collection for chaining
+ */
+ addClasses : function(names){
+
+ for(var i = 0;i < this.length;i++){
+
+ qx.bom.element.Class.addClasses(this[i], names);
+ };
+ return this;
+ },
+ /**
+ * Removes a class name from each element in the collection
+ *
+ * @attach {qxWeb}
+ * @param name {String} The class name to remove
+ * @return {qxWeb} The collection for chaining
+ */
+ removeClass : function(name){
+
+ for(var i = 0;i < this.length;i++){
+
+ qx.bom.element.Class.remove(this[i], name);
+ };
+ return this;
+ },
+ /**
+ * Removes multiple class names from each element in the collection
+ *
+ * @attach {qxWeb}
+ * @param names {String[]} List of class names to remove
+ * @return {qxWeb} The collection for chaining
+ */
+ removeClasses : function(names){
+
+ for(var i = 0;i < this.length;i++){
+
+ qx.bom.element.Class.removeClasses(this[i], names);
+ };
+ return this;
+ },
+ /**
+ * Checks if the first element in the collection has the given class name
+ *
+ * @attach {qxWeb}
+ * @param name {String} Class name to check for
+ * @return {Boolean} true if the first item has the given class name
+ */
+ hasClass : function(name){
+
+ if(!this[0]){
+
+ return false;
+ };
+ return qx.bom.element.Class.has(this[0], name);
+ },
+ /**
+ * Returns the class name of the first element in the collection
+ *
+ * @attach {qxWeb}
+ * @return {String} Class name
+ */
+ getClass : function(){
+
+ if(!this[0]){
+
+ return "";
+ };
+ return qx.bom.element.Class.get(this[0]);
+ },
+ /**
+ * Toggles the given class name on each item in the collection
+ *
+ * @attach {qxWeb}
+ * @param name {String} Class name
+ * @return {qxWeb} The collection for chaining
+ */
+ toggleClass : function(name){
+
+ var bCls = qx.bom.element.Class;
+ for(var i = 0,l = this.length;i < l;i++){
+
+ bCls.has(this[i], name) ? bCls.remove(this[i], name) : bCls.add(this[i], name);
+ };
+ return this;
+ },
+ /**
+ * Toggles the given list of class names on each item in the collection
+ *
+ * @attach {qxWeb}
+ * @param names {String[]} Class names
+ * @return {qxWeb} The collection for chaining
+ */
+ toggleClasses : function(names){
+
+ for(var i = 0,l = names.length;i < l;i++){
+
+ this.toggleClass(names[i]);
+ };
+ return this;
+ },
+ /**
+ * Replaces a class name on each element in the collection
+ *
+ * @attach {qxWeb}
+ * @param oldName {String} Class name to remove
+ * @param newName {String} Class name to add
+ * @return {qxWeb} The collection for chaining
+ */
+ replaceClass : function(oldName, newName){
+
+ for(var i = 0,l = this.length;i < l;i++){
+
+ qx.bom.element.Class.replace(this[i], oldName, newName);
+ };
+ return this;
+ },
+ /**
+ * Returns the rendered height of the first element in the collection.
+ * @attach {qxWeb}
+ * @return {Number} The first item's rendered height
+ */
+ getHeight : function(){
+
+ var elem = this[0];
+ if(elem){
+
+ if(qx.dom.Node.isElement(elem)){
+
+ return qx.bom.element.Dimension.getHeight(elem);
+ } else if(qx.dom.Node.isDocument(elem)){
+
+ return qx.bom.Document.getHeight(qx.dom.Node.getWindow(elem));
+ } else if(qx.dom.Node.isWindow(elem)){
+
+ return qx.bom.Viewport.getHeight(elem);
+ };;
+ };
+ return null;
+ },
+ /**
+ * Returns the rendered width of the first element in the collection
+ * @attach {qxWeb}
+ * @return {Number} The first item's rendered width
+ */
+ getWidth : function(){
+
+ var elem = this[0];
+ if(elem){
+
+ if(qx.dom.Node.isElement(elem)){
+
+ return qx.bom.element.Dimension.getWidth(elem);
+ } else if(qx.dom.Node.isDocument(elem)){
+
+ return qx.bom.Document.getWidth(qx.dom.Node.getWindow(elem));
+ } else if(qx.dom.Node.isWindow(elem)){
+
+ return qx.bom.Viewport.getWidth(elem);
+ };;
+ };
+ return null;
+ },
+ /**
+ * Returns the computed location of the given element in the context of the
+ * document dimensions.
+ *
+ * @attach {qxWeb}
+ * @return {Map} A map with the keys left, top,
+ * right and bottom which contains the distance
+ * of the element relative to the document.
+ */
+ getOffset : function(){
+
+ var elem = this[0];
+ if(elem){
+
+ return qx.bom.element.Location.get(elem);
+ };
+ return null;
+ },
+ /**
+ * Returns the content height of the first element in the collection.
+ * This is the maximum height the element can use, excluding borders,
+ * margins, padding or scroll bars.
+ * @attach {qxWeb}
+ * @return {Number} Computed content height
+ */
+ getContentHeight : function(){
+
+ var obj = this[0];
+ if(qx.dom.Node.isElement(obj)){
+
+ return qx.bom.element.Dimension.getContentHeight(obj);
+ };
+ return null;
+ },
+ /**
+ * Returns the content width of the first element in the collection.
+ * This is the maximum width the element can use, excluding borders,
+ * margins, padding or scroll bars.
+ * @attach {qxWeb}
+ * @return {Number} Computed content width
+ */
+ getContentWidth : function(){
+
+ var obj = this[0];
+ if(qx.dom.Node.isElement(obj)){
+
+ return qx.bom.element.Dimension.getContentWidth(obj);
+ };
+ return null;
+ },
+ /**
+ * Returns the distance between the first element in the collection and its
+ * offset parent
+ *
+ * @attach {qxWeb}
+ * @return {Map} a map with the keys left and top
+ * containing the distance between the elements
+ */
+ getPosition : function(){
+
+ var obj = this[0];
+ if(qx.dom.Node.isElement(obj)){
+
+ return qx.bom.element.Location.getPosition(obj);
+ };
+ return null;
+ },
+ /**
+ * Includes a Stylesheet file
+ *
+ * @attachStatic {qxWeb}
+ * @param uri {String} The stylesheet's URI
+ * @param doc {Document?} Document to modify
+ */
+ includeStylesheet : function(uri, doc){
+
+ qx.bom.Stylesheet.includeFile(uri, doc);
+ },
+ /**
+ * Hides all elements in the collection by setting their "display"
+ * style to "none". The previous value is stored so it can be re-applied
+ * when {@link #show} is called.
+ *
+ * @attach {qxWeb}
+ * @return {qxWeb} The collection for chaining
+ */
+ hide : function(){
+
+ for(var i = 0,l = this.length;i < l;i++){
+
+ var item = this.slice(i, i + 1);
+ var prevStyle = item.getStyle("display");
+ if(prevStyle !== "none"){
+
+ item[0].$$qPrevDisp = prevStyle;
+ item.setStyle("display", "none");
+ };
+ };
+ return this;
+ },
+ /**
+ * Shows any elements with "display: none" in the collection. If an element
+ * was hidden by using the {@link #hide} method, its previous
+ * "display" style value will be re-applied. Otherwise, the
+ * default "display" value for the element type will be applied.
+ *
+ * @attach {qxWeb}
+ * @return {qxWeb} The collection for chaining
+ */
+ show : function(){
+
+ for(var i = 0,l = this.length;i < l;i++){
+
+ var item = this.slice(i, i + 1);
+ var currentVal = item.getStyle("display");
+ var prevVal = item[0].$$qPrevDisp;
+ var newVal;
+ if(currentVal == "none"){
+
+ if(prevVal && prevVal != "none"){
+
+ newVal = prevVal;
+ } else {
+
+ var doc = qxWeb.getDocument(item[0]);
+ newVal = qx.module.Css.__getDisplayDefault(item[0].tagName, doc);
+ };
+ item.setStyle("display", newVal);
+ item[0].$$qPrevDisp = "none";
+ };
+ };
+ return this;
+ },
+ /**
+ * Maps HTML elements to their default "display" style values.
+ */
+ __displayDefaults : {
+ },
+ /**
+ * Attempts tp determine the default "display" style value for
+ * elements with the given tag name.
+ *
+ * @param tagName {String} Tag name
+ * @param doc {Document?} Document element. Default: The current document
+ * @return {String} The default "display" value, e.g. inline
+ * or block
+ */
+ __getDisplayDefault : function(tagName, doc){
+
+ var defaults = qx.module.Css.__displayDefaults;
+ if(!defaults[tagName]){
+
+ var docu = doc || document;
+ var tempEl = qxWeb(docu.createElement(tagName)).appendTo(doc.body);
+ defaults[tagName] = tempEl.getStyle("display");
+ tempEl.remove();
+ };
+ return defaults[tagName] || "";
+ }
+ },
+ defer : function(statics){
+
+ qxWeb.$attach({
+ "setStyle" : statics.setStyle,
+ "getStyle" : statics.getStyle,
+ "setStyles" : statics.setStyles,
+ "getStyles" : statics.getStyles,
+ "addClass" : statics.addClass,
+ "addClasses" : statics.addClasses,
+ "removeClass" : statics.removeClass,
+ "removeClasses" : statics.removeClasses,
+ "hasClass" : statics.hasClass,
+ "getClass" : statics.getClass,
+ "toggleClass" : statics.toggleClass,
+ "toggleClasses" : statics.toggleClasses,
+ "replaceClass" : statics.replaceClass,
+ "getHeight" : statics.getHeight,
+ "getWidth" : statics.getWidth,
+ "getOffset" : statics.getOffset,
+ "getContentHeight" : statics.getContentHeight,
+ "getContentWidth" : statics.getContentWidth,
+ "getPosition" : statics.getPosition,
+ "hide" : statics.hide,
+ "show" : statics.show
+ });
+ qxWeb.$attachStatic({
+ "includeStylesheet" : statics.includeStylesheet
+ });
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2012 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Martin Wittemann (wittemann)
+
+************************************************************************ */
+/**
+ * This class takes care of the normalization of the native 'String' object.
+ * Therefore it checks the availability of the following methods and appends
+ * it, if not available. This means you can use the methods during
+ * development in every browser. For usage samples, check out the attached links.
+ *
+ * *trim*:
+ * MDN documentation |
+ * Annotated ES5 Spec
+ */
+qx.Bootstrap.define("qx.lang.normalize.String", {
+ defer : function(){
+
+ // trim
+ if(!qx.core.Environment.get("ecmascript.string.trim")){
+
+ String.prototype.trim = function(context){
+
+ return this.replace(/^\s+|\s+$/g, '');
+ };
+ };
+ }
+});
+
+/* ************************************************************************
+
+ qooxdoo - the new era of web development
+
+ http://qooxdoo.org
+
+ Copyright:
+ 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de
+
+ License:
+ LGPL: http://www.gnu.org/licenses/lgpl.html
+ EPL: http://www.eclipse.org/org/documents/epl-v10.php
+ See the LICENSE file in the project's top-level directory for details.
+
+ Authors:
+ * Sebastian Werner (wpbasti)
+ * Andreas Ecker (ecker)
+
+ ======================================================================
+
+ This class contains code based on the following work:
+
+ * Mootools
+ http://mootools.net/
+ Version 1.1.1
+
+ Copyright:
+ (c) 2007 Valerio Proietti
+
+ License:
+ MIT: http://www.opensource.org/licenses/mit-license.php
+
+ and
+
+ * XRegExp
+ http://xregexp.com/
+ Version 1.5
+
+ Copyright:
+ (c) 2006-2007, Steven Levithan
+
+ License:
+ MIT: http://www.opensource.org/licenses/mit-license.php
+
+ Authors:
+ * Steven Levithan
+
+************************************************************************ */
+/* ************************************************************************
+#require(qx.lang.normalize.String)
+************************************************************************ */
+/**
+ * String helper functions
+ *
+ * The native JavaScript String is not modified by this class. However,
+ * there are modifications to the native String in {@link qx.lang.normalize.String} for
+ * browsers that do not support certain features.
+ */
+qx.Bootstrap.define("qx.lang.String", {
+ statics : {
+ /**
+ * Unicode letters. they are taken from Steve Levithan's excellent XRegExp library [http://xregexp.com/addons/unicode/unicode-base.js]
+ */
+ __unicodeLetters : "0041-005A0061-007A00AA00B500BA00C0-00D600D8-00F600F8-02C102C6-02D102E0-02E402EC02EE0370-037403760377037A-037D03860388-038A038C038E-03A103A3-03F503F7-0481048A-05250531-055605590561-058705D0-05EA05F0-05F20621-064A066E066F0671-06D306D506E506E606EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA07F407F507FA0800-0815081A082408280904-0939093D09500958-0961097109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E460E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EC60EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10A0-10C510D0-10FA10FC1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317D717DC1820-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541AA71B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C7D1CE9-1CEC1CEE-1CF11D00-1DBF1E00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FBC1FBE1FC2-1FC41FC6-1FCC1FD0-1FD31FD6-1FDB1FE0-1FEC1FF2-1FF41FF6-1FFC2071207F2090-209421022107210A-211321152119-211D212421262128212A-212D212F-2139213C-213F2145-2149214E218321842C00-2C2E2C30-2C5E2C60-2CE42CEB-2CEE2D00-2D252D30-2D652D6F2D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE2E2F300530063031-3035303B303C3041-3096309D-309F30A1-30FA30FC-30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A48CA4D0-A4FDA500-A60CA610-A61FA62AA62BA640-A65FA662-A66EA67F-A697A6A0-A6E5A717-A71FA722-A788A78BA78CA7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2A9CFAA00-AA28AA40-AA42AA44-AA4BAA60-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADB-AADDABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB00-FB06FB13-FB17FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF21-FF3AFF41-FF5AFF66-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC",
+ /**
+ * A RegExp that matches the first letter in a word - unicode aware
+ */
+ __unicodeFirstLetterInWordRegexp : null,
+ /**
+ * {Map} Cache for often used string operations [camelCasing and hyphenation]
+ * e.g. marginTop => margin-top
+ */
+ __stringsMap : {
+ },
+ /**
+ * Converts a hyphenated string (separated by '-') to camel case.
+ *
+ * Example:
+ * qx.lang.String.camelCase("I-like-cookies"); //returns "ILikeCookies"
+ *
+ * @param str {String} hyphenated string
+ * @return {String} camelcase string
+ */
+ camelCase : function(str){
+
+ var result = this.__stringsMap[str];
+ if(!result){
+
+ result = str.replace(/\-([a-z])/g, function(match, chr){
+
+ return chr.toUpperCase();
+ });
+ if(str.indexOf("-") >= 0){
+
+ this.__stringsMap[str] = result;
+ };
+ };
+ return result;
+ },
+ /**
+ * Converts a camelcased string to a hyphenated (separated by '-') string.
+ *
+ * Example:
+ * qx.lang.String.hyphenate("weLikeCookies"); //returns "we-like-cookies"
+ *
+ * @param str {String} camelcased string
+ * @return {String} hyphenated string
+ */
+ hyphenate : function(str){
+
+ var result = this.__stringsMap[str];
+ if(!result){
+
+ result = str.replace(/[A-Z]/g, function(match){
+
+ return ('-' + match.charAt(0).toLowerCase());
+ });
+ if(str.indexOf("-") == -1){
+
+ this.__stringsMap[str] = result;
+ };
+ };
+ return result;
+ },
+ /**
+ * Converts a string to camel case.
+ *
+ * Example:
+ * qx.lang.String.camelCase("i like cookies"); //returns "I Like Cookies"
+ *
+ * @param str {String} any string
+ * @return {String} capitalized string
+ */
+ capitalize : function(str){
+
+ if(this.__unicodeFirstLetterInWordRegexp === null){
+
+ var unicodeEscapePrefix = '\\u';
+ this.__unicodeFirstLetterInWordRegexp = new RegExp("(^|[^" + this.__unicodeLetters.replace(/[0-9A-F]{4}/g, function(match){
+
+ return unicodeEscapePrefix + match;
+ }) + "])[" + this.__unicodeLetters.replace(/[0-9A-F]{4}/g, function(match){
+
+ return unicodeEscapePrefix + match;
+ }) + "]", "g");
+ };
+ return str.replace(this.__unicodeFirstLetterInWordRegexp, function(match){
+
+ return match.toUpperCase();
+ });
+ },
+ /**
+ * Removes all extraneous whitespace from a string and trims it
+ *
+ * Example:
+ *
+ *
+ * qx.lang.String.clean(" i like cookies \n\n");
+ *
+ *
+ * Returns "i like cookies"
+ *
+ * @param str {String} the string to clean up
+ * @return {String} Cleaned up string
+ */
+ clean : function(str){
+
+ return str.replace(/\s+/g, ' ').trim();
+ },
+ /**
+ * removes white space from the left side of a string
+ *
+ * @param str {String} the string to trim
+ * @return {String} the trimmed string
+ */
+ trimLeft : function(str){
+
+ return str.replace(/^\s+/, "");
+ },
+ /**
+ * removes white space from the right side of a string
+ *
+ * @param str {String} the string to trim
+ * @return {String} the trimmed string
+ */
+ trimRight : function(str){
+
+ return str.replace(/\s+$/, "");
+ },
+ /**
+ * removes white space from the left and the right side of a string
+ *
+ * @deprecated {2.1} please use the native trim method.
+ * @param str {String} the string to trim
+ * @return {String} the trimmed string
+ */
+ trim : function(str){
+
+ {
+ };
+ return str.replace(/^\s+|\s+$/g, "");
+ },
+ /**
+ * Check whether the string starts with the given substring
+ *
+ * @param fullstr {String} the string to search in
+ * @param substr {String} the substring to look for
+ * @return {Boolean} whether the string starts with the given substring
+ */
+ startsWith : function(fullstr, substr){
+
+ return fullstr.indexOf(substr) === 0;
+ },
+ /**
+ * Check whether the string ends with the given substring
+ *
+ * @param fullstr {String} the string to search in
+ * @param substr {String} the substring to look for
+ * @return {Boolean} whether the string ends with the given substring
+ */
+ endsWith : function(fullstr, substr){
+
+ return fullstr.substring(fullstr.length - substr.length, fullstr.length) === substr;
+ },
+ /**
+ * Returns a string, which repeats a string 'length' times
+ *
+ * @param str {String} string used to repeat
+ * @param times {Integer} the number of repetitions
+ * @return {String} repeated string
+ */
+ repeat : function(str, times){
+
+ return str.length > 0 ? new Array(times + 1).join(str) : "";
+ },
+ /**
+ * Pad a string up to a given length. Padding characters are added to the left of the string.
+ *
+ * @param str {String} the string to pad
+ * @param length {Integer} the final length of the string
+ * @param ch {String} character used to fill up the string
+ * @return {String} padded string
+ */
+ pad : function(str, length, ch){
+
+ var padLength = length - str.length;
+ if(padLength > 0){
+
+ if(typeof ch === "undefined"){
+
+ ch = "0";
+ };
+ return this.repeat(ch, padLength) + str;
+ } else {
+
+ return str;
+ };
+ },
+ /**
+ * Convert the first character of the string to upper case.
+ *
+ * @signature function(str)
+ * @param str {String} the string
+ * @return {String} the string with an upper case first character
+ */
+ firstUp : qx.Bootstrap.firstUp,
+ /**
+ * Convert the first character of the string to lower case.
+ *
+ * @signature function(str)
+ * @param str {String} the string
+ * @return {String} the string with a lower case first character
+ */
+ firstLow : qx.Bootstrap.firstLow,
+ /**
+ * Check whether the string contains a given substring
+ *
+ * @param str {String} the string
+ * @param substring {String} substring to search for
+ * @return {Boolean} whether the string contains the substring
+ */
+ contains : function(str, substring){
+
+ return str.indexOf(substring) != -1;
+ },
+ /**
+ * Print a list of arguments using a format string
+ * In the format string occurrences of %n are replaced by the n'th element of the args list.
+ * Example:
+ * qx.lang.String.format("Hello %1, my name is %2", ["Egon", "Franz"]) == "Hello Egon, my name is Franz"
+ *
+ * @param pattern {String} format string
+ * @param args {Array} array of arguments to insert into the format string
+ * @return {String} the formatted string
+ */
+ format : function(pattern, args){
+
+ var str = pattern;
+ var i = args.length;
+ while(i--){
+
+ // be sure to always use a string for replacement.
+ str = str.replace(new RegExp("%" + (i + 1), "g"), args[i] + "");
+ };
+ return str;
+ },
+ /**
+ * Escapes all chars that have a special meaning in regular expressions
+ *
+ * @param str {String} the string where to escape the chars.
+ * @return {String} the string with the escaped chars.
+ */
+ escapeRegexpChars : function(str){
+
+ return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
+ },
+ /**
+ * Converts a string to an array of characters.
+ * "hello" => [ "h", "e", "l", "l", "o" ];
+ *
+ * @param str {String} the string which should be split
+ * @return {Array} the result array of characters
+ */
+ toArray : function(str){
+
+ return str.split(/\B|\b/g);
+ },
+ /**
+ * Remove HTML/XML tags from a string
+ * Example:
+ * qx.lang.String.stripTags("<h1>Hello</h1>") == "Hello"
+ *
+ * @param str {String} string containing tags
+ * @return {String} the string with stripped tags
+ */
+ stripTags : function(str){
+
+ return str.replace(/<\/?[^>]+>/gi, "");
+ },
+ /**
+ * Strips