Changeset 7457
- Timestamp:
- 02/27/07 11:30:40 (23 months ago)
- Files:
-
- 1 modified
-
trunk/src/query.js (modified) (27 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/query.js
r7447 r7457 8 8 var h = d.render.html; 9 9 10 //////////////////////////////////////////////////////////////////////// 11 // Utility code 12 //////////////////////////////////////////////////////////////////////// 13 10 14 var _getIndexes = function(q){ 11 15 return [ q.indexOf("#"), q.indexOf("."), q.indexOf("["), q.indexOf(":") ]; 16 } 17 18 var _lowestFromIndex = function(query, index){ 19 // spammy and verbose, but fast 20 var ql = query.length; 21 var i = _getIndexes(query); 22 var end = ql; 23 for(var x=index; x<i.length; x++){ 24 if(i[x] >= 0){ 25 if(i[x] < end){ 26 end = i[x]; 27 } 28 } 29 } 30 return (end < 0) ? ql : end; 31 } 32 33 var getIdEnd = function(query){ 34 return _lowestFromIndex(query, 1); 12 35 } 13 36 … … 21 44 } 22 45 23 var getIdEnd = function(query){24 return _lowestFromIndex(query, 1);25 }26 27 46 //////////////////////////////////////////////////////////////////////// 28 47 // XPath query code 29 48 //////////////////////////////////////////////////////////////////////// 49 50 var xPathAttrs = [ 51 // FIXME: need to re-order in order of likelyness to be used in matches 52 { 53 key: "|=", 54 match: function(attr, value){ 55 return "[contains(concat(' ',@"+attr+",' '), ' "+ value +"-')]"; 56 } 57 }, 58 { 59 key: "^=", 60 match: function(attr, value){ 61 return "[starts-with(@"+attr+", '"+ value +"')]"; 62 } 63 }, 64 { 65 key: "*=", 66 match: function(attr, value){ 67 return "[contains(@"+attr+", '"+ value +"')]"; 68 } 69 }, 70 { 71 key: "$=", 72 match: function(attr, value){ 73 return "[substring(@"+attr+", string-length(@"+attr+")-"+(value.length-1)+")='"+value+"']"; 74 } 75 }, 76 { 77 key: "!=", 78 match: function(attr, value){ 79 return "[not(@"+attr+"='"+ value +"')]"; 80 } 81 }, 82 // NOTE: the "=" match MUST come last! 83 { 84 key: "=", 85 match: function(attr, value){ 86 return "[@"+attr+"='"+ value +"']"; 87 } 88 } 89 ]; 90 91 var handleAttrs = function( attrList, 92 query, 93 getDefault, 94 handleMatch){ 95 var matcher; 96 var i = _getIndexes(query); 97 if(i[2] >= 0){ 98 var lBktIdx = query.indexOf("]", i[2]); 99 var condition = query.substring(i[2]+1, lBktIdx); 100 while(condition && condition.length){ 101 if(condition.charAt(0) == "@"){ 102 condition = condition.slice(1); 103 } 104 105 matcher = null; 106 // http://www.w3.org/TR/css3-selectors/#attribute-selectors 107 for(var x=0; x<attrList.length; x++){ 108 var ta = attrList[x]; 109 var tci = condition.indexOf(ta.key); 110 if(tci >= 0){ 111 var attr = condition.substring(0, tci); 112 var value = condition.substring(tci+ta.key.length); 113 if( (value.charAt(0) == "\"")|| 114 (value.charAt(0) == "\'")){ 115 value = value.substring(1, value.length-1); 116 } 117 matcher = ta.match(attr, value); 118 break; 119 } 120 } 121 if((!matcher)&&(condition.length)){ 122 matcher = getDefault(condition); 123 } 124 if(matcher){ 125 handleMatch(matcher); 126 // ff = agree(ff, matcher); 127 } 128 129 condition = null; 130 var nbktIdx = query.indexOf("[", lBktIdx); 131 if(0 <= nbktIdx){ 132 lBktIdx = query.indexOf("]", nbktIdx); 133 if(0 <= lBktIdx){ 134 condition = query.substring(nbktIdx+1, lBktIdx); 135 } 136 } 137 } 138 } 139 } 30 140 31 141 var buildPath = function(query){ … … 64 174 } 65 175 66 // FIXME: need to implement attribute and pseudo-class checks!! 67 176 handleAttrs(xPathAttrs, tqp, 177 function(condition){ 178 return "[@"+condition+"]"; 179 }, 180 function(matcher){ 181 xpath += matcher; 182 } 183 ); 184 185 // FIXME: need to implement pseudo-class checks!! 68 186 }; 187 // dojo.debug(xpath); 69 188 return xpath; 70 189 }; … … 76 195 } 77 196 78 var doc = d ojo.doc();79 var parent = d ojo.body(); // FIXME197 var doc = d.doc(); 198 var parent = d.body(); // FIXME 80 199 // FIXME: don't need to memoize. The closure scope handles it for us. 81 200 var xpath = buildPath(path); … … 188 307 } 189 308 190 var _lowestFromIndex = function(query, index){191 // spammy and verbose, but fast192 var ql = query.length;193 var i = _getIndexes(query);194 var end = ql;195 for(var x=index; x<i.length; x++){196 if(i[x] >= 0){197 if(i[x] < end){198 end = i[x];199 }200 }201 }202 return (end < 0) ? ql : end;203 }204 205 309 var getTagNameEnd = function(query){ 206 310 var i = _getIndexes(query); … … 363 467 { 364 468 key: "|=", 365 getMatcher: function(attr, value){469 match: function(attr, value){ 366 470 // E[hreflang|="en"] 367 471 // an E element whose "hreflang" attribute has a … … 380 484 { 381 485 key: "^=", 382 getMatcher: function(attr, value){486 match: function(attr, value){ 383 487 return function(elem){ 384 488 return (_getAttr(elem, attr).indexOf(value)==0); … … 388 492 { 389 493 key: "*=", 390 getMatcher: function(attr, value){494 match: function(attr, value){ 391 495 return function(elem){ 392 496 return (_getAttr(elem, attr).indexOf(value)>=0); … … 396 500 { 397 501 key: "$=", 398 getMatcher: function(attr, value){502 match: function(attr, value){ 399 503 return function(elem){ 400 504 var ea = _getAttr(elem, attr); … … 405 509 { 406 510 key: "!=", 407 getMatcher: function(attr, value){511 match: function(attr, value){ 408 512 return function(elem){ 409 513 return (_getAttr(elem, attr) != value); … … 414 518 { 415 519 key: "=", 416 getMatcher: function(attr, value){520 match: function(attr, value){ 417 521 return function(elem){ 418 522 return (_getAttr(elem, attr) == value); … … 425 529 { 426 530 key: "first-child", 427 getMatcher: function(name, condition){531 match: function(name, condition){ 428 532 return function(elem){ 429 533 if(elem.nodeType != 1){ return false; } … … 439 543 { 440 544 key: "last-child", 441 getMatcher: function(name, condition){545 match: function(name, condition){ 442 546 return function(elem){ 443 547 if(elem.nodeType != 1){ return false; } … … 453 557 { 454 558 key: "empty", 455 getMatcher: function(name, condition){559 match: function(name, condition){ 456 560 return function(elem){ 457 561 // DomQuery and jQuery get this wrong, oddly enough. … … 471 575 { 472 576 key: "contains", 473 getMatcher: function(name, condition){577 match: function(name, condition){ 474 578 return function(elem){ 475 579 // FIXME: I dislike this version of "contains", as … … 484 588 { 485 589 key: "not", 486 getMatcher: function(name, condition){590 match: function(name, condition){ 487 591 var ntf = getFilterFunc(condition); 488 592 return function(elem){ … … 498 602 { 499 603 key: "nth-child", 500 getMatcher: function(name, condition){ 604 match: function(name, condition){ 605 var pi = parseInt; 501 606 if(condition == "odd"){ 502 607 return function(elem){ … … 511 616 } 512 617 }else if(condition.indexOf("0n+") == 0){ 513 var ncount = p arseInt(condition.substr(3));618 var ncount = pi(condition.substr(3)); 514 619 return function(elem){ 515 620 return (elem.parentNode.childNodes[ncount-1] === elem); … … 518 623 (condition.length > 3) ){ 519 624 var tparts = condition.split("n+", 2); 520 var pred = p arseInt(tparts[0]);521 var idx = p arseInt(tparts[1]);625 var pred = pi(tparts[0]); 626 var idx = pi(tparts[1]); 522 627 return function(elem){ 523 628 return ((getNodeIndex(elem) % pred) == idx); 524 629 } 525 630 }else if(condition.indexOf("n") == -1){ 526 var ncount = p arseInt(condition);631 var ncount = pi(condition); 527 632 return function(elem){ 528 633 // removeChaffNodes(elem.parentNode); … … 573 678 }); 574 679 575 /*576 var spcCC = " ".charCodeAt(0);577 var cnl = className.length;578 ff = agree(ff, function(elem){579 var ecn = elem.className;580 var ecnl = ecn.length;581 var cni = ecn.indexOf(className);582 if(cni == 0){583 // if it's at the front...584 return (585 // and it's the whole thing...586 (ecnl == cnl) ||587 // or it's a full match588 (ecn.charCodeAt(cnl) == spcCC)589 );590 }else if(ecnl == (cni+cnl)){591 // or it's at the back...592 return (593 // and it's the whole thing...594 (ecnl == cnl) ||595 // or it's a full match596 (ecn.charCodeAt(cni-1) == spcCC)597 );598 }else{599 return (600 (ecn.charCodeAt(cni-1) == spcCC) &&601 (ecn.charCodeAt(cni+cnl) == spcCC)602 );603 }604 });605 */606 607 680 } 608 681 // [ "#", ".", "[", ":" ]; 682 var defaultGetter = (h.ie) ? 683 function(cond){ 684 return function(elem){ 685 return elem[cond]; 686 } 687 } : function(cond){ 688 return function(elem){ 689 return elem.hasAttribute(cond); 690 } 691 }; 692 handleAttrs(attrs, query, defaultGetter, 693 function(tmatcher){ 694 ff = agree(ff, tmatcher); 695 } 696 ); 697 609 698 var matcher; 610 if(i[2] >= 0){611 // FIXME: need to implement chained attribute searches!!612 // var lBktIdx = query.lastIndexOf("]");613 var lBktIdx = query.indexOf("]", i[2]);614 var condition = query.substring(i[2]+1, lBktIdx);615 while(condition && condition.length){616 if(condition.charAt(0) == "@"){617 condition = condition.slice(1);618 }619 620 matcher = null;621 // http://www.w3.org/TR/css3-selectors/#attribute-selectors622 for(var x=0; x<attrs.length; x++){623 var ta = attrs[x];624 var tci = condition.indexOf(ta.key);625 if(tci >= 0){626 var attr = condition.substring(0, tci);627 var value = condition.substring(tci+ta.key.length);628 if( (value.charAt(0) == "\"")||629 (value.charAt(0) == "\'")){630 value = value.substring(1, value.length-1);631 }632 matcher = ta.getMatcher(attr, value);633 break;634 }635 }636 if((!matcher)&&(condition.length)){637 matcher = (function(cond){638 if(dojo.render.html.ie){639 return function(elem){640 return elem[cond];641 }642 }else{643 return function(elem){644 return elem.hasAttribute(cond);645 }646 }647 })(condition);648 }649 if(matcher){650 ff = agree(ff, matcher);651 }652 653 condition = null;654 var nbktIdx = query.indexOf("[", lBktIdx);655 if(0 <= nbktIdx){656 lBktIdx = query.indexOf("]", nbktIdx);657 if(0 <= lBktIdx){658 condition = query.substring(nbktIdx+1, lBktIdx);659 }660 }661 }662 }663 699 if(i[3]>= 0){ 664 700 // NOTE: we count on the pseudo name being at the end … … 682 718 var ta = pseudos[x]; 683 719 if(ta.key == pseudoName){ 684 matcher = ta. getMatcher(pseudoName, condition);720 matcher = ta.match(pseudoName, condition); 685 721 break; 686 722 } … … 894 930 // potentially optimized variant or if we should try something 895 931 // new. 896 (document["evaluate"] && ! dojo.render.html.safari) ?932 (document["evaluate"] && !h.safari) ? 897 933 function(query){ 898 934 // has xpath support that's faster than DOM 899 935 var qparts = query.split(" "); 936 // can we handle it? 900 937 if( (document["evaluate"])&& 901 938 (query.indexOf(":") == -1)&& 902 (query.indexOf("[") == -1) ){ 939 ( 940 (true) // || 941 // (query.indexOf("[") == -1) || 942 // (query.indexOf("=") == -1) 943 ) 944 ){ 945 // dojo.debug(query); 946 // should we handle it? 947 var gtIdx = query.indexOf(">") 903 948 // kind of a lame heuristic, but it works 904 var gtIdx = query.indexOf(">")905 949 if( 906 950 // a "div div div" style query … … 908 952 // or something else with moderate complexity. kinda janky 909 953 (qparts.length > 3)|| 954 (query.indexOf("[")>=0)|| 910 955 // or if it's a ".thinger" query 911 956 ((1 == qparts.length)&&(0 <= query.indexOf("."))) … … 915 960 return getXPathFunc(query); 916 961 } 962 // return getXPathFunc(query); 917 963 } 918 964 … … 964 1010 var _zipIdx = 0; 965 1011 var _zip = function(arr){ 966 var ret = new d ojo.NodeList();1012 var ret = new d.NodeList(); 967 1013 if(!arr){ return ret; } 968 1014 ret.push(arr[0]); … … 985 1031 // NOTE: ignores xpath-ish queries for now 986 1032 if(typeof query != "string"){ 987 return new d ojo.NodeList(query);1033 return new d.NodeList(query); 988 1034 } 989 1035 … … 992 1038 } 993 1039 1040 /* 1041 // exposing these was a mistake 994 1042 d.query.attrs = attrs; 995 1043 d.query.pseudos = pseudos; 1044 */ 996 1045 997 1046 d._filterQueryResult = function(nodeList, simpleFilter){ 998 var tnl = new d ojo.NodeList();1047 var tnl = new d.NodeList(); 999 1048 var ff = (simpleFilter) ? getFilterFunc(simpleFilter) : function(){ return true; }; 1000 1049 // dojo.debug(ff);