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.documentmodeInteger0{@link qx.bom.client.Browser#getDocumentMode}
browser.nameString chrome {@link qx.bom.client.Browser#getName}
browser.quirksmodeBooleanfalse{@link qx.bom.client.Browser#getQuirksMode}
browser.versionString11.0{@link qx.bom.client.Browser#getVersion}
runtime
runtime.name String node.js {@link qx.bom.client.Runtime#getName}
css
css.borderradiusString or nullborderRadius{@link qx.bom.client.Css#getBorderRadius}
css.borderimageString or nullWebkitBorderImage{@link qx.bom.client.Css#getBorderImage}
css.borderimage.standardsyntaxBoolean or nulltrue{@link qx.bom.client.Css#getBorderImageSyntax}
css.boxmodelStringcontent{@link qx.bom.client.Css#getBoxModel}
css.boxshadowString or nullboxShadow{@link qx.bom.client.Css#getBoxShadow}
css.gradient.linearString or null-moz-linear-gradient{@link qx.bom.client.Css#getLinearGradient}
css.gradient.filterBooleantrue{@link qx.bom.client.Css#getFilterGradient}
css.gradient.radialString or null-moz-radial-gradient{@link qx.bom.client.Css#getRadialGradient}
css.gradient.legacywebkitBooleanfalse{@link qx.bom.client.Css#getLegacyWebkitGradient}
css.placeholderBooleantrue{@link qx.bom.client.Css#getPlaceholder}
css.textoverflowString or nulltextOverflow{@link qx.bom.client.Css#getTextOverflow}
css.rgbaBooleantrue{@link qx.bom.client.Css#getRgba}
css.usermodifyString or nullWebkitUserModify{@link qx.bom.client.Css#getUserModify}
css.appearanceString or nullWebkitAppearance{@link qx.bom.client.Css#getAppearance}
css.floatString or nullcssFloat{@link qx.bom.client.Css#getFloat}
css.userselectString or nullWebkitUserSelect{@link qx.bom.client.Css#getUserSelect}
css.userselect.noneString or null-moz-none{@link qx.bom.client.Css#getUserSelectNone}
css.boxsizingString or nullboxSizing{@link qx.bom.client.Css#getBoxSizing}
css.animationObject or null{end-event: "webkitAnimationEnd", keyframes: "@-webkit-keyframes", play-state: null, name: "WebkitAnimation"}{@link qx.bom.client.CssAnimation#getSupport}
css.animation.requestframeString or nullmozRequestAnimationFrame{@link qx.bom.client.CssAnimation#getRequestAnimationFrame}
css.transformObject 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.3dBooleanfalse{@link qx.bom.client.CssTransform#get3D}
css.inlineblockString or nullinline-block{@link qx.bom.client.Css#getInlineBlock}
css.opacityBooleantrue{@link qx.bom.client.Css#getOpacity}
deprecated since 2.1: css.overflowxyBooleantrue{@link qx.bom.client.Css#getOverflowXY}
css.textShadowBooleantrue{@link qx.bom.client.Css#getTextShadow}
css.textShadow.filterBooleantrue{@link qx.bom.client.Css#getFilterTextShadow}
device
device.nameStringpc{@link qx.bom.client.Device#getName}
device.typeStringmobile{@link qx.bom.client.Device#getType}
ecmascript
ecmascript.error.stacktraceString or nullstack{@link qx.bom.client.EcmaScript#getStackTrace}
ecmascript.array.indexofBooleantrue{@link qx.bom.client.EcmaScript#getArrayIndexOf}
ecmascript.array.lastindexofBooleantrue{@link qx.bom.client.EcmaScript#getArrayLastIndexOf}
ecmascript.array.foreachBooleantrue{@link qx.bom.client.EcmaScript#getArrayForEach}
ecmascript.array.filterBooleantrue{@link qx.bom.client.EcmaScript#getArrayFilter}
ecmascript.array.mapBooleantrue{@link qx.bom.client.EcmaScript#getArrayMap}
ecmascript.array.someBooleantrue{@link qx.bom.client.EcmaScript#getArraySome}
ecmascript.array.everyBooleantrue{@link qx.bom.client.EcmaScript#getArrayEvery}
ecmascript.array.reduceBooleantrue{@link qx.bom.client.EcmaScript#getArrayReduce}
ecmascript.array.reducerightBooleantrue{@link qx.bom.client.EcmaScript#getArrayReduceRight}
ecmascript.function.bindBooleantrue{@link qx.bom.client.EcmaScript#getFunctionBind}
ecmascript.object.keysBooleantrue{@link qx.bom.client.EcmaScript#getObjectKeys}
ecmascript.date.nowBooleantrue{@link qx.bom.client.EcmaScript#getDateNow}
ecmascript.error.toStringBooleantrue{@link qx.bom.client.EcmaScript#getErrorToString}
ecmascript.string.trimBooleantrue{@link qx.bom.client.EcmaScript#getStringTrim}
engine
engine.nameStringwebkit{@link qx.bom.client.Engine#getName}
engine.versionString534.24{@link qx.bom.client.Engine#getVersion}
event
event.pointerBooleantrue{@link qx.bom.client.Event#getPointer}
event.mspointerBooleantrue{@link qx.bom.client.Event#getMsPointer}
event.touchBooleanfalse{@link qx.bom.client.Event#getTouch}
event.helpBooleanfalse{@link qx.bom.client.Event#getHelp}
event.hashchangeBooleantrue{@link qx.bom.client.Event#getHashChange}
html
html.audioBooleantrue{@link qx.bom.client.Html#getAudio}
html.audio.mp3String""{@link qx.bom.client.Html#getAudioMp3}
html.audio.oggString"maybe"{@link qx.bom.client.Html#getAudioOgg}
html.audio.wavString"probably"{@link qx.bom.client.Html#getAudioWav}
html.audio.auString"maybe"{@link qx.bom.client.Html#getAudioAu}
html.audio.aifString"probably"{@link qx.bom.client.Html#getAudioAif}
html.canvasBooleantrue{@link qx.bom.client.Html#getCanvas}
html.classlistBooleantrue{@link qx.bom.client.Html#getClassList}
html.geolocationBooleantrue{@link qx.bom.client.Html#getGeoLocation}
html.storage.localBooleantrue{@link qx.bom.client.Html#getLocalStorage}
html.storage.sessionBooleantrue{@link qx.bom.client.Html#getSessionStorage}
html.storage.userdataBooleantrue{@link qx.bom.client.Html#getUserDataStorage}
html.svgBooleantrue{@link qx.bom.client.Html#getSvg}
html.videoBooleantrue{@link qx.bom.client.Html#getVideo}
html.video.h264String"probably"{@link qx.bom.client.Html#getVideoH264}
html.video.oggString""{@link qx.bom.client.Html#getVideoOgg}
html.video.webmString"maybe"{@link qx.bom.client.Html#getVideoWebm}
html.vmlBooleanfalse{@link qx.bom.client.Html#getVml}
html.webworkerBooleantrue{@link qx.bom.client.Html#getWebWorker}
html.filereaderBooleantrue{@link qx.bom.client.Html#getFileReader}
html.xpathBooleantrue{@link qx.bom.client.Html#getXPath}
html.xulBooleantrue{@link qx.bom.client.Html#getXul}
html.consoleBooleantrue{@link qx.bom.client.Html#getConsole}
html.element.containsBooleantrue{@link qx.bom.client.Html#getContains}
html.element.compareDocumentPositionBooleantrue{@link qx.bom.client.Html#getCompareDocumentPosition}
html.element.textContentBooleantrue{@link qx.bom.client.Html#getTextContent}
html.image.naturaldimensionsBooleantrue{@link qx.bom.client.Html#getNaturalDimensions}
html.history.stateBooleantrue{@link qx.bom.client.Html#getHistoryState}
html.selectionStringgetSelection{@link qx.bom.client.Html#getSelection}
XML
xml.implementationBooleantrue{@link qx.bom.client.Xml#getImplementation}
xml.domparserBooleantrue{@link qx.bom.client.Xml#getDomParser}
xml.selectsinglenodeBooleanfalse{@link qx.bom.client.Xml#getSelectSingleNode}
xml.selectnodesBooleanfalse{@link qx.bom.client.Xml#getSelectNodes}
xml.getelementsbytagnamensBooleantrue{@link qx.bom.client.Xml#getElementsByTagNameNS}
xml.dompropertiesBooleanfalse{@link qx.bom.client.Xml#getDomProperties}
xml.attributensBooleantrue{@link qx.bom.client.Xml#getAttributeNS}
xml.createelementnsBooleantrue{@link qx.bom.client.Xml#getCreateElementNS}
xml.createnodeBooleanfalse{@link qx.bom.client.Xml#getCreateNode}
xml.getqualifieditemBooleanfalse{@link qx.bom.client.Xml#getQualifiedItem}
Stylesheets
html.stylesheet.createstylesheetBooleanfalse{@link qx.bom.client.Stylesheet#getCreateStyleSheet}
html.stylesheet.insertruleBooleantrue{@link qx.bom.client.Stylesheet#getInsertRule}
html.stylesheet.deleteruleBooleantrue{@link qx.bom.client.Stylesheet#getDeleteRule}
html.stylesheet.addimportBooleanfalse{@link qx.bom.client.Stylesheet#getAddImport}
html.stylesheet.removeimportBooleanfalse{@link qx.bom.client.Stylesheet#getRemoveImport}
io
io.maxrequestsInteger4{@link qx.bom.client.Transport#getMaxConcurrentRequestCount}
io.sslBooleanfalse{@link qx.bom.client.Transport#getSsl}
io.xhrStringxhr{@link qx.bom.client.Transport#getXmlHttpRequest}
locale
localeStringde{@link qx.bom.client.Locale#getLocale}
locale.variantStringde{@link qx.bom.client.Locale#getVariant}
os
os.nameStringosx{@link qx.bom.client.OperatingSystem#getName}
os.versionString10.6{@link qx.bom.client.OperatingSystem#getVersion}
os.scrollBarOverlayedBooleanfalse{@link qx.bom.client.Scroll#scrollBarOverlayed}
phonegap
phonegapBooleanfalse{@link qx.bom.client.PhoneGap#getPhoneGap}
phonegap.notificationBooleanfalse{@link qx.bom.client.PhoneGap#getNotification}
plugin
plugin.divxBooleanfalse{@link qx.bom.client.Plugin#getDivX}
plugin.divx.versionString{@link qx.bom.client.Plugin#getDivXVersion}
plugin.flashBooleantrue{@link qx.bom.client.Flash#isAvailable}
plugin.flash.expressBooleantrue{@link qx.bom.client.Flash#getExpressInstall}
plugin.flash.strictsecurityBooleantrue{@link qx.bom.client.Flash#getStrictSecurityModel}
plugin.flash.versionString10.2.154{@link qx.bom.client.Flash#getVersion}
plugin.gearsBooleanfalse{@link qx.bom.client.Plugin#getGears}
plugin.activexBooleanfalse{@link qx.bom.client.Plugin#getActiveX}
plugin.skypeBooleanfalse{@link qx.bom.client.Plugin#getSkype}
plugin.pdfBooleanfalse{@link qx.bom.client.Plugin#getPdf}
plugin.pdf.versionString{@link qx.bom.client.Plugin#getPdfVersion}
plugin.quicktimeBooleantrue{@link qx.bom.client.Plugin#getQuicktime}
plugin.quicktime.versionString7.6{@link qx.bom.client.Plugin#getQuicktimeVersion}
plugin.silverlightBooleanfalse{@link qx.bom.client.Plugin#getSilverlight}
plugin.silverlight.versionString{@link qx.bom.client.Plugin#getSilverlightVersion}
plugin.windowsmediaBooleanfalse{@link qx.bom.client.Plugin#getWindowsMedia}
plugin.windowsmedia.versionString{@link qx.bom.client.Plugin#getWindowsMediaVersion}
qx
qx.allowUrlSettingsBooleantruedefault: false
qx.allowUrlVariantsBooleantruedefault: false
qx.applicationStringname.spacedefault: <<application name>>
qx.aspectsBooleanfalsedefault: false
qx.debugBooleantruedefault: true
qx.debug.databindingBooleanfalsedefault: false
qx.debug.disposeBooleanfalsedefault: false
qx.debug.dispose.levelInteger0default: 0
qx.debug.ioBooleantruedefault: false
qx.debug.io.remoteBooleantruedefault: false
qx.debug.io.remote.dataBooleantruedefault: false
qx.debug.property.levelInteger0default: 0
qx.debug.ui.queueBooleantruedefault: true
qx.dynamicmousewheelBooleantruedefault: true
qx.dynlocaleBooleantruedefault: true
qx.globalErrorHandlingBooleantruedefault: true
qx.mobile.emulatetouchBooleanfalsedefault: false
qx.mobile.nativescrollBooleanfalsedefault: false
qx.optimization.basecallsBooleantruetrue if the corresp. optimize key is set in the config
qx.optimization.commentsBooleantruetrue if the corresp. optimize key is set in the config
qx.optimization.privatesBooleantruetrue if the corresp. optimize key is set in the config
qx.optimization.stringsBooleantruetrue if the corresp. optimize key is set in the config
qx.optimization.variablesBooleantruetrue if the corresp. optimize key is set in the config
qx.optimization.variantsBooleantruetrue if the corresp. optimize key is set in the config
qx.revisionString27348
qx.themeStringqx.theme.Moderndefault: <<initial theme name>>
qx.versionString${qxversion}
qx.blankpageStringURI to blank.html page
module
module.databindingBooleantruedefault: true
module.loggerBooleantruedefault: true
module.propertyBooleantruedefault: true
module.eventsBooleantruedefault: true

Asynchronous checks

+ *
html.dataurlBooleantrue{@link qx.bom.client.Html#getDataUrl}
+ * + */ +qx.Bootstrap.define("qx.core.Environment", { + statics : { + /** Map containing the synchronous check functions. */ + _checks : { + }, + /** Map containing the asynchronous check functions. */ + _asyncChecks : { + }, + /** Internal cache for all checks. */ + __cache : { + }, + /** Internal map for environment keys to check methods. */ + _checksMap : { + "engine.version" : "qx.bom.client.Engine.getVersion", + "engine.name" : "qx.bom.client.Engine.getName", + "browser.name" : "qx.bom.client.Browser.getName", + "browser.version" : "qx.bom.client.Browser.getVersion", + "browser.documentmode" : "qx.bom.client.Browser.getDocumentMode", + "browser.quirksmode" : "qx.bom.client.Browser.getQuirksMode", + "runtime.name" : "qx.bom.client.Runtime.getName", + "device.name" : "qx.bom.client.Device.getName", + "device.type" : "qx.bom.client.Device.getType", + "locale" : "qx.bom.client.Locale.getLocale", + "locale.variant" : "qx.bom.client.Locale.getVariant", + "os.name" : "qx.bom.client.OperatingSystem.getName", + "os.version" : "qx.bom.client.OperatingSystem.getVersion", + "os.scrollBarOverlayed" : "qx.bom.client.Scroll.scrollBarOverlayed", + "plugin.gears" : "qx.bom.client.Plugin.getGears", + "plugin.activex" : "qx.bom.client.Plugin.getActiveX", + "plugin.skype" : "qx.bom.client.Plugin.getSkype", + "plugin.quicktime" : "qx.bom.client.Plugin.getQuicktime", + "plugin.quicktime.version" : "qx.bom.client.Plugin.getQuicktimeVersion", + "plugin.windowsmedia" : "qx.bom.client.Plugin.getWindowsMedia", + "plugin.windowsmedia.version" : "qx.bom.client.Plugin.getWindowsMediaVersion", + "plugin.divx" : "qx.bom.client.Plugin.getDivX", + "plugin.divx.version" : "qx.bom.client.Plugin.getDivXVersion", + "plugin.silverlight" : "qx.bom.client.Plugin.getSilverlight", + "plugin.silverlight.version" : "qx.bom.client.Plugin.getSilverlightVersion", + "plugin.flash" : "qx.bom.client.Flash.isAvailable", + "plugin.flash.version" : "qx.bom.client.Flash.getVersion", + "plugin.flash.express" : "qx.bom.client.Flash.getExpressInstall", + "plugin.flash.strictsecurity" : "qx.bom.client.Flash.getStrictSecurityModel", + "plugin.pdf" : "qx.bom.client.Plugin.getPdf", + "plugin.pdf.version" : "qx.bom.client.Plugin.getPdfVersion", + "io.maxrequests" : "qx.bom.client.Transport.getMaxConcurrentRequestCount", + "io.ssl" : "qx.bom.client.Transport.getSsl", + "io.xhr" : "qx.bom.client.Transport.getXmlHttpRequest", + "event.touch" : "qx.bom.client.Event.getTouch", + "event.pointer" : "qx.bom.client.Event.getPointer", + "event.help" : "qx.bom.client.Event.getHelp", + "event.hashchange" : "qx.bom.client.Event.getHashChange", + "ecmascript.stacktrace" : "qx.bom.client.EcmaScript.getStackTrace", + // @deprecated {2.1} + "ecmascript.error.stacktrace" : "qx.bom.client.EcmaScript.getStackTrace", + "ecmascript.array.indexof" : "qx.bom.client.EcmaScript.getArrayIndexOf", + "ecmascript.array.lastindexof" : "qx.bom.client.EcmaScript.getArrayLastIndexOf", + "ecmascript.array.foreach" : "qx.bom.client.EcmaScript.getArrayForEach", + "ecmascript.array.filter" : "qx.bom.client.EcmaScript.getArrayFilter", + "ecmascript.array.map" : "qx.bom.client.EcmaScript.getArrayMap", + "ecmascript.array.some" : "qx.bom.client.EcmaScript.getArraySome", + "ecmascript.array.every" : "qx.bom.client.EcmaScript.getArrayEvery", + "ecmascript.array.reduce" : "qx.bom.client.EcmaScript.getArrayReduce", + "ecmascript.array.reduceright" : "qx.bom.client.EcmaScript.getArrayReduceRight", + "ecmascript.function.bind" : "qx.bom.client.EcmaScript.getFunctionBind", + "ecmascript.object.keys" : "qx.bom.client.EcmaScript.getObjectKeys", + "ecmascript.date.now" : "qx.bom.client.EcmaScript.getDateNow", + "ecmascript.error.toString" : "qx.bom.client.EcmaScript.getErrorToString", + "ecmascript.string.trim" : "qx.bom.client.EcmaScript.getStringTrim", + "html.webworker" : "qx.bom.client.Html.getWebWorker", + "html.filereader" : "qx.bom.client.Html.getFileReader", + "html.geolocation" : "qx.bom.client.Html.getGeoLocation", + "html.audio" : "qx.bom.client.Html.getAudio", + "html.audio.ogg" : "qx.bom.client.Html.getAudioOgg", + "html.audio.mp3" : "qx.bom.client.Html.getAudioMp3", + "html.audio.wav" : "qx.bom.client.Html.getAudioWav", + "html.audio.au" : "qx.bom.client.Html.getAudioAu", + "html.audio.aif" : "qx.bom.client.Html.getAudioAif", + "html.video" : "qx.bom.client.Html.getVideo", + "html.video.ogg" : "qx.bom.client.Html.getVideoOgg", + "html.video.h264" : "qx.bom.client.Html.getVideoH264", + "html.video.webm" : "qx.bom.client.Html.getVideoWebm", + "html.storage.local" : "qx.bom.client.Html.getLocalStorage", + "html.storage.session" : "qx.bom.client.Html.getSessionStorage", + "html.storage.userdata" : "qx.bom.client.Html.getUserDataStorage", + "html.classlist" : "qx.bom.client.Html.getClassList", + "html.xpath" : "qx.bom.client.Html.getXPath", + "html.xul" : "qx.bom.client.Html.getXul", + "html.canvas" : "qx.bom.client.Html.getCanvas", + "html.svg" : "qx.bom.client.Html.getSvg", + "html.vml" : "qx.bom.client.Html.getVml", + "html.dataset" : "qx.bom.client.Html.getDataset", + "html.dataurl" : "qx.bom.client.Html.getDataUrl", + "html.console" : "qx.bom.client.Html.getConsole", + "html.stylesheet.createstylesheet" : "qx.bom.client.Stylesheet.getCreateStyleSheet", + "html.stylesheet.insertrule" : "qx.bom.client.Stylesheet.getInsertRule", + "html.stylesheet.deleterule" : "qx.bom.client.Stylesheet.getDeleteRule", + "html.stylesheet.addimport" : "qx.bom.client.Stylesheet.getAddImport", + "html.stylesheet.removeimport" : "qx.bom.client.Stylesheet.getRemoveImport", + "html.element.contains" : "qx.bom.client.Html.getContains", + "html.element.compareDocumentPosition" : "qx.bom.client.Html.getCompareDocumentPosition", + "html.element.textcontent" : "qx.bom.client.Html.getTextContent", + "html.image.naturaldimensions" : "qx.bom.client.Html.getNaturalDimensions", + "html.history.state" : "qx.bom.client.Html.getHistoryState", + "html.selection" : "qx.bom.client.Html.getSelection", + "json" : "qx.bom.client.Json.getJson", + "css.textoverflow" : "qx.bom.client.Css.getTextOverflow", + "css.placeholder" : "qx.bom.client.Css.getPlaceholder", + "css.borderradius" : "qx.bom.client.Css.getBorderRadius", + "css.borderimage" : "qx.bom.client.Css.getBorderImage", + "css.borderimage.standardsyntax" : "qx.bom.client.Css.getBorderImageSyntax", + "css.boxshadow" : "qx.bom.client.Css.getBoxShadow", + "css.gradient.linear" : "qx.bom.client.Css.getLinearGradient", + "css.gradient.filter" : "qx.bom.client.Css.getFilterGradient", + "css.gradient.radial" : "qx.bom.client.Css.getRadialGradient", + "css.gradient.legacywebkit" : "qx.bom.client.Css.getLegacyWebkitGradient", + "css.boxmodel" : "qx.bom.client.Css.getBoxModel", + "css.rgba" : "qx.bom.client.Css.getRgba", + "css.userselect" : "qx.bom.client.Css.getUserSelect", + "css.userselect.none" : "qx.bom.client.Css.getUserSelectNone", + "css.usermodify" : "qx.bom.client.Css.getUserModify", + "css.appearance" : "qx.bom.client.Css.getAppearance", + "css.float" : "qx.bom.client.Css.getFloat", + "css.boxsizing" : "qx.bom.client.Css.getBoxSizing", + "css.animation" : "qx.bom.client.CssAnimation.getSupport", + "css.animation.requestframe" : "qx.bom.client.CssAnimation.getRequestAnimationFrame", + "css.transform" : "qx.bom.client.CssTransform.getSupport", + "css.transform.3d" : "qx.bom.client.CssTransform.get3D", + "css.inlineblock" : "qx.bom.client.Css.getInlineBlock", + "css.opacity" : "qx.bom.client.Css.getOpacity", + "css.overflowxy" : "qx.bom.client.Css.getOverflowXY", + // @deprecated {2.1} + "css.textShadow" : "qx.bom.client.Css.getTextShadow", + "css.textShadow.filter" : "qx.bom.client.Css.getFilterTextShadow", + "phonegap" : "qx.bom.client.PhoneGap.getPhoneGap", + "phonegap.notification" : "qx.bom.client.PhoneGap.getNotification", + "xml.implementation" : "qx.bom.client.Xml.getImplementation", + "xml.domparser" : "qx.bom.client.Xml.getDomParser", + "xml.selectsinglenode" : "qx.bom.client.Xml.getSelectSingleNode", + "xml.selectnodes" : "qx.bom.client.Xml.getSelectNodes", + "xml.getelementsbytagnamens" : "qx.bom.client.Xml.getElementsByTagNameNS", + "xml.domproperties" : "qx.bom.client.Xml.getDomProperties", + "xml.attributens" : "qx.bom.client.Xml.getAttributeNS", + "xml.createnode" : "qx.bom.client.Xml.getCreateNode", + "xml.getqualifieditem" : "qx.bom.client.Xml.getQualifiedItem", + "xml.createelementns" : "qx.bom.client.Xml.getCreateElementNS" + }, + /** + * The default accessor for the checks. It returns the value the current + * environment has for the given key. The key could be something like + * "qx.debug", "css.textoverflow" or "io.ssl". A complete list of + * checks can be found in the class comment of this class. + * + * Please keep in mind that the result is cached. If you want to run the + * check function again in case something could have been changed, take a + * look at the {@link #invalidateCacheKey} function. + * + * @param key {String} The name of the check you want to query. + * @return {var} The stored value depending on the given key. + * (Details in the class doc) + */ + get : function(key){ + + if(qx.Bootstrap.DEBUG){ + + // @deprecated {2.1} + if(key == "css.overflowxy"){ + + qx.Bootstrap.warn("The environment key 'css.overflowxy' is deprecated."); + }; + // @deprecated {2.1} + if(key == "ecmascript.stacktrace"){ + + qx.Bootstrap.warn("The environment key 'ecmascript.stacktrace' is now 'ecmascript.error.stacktrace'."); + key = "ecmascript.error.stacktrace"; + }; + }; + // check the cache + if(this.__cache[key] != undefined){ + + return this.__cache[key]; + }; + // search for a matching check + var check = this._checks[key]; + if(check){ + + // execute the check and write the result in the cache + var value = check(); + this.__cache[key] = value; + return value; + }; + // try class lookup + var classAndMethod = this._getClassNameFromEnvKey(key); + if(classAndMethod[0] != undefined){ + + var clazz = classAndMethod[0]; + var method = classAndMethod[1]; + var value = clazz[method](); + // call the check method + this.__cache[key] = value; + return value; + }; + // debug flag + if(qx.Bootstrap.DEBUG){ + + qx.Bootstrap.warn(key + " is not a valid key. Please see the API-doc of " + "qx.core.Environment for a list of predefined keys."); + qx.Bootstrap.trace(this); + }; + }, + /** + * Maps an environment key to a check class and method name. + * + * @param key {String} The name of the check you want to query. + * @return {Array} [className, methodName] of + * the corresponding implementation. + */ + _getClassNameFromEnvKey : function(key){ + + var envmappings = this._checksMap; + if(envmappings[key] != undefined){ + + var implementation = envmappings[key]; + // separate class from method + var lastdot = implementation.lastIndexOf("."); + if(lastdot > -1){ + + var classname = implementation.slice(0, lastdot); + var methodname = implementation.slice(lastdot + 1); + var clazz = qx.Bootstrap.getByName(classname); + if(clazz != undefined){ + + return [clazz, methodname]; + }; + }; + }; + return [undefined, undefined]; + }, + /** + * Invokes the callback as soon as the check has been done. If no check + * could be found, a warning will be printed. + * + * @param key {String} The key of the asynchronous check. + * @param callback {Function} The function to call as soon as the check is + * done. The function should have one argument which is the result of the + * check. + * @param self {var} The context to use when invoking the callback. + */ + getAsync : function(key, callback, self){ + + // check the cache + var env = this; + if(this.__cache[key] != undefined){ + + // force async behavior + window.setTimeout(function(){ + + callback.call(self, env.__cache[key]); + }, 0); + return; + }; + var check = this._asyncChecks[key]; + if(check){ + + check(function(result){ + + env.__cache[key] = result; + callback.call(self, result); + }); + return; + }; + // try class lookup + var classAndMethod = this._getClassNameFromEnvKey(key); + if(classAndMethod[0] != undefined){ + + var clazz = classAndMethod[0]; + var method = classAndMethod[1]; + clazz[method](function(result){ + + // call the check method + env.__cache[key] = result; + callback.call(self, result); + }); + return; + }; + // debug flag + if(qx.Bootstrap.DEBUG){ + + qx.Bootstrap.warn(key + " is not a valid key. Please see the API-doc of " + "qx.core.Environment for a list of predefined keys."); + qx.Bootstrap.trace(this); + }; + }, + /** + * Returns the proper value dependent on the check for the given key. + * + * @param key {String} The name of the check the select depends on. + * @param values {Map} A map containing the values which should be returned + * in any case. The "default" key could be used as a catch all statement. + * @return {var} The value which is stored in the map for the given + * check of the key. + */ + select : function(key, values){ + + return this.__pickFromValues(this.get(key), values); + }, + /** + * Selects the proper function dependent on the asynchronous check. + * + * @param key {String} The key for the async check. + * @param values {Map} A map containing functions. The map keys should + * contain all possibilities which could be returned by the given check + * key. The "default" key could be used as a catch all statement. + * The called function will get one parameter, the result of the query. + * @param self {var} The context which should be used when calling the + * method in the values map. + */ + selectAsync : function(key, values, self){ + + this.getAsync(key, function(result){ + + var value = this.__pickFromValues(key, values); + value.call(self, result); + }, this); + }, + /** + * Internal helper which tries to pick the given key from the given values + * map. If that key is not found, it tries to use a key named "default". + * If there is also no default key, it prints out a warning and returns + * undefined. + * + * @param key {String} The key to search for in the values. + * @param values {Map} A map containing some keys. + * @return {var} The value stored as values[key] usually. + */ + __pickFromValues : function(key, values){ + + var value = values[key]; + if(values.hasOwnProperty(key)){ + + return value; + }; + // check for piped values + for(var id in values){ + + if(id.indexOf("|") != -1){ + + var ids = id.split("|"); + for(var i = 0;i < ids.length;i++){ + + if(ids[i] == key){ + + return values[id]; + }; + }; + }; + }; + if(values["default"] !== undefined){ + + return values["default"]; + }; + if(qx.Bootstrap.DEBUG){ + + throw new Error('No match for variant "' + key + '" (' + (typeof key) + ' type)' + ' in variants [' + qx.Bootstrap.keys(values) + '] found, and no default ("default") given'); + }; + }, + /** + * Takes a given map containing the check names as keys and converts + * the map to an array only containing the values for check evaluating + * to 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 = ''; + el.firstChild.style.behavior = "url(#default#VML)"; + var hasVml = typeof el.firstChild.adj == "object"; + document.body.removeChild(el); + return hasVml; + }, + /** + * Checks if canvas could be used + * + * @internal + * @return {Boolean} 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 + * + * + * @return {Function} Wrapped function + */ + create : function(func, options){ + + { + }; + // Nothing to be done when there are no options. + if(!options){ + + return func; + }; + // Check for at least one attribute. + if(!(options.self || options.args || options.delay != null || options.periodical != null || options.attempt)){ + + return func; + }; + return function(event){ + + { + }; + // Convert (and copy) incoming arguments + var args = qx.lang.Array.fromArguments(arguments); + // Prepend static arguments + if(options.args){ + + args = options.args.concat(args); + }; + if(options.delay || options.periodical){ + + var returns = function(){ + + return func.apply(options.self || this, args); + }; + if(qx.core.Environment.get("qx.globalErrorHandling")){ + + returns = qx.event.GlobalError.observeMethod(returns); + }; + if(options.delay){ + + return window.setTimeout(returns, options.delay); + }; + if(options.periodical){ + + return window.setInterval(returns, options.periodical); + }; + } else if(options.attempt){ + + var ret = false; + try{ + + ret = func.apply(options.self || this, args); + } catch(ex) { + }; + return ret; + } else { + + return func.apply(options.self || this, args); + }; + }; + }, + /** + * Returns a function whose "this" is altered. + * + * + * *Native way* + * + * This is also a feature of JavaScript 1.8.5 and will be supplied + * by modern browsers. Including {@link qx.lang.normalize.Function} + * will supply a cross browser normalization of the native + * implementation. We like to encourage you to use the native function! + * + * + * *Syntax* + * + *
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