PageRenderTime 1321ms CodeModel.GetById 1123ms app.highlight 40ms RepoModel.GetById 126ms app.codeStats 1ms

/ext-4.0.7/docs/source/ComponentQuery.html

https://bitbucket.org/srogerf/javascript
HTML | 535 lines | 495 code | 40 blank | 0 comment | 0 complexity | eb12dfb7152b116026fe3e67204537ea MD5 | raw file
  1<!DOCTYPE html>
  2<html>
  3<head>
  4  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5  <title>The source code</title>
  6  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8  <style type="text/css">
  9    .highlight { display: block; background-color: #ddd; }
 10  </style>
 11  <script type="text/javascript">
 12    function highlight() {
 13      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
 14    }
 15  </script>
 16</head>
 17<body onload="prettyPrint(); highlight();">
 18  <pre class="prettyprint lang-js"><span id='Ext-ComponentQuery'>/**
 19</span> * Provides searching of Components within Ext.ComponentManager (globally) or a specific
 20 * Ext.container.Container on the document with a similar syntax to a CSS selector.
 21 *
 22 * Components can be retrieved by using their {@link Ext.Component xtype} with an optional . prefix
 23 *
 24 * - `component` or `.component`
 25 * - `gridpanel` or `.gridpanel`
 26 *
 27 * An itemId or id must be prefixed with a #
 28 *
 29 * - `#myContainer`
 30 *
 31 * Attributes must be wrapped in brackets
 32 *
 33 * - `component[autoScroll]`
 34 * - `panel[title=&quot;Test&quot;]`
 35 *
 36 * Member expressions from candidate Components may be tested. If the expression returns a *truthy* value,
 37 * the candidate Component will be included in the query:
 38 *
 39 *     var disabledFields = myFormPanel.query(&quot;{isDisabled()}&quot;);
 40 *
 41 * Pseudo classes may be used to filter results in the same way as in {@link Ext.DomQuery DomQuery}:
 42 *
 43 *     // Function receives array and returns a filtered array.
 44 *     Ext.ComponentQuery.pseudos.invalid = function(items) {
 45 *         var i = 0, l = items.length, c, result = [];
 46 *         for (; i &lt; l; i++) {
 47 *             if (!(c = items[i]).isValid()) {
 48 *                 result.push(c);
 49 *             }
 50 *         }
 51 *         return result;
 52 *     };
 53 *      
 54 *     var invalidFields = myFormPanel.query('field:invalid');
 55 *     if (invalidFields.length) {
 56 *         invalidFields[0].getEl().scrollIntoView(myFormPanel.body);
 57 *         for (var i = 0, l = invalidFields.length; i &lt; l; i++) {
 58 *             invalidFields[i].getEl().frame(&quot;red&quot;);
 59 *         }
 60 *     }
 61 *
 62 * Default pseudos include:
 63 *
 64 * - not
 65 * - last
 66 *
 67 * Queries return an array of components.
 68 * Here are some example queries.
 69 *
 70 *     // retrieve all Ext.Panels in the document by xtype
 71 *     var panelsArray = Ext.ComponentQuery.query('panel');
 72 *
 73 *     // retrieve all Ext.Panels within the container with an id myCt
 74 *     var panelsWithinmyCt = Ext.ComponentQuery.query('#myCt panel');
 75 *
 76 *     // retrieve all direct children which are Ext.Panels within myCt
 77 *     var directChildPanel = Ext.ComponentQuery.query('#myCt &gt; panel');
 78 *
 79 *     // retrieve all grids and trees
 80 *     var gridsAndTrees = Ext.ComponentQuery.query('gridpanel, treepanel');
 81 *
 82 * For easy access to queries based from a particular Container see the {@link Ext.container.Container#query},
 83 * {@link Ext.container.Container#down} and {@link Ext.container.Container#child} methods. Also see
 84 * {@link Ext.Component#up}.
 85 */
 86Ext.define('Ext.ComponentQuery', {
 87    singleton: true,
 88    uses: ['Ext.ComponentManager']
 89}, function() {
 90
 91    var cq = this,
 92
 93        // A function source code pattern with a placeholder which accepts an expression which yields a truth value when applied
 94        // as a member on each item in the passed array.
 95        filterFnPattern = [
 96            'var r = [],',
 97                'i = 0,',
 98                'it = items,',
 99                'l = it.length,',
100                'c;',
101            'for (; i &lt; l; i++) {',
102                'c = it[i];',
103                'if (c.{0}) {',
104                   'r.push(c);',
105                '}',
106            '}',
107            'return r;'
108        ].join(''),
109
110        filterItems = function(items, operation) {
111            // Argument list for the operation is [ itemsArray, operationArg1, operationArg2...]
112            // The operation's method loops over each item in the candidate array and
113            // returns an array of items which match its criteria
114            return operation.method.apply(this, [ items ].concat(operation.args));
115        },
116
117        getItems = function(items, mode) {
118            var result = [],
119                i = 0,
120                length = items.length,
121                candidate,
122                deep = mode !== '&gt;';
123                
124            for (; i &lt; length; i++) {
125                candidate = items[i];
126                if (candidate.getRefItems) {
127                    result = result.concat(candidate.getRefItems(deep));
128                }
129            }
130            return result;
131        },
132
133        getAncestors = function(items) {
134            var result = [],
135                i = 0,
136                length = items.length,
137                candidate;
138            for (; i &lt; length; i++) {
139                candidate = items[i];
140                while (!!(candidate = (candidate.ownerCt || candidate.floatParent))) {
141                    result.push(candidate);
142                }
143            }
144            return result;
145        },
146
147        // Filters the passed candidate array and returns only items which match the passed xtype
148        filterByXType = function(items, xtype, shallow) {
149            if (xtype === '*') {
150                return items.slice();
151            }
152            else {
153                var result = [],
154                    i = 0,
155                    length = items.length,
156                    candidate;
157                for (; i &lt; length; i++) {
158                    candidate = items[i];
159                    if (candidate.isXType(xtype, shallow)) {
160                        result.push(candidate);
161                    }
162                }
163                return result;
164            }
165        },
166
167        // Filters the passed candidate array and returns only items which have the passed className
168        filterByClassName = function(items, className) {
169            var EA = Ext.Array,
170                result = [],
171                i = 0,
172                length = items.length,
173                candidate;
174            for (; i &lt; length; i++) {
175                candidate = items[i];
176                if (candidate.el ? candidate.el.hasCls(className) : EA.contains(candidate.initCls(), className)) {
177                    result.push(candidate);
178                }
179            }
180            return result;
181        },
182
183        // Filters the passed candidate array and returns only items which have the specified property match
184        filterByAttribute = function(items, property, operator, value) {
185            var result = [],
186                i = 0,
187                length = items.length,
188                candidate;
189            for (; i &lt; length; i++) {
190                candidate = items[i];
191                if (!value ? !!candidate[property] : (String(candidate[property]) === value)) {
192                    result.push(candidate);
193                }
194            }
195            return result;
196        },
197
198        // Filters the passed candidate array and returns only items which have the specified itemId or id
199        filterById = function(items, id) {
200            var result = [],
201                i = 0,
202                length = items.length,
203                candidate;
204            for (; i &lt; length; i++) {
205                candidate = items[i];
206                if (candidate.getItemId() === id) {
207                    result.push(candidate);
208                }
209            }
210            return result;
211        },
212
213        // Filters the passed candidate array and returns only items which the named pseudo class matcher filters in
214        filterByPseudo = function(items, name, value) {
215            return cq.pseudos[name](items, value);
216        },
217
218        // Determines leading mode
219        // &gt; for direct child, and ^ to switch to ownerCt axis
220        modeRe = /^(\s?([&gt;\^])\s?|\s|$)/,
221
222        // Matches a token with possibly (true|false) appended for the &quot;shallow&quot; parameter
223        tokenRe = /^(#)?([\w\-]+|\*)(?:\((true|false)\))?/,
224
225        matchers = [{
226            // Checks for .xtype with possibly (true|false) appended for the &quot;shallow&quot; parameter
227            re: /^\.([\w\-]+)(?:\((true|false)\))?/,
228            method: filterByXType
229        },{
230            // checks for [attribute=value]
231            re: /^(?:[\[](?:@)?([\w\-]+)\s?(?:(=|.=)\s?['&quot;]?(.*?)[&quot;']?)?[\]])/,
232            method: filterByAttribute
233        }, {
234            // checks for #cmpItemId
235            re: /^#([\w\-]+)/,
236            method: filterById
237        }, {
238            // checks for :&lt;pseudo_class&gt;(&lt;selector&gt;)
239            re: /^\:([\w\-]+)(?:\(((?:\{[^\}]+\})|(?:(?!\{)[^\s&gt;\/]*?(?!\})))\))?/,
240            method: filterByPseudo
241        }, {
242            // checks for {&lt;member_expression&gt;}
243            re: /^(?:\{([^\}]+)\})/,
244            method: filterFnPattern
245        }];
246
247    // @class Ext.ComponentQuery.Query
248    // This internal class is completely hidden in documentation.
249    cq.Query = Ext.extend(Object, {
250        constructor: function(cfg) {
251            cfg = cfg || {};
252            Ext.apply(this, cfg);
253        },
254
255        // Executes this Query upon the selected root.
256        // The root provides the initial source of candidate Component matches which are progressively
257        // filtered by iterating through this Query's operations cache.
258        // If no root is provided, all registered Components are searched via the ComponentManager.
259        // root may be a Container who's descendant Components are filtered
260        // root may be a Component with an implementation of getRefItems which provides some nested Components such as the
261        // docked items within a Panel.
262        // root may be an array of candidate Components to filter using this Query.
263        execute : function(root) {
264            var operations = this.operations,
265                i = 0,
266                length = operations.length,
267                operation,
268                workingItems;
269
270            // no root, use all Components in the document
271            if (!root) {
272                workingItems = Ext.ComponentManager.all.getArray();
273            }
274            // Root is a candidate Array
275            else if (Ext.isArray(root)) {
276                workingItems = root;
277            }
278
279            // We are going to loop over our operations and take care of them
280            // one by one.
281            for (; i &lt; length; i++) {
282                operation = operations[i];
283
284                // The mode operation requires some custom handling.
285                // All other operations essentially filter down our current
286                // working items, while mode replaces our current working
287                // items by getting children from each one of our current
288                // working items. The type of mode determines the type of
289                // children we get. (e.g. &gt; only gets direct children)
290                if (operation.mode === '^') {
291                    workingItems = getAncestors(workingItems || [root]);
292                }
293                else if (operation.mode) {
294                    workingItems = getItems(workingItems || [root], operation.mode);
295                }
296                else {
297                    workingItems = filterItems(workingItems || getItems([root]), operation);
298                }
299
300                // If this is the last operation, it means our current working
301                // items are the final matched items. Thus return them!
302                if (i === length -1) {
303                    return workingItems;
304                }
305            }
306            return [];
307        },
308
309        is: function(component) {
310            var operations = this.operations,
311                components = Ext.isArray(component) ? component : [component],
312                originalLength = components.length,
313                lastOperation = operations[operations.length-1],
314                ln, i;
315
316            components = filterItems(components, lastOperation);
317            if (components.length === originalLength) {
318                if (operations.length &gt; 1) {
319                    for (i = 0, ln = components.length; i &lt; ln; i++) {
320                        if (Ext.Array.indexOf(this.execute(), components[i]) === -1) {
321                            return false;
322                        }
323                    }
324                }
325                return true;
326            }
327            return false;
328        }
329    });
330
331    Ext.apply(this, {
332
333        // private cache of selectors and matching ComponentQuery.Query objects
334        cache: {},
335
336        // private cache of pseudo class filter functions
337        pseudos: {
338            not: function(components, selector){
339                var CQ = Ext.ComponentQuery,
340                    i = 0,
341                    length = components.length,
342                    results = [],
343                    index = -1,
344                    component;
345                
346                for(; i &lt; length; ++i) {
347                    component = components[i];
348                    if (!CQ.is(component, selector)) {
349                        results[++index] = component;
350                    }
351                }
352                return results;
353            },
354            last: function(components) {
355                return components[components.length - 1];
356            }
357        },
358
359<span id='Ext-ComponentQuery-method-query'>        /**
360</span>         * Returns an array of matched Components from within the passed root object.
361         *
362         * This method filters returned Components in a similar way to how CSS selector based DOM
363         * queries work using a textual selector string.
364         *
365         * See class summary for details.
366         *
367         * @param {String} selector The selector string to filter returned Components
368         * @param {Ext.container.Container} root The Container within which to perform the query.
369         * If omitted, all Components within the document are included in the search.
370         * 
371         * This parameter may also be an array of Components to filter according to the selector.&lt;/p&gt;
372         * @returns {Ext.Component[]} The matched Components.
373         * 
374         * @member Ext.ComponentQuery
375         */
376        query: function(selector, root) {
377            var selectors = selector.split(','),
378                length = selectors.length,
379                i = 0,
380                results = [],
381                noDupResults = [], 
382                dupMatcher = {}, 
383                query, resultsLn, cmp;
384
385            for (; i &lt; length; i++) {
386                selector = Ext.String.trim(selectors[i]);
387                query = this.cache[selector];
388                if (!query) {
389                    this.cache[selector] = query = this.parse(selector);
390                }
391                results = results.concat(query.execute(root));
392            }
393
394            // multiple selectors, potential to find duplicates
395            // lets filter them out.
396            if (length &gt; 1) {
397                resultsLn = results.length;
398                for (i = 0; i &lt; resultsLn; i++) {
399                    cmp = results[i];
400                    if (!dupMatcher[cmp.id]) {
401                        noDupResults.push(cmp);
402                        dupMatcher[cmp.id] = true;
403                    }
404                }
405                results = noDupResults;
406            }
407            return results;
408        },
409
410<span id='Ext-ComponentQuery-method-is'>        /**
411</span>         * Tests whether the passed Component matches the selector string.
412         * @param {Ext.Component} component The Component to test
413         * @param {String} selector The selector string to test against.
414         * @return {Boolean} True if the Component matches the selector.
415         * @member Ext.ComponentQuery
416         */
417        is: function(component, selector) {
418            if (!selector) {
419                return true;
420            }
421            var query = this.cache[selector];
422            if (!query) {
423                this.cache[selector] = query = this.parse(selector);
424            }
425            return query.is(component);
426        },
427
428        parse: function(selector) {
429            var operations = [],
430                length = matchers.length,
431                lastSelector,
432                tokenMatch,
433                matchedChar,
434                modeMatch,
435                selectorMatch,
436                i, matcher, method;
437
438            // We are going to parse the beginning of the selector over and
439            // over again, slicing off the selector any portions we converted into an
440            // operation, until it is an empty string.
441            while (selector &amp;&amp; lastSelector !== selector) {
442                lastSelector = selector;
443
444                // First we check if we are dealing with a token like #, * or an xtype
445                tokenMatch = selector.match(tokenRe);
446
447                if (tokenMatch) {
448                    matchedChar = tokenMatch[1];
449
450                    // If the token is prefixed with a # we push a filterById operation to our stack
451                    if (matchedChar === '#') {
452                        operations.push({
453                            method: filterById,
454                            args: [Ext.String.trim(tokenMatch[2])]
455                        });
456                    }
457                    // If the token is prefixed with a . we push a filterByClassName operation to our stack
458                    // FIXME: Not enabled yet. just needs \. adding to the tokenRe prefix
459                    else if (matchedChar === '.') {
460                        operations.push({
461                            method: filterByClassName,
462                            args: [Ext.String.trim(tokenMatch[2])]
463                        });
464                    }
465                    // If the token is a * or an xtype string, we push a filterByXType
466                    // operation to the stack.
467                    else {
468                        operations.push({
469                            method: filterByXType,
470                            args: [Ext.String.trim(tokenMatch[2]), Boolean(tokenMatch[3])]
471                        });
472                    }
473
474                    // Now we slice of the part we just converted into an operation
475                    selector = selector.replace(tokenMatch[0], '');
476                }
477
478                // If the next part of the query is not a space or &gt; or ^, it means we
479                // are going to check for more things that our current selection
480                // has to comply to.
481                while (!(modeMatch = selector.match(modeRe))) {
482                    // Lets loop over each type of matcher and execute it
483                    // on our current selector.
484                    for (i = 0; selector &amp;&amp; i &lt; length; i++) {
485                        matcher = matchers[i];
486                        selectorMatch = selector.match(matcher.re);
487                        method = matcher.method;
488
489                        // If we have a match, add an operation with the method
490                        // associated with this matcher, and pass the regular
491                        // expression matches are arguments to the operation.
492                        if (selectorMatch) {
493                            operations.push({
494                                method: Ext.isString(matcher.method)
495                                    // Turn a string method into a function by formatting the string with our selector matche expression
496                                    // A new method is created for different match expressions, eg {id=='textfield-1024'}
497                                    // Every expression may be different in different selectors.
498                                    ? Ext.functionFactory('items', Ext.String.format.apply(Ext.String, [method].concat(selectorMatch.slice(1))))
499                                    : matcher.method,
500                                args: selectorMatch.slice(1)
501                            });
502                            selector = selector.replace(selectorMatch[0], '');
503                            break; // Break on match
504                        }
505                        //&lt;debug&gt;
506                        // Exhausted all matches: It's an error
507                        if (i === (length - 1)) {
508                            Ext.Error.raise('Invalid ComponentQuery selector: &quot;' + arguments[0] + '&quot;');
509                        }
510                        //&lt;/debug&gt;
511                    }
512                }
513
514                // Now we are going to check for a mode change. This means a space
515                // or a &gt; to determine if we are going to select all the children
516                // of the currently matched items, or a ^ if we are going to use the
517                // ownerCt axis as the candidate source.
518                if (modeMatch[1]) { // Assignment, and test for truthiness!
519                    operations.push({
520                        mode: modeMatch[2]||modeMatch[1]
521                    });
522                    selector = selector.replace(modeMatch[0], '');
523                }
524            }
525
526            //  Now that we have all our operations in an array, we are going
527            // to create a new Query using these operations.
528            return new cq.Query({
529                operations: operations
530            });
531        }
532    });
533});</pre>
534</body>
535</html>