    /** * Provides searching of Components within Ext.ComponentManager (globally) or a specific * Ext.container.Container on the document with a similar syntax to a CSS selector. * Returns Array of matching Components, or empty Array. * * ## Basic Component lookup * * Components can be retrieved by using their {@link Ext.Component xtype}: * * - `component` * - `gridpanel` * * Matching by `xtype` matches inherited types, so in the following code, the previous field * *of any type which inherits from `TextField`* will be found: * *     prevField = myField.previousNode('textfield'); * * To match only the exact type, pass the "shallow" flag by adding `(true)` to xtype * (See Component's {@link Ext.Component#isXType isXType} method): * *     prevTextField = myField.previousNode('textfield(true)'); * * You can search Components by their `id` or `itemId` property, prefixed with a #: * *     #myContainer * * Component `xtype` and `id` or `itemId` can be used together to avoid possible * id collisions between Components of different types: * *     panel#myPanel * * When Component's `id` or `xtype` contains dots, you can escape them in your selector: * *     my\.panel#myPanel * * Keep in mind that JavaScript treats the backslash character in a special way, so you * need to escape it, too, in the actual code: * *     var myPanel = Ext.ComponentQuery.query('my\\.panel#myPanel'); * * ## Traversing Component tree * * Components can be found by their relation to other Components. There are several * relationship operators, mostly taken from CSS selectors: * * - **`E F`** All descendant Components of E that match F * - **`E > F`** All direct children Components of E that match F * - **`E ^ F`** All parent Components of E that match F * * Expressions between relationship operators are matched left to right, i.e. leftmost * selector is applied first, then if one or more matches are found, relationship operator * itself is applied, then next selector expression, etc. It is possible to combine * relationship operators in complex selectors: * *     window[title="Input form"] textfield[name=login] ^ form > button[action=submit] * * That selector can be read this way: Find a window with title "Input form", in that * window find a TextField with name "login" at any depth (including subpanels and/or * FieldSets), then find an `Ext.form.Panel` that is a parent of the TextField, and in * that form find a direct child that is a button with custom property `action` set to * value "submit". * * Whitespace on both sides of `^` and `>` operators is non-significant, i.e. can be * omitted, but usually is used for clarity. * * ## Searching by Component attributes * * Components can be searched by their object property values (attributes). To do that, * use attribute matching expression in square brackets: * * - `component[disabled]` - matches any Component that has `disabled` property with * any truthy (non-empty, not `false`) value. * - `panel[title="Test"]` - matches any Component that has `title` property set to * "Test". Note that if the value does not contain spaces, the quotes are optional. * * Attributes can use any of the following operators to compare values: * `=`, `!=`, `^=`, `$=`, `*=`, `%=`, `|=` and `~=`. * * Prefixing the attribute name with an at sign `@` means that the property must be * the object's `ownProperty`, not a property from the prototype chain. * * Specifications like `[propName]` check that the property is a truthy value. To check * that the object has an `ownProperty` of a certain name, regardless of the value use * the form `[?propName]`. * * The specified value is coerced to match the type of the property found in the * candidate Component using {@link Ext#coerce}. * * If you need to find Components by their `itemId` property, use the `#id` form; it will * do the same as `[itemId=id]` but is easier to read. * * If you need to include a metacharacter like (, ), [, ], etc., in the query, escape it * by prefixing it with a backslash: * *      var component = Ext.ComponentQuery.query('[myProperty=\\[foo\\]]'); * * ## Attribute matching operators * * The '=' operator will return the results that **exactly** match the * specified object property (attribute): * *     Ext.ComponentQuery.query('panel[cls=my-cls]'); * * Will match the following Component: * *     Ext.create('Ext.window.Window', { *         cls: 'my-cls' *     }); * * But will not match the following Component, because 'my-cls' is one value * among others: * *      Ext.create('Ext.panel.Panel', { *          cls: 'foo-cls my-cls bar-cls' *      }); * * You can use the '~=' operator instead, it will return Components with * the property that **exactly** matches one of the whitespace-separated * values. This is also true for properties that only have *one* value: * *     Ext.ComponentQuery.query('panel[cls~=my-cls]'); * * Will match both Components: * *     Ext.create('Ext.panel.Panel', { *         cls: 'foo-cls my-cls bar-cls' *     }); *      *     Ext.create('Ext.window.Window', { *         cls: 'my-cls' *     }); * * Generally, '=' operator is more suited for object properties other than * CSS classes, while '~=' operator will work best with properties that * hold lists of whitespace-separated CSS classes. * * The '^=' operator will return Components with specified attribute that * start with the passed value: * *     Ext.ComponentQuery.query('panel[title^=Sales]'); * * Will match the following Component: * *     Ext.create('Ext.panel.Panel', { *         title: 'Sales estimate for Q4' *     }); * * The '$=' operator will return Components with specified properties that * end with the passed value: * *     Ext.ComponentQuery.query('field[fieldLabel$=name]'); * * Will match the following Component: * *     Ext.create('Ext.form.field.Text', { *         fieldLabel: 'Enter your name' *     }); * * The '/=' operator will return Components with specified properties that * match the passed regular expression: * *     Ext.ComponentQuery.query('button[action/="edit|save"]'); * * Will match the following Components with a custom `action` property: * *     Ext.create('Ext.button.Button', { *          action: 'edit' *     }); * *     Ext.create('Ext.button.Button', { *          action: 'save' *     }); * * When you need to use meta characters like [], (), etc. in your query, make sure * to escape them with back slashes: * *     Ext.ComponentQuery.query('panel[title="^Sales for Q\\[1-4\\]"]'); * * The following test will find panels with their `ownProperty` collapsed being equal to * `false`. It will **not** match a collapsed property from the prototype chain. * *     Ext.ComponentQuery.query('panel[@collapsed=false]'); * * Member expressions from candidate Components may be tested. If the expression returns * a *truthy* value, the candidate Component will be included in the query: * *     var disabledFields = myFormPanel.query("{isDisabled()}"); * * Such expressions are executed in Component's context, and the above expression is * similar to running this snippet for every Component in your application: * *      if (component.isDisabled()) { *          matches.push(component); *      } * * It is important to use only methods that are available in **every** Component instance * to avoid run time exceptions. If you need to match your Components with a custom * condition formula, you can augment `Ext.Component` to provide custom matcher that * will return `false` by default, and override it in your custom classes: *  *      Ext.define('My.Component', { *          override: 'Ext.Component', *          myMatcher: function() { return false; } *      }); * *      Ext.define('My.Panel', { *          extend: 'Ext.panel.Panel', *          requires: ['My.Component'],     // Ensure that Component override is applied *          myMatcher: function(selector) { *              return selector === 'myPanel'; *          } *      }); * * After that you can use a selector with your custom matcher to find all instances * of `My.Panel`: * *      Ext.ComponentQuery.query("{myMatcher('myPanel')}"); * * However if you really need to use a custom matcher, you may find it easier to implement * a custom Pseudo class instead (see below). * * ## Conditional matching * * Attribute matchers can be combined to select only Components that match **all** * conditions (logical AND operator): * *     Ext.ComponentQuery.query('panel[cls~=my-cls][floating=true][title$="sales data"]'); * * E.g., the query above will match only a Panel-descended Component that has 'my-cls' * CSS class *and* is floating *and* with a title that ends with "sales data". * * Expressions separated with commas will match any Component that satisfies * *either* expression (logical OR operator): * *     Ext.ComponentQuery.query('field[fieldLabel^=User], field[fieldLabel*=password]'); * * E.g., the query above will match any field with field label starting with "User", * *or* any field that has "password" in its label. * * If you need to include a comma in an attribute matching expression, escape it with a * backslash: * *     Ext.ComponentQuery.query('field[fieldLabel^="User\\, foo"], field[fieldLabel*=password]'); * * ## Pseudo classes * * Pseudo classes may be used to filter results in the same way as in * {@link Ext.dom.Query}. There are five default pseudo classes: * * * `not` Negates a selector. * * `first` Filters out all except the first matching item for a selector. * * `last` Filters out all except the last matching item for a selector. * * `focusable` Filters out all except Components which by definition and configuration are *      potentially able to recieve focus, regardless of their current state * * `canfocus` Filters out all except Components which are curently able to recieve focus. *      That is, they are defined and configured focusable, and they are also visible and enabled. * * `nth-child` Filters Components by ordinal position in the selection. * * `scrollable` Filters out all except Components which are scrollable. * * `visible` Filters out hidden Components. May test deep visibility using `':visible(true)'` * * These pseudo classes can be used with other matchers or without them: * *      // Select first direct child button in any panel *      Ext.ComponentQuery.query('panel > button:first'); * *      // Select last field in Profile form *      Ext.ComponentQuery.query('form[title=Profile] field:last'); * *      // Find first focusable Component in a panel and focus it *      panel.down(':canfocus').focus(); * *      // Select any field that is not hidden in a form *      form.query('field:not(hiddenfield)'); * *      // Find last scrollable Component and reset its scroll positions. *      tabpanel.down(':scrollable[hideMode=display]:last').getScrollable().scrollTo(0, 0); * * Pseudo class `nth-child` can be used to find any child Component by its * position relative to its siblings. This class' handler takes one argument * that specifies the selection formula as `Xn` or `Xn+Y`: * *      // Find every odd field in a form *      form.query('field:nth-child(2n+1)'); // or use shortcut: :nth-child(odd) * *      // Find every even field in a form *      form.query('field:nth-child(2n)');   // or use shortcut: :nth-child(even) * *      // Find every 3rd field in a form *      form.query('field:nth-child(3n)'); * * Pseudo classes can be combined to further filter the results, e.g., in the * form example above we can modify the query to exclude hidden fields: * *      // Find every 3rd non-hidden field in a form *      form.query('field:not(hiddenfield):nth-child(3n)'); * * Note that when combining pseudo classes, whitespace is significant, i.e. * there should be no spaces between pseudo classes. This is a common mistake; * if you accidentally type a space between `field` and `:not`, the query * will not return any result because it will mean "find *field's children * Components* that are not hidden fields...". * * ## Custom pseudo classes * * It is possible to define your own custom pseudo classes. In fact, a * pseudo class is just a property in `Ext.ComponentQuery.pseudos` object * that defines pseudo class name (property name) and pseudo class handler * (property value): * *     // Function receives array and returns a filtered array. *     Ext.ComponentQuery.pseudos.invalid = function(items) { *         var i = 0, l = items.length, c, result = []; *         for (; i < l; i++) { *             if (!(c = items[i]).isValid()) { *                 result.push(c); *             } *         } *         return result; *     }; *  *     var invalidFields = myFormPanel.query('field:invalid'); *     if (invalidFields.length) { *         invalidFields[0].getEl().scrollIntoView(myFormPanel.body); *         for (var i = 0, l = invalidFields.length; i < l; i++) { *             invalidFields[i].getEl().frame("red"); *         } *     } * * Pseudo class handlers can be even more flexible, with a selector * argument used to define the logic: * *      // Handler receives array of itmes and selector in parentheses *      Ext.ComponentQuery.pseudos.titleRegex = function(components, selector) { *          var i = 0, l = components.length, c, result = [], regex = new RegExp(selector); *          for (; i < l; i++) { *              c = components[i]; *              if (c.title && regex.test(c.title)) { *                  result.push(c); *              } *          } *          return result; *      } * *      var salesTabs = tabPanel.query('panel:titleRegex("sales\\s+for\\s+201[123]")'); * * Be careful when using custom pseudo classes with MVC Controllers: when * you use a pseudo class in Controller's `control` or `listen` component * selectors, the pseudo class' handler function will be called very often * and may slow down your application significantly. A good rule of thumb * is to always specify Component xtype with the pseudo class so that the * handlers are only called on Components that you need, and try to make * the condition checks as cheap in terms of execution time as possible. * Note how in the example above, handler function checks that Component * *has* a title first, before running regex test on it. * * ## Query examples * * Queries return an array of Components. Here are some example queries: * *     // retrieve all Ext.Panels in the document by xtype *     var panelsArray = Ext.ComponentQuery.query('panel'); * *     // retrieve all Ext.Panels within the container with an id myCt *     var panelsWithinmyCt = Ext.ComponentQuery.query('#myCt panel'); * *     // retrieve all direct children which are Ext.Panels within myCt *     var directChildPanel = Ext.ComponentQuery.query('#myCt > panel'); * *     // retrieve all grids or trees *     var gridsAndTrees = Ext.ComponentQuery.query('gridpanel, treepanel'); * *     // Focus first Component *     myFormPanel.child(':canfocus').focus(); * *     // Retrieve every odd text field in a form *     myFormPanel.query('textfield:nth-child(odd)'); * *     // Retrieve every even field in a form, excluding hidden fields *     myFormPanel.query('field:not(hiddenfield):nth-child(even)'); * *     // Retrieve every scrollable in a tabpanel *     tabpanel.query(':scrollable'); * * For easy access to queries based from a particular Container see the * {@link Ext.container.Container#query}, {@link Ext.container.Container#down} and * {@link Ext.container.Container#child} methods. Also see * {@link Ext.Component#up}. */Ext.define('Ext.ComponentQuery', {    singleton: true,    requires: [        'Ext.ComponentManager',        'Ext.util.Operators',        'Ext.util.LruCache'    ]}, function() {     var cq = this,        queryOperators = Ext.util.Operators,        nthRe = /(\d*)n\+?(\d*)/,        nthRe2 = /\D/,        stripLeadingSpaceRe = /^(\s)+/,        unescapeRe = /\\(.)/g,        regexCache = new Ext.util.LruCache({            maxSize: 100        }),         // A function source code pattern with a placeholder which accepts an expression which yields a truth value when applied         // as a member on each item in the passed array.         filterFnPattern = [            'var r = [],',                'i = 0,',                'it = items,',                'l = it.length,',                'c;',            'for (; i < l; i++) {',                'c = it[i];',                'if (c.{0}) {',                   'r.push(c);',                '}',            '}',            'return r;'        ].join(''),         filterItems = function(items, operation) {            // Argument list for the operation is [ itemsArray, operationArg1, operationArg2...]             // The operation's method loops over each item in the candidate array and             // returns an array of items which match its criteria             return operation.method.apply(this, [ items ].concat(operation.args));        },         getItems = function(items, mode) {            var result = [],                i = 0,                length = items.length,                candidate,                deep = mode !== '>';                            for (; i < length; i++) {                candidate = items[i];                if (candidate.getRefItems) {                    result = result.concat(candidate.getRefItems(deep));                }            }            return result;        },         getAncestors = function(items) {            var result = [],                i = 0,                length = items.length,                candidate;            for (; i < length; i++) {                candidate = items[i];                while (!!(candidate = candidate.getRefOwner())) {                    result.push(candidate);                }            }            return result;        },         // Filters the passed candidate array and returns only items which match the passed xtype         filterByXType = function(items, xtype, shallow) {            if (xtype === '*') {                return items.slice();            }            else {                var result = [],                    i = 0,                    length = items.length,                    candidate;                for (; i < length; i++) {                    candidate = items[i];                    if (candidate.isXType(xtype, shallow)) {                        result.push(candidate);                    }                }                return result;            }        },         // Filters the passed candidate array and returns only items which have the specified property match         filterByAttribute = function(items, property, operator, compareTo) {            var result = [],                i = 0,                length = items.length,                mustBeOwnProperty,                presenceOnly,                candidate, propValue,                j, propLen,                config;             // Prefixing property name with an @ means that the property must be in the candidate, not in its prototype             if (property.charAt(0) === '@') {                mustBeOwnProperty = true;                property = property.substr(1);            }            if (property.charAt(0) === '?') {                mustBeOwnProperty = true;                presenceOnly = true;                property = property.substr(1);            }             for (; i < length; i++) {                candidate = items[i];                 // If the candidate is a product of the Ext class system, then                 // use the configurator to call getters to access the property.                 // CQ can be used to filter raw Objects.                 config = candidate.self && candidate.self.getConfigurator && candidate.self.$config.configs[property];                if (config) {                    propValue = candidate[config.names.get]();                } else if (mustBeOwnProperty && !candidate.hasOwnProperty(property)) {                    continue;                } else {                    propValue = candidate[property];                }                 if (presenceOnly) {                    result.push(candidate);                }                // implies property is an array, and we must compare value against each element.                 else if (operator === '~=') {                    if (propValue) {                        //We need an array                         if (!Ext.isArray(propValue)) {                            propValue = propValue.split(' ');                        }                         for (j = 0, propLen = propValue.length; j < propLen; j++) {                            if (queryOperators[operator](Ext.coerce(propValue[j], compareTo), compareTo)) {                                result.push(candidate);                                break;                            }                        }                    }                }                else if (operator === '/=') {                    if (propValue != null && compareTo.test(propValue)) {                        result.push(candidate);                    }                } else if (!compareTo ? !!candidate[property] : queryOperators[operator](Ext.coerce(propValue, compareTo), compareTo)) {                    result.push(candidate);                }            }            return result;        },         // Filters the passed candidate array and returns only items which have the specified itemId or id         filterById = function(items, id, idOnly) {            var result = [],                i = 0,                length = items.length,                candidate, check;             for (; i < length; i++) {                candidate = items[i];                check = idOnly ? candidate.id : candidate.getItemId();                if (check === id) {                    result.push(candidate);                }            }            return result;        },         // Filters the passed candidate array and returns only items which the named pseudo class matcher filters in         filterByPseudo = function(items, name, value) {            return cq.pseudos[name](items, value);        },         // Determines leading mode         // > for direct child, and ^ to switch to ownerCt axis         modeRe = /^(\s?([>\^])\s?|\s|$)/,         // Matches a token with possibly (true|false) appended for the "shallow" parameter         tokenRe = /^(#)?((?:\\\.|[\w\-])+|\*)(?:\((true|false)\))?/,         matchers = [{            // Checks for .xtype with possibly (true|false) appended for the "shallow" parameter             re: /^\.((?:\\\.|[\w\-])+)(?:\((true|false)\))?/,            method: filterByXType,            argTransform: function(args) {                //<debug>                 var selector = args[0];                Ext.log.warn('"'+ selector +'" ComponentQuery selector style is deprecated,' +                             ' use "' + selector.replace(/^\./, '') + '" without the leading dot instead');                //</debug>                                 if (args[1] !== undefined) {                    args[1] = args[1].replace(unescapeRe, '$1');                }                                return args.slice(1);            }        }, {            // Allow [@attribute] to check truthy ownProperty             // Allow [?attribute] to check for presence of ownProperty             // Allow [$attribute]             // Checks for @|?|$ -> word/hyphen chars -> any special attribute selector characters before             // the '=', etc. It strips out whitespace.             // For example:             //     [attribute=value], [attribute^=value], [attribute$=value], [attribute*=value],             //     [attribute~=value], [attribute%=value], [attribute!=value]             re: /^(?:\[((?:[@?$])?[\w\-]*)\s*(?:([\^$*~%!\/]?=)\s*(['"])?((?:\\\]|.)*?)\3)?(?!\\)\])/,            method: filterByAttribute,            argTransform: function(args) {                var selector  = args[0],                    property  = args[1],                    operator  = args[2],                    //quote     = args[3],                     compareTo = args[4],                    compareRe;                                // Unescape the attribute value matcher first                 if (compareTo !== undefined) {                    compareTo = compareTo.replace(unescapeRe, '$1');                     //<debug>                     var format = Ext.String.format,                        msg = "ComponentQuery selector '{0}' has an unescaped ({1}) character at the {2} " +                              "of the attribute value pattern. Usually that indicates an error " +                              "where the opening quote is not followed by the closing quote. " +                              "If you need to match a ({1}) character at the {2} of the attribute " +                              "value, escape the quote character in your pattern: (\\{1})",                        match;                                    if (match = /^(['"]).*?[^'"]$/.exec(compareTo)) { // jshint ignore:line                         Ext.log.warn(format(msg, selector, match[1], 'beginning'));                    }                    else if (match = /^[^'"].*?(['"])$/.exec(compareTo)) { // jshint ignore:line                         Ext.log.warn(format(msg, selector, match[1], 'end'));                    }                    //</debug>                 }                                if (operator === '/=') {                    compareRe = regexCache.get(compareTo);                    if (compareRe) {                        compareTo = compareRe;                    } else {                        compareTo = regexCache.add(compareTo, new RegExp(compareTo));                    }                }                                return [property, operator, compareTo];            }        }, {            // checks for #cmpItemId             re: /^#((?:\\\.|[\w\-])+)/,            method: filterById        }, {            // checks for :<pseudo_class>(<selector>)             re: /^\:([\w\-]+)(?:\(((?:\{[^\}]+\})|(?:(?!\{)[^\s>\/]*?(?!\})))\))?/,            method: filterByPseudo,            argTransform: function(args) {                if (args[2] !== undefined) {                    args[2] = args[2].replace(unescapeRe, '$1');                }                                return args.slice(1);            }        }, {            // checks for {<member_expression>}             re: /^(?:\{([^\}]+)\})/,            method: filterFnPattern        }];     // Internal class Ext.ComponentQuery.Query     cq.Query = Ext.extend(Object, {        constructor: function(cfg) {            cfg = cfg || {};            Ext.apply(this, cfg);        },                // Executes this Query upon the selected root.         // The root provides the initial source of candidate Component matches which are progressively         // filtered by iterating through this Query's operations cache.         // If no root is provided, all registered Components are searched via the ComponentManager.         // root may be a Container who's descendant Components are filtered         // root may be a Component with an implementation of getRefItems which provides some nested Components such as the         // docked items within a Panel.         // root may be an array of candidate Components to filter using this Query.         execute: function(root) {            var operations = this.operations,                result = [],                op, i, len;                        for (i = 0, len = operations.length; i < len; i++) {                op = operations[i];                                result = result.concat(this._execute(root, op));            }                        return result;        },                _execute: function(root, operations) {            var i = 0,                length = operations.length,                operation,                workingItems;             // no root, use all Components in the document             if (!root) {                workingItems = Ext.ComponentManager.getAll();            }            // Root is an iterable object like an Array, or system Collection, eg HtmlCollection             else if (Ext.isIterable(root)) {                workingItems = root;            }            // Root is a MixedCollection             else if (root.isMixedCollection) {                workingItems = root.items;            }             // We are going to loop over our operations and take care of them             // one by one.             for (; i < length; i++) {                operation = operations[i];                 // The mode operation requires some custom handling.                 // All other operations essentially filter down our current                 // working items, while mode replaces our current working                 // items by getting children from each one of our current                 // working items. The type of mode determines the type of                 // children we get. (e.g. > only gets direct children)                 if (operation.mode === '^') {                    workingItems = getAncestors(workingItems || [root]);                }                else if (operation.mode) {                    workingItems = getItems(workingItems || [root], operation.mode);                }                else {                    workingItems = filterItems(workingItems || getItems([root]), operation);                }                 // If this is the last operation, it means our current working                 // items are the final matched items. Thus return them!                 if (i === length -1) {                    return workingItems;                }            }            return [];        },         is: function(component, root) {            var operations = this.operations,                result = false,                len = operations.length,                op, i;                        if (len === 0) {                return true;            }                        for (i = 0; i < len; i++) {                op = operations[i];                                result = this._is(component, root, op);                                if (result) {                    return result;                }            }                        return false;        },                _is: function(component, root, operations) {            var len = operations.length,                active = [component],                operation, i, j, mode, items, item;                            // Loop backwards, since we're going up the hierarchy             for (i = len - 1; i >= 0; --i) {                operation = operations[i];                mode = operation.mode;                // Traversing hierarchy                 if (mode) {                    if (mode === '^') {                        active = getItems(active, ' ');                    } else if (mode === '>') {                        items = [];                        for (j = 0, len = active.length; j < len; ++j) {                            item = active[j].getRefOwner();                            if (item) {                                items.push(item);                            }                        }                        active = items;                    } else {                        active = getAncestors(active);                    }                } else {                    active = filterItems(active, operation);                }                 // After traversing the hierarchy, if we have no items, jump out                 if (active.length === 0) {                    return false;                }            }             // We don't push these on as operations because we don't want to mutate the             // array, but this is essentially a continuation of the loop above.             if (root) {                if (!mode) {                    // Last operation wasn't a mode operation, so navigate up to find                     // ancestors                     active = getAncestors(active);                }                 if (active.length > 0) {                    // If we have active items, check the root exists there to ensure we're                     // part of the tree                     active = filterItems(active, {                        method: filterById,                        args: [root.id, true]                    });                }                 if (active.length === 0) {                    return false;                }            }            return true;        },                getMatches: function(components, operations) {            var len = operations.length,                i;                            for (i = 0; i < len; ++i) {                components = filterItems(components, operations[i]);                // Performance enhancement, if we have nothing, we can                 // never add anything new, so jump out                 if (components.length === 0) {                    break;                }              }            return components;        },         isMultiMatch: function() {            return this.operations.length > 1;        }    });     Ext.apply(cq, {         /**         * @private         * Cache of selectors and matching ComponentQuery.Query objects         */        cache: new Ext.util.LruCache({            maxSize: 100        }),         /**         * @private         * Cache of pseudo class filter functions         */        pseudos: {            not: function(components, selector){                var i = 0,                    length = components.length,                    results = [],                    index = -1,                    component;                 for(; i < length; ++i) {                    component = components[i];                    if (!cq.is(component, selector)) {                        results[++index] = component;                    }                }                return results;            },            first: function(components) {                var ret = [];                 if (components.length > 0) {                    ret.push(components[0]);                }                return ret;            },            last: function(components) {                var len = components.length,                    ret = [];                 if (len > 0) {                    ret.push(components[len - 1]);                }                return ret;            },            // This filters for components which by definition and configuration are             // theoretically focusable. It does not take into account the current app state.             focusable: function(cmps) {                var len = cmps.length,                    results = [],                    i = 0,                    c;                 for (; i < len; i++) {                    c = cmps[i];                     if (c.isFocusable && c.isFocusable()) {                        results.push(c);                    }                }                 return results;            },            // This filters for components which are currently able to recieve focus.             canfocus: function(cmps, value) {                var len = cmps.length,                    results = [],                    i = 0,                    c;                 for (; i < len; i++) {                    c = cmps[i];                     if (c.canFocus && c.canFocus(false, value)) {                        results.push(c);                    }                }                 return results;            },            "nth-child" : function(c, a) {                var result = [],                    m = nthRe.exec(a === "even" && "2n" || a === "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),                    f = (m[1] || 1) - 0, len = m[2] - 0,                    i, n, nodeIndex;                 for (i = 0; n = c[i]; i++) { // jshint ignore:line                     nodeIndex = i + 1;                    if (f === 1) {                        if (len === 0 || nodeIndex === len) {                            result.push(n);                        }                    } else if ((nodeIndex + len) % f === 0){                        result.push(n);                    }                }                 return result;            },            scrollable: function(cmps) {                var len = cmps.length,                    results = [],                    i = 0,                    c;                 for (; i < len; i++) {                    c = cmps[i];                     // Note that modern toolkit prefixes with an underscore.                     if (c.scrollable || c._scrollable) {                        results.push(c);                    }                }                 return results;            },            visible: function(cmps, deep) {                deep = deep === 'true';                var len = cmps.length,                    results = [],                    i = 0,                    c;                 for (; i < len; i++) {                    c = cmps[i];                     // Note that modern toolkit prefixes with an underscore.                     if (c.isVisible(deep)) {                        results.push(c);                    }                }                 return results;            }        },         /**         * Returns an array of matched Components from within the passed root object.         *         * This method filters returned Components in a similar way to how CSS selector based DOM         * queries work using a textual selector string.         *         * See class summary for details.         *         * @param {String} selector The selector string to filter returned Components.         * @param {Ext.container.Container} [root] The Container within which to perform the query.         * If omitted, all Components within the document are included in the search.         *         * This parameter may also be an array of Components to filter according to the selector.         * @return {Ext.Component[]} The matched Components.         *         * @member Ext.ComponentQuery         */        query: function(selector, root) {            // An empty query will match every Component             if (!selector) {                return Ext.ComponentManager.all.getArray();            }                        var results = [],                noDupResults = [],                 dupMatcher = {},                 query = cq.cache.get(selector),                resultsLn, cmp, i;             if (!query) {                query = cq.cache.add(selector, cq.parse(selector));            }                        results = query.execute(root);                        // multiple selectors, potential to find duplicates             // lets filter them out.             if (query.isMultiMatch()) {                resultsLn = results.length;                for (i = 0; i < resultsLn; i++) {                    cmp = results[i];                    if (!dupMatcher[cmp.id]) {                        noDupResults.push(cmp);                        dupMatcher[cmp.id] = true;                    }                }                results = noDupResults;            }            return results;        },         /**         * Traverses the tree rooted at the passed root in pre-order mode, calling the passed function on the nodes at each level.         * That is the function is called upon each node **before** being called on its children).         *         * For an object to be queryable, it must implement the `getRefItems` method which returns all         * immediate child items.         *         * This method is used at each level down the cascade. Currently {@link Ext.Component Component}s         * and {@link Ext.data.TreeModel TreeModel}s are queryable.         *         * If you have tree-structured data, you can make your nodes queryable, and use ComponentQuery on them.         *         * @param {Object} selector A ComponentQuery selector used to filter candidate nodes before calling the function.         * An empty string matches any node.         * @param {String} root The root queryable object to start from.         * @param {Function} fn The function to call. Return `false` to abort the traverse.         * @param {Object} fn.node The node being visited.         * @param {Object} [scope] The context (`this` reference) in which the function is executed.         * @param {Array} [extraArgs] A set of arguments to be appended to the function's argument list to pass down extra data known to the caller         * **after** the node being visited.         */        visitPreOrder: function(selector, root, fn, scope, extraArgs) {            cq._visit(true, selector, root, fn, scope, extraArgs);        },         /**         * Traverses the tree rooted at the passed root in post-order mode, calling the passed function on the nodes at each level.         * That is the function is called upon each node **after** being called on its children).         *         * For an object to be queryable, it must implement the `getRefItems` method which returns all         * immediate child items.         *         * This method is used at each level down the cascade. Currently {@link Ext.Component Component}s         * and {@link Ext.data.TreeModel TreeModel}s are queryable.         *         * If you have tree-structured data, you can make your nodes queryable, and use ComponentQuery on them.         *         * @param {Object} selector A ComponentQuery selector used to filter candidate nodes before calling the function.         * An empty string matches any node.         * @param {String} root The root queryable object to start from.         * @param {Function} fn The function to call. Return `false` to abort the traverse.         * @param {Object} fn.node The node being visited.         * @param {Object} [scope] The context (`this` reference) in which the function is executed.         * @param {Array} [extraArgs] A set of arguments to be appended to the function's argument list to pass down extra data known to the caller         * **after** the node being visited.         */        visitPostOrder: function(selector, root, fn, scope, extraArgs) {            cq._visit(false, selector, root, fn, scope, extraArgs);        },         /**         * @private         * Visit implementation which handles both preOrder and postOrder modes.         */        _visit: function(preOrder, selector, root, fn, scope, extraArgs) {            var query = cq.cache.get(selector),                callArgs = [root],                children,                len = 0,                i, rootMatch;             if (!query) {                query = cq.cache.add(selector, cq.parse(selector));            }             rootMatch = query.is(root);             if (root.getRefItems) {                children = root.getRefItems();                len = children.length;            }             // append optional extraArgs             if (extraArgs) {                Ext.Array.push(callArgs, extraArgs);            }            if (preOrder) {                if (rootMatch) {                    if (fn.apply(scope || root, callArgs) === false) {                        return false;                    }                }            }            for (i = 0; i < len; i++) {                if (cq._visit.call(cq, preOrder, selector, children[i], fn, scope, extraArgs) === false) {                    return false;                }            }            if (!preOrder) {                if (rootMatch) {                    if (fn.apply(scope || root, callArgs) === false) {                        return false;                    }                }            }        },         /**         * Tests whether the passed Component matches the selector string.         * An empty selector will always match.         *         * @param {Ext.Component} component The Component to test         * @param {String} selector The selector string to test against.         * @param {Ext.Component} [root=null] The root component.         * @return {Boolean} True if the Component matches the selector.         * @member Ext.ComponentQuery         */        is: function(component, selector, root) {            if (!selector) {                return true;            }                        var query = cq.cache.get(selector);            if (!query) {                query = cq.cache.add(selector, cq.parse(selector));            }                        return query.is(component, root);        },         parse: function(selector) {            var operations = [],                selectors, sel, i, len;                        selectors = Ext.splitAndUnescape(selector, ',');                        for (i = 0, len = selectors.length; i < len; i++) {                // Trim the whitespace as the parser expects it.                 sel = Ext.String.trim(selectors[i]);                                // Usually, a dangling comma at the end of a selector means a typo.                 // In that case, the last sel value will be an empty string; the parser                 // will silently ignore it which is not good, so we throw an error here.                 //<debug>                 if (sel === '') {                    Ext.raise('Invalid ComponentQuery selector: ""');                }                //</debug>                                 operations.push(cq._parse(sel));            }             //  Now that we have all our operations in an array, we are going             // to create a new Query using these operations.             return new cq.Query({                operations: operations            });        },                _parse: function(selector) {            var operations = [],                trim = Ext.String.trim,                length = matchers.length,                lastSelector,                tokenMatch,                token,                matchedChar,                modeMatch,                selectorMatch,                transform,                i, matcher, method, args;             // We are going to parse the beginning of the selector over and             // over again, slicing off the selector any portions we converted into an             // operation, until it is an empty string.             while (selector && lastSelector !== selector) {                lastSelector = selector;                 // First we check if we are dealing with a token like #, * or an xtype                 tokenMatch = selector.match(tokenRe);                 if (tokenMatch) {                    matchedChar = tokenMatch[1];                    token = trim(tokenMatch[2]).replace(unescapeRe, '$1');                     // If the token is prefixed with a # we push a filterById operation to our stack                     if (matchedChar === '#') {                        operations.push({                            method: filterById,                            args: [token]                        });                    }                    // If the token is a * or an xtype string, we push a filterByXType                     // operation to the stack.                     else {                        operations.push({                            method: filterByXType,                            args: [token, Boolean(tokenMatch[3])]                        });                    }                     // Now we slice of the part we just converted into an operation                     selector = selector.replace(tokenMatch[0], '').replace(stripLeadingSpaceRe, '$1');                }                 // If the next part of the query is not a space or > or ^, it means we                 // are going to check for more things that our current selection                 // has to comply to.                 while (!(modeMatch = selector.match(modeRe))) {                    // Lets loop over each type of matcher and execute it                     // on our current selector.                     for (i = 0; selector && i < length; i++) {                        matcher = matchers[i];                        selectorMatch = selector.match(matcher.re);                        method = matcher.method;                        transform = matcher.argTransform;                         // If we have a match, add an operation with the method                         // associated with this matcher, and pass the regular                         // expression matches are arguments to the operation.                         if (selectorMatch) {                            // Transform function will do unescaping and additional checks                             if (transform) {                                args = transform(selectorMatch);                            }                            else {                                args = selectorMatch.slice(1);                            }                                                        operations.push({                                method: Ext.isString(matcher.method)                                    // Turn a string method into a function by formatting the string with our selector matche expression                                     // A new method is created for different match expressions, eg {id=='textfield-1024'}                                     // Every expression may be different in different selectors.                                     ? Ext.functionFactory('items', Ext.String.format.apply(Ext.String, [method].concat(selectorMatch.slice(1))))                                    : matcher.method,                                args: args                            });                                                        selector = selector.replace(selectorMatch[0], '').replace(stripLeadingSpaceRe, '$1');                            break; // Break on match                         }                        // Exhausted all matches: It's an error                         if (i === (length - 1)) {                            Ext.raise('Invalid ComponentQuery selector: "' + arguments[0] + '"');                        }                    }                }                 // Now we are going to check for a mode change. This means a space                 // or a > to determine if we are going to select all the children                 // of the currently matched items, or a ^ if we are going to use the                 // ownerCt axis as the candidate source.                 if (modeMatch[1]) { // Assignment, and test for truthiness!                     operations.push({                        mode: modeMatch[2]||modeMatch[1]                    });                                        // When we have consumed the mode character, clean up leading spaces                     selector = selector.replace(modeMatch[0], '').replace(stripLeadingSpaceRe, '');                }            }                        return operations;        }    });     /**     * Same as {@link Ext.ComponentQuery#query}.     * @param {String} selector The selector string to filter returned Components.     * @param {Ext.container.Container} [root] The Container within which to perform the query.     * If omitted, all Components within the document are included in the search.     *     * This parameter may also be an array of Components to filter according to the selector.     * @return {Ext.Component[]} The matched Components.     * @method all     * @member Ext     */    Ext.all = function () {        return cq.query.apply(cq, arguments);    };     /**     * Returns the first match to the given component query.     * See {@link Ext.ComponentQuery#query}.     * @param {String} selector The selector string to filter returned Component.     * @param {Ext.container.Container} [root] The Container within which to perform the query.     * If omitted, all Components within the document are included in the search.     *     * This parameter may also be an array of Components to filter according to the selector.     * @return {Ext.Component} The first matched Component or `null`.     * @method first     * @member Ext     */    Ext.first = function () {        var matches = cq.query.apply(cq, arguments);        return (matches && matches[0]) || null;    }});