[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/2in3/2.9.0/build/yui2-selector/ -> yui2-selector-debug.js (source)

   1  YUI.add('yui2-selector', function(Y) {
   2      var YAHOO    = Y.YUI2;
   3      /*
   4  Copyright (c) 2011, Yahoo! Inc. All rights reserved.
   5  Code licensed under the BSD License:
   6  http://developer.yahoo.com/yui/license.html
   7  version: 2.9.0
   8  */
   9  var Y = YAHOO,
  10      Y_DOM = YAHOO.util.Dom, 
  11      EMPTY_ARRAY = [],
  12      Y_UA = Y.env.ua,
  13      Y_Lang = Y.lang,
  14      Y_DOC = document,
  15      Y_DOCUMENT_ELEMENT = Y_DOC.documentElement,
  16  
  17      Y_DOM_inDoc = Y_DOM.inDocument, 
  18      Y_mix = Y_Lang.augmentObject,
  19      Y_guid = Y_DOM.generateId,
  20  
  21      Y_getDoc = function(element) {
  22          var doc = Y_DOC;
  23          if (element) {
  24              doc = (element.nodeType === 9) ? element : // element === document
  25                  element.ownerDocument || // element === DOM node
  26                  element.document || // element === window
  27                  Y_DOC; // default
  28          }
  29  
  30          return doc;
  31      },
  32      
  33      Y_Array = function(o, startIdx) {
  34          var l, a, start = startIdx || 0;
  35  
  36          // IE errors when trying to slice HTMLElement collections
  37          try {
  38              return Array.prototype.slice.call(o, start);
  39          } catch (e) {
  40              a = [];
  41              l = o.length;
  42              for (; start < l; start++) {
  43                  a.push(o[start]);
  44              }
  45              return a;
  46          }
  47      },
  48  
  49      Y_DOM_allById = function(id, root) {
  50          root = root || Y_DOC;
  51          var nodes = [],
  52              ret = [],
  53              i,
  54              node;
  55  
  56          if (root.querySelectorAll) {
  57              ret = root.querySelectorAll('[id="' + id + '"]');
  58          } else if (root.all) {
  59              nodes = root.all(id);
  60  
  61              if (nodes) {
  62                  // root.all may return HTMLElement or HTMLCollection.
  63                  // some elements are also HTMLCollection (FORM, SELECT).
  64                  if (nodes.nodeName) {
  65                      if (nodes.id === id) { // avoid false positive on name
  66                          ret.push(nodes);
  67                          nodes = EMPTY_ARRAY; // done, no need to filter
  68                      } else { //  prep for filtering
  69                          nodes = [nodes];
  70                      }
  71                  }
  72  
  73                  if (nodes.length) {
  74                      // filter out matches on node.name
  75                      // and element.id as reference to element with id === 'id'
  76                      for (i = 0; node = nodes[i++];) {
  77                          if (node.id === id  || 
  78                                  (node.attributes && node.attributes.id &&
  79                                  node.attributes.id.value === id)) { 
  80                              ret.push(node);
  81                          }
  82                      }
  83                  }
  84              }
  85          } else {
  86              ret = [Y_getDoc(root).getElementById(id)];
  87          }
  88  
  89          return ret;
  90      };
  91  
  92  /**
  93   * The selector-native module provides support for native querySelector
  94   * @module dom
  95   * @submodule selector-native
  96   * @for Selector
  97   */
  98  
  99  /**
 100   * Provides support for using CSS selectors to query the DOM 
 101   * @class Selector 
 102   * @static
 103   * @for Selector
 104   */
 105  
 106  var COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
 107      OWNER_DOCUMENT = 'ownerDocument',
 108  
 109  Selector = {
 110      _foundCache: [],
 111  
 112      useNative: true,
 113  
 114      _compare: ('sourceIndex' in Y_DOCUMENT_ELEMENT) ?
 115          function(nodeA, nodeB) {
 116              var a = nodeA.sourceIndex,
 117                  b = nodeB.sourceIndex;
 118  
 119              if (a === b) {
 120                  return 0;
 121              } else if (a > b) {
 122                  return 1;
 123              }
 124  
 125              return -1;
 126  
 127          } : (Y_DOCUMENT_ELEMENT[COMPARE_DOCUMENT_POSITION] ?
 128          function(nodeA, nodeB) {
 129              if (nodeA[COMPARE_DOCUMENT_POSITION](nodeB) & 4) {
 130                  return -1;
 131              } else {
 132                  return 1;
 133              }
 134          } :
 135          function(nodeA, nodeB) {
 136              var rangeA, rangeB, compare;
 137              if (nodeA && nodeB) {
 138                  rangeA = nodeA[OWNER_DOCUMENT].createRange();
 139                  rangeA.setStart(nodeA, 0);
 140                  rangeB = nodeB[OWNER_DOCUMENT].createRange();
 141                  rangeB.setStart(nodeB, 0);
 142                  compare = rangeA.compareBoundaryPoints(1, rangeB); // 1 === Range.START_TO_END
 143              }
 144  
 145              return compare;
 146          
 147      }),
 148  
 149      _sort: function(nodes) {
 150          if (nodes) {
 151              nodes = Y_Array(nodes, 0, true);
 152              if (nodes.sort) {
 153                  nodes.sort(Selector._compare);
 154              }
 155          }
 156  
 157          return nodes;
 158      },
 159  
 160      _deDupe: function(nodes) {
 161          var ret = [],
 162              i, node;
 163  
 164          for (i = 0; (node = nodes[i++]);) {
 165              if (!node._found) {
 166                  ret[ret.length] = node;
 167                  node._found = true;
 168              }
 169          }
 170  
 171          for (i = 0; (node = ret[i++]);) {
 172              node._found = null;
 173              node.removeAttribute('_found');
 174          }
 175  
 176          return ret;
 177      },
 178  
 179      /**
 180       * Retrieves a set of nodes based on a given CSS selector. 
 181       * @method query
 182       *
 183       * @param {string} selector The CSS Selector to test the node against.
 184       * @param {HTMLElement} root optional An HTMLElement to start the query from. Defaults to Y.config.doc
 185       * @param {Boolean} firstOnly optional Whether or not to return only the first match.
 186       * @return {Array} An array of nodes that match the given selector.
 187       * @static
 188       */
 189      query: function(selector, root, firstOnly, skipNative) {
 190          if (root && typeof root == 'string') {
 191              root = Y_DOM.get(root);
 192              if (!root) {
 193                  return (firstOnly) ? null : [];
 194              }
 195          } else {
 196              root = root || Y_DOC;
 197          }
 198  
 199          var ret = [],
 200              useNative = (Selector.useNative && Y_DOC.querySelector && !skipNative),
 201              queries = [[selector, root]],
 202              query,
 203              result,
 204              i,
 205              fn = (useNative) ? Selector._nativeQuery : Selector._bruteQuery;
 206  
 207          if (selector && fn) {
 208              // split group into seperate queries
 209              if (!skipNative && // already done if skipping
 210                      (!useNative || root.tagName)) { // split native when element scoping is needed
 211                  queries = Selector._splitQueries(selector, root);
 212              }
 213  
 214              for (i = 0; (query = queries[i++]);) {
 215                  result = fn(query[0], query[1], firstOnly);
 216                  if (!firstOnly) { // coerce DOM Collection to Array
 217                      result = Y_Array(result, 0, true);
 218                  }
 219                  if (result) {
 220                      ret = ret.concat(result);
 221                  }
 222              }
 223  
 224              if (queries.length > 1) { // remove dupes and sort by doc order 
 225                  ret = Selector._sort(Selector._deDupe(ret));
 226              }
 227          }
 228  
 229          YAHOO.log('query: ' + selector + ' returning: ' + ret.length, 'info', 'Selector');
 230          return (firstOnly) ? (ret[0] || null) : ret;
 231  
 232      },
 233  
 234      // allows element scoped queries to begin with combinator
 235      // e.g. query('> p', document.body) === query('body > p')
 236      _splitQueries: function(selector, node) {
 237          var groups = selector.split(','),
 238              queries = [],
 239              prefix = '',
 240              i, len;
 241  
 242          if (node) {
 243              // enforce for element scoping
 244              if (node.tagName) {
 245                  node.id = node.id || Y_guid();
 246                  prefix = '[id="' + node.id + '"] ';
 247              }
 248  
 249              for (i = 0, len = groups.length; i < len; ++i) {
 250                  selector =  prefix + groups[i];
 251                  queries.push([selector, node]);
 252              }
 253          }
 254  
 255          return queries;
 256      },
 257  
 258      _nativeQuery: function(selector, root, one) {
 259          if (Y_UA.webkit && selector.indexOf(':checked') > -1 &&
 260                  (Selector.pseudos && Selector.pseudos.checked)) { // webkit (chrome, safari) fails to find "selected"
 261              return Selector.query(selector, root, one, true); // redo with skipNative true to try brute query
 262          }
 263          try {
 264              //YAHOO.log('trying native query with: ' + selector, 'info', 'selector-native');
 265              return root['querySelector' + (one ? '' : 'All')](selector);
 266          } catch(e) { // fallback to brute if available
 267              //YAHOO.log('native query error; reverting to brute query with: ' + selector, 'info', 'selector-native');
 268              return Selector.query(selector, root, one, true); // redo with skipNative true
 269          }
 270      },
 271  
 272      filter: function(nodes, selector) {
 273          var ret = [],
 274              i, node;
 275  
 276          if (nodes && selector) {
 277              for (i = 0; (node = nodes[i++]);) {
 278                  if (Selector.test(node, selector)) {
 279                      ret[ret.length] = node;
 280                  }
 281              }
 282          } else {
 283              YAHOO.log('invalid filter input (nodes: ' + nodes +
 284                      ', selector: ' + selector + ')', 'warn', 'Selector');
 285          }
 286  
 287          return ret;
 288      },
 289  
 290      test: function(node, selector, root) {
 291          var ret = false,
 292              groups = selector.split(','),
 293              useFrag = false,
 294              parent,
 295              item,
 296              items,
 297              frag,
 298              i, j, group;
 299  
 300          if (node && node.tagName) { // only test HTMLElements
 301  
 302              // we need a root if off-doc
 303              if (!root && !Y_DOM_inDoc(node)) {
 304                  parent = node.parentNode;
 305                  if (parent) { 
 306                      root = parent;
 307                  } else { // only use frag when no parent to query
 308                      frag = node[OWNER_DOCUMENT].createDocumentFragment();
 309                      frag.appendChild(node);
 310                      root = frag;
 311                      useFrag = true;
 312                  }
 313              }
 314              root = root || node[OWNER_DOCUMENT];
 315  
 316              if (!node.id) {
 317                  node.id = Y_guid();
 318              }
 319              for (i = 0; (group = groups[i++]);) { // TODO: off-dom test
 320                  group += '[id="' + node.id + '"]';
 321                  items = Selector.query(group, root);
 322  
 323                  for (j = 0; item = items[j++];) {
 324                      if (item === node) {
 325                          ret = true;
 326                          break;
 327                      }
 328                  }
 329                  if (ret) {
 330                      break;
 331                  }
 332              }
 333  
 334              if (useFrag) { // cleanup
 335                  frag.removeChild(node);
 336              }
 337          }
 338  
 339          return ret;
 340      }
 341  
 342  };
 343  
 344  YAHOO.util.Selector = Selector;
 345  /**
 346   * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements.
 347   * @module dom
 348   * @submodule selector-css2
 349   * @for Selector
 350   */
 351  
 352  /**
 353   * Provides helper methods for collecting and filtering DOM elements.
 354   */
 355  
 356  var PARENT_NODE = 'parentNode',
 357      TAG_NAME = 'tagName',
 358      ATTRIBUTES = 'attributes',
 359      COMBINATOR = 'combinator',
 360      PSEUDOS = 'pseudos',
 361  
 362      SelectorCSS2 = {
 363          _reRegExpTokens: /([\^\$\?\[\]\*\+\-\.\(\)\|\\])/, // TODO: move?
 364          SORT_RESULTS: true,
 365          _children: function(node, tag) {
 366              var ret = node.children,
 367                  i,
 368                  children = [],
 369                  childNodes,
 370                  child;
 371  
 372              if (node.children && tag && node.children.tags) {
 373                  children = node.children.tags(tag);
 374              } else if ((!ret && node[TAG_NAME]) || (ret && tag)) { // only HTMLElements have children
 375                  childNodes = ret || node.childNodes;
 376                  ret = [];
 377                  for (i = 0; (child = childNodes[i++]);) {
 378                      if (child.tagName) {
 379                          if (!tag || tag === child.tagName) {
 380                              ret.push(child);
 381                          }
 382                      }
 383                  }
 384              }
 385  
 386              return ret || [];
 387          },
 388  
 389          _re: {
 390              //attr: /(\[.*\])/g,
 391              attr: /(\[[^\]]*\])/g,
 392              //esc: /\\[:\[][\w\d\]]*/gi,
 393              esc: /\\[:\[\]\(\)#\.\'\>+~"]/gi,
 394              //pseudos: /:([\-\w]+(?:\(?:['"]?(.+)['"]?\))*)/i
 395              pseudos: /(\([^\)]*\))/g
 396          },
 397  
 398          /**
 399           * Mapping of shorthand tokens to corresponding attribute selector 
 400           * @property shorthand
 401           * @type object
 402           */
 403          shorthand: {
 404              //'\\#([^\\s\\\\(\\[:]*)': '[id=$1]',
 405              '\\#(-?[_a-z]+[-\\w\\uE000]*)': '[id=$1]',
 406              //'\\#([^\\s\\\.:\\[\\]]*)': '[id=$1]',
 407              //'\\.([^\\s\\\\(\\[:]*)': '[className=$1]'
 408              '\\.(-?[_a-z]+[-\\w\\uE000]*)': '[className~=$1]'
 409          },
 410  
 411          /**
 412           * List of operators and corresponding boolean functions. 
 413           * These functions are passed the attribute and the current node's value of the attribute.
 414           * @property operators
 415           * @type object
 416           */
 417          operators: {
 418              '': function(node, attr) { return !!node.getAttribute(attr); }, // Just test for existence of attribute
 419              //'': '.+',
 420              //'=': '^{val}$', // equality
 421              '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited
 422              '|=': '^{val}(?:-|$)' // optional hyphen-delimited
 423          },
 424  
 425          pseudos: {
 426             'first-child': function(node) { 
 427                  return Selector._children(node[PARENT_NODE])[0] === node; 
 428              } 
 429          },
 430  
 431          _bruteQuery: function(selector, root, firstOnly) {
 432              var ret = [],
 433                  nodes = [],
 434                  tokens = Selector._tokenize(selector),
 435                  token = tokens[tokens.length - 1],
 436                  rootDoc = Y_getDoc(root),
 437                  child,
 438                  id,
 439                  className,
 440                  tagName;
 441  
 442  
 443              // if we have an initial ID, set to root when in document
 444              /*
 445              if (tokens[0] && rootDoc === root &&  
 446                      (id = tokens[0].id) &&
 447                      rootDoc.getElementById(id)) {
 448                  root = rootDoc.getElementById(id);
 449              }
 450              */
 451  
 452              if (token) {
 453                  // prefilter nodes
 454                  id = token.id;
 455                  className = token.className;
 456                  tagName = token.tagName || '*';
 457  
 458                  if (root.getElementsByTagName) { // non-IE lacks DOM api on doc frags
 459                      // try ID first, unless no root.all && root not in document
 460                      // (root.all works off document, but not getElementById)
 461                      // TODO: move to allById?
 462                      if (id && (root.all || (root.nodeType === 9 || Y_DOM_inDoc(root)))) {
 463                          nodes = Y_DOM_allById(id, root);
 464                      // try className
 465                      } else if (className) {
 466                          nodes = root.getElementsByClassName(className);
 467                      } else { // default to tagName
 468                          nodes = root.getElementsByTagName(tagName);
 469                      }
 470  
 471                  } else { // brute getElementsByTagName('*')
 472                      child = root.firstChild;
 473                      while (child) {
 474                          if (child.tagName) { // only collect HTMLElements
 475                              nodes.push(child);
 476                          }
 477                          child = child.nextSilbing || child.firstChild;
 478                      }
 479                  }
 480                  if (nodes.length) {
 481                      ret = Selector._filterNodes(nodes, tokens, firstOnly);
 482                  }
 483              }
 484  
 485              return ret;
 486          },
 487          
 488          _filterNodes: function(nodes, tokens, firstOnly) {
 489              var i = 0,
 490                  j,
 491                  len = tokens.length,
 492                  n = len - 1,
 493                  result = [],
 494                  node = nodes[0],
 495                  tmpNode = node,
 496                  getters = Selector.getters,
 497                  operator,
 498                  combinator,
 499                  token,
 500                  path,
 501                  pass,
 502                  //FUNCTION = 'function',
 503                  value,
 504                  tests,
 505                  test;
 506  
 507              //do {
 508              for (i = 0; (tmpNode = node = nodes[i++]);) {
 509                  n = len - 1;
 510                  path = null;
 511                  
 512                  testLoop:
 513                  while (tmpNode && tmpNode.tagName) {
 514                      token = tokens[n];
 515                      tests = token.tests;
 516                      j = tests.length;
 517                      if (j && !pass) {
 518                          while ((test = tests[--j])) {
 519                              operator = test[1];
 520                              if (getters[test[0]]) {
 521                                  value = getters[test[0]](tmpNode, test[0]);
 522                              } else {
 523                                  value = tmpNode[test[0]];
 524                                  // use getAttribute for non-standard attributes
 525                                  if (value === undefined && tmpNode.getAttribute) {
 526                                      value = tmpNode.getAttribute(test[0]);
 527                                  }
 528                              }
 529  
 530                              if ((operator === '=' && value !== test[2]) ||  // fast path for equality
 531                                  (typeof operator !== 'string' && // protect against String.test monkey-patch (Moo)
 532                                  operator.test && !operator.test(value)) ||  // regex test
 533                                  (!operator.test && // protect against RegExp as function (webkit)
 534                                          typeof operator === 'function' && !operator(tmpNode, test[0], test[2]))) { // function test
 535  
 536                                  // skip non element nodes or non-matching tags
 537                                  if ((tmpNode = tmpNode[path])) {
 538                                      while (tmpNode &&
 539                                          (!tmpNode.tagName ||
 540                                              (token.tagName && token.tagName !== tmpNode.tagName))
 541                                      ) {
 542                                          tmpNode = tmpNode[path]; 
 543                                      }
 544                                  }
 545                                  continue testLoop;
 546                              }
 547                          }
 548                      }
 549  
 550                      n--; // move to next token
 551                      // now that we've passed the test, move up the tree by combinator
 552                      if (!pass && (combinator = token.combinator)) {
 553                          path = combinator.axis;
 554                          tmpNode = tmpNode[path];
 555  
 556                          // skip non element nodes
 557                          while (tmpNode && !tmpNode.tagName) {
 558                              tmpNode = tmpNode[path]; 
 559                          }
 560  
 561                          if (combinator.direct) { // one pass only
 562                              path = null; 
 563                          }
 564  
 565                      } else { // success if we made it this far
 566                          result.push(node);
 567                          if (firstOnly) {
 568                              return result;
 569                          }
 570                          break;
 571                      }
 572                  }
 573              }// while (tmpNode = node = nodes[++i]);
 574              node = tmpNode = null;
 575              return result;
 576          },
 577  
 578          combinators: {
 579              ' ': {
 580                  axis: 'parentNode'
 581              },
 582  
 583              '>': {
 584                  axis: 'parentNode',
 585                  direct: true
 586              },
 587  
 588  
 589              '+': {
 590                  axis: 'previousSibling',
 591                  direct: true
 592              }
 593          },
 594  
 595          _parsers: [
 596              {
 597                  name: ATTRIBUTES,
 598                  //re: /^\[(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,
 599                  re: /^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\uE004'"]*)['"]?\uE004/i,
 600                  fn: function(match, token) {
 601                      var operator = match[2] || '',
 602                          operators = Selector.operators,
 603                          escVal = (match[3]) ? match[3].replace(/\\/g, '') : '',
 604                          test;
 605  
 606                      // add prefiltering for ID and CLASS
 607                      if ((match[1] === 'id' && operator === '=') ||
 608                              (match[1] === 'className' &&
 609                              Y_DOCUMENT_ELEMENT.getElementsByClassName &&
 610                              (operator === '~=' || operator === '='))) {
 611                          token.prefilter = match[1];
 612  
 613  
 614                          match[3] = escVal; 
 615  
 616                          // escape all but ID for prefilter, which may run through QSA (via Dom.allById)
 617                          token[match[1]] = (match[1] === 'id') ? match[3] : escVal;
 618  
 619                      }
 620  
 621                      // add tests
 622                      if (operator in operators) {
 623                          test = operators[operator];
 624                          if (typeof test === 'string') {
 625                              match[3] = escVal.replace(Selector._reRegExpTokens, '\\$1');
 626                              test = new RegExp(test.replace('{val}', match[3]));
 627                          }
 628                          match[2] = test;
 629                      }
 630                      if (!token.last || token.prefilter !== match[1]) {
 631                          return match.slice(1);
 632                      }
 633                  }
 634  
 635              },
 636              {
 637                  name: TAG_NAME,
 638                  re: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
 639                  fn: function(match, token) {
 640                      var tag = match[1].toUpperCase();
 641                      token.tagName = tag;
 642  
 643                      if (tag !== '*' && (!token.last || token.prefilter)) {
 644                          return [TAG_NAME, '=', tag];
 645                      }
 646                      if (!token.prefilter) {
 647                          token.prefilter = 'tagName';
 648                      }
 649                  }
 650              },
 651              {
 652                  name: COMBINATOR,
 653                  re: /^\s*([>+~]|\s)\s*/,
 654                  fn: function(match, token) {
 655                  }
 656              },
 657              {
 658                  name: PSEUDOS,
 659                  re: /^:([\-\w]+)(?:\uE005['"]?([^\uE005]*)['"]?\uE006)*/i,
 660                  fn: function(match, token) {
 661                      var test = Selector[PSEUDOS][match[1]];
 662                      if (test) { // reorder match array and unescape special chars for tests
 663                          if (match[2]) {
 664                              match[2] = match[2].replace(/\\/g, '');
 665                          }
 666                          return [match[2], test]; 
 667                      } else { // selector token not supported (possibly missing CSS3 module)
 668                          return false;
 669                      }
 670                  }
 671              }
 672              ],
 673  
 674          _getToken: function(token) {
 675              return {
 676                  tagName: null,
 677                  id: null,
 678                  className: null,
 679                  attributes: {},
 680                  combinator: null,
 681                  tests: []
 682              };
 683          },
 684  
 685          /**
 686              Break selector into token units per simple selector.
 687              Combinator is attached to the previous token.
 688           */
 689          _tokenize: function(selector) {
 690              selector = selector || '';
 691              selector = Selector._replaceShorthand(Y_Lang.trim(selector)); 
 692              var token = Selector._getToken(),     // one token per simple selector (left selector holds combinator)
 693                  query = selector, // original query for debug report
 694                  tokens = [],    // array of tokens
 695                  found = false,  // whether or not any matches were found this pass
 696                  match,         // the regex match
 697                  test,
 698                  i, parser;
 699  
 700              /*
 701                  Search for selector patterns, store, and strip them from the selector string
 702                  until no patterns match (invalid selector) or we run out of chars.
 703  
 704                  Multiple attributes and pseudos are allowed, in any order.
 705                  for example:
 706                      'form:first-child[type=button]:not(button)[lang|=en]'
 707              */
 708  
 709              outer:
 710              do {
 711                  found = false; // reset after full pass
 712  
 713                  for (i = 0; (parser = Selector._parsers[i++]);) {
 714                      if ( (match = parser.re.exec(selector)) ) { // note assignment
 715                          if (parser.name !== COMBINATOR ) {
 716                              token.selector = selector;
 717                          }
 718                          selector = selector.replace(match[0], ''); // strip current match from selector
 719                          if (!selector.length) {
 720                              token.last = true;
 721                          }
 722  
 723                          if (Selector._attrFilters[match[1]]) { // convert class to className, etc.
 724                              match[1] = Selector._attrFilters[match[1]];
 725                          }
 726  
 727                          test = parser.fn(match, token);
 728                          if (test === false) { // selector not supported
 729                              found = false;
 730                              break outer;
 731                          } else if (test) {
 732                              token.tests.push(test);
 733                          }
 734  
 735                          if (!selector.length || parser.name === COMBINATOR) {
 736                              tokens.push(token);
 737                              token = Selector._getToken(token);
 738                              if (parser.name === COMBINATOR) {
 739                                  token.combinator = Selector.combinators[match[1]];
 740                              }
 741                          }
 742                          found = true;
 743  
 744  
 745                      }
 746                  }
 747              } while (found && selector.length);
 748  
 749              if (!found || selector.length) { // not fully parsed
 750                  YAHOO.log('query: ' + query + ' contains unsupported token in: ' + selector, 'warn', 'Selector');
 751                  tokens = [];
 752              }
 753              return tokens;
 754          },
 755  
 756          _replaceShorthand: function(selector) {
 757              var shorthand = Selector.shorthand,
 758                  esc = selector.match(Selector._re.esc), // pull escaped colon, brackets, etc. 
 759                  attrs,
 760                  pseudos,
 761                  re, i, len;
 762  
 763              if (esc) {
 764                  selector = selector.replace(Selector._re.esc, '\uE000');
 765              }
 766  
 767              attrs = selector.match(Selector._re.attr);
 768              pseudos = selector.match(Selector._re.pseudos);
 769  
 770              if (attrs) {
 771                  selector = selector.replace(Selector._re.attr, '\uE001');
 772              }
 773  
 774              if (pseudos) {
 775                  selector = selector.replace(Selector._re.pseudos, '\uE002');
 776              }
 777  
 778  
 779              for (re in shorthand) {
 780                  if (shorthand.hasOwnProperty(re)) {
 781                      selector = selector.replace(new RegExp(re, 'gi'), shorthand[re]);
 782                  }
 783              }
 784  
 785              if (attrs) {
 786                  for (i = 0, len = attrs.length; i < len; ++i) {
 787                      selector = selector.replace(/\uE001/, attrs[i]);
 788                  }
 789              }
 790  
 791              if (pseudos) {
 792                  for (i = 0, len = pseudos.length; i < len; ++i) {
 793                      selector = selector.replace(/\uE002/, pseudos[i]);
 794                  }
 795              }
 796  
 797              selector = selector.replace(/\[/g, '\uE003');
 798              selector = selector.replace(/\]/g, '\uE004');
 799  
 800              selector = selector.replace(/\(/g, '\uE005');
 801              selector = selector.replace(/\)/g, '\uE006');
 802  
 803              if (esc) {
 804                  for (i = 0, len = esc.length; i < len; ++i) {
 805                      selector = selector.replace('\uE000', esc[i]);
 806                  }
 807              }
 808  
 809              return selector;
 810          },
 811  
 812          _attrFilters: {
 813              'class': 'className',
 814              'for': 'htmlFor'
 815          },
 816  
 817          getters: {
 818              href: function(node, attr) {
 819                  return Y_DOM.getAttribute(node, attr);
 820              }
 821          }
 822      };
 823  
 824  Y_mix(Selector, SelectorCSS2, true);
 825  Selector.getters.src = Selector.getters.rel = Selector.getters.href;
 826  
 827  // IE wants class with native queries
 828  if (Selector.useNative && Y_DOC.querySelector) {
 829      Selector.shorthand['\\.([^\\s\\\\(\\[:]*)'] = '[class~=$1]';
 830  }
 831  
 832  /**
 833   * The selector css3 module provides support for css3 selectors.
 834   * @module dom
 835   * @submodule selector-css3
 836   * @for Selector
 837   */
 838  
 839  /*
 840      an+b = get every _a_th node starting at the _b_th
 841      0n+b = no repeat ("0" and "n" may both be omitted (together) , e.g. "0n+1" or "1", not "0+1"), return only the _b_th element
 842      1n+b =  get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n")
 843      an+0 = get every _a_th element, "0" may be omitted 
 844  */
 845  
 846  Selector._reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;
 847  
 848  Selector._getNth = function(node, expr, tag, reverse) {
 849      Selector._reNth.test(expr);
 850      var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_)
 851          n = RegExp.$2, // "n"
 852          oddeven = RegExp.$3, // "odd" or "even"
 853          b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_
 854          result = [],
 855          siblings = Selector._children(node.parentNode, tag),
 856          op;
 857  
 858      if (oddeven) {
 859          a = 2; // always every other
 860          op = '+';
 861          n = 'n';
 862          b = (oddeven === 'odd') ? 1 : 0;
 863      } else if ( isNaN(a) ) {
 864          a = (n) ? 1 : 0; // start from the first or no repeat
 865      }
 866  
 867      if (a === 0) { // just the first
 868          if (reverse) {
 869              b = siblings.length - b + 1; 
 870          }
 871  
 872          if (siblings[b - 1] === node) {
 873              return true;
 874          } else {
 875              return false;
 876          }
 877  
 878      } else if (a < 0) {
 879          reverse = !!reverse;
 880          a = Math.abs(a);
 881      }
 882  
 883      if (!reverse) {
 884          for (var i = b - 1, len = siblings.length; i < len; i += a) {
 885              if ( i >= 0 && siblings[i] === node ) {
 886                  return true;
 887              }
 888          }
 889      } else {
 890          for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) {
 891              if ( i < len && siblings[i] === node ) {
 892                  return true;
 893              }
 894          }
 895      }
 896      return false;
 897  };
 898  
 899  Y_mix(Selector.pseudos, {
 900      'root': function(node) {
 901          return node === node.ownerDocument.documentElement;
 902      },
 903  
 904      'nth-child': function(node, expr) {
 905          return Selector._getNth(node, expr);
 906      },
 907  
 908      'nth-last-child': function(node, expr) {
 909          return Selector._getNth(node, expr, null, true);
 910      },
 911  
 912      'nth-of-type': function(node, expr) {
 913          return Selector._getNth(node, expr, node.tagName);
 914      },
 915       
 916      'nth-last-of-type': function(node, expr) {
 917          return Selector._getNth(node, expr, node.tagName, true);
 918      },
 919       
 920      'last-child': function(node) {
 921          var children = Selector._children(node.parentNode);
 922          return children[children.length - 1] === node;
 923      },
 924  
 925      'first-of-type': function(node) {
 926          return Selector._children(node.parentNode, node.tagName)[0] === node;
 927      },
 928       
 929      'last-of-type': function(node) {
 930          var children = Selector._children(node.parentNode, node.tagName);
 931          return children[children.length - 1] === node;
 932      },
 933       
 934      'only-child': function(node) {
 935          var children = Selector._children(node.parentNode);
 936          return children.length === 1 && children[0] === node;
 937      },
 938  
 939      'only-of-type': function(node) {
 940          var children = Selector._children(node.parentNode, node.tagName);
 941          return children.length === 1 && children[0] === node;
 942      },
 943  
 944      'empty': function(node) {
 945          return node.childNodes.length === 0;
 946      },
 947  
 948      'not': function(node, expr) {
 949          return !Selector.test(node, expr);
 950      },
 951  
 952      'contains': function(node, expr) {
 953          var text = node.innerText || node.textContent || '';
 954          return text.indexOf(expr) > -1;
 955      },
 956  
 957      'checked': function(node) {
 958          return (node.checked === true || node.selected === true);
 959      },
 960  
 961      enabled: function(node) {
 962          return (node.disabled !== undefined && !node.disabled);
 963      },
 964  
 965      disabled: function(node) {
 966          return (node.disabled);
 967      }
 968  });
 969  
 970  Y_mix(Selector.operators, {
 971      '^=': '^{val}', // Match starts with value
 972      '!=': function(node, attr, val) { return node[attr] !== val; }, // Match starts with value
 973      '$=': '{val}$', // Match ends with value
 974      '*=': '{val}' // Match contains value as substring 
 975  });
 976  
 977  Selector.combinators['~'] = {
 978      axis: 'previousSibling'
 979  };
 980  YAHOO.register("selector", YAHOO.util.Selector, {version: "2.9.0", build: "2800"});
 981  
 982  }, '2.9.0' ,{"requires": ["yui2-yahoo", "yui2-dom"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1