You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SelectorEngineSizzleGwt.java 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. /*
  2. * Copyright 2010 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.google.gwt.query.client.impl.research;
  17. import com.google.gwt.core.client.JavaScriptObject;
  18. import com.google.gwt.core.client.JsArray;
  19. import com.google.gwt.dom.client.Element;
  20. import com.google.gwt.dom.client.Node;
  21. import com.google.gwt.dom.client.NodeList;
  22. import com.google.gwt.query.client.GQUtils;
  23. import com.google.gwt.query.client.impl.SelectorEngineImpl;
  24. /**
  25. * Pure Javascript Selector Engine Gwt Implementation based on
  26. * Sizzle CSS Selector Engine v1.0.
  27. *
  28. * It has so many JSNI code, the idea is to make an entire implementation
  29. * using Java. Right now it performs worse than pure JSNI implementation
  30. *
  31. */
  32. public class SelectorEngineSizzleGwt extends SelectorEngineImpl {
  33. public static native boolean contains(Object a, Object b) /*-{
  34. var ret =
  35. document.compareDocumentPosition ?
  36. (a.compareDocumentPosition(b) & 16):
  37. a !== b && (a.contains ? a.contains(b) : true);
  38. return ret ? true : false;
  39. }-*/;
  40. public static native JavaScriptObject createExpr() /*-{
  41. var done = 0;
  42. $wnd.Expr = {
  43. order: [ "ID", "NAME", "TAG" ],
  44. match: {
  45. ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
  46. CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
  47. NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
  48. ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
  49. TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
  50. CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
  51. POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
  52. PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/,
  53. CHUNKER: /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g
  54. },
  55. leftMatch: {},
  56. attrMap: {
  57. "class": "className",
  58. "for": "htmlFor"
  59. },
  60. attrHandle: {
  61. href: function(elem){
  62. return elem.getAttribute("href");
  63. }
  64. },
  65. relative: {
  66. "+": function(checkSet, part){
  67. var isPartStr = typeof part === "string",
  68. isTag = isPartStr && !/\W/.test(part),
  69. isPartStrNotTag = isPartStr && !isTag;
  70. if ( isTag ) {
  71. part = part.toLowerCase();
  72. }
  73. for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
  74. if ( (elem = checkSet[i]) ) {
  75. while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
  76. checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
  77. elem || false :
  78. elem === part;
  79. }
  80. }
  81. if ( isPartStrNotTag ) {
  82. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)( part, checkSet, true );
  83. }
  84. },
  85. ">": function(checkSet, part){
  86. var isPartStr = typeof part === "string";
  87. if ( isPartStr && !/\W/.test(part) ) {
  88. part = part.toLowerCase();
  89. for ( var i = 0, l = checkSet.length; i < l; i++ ) {
  90. var elem = checkSet[i];
  91. if ( elem ) {
  92. var parent = elem.parentNode;
  93. checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
  94. }
  95. }
  96. } else {
  97. for ( var i = 0, l = checkSet.length; i < l; i++ ) {
  98. var elem = checkSet[i];
  99. if ( elem ) {
  100. checkSet[i] = isPartStr ?
  101. elem.parentNode :
  102. elem.parentNode === part;
  103. }
  104. }
  105. if ( isPartStr ) {
  106. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)( part, checkSet, true );
  107. }
  108. }
  109. },
  110. "": function(checkSet, part){
  111. var doneName = done++;
  112. if ( typeof part === "string" && !/\W/.test(part) ) {
  113. checkFn = $wnd.dirNodeCheck;
  114. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::dirNodeCheck(Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)("parentNode", part, doneName, checkSet);
  115. } else {
  116. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::dirCheck(Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)("parentNode", part, doneName, checkSet);
  117. }
  118. },
  119. "~": function(checkSet, part){
  120. var doneName = done++;
  121. if ( typeof part === "string" && !/\W/.test(part) ) {
  122. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::dirNodeCheck(Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)("previousSibling", part, doneName, checkSet);
  123. } else {
  124. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::dirCheck(Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)("previousSibling", part, doneName, checkSet);
  125. }
  126. }
  127. },
  128. find: {
  129. ID: function(match, context){
  130. if ( typeof context.getElementById !== "undefined") {
  131. var m = context.getElementById(match[1]);
  132. return m ? [m] : [];
  133. }
  134. },
  135. NAME: function(match, context){
  136. if ( typeof context.getElementsByName !== "undefined" ) {
  137. var ret = [], results = context.getElementsByName(match[1]);
  138. for ( var i = 0, l = results.length; i < l; i++ ) {
  139. if ( results[i].getAttribute("name") === match[1] ) {
  140. ret.push( results[i] );
  141. }
  142. }
  143. return ret.length === 0 ? null : ret;
  144. }
  145. },
  146. TAG: function(match, context){
  147. return context.getElementsByTagName(match[1]);
  148. }
  149. },
  150. preFilter: {
  151. CLASS: function(match, curLoop, inplace, result, not){
  152. match = " " + match[1].replace(/\\/g, "") + " ";
  153. for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
  154. if ( elem ) {
  155. if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {
  156. if ( !inplace ) {
  157. result.push( elem );
  158. }
  159. } else if ( inplace ) {
  160. curLoop[i] = false;
  161. }
  162. }
  163. }
  164. return false;
  165. },
  166. ID: function(match){
  167. return match[1].replace(/\\/g, "");
  168. },
  169. TAG: function(match, curLoop){
  170. return match[1].toLowerCase();
  171. },
  172. CHILD: function(match){
  173. if ( match[1] === "nth" ) {
  174. // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
  175. var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
  176. match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
  177. !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
  178. // calculate the numbers (first)n+(last) including if they are negative
  179. match[2] = (test[1] + (test[2] || 1)) - 0;
  180. match[3] = test[3] - 0;
  181. }
  182. match[0] = done++;
  183. return match;
  184. },
  185. ATTR: function(match, curLoop, inplace, result, not){
  186. var name = match[1].replace(/\\/g, "");
  187. if ($wnd.Expr.attrMap[name] ) {
  188. match[1] = $wnd.Expr.attrMap[name];
  189. }
  190. if ( match[2] === "~=" ) {
  191. match[4] = " " + match[4] + " ";
  192. }
  193. return match;
  194. },
  195. PSEUDO: function(match, curLoop, inplace, result, not){
  196. if ( match[1] === "not" ) {
  197. // If we're dealing with a complex expression, or a simple one
  198. if ( ( $wnd.Expr.match.CHUNKER.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
  199. match[3] = @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::select(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;Lcom/google/gwt/core/client/JsArray;Lcom/google/gwt/core/client/JsArray;)(match[3], null, null, curLoop);
  200. } else {
  201. var ret = @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)(match[3], curLoop, inplace, true ^ not);
  202. if ( !inplace ) {
  203. result.push.apply( result, ret );
  204. }
  205. return false;
  206. }
  207. } else if ( $wnd.Expr.match.POS.test( match[0] ) || $wnd.Expr.match.CHILD.test( match[0] ) ) {
  208. return true;
  209. }
  210. return match;
  211. },
  212. POS: function(match){
  213. match.unshift( true );
  214. return match;
  215. }
  216. },
  217. filters: {
  218. enabled: function(elem){
  219. return elem.disabled === false && elem.type !== "hidden";
  220. },
  221. disabled: function(elem){
  222. return elem.disabled === true;
  223. },
  224. checked: function(elem){
  225. return elem.checked === true;
  226. },
  227. selected: function(elem){
  228. // Accessing this property makes selected-by-default
  229. // options in Safari work properly
  230. elem.parentNode.selectedIndex;
  231. return elem.selected === true;
  232. },
  233. parent: function(elem){
  234. return !!elem.firstChild;
  235. },
  236. empty: function(elem){
  237. return !elem.firstChild;
  238. },
  239. has: function(elem, i, match){
  240. return !!@com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::select(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;Lcom/google/gwt/core/client/JsArray;Lcom/google/gwt/core/client/JsArray;)(match[3], elem, null, null).length;
  241. },
  242. header: function(elem){
  243. return /h\d/i.test( elem.nodeName );
  244. },
  245. text: function(elem){
  246. return "text" === elem.type;
  247. },
  248. radio: function(elem){
  249. return "radio" === elem.type;
  250. },
  251. checkbox: function(elem){
  252. return "checkbox" === elem.type;
  253. },
  254. file: function(elem){
  255. return "file" === elem.type;
  256. },
  257. password: function(elem){
  258. return "password" === elem.type;
  259. },
  260. submit: function(elem){
  261. return "submit" === elem.type;
  262. },
  263. image: function(elem){
  264. return "image" === elem.type;
  265. },
  266. reset: function(elem){
  267. return "reset" === elem.type;
  268. },
  269. button: function(elem){
  270. return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
  271. },
  272. input: function(elem){
  273. return /input|select|textarea|button/i.test(elem.nodeName);
  274. }
  275. },
  276. setFilters: {
  277. first: function(elem, i){
  278. return i === 0;
  279. },
  280. last: function(elem, i, match, array){
  281. return i === array.length - 1;
  282. },
  283. even: function(elem, i){
  284. return i % 2 === 0;
  285. },
  286. odd: function(elem, i){
  287. return i % 2 === 1;
  288. },
  289. lt: function(elem, i, match){
  290. return i < match[3] - 0;
  291. },
  292. gt: function(elem, i, match){
  293. return i > match[3] - 0;
  294. },
  295. nth: function(elem, i, match){
  296. return match[3] - 0 === i;
  297. },
  298. eq: function(elem, i, match){
  299. return match[3] - 0 === i;
  300. }
  301. },
  302. filter: {
  303. PSEUDO: function(elem, match, i, array){
  304. var name = match[1], filter = $wnd.Expr.filters[ name ];
  305. if ( filter ) {
  306. return filter( elem, i, match, array );
  307. } else if ( name === "contains" ) {
  308. return (elem.textContent || elem.innerText || @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::getText(Ljava/lang/Object;)([ elem ]) || "").indexOf(match[3]) >= 0;
  309. } else if ( name === "not" ) {
  310. var not = match[3];
  311. for ( var i = 0, l = not.length; i < l; i++ ) {
  312. if ( not[i] === elem ) {
  313. return false;
  314. }
  315. }
  316. return true;
  317. } else {
  318. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::error(Ljava/lang/String;)("Syntax error, unrecognized expression: " + name);
  319. }
  320. },
  321. CHILD: function(elem, match){
  322. var type = match[1], node = elem;
  323. switch (type) {
  324. case 'only':
  325. case 'first':
  326. while ( (node = node.previousSibling) ) {
  327. if ( node.nodeType === 1 ) {
  328. return false;
  329. }
  330. }
  331. if ( type === "first" ) {
  332. return true;
  333. }
  334. node = elem;
  335. case 'last':
  336. while ( (node = node.nextSibling) ) {
  337. if ( node.nodeType === 1 ) {
  338. return false;
  339. }
  340. }
  341. return true;
  342. case 'nth':
  343. var first = match[2], last = match[3];
  344. if ( first === 1 && last === 0 ) {
  345. return true;
  346. }
  347. var doneName = match[0],
  348. parent = elem.parentNode;
  349. if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
  350. var count = 0;
  351. for ( node = parent.firstChild; node; node = node.nextSibling ) {
  352. if ( node.nodeType === 1 ) {
  353. node.nodeIndex = ++count;
  354. }
  355. }
  356. parent.sizcache = doneName;
  357. }
  358. var diff = elem.nodeIndex - last;
  359. if ( first === 0 ) {
  360. return diff === 0;
  361. } else {
  362. return ( diff % first === 0 && diff / first >= 0 );
  363. }
  364. }
  365. },
  366. ID: function(elem, match){
  367. return elem.nodeType === 1 && elem.getAttribute("id") === match;
  368. },
  369. TAG: function(elem, match){
  370. return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
  371. },
  372. CLASS: function(elem, match){
  373. return (" " + (elem.className || elem.getAttribute("class")) + " ")
  374. .indexOf( match ) > -1;
  375. },
  376. ATTR: function(elem, match){
  377. var name = match[1],
  378. result = $wnd.Expr.attrHandle[ name ] ?
  379. $wnd.Expr.attrHandle[ name ]( elem ) :
  380. elem[ name ] != null ?
  381. elem[ name ] :
  382. elem.getAttribute( name ),
  383. value = result + "",
  384. type = match[2],
  385. check = match[4];
  386. return result == null ?
  387. type === "!=" :
  388. type === "=" ?
  389. value === check :
  390. type === "*=" ?
  391. value.indexOf(check) >= 0 :
  392. type === "~=" ?
  393. (" " + value + " ").indexOf(check) >= 0 :
  394. !check ?
  395. value && result !== false :
  396. type === "!=" ?
  397. value !== check :
  398. type === "^=" ?
  399. value.indexOf(check) === 0 :
  400. type === "$=" ?
  401. value.substr(value.length - check.length) === check :
  402. type === "|=" ?
  403. value === check || value.substr(0, check.length + 1) === check + "-" :
  404. false;
  405. },
  406. POS: function(elem, match, i, array){
  407. var name = match[2], filter = $wnd.Expr.setFilters[ name ];
  408. if ( filter ) {
  409. return filter( elem, i, match, array );
  410. }
  411. }
  412. }
  413. };
  414. for ( var type in $wnd.Expr.match ) {
  415. $wnd.Expr.match[ type ] = new RegExp( $wnd.Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
  416. $wnd.Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + $wnd.Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){
  417. return "\\" + (num - 0 + 1);
  418. }));
  419. }
  420. return $wnd.Expr;
  421. }-*/;
  422. public static native void dirCheck(String dir, Object cur, int doneName, Object checkSet) /*-{
  423. for ( var i = 0, l = checkSet.length; i < l; i++ ) {
  424. var elem = checkSet[i];
  425. if ( elem ) {
  426. elem = elem[dir];
  427. var match = false;
  428. while ( elem ) {
  429. if ( elem.sizcache === doneName ) {
  430. match = checkSet[elem.sizset];
  431. break;
  432. }
  433. if ( elem.nodeType === 1 ) {
  434. elem.sizcache = doneName;
  435. elem.sizset = i;
  436. if ( typeof cur !== "string" ) {
  437. if ( elem === cur ) {
  438. match = true;
  439. break;
  440. }
  441. } else if ( @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)( cur, [elem], false ).length > 0 ) {
  442. match = elem;
  443. break;
  444. }
  445. }
  446. elem = elem[dir];
  447. }
  448. checkSet[i] = match;
  449. }
  450. }
  451. }-*/;
  452. public static native void dirNodeCheck(String dir, Object cur, int doneName, Object checkSet) /*-{
  453. for ( var i = 0, l = checkSet.length; i < l; i++ ) {
  454. var elem = checkSet[i];
  455. if ( elem ) {
  456. elem = elem[dir];
  457. var match = false;
  458. while ( elem ) {
  459. if ( elem.sizcache === doneName ) {
  460. match = checkSet[elem.sizset];
  461. break;
  462. }
  463. if ( elem.nodeType === 1){
  464. elem.sizcache = doneName;
  465. elem.sizset = i;
  466. }
  467. if ( elem.nodeName.toLowerCase() === cur ) {
  468. match = elem;
  469. break;
  470. }
  471. elem = elem[dir];
  472. }
  473. checkSet[i] = match;
  474. }
  475. }
  476. }-*/;
  477. public static void error(String msg) {
  478. throw new IllegalArgumentException("Syntax error, unrecognized expression: " + msg);
  479. }
  480. public static native JsArray<Node> filter(String expr, JsArray<Node> set, boolean inplace, Object not) /*-{
  481. var old = expr, result = [], curLoop = set, match, anyFound;
  482. while ( expr && set.length ) {
  483. for ( var type in $wnd.Expr.filter ) {
  484. if ( (match = $wnd.Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
  485. var filter = $wnd.Expr.filter[ type ], found, item, left = match[1];
  486. anyFound = false;
  487. match.splice(1,1);
  488. if ( left.substr( left.length - 1 ) === "\\" ) {
  489. continue;
  490. }
  491. if ( curLoop === result ) {
  492. result = [];
  493. }
  494. if ( $wnd.Expr.preFilter[ type ] ) {
  495. match = $wnd.Expr.preFilter[ type ]( match, curLoop, inplace, result, not);
  496. if ( !match ) {
  497. anyFound = found = true;
  498. } else if ( match === true ) {
  499. continue;
  500. }
  501. }
  502. if ( match ) {
  503. for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
  504. if ( item ) {
  505. found = filter( item, match, i, curLoop );
  506. var pass = not ^ !!found;
  507. if ( inplace && found != null ) {
  508. if ( pass ) {
  509. anyFound = true;
  510. } else {
  511. curLoop[i] = false;
  512. }
  513. } else if ( pass ) {
  514. result.push( item );
  515. anyFound = true;
  516. }
  517. }
  518. }
  519. }
  520. if ( found !== undefined ) {
  521. if ( !inplace ) {
  522. curLoop = result;
  523. }
  524. expr = expr.replace( $wnd.Expr.match[ type ], "" );
  525. if ( !anyFound ) {
  526. return [];
  527. }
  528. break;
  529. }
  530. }
  531. }
  532. // Improper expression
  533. if ( expr === old ) {
  534. if ( anyFound == null ) {
  535. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::error(Ljava/lang/String;)(expr);
  536. } else {
  537. break;
  538. }
  539. }
  540. old = expr;
  541. }
  542. return curLoop;
  543. }-*/;
  544. public static native JavaScriptObject find(String expr, Node context) /*-{
  545. var set, match;
  546. if ( !expr ) {
  547. return [];
  548. }
  549. for ( var i = 0, l = $wnd.Expr.order.length; i < l; i++ ) {
  550. var type = $wnd.Expr.order[i], match;
  551. if ( (match = $wnd.Expr.leftMatch[ type ].exec( expr )) ) {
  552. var left = match[1];
  553. match.splice(1,1);
  554. if ( left.substr( left.length - 1 ) !== "\\" ) {
  555. match[1] = (match[1] || "").replace(/\\/g, "");
  556. set = $wnd.Expr.find[ type ]( match, context);
  557. if ( set != null ) {
  558. expr = expr.replace( $wnd.Expr.match[ type ], "" );
  559. break;
  560. }
  561. }
  562. }
  563. }
  564. if ( !set ) {
  565. set = context.getElementsByTagName("*");
  566. }
  567. return {set: set, expr: expr};
  568. }-*/;
  569. public static native String getText(Object elems) /*-{
  570. var ret = "", elem;
  571. for ( var i = 0; elems[i]; i++ ) {
  572. elem = elems[i];
  573. // Get the text from text nodes and CDATA nodes
  574. if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
  575. ret += elem.nodeValue;
  576. // Traverse everything else, except comment nodes
  577. } else if ( elem.nodeType !== 8 ) {
  578. ret += @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::getText(Ljava/lang/Object;)(elem.childNodes);
  579. }
  580. }
  581. return ret;
  582. }-*/;
  583. public static native JsArray<Node> makeArray(NodeList<Node> array, JsArray<Node> results) /*-{
  584. var ret = results || [];
  585. if ( Object.prototype.toString.call(array) === "[object Array]" ) {
  586. Array.prototype.push.apply( ret, array );
  587. } else {
  588. if ( typeof array.length === "number" ) {
  589. for ( var i = 0, l = array.length; i < l; i++ ) {
  590. ret.push( array[i] );
  591. }
  592. } else {
  593. for ( var i = 0; array[i]; i++ ) {
  594. ret.push( array[i] );
  595. }
  596. }
  597. }
  598. return ret;
  599. }-*/;
  600. public static native JsArray<Element> posProcess(String selector, Node context) /*-{
  601. var tmpSet = [], later = "", match, root = context.nodeType ? [context] : context;
  602. // Position selectors must be done after the filter
  603. // And so must :not(positional) so we move all PSEUDOs to the end
  604. while ( (match = $wnd.Expr.match.PSEUDO.exec( selector )) ) {
  605. later += match[0];
  606. selector = selector.replace($wnd.Expr.match.PSEUDO, "" );
  607. }
  608. selector = $wnd.Expr.relative[selector] ? selector + "*" : selector;
  609. for ( var i = 0, l = root.length; i < l; i++ ) {
  610. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::select(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;Lcom/google/gwt/core/client/JsArray;Lcom/google/gwt/core/client/JsArray;)(selector, root[i], tmpSet, null);
  611. }
  612. return @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)( later, tmpSet, false );
  613. }-*/;
  614. private static native JsArray<Element> select(String selector, Node context, JsArray<Element> results, JsArray<Element> seed) /*-{
  615. results = results || [];
  616. var origContext = context = context || document;
  617. var parts = [], m, set, checkSet, extra, prune = true, soFar = selector;
  618. // Reset the position of the chunker regexp (start from head)
  619. while ( ($wnd.Expr.match.CHUNKER.exec(""), m = $wnd.Expr.match.CHUNKER.exec(soFar)) !== null ) {
  620. soFar = m[3];
  621. parts.push( m[1] );
  622. if ( m[2] ) {
  623. extra = m[3];
  624. break;
  625. }
  626. }
  627. if ( parts.length > 1 && $wnd.Expr.match.POS.exec( selector ) ) {
  628. if ( parts.length === 2 && $wnd.Expr.relative[ parts[0] ] ) {
  629. set = @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::posProcess(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;)(parts[0] + parts[1], context);
  630. } else {
  631. set = $wnd.Expr.relative[ parts[0] ] ?
  632. [ context ] :
  633. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::select(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;Lcom/google/gwt/core/client/JsArray;Lcom/google/gwt/core/client/JsArray;)(parts.shift(), context, null, null);
  634. while ( parts.length ) {
  635. selector = parts.shift();
  636. if ( $wnd.Expr.relative[ selector ] ) {
  637. selector += parts.shift();
  638. }
  639. set = @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::posProcess(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;)(selector, set);
  640. }
  641. }
  642. } else {
  643. // Take a shortcut and set the context if the root selector is an ID
  644. // (but not if it'll be faster if the inner selector is an ID)
  645. if ( !seed && parts.length > 1 && context.nodeType === 9 &&
  646. $wnd.Expr.match.ID.test(parts[0]) && !$wnd.Expr.match.ID.test(parts[parts.length - 1]) ) {
  647. var ret = @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::find(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;)( parts.shift(), context);
  648. context = ret.expr ? @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)( ret.expr, ret.set, false )[0] : ret.set[0];
  649. }
  650. if ( context ) {
  651. var ret = seed ?
  652. { expr: parts.pop(), set: @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::makeArray(Lcom/google/gwt/dom/client/NodeList;Lcom/google/gwt/core/client/JsArray;)(seed, null) } :
  653. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::find(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;)( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context);
  654. set = ret.expr ? @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)( ret.expr, ret.set, false ) : ret.set;
  655. if ( parts.length > 0 ) {
  656. checkSet = @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::makeArray(Lcom/google/gwt/dom/client/NodeList;Lcom/google/gwt/core/client/JsArray;)(set, null);
  657. } else {
  658. prune = false;
  659. }
  660. while ( parts.length ) {
  661. var cur = parts.pop(), pop = cur;
  662. if ( !$wnd.Expr.relative[ cur ] ) {
  663. cur = "";
  664. } else {
  665. pop = parts.pop();
  666. }
  667. if ( pop == null ) {
  668. pop = context;
  669. }
  670. $wnd.Expr.relative[ cur ]( checkSet, pop);
  671. }
  672. } else {
  673. checkSet = parts = [];
  674. }
  675. }
  676. if ( !checkSet ) {
  677. checkSet = set;
  678. }
  679. if ( !checkSet ) {
  680. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::error(Ljava/lang/String;)(cur || selector);
  681. }
  682. if ( Object.prototype.toString.call(checkSet) === "[object Array]" ) {
  683. if ( !prune ) {
  684. results.push.apply( results, checkSet );
  685. } else if ( context && context.nodeType === 1 ) {
  686. for ( var i = 0; checkSet[i] != null; i++ ) {
  687. if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::contains(Ljava/lang/Object;Ljava/lang/Object;)(context, checkSet[i])) ) {
  688. results.push( set[i] );
  689. }
  690. }
  691. } else {
  692. for ( var i = 0; checkSet[i] != null; i++ ) {
  693. if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
  694. results.push( set[i] );
  695. }
  696. }
  697. }
  698. } else {
  699. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::makeArray(Lcom/google/gwt/dom/client/NodeList;Lcom/google/gwt/core/client/JsArray;)(checkSet, results);
  700. }
  701. if ( extra ) {
  702. @com.google.gwt.query.client.impl.research.SelectorEngineSizzleGwt::select(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;Lcom/google/gwt/core/client/JsArray;Lcom/google/gwt/core/client/JsArray;)(extra, origContext, results, seed);
  703. }
  704. return results;
  705. }-*/;
  706. public SelectorEngineSizzleGwt() {
  707. createExpr();
  708. }
  709. public NodeList<Element> select(String selector, Node context) {
  710. JsArray<Element> results = JavaScriptObject.createArray().cast();
  711. return GQUtils.unique(select(selector, context, results, null)).cast();
  712. }
  713. }