/** qooxdoo v4.0.1 | (c) 2013 1&1 Internet AG, http://1und1.de | http://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.globalErrorHandling":false,"qx.optimization.variants":true,"qx.revision":"","qx.theme":"qx.theme.Modern","qx.version":"4.0.1"};
for (var k in envinfo) qx.$$environment[k] = envinfo[k];
qx.$$packageData = {};
/** qooxdoo v4.0.1 | (c) 2013 1&1 Internet AG, http://1und1.de | http://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)
************************************************************************ */
/**
* Create namespace
*
* @ignore(qx.data)
* @ignore(qx.data.IListData)
* @ignore(qx.util.OOUtil)
*/
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 part = splits[0];
var parent = qx.$$namespaceRoot && qx.$$namespaceRoot[part] ? qx.$$namespaceRoot : window;
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 + "()";
};
};
},
base : function(args, varargs){
if(qx.Bootstrap.DEBUG){
if(!qx.Bootstrap.isFunction(args.callee.base)){
throw new Error("Cannot call super class. Method is not derived: " + args.callee.displayName);
};
};
if(arguments.length === 1){
return args.callee.base.call(this);
} else {
return args.callee.base.apply(this, Array.prototype.slice.call(arguments, 1));
};
},
define : function(name, config){
if(!config){
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;
// Enable basecalls within constructor
proto.base = qx.Bootstrap.base;
proto.name = proto.classname = name;
var members = config.members || {
};
var key,member;
// use keys to include the shadowed in IE
for(var i = 0,keys = qx.Bootstrap.keys(members),l = keys.length;i < l;i++){
key = keys[i];
member = members[key];
// Enable basecalls for methods
// Hint: proto[key] is not yet overwritten here
if(member instanceof Function && proto[key]){
member.base = proto[key];
};
proto[key] = member;
};
} else {
clazz = config.statics || {
};
// Merge class into former class (needed for 'optimize: ["statics"]')
if(qx.Bootstrap.$$registry && qx.Bootstrap.$$registry[name]){
var formerClass = qx.Bootstrap.$$registry[name];
// Add/overwrite properties and return early if necessary
if(this.keys(clazz).length !== 0){
// Execute defer to prevent too early overrides
if(config.defer){
config.defer(clazz, proto);
};
for(var curProp in clazz){
formerClass[curProp] = clazz[curProp];
};
return formerClass;
};
};
};
// Store type info
clazz.$$type = "Class";
// Attach toString
if(!clazz.hasOwnProperty("toString")){
clazz.toString = this.genericToString;
};
// Create namespace
var basename = name ? this.createNamespace(name, clazz) : "";
// Store names in constructor/object
clazz.name = clazz.classname = name;
clazz.basename = basename;
clazz.$$events = config.events;
// Execute defer section
if(config.defer){
config.defer(clazz, proto);
};
// Store class reference in global class registry
if(name != null){
qx.Bootstrap.$$registry[name] = clazz;
};
return clazz;
}
};
/**
* Internal class that is responsible for bootstrapping the qooxdoo
* framework at load time.
*/
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
* @signature function(name, object)
* @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 {String} last part of the namespace (which object is assigned to)
* @throws {Error} when the given object already exists.
*/
createNamespace : qx.Bootstrap.createNamespace,
/**
* Offers the ability to change the root for creating namespaces from window to
* whatever object is given.
*
* @param root {Object} The root to use.
* @internal
*/
setRoot : function(root){
qx.$$namespaceRoot = root;
},
/**
* Call the same method of the super class.
*
* @signature function(args, varargs)
* @param args {arguments} the arguments variable of the calling method
* @param varargs {var} variable number of arguments passed to the overwritten function
* @return {var} the return value of the method of the base class.
*/
base : qx.Bootstrap.base,
/**
* Define a new class using the qooxdoo class system.
* Lightweight version of {@link qx.Class#define} with less features.
*
* @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. The configuration map has the following keys:
*
Name | Type | Description |
---|---|---|
extend | Class | The super class the current class inherits from. |
construct | Function | The constructor of the class. |
statics | Map | Map of static values / functions of the class. |
members | Map | Map of instance members of the class. |
defer | Function | Function that is called at the end of * processing the class declaration. |
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];
},
/** @type {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
* @type {String[]}
*/
__shadowedKeys : ["isPrototypeOf", "hasOwnProperty", "toLocaleString", "toString", "valueOf", "propertyIsEnumerable", "constructor"],
/**
* 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"],
/**
* Mapping from JavaScript string representation of objects to names
* @internal
* @type {Map}
*/
__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 difference 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 difference 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: 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 is a base class for the OO system defined by Class, Mixin * and Interface. It contains helper which are basically needed to create the * Classes which define the OO system. */ qx.Bootstrap.define("qx.util.OOUtil", { statics : { /** * Whether the given class exists * * @param name {String} class name to check * @return {Boolean} true if class exists */ classIsDefined : function(name){ return qx.Bootstrap.getByName(name) !== undefined; }, /** * Returns the definition of the given property, if not redefined. * Returns null if the property does not exist. * * @param clazz {Class} class to check * @param name {String} name of the class to check for * @return {Map|null} whether the object support the given event. */ getPropertyDefinition : function(clazz, name){ while(clazz){ if(clazz.$$properties && clazz.$$properties[name]){ return clazz.$$properties[name]; }; clazz = clazz.superclass; }; return null; }, /** * Whether a class has the given property * * @param clazz {Class} class to check * @param name {String} name of the property to check for * @return {Boolean} whether the class includes the given property. */ hasProperty : function(clazz, name){ return !!qx.util.OOUtil.getPropertyDefinition(clazz, name); }, /** * Returns the event type of the given event. Returns null if * the event does not exist. * * @param clazz {Class} class to check * @param name {String} name of the event * @return {String|null} Event type of the given event. */ getEventType : function(clazz, name){ var clazz = clazz.constructor; while(clazz.superclass){ if(clazz.$$events && clazz.$$events[name] !== undefined){ return clazz.$$events[name]; }; clazz = clazz.superclass; }; return null; }, /** * Whether a class supports the given event type * * @param clazz {Class} class to check * @param name {String} name of the event to check for * @return {Boolean} whether the class supports the given event. */ supportsEvent : function(clazz, name){ return !!qx.util.OOUtil.getEventType(clazz, name); }, /** * Returns the class or one of its super classes which contains the * declaration of the given interface. Returns null if the interface is not * specified anywhere. * * @param clazz {Class} class to look for the interface * @param iface {Interface} interface to look for * @return {Class | null} the class which directly implements the given interface */ getByInterface : function(clazz, iface){ var list,i,l; while(clazz){ if(clazz.$$implements){ list = clazz.$$flatImplements; for(i = 0,l = list.length;i < l;i++){ if(list[i] === iface){ return clazz; }; }; }; clazz = clazz.superclass; }; return null; }, /** * Whether a given class or any of its super classes includes a given interface. * * This function will return "true" if the interface was defined * in the class declaration ({@link qx.Class#define}) of the class * or any of its super classes using the "implement" * key. * * @param clazz {Class} class to check * @param iface {Interface} the interface to check for * @return {Boolean} whether the class includes the interface. */ hasInterface : function(clazz, iface){ return !!qx.util.OOUtil.getByInterface(clazz, iface); }, /** * Returns a list of all mixins available in a given class. * * @param clazz {Class} class which should be inspected * @return {Mixin[]} array of mixins this class uses */ getMixins : function(clazz){ var list = []; while(clazz){ if(clazz.$$includes){ list.push.apply(list, clazz.$$flatIncludes); }; clazz = clazz.superclass; }; return list; } } }); /* ************************************************************************ 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 generator is also responsible for requiring the necessary implementation * classes for each check. When using a check of a new category, make sure to * rebuild you application and let the generator include the necessary files. * * The following table shows the available checks. If you are * interested in more details, check the reference to the implementation of * each check. Please do not use those check implementations directly, as the * Environment class comes with a smart caching feature. * *
Synchronous checks* |
* |||
Key |
* Type |
* Example |
* Details |
*
---|---|---|---|
browser | *|||
browser.documentmode | Integer | 0 |
* {@link qx.bom.client.Browser#getDocumentMode} | *
browser.name | String | chrome |
* {@link qx.bom.client.Browser#getName} | *
browser.quirksmode | Boolean | false |
* {@link qx.bom.client.Browser#getQuirksMode} | *
browser.version | String | 11.0 |
* {@link qx.bom.client.Browser#getVersion} | *
runtime | *|||
runtime.name | String | node.js |
* {@link qx.bom.client.Runtime#getName} | *
css | *|||
css.borderradius | String or null | borderRadius |
* {@link qx.bom.client.Css#getBorderRadius} | *
css.borderimage | String or null | WebkitBorderImage |
* {@link qx.bom.client.Css#getBorderImage} | *
css.borderimage.standardsyntax | Boolean or null | true |
* {@link qx.bom.client.Css#getBorderImageSyntax} | *
css.boxmodel | String | content |
* {@link qx.bom.client.Css#getBoxModel} | *
css.boxshadow | String or null | boxShadow |
* {@link qx.bom.client.Css#getBoxShadow} | *
css.gradient.linear | String or null | -moz-linear-gradient |
* {@link qx.bom.client.Css#getLinearGradient} | *
css.gradient.filter | Boolean | true |
* {@link qx.bom.client.Css#getFilterGradient} | *
css.gradient.radial | String or null | -moz-radial-gradient |
* {@link qx.bom.client.Css#getRadialGradient} | *
css.gradient.legacywebkit | Boolean | false |
* {@link qx.bom.client.Css#getLegacyWebkitGradient} | *
css.placeholder | Boolean | true |
* {@link qx.bom.client.Css#getPlaceholder} | *
css.textoverflow | String or null | textOverflow |
* {@link qx.bom.client.Css#getTextOverflow} | *
css.rgba | Boolean | true |
* {@link qx.bom.client.Css#getRgba} | *
css.usermodify | String or null | WebkitUserModify |
* {@link qx.bom.client.Css#getUserModify} | *
css.appearance | String or null | WebkitAppearance |
* {@link qx.bom.client.Css#getAppearance} | *
css.float | String or null | cssFloat |
* {@link qx.bom.client.Css#getFloat} | *
css.userselect | String or null | WebkitUserSelect |
* {@link qx.bom.client.Css#getUserSelect} | *
css.userselect.none | String or null | -moz-none |
* {@link qx.bom.client.Css#getUserSelectNone} | *
css.boxsizing | String or null | boxSizing |
* {@link qx.bom.client.Css#getBoxSizing} | *
css.animation | Object or null | {end-event: "webkitAnimationEnd", keyframes: "@-webkit-keyframes", play-state: null, name: "WebkitAnimation"} |
* {@link qx.bom.client.CssAnimation#getSupport} | *
css.animation.requestframe | String or null | mozRequestAnimationFrame |
* {@link qx.bom.client.CssAnimation#getRequestAnimationFrame} | *
css.transform | Object or null | {3d: true, origin: "WebkitTransformOrigin", name: "WebkitTransform", style: "WebkitTransformStyle", perspective: "WebkitPerspective", perspective-origin: "WebkitPerspectiveOrigin", backface-visibility: "WebkitBackfaceVisibility"} |
* {@link qx.bom.client.CssTransform#getSupport} | *
css.transform.3d | Boolean | false |
* {@link qx.bom.client.CssTransform#get3D} | *
css.transition | Object or null | {end-event: "webkitTransitionEnd", name: "WebkitTransition"} |
* {@link qx.bom.client.CssTransition#getSupport} | *
css.inlineblock | String or null | inline-block |
* {@link qx.bom.client.Css#getInlineBlock} | *
css.opacity | Boolean | true |
* {@link qx.bom.client.Css#getOpacity} | *
css.textShadow | Boolean | true |
* {@link qx.bom.client.Css#getTextShadow} | *
css.textShadow.filter | Boolean | true |
* {@link qx.bom.client.Css#getFilterTextShadow} | *
css.alphaimageloaderneeded | Boolean | false |
* {@link qx.bom.client.Css#getAlphaImageLoaderNeeded} | *
css.pointerevents | Boolean | true |
* {@link qx.bom.client.Css#getPointerEvents} | *
css.flexboxSyntax | String or null | "flex" |
* {@link qx.bom.client.Css#getFlexboxSyntax} | *
device | *|||
device.name | String | pc |
* {@link qx.bom.client.Device#getName} | *
device.type | String | mobile |
* {@link qx.bom.client.Device#getType} | *
device.pixelRatio | Number | 2 |
* {@link qx.bom.client.Device#getDevicePixelRatio} | *
device.touch | String | true |
* {@link qx.bom.client.Device#getTouch} | *
ecmascript | *|||
ecmascript.error.stacktrace | String or null | stack |
* {@link qx.bom.client.EcmaScript#getStackTrace} | *
ecmascript.array.indexof | Boolean | true |
* {@link qx.bom.client.EcmaScript#getArrayIndexOf} | *
ecmascript.array.lastindexof | Boolean | true |
* {@link qx.bom.client.EcmaScript#getArrayLastIndexOf} | *
ecmascript.array.foreach | Boolean | true |
* {@link qx.bom.client.EcmaScript#getArrayForEach} | *
ecmascript.array.filter | Boolean | true |
* {@link qx.bom.client.EcmaScript#getArrayFilter} | *
ecmascript.array.map | Boolean | true |
* {@link qx.bom.client.EcmaScript#getArrayMap} | *
ecmascript.array.some | Boolean | true |
* {@link qx.bom.client.EcmaScript#getArraySome} | *
ecmascript.array.every | Boolean | true |
* {@link qx.bom.client.EcmaScript#getArrayEvery} | *
ecmascript.array.reduce | Boolean | true |
* {@link qx.bom.client.EcmaScript#getArrayReduce} | *
ecmascript.array.reduceright | Boolean | true |
* {@link qx.bom.client.EcmaScript#getArrayReduceRight} | *
ecmascript.function.bind | Boolean | true |
* {@link qx.bom.client.EcmaScript#getFunctionBind} | *
ecmascript.object.keys | Boolean | true |
* {@link qx.bom.client.EcmaScript#getObjectKeys} | *
ecmascript.date.now | Boolean | true |
* {@link qx.bom.client.EcmaScript#getDateNow} | *
ecmascript.error.toString | Boolean | true |
* {@link qx.bom.client.EcmaScript#getErrorToString} | *
ecmascript.string.trim | Boolean | true |
* {@link qx.bom.client.EcmaScript#getStringTrim} | *
engine | *|||
engine.name | String | webkit |
* {@link qx.bom.client.Engine#getName} | *
engine.version | String | 534.24 |
* {@link qx.bom.client.Engine#getVersion} | *
event | *|||
event.mspointer | Boolean | true |
* {@link qx.bom.client.Event#getMsPointer} | *
event.touch | Boolean | false |
* {@link qx.bom.client.Event#getTouch} | *
event.help | Boolean | false |
* {@link qx.bom.client.Event#getHelp} | *
event.hashchange | Boolean | true |
* {@link qx.bom.client.Event#getHashChange} | *
event.dispatchevent | Boolean | true |
* {@link qx.bom.client.Event#getDispatchEvent} | *
event.customevent | Boolean | true |
* {@link qx.bom.client.Event#getCustomEvent} | *
event.mouseevent | Boolean | true |
* {@link qx.bom.client.Event#getMouseEvent} | *
event.mousewheel | Map | {type: "wheel", target: window} |
* {@link qx.bom.client.Event#getMouseWheel} | *
html | *|||
html.audio | Boolean | true |
* {@link qx.bom.client.Html#getAudio} | *
html.audio.mp3 | String | "" |
* {@link qx.bom.client.Html#getAudioMp3} | *
html.audio.ogg | String | "maybe" |
* {@link qx.bom.client.Html#getAudioOgg} | *
html.audio.wav | String | "probably" |
* {@link qx.bom.client.Html#getAudioWav} | *
html.audio.au | String | "maybe" |
* {@link qx.bom.client.Html#getAudioAu} | *
html.audio.aif | String | "probably" |
* {@link qx.bom.client.Html#getAudioAif} | *
html.canvas | Boolean | true |
* {@link qx.bom.client.Html#getCanvas} | *
html.classlist | Boolean | true |
* {@link qx.bom.client.Html#getClassList} | *
html.geolocation | Boolean | true |
* {@link qx.bom.client.Html#getGeoLocation} | *
html.storage.local | Boolean | true |
* {@link qx.bom.client.Html#getLocalStorage} | *
html.storage.session | Boolean | true |
* {@link qx.bom.client.Html#getSessionStorage} | *
html.storage.userdata | Boolean | true |
* {@link qx.bom.client.Html#getUserDataStorage} | *
html.svg | Boolean | true |
* {@link qx.bom.client.Html#getSvg} | *
html.video | Boolean | true |
* {@link qx.bom.client.Html#getVideo} | *
html.video.h264 | String | "probably" |
* {@link qx.bom.client.Html#getVideoH264} | *
html.video.ogg | String | "" |
* {@link qx.bom.client.Html#getVideoOgg} | *
html.video.webm | String | "maybe" |
* {@link qx.bom.client.Html#getVideoWebm} | *
html.vml | Boolean | false |
* {@link qx.bom.client.Html#getVml} | *
html.webworker | Boolean | true |
* {@link qx.bom.client.Html#getWebWorker} | *
html.filereader | Boolean | true |
* {@link qx.bom.client.Html#getFileReader} | *
html.xpath | Boolean | true |
* {@link qx.bom.client.Html#getXPath} | *
html.xul | Boolean | true |
* {@link qx.bom.client.Html#getXul} | *
html.console | Boolean | true |
* {@link qx.bom.client.Html#getConsole} | *
html.element.contains | Boolean | true |
* {@link qx.bom.client.Html#getContains} | *
html.element.compareDocumentPosition | Boolean | true |
* {@link qx.bom.client.Html#getCompareDocumentPosition} | *
html.element.textContent | Boolean | true |
* {@link qx.bom.client.Html#getTextContent} | *
html.image.naturaldimensions | Boolean | true |
* {@link qx.bom.client.Html#getNaturalDimensions} | *
html.history.state | Boolean | true |
* {@link qx.bom.client.Html#getHistoryState} | *
html.selection | String | getSelection |
* {@link qx.bom.client.Html#getSelection} | *
html.node.isequalnode | Boolean | true |
* {@link qx.bom.client.Html#getIsEqualNode} | *
XML | *|||
xml.implementation | Boolean | true |
* {@link qx.bom.client.Xml#getImplementation} | *
xml.domparser | Boolean | true |
* {@link qx.bom.client.Xml#getDomParser} | *
xml.selectsinglenode | Boolean | false |
* {@link qx.bom.client.Xml#getSelectSingleNode} | *
xml.selectnodes | Boolean | false |
* {@link qx.bom.client.Xml#getSelectNodes} | *
xml.getelementsbytagnamens | Boolean | true |
* {@link qx.bom.client.Xml#getElementsByTagNameNS} | *
xml.domproperties | Boolean | false |
* {@link qx.bom.client.Xml#getDomProperties} | *
xml.attributens | Boolean | true |
* {@link qx.bom.client.Xml#getAttributeNS} | *
xml.createelementns | Boolean | true |
* {@link qx.bom.client.Xml#getCreateElementNS} | *
xml.createnode | Boolean | false |
* {@link qx.bom.client.Xml#getCreateNode} | *
xml.getqualifieditem | Boolean | false |
* {@link qx.bom.client.Xml#getQualifiedItem} | *
Stylesheets | *|||
html.stylesheet.createstylesheet | Boolean | false |
* {@link qx.bom.client.Stylesheet#getCreateStyleSheet} | *
html.stylesheet.insertrule | Boolean | true |
* {@link qx.bom.client.Stylesheet#getInsertRule} | *
html.stylesheet.deleterule | Boolean | true |
* {@link qx.bom.client.Stylesheet#getDeleteRule} | *
html.stylesheet.addimport | Boolean | false |
* {@link qx.bom.client.Stylesheet#getAddImport} | *
html.stylesheet.removeimport | Boolean | false |
* {@link qx.bom.client.Stylesheet#getRemoveImport} | *
io | *|||
io.maxrequests | Integer | 4 |
* {@link qx.bom.client.Transport#getMaxConcurrentRequestCount} | *
io.ssl | Boolean | false |
* {@link qx.bom.client.Transport#getSsl} | *
io.xhr | String | xhr |
* {@link qx.bom.client.Transport#getXmlHttpRequest} | *
locale | *|||
locale | String | de |
* {@link qx.bom.client.Locale#getLocale} | *
locale.variant | String | de |
* {@link qx.bom.client.Locale#getVariant} | *
os | *|||
os.name | String | osx |
* {@link qx.bom.client.OperatingSystem#getName} | *
os.version | String | 10.6 |
* {@link qx.bom.client.OperatingSystem#getVersion} | *
os.scrollBarOverlayed | Boolean | false |
* {@link qx.bom.client.Scroll#scrollBarOverlayed} | *
phonegap | *|||
phonegap | Boolean | false |
* {@link qx.bom.client.PhoneGap#getPhoneGap} | *
phonegap.notification | Boolean | false |
* {@link qx.bom.client.PhoneGap#getNotification} | *
plugin | *|||
plugin.divx | Boolean | false |
* {@link qx.bom.client.Plugin#getDivX} | *
plugin.divx.version | String | * | {@link qx.bom.client.Plugin#getDivXVersion} | *
plugin.flash | Boolean | true |
* {@link qx.bom.client.Flash#isAvailable} | *
plugin.flash.express | Boolean | true |
* {@link qx.bom.client.Flash#getExpressInstall} | *
plugin.flash.strictsecurity | Boolean | true |
* {@link qx.bom.client.Flash#getStrictSecurityModel} | *
plugin.flash.version | String | 10.2.154 |
* {@link qx.bom.client.Flash#getVersion} | *
plugin.gears | Boolean | false |
* {@link qx.bom.client.Plugin#getGears} | *
plugin.activex | Boolean | false |
* {@link qx.bom.client.Plugin#getActiveX} | *
plugin.skype | Boolean | false |
* {@link qx.bom.client.Plugin#getSkype} | *
plugin.pdf | Boolean | false |
* {@link qx.bom.client.Plugin#getPdf} | *
plugin.pdf.version | String | * | {@link qx.bom.client.Plugin#getPdfVersion} | *
plugin.quicktime | Boolean | true |
* {@link qx.bom.client.Plugin#getQuicktime} | *
plugin.quicktime.version | String | 7.6 |
* {@link qx.bom.client.Plugin#getQuicktimeVersion} | *
plugin.silverlight | Boolean | false |
* {@link qx.bom.client.Plugin#getSilverlight} | *
plugin.silverlight.version | String | * | {@link qx.bom.client.Plugin#getSilverlightVersion} | *
plugin.windowsmedia | Boolean | false |
* {@link qx.bom.client.Plugin#getWindowsMedia} | *
plugin.windowsmedia.version | String | * | {@link qx.bom.client.Plugin#getWindowsMediaVersion} | *
qx | *|||
qx.allowUrlSettings | Boolean | true |
* default: false |
*
qx.allowUrlVariants | Boolean | true |
* default: false |
*
qx.application | String | name.space |
* default: <<application name>> |
*
qx.aspects | Boolean | false |
* default: false |
*
qx.debug | Boolean | true |
* default: true |
*
qx.debug.databinding | Boolean | false |
* default: false |
*
qx.debug.dispose | Boolean | false |
* default: false |
*
qx.debug.dispose.level | Integer | 0 |
* default: 0 |
*
qx.debug.io | Boolean | true |
* default: false |
*
qx.debug.io.remote | Boolean | true |
* default: false |
*
qx.debug.io.remote.data | Boolean | true |
* default: false |
*
qx.debug.property.level | Integer | 0 |
* default: 0 |
*
qx.debug.ui.queue | Boolean | true |
* default: true |
*
qx.dynlocale | Boolean | true |
* default: true |
*
qx.dyntheme | Boolean | true |
* default: true |
*
qx.globalErrorHandling | Boolean | true |
* default: true |
*
qx.mobile.nativescroll | Boolean | false |
* {@link qx.bom.client.Scroll#getNativeScroll} | *
qx.optimization.basecalls | Boolean | true |
* true if the corresp. optimize key is set in the config | *
qx.optimization.comments | Boolean | true |
* true if the corresp. optimize key is set in the config | *
qx.optimization.privates | Boolean | true |
* true if the corresp. optimize key is set in the config | *
qx.optimization.strings | Boolean | true |
* true if the corresp. optimize key is set in the config | *
qx.optimization.variables | Boolean | true |
* true if the corresp. optimize key is set in the config | *
qx.optimization.variants | Boolean | true |
* true if the corresp. optimize key is set in the config | *
qx.revision | String | 27348 |
* |
qx.theme | String | qx.theme.Modern |
* default: <<initial theme name>> |
*
qx.version | String | ${qxversion} |
* |
qx.blankpage | String | URI to blank.html page |
* |
module | *|||
module.databinding | Boolean | true |
* default: true |
*
module.logger | Boolean | true |
* default: true |
*
module.property | Boolean | true |
* default: true |
*
module.events | Boolean | true |
* default: true |
*
Asynchronous checks* |
* |||
html.dataurl | Boolean | true |
* {@link qx.bom.client.Html#getDataUrl} | *
plugin.pdfjs | Boolean | false |
* {@link qx.bom.client.Pdfjs#getPdfjs} | *
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.dyntheme", function(){
return true;
});
this.add("qx.mobile.emulatetouch", function(){
return false;
});
// @deprecated {4.0}
this.add("qx.emulatemouse", function(){
return false;
});
// @deprecated {4.0}
this.add("qx.blankpage", function(){
return "qx/static/blank.html";
});
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 (presto powered).
*
* Note that with opera >= 15 their engine switched to blink, so
* things like "window.opera" don't work anymore or changed (e.g. user agent).
*
* @return {Boolean} true, if its opera (presto powered).
*/
__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.
*
* Note:
* "window.controllers" is gone/hidden with Firefox 30+
* "window.navigator.mozApps" is supported since Firefox 11+
* "window.navigator.product" is actually useless cause the HTML5 spec
* states it should be the constant "Gecko".
*
* - https://developer.mozilla.org/en-US/docs/Web/API/Window.controllers
* - https://developer.mozilla.org/en-US/docs/Web/API/Navigator.mozApps
* - http://www.w3.org/html/wg/drafts/html/master/webappapis.html#navigatorid
*
* @return {Boolean} true, if its gecko.
*/
__isGecko : function(){
return (window.controllers || window.navigator.mozApps) && 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 is responsible for the normalization of the native 'Array' object.
* It checks if these methods are available and, if not, appends them to
* ensure compatibility in all browsers.
* For usage samples, check out the attached links.
*
* MDN documentation © Mozilla Contributors.
*
* @group (Polyfill)
*/
qx.Bootstrap.define("qx.lang.normalize.Array", {
statics : {
/**
* The indexOf()
method returns the first index at which a given
* element can be found in the array, or -1 if it is not present.
*
* MDN documentation |
* Annotated ES5 Spec
*
* @param searchElement {var} Element to locate in the array.
* @param fromIndex {Integer?} The index to start the search at.
* If the index is greater than or equal to the array's length,
* -1 is returned, which means the array will not be searched.
* If the provided index value is a negative number, it is taken
* as the offset from the end of the array. Note: if the provided
* index is negative, the array is still searched from front to
* back. If the calculated index is less than 0, then the whole
* array will be searched. Default: 0 (Entire array is searched)
* @return {Integer} The first index at which the element was found or -1
* if the element was not found in the array
*/
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;
},
/**
* The lastIndexOf()
method returns the last index
* at which a given element can be found in the array, or -1 if
* it is not present. The array is searched backwards, starting at
* fromIndex
.
*
* MDN documentation |
* Annotated ES5 Spec
*
* @param searchElement {var} Element to locate in the array.
* @param fromIndex {Integer?} 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 last index at which the element was found or -1
* if the element was not found in the array
*/
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;
},
/**
* The forEach()
method executes a provided function
* once per array element. You can not break the loop with this function.
* If you want to do so, use {@link #some} or {@link #every}.
*
* MDN documentation |
* Annotated ES5 Spec
*
* @param callback {Function} Function to execute for each element.
* @param obj {Object?} Value to use as this
when executing callback
.
*/
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);
};
};
},
/**
* The filter()
method creates a new array with
* all elements that pass the test implemented by the provided
* function.
*
* MDN documentation |
* Annotated ES5 Spec
*
* @param callback {Function} Function to test each element of the array.
* @param obj {Object?} Value to use as this
when executing callback
.
* @return {Array} filtered array
*/
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;
},
/**
* The map()
method creates a new array with
* the results of calling a provided function on every
* element in this array.
*
* MDN documentation |
* Annotated ES5 Spec
*
* @param callback {Function} Function that produces an element of the new Array,
* taking three arguments:
* currentValue
The current element being processed in the array.index
The index of the current element being processed in the array.array
The array map was called upon.this
when executing callback
.
* @return {Array} result array
*/
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;
},
/**
* The some()
method tests whether some
* element in the array passes the test implemented by
* the provided function.
*
* MDN documentation |
* Annotated ES5 Spec
*
* @param callback {Function} Function to test for each element.
* @param obj {Object?} Value to use as this
when executing callback
.
* @return {Array} result array
*/
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;
},
/**
* The every()
method tests whether all elements
* in the array pass the test implemented by the provided function.
*
* MDN documentation |
* Annotated ES5 Spec
*
* @param callback {Function} Function to test for each element.
* @param obj {Object?} Value to use as this
when executing callback
.
* @return {Array} result array
*/
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;
},
/**
* The reduce()
method applies a function against
* an accumulator and each value of the array (from left-to-right)
* has to reduce it to a single value.
*
* MDN documentation |
* Annotated ES5 Spec
*
* @param callback {Function} Function to execute on each value in
* the array, taking four arguments:
* previousValue
The value previously returned in
* the last invocation of the callback, or initialValue, if supplied.
* (See below.)currentValue
The current element being processed in the array.index
The index of the current element being processed in the array.array
The array reduce
was called upon.previousValue
The value previously returned in
* the last invocation of the callback, or initialValue, if supplied.
* (See below.)currentValue
The current element being processed in the array.index
The index of the current element being processed in the array.array
The array reduce
was called upon.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.
*
* @require(qx.bom.client.Engine)
* @require(qx.lang.normalize.Array)
*/
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)
************************************************************************ */
/**
* 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.
*
* @ignore(q)
*
* @group (Core)
*/
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, a DOM element node or a DOM document node will
* be ignored.
* @param clazz {Class} The class of the new collection.
* @return {q} A new initialized collection.
*/
$init : function(arg, clazz){
var clean = [];
for(var i = 0;i < arg.length;i++){
// check for node or window object
var isNode = !!(arg[i] && (arg[i].nodeType === 1 || arg[i].nodeType === 9 || arg[i].nodeType === 11));
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]);
};
};
if(arg[0] && arg[0].getAttribute && arg[0].getAttribute("data-qx-class")){
clazz = qx.Bootstrap.getByName(arg[0].getAttribute("data-qx-class")) || clazz;
};
var col = qx.lang.Array.cast(clean, clazz);
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.
*
* @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. The configuration map has the following keys:
* Name | Type | Description |
---|---|---|
extend | Class | The super class the current class inherits from. |
construct | Function | The constructor of the class. |
statics | Map | Map of static values / functions of the class. |
members | Map | Map of instance members of the class. |
defer | Function | Function that is called at the end of * processing the class declaration. |
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 .
*
* @ignore(qx.data)
* @ignore(qx.data.IListData)
* @ignore(qx.Class.*)
* @require(qx.lang.normalize.Date)
*/
qx.Bootstrap.define("qx.lang.Array", {
statics : {
/**
* 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++){
if(arr[i] != undefined){
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 does not modify 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
*/
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{
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.10.18
Homepage:
http://sizzlejs.com/
Documentation:
https://github.com/jquery/sizzle/wiki/Sizzle-Documentation
Discussion:
https://groups.google.com/forum/#!forum/sizzlejs
Code:
https://github.com/jquery/sizzle
Copyright:
(c) 2009, 2013 jQuery Foundation and other contributors
License:
MIT: http://www.opensource.org/licenses/mit-license.php
----------------------------------------------------------------------
Copyright 2013 jQuery Foundation and other contributors
http://jquery.com/
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:
v1.10.18
commit a9eb3ca3c5e1b568057390f73da385809ac69340
************************************************************************ */
/**
* 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 v1.10.18
* http://sizzlejs.com/
*
* Copyright 2013 jQuery Foundation, Inc. and other contributors
* Released under the MIT license
* http://jquery.org/license
*
* Date: 2014-02-05
*/
(function(window){
var i,support,Expr,getText,isXML,compile,select,outermostContext,sortInput,hasDuplicate,// Local document vars
setDocument,document,docElem,documentIsHTML,rbuggyQSA,rbuggyMatches,matches,contains,// Instance-specific data
expando = "sizzle" + -(new Date()),preferredDoc = window.document,dirruns = 0,done = 0,classCache = createCache(),tokenCache = createCache(),compilerCache = createCache(),sortOrder = function(a, b){
if(a === b){
hasDuplicate = true;
};
return 0;
},// General-purpose constants
strundefined = typeof undefined,MAX_NEGATIVE = 1 << 31,// Instance methods
hasOwn = ({
}).hasOwnProperty,arr = [],pop = arr.pop,push_native = arr.push,push = arr.push,slice = arr.slice,// Use a stripped-down indexOf if we can't use a native one
indexOf = arr.indexOf || function(elem){
var i = 0,len = this.length;
for(;i < len;i++){
if(this[i] === elem){
return i;
};
};
return -1;
},booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",// Regular expressions
// 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
attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",// Prefer arguments quoted,
// then not containing pseudos/brackets,
// then attribute selectors/non-parenthetical expressions,
// then anything else
// These preferences are here to reduce the number of selectors
// needing tokenize in the PSEUDO preFilter
pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace(3, 8) + ")*)|.*)\\)|)",// 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 + "*([>+~]|" + whitespace + ")" + whitespace + "*"),rattributeQuotes = new RegExp("=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g"),rpseudo = new RegExp(pseudos),ridentifier = new RegExp("^" + identifier + "$"),matchExpr = {
"ID" : new RegExp("^#(" + characterEncoding + ")"),
"CLASS" : new RegExp("^\\.(" + characterEncoding + ")"),
"TAG" : new RegExp("^(" + characterEncoding.replace("w", "w*") + ")"),
"ATTR" : new RegExp("^" + attributes),
"PSEUDO" : new RegExp("^" + pseudos),
"CHILD" : new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i"),
"bool" : new RegExp("^(?:" + booleans + ")$", "i"),
// For use in libraries implementing .is()
// We use this for POS matching in `select`
"needsContext" : new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i")
},rinputs = /^(?:input|select|textarea|button)$/i,rheader = /^h\d$/i,rnative = /^[^{]+\{\s*\[native \w/,// Easily-parseable/retrievable ID or TAG or CLASS selectors
rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,rsibling = /[+~]/,rescape = /'|\\/g,// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
runescape = new RegExp("\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig"),funescape = function(_, escaped, escapedWhitespace){
var high = "0x" + escaped - 0x10000;
// NaN means non-codepoint
// Support: Firefox<24
// Workaround erroneous numeric interpretation of +"0x"
return high !== high || escapedWhitespace ? escaped : high < 0 ? // BMP codepoint
String.fromCharCode(high + 0x10000) : // Supplemental Plane codepoint (surrogate pair)
String.fromCharCode(high >> 10 | 0xD800, high & 0x3FF | 0xDC00);
};
// Optimize for push.apply( _, NodeList )
try{
push.apply((arr = slice.call(preferredDoc.childNodes)), preferredDoc.childNodes);
// Support: Android<4.0
// Detect silently failing push.apply
arr[preferredDoc.childNodes.length].nodeType;
} catch(e) {
push = {
apply : arr.length ? // Leverage slice if possible
function(target, els){
push_native.apply(target, slice.call(els));
} : // Support: IE<9
// Otherwise append directly
function(target, els){
var j = target.length,i = 0;
// Can't trust NodeList.length
while((target[j++] = els[i++])){
};
target.length = j - 1;
}
};
};
function Sizzle(selector, context, results, seed){
var match,elem,m,nodeType,// QSA vars
i,groups,old,nid,newContext,newSelector;
if((context ? context.ownerDocument || context : preferredDoc) !== document){
setDocument(context);
};
context = context || document;
results = results || [];
if(!selector || typeof selector !== "string"){
return results;
};
if((nodeType = context.nodeType) !== 1 && nodeType !== 9){
return [];
};
if(documentIsHTML && !seed){
// Shortcuts
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 (jQuery #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, context.getElementsByTagName(selector));
return results;
} else if((m = match[3]) && support.getElementsByClassName && context.getElementsByClassName){
push.apply(results, context.getElementsByClassName(m));
return results;
};;
};
// QSA path
if(support.qsa && (!rbuggyQSA || !rbuggyQSA.test(selector))){
nid = old = expando;
newContext = context;
newSelector = 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(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 + toSelector(groups[i]);
};
newContext = rsibling.test(selector) && testContext(context.parentNode) || context;
newSelector = groups.join(",");
};
if(newSelector){
try{
push.apply(results, newContext.querySelectorAll(newSelector));
return results;
} catch(qsaError) {
}finally{
if(!old){
context.removeAttribute("id");
};
};
};
};
};
// All others
return select(selector.replace(rtrim, "$1"), context, results, seed);
};
/**
* Create key-value caches of limited size
* @return {Function} Returns the Object data after storing it on itself with
* property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
* deleting the oldest entry
*/
function createCache(){
var keys = [];
function cache(key, value){
// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
if(keys.push(key + " ") > Expr.cacheLength){
// Only keep the most recent entries
delete cache[keys.shift()];
};
return (cache[key + " "] = value);
};
return cache;
};
/**
* Mark a function for special use by Sizzle
* @param fn {Function} The function to mark
*/
function markFunction(fn){
fn[expando] = true;
return fn;
};
/**
* Support testing using an element
* @param fn {Function} Passed the created div and expects a boolean result
*/
function assert(fn){
var div = document.createElement("div");
try{
return !!fn(div);
} catch(e) {
return false;
}finally{
// Remove from its parent by default
if(div.parentNode){
div.parentNode.removeChild(div);
};
// release memory in IE
div = null;
};
};
/**
* Adds the same handler for all of the specified attrs
* @param attrs {String} Pipe-separated list of attributes
* @param handler {Function} The method that will be applied
*/
function addHandle(attrs, handler){
var arr = attrs.split("|"),i = attrs.length;
while(i--){
Expr.attrHandle[arr[i]] = handler;
};
};
/**
* Checks document order of two siblings
* @param a {Element}
* @param b {Element}
* @return {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
*/
function siblingCheck(a, b){
var cur = b && a,diff = cur && a.nodeType === 1 && b.nodeType === 1 && (~b.sourceIndex || MAX_NEGATIVE) - (~a.sourceIndex || MAX_NEGATIVE);
// Use IE sourceIndex if available on both nodes
if(diff){
return diff;
};
// Check if b follows a
if(cur){
while((cur = cur.nextSibling)){
if(cur === b){
return -1;
};
};
};
return a ? 1 : -1;
};
/**
* Returns a function to use in pseudos for input types
* @param type {String}
*/
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
* @param type {String}
*/
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
* @param fn {Function}
*/
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]);
};
};
});
});
};
/**
* Checks a node for validity as a Sizzle context
* @param context {Element|Object}
* @return {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
*/
function testContext(context){
return context && typeof context.getElementsByTagName !== strundefined && context;
};
// Expose support vars for convenience
support = Sizzle.support = {
};
/**
* Detects XML nodes
* @param elem {Element|Object} An element or a document
* @return {Boolean} True iff elem is a non-HTML XML node
*/
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;
};
/**
* Sets document-related variables once based on the current document
* @param doc {Element|Object?} An element or document object to use to set the document
* @return {Object} Returns the current document
*/
setDocument = Sizzle.setDocument = function(node){
var hasCompare,doc = node ? node.ownerDocument || node : preferredDoc,parent = doc.defaultView;
// If no document and documentElement is available, return
if(doc === document || doc.nodeType !== 9 || !doc.documentElement){
return document;
};
// Set our document
document = doc;
docElem = doc.documentElement;
// Support tests
documentIsHTML = !isXML(doc);
// Support: IE>8
// If iframe document is assigned to "document" variable and if iframe has been reloaded,
// IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
// IE6-8 do not support the defaultView property so parent will be undefined
if(parent && parent !== parent.top){
// IE11 does not have attachEvent, so all must suffer
if(parent.addEventListener){
parent.addEventListener("unload", function(){
setDocument();
}, false);
} else if(parent.attachEvent){
parent.attachEvent("onunload", function(){
setDocument();
});
};
};
/* Attributes
---------------------------------------------------------------------- */
// Support: IE<8
// Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
support.attributes = assert(function(div){
div.className = "i";
return !div.getAttribute("className");
});
/* getElement(s)By*
---------------------------------------------------------------------- */
// Check if getElementsByTagName("*") returns only elements
support.getElementsByTagName = assert(function(div){
div.appendChild(doc.createComment(""));
return !div.getElementsByTagName("*").length;
});
// Check if getElementsByClassName can be trusted
support.getElementsByClassName = rnative.test(doc.getElementsByClassName) && assert(function(div){
div.innerHTML = "";
// Support: Safari<4
// Catch class over-caching
div.firstChild.className = "i";
// Support: Opera<10
// Catch gEBCN failure to find non-leading classes
return div.getElementsByClassName("i").length === 2;
});
// Support: IE<10
// Check if getElementById returns elements by name
// The broken getElementById methods don't pick up programatically-set names,
// so use a roundabout getElementsByName test
support.getById = assert(function(div){
docElem.appendChild(div).id = expando;
return !doc.getElementsByName || !doc.getElementsByName(expando).length;
});
// ID find and filter
if(support.getById){
Expr.find["ID"] = function(id, context){
if(typeof context.getElementById !== strundefined && documentIsHTML){
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] : [];
};
};
Expr.filter["ID"] = function(id){
var attrId = id.replace(runescape, funescape);
return function(elem){
return elem.getAttribute("id") === attrId;
};
};
} else {
// Support: IE6/7
// getElementById is not reliable as a find shortcut
delete Expr.find["ID"];
Expr.filter["ID"] = function(id){
var attrId = id.replace(runescape, funescape);
return function(elem){
var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
return node && node.value === attrId;
};
};
};
// Tag
Expr.find["TAG"] = support.getElementsByTagName ? function(tag, context){
if(typeof context.getElementsByTagName !== strundefined){
return context.getElementsByTagName(tag);
};
} : function(tag, context){
var elem,tmp = [],i = 0,results = context.getElementsByTagName(tag);
// Filter out possible comments
if(tag === "*"){
while((elem = results[i++])){
if(elem.nodeType === 1){
tmp.push(elem);
};
};
return tmp;
};
return results;
};
// Class
Expr.find["CLASS"] = support.getElementsByClassName && function(className, context){
if(typeof context.getElementsByClassName !== strundefined && documentIsHTML){
return context.getElementsByClassName(className);
};
};
/* QSA/matchesSelector
---------------------------------------------------------------------- */
// QSA and matchesSelector support
// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
rbuggyMatches = [];
// qSa(:focus) reports false when true (Chrome 21)
// We allow this because of a bug in IE8/9 that throws an error
// whenever `document.activeElement` is accessed on an iframe
// So, we allow :focus to pass through QSA all the time to avoid the IE error
// See http://bugs.jquery.com/ticket/13378
rbuggyQSA = [];
if((support.qsa = rnative.test(doc.querySelectorAll))){
// 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 explicitly
// setting a boolean content attribute,
// since its presence should be enough
// http://bugs.jquery.com/ticket/12359
div.innerHTML = "";
// Support: IE8, Opera 10-12
// Nothing should be selected when empty strings follow ^= or $= or *=
if(div.querySelectorAll("[t^='']").length){
rbuggyQSA.push("[*^$]=" + whitespace + "*(?:''|\"\")");
};
// Support: IE8
// Boolean attributes and "value" are not treated correctly
if(!div.querySelectorAll("[selected]").length){
rbuggyQSA.push("\\[" + whitespace + "*(?:value|" + booleans + ")");
};
// Webkit/Opera - :checked should return selected option elements
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
// IE8 throws error here and will not see later tests
if(!div.querySelectorAll(":checked").length){
rbuggyQSA.push(":checked");
};
});
assert(function(div){
// Support: Windows 8 Native Apps
// The type and name attributes are restricted during .innerHTML assignment
var input = doc.createElement("input");
input.setAttribute("type", "hidden");
div.appendChild(input).setAttribute("name", "D");
// Support: IE8
// Enforce case-sensitivity of name attribute
if(div.querySelectorAll("[name=d]").length){
rbuggyQSA.push("name" + whitespace + "*[*^$|!~]?=");
};
// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
// IE8 throws error here and will not see later tests
if(!div.querySelectorAll(":enabled").length){
rbuggyQSA.push(":enabled", ":disabled");
};
// Opera 10-11 does not throw on post-comma invalid pseudos
div.querySelectorAll("*,:x");
rbuggyQSA.push(",.*:");
});
};
if((support.matchesSelector = rnative.test((matches = docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || docElem.msMatchesSelector)))){
assert(function(div){
// Check to see if it's possible to do matchesSelector
// on a disconnected node (IE 9)
support.disconnectedMatch = matches.call(div, "div");
// This should fail with an exception
// Gecko does not error, returns false instead
matches.call(div, "[s!='']:x");
rbuggyMatches.push("!=", pseudos);
});
};
rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|"));
rbuggyMatches = rbuggyMatches.length && new RegExp(rbuggyMatches.join("|"));
/* Contains
---------------------------------------------------------------------- */
hasCompare = rnative.test(docElem.compareDocumentPosition);
// Element contains another
// Purposefully does not implement inclusive descendent
// As in, an element does not contain itself
contains = hasCompare || rnative.test(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) : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16));
} : function(a, b){
if(b){
while((b = b.parentNode)){
if(b === a){
return true;
};
};
};
return false;
};
/* Sorting
---------------------------------------------------------------------- */
// Document order sorting
sortOrder = hasCompare ? function(a, b){
// Flag for duplicate removal
if(a === b){
hasDuplicate = true;
return 0;
};
// Sort on method existence if only one input has compareDocumentPosition
var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
if(compare){
return compare;
};
// Calculate position if both inputs belong to the same document
compare = (a.ownerDocument || a) === (b.ownerDocument || b) ? a.compareDocumentPosition(b) : // Otherwise we know they are disconnected
1;
// Disconnected nodes
if(compare & 1 || (!support.sortDetached && b.compareDocumentPosition(a) === compare)){
// Choose the first element that is related to our preferred document
if(a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a)){
return -1;
};
if(b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b)){
return 1;
};
// Maintain original order
return sortInput ? (indexOf.call(sortInput, a) - indexOf.call(sortInput, b)) : 0;
};
return compare & 4 ? -1 : 1;
} : function(a, b){
// Exit early if the nodes are identical
if(a === b){
hasDuplicate = true;
return 0;
};
var cur,i = 0,aup = a.parentNode,bup = b.parentNode,ap = [a],bp = [b];
// Parentless nodes are either documents or disconnected
if(!aup || !bup){
return a === doc ? -1 : b === doc ? 1 : aup ? -1 : bup ? 1 : sortInput ? (indexOf.call(sortInput, a) - indexOf.call(sortInput, b)) : 0;
} else if(aup === bup){
return siblingCheck(a, b);
};
// Otherwise we need full lists of their ancestors for comparison
cur = a;
while((cur = cur.parentNode)){
ap.unshift(cur);
};
cur = b;
while((cur = cur.parentNode)){
bp.unshift(cur);
};
// Walk down the tree looking for a discrepancy
while(ap[i] === bp[i]){
i++;
};
return i ? // Do a sibling check if the nodes have a common ancestor
siblingCheck(ap[i], bp[i]) : // Otherwise nodes in our document sort first
ap[i] === preferredDoc ? -1 : bp[i] === preferredDoc ? 1 : 0;
};
return doc;
};
Sizzle.matches = function(expr, elements){
return Sizzle(expr, null, null, elements);
};
Sizzle.matchesSelector = function(elem, expr){
// Set document vars if needed
if((elem.ownerDocument || elem) !== document){
setDocument(elem);
};
// Make sure that attribute selectors are quoted
expr = expr.replace(rattributeQuotes, "='$1']");
if(support.matchesSelector && documentIsHTML && (!rbuggyMatches || !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 || support.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, document, null, [elem]).length > 0;
};
Sizzle.contains = function(context, elem){
// Set document vars if needed
if((context.ownerDocument || context) !== document){
setDocument(context);
};
return contains(context, elem);
};
Sizzle.attr = function(elem, name){
// Set document vars if needed
if((elem.ownerDocument || elem) !== document){
setDocument(elem);
};
var fn = Expr.attrHandle[name.toLowerCase()],// Don't get fooled by Object.prototype properties (jQuery #13807)
val = fn && hasOwn.call(Expr.attrHandle, name.toLowerCase()) ? fn(elem, name, !documentIsHTML) : undefined;
return val !== undefined ? val : support.attributes || !documentIsHTML ? elem.getAttribute(name) : (val = elem.getAttributeNode(name)) && val.specified ? val.value : null;
};
Sizzle.error = function(msg){
throw new Error("Syntax error, unrecognized expression: " + msg);
};
/**
* Document sorting and removing duplicates
* @param results {ArrayLike}
*/
Sizzle.uniqueSort = function(results){
var elem,duplicates = [],j = 0,i = 0;
// Unless we *know* we can detect duplicates, assume their presence
hasDuplicate = !support.detectDuplicates;
sortInput = !support.sortStable && results.slice(0);
results.sort(sortOrder);
if(hasDuplicate){
while((elem = results[i++])){
if(elem === results[i]){
j = duplicates.push(i);
};
};
while(j--){
results.splice(duplicates[j], 1);
};
};
// Clear input after sorting to release objects
// See https://github.com/jquery/sizzle/pull/225
sortInput = null;
return results;
};
/**
* Utility function for retrieving the text value of an array of DOM nodes
* @param elem {Array|Element}
*/
getText = Sizzle.getText = function(elem){
var node,ret = "",i = 0,nodeType = elem.nodeType;
if(!nodeType){
// If no nodeType, this is expected to be an array
while((node = elem[i++])){
// Do not traverse comment nodes
ret += getText(node);
};
} else if(nodeType === 1 || nodeType === 9 || nodeType === 11){
// Use textContent for elements
// innerText usage removed for consistency of new lines (jQuery #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;
};;
// Do not include comment or processing instruction nodes
return ret;
};
Expr = Sizzle.selectors = {
// Can be adjusted by the user
cacheLength : 50,
createPseudo : markFunction,
match : matchExpr,
attrHandle : {
},
find : {
},
relative : {
">" : {
dir : "parentNode",
first : true
},
" " : {
dir : "parentNode"
},
"+" : {
dir : "previousSibling",
first : true
},
"~" : {
dir : "previousSibling"
}
},
preFilter : {
"ATTR" : function(match){
match[1] = match[1].replace(runescape, funescape);
// Move the given value to match[3] whether quoted or unquoted
match[3] = (match[4] || match[5] || "").replace(runescape, funescape);
if(match[2] === "~="){
match[3] = " " + match[3] + " ";
};
return match.slice(0, 4);
},
"CHILD" : function(match){
/* matches from matchExpr["CHILD"]
1 type (only|nth|...)
2 what (child|of-type)
3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
4 xn-component of xn+y argument ([+-]?\d*n|)
5 sign of xn-component
6 x of xn-component
7 sign of y-component
8 y of y-component
*/
match[1] = match[1].toLowerCase();
if(match[1].slice(0, 3) === "nth"){
// nth-* requires argument
if(!match[3]){
Sizzle.error(match[0]);
};
// numeric x and y parameters for Expr.filter.CHILD
// remember that false/true cast respectively to 0/1
match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd"));
match[5] = +((match[7] + match[8]) || match[3] === "odd");
} else if(match[3]){
Sizzle.error(match[0]);
};
return match;
},
"PSEUDO" : function(match){
var excess,unquoted = !match[5] && match[2];
if(matchExpr["CHILD"].test(match[0])){
return null;
};
// Accept quoted arguments as-is
if(match[3] && match[4] !== undefined){
match[2] = match[4];
} else if(unquoted && 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
match[0] = match[0].slice(0, excess);
match[2] = unquoted.slice(0, excess);
};
// Return only captures needed by the pseudo filter method (type and argument)
return match.slice(0, 3);
}
},
filter : {
"TAG" : function(nodeNameSelector){
var nodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase();
return nodeNameSelector === "*" ? function(){
return true;
} : function(elem){
return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
};
},
"CLASS" : function(className){
var pattern = classCache[className + " "];
return pattern || (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) && classCache(className, function(elem){
return pattern.test(typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "");
});
},
"ATTR" : function(name, operator, check){
return function(elem){
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.slice(-check.length) === check : operator === "~=" ? (" " + result + " ").indexOf(check) > -1 : operator === "|=" ? result === check || result.slice(0, check.length + 1) === check + "-" : false;
};
},
"CHILD" : function(type, what, argument, first, last){
var simple = type.slice(0, 3) !== "nth",forward = type.slice(-4) !== "last",ofType = what === "of-type";
return first === 1 && last === 0 ? // Shortcut for :nth-*(n)
function(elem){
return !!elem.parentNode;
} : function(elem, context, xml){
var cache,outerCache,node,diff,nodeIndex,start,dir = simple !== forward ? "nextSibling" : "previousSibling",parent = elem.parentNode,name = ofType && elem.nodeName.toLowerCase(),useCache = !xml && !ofType;
if(parent){
// :(first|last|only)-(child|of-type)
if(simple){
while(dir){
node = elem;
while((node = node[dir])){
if(ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1){
return false;
};
};
// Reverse direction for :only-* (if we haven't yet done so)
start = dir = type === "only" && !start && "nextSibling";
};
return true;
};
start = [forward ? parent.firstChild : parent.lastChild];
// non-xml :nth-child(...) stores cache data on `parent`
if(forward && useCache){
// Seek `elem` from a previously-cached index
outerCache = parent[expando] || (parent[expando] = {
});
cache = outerCache[type] || [];
nodeIndex = cache[0] === dirruns && cache[1];
diff = cache[0] === dirruns && cache[2];
node = nodeIndex && parent.childNodes[nodeIndex];
while((node = ++nodeIndex && node && node[dir] || // Fallback to seeking `elem` from the start
(diff = nodeIndex = 0) || start.pop())){
// When found, cache indexes on `parent` and break
if(node.nodeType === 1 && ++diff && node === elem){
outerCache[type] = [dirruns, nodeIndex, diff];
break;
};
};
} else if(useCache && (cache = (elem[expando] || (elem[expando] = {
}))[type]) && cache[0] === dirruns){
diff = cache[1];
} else {
// Use the same loop as above to seek `elem` from the start
while((node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop())){
if((ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1) && ++diff){
// Cache the index of each encountered element
if(useCache){
(node[expando] || (node[expando] = {
}))[type] = [dirruns, diff];
};
if(node === elem){
break;
};
};
};
};
// Incorporate the offset, then check against cycle size
diff -= last;
return diff === first || (diff % first === 0 && diff / first >= 0);
};
};
},
"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 : {
// Potentially complex 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;
};
}),
// "Whether an element is represented by a :lang() selector
// is based solely on the element's language value
// being equal to the identifier C,
// or beginning with the identifier C immediately followed by "-".
// The matching of C against the element's language value is performed case-insensitively.
// The identifier C does not have to be a valid language name."
// http://www.w3.org/TR/selectors/#lang-pseudo
"lang" : markFunction(function(lang){
// lang value must be a valid identifier
if(!ridentifier.test(lang || "")){
Sizzle.error("unsupported lang: " + lang);
};
lang = lang.replace(runescape, funescape).toLowerCase();
return function(elem){
var elemLang;
do {
if((elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang"))){
elemLang = elemLang.toLowerCase();
return elemLang === lang || elemLang.indexOf(lang + "-") === 0;
};
}while(((elem = elem.parentNode) && elem.nodeType === 1));
return false;
};
}),
// Miscellaneous
"target" : function(elem){
var hash = window.location && window.location.hash;
return hash && hash.slice(1) === elem.id;
},
"root" : function(elem){
return elem === docElem;
},
"focus" : function(elem){
return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
},
// Boolean properties
"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;
},
// Contents
"empty" : function(elem){
// http://www.w3.org/TR/selectors/#empty-pseudo
// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
// but not by others (comment: 8; processing instruction: 7; etc.)
// nodeType < 6 works because attributes (2) do not appear as children
for(elem = elem.firstChild;elem;elem = elem.nextSibling){
if(elem.nodeType < 6){
return false;
};
};
return true;
},
"parent" : function(elem){
return !Expr.pseudos["empty"](elem);
},
// Element/input types
"header" : function(elem){
return rheader.test(elem.nodeName);
},
"input" : function(elem){
return rinputs.test(elem.nodeName);
},
"button" : function(elem){
var name = elem.nodeName.toLowerCase();
return name === "input" && elem.type === "button" || name === "button";
},
"text" : function(elem){
var attr;
return elem.nodeName.toLowerCase() === "input" && elem.type === "text" && // Support: IE<8
// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
((attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text");
},
// Position-in-collection
"first" : createPositionalPseudo(function(){
return [0];
}),
"last" : createPositionalPseudo(function(matchIndexes, length){
return [length - 1];
}),
"eq" : createPositionalPseudo(function(matchIndexes, length, argument){
return [argument < 0 ? argument + length : argument];
}),
"even" : createPositionalPseudo(function(matchIndexes, length){
var i = 0;
for(;i < length;i += 2){
matchIndexes.push(i);
};
return matchIndexes;
}),
"odd" : createPositionalPseudo(function(matchIndexes, length){
var i = 1;
for(;i < length;i += 2){
matchIndexes.push(i);
};
return matchIndexes;
}),
"lt" : createPositionalPseudo(function(matchIndexes, length, argument){
var i = argument < 0 ? argument + length : argument;
for(;--i >= 0;){
matchIndexes.push(i);
};
return matchIndexes;
}),
"gt" : createPositionalPseudo(function(matchIndexes, length, argument){
var i = argument < 0 ? argument + length : argument;
for(;++i < length;){
matchIndexes.push(i);
};
return matchIndexes;
})
}
};
Expr.pseudos["nth"] = Expr.pseudos["eq"];
// Add button/input type pseudos
for(i in {
radio : true,
checkbox : true,
file : true,
password : true,
image : true
}){
Expr.pseudos[i] = createInputPseudo(i);
};
for(i in {
submit : true,
reset : true
}){
Expr.pseudos[i] = createButtonPseudo(i);
};
// Easy API for creating new setFilters
function setFilters(){
};
setFilters.prototype = Expr.filters = Expr.pseudos;
Expr.setFilters = new setFilters();
function tokenize(selector, parseOnly){
var matched,match,tokens,type,soFar,groups,preFilters,cached = tokenCache[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){
// Don't consume trailing commas as valid
soFar = soFar.slice(match[0].length) || soFar;
};
groups.push((tokens = []));
};
matched = false;
// Combinators
if((match = rcombinators.exec(soFar))){
matched = match.shift();
tokens.push({
value : matched,
// Cast descendant combinators to space
type : match[0].replace(rtrim, " ")
});
soFar = soFar.slice(matched.length);
};
// Filters
for(type in Expr.filter){
if((match = matchExpr[type].exec(soFar)) && (!preFilters[type] || (match = preFilters[type](match)))){
matched = match.shift();
tokens.push({
value : matched,
type : type,
matches : match
});
soFar = soFar.slice(matched.length);
};
};
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 toSelector(tokens){
var i = 0,len = tokens.length,selector = "";
for(;i < len;i++){
selector += tokens[i].value;
};
return selector;
};
function addCombinator(matcher, combinator, base){
var dir = combinator.dir,checkNonElements = base && dir === "parentNode",doneName = done++;
return combinator.first ? // Check against closest ancestor/preceding element
function(elem, context, xml){
while((elem = elem[dir])){
if(elem.nodeType === 1 || checkNonElements){
return matcher(elem, context, xml);
};
};
} : // Check against all ancestor/preceding elements
function(elem, context, xml){
var oldCache,outerCache,newCache = [dirruns, doneName];
// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
if(xml){
while((elem = elem[dir])){
if(elem.nodeType === 1 || checkNonElements){
if(matcher(elem, context, xml)){
return true;
};
};
};
} else {
while((elem = elem[dir])){
if(elem.nodeType === 1 || checkNonElements){
outerCache = elem[expando] || (elem[expando] = {
});
if((oldCache = outerCache[dir]) && oldCache[0] === dirruns && oldCache[1] === doneName){
// Assign to newCache so results back-propagate to previous elements
return (newCache[2] = oldCache[2]);
} else {
// Reuse newcache so results back-propagate to previous elements
outerCache[dir] = newCache;
// A match means we're done; a fail means we have to keep checking
if((newCache[2] = matcher(elem, context, xml))){
return true;
};
};
};
};
};
};
};
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 multipleContexts(selector, contexts, results){
var i = 0,len = contexts.length;
for(;i < len;i++){
Sizzle(selector, contexts[i], results);
};
return results;
};
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){
var temp,i,elem,preMap = [],postMap = [],preexisting = results.length,// Get initial elements from seed or context
elems = seed || multipleContexts(selector || "*", context.nodeType ? [context] : context, []),// 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){
temp = condense(matcherOut, postMap);
postFilter(temp, [], context, xml);
// Un-match failing elements by moving them back to matcherIn
i = temp.length;
while(i--){
if((elem = temp[i])){
matcherOut[postMap[i]] = !(matcherIn[postMap[i]] = elem);
};
};
};
if(seed){
if(postFinder || preFilter){
if(postFinder){
// Get the final matcherOut by condensing this intermediate into postFinder contexts
temp = [];
i = matcherOut.length;
while(i--){
if((elem = matcherOut[i])){
// Restore matcherIn since elem is not yet a final match
temp.push((matcherIn[i] = elem));
};
};
postFinder(null, (matcherOut = []), temp, xml);
};
// Move matched elements from seed to results to keep them synchronized
i = matcherOut.length;
while(i--){
if((elem = matcherOut[i]) && (temp = postFinder ? indexOf.call(seed, elem) : preMap[i]) > -1){
seed[temp] = !(results[temp] = 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 {
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 && toSelector(// If the preceding token was a descendant combinator, insert an implicit any-element `*`
tokens.slice(0, i - 1).concat({
value : tokens[i - 2].type === " " ? "*" : ""
})).replace(rtrim, "$1"), matcher, i < j && matcherFromTokens(tokens.slice(i, j)), j < len && matcherFromTokens((tokens = tokens.slice(j))), j < len && toSelector(tokens));
};
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, outermost){
var elem,j,matcher,matchedCount = 0,i = "0",unmatched = seed && [],setMatched = [],contextBackup = outermostContext,// We must always have either seed elements or outermost context
elems = seed || byElement && Expr.find["TAG"]("*", outermost),// Use integer dirruns iff this is the outermost matcher
dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),len = elems.length;
if(outermost){
outermostContext = context !== document && context;
};
// Add elements passing elementMatchers directly to results
// Keep `i` a string if there are no elements so `matchedCount` will be "00" below
// Support: IE<9, Safari
// Tolerate NodeList properties (IE: "length"; Safari: bind
method:
* * // sample code, assumes the used variables are already defined * * // the listener method demonstrates how to pass dynamic values * // to a method using 'bind' * var changeValueListener = function(value, event) { * // value is passed by the 'bind' method: its value is 'myArray[i]' * // second argument is passed by the 'on' method: its value is a event object * // 'this' is pointing to 'myComponent', since the first argument of 'bind' defines the context of the function call * }; * var myArray = [ 0, 2, 4, 6 ]; * for (var i=0, j=myArray.length; i<j; i++) { * myComponent.on("changeValue", changeValueListener.bind(myComponent, myArray[i])); * } ** * @param that {var?} Context for the bound function * @return {Function} The bound function */ bind : function(that){ var slice = Array.prototype.slice; // .length is 1 // 1. Let Target be the this value. var target = this; // 2. If IsCallable(Target) is false, throw a TypeError exception. if(typeof target != "function"){ throw new TypeError("Function.prototype.bind called on incompatible " + target); }; // 3. Let A be a new (possibly empty) internal list of all of the // argument values provided after thisArg (arg1, arg2 etc), in order. // XXX slicedArgs will stand in for "A" if used var args = slice.call(arguments, 1); // for normal call // 4. Let F be a new native ECMAScript object. // 11. Set the [[Prototype]] internal property of F to the standard // built-in Function prototype object as specified in 15.3.3.1. // 12. Set the [[Call]] internal property of F as described in // 15.3.4.5.1. // 13. Set the [[Construct]] internal property of F as described in // 15.3.4.5.2. // 14. Set the [[HasInstance]] internal property of F as described in // 15.3.4.5.3. var bound = function(){ if(this instanceof bound){ // 15.3.4.5.2 [[Construct]] // When the [[Construct]] internal method of a function object, // F that was created using the bind function is called with a // list of arguments ExtraArgs, the following steps are taken: // 1. Let target be the value of F's [[TargetFunction]] // internal property. // 2. If target has no [[Construct]] internal method, a // TypeError exception is thrown. // 3. Let boundArgs be the value of F's [[BoundArgs]] internal // property. // 4. Let args be a new list containing the same values as the // list boundArgs in the same order followed by the same // values as the list ExtraArgs in the same order. // 5. Return the result of calling the [[Construct]] internal // method of target providing args as the arguments. var F = function(){ }; F.prototype = target.prototype; var self = new F; var result = target.apply(self, args.concat(slice.call(arguments))); if(Object(result) === result){ return result; }; return self; } else { // 15.3.4.5.1 [[Call]] // When the [[Call]] internal method of a function object, F, // which was created using the bind function is called with a // this value and a list of arguments ExtraArgs, the following // steps are taken: // 1. Let boundArgs be the value of F's [[BoundArgs]] internal // property. // 2. Let boundThis be the value of F's [[BoundThis]] internal // property. // 3. Let target be the value of F's [[TargetFunction]] internal // property. // 4. Let args be a new list containing the same values as the // list boundArgs in the same order followed by the same // values as the list ExtraArgs in the same order. // 5. Return the result of calling the [[Call]] internal method // of target providing boundThis as the this value and // providing args as the arguments. // equiv: target.call(this, ...boundArgs, ...args) return target.apply(that, args.concat(slice.call(arguments))); }; }; // XXX bound.length is never writable, so don't even try // // 15. If the [[Class]] internal property of Target is "Function", then // a. Let L be the length property of Target minus the length of A. // b. Set the length own property of F to either 0 or L, whichever is // larger. // 16. Else set the length own property of F to 0. // 17. Set the attributes of the length own property of F to the values // specified in 15.3.5.1. // (Not implemented but in the spec) // 18. Set the [[Extensible]] internal property of F to true. // (Not implemented but in the spec) // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). // 20. Call the [[DefineOwnProperty]] internal method of F with // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and // false. // 21. Call the [[DefineOwnProperty]] internal method of F with // arguments "arguments", PropertyDescriptor {[[Get]]: thrower, // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, // and false. // NOTE Function objects created using Function.prototype.bind do not // have a prototype property or the [[Code]], [[FormalParameters]], and // [[Scope]] internal properties. // XXX can't delete prototype in pure-js. // 22. Return F. return bound; } }, defer : function(statics){ if(!qx.core.Environment.get("ecmascript.function.bind")){ Function.prototype.bind = statics.bind; }; } }); /* ************************************************************************ 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 is used to define mixins (similar to mixins in Ruby). * * Mixins are collections of code and variables, which can be merged into * other classes. They are similar to classes but don't support inheritance. * * See the description of the {@link #define} method how a mixin is defined. * * @require(qx.lang.normalize.Array) */ qx.Bootstrap.define("qx.Mixin", { statics : { /* --------------------------------------------------------------------------- PUBLIC API --------------------------------------------------------------------------- */ /** * Define a new mixin. * * Example: *
* qx.Mixin.define("name", * { * include: [SuperMixins], * * properties: { * tabIndex: {type: "number", init: -1} * }, * * members: * { * prop1: "foo", * meth1: function() {}, * meth2: function() {} * } * }); ** * @param name {String} name of the mixin * @param config {Map ? null} Mixin definition structure. The configuration map has the following keys: *
Name | Type | Description |
---|---|---|
construct | Function | An optional mixin constructor. It is called on instantiation each * class including this mixin. The constructor takes no parameters. |
destruct | Function | An optional mixin destructor. |
include | Mixin[] | Array of mixins, which will be merged into the mixin. |
statics | Map | * Map of statics of the mixin. The statics will not get copied into the target class. They remain * accessible from the mixin. This is the same behaviour as statics in interfaces ({@link qx.Interface#define}). * |
members | Map | Map of members of the mixin. |
properties | Map | Map of property definitions. For a description of the format of a property definition see * {@link qx.core.Property}. |
events | Map | * Map of events the mixin fires. The keys are the names of the events and the values are * corresponding event type classes. * |
true
if the mixin passed the compatibilty check
*/
checkCompatibility : function(mixins){
var list = this.flatten(mixins);
var len = list.length;
if(len < 2){
return true;
};
var properties = {
};
var members = {
};
var events = {
};
var mixin;
for(var i = 0;i < len;i++){
mixin = list[i];
for(var key in mixin.events){
if(events[key]){
throw new Error('Conflict between mixin "' + mixin.name + '" and "' + events[key] + '" in member "' + key + '"!');
};
events[key] = mixin.name;
};
for(var key in mixin.properties){
if(properties[key]){
throw new Error('Conflict between mixin "' + mixin.name + '" and "' + properties[key] + '" in property "' + key + '"!');
};
properties[key] = mixin.name;
};
for(var key in mixin.members){
if(members[key]){
throw new Error('Conflict between mixin "' + mixin.name + '" and "' + members[key] + '" in member "' + key + '"!');
};
members[key] = mixin.name;
};
};
return true;
},
/**
* Checks if a class is compatible to the given mixin (no conflicts)
*
* @param mixin {Mixin} mixin to check
* @param clazz {Class} class to check
* @throws {Error} when the given mixin is incompatible to the class
* @return {Boolean} true if the mixin is compatible to the given class
*/
isCompatible : function(mixin, clazz){
var list = qx.util.OOUtil.getMixins(clazz);
list.push(mixin);
return qx.Mixin.checkCompatibility(list);
},
/**
* Returns a mixin by name
*
* @param name {String} class name to resolve
* @return {Class} the class
*/
getByName : function(name){
return this.$$registry[name];
},
/**
* Determine if mixin exists
*
* @param name {String} mixin name to check
* @return {Boolean} true if mixin exists
*/
isDefined : function(name){
return this.getByName(name) !== undefined;
},
/**
* Determine the number of mixins which are defined
*
* @return {Number} the number of mixins
*/
getTotalNumber : function(){
return qx.Bootstrap.objectGetLength(this.$$registry);
},
/**
* Generates a list of all mixins given plus all the
* mixins these includes plus... (deep)
*
* @param mixins {Mixin[] ? []} List of mixins
* @return {Array} List of all mixins
*/
flatten : function(mixins){
if(!mixins){
return [];
};
// we need to create a copy and not to modify the existing array
var list = mixins.concat();
for(var i = 0,l = mixins.length;i < l;i++){
if(mixins[i].$$includes){
list.push.apply(list, this.flatten(mixins[i].$$includes));
};
};
return list;
},
/*
---------------------------------------------------------------------------
PRIVATE/INTERNAL API
---------------------------------------------------------------------------
*/
/**
* This method will be attached to all mixins to return
* a nice identifier for them.
*
* @internal
* @return {String} The mixin identifier
*/
genericToString : function(){
return "[Mixin " + this.name + "]";
},
/** Registers all defined mixins */
$$registry : {
},
/** @type {Map} allowed keys in mixin definition */
__allowedKeys : null,
/**
* Validates incoming configuration and checks keys and values
*
* @signature function(name, config)
* @param name {String} The name of the class
* @param config {Map} Configuration map
*/
__validateConfig : function(name, config){
}
}
});
/* ************************************************************************
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)
* Andreas Ecker (ecker)
************************************************************************ */
/**
* Basis for Aspect Oriented features in qooxdoo.
*
* This class makes it possible to attach functions (aspects) before or
* after each function call of any function defined in {@link qx.Class#define}.
*
* Classes, which define own aspects must add an explicit require to this class
* in the header comment using the following code:
*
* * #require(qx.core.Aspect) * #ignore(auto-require) ** * One example for a qooxdoo aspect is profiling ({@link qx.dev.Profile}). */ qx.Bootstrap.define("qx.core.Aspect", { statics : { /** @type {Array} Registry for all known aspect wishes */ __registry : [], /** * This function is used by {@link qx.Class#define} to wrap all statics, members and * constructors. * * @param fullName {String} Full name of the function including the class name. * @param fcn {Function} function to wrap. * @param type {String} Type of the wrapped function. One of "member", "static", * "constructor", "destructor" or "property". * * @return {Function} wrapped function */ wrap : function(fullName, fcn, type){ var before = []; var after = []; var reg = this.__registry; var entry; for(var i = 0;i < reg.length;i++){ entry = reg[i]; if((entry.type == null || type == entry.type || entry.type == "*") && (entry.name == null || fullName.match(entry.name))){ entry.pos == -1 ? before.push(entry.fcn) : after.push(entry.fcn); }; }; if(before.length === 0 && after.length === 0){ return fcn; }; var wrapper = function(){ for(var i = 0;i < before.length;i++){ before[i].call(this, fullName, fcn, type, arguments); }; var ret = fcn.apply(this, arguments); for(var i = 0;i < after.length;i++){ after[i].call(this, fullName, fcn, type, arguments, ret); }; return ret; }; if(type !== "static"){ wrapper.self = fcn.self; wrapper.base = fcn.base; }; fcn.wrapper = wrapper; wrapper.original = fcn; return wrapper; }, /** * Register a function to be called just before or after each time * one of the selected functions is called. * * @param fcn {Function} Function to be called just before or after any of the * selected functions is called. If position is "before" the functions * supports the same signature as {@link qx.dev.Profile#profileBefore}. If * position is "after" it supports the same signature as * {@link qx.dev.Profile#profileAfter}. * @param position {String?"after"} One of "before" or "after". Whether the function * should be called before or after the wrapped function. * @param type {String?null} Type of the wrapped function. One of "member", * "static", "constructor", "destructor", "property" or "*".
null
* is handled identical to "*".
* @param name {String|RegExp?null} Each function, with a full name matching
* this pattern (using fullName.match(name)
) will be
* wrapped.
*/
addAdvice : function(fcn, position, type, name){
this.__registry.push({
fcn : fcn,
pos : position === "before" ? -1 : 1,
type : type,
name : name
});
}
}
});
/* ************************************************************************
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 is responsible for the normalization of the native 'String' object.
* It checks if these methods are available and, if not, appends them to
* ensure compatibility in all browsers.
* For usage samples, check out the attached links.
*
* @group (Polyfill)
*/
qx.Bootstrap.define("qx.lang.normalize.String", {
statics : {
/**
* Removes whitespace from both ends of the string.
*
* MDN documentation |
* Annotated ES5 Spec
*
* @return {String} The trimmed string
*/
trim : function(){
return this.replace(/^\s+|\s+$/g, '');
}
},
defer : function(statics){
// trim
if(!qx.core.Environment.get("ecmascript.string.trim")){
String.prototype.trim = statics.trim;
};
}
});
/* ************************************************************************
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 is responsible for the normalization of the native Object.
* It checks if these methods are available and, if not, appends them to
* ensure compatibility in all browsers.
* For usage samples, check out the attached links.
*
* @group (Polyfill)
*/
qx.Bootstrap.define("qx.lang.normalize.Object", {
statics : {
/**
* Get the keys of a map as array as returned by a "for ... in" statement.
*
* MDN documentation |
* Annotated ES5 Spec
*
* @signature function(map)
* @param map {Object} the map
* @return {Array} array of the keys of the map
*/
keys : qx.Bootstrap.keys
},
defer : function(statics){
// keys
if(!qx.core.Environment.get("ecmascript.object.keys")){
Object.keys = statics.keys;
};
}
});
/* ************************************************************************
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 is used to define interfaces (similar to Java interfaces).
*
* See the description of the {@link #define} method how an interface is
* defined.
*
* @require(qx.lang.normalize.Array)
*/
qx.Bootstrap.define("qx.Interface", {
statics : {
/*
---------------------------------------------------------------------------
PUBLIC API
---------------------------------------------------------------------------
*/
/**
* Define a new interface. Interface definitions look much like class definitions.
*
* The main difference is that the bodies of functions defined in members
* and statics
are called before the original function with the
* same arguments. This can be used to check the passed arguments. If the
* checks fail, an exception should be thrown. It is convenient to use the
* method defined in {@link qx.core.MAssert} to check the arguments.
*
* In the build
version the checks are omitted.
*
* For properties only the names are required so the value of the properties
* can be empty maps.
*
* Example:
* * qx.Interface.define("name", * { * extend: [SuperInterfaces], * * statics: * { * PI : 3.14 * }, * * properties: {"color": {}, "name": {} }, * * members: * { * meth1: function() {}, * meth2: function(a, b) { this.assertArgumentsCount(arguments, 2, 2); }, * meth3: function(c) { this.assertInterface(c.constructor, qx.some.Interface); } * }, * * events : * { * keydown : "qx.event.type.KeySequence" * } * }); ** * @param name {String} name of the interface * @param config {Map ? null} Interface definition structure. The configuration map has the following keys: *
Name | Type | Description |
---|---|---|
extend | Interface | Interface[] | Single interface or array of interfaces this interface inherits from. |
members | Map | Map of members of the interface. |
statics | Map | * Map of statics of the interface. The statics will not get copied into the target class. * This is the same behaviour as statics in mixins ({@link qx.Mixin#define}). * |
properties | Map | Map of properties and their definitions. |
events | Map | Map of event names and the corresponding event class name. |
false
, the method
* will return a boolean instead of throwing an exception
* @return {Boolean} true
if all members are supported
*/
__checkMembers : function(object, clazz, iface, wrap, shouldThrow){
// Validate members
var members = iface.$$members;
if(members){
for(var key in members){
if(qx.Bootstrap.isFunction(members[key])){
var isPropertyMethod = this.__isPropertyMethod(clazz, key);
var hasMemberFunction = isPropertyMethod || qx.Bootstrap.isFunction(object[key]);
if(!hasMemberFunction){
if(shouldThrow){
throw new Error('Implementation of method "' + key + '" is missing in class "' + clazz.classname + '" required by interface "' + iface.name + '"');
} else {
return false;
};
};
// Only wrap members if the interface was not been applied yet. This
// can easily be checked by the recursive hasInterface method.
var shouldWrapFunction = wrap === true && !isPropertyMethod && !qx.util.OOUtil.hasInterface(clazz, iface);
if(shouldWrapFunction){
object[key] = this.__wrapInterfaceMember(iface, object[key], key, members[key]);
};
} else {
// Other members are not checked more detailed because of
// JavaScript's loose type handling
if(typeof object[key] === undefined){
if(typeof object[key] !== "function"){
if(shouldThrow){
throw new Error('Implementation of member "' + key + '" is missing in class "' + clazz.classname + '" required by interface "' + iface.name + '"');
} else {
return false;
};
};
};
};
};
};
if(!shouldThrow){
return true;
};
},
/**
* Internal helper to detect if the method will be generated by the
* property system.
*
* @param clazz {Class} The current class.
* @param methodName {String} The name of the method.
*
* @return {Boolean} true, if the method will be generated by the property
* system.
*/
__isPropertyMethod : function(clazz, methodName){
var match = methodName.match(/^(is|toggle|get|set|reset)(.*)$/);
if(!match){
return false;
};
var propertyName = qx.Bootstrap.firstLow(match[2]);
var isPropertyMethod = qx.util.OOUtil.getPropertyDefinition(clazz, propertyName);
if(!isPropertyMethod){
return false;
};
var isBoolean = match[0] == "is" || match[0] == "toggle";
if(isBoolean){
return qx.util.OOUtil.getPropertyDefinition(clazz, propertyName).check == "Boolean";
};
return true;
},
/**
* Assert properties
*
* @param clazz {Class} class to check interface for
* @param iface {Interface} the interface to verify
* @param shouldThrow {Boolean} if false
, the method
* will return a boolean instead of throwing an exception
* @return {Boolean} true
if all properties are supported
*/
__checkProperties : function(clazz, iface, shouldThrow){
if(iface.$$properties){
for(var key in iface.$$properties){
if(!qx.util.OOUtil.getPropertyDefinition(clazz, key)){
if(shouldThrow){
throw new Error('The property "' + key + '" is not supported by Class "' + clazz.classname + '"!');
} else {
return false;
};
};
};
};
if(!shouldThrow){
return true;
};
},
/**
* Assert events
*
* @param clazz {Class} class to check interface for
* @param iface {Interface} the interface to verify
* @param shouldThrow {Boolean} if false
, the method
* will return a boolean instead of throwing an exception
* @return {Boolean} true
if all events are supported
*/
__checkEvents : function(clazz, iface, shouldThrow){
if(iface.$$events){
for(var key in iface.$$events){
if(!qx.util.OOUtil.supportsEvent(clazz, key)){
if(shouldThrow){
throw new Error('The event "' + key + '" is not supported by Class "' + clazz.classname + '"!');
} else {
return false;
};
};
};
};
if(!shouldThrow){
return true;
};
},
/**
* Asserts that the given object implements all the methods defined in the
* interface. This method throws an exception if the object does not
* implement the interface.
*
* @param object {qx.core.Object} Object to check interface for
* @param iface {Interface} The interface to verify
*/
assertObject : function(object, iface){
var clazz = object.constructor;
this.__checkMembers(object, clazz, iface, false, true);
this.__checkProperties(clazz, iface, true);
this.__checkEvents(clazz, iface, true);
// Validate extends, recursive
var extend = iface.$$extends;
if(extend){
for(var i = 0,l = extend.length;i < l;i++){
this.assertObject(object, extend[i]);
};
};
},
/**
* Checks if an interface is implemented by a class
*
* @param clazz {Class} class to check interface for
* @param iface {Interface} the interface to verify
* @param wrap {Boolean ? false} wrap functions required by interface to
* check parameters etc.
*/
assert : function(clazz, iface, wrap){
this.__checkMembers(clazz.prototype, clazz, iface, wrap, true);
this.__checkProperties(clazz, iface, true);
this.__checkEvents(clazz, iface, true);
// Validate extends, recursive
var extend = iface.$$extends;
if(extend){
for(var i = 0,l = extend.length;i < l;i++){
this.assert(clazz, extend[i], wrap);
};
};
},
/**
* Asserts that the given object implements all the methods defined in the
* interface.
*
* @param object {qx.core.Object} Object to check interface for
* @param iface {Interface} The interface to verify
* @return {Boolean} true
if the objects implements the interface
*/
objectImplements : function(object, iface){
var clazz = object.constructor;
if(!this.__checkMembers(object, clazz, iface) || !this.__checkProperties(clazz, iface) || !this.__checkEvents(clazz, iface)){
return false;
};
// Validate extends, recursive
var extend = iface.$$extends;
if(extend){
for(var i = 0,l = extend.length;i < l;i++){
if(!this.objectImplements(object, extend[i])){
return false;
};
};
};
return true;
},
/**
* Tests whether an interface is implemented by a class, without throwing an
* exception when it doesn't.
*
* @param clazz {Class} class to check interface for
* @param iface {Interface} the interface to verify
* @return {Boolean} true
if interface is implemented
*/
classImplements : function(clazz, iface){
if(!this.__checkMembers(clazz.prototype, clazz, iface) || !this.__checkProperties(clazz, iface) || !this.__checkEvents(clazz, iface)){
return false;
};
// Validate extends, recursive
var extend = iface.$$extends;
if(extend){
for(var i = 0,l = extend.length;i < l;i++){
if(!this.has(clazz, extend[i])){
return false;
};
};
};
return true;
},
/*
---------------------------------------------------------------------------
PRIVATE/INTERNAL API
---------------------------------------------------------------------------
*/
/**
* This method will be attached to all interface to return
* a nice identifier for them.
*
* @internal
* @return {String} The interface identifier
*/
genericToString : function(){
return "[Interface " + this.name + "]";
},
/** Registry of all defined interfaces */
$$registry : {
},
/**
* Wrap a method with a precondition check.
*
* @signature function(iface, origFunction, functionName, preCondition)
* @param iface {String} Name of the interface, where the pre condition
* was defined. (Used in error messages).
* @param origFunction {Function} function to wrap.
* @param functionName {String} name of the function. (Used in error messages).
* @param preCondition {Function}. This function gets called with the arguments of the
* original function. If this function return true the original function is called.
* Otherwise an exception is thrown.
* @return {Function} wrapped function
*/
__wrapInterfaceMember : function(iface, origFunction, functionName, preCondition){
},
/** @type {Map} allowed keys in interface definition */
__allowedKeys : null,
/**
* Validates incoming configuration and checks keys and values
*
* @signature function(name, config)
* @param name {String} The name of the class
* @param config {Map} Configuration map
*/
__validateConfig : function(name, config){
}
}
});
/* ************************************************************************
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 is responsible for the normalization of the native 'Error' object.
* It contains a simple bugfix for toString which might not print out the proper
* error message.
*
* @group (Polyfill)
*/
qx.Bootstrap.define("qx.lang.normalize.Error", {
statics : {
/**
* Returns a string representation of the Error object.
*
* MDN documentation |
* Annotated ES5 Spec
*
* @return {String} Error message
*/
toString : function(){
var name = this.name || "Error";
var message = this.message || "";
if(name === "" && message === ""){
return "Error";
};
if(name === ""){
return message;
};
if(message === ""){
return name;
};
return name + ": " + message;
}
},
defer : function(statics){
// toString
if(!qx.core.Environment.get("ecmascript.error.toString")){
Error.prototype.toString = statics.toString;
};
}
});
/* ************************************************************************
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)
************************************************************************ */
/**
* Internal class for handling of dynamic properties. Should only be used
* through the methods provided by {@link qx.Class}.
*
* For a complete documentation of properties take a look at
* http://manual.qooxdoo.org/${qxversion}/pages/core.html#properties.
*
*
* *Normal properties*
*
* The properties
key in the class definition map of {@link qx.Class#define}
* is used to generate the properties.
*
* Valid keys of a property definition are:
*
* Name | Type | Description |
---|---|---|
check | Array, String, Function |
* The check is used to check the type the incoming value of a property. This will only
* be executed in the source version. The build version will not contain the checks.
* The check can be:
*
|
init | var |
* Sets the default/initial value of the property. If no property value is set or the property
* gets reset, the getter will return the init value.
* |
apply | String |
* On change of the property value the method of the specified name will be called. The signature of
* the method is function(newValue, oldValue, propertyName) . It is conventional to name
* the callback _apply + PropertyName, with the property name camel-cased (e.g.
* "_applyFooBar" for a property fooBar).
* |
event | String | * On change of the property value an event with the given name will be dispatched. The event type is * {@link qx.event.type.Data}. * |
themeable | Boolean | * Whether this property can be set using themes. * |
inheritable | Boolean | * Whether the property value should be inheritable. If the property does not have an user defined or an * init value, the property will try to get the value from the parent of the current object. * |
nullable | Boolean |
* Whether null is an allowed value of the property. This is complementary to the check
* defined using the check key.
* |
refine | Boolean |
* Whether the property definition is a refinement of a property in one of the super classes of the class.
* Only the init value can be changed using refine.
* |
transform | String |
* On setting of the property value the method of the specified name will
* be called. The signature of the method is function(value) .
* The parameter value is the value passed to the setter.
* The function must return the modified or unmodified value.
* Transformation occurs before the check function, so both may be
* specified if desired. Alternatively, the transform function may throw
* an error if the value passed to it is invalid.
* |
validate | Function, String |
* On setting of the property value the method of the specified name will
* be called. The signature of the method is function(value) .
* The parameter value is the value passed to the setter.
* If the validation fails, an qx.core.ValidationError should
* be thrown by the validation function. Otherwise, just do nothing in the
* function.* If a string is given, the string should hold a reference to a member * method. * "methodname" for example
* "__validateProperty" * There are some default validators in the {@link qx.util.Validate} class. * See this documentation for usage examples. * |
dereference | Boolean | * By default, the references to the values (current, init, ...) of the * property will be stored as references on the object. When disposing * this object, the references will not be deleted. Setting the * dereference key to true tells the property system to delete all * connections made by this property on dispose. This can be necessary for * disconnecting DOM objects to allow the garbage collector to work * properly. * |
deferredInit | Boolean | * Allow for a deferred initialization for reference types. Defaults to false. * |
Name | Type | Description |
---|---|---|
group | String[] | * A list of property names which should be set using the property group. * |
mode | String |
* If mode is set to "shorthand" , the properties can be set using a CSS like shorthand mode.
* |
themeable | Boolean | * Whether this property can be set using themes. * |
null
.
*
* @param code {String[]} String array to append the code to
* @param config {Object} The property configuration map
* @param name {String} name of the property
* @param variant {String} Method variant.
*/
__emitNormalizeUndefinedValues : function(code, config, name, variant){
// Properties which are not inheritable have no possibility to get
// undefined at this position. (Hint: set(), setRuntime() and setThemed() only allow non undefined values)
if(variant !== "set" && variant !== "setRuntime" && variant !== "setThemed"){
code.push('if(computed===undefined)computed=null;');
};
// Compare old/new computed value
code.push('if(old===computed)return value;');
// Normalize old value
if(config.init !== undefined && variant !== "init"){
code.push('if(old===undefined)old=this.', this.$$store.init[name], ";");
} else {
code.push('if(old===undefined)old=null;');
};
},
/**
* Emit code to call the apply method and fire the change event
*
* @param code {String[]} String array to append the code to
* @param config {Object} The property configuration map
* @param name {String} name of the property
* @param variant {String} variant of the method e.g. setThemed
*/
__emitCallCallback : function(code, config, name, variant){
// Execute user configured setter
if(config.apply){
code.push('this.', config.apply, '(computed, old, "', name, '", "', variant, '");');
};
// Fire event
if(config.event){
code.push("var reg=qx.event.Registration;", "if(reg.hasListener(this, '", config.event, "')){", "reg.fireEvent(this, '", config.event, "', qx.event.type.Data, [computed, old]", ")}");
};
},
/**
* Emit code to update the inherited values of child objects
*
* @param code {String[]} String array to append the code to
* @param name {String} name of the property
*/
__emitRefreshChildrenValue : function(code, name){
code.push('var a=this._getChildren();if(a)for(var i=0,l=a.length;iclassname
"qx.ui.core.Widget"
).basename
"qx.ui.core"
).constructor
superclass
this.self(arguments)
({@link qx.core.Object#self}):
* * statics : { FOO : "bar" }, * members: { * baz: function(x) { * this.self(arguments).FOO; * ... * } * } ** * Each overriding method may call the overridden method by using *
this.base(arguments [, ...])
({@link qx.core.Object#base}). This is also true for calling
* the constructor of the superclass.
* * members: { * foo: function(x) { * this.base(arguments, x); * ... * } * } ** * By using
qx.Class
within an app, the native JS data types are
* conveniently polyfilled according to {@link qx.lang.normalize}.
*
* @require(qx.Interface)
* @require(qx.Mixin)
* @require(qx.lang.normalize.Array)
* @require(qx.lang.normalize.Date)
* @require(qx.lang.normalize.Error)
* @require(qx.lang.normalize.Function)
* @require(qx.lang.normalize.String)
* @require(qx.lang.normalize.Object)
*/
qx.Bootstrap.define("qx.Class", {
statics : {
/**
* A static reference to the property implementation in the case it
* should be included.
*/
__Property : qx.core.Environment.get("module.property") ? qx.core.Property : null,
/*
---------------------------------------------------------------------------
PUBLIC METHODS
---------------------------------------------------------------------------
*/
/**
* Define a new class using the qooxdoo class system. This sets up the
* namespace for the class and generates the class from the definition map.
*
* Example:
* * qx.Class.define("name", * { * extend : Object, // superclass * implement : [Interfaces], * include : [Mixins], * * statics: * { * CONSTANT : 3.141, * * publicMethod: function() {}, * _protectedMethod: function() {}, * __privateMethod: function() {} * }, * * properties: * { * "tabIndex": { check: "Number", init : -1 } * }, * * members: * { * publicField: "foo", * publicMethod: function() {}, * * _protectedField: "bar", * _protectedMethod: function() {}, * * __privateField: "baz", * __privateMethod: function() {} * } * }); ** * @param name {String?null} Name of the class. If
null
, the class
* will not be added to any namespace which could be handy for testing.
* @param config {Map ? null} Class definition structure. The configuration map has the following keys:
* Name | Type | Description |
---|---|---|
type | String | * Type of the class. Valid types are "abstract", "static" and "singleton". * If unset it defaults to a regular non-static class. * |
extend | Class | The super class the current class inherits from. |
implement | Interface | Interface[] | Single interface or array of interfaces the class implements. |
include | Mixin | Mixin[] | Single mixin or array of mixins, which will be merged into the class. |
construct | Function | The constructor of the class. |
statics | Map | Map of static members of the class. |
properties | Map | Map of property definitions. For a description of the format of a property definition see * {@link qx.core.Property}. |
members | Map | Map of instance members of the class. |
environment | Map | Map of environment settings for this class. For a description of the format of a setting see * {@link qx.core.Environment}. |
events | Map | * Map of events the class fires. The keys are the names of the events and the values are the * corresponding event type class names. * |
defer | Function | Function that is called at the end of processing the class declaration. It allows access to the declared statics, members and properties. |
destruct | Function | The destructor of the class. |
extend
key.
*
* @param obj {Object} class to check
* @param iface {Interface} the interface to check for
* @return {Boolean} whether the class conforms to the interface.
*/
implementsInterface : function(obj, iface){
var clazz = obj.constructor;
if(this.hasInterface(clazz, iface)){
return true;
};
if(qx.Interface.objectImplements(obj, iface)){
return true;
};
if(qx.Interface.classImplements(clazz, iface)){
return true;
};
return false;
},
/**
* Helper method to handle singletons
*
* @internal
* @return {Object} The singleton instance
*/
getInstance : function(){
if(!this.$$instance){
this.$$allowconstruct = true;
this.$$instance = new this();
delete this.$$allowconstruct;
};
return this.$$instance;
},
/*
---------------------------------------------------------------------------
PRIVATE/INTERNAL BASICS
---------------------------------------------------------------------------
*/
/**
* This method will be attached to all classes to return
* a nice identifier for them.
*
* @internal
* @return {String} The class identifier
*/
genericToString : function(){
return "[Class " + this.classname + "]";
},
/** Stores all defined classes */
$$registry : qx.Bootstrap.$$registry,
/** @type {Map} allowed keys in non-static class definition */
__allowedKeys : null,
/** @type {Map} allowed keys in static class definition */
__staticAllowedKeys : null,
/**
* Validates an incoming configuration and checks for proper keys and values
*
* @signature function(name, config)
* @param name {String} The name of the class
* @param config {Map} Configuration map
*/
__validateConfig : function(name, config){
},
/**
* Validates the interfaces required by abstract base classes
*
* @signature function(clazz)
* @param clazz {Class} The configured class.
*/
__validateAbstractInterfaces : function(clazz){
},
/**
* Creates a class by type. Supports modern inheritance etc.
*
* @param name {String} Full name of the class
* @param type {String} type of the class, i.e. "static", "abstract" or "singleton"
* @param extend {Class} Superclass to inherit from
* @param statics {Map} Static methods or fields
* @param construct {Function} Constructor of the class
* @param destruct {Function} Destructor of the class
* @param mixins {Mixin[]} array of mixins of the class
* @return {Class} The generated class
*/
__createClass : function(name, type, extend, statics, construct, destruct, mixins){
var clazz;
if(!extend && qx.core.Environment.get("qx.aspects") == false){
// Create empty/non-empty class
clazz = statics || {
};
qx.Bootstrap.setDisplayNames(clazz, name);
} else {
clazz = {
};
if(extend){
// Create default constructor
if(!construct){
construct = this.__createDefaultConstructor();
};
if(this.__needsConstructorWrapper(extend, mixins)){
clazz = this.__wrapConstructor(construct, name, type);
} else {
clazz = construct;
};
// Add singleton getInstance()
if(type === "singleton"){
clazz.getInstance = this.getInstance;
};
qx.Bootstrap.setDisplayName(construct, name, "constructor");
};
// Copy statics
if(statics){
qx.Bootstrap.setDisplayNames(statics, name);
var key;
for(var i = 0,a = Object.keys(statics),l = a.length;i < l;i++){
key = a[i];
var staticValue = statics[key];
if(qx.core.Environment.get("qx.aspects")){
if(staticValue instanceof Function){
staticValue = qx.core.Aspect.wrap(name + "." + key, staticValue, "static");
};
clazz[key] = staticValue;
} else {
clazz[key] = staticValue;
};
};
};
};
// Create namespace
var basename = name ? qx.Bootstrap.createNamespace(name, clazz) : "";
// Store names in constructor/object
clazz.name = clazz.classname = name;
clazz.basename = basename;
// Store type info
clazz.$$type = "Class";
if(type){
clazz.$$classtype = type;
};
// Attach toString
if(!clazz.hasOwnProperty("toString")){
clazz.toString = this.genericToString;
};
if(extend){
qx.Bootstrap.extendClass(clazz, construct, extend, name, basename);
// Store destruct onto class
if(destruct){
if(qx.core.Environment.get("qx.aspects")){
destruct = qx.core.Aspect.wrap(name, destruct, "destructor");
};
clazz.$$destructor = destruct;
qx.Bootstrap.setDisplayName(destruct, name, "destruct");
};
};
// Store class reference in global class registry
this.$$registry[name] = clazz;
// Return final class object
return clazz;
},
/*
---------------------------------------------------------------------------
PRIVATE ADD HELPERS
---------------------------------------------------------------------------
*/
/**
* Attach events to the class
*
* @param clazz {Class} class to add the events to
* @param events {Map} map of event names the class fires.
* @param patch {Boolean ? false} Enable redefinition of event type?
*/
__addEvents : function(clazz, events, patch){
{
var key,key;
};
if(clazz.$$events){
for(var key in events){
clazz.$$events[key] = events[key];
};
} else {
clazz.$$events = events;
};
},
/**
* Attach properties to classes
*
* @param clazz {Class} class to add the properties to
* @param properties {Map} map of properties
* @param patch {Boolean ? false} Overwrite property with the limitations of a property
which means you are able to refine but not to replace (esp. for new properties)
*/
__addProperties : function(clazz, properties, patch){
// check for the property module
if(!qx.core.Environment.get("module.property")){
throw new Error("Property module disabled.");
};
var config;
if(patch === undefined){
patch = false;
};
var proto = clazz.prototype;
for(var name in properties){
config = properties[name];
{
};
// Store name into configuration
config.name = name;
// Add config to local registry
if(!config.refine){
if(clazz.$$properties === undefined){
clazz.$$properties = {
};
};
clazz.$$properties[name] = config;
};
// Store init value to prototype. This makes it possible to
// overwrite this value in derived classes.
if(config.init !== undefined){
clazz.prototype["$$init_" + name] = config.init;
};
// register event name
if(config.event !== undefined){
// break if no events layer loaded
if(!qx.core.Environment.get("module.events")){
throw new Error("Events module not enabled.");
};
var event = {
};
event[config.event] = "qx.event.type.Data";
this.__addEvents(clazz, event, patch);
};
// Remember inheritable properties
if(config.inheritable){
this.__Property.$$inheritable[name] = true;
if(!proto.$$refreshInheritables){
this.__Property.attachRefreshInheritables(clazz);
};
};
if(!config.refine){
this.__Property.attachMethods(clazz, name, config);
};
};
},
/**
* Validates the given property
*
* @signature function(clazz, name, config, patch)
* @param clazz {Class} class to add property to
* @param name {String} name of the property
* @param config {Map} configuration map
* @param patch {Boolean ? false} enable refine/patch?
*/
__validateProperty : null,
/**
* Attach members to a class
*
* @param clazz {Class} clazz to add members to
* @param members {Map} The map of members to attach
* @param patch {Boolean ? false} Enable patching of
* @param base {Boolean ? true} Attach base flag to mark function as members
* of this class
* @param wrap {Boolean ? false} Whether the member method should be wrapped.
* this is needed to allow base calls in patched mixin members.
*/
__addMembers : function(clazz, members, patch, base, wrap){
var proto = clazz.prototype;
var key,member;
qx.Bootstrap.setDisplayNames(members, clazz.classname + ".prototype");
for(var i = 0,a = Object.keys(members),l = a.length;i < l;i++){
key = a[i];
member = members[key];
{
};
// Added helper stuff to functions
// Hint: Could not use typeof function because RegExp objects are functions, too
// Protect to apply base property and aspect support on special attributes e.g.
// classes which are function like as well.
if(base !== false && member instanceof Function && member.$$type == null){
if(wrap == true){
// wrap "patched" mixin member
member = this.__mixinMemberWrapper(member, proto[key]);
} else {
// Configure extend (named base here)
// Hint: proto[key] is not yet overwritten here
if(proto[key]){
member.base = proto[key];
};
member.self = clazz;
};
if(qx.core.Environment.get("qx.aspects")){
member = qx.core.Aspect.wrap(clazz.classname + "." + key, member, "member");
};
};
// Attach member
proto[key] = member;
};
},
/**
* Wraps a member function of a mixin, which is included using "patch". This
* allows "base" calls in the mixin member function.
*
* @param member {Function} The mixin method to wrap
* @param base {Function} The overwritten method
* @return {Function} the wrapped mixin member
*/
__mixinMemberWrapper : function(member, base){
if(base){
return function(){
var oldBase = member.base;
member.base = base;
var retval = member.apply(this, arguments);
member.base = oldBase;
return retval;
};
} else {
return member;
};
},
/**
* Add a single interface to a class
*
* @param clazz {Class} class to add interface to
* @param iface {Interface} the Interface to add
*/
__addInterface : function(clazz, iface){
{
};
// Store interface reference
var list = qx.Interface.flatten([iface]);
if(clazz.$$implements){
clazz.$$implements.push(iface);
clazz.$$flatImplements.push.apply(clazz.$$flatImplements, list);
} else {
clazz.$$implements = [iface];
clazz.$$flatImplements = list;
};
},
/**
* Wrap the constructor of an already existing clazz. This function will
* replace all references to the existing constructor with the new wrapped
* constructor.
*
* @param clazz {Class} The class to wrap
* @return {Class} The wrapped class
*/
__retrospectWrapConstruct : function(clazz){
var name = clazz.classname;
var wrapper = this.__wrapConstructor(clazz, name, clazz.$$classtype);
// copy all keys from the wrapped constructor to the wrapper
for(var i = 0,a = Object.keys(clazz),l = a.length;i < l;i++){
key = a[i];
wrapper[key] = clazz[key];
};
// fix prototype
wrapper.prototype = clazz.prototype;
// fix self references in members
var members = clazz.prototype;
for(var i = 0,a = Object.keys(members),l = a.length;i < l;i++){
key = a[i];
var method = members[key];
// check if method is available because null values can be stored as
// init values on classes e.g. [BUG #3709]
if(method && method.self == clazz){
method.self = wrapper;
};
};
// fix base and superclass references in all defined classes
for(var key in this.$$registry){
var construct = this.$$registry[key];
if(!construct){
continue;
};
if(construct.base == clazz){
construct.base = wrapper;
};
if(construct.superclass == clazz){
construct.superclass = wrapper;
};
if(construct.$$original){
if(construct.$$original.base == clazz){
construct.$$original.base = wrapper;
};
if(construct.$$original.superclass == clazz){
construct.$$original.superclass = wrapper;
};
};
};
qx.Bootstrap.createNamespace(name, wrapper);
this.$$registry[name] = wrapper;
return wrapper;
},
/**
* Include all features of the mixin into the given class, recursively.
*
* @param clazz {Class} The class onto which the mixin should be attached.
* @param mixin {Mixin} Include all features of this mixin
* @param patch {Boolean} Overwrite existing fields, functions and properties
*/
__addMixin : function(clazz, mixin, patch){
{
};
if(this.hasMixin(clazz, mixin)){
return;
};
var isConstructorWrapped = clazz.$$original;
if(mixin.$$constructor && !isConstructorWrapped){
clazz = this.__retrospectWrapConstruct(clazz);
};
// Attach content
var list = qx.Mixin.flatten([mixin]);
var entry;
for(var i = 0,l = list.length;i < l;i++){
entry = list[i];
// Attach events
if(entry.$$events){
this.__addEvents(clazz, entry.$$events, patch);
};
// Attach properties (Properties are already readonly themselves, no patch handling needed)
if(entry.$$properties){
this.__addProperties(clazz, entry.$$properties, patch);
};
// Attach members (Respect patch setting, but dont apply base variables)
if(entry.$$members){
this.__addMembers(clazz, entry.$$members, patch, patch, patch);
};
};
// Store mixin reference
if(clazz.$$includes){
clazz.$$includes.push(mixin);
clazz.$$flatIncludes.push.apply(clazz.$$flatIncludes, list);
} else {
clazz.$$includes = [mixin];
clazz.$$flatIncludes = list;
};
},
/*
---------------------------------------------------------------------------
PRIVATE FUNCTION HELPERS
---------------------------------------------------------------------------
*/
/**
* Returns the default constructor.
* This constructor just calls the constructor of the base class.
*
* @return {Function} The default constructor.
*/
__createDefaultConstructor : function(){
function defaultConstructor(){
defaultConstructor.base.apply(this, arguments);
};
return defaultConstructor;
},
/**
* Returns an empty function. This is needed to get an empty function with an empty closure.
*
* @return {Function} empty function
*/
__createEmptyFunction : function(){
return function(){
};
},
/**
* Checks if the constructor needs to be wrapped.
*
* @param base {Class} The base class.
* @param mixins {Mixin[]} All mixins which should be included.
* @return {Boolean} true, if the constructor needs to be wrapped.
*/
__needsConstructorWrapper : function(base, mixins){
{
};
// Check for base class mixin constructors
if(base && base.$$includes){
var baseMixins = base.$$flatIncludes;
for(var i = 0,l = baseMixins.length;i < l;i++){
if(baseMixins[i].$$constructor){
return true;
};
};
};
// check for direct mixin constructors
if(mixins){
var flatMixins = qx.Mixin.flatten(mixins);
for(var i = 0,l = flatMixins.length;i < l;i++){
if(flatMixins[i].$$constructor){
return true;
};
};
};
return false;
},
/**
* Generate a wrapper of the original class constructor in order to enable
* some of the advanced OO features (e.g. abstract class, singleton, mixins)
*
* @param construct {Function} the original constructor
* @param name {String} name of the class
* @param type {String} the user specified class type
* @return {Function} The wrapped constructor
*/
__wrapConstructor : function(construct, name, type){
var wrapper = function(){
var clazz = wrapper;
{
};
// Execute default constructor
var retval = clazz.$$original.apply(this, arguments);
// Initialize local mixins
if(clazz.$$includes){
var mixins = clazz.$$flatIncludes;
for(var i = 0,l = mixins.length;i < l;i++){
if(mixins[i].$$constructor){
mixins[i].$$constructor.apply(this, arguments);
};
};
};
{
};
// Return optional return value
return retval;
};
if(qx.core.Environment.get("qx.aspects")){
var aspectWrapper = qx.core.Aspect.wrap(name, wrapper, "constructor");
wrapper.$$original = construct;
wrapper.constructor = aspectWrapper;
wrapper = aspectWrapper;
};
// Store original constructor
wrapper.$$original = construct;
// Store wrapper into constructor (needed for base calls etc.)
construct.wrapper = wrapper;
// Return generated wrapper
return wrapper;
}
},
defer : function(){
// Binding of already loaded bootstrap classes
if(qx.core.Environment.get("qx.aspects")){
for(var classname in qx.Bootstrap.$$registry){
var statics = qx.Bootstrap.$$registry[classname];
for(var key in statics){
// only functions, no regexps
if(statics[key] instanceof Function){
statics[key] = qx.core.Aspect.wrap(classname + "." + key, statics[key], "static");
};
};
};
};
}
});
/* ************************************************************************
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:
* Martin Wittemann (martinwittemann)
************************************************************************ */
/**
* This mixin is forwarding the static methods of
* {@link qx.data.SingleValueBinding} to the instance including the mixin.
* The source object will be this
.
*/
qx.Mixin.define("qx.data.MBinding", {
members : {
/**
* The bind method delegates the call to the
* {@link qx.data.SingleValueBinding#bind} function. As source, the current
* object (this) will be used.
*
* @param sourcePropertyChain {String} The property chain which represents
* the source property.
* @param targetObject {qx.core.Object} The object which the source should
* be bind to.
* @param targetProperty {String} The property name of the target object.
* @param options {Map} A map containing the options. See
* {@link qx.data.SingleValueBinding#bind} for more
* information.
*
* @return {var} Returns the internal id for that binding. This can be used
* for referencing the binding e.g. for removing. This is not an atomic
* id so you can't you use it as a hash-map index.
*
* @throws {qx.core.AssertionError} If the event is no data event or
* there is no property definition for object and property (source and
* target).
*/
bind : function(sourcePropertyChain, targetObject, targetProperty, options){
return qx.data.SingleValueBinding.bind(this, sourcePropertyChain, targetObject, targetProperty, options);
},
/**
* Removes the binding with the given id from the current object. The
* id hast to be the id returned by any of the bind functions.
*
* @param id {var} The id of the binding.
* @throws {Error} If the binding could not be found.
*/
removeBinding : function(id){
qx.data.SingleValueBinding.removeBindingFromObject(this, id);
},
/**
* Removes all bindings from the object.
*
* @throws {qx.core.AssertionError} If the object is not in the internal
* registry of the bindings.
* @throws {Error} If one of the bindings listed internally can not be
* removed.
*/
removeAllBindings : function(){
qx.data.SingleValueBinding.removeAllBindingsForObject(this);
},
/**
* Returns an array which lists all bindings for the object.
*
* @return {Array} An array of binding informations. Every binding
* information is an array itself containing id, sourceObject, sourceEvent,
* targetObject and targetProperty in that order.
*/
getBindings : function(){
return qx.data.SingleValueBinding.getAllBindingsForObject(this);
}
}
});
/* ************************************************************************
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:
* Martin Wittemann (martinwittemann)
************************************************************************ */
/**
* The data binding package is still under development so there will be changes
* to the API. This Features is for testing purpose only.
*/
qx.Class.define("qx.data.SingleValueBinding", {
statics : {
/** internal reference for all bindings */
__bindings : {
},
/**
* The function is responsible for binding a source objects property to
* a target objects property. Both properties have to have the usual qooxdoo
* getter and setter. The source property also needs to fire change-events
* on every change of its value.
* Please keep in mind, that this binding is unidirectional. If you need
* a binding in both directions, you have to use two of this bindings.
*
* It's also possible to bind some kind of a hierarchy as a source. This
* means that you can separate the source properties with a dot and bind
* by that the object referenced to this property chain.
* Example with an object 'a' which has object 'b' stored in its 'child'
* property. Object b has a string property named abc:
*
* qx.data.SingleValueBinding.bind(a, "child.abc", textfield, "value");
*
* In that case, if the property abc of b changes, the textfield will
* automatically contain the new value. Also if the child of a changes, the
* new value (abc of the new child) will be in the textfield.
*
* There is also a possibility of binding an array. Therefor the array
* {@link qx.data.IListData} is needed because this array has change events
* which the native does not. Imagine a qooxdoo object a which has a
* children property containing an array holding more of its own kind.
* Every object has a name property as a string.
* * var svb = qx.data.SingleValueBinding; * // bind the first childs name of 'a' to a textfield * svb.bind(a, "children[0].name", textfield, "value"); * // bind the last childs name of 'a' to a textfield * svb.bind(a, "children[last].name", textfield2, "value"); * // also deeper bindinds are possible * svb.bind(a, "children[0].children[0].name", textfield3, "value"); ** * As you can see in this example, the abc property of a's b will be bound * to the textfield. If now the value of b changed or even the a will get a * new b, the binding still shows the right value. * * @param sourceObject {qx.core.Object} The source of the binding. * @param sourcePropertyChain {String} The property chain which represents * the source property. * @param targetObject {qx.core.Object} The object which the source should * be bind to. * @param targetPropertyChain {String} The property chain to the target * object. * @param options {Map?null} A map containing the options. *
function(data, model, source, target) {return data > 100;}
* onUpdate : function(source, target, data) {...}
* 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+$/, "");
},
/**
* 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