/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. */
  86. Ext.define('Ext.ComponentQuery', {
  87. singleton: true,
  88. uses: ['Ext.ComponentManager']
  89. }, function() {
  90. var cq = this,
  91. // A function source code pattern with a placeholder which accepts an expression which yields a truth value when applied
  92. // as a member on each item in the passed array.
  93. filterFnPattern = [
  94. 'var r = [],',
  95. 'i = 0,',
  96. 'it = items,',
  97. 'l = it.length,',
  98. 'c;',
  99. 'for (; i &lt; l; i++) {',
  100. 'c = it[i];',
  101. 'if (c.{0}) {',
  102. 'r.push(c);',
  103. '}',
  104. '}',
  105. 'return r;'
  106. ].join(''),
  107. filterItems = function(items, operation) {
  108. // Argument list for the operation is [ itemsArray, operationArg1, operationArg2...]
  109. // The operation's method loops over each item in the candidate array and
  110. // returns an array of items which match its criteria
  111. return operation.method.apply(this, [ items ].concat(operation.args));
  112. },
  113. getItems = function(items, mode) {
  114. var result = [],
  115. i = 0,
  116. length = items.length,
  117. candidate,
  118. deep = mode !== '&gt;';
  119. for (; i &lt; length; i++) {
  120. candidate = items[i];
  121. if (candidate.getRefItems) {
  122. result = result.concat(candidate.getRefItems(deep));
  123. }
  124. }
  125. return result;
  126. },
  127. getAncestors = function(items) {
  128. var result = [],
  129. i = 0,
  130. length = items.length,
  131. candidate;
  132. for (; i &lt; length; i++) {
  133. candidate = items[i];
  134. while (!!(candidate = (candidate.ownerCt || candidate.floatParent))) {
  135. result.push(candidate);
  136. }
  137. }
  138. return result;
  139. },
  140. // Filters the passed candidate array and returns only items which match the passed xtype
  141. filterByXType = function(items, xtype, shallow) {
  142. if (xtype === '*') {
  143. return items.slice();
  144. }
  145. else {
  146. var result = [],
  147. i = 0,
  148. length = items.length,
  149. candidate;
  150. for (; i &lt; length; i++) {
  151. candidate = items[i];
  152. if (candidate.isXType(xtype, shallow)) {
  153. result.push(candidate);
  154. }
  155. }
  156. return result;
  157. }
  158. },
  159. // Filters the passed candidate array and returns only items which have the passed className
  160. filterByClassName = function(items, className) {
  161. var EA = Ext.Array,
  162. result = [],
  163. i = 0,
  164. length = items.length,
  165. candidate;
  166. for (; i &lt; length; i++) {
  167. candidate = items[i];
  168. if (candidate.el ? candidate.el.hasCls(className) : EA.contains(candidate.initCls(), className)) {
  169. result.push(candidate);
  170. }
  171. }
  172. return result;
  173. },
  174. // Filters the passed candidate array and returns only items which have the specified property match
  175. filterByAttribute = function(items, property, operator, value) {
  176. var result = [],
  177. i = 0,
  178. length = items.length,
  179. candidate;
  180. for (; i &lt; length; i++) {
  181. candidate = items[i];
  182. if (!value ? !!candidate[property] : (String(candidate[property]) === value)) {
  183. result.push(candidate);
  184. }
  185. }
  186. return result;
  187. },
  188. // Filters the passed candidate array and returns only items which have the specified itemId or id
  189. filterById = function(items, id) {
  190. var result = [],
  191. i = 0,
  192. length = items.length,
  193. candidate;
  194. for (; i &lt; length; i++) {
  195. candidate = items[i];
  196. if (candidate.getItemId() === id) {
  197. result.push(candidate);
  198. }
  199. }
  200. return result;
  201. },
  202. // Filters the passed candidate array and returns only items which the named pseudo class matcher filters in
  203. filterByPseudo = function(items, name, value) {
  204. return cq.pseudos[name](items, value);
  205. },
  206. // Determines leading mode
  207. // &gt; for direct child, and ^ to switch to ownerCt axis
  208. modeRe = /^(\s?([&gt;\^])\s?|\s|$)/,
  209. // Matches a token with possibly (true|false) appended for the &quot;shallow&quot; parameter
  210. tokenRe = /^(#)?([\w\-]+|\*)(?:\((true|false)\))?/,
  211. matchers = [{
  212. // Checks for .xtype with possibly (true|false) appended for the &quot;shallow&quot; parameter
  213. re: /^\.([\w\-]+)(?:\((true|false)\))?/,
  214. method: filterByXType
  215. },{
  216. // checks for [attribute=value]
  217. re: /^(?:[\[](?:@)?([\w\-]+)\s?(?:(=|.=)\s?['&quot;]?(.*?)[&quot;']?)?[\]])/,
  218. method: filterByAttribute
  219. }, {
  220. // checks for #cmpItemId
  221. re: /^#([\w\-]+)/,
  222. method: filterById
  223. }, {
  224. // checks for :&lt;pseudo_class&gt;(&lt;selector&gt;)
  225. re: /^\:([\w\-]+)(?:\(((?:\{[^\}]+\})|(?:(?!\{)[^\s&gt;\/]*?(?!\})))\))?/,
  226. method: filterByPseudo
  227. }, {
  228. // checks for {&lt;member_expression&gt;}
  229. re: /^(?:\{([^\}]+)\})/,
  230. method: filterFnPattern
  231. }];
  232. // @class Ext.ComponentQuery.Query
  233. // This internal class is completely hidden in documentation.
  234. cq.Query = Ext.extend(Object, {
  235. constructor: function(cfg) {
  236. cfg = cfg || {};
  237. Ext.apply(this, cfg);
  238. },
  239. // Executes this Query upon the selected root.
  240. // The root provides the initial source of candidate Component matches which are progressively
  241. // filtered by iterating through this Query's operations cache.
  242. // If no root is provided, all registered Components are searched via the ComponentManager.
  243. // root may be a Container who's descendant Components are filtered
  244. // root may be a Component with an implementation of getRefItems which provides some nested Components such as the
  245. // docked items within a Panel.
  246. // root may be an array of candidate Components to filter using this Query.
  247. execute : function(root) {
  248. var operations = this.operations,
  249. i = 0,
  250. length = operations.length,
  251. operation,
  252. workingItems;
  253. // no root, use all Components in the document
  254. if (!root) {
  255. workingItems = Ext.ComponentManager.all.getArray();
  256. }
  257. // Root is a candidate Array
  258. else if (Ext.isArray(root)) {
  259. workingItems = root;
  260. }
  261. // We are going to loop over our operations and take care of them
  262. // one by one.
  263. for (; i &lt; length; i++) {
  264. operation = operations[i];
  265. // The mode operation requires some custom handling.
  266. // All other operations essentially filter down our current
  267. // working items, while mode replaces our current working
  268. // items by getting children from each one of our current
  269. // working items. The type of mode determines the type of
  270. // children we get. (e.g. &gt; only gets direct children)
  271. if (operation.mode === '^') {
  272. workingItems = getAncestors(workingItems || [root]);
  273. }
  274. else if (operation.mode) {
  275. workingItems = getItems(workingItems || [root], operation.mode);
  276. }
  277. else {
  278. workingItems = filterItems(workingItems || getItems([root]), operation);
  279. }
  280. // If this is the last operation, it means our current working
  281. // items are the final matched items. Thus return them!
  282. if (i === length -1) {
  283. return workingItems;
  284. }
  285. }
  286. return [];
  287. },
  288. is: function(component) {
  289. var operations = this.operations,
  290. components = Ext.isArray(component) ? component : [component],
  291. originalLength = components.length,
  292. lastOperation = operations[operations.length-1],
  293. ln, i;
  294. components = filterItems(components, lastOperation);
  295. if (components.length === originalLength) {
  296. if (operations.length &gt; 1) {
  297. for (i = 0, ln = components.length; i &lt; ln; i++) {
  298. if (Ext.Array.indexOf(this.execute(), components[i]) === -1) {
  299. return false;
  300. }
  301. }
  302. }
  303. return true;
  304. }
  305. return false;
  306. }
  307. });
  308. Ext.apply(this, {
  309. // private cache of selectors and matching ComponentQuery.Query objects
  310. cache: {},
  311. // private cache of pseudo class filter functions
  312. pseudos: {
  313. not: function(components, selector){
  314. var CQ = Ext.ComponentQuery,
  315. i = 0,
  316. length = components.length,
  317. results = [],
  318. index = -1,
  319. component;
  320. for(; i &lt; length; ++i) {
  321. component = components[i];
  322. if (!CQ.is(component, selector)) {
  323. results[++index] = component;
  324. }
  325. }
  326. return results;
  327. },
  328. last: function(components) {
  329. return components[components.length - 1];
  330. }
  331. },
  332. <span id='Ext-ComponentQuery-method-query'> /**
  333. </span> * Returns an array of matched Components from within the passed root object.
  334. *
  335. * This method filters returned Components in a similar way to how CSS selector based DOM
  336. * queries work using a textual selector string.
  337. *
  338. * See class summary for details.
  339. *
  340. * @param {String} selector The selector string to filter returned Components
  341. * @param {Ext.container.Container} root The Container within which to perform the query.
  342. * If omitted, all Components within the document are included in the search.
  343. *
  344. * This parameter may also be an array of Components to filter according to the selector.&lt;/p&gt;
  345. * @returns {Ext.Component[]} The matched Components.
  346. *
  347. * @member Ext.ComponentQuery
  348. */
  349. query: function(selector, root) {
  350. var selectors = selector.split(','),
  351. length = selectors.length,
  352. i = 0,
  353. results = [],
  354. noDupResults = [],
  355. dupMatcher = {},
  356. query, resultsLn, cmp;
  357. for (; i &lt; length; i++) {
  358. selector = Ext.String.trim(selectors[i]);
  359. query = this.cache[selector];
  360. if (!query) {
  361. this.cache[selector] = query = this.parse(selector);
  362. }
  363. results = results.concat(query.execute(root));
  364. }
  365. // multiple selectors, potential to find duplicates
  366. // lets filter them out.
  367. if (length &gt; 1) {
  368. resultsLn = results.length;
  369. for (i = 0; i &lt; resultsLn; i++) {
  370. cmp = results[i];
  371. if (!dupMatcher[cmp.id]) {
  372. noDupResults.push(cmp);
  373. dupMatcher[cmp.id] = true;
  374. }
  375. }
  376. results = noDupResults;
  377. }
  378. return results;
  379. },
  380. <span id='Ext-ComponentQuery-method-is'> /**
  381. </span> * Tests whether the passed Component matches the selector string.
  382. * @param {Ext.Component} component The Component to test
  383. * @param {String} selector The selector string to test against.
  384. * @return {Boolean} True if the Component matches the selector.
  385. * @member Ext.ComponentQuery
  386. */
  387. is: function(component, selector) {
  388. if (!selector) {
  389. return true;
  390. }
  391. var query = this.cache[selector];
  392. if (!query) {
  393. this.cache[selector] = query = this.parse(selector);
  394. }
  395. return query.is(component);
  396. },
  397. parse: function(selector) {
  398. var operations = [],
  399. length = matchers.length,
  400. lastSelector,
  401. tokenMatch,
  402. matchedChar,
  403. modeMatch,
  404. selectorMatch,
  405. i, matcher, method;
  406. // We are going to parse the beginning of the selector over and
  407. // over again, slicing off the selector any portions we converted into an
  408. // operation, until it is an empty string.
  409. while (selector &amp;&amp; lastSelector !== selector) {
  410. lastSelector = selector;
  411. // First we check if we are dealing with a token like #, * or an xtype
  412. tokenMatch = selector.match(tokenRe);
  413. if (tokenMatch) {
  414. matchedChar = tokenMatch[1];
  415. // If the token is prefixed with a # we push a filterById operation to our stack
  416. if (matchedChar === '#') {
  417. operations.push({
  418. method: filterById,
  419. args: [Ext.String.trim(tokenMatch[2])]
  420. });
  421. }
  422. // If the token is prefixed with a . we push a filterByClassName operation to our stack
  423. // FIXME: Not enabled yet. just needs \. adding to the tokenRe prefix
  424. else if (matchedChar === '.') {
  425. operations.push({
  426. method: filterByClassName,
  427. args: [Ext.String.trim(tokenMatch[2])]
  428. });
  429. }
  430. // If the token is a * or an xtype string, we push a filterByXType
  431. // operation to the stack.
  432. else {
  433. operations.push({
  434. method: filterByXType,
  435. args: [Ext.String.trim(tokenMatch[2]), Boolean(tokenMatch[3])]
  436. });
  437. }
  438. // Now we slice of the part we just converted into an operation
  439. selector = selector.replace(tokenMatch[0], '');
  440. }
  441. // If the next part of the query is not a space or &gt; or ^, it means we
  442. // are going to check for more things that our current selection
  443. // has to comply to.
  444. while (!(modeMatch = selector.match(modeRe))) {
  445. // Lets loop over each type of matcher and execute it
  446. // on our current selector.
  447. for (i = 0; selector &amp;&amp; i &lt; length; i++) {
  448. matcher = matchers[i];
  449. selectorMatch = selector.match(matcher.re);
  450. method = matcher.method;
  451. // If we have a match, add an operation with the method
  452. // associated with this matcher, and pass the regular
  453. // expression matches are arguments to the operation.
  454. if (selectorMatch) {
  455. operations.push({
  456. method: Ext.isString(matcher.method)
  457. // Turn a string method into a function by formatting the string with our selector matche expression
  458. // A new method is created for different match expressions, eg {id=='textfield-1024'}
  459. // Every expression may be different in different selectors.
  460. ? Ext.functionFactory('items', Ext.String.format.apply(Ext.String, [method].concat(selectorMatch.slice(1))))
  461. : matcher.method,
  462. args: selectorMatch.slice(1)
  463. });
  464. selector = selector.replace(selectorMatch[0], '');
  465. break; // Break on match
  466. }
  467. //&lt;debug&gt;
  468. // Exhausted all matches: It's an error
  469. if (i === (length - 1)) {
  470. Ext.Error.raise('Invalid ComponentQuery selector: &quot;' + arguments[0] + '&quot;');
  471. }
  472. //&lt;/debug&gt;
  473. }
  474. }
  475. // Now we are going to check for a mode change. This means a space
  476. // or a &gt; to determine if we are going to select all the children
  477. // of the currently matched items, or a ^ if we are going to use the
  478. // ownerCt axis as the candidate source.
  479. if (modeMatch[1]) { // Assignment, and test for truthiness!
  480. operations.push({
  481. mode: modeMatch[2]||modeMatch[1]
  482. });
  483. selector = selector.replace(modeMatch[0], '');
  484. }
  485. }
  486. // Now that we have all our operations in an array, we are going
  487. // to create a new Query using these operations.
  488. return new cq.Query({
  489. operations: operations
  490. });
  491. }
  492. });
  493. });</pre>
  494. </body>
  495. </html>