[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/2in3/2.9.0/build/yui2-selector/ -> yui2-selector.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          return (firstOnly) ? (ret[0] || null) : ret;
 230  
 231      },
 232  
 233      // allows element scoped queries to begin with combinator
 234      // e.g. query('> p', document.body) === query('body > p')
 235      _splitQueries: function(selector, node) {
 236          var groups = selector.split(','),
 237              queries = [],
 238              prefix = '',
 239              i, len;
 240  
 241          if (node) {
 242              // enforce for element scoping
 243              if (node.tagName) {
 244                  node.id = node.id || Y_guid();
 245                  prefix = '[id="' + node.id + '"] ';
 246              }
 247  
 248              for (i = 0, len = groups.length; i < len; ++i) {
 249                  selector =  prefix + groups[i];
 250                  queries.push([selector, node]);
 251              }
 252          }
 253  
 254          return queries;
 255      },
 256  
 257      _nativeQuery: function(selector, root, one) {
 258          if (Y_UA.webkit && selector.indexOf(':checked') > -1 &&
 259                  (Selector.pseudos && Selector.pseudos.checked)) { // webkit (chrome, safari) fails to find "selected"
 260              return Selector.query(selector, root, one, true); // redo with skipNative true to try brute query
 261          }
 262          try {
 263              return root['querySelector' + (one ? '' : 'All')](selector);
 264          } catch(e) { // fallback to brute if available
 265              return Selector.query(selector, root, one, true); // redo with skipNative true
 266          }
 267      },
 268  
 269      filter: function(nodes, selector) {
 270          var ret = [],
 271              i, node;
 272  
 273          if (nodes && selector) {
 274              for (i = 0; (node = nodes[i++]);) {
 275                  if (Selector.test(node, selector)) {
 276                      ret[ret.length] = node;
 277                  }
 278              }
 279          } else {
 280          }
 281  
 282          return ret;
 283      },
 284  
 285      test: function(node, selector, root) {
 286          var ret = false,
 287              groups = selector.split(','),
 288              useFrag = false,
 289              parent,
 290              item,
 291              items,
 292              frag,
 293              i, j, group;
 294  
 295          if (node && node.tagName) { // only test HTMLElements
 296  
 297              // we need a root if off-doc
 298              if (!root && !Y_DOM_inDoc(node)) {
 299                  parent = node.parentNode;
 300                  if (parent) { 
 301                      root = parent;
 302                  } else { // only use frag when no parent to query
 303                      frag = node[OWNER_DOCUMENT].createDocumentFragment();
 304                      frag.appendChild(node);
 305                      root = frag;
 306                      useFrag = true;
 307                  }
 308              }
 309              root = root || node[OWNER_DOCUMENT];
 310  
 311              if (!node.id) {
 312                  node.id = Y_guid();
 313              }
 314              for (i = 0; (group = groups[i++]);) { // TODO: off-dom test
 315                  group += '[id="' + node.id + '"]';
 316                  items = Selector.query(group, root);
 317  
 318                  for (j = 0; item = items[j++];) {
 319                      if (item === node) {
 320                          ret = true;
 321                          break;
 322                      }
 323                  }
 324                  if (ret) {
 325                      break;
 326                  }
 327              }
 328  
 329              if (useFrag) { // cleanup
 330                  frag.removeChild(node);
 331              }
 332          }
 333  
 334          return ret;
 335      }
 336  
 337  };
 338  
 339  YAHOO.util.Selector = Selector;
 340  /**
 341   * The selector module provides helper methods allowing CSS2 Selectors to be used with DOM elements.
 342   * @module dom
 343   * @submodule selector-css2
 344   * @for Selector
 345   */
 346  
 347  /**
 348   * Provides helper methods for collecting and filtering DOM elements.
 349   */
 350  
 351  var PARENT_NODE = 'parentNode',
 352      TAG_NAME = 'tagName',
 353      ATTRIBUTES = 'attributes',
 354      COMBINATOR = 'combinator',
 355      PSEUDOS = 'pseudos',
 356  
 357      SelectorCSS2 = {
 358          _reRegExpTokens: /([\^\$\?\[\]\*\+\-\.\(\)\|\\])/, // TODO: move?
 359          SORT_RESULTS: true,
 360          _children: function(node, tag) {
 361              var ret = node.children,
 362                  i,
 363                  children = [],
 364                  childNodes,
 365                  child;
 366  
 367              if (node.children && tag && node.children.tags) {
 368                  children = node.children.tags(tag);
 369              } else if ((!ret && node[TAG_NAME]) || (ret && tag)) { // only HTMLElements have children
 370                  childNodes = ret || node.childNodes;
 371                  ret = [];
 372                  for (i = 0; (child = childNodes[i++]);) {
 373                      if (child.tagName) {
 374                          if (!tag || tag === child.tagName) {
 375                              ret.push(child);
 376                          }
 377                      }
 378                  }
 379              }
 380  
 381              return ret || [];
 382          },
 383  
 384          _re: {
 385              //attr: /(\[.*\])/g,
 386              attr: /(\[[^\]]*\])/g,
 387              //esc: /\\[:\[][\w\d\]]*/gi,
 388              esc: /\\[:\[\]\(\)#\.\'\>+~"]/gi,
 389              //pseudos: /:([\-\w]+(?:\(?:['"]?(.+)['"]?\))*)/i
 390              pseudos: /(\([^\)]*\))/g
 391          },
 392  
 393          /**
 394           * Mapping of shorthand tokens to corresponding attribute selector 
 395           * @property shorthand
 396           * @type object
 397           */
 398          shorthand: {
 399              //'\\#([^\\s\\\\(\\[:]*)': '[id=$1]',
 400              '\\#(-?[_a-z]+[-\\w\\uE000]*)': '[id=$1]',
 401              //'\\#([^\\s\\\.:\\[\\]]*)': '[id=$1]',
 402              //'\\.([^\\s\\\\(\\[:]*)': '[className=$1]'
 403              '\\.(-?[_a-z]+[-\\w\\uE000]*)': '[className~=$1]'
 404          },
 405  
 406          /**
 407           * List of operators and corresponding boolean functions. 
 408           * These functions are passed the attribute and the current node's value of the attribute.
 409           * @property operators
 410           * @type object
 411           */
 412          operators: {
 413              '': function(node, attr) { return !!node.getAttribute(attr); }, // Just test for existence of attribute
 414              //'': '.+',
 415              //'=': '^{val}$', // equality
 416              '~=': '(?:^|\\s+){val}(?:\\s+|$)', // space-delimited
 417              '|=': '^{val}(?:-|$)' // optional hyphen-delimited
 418          },
 419  
 420          pseudos: {
 421             'first-child': function(node) { 
 422                  return Selector._children(node[PARENT_NODE])[0] === node; 
 423              } 
 424          },
 425  
 426          _bruteQuery: function(selector, root, firstOnly) {
 427              var ret = [],
 428                  nodes = [],
 429                  tokens = Selector._tokenize(selector),
 430                  token = tokens[tokens.length - 1],
 431                  rootDoc = Y_getDoc(root),
 432                  child,
 433                  id,
 434                  className,
 435                  tagName;
 436  
 437  
 438              // if we have an initial ID, set to root when in document
 439              /*
 440              if (tokens[0] && rootDoc === root &&  
 441                      (id = tokens[0].id) &&
 442                      rootDoc.getElementById(id)) {
 443                  root = rootDoc.getElementById(id);
 444              }
 445              */
 446  
 447              if (token) {
 448                  // prefilter nodes
 449                  id = token.id;
 450                  className = token.className;
 451                  tagName = token.tagName || '*';
 452  
 453                  if (root.getElementsByTagName) { // non-IE lacks DOM api on doc frags
 454                      // try ID first, unless no root.all && root not in document
 455                      // (root.all works off document, but not getElementById)
 456                      // TODO: move to allById?
 457                      if (id && (root.all || (root.nodeType === 9 || Y_DOM_inDoc(root)))) {
 458                          nodes = Y_DOM_allById(id, root);
 459                      // try className
 460                      } else if (className) {
 461                          nodes = root.getElementsByClassName(className);
 462                      } else { // default to tagName
 463                          nodes = root.getElementsByTagName(tagName);
 464                      }
 465  
 466                  } else { // brute getElementsByTagName('*')
 467                      child = root.firstChild;
 468                      while (child) {
 469                          if (child.tagName) { // only collect HTMLElements
 470                              nodes.push(child);
 471                          }
 472                          child = child.nextSilbing || child.firstChild;
 473                      }
 474                  }
 475                  if (nodes.length) {
 476                      ret = Selector._filterNodes(nodes, tokens, firstOnly);
 477                  }
 478              }
 479  
 480              return ret;
 481          },
 482          
 483          _filterNodes: function(nodes, tokens, firstOnly) {
 484              var i = 0,
 485                  j,
 486                  len = tokens.length,
 487                  n = len - 1,
 488                  result = [],
 489                  node = nodes[0],
 490                  tmpNode = node,
 491                  getters = Selector.getters,
 492                  operator,
 493                  combinator,
 494                  token,
 495                  path,
 496                  pass,
 497                  //FUNCTION = 'function',
 498                  value,
 499                  tests,
 500                  test;
 501  
 502              //do {
 503              for (i = 0; (tmpNode = node = nodes[i++]);) {
 504                  n = len - 1;
 505                  path = null;
 506                  
 507                  testLoop:
 508                  while (tmpNode && tmpNode.tagName) {
 509                      token = tokens[n];
 510                      tests = token.tests;
 511                      j = tests.length;
 512                      if (j && !pass) {
 513                          while ((test = tests[--j])) {
 514                              operator = test[1];
 515                              if (getters[test[0]]) {
 516                                  value = getters[test[0]](tmpNode, test[0]);
 517                              } else {
 518                                  value = tmpNode[test[0]];
 519                                  // use getAttribute for non-standard attributes
 520                                  if (value === undefined && tmpNode.getAttribute) {
 521                                      value = tmpNode.getAttribute(test[0]);
 522                                  }
 523                              }
 524  
 525                              if ((operator === '=' && value !== test[2]) ||  // fast path for equality
 526                                  (typeof operator !== 'string' && // protect against String.test monkey-patch (Moo)
 527                                  operator.test && !operator.test(value)) ||  // regex test
 528                                  (!operator.test && // protect against RegExp as function (webkit)
 529                                          typeof operator === 'function' && !operator(tmpNode, test[0], test[2]))) { // function test
 530  
 531                                  // skip non element nodes or non-matching tags
 532                                  if ((tmpNode = tmpNode[path])) {
 533                                      while (tmpNode &&
 534                                          (!tmpNode.tagName ||
 535                                              (token.tagName && token.tagName !== tmpNode.tagName))
 536                                      ) {
 537                                          tmpNode = tmpNode[path]; 
 538                                      }
 539                                  }
 540                                  continue testLoop;
 541                              }
 542                          }
 543                      }
 544  
 545                      n--; // move to next token
 546                      // now that we've passed the test, move up the tree by combinator
 547                      if (!pass && (combinator = token.combinator)) {
 548                          path = combinator.axis;
 549                          tmpNode = tmpNode[path];
 550  
 551                          // skip non element nodes
 552                          while (tmpNode && !tmpNode.tagName) {
 553                              tmpNode = tmpNode[path]; 
 554                          }
 555  
 556                          if (combinator.direct) { // one pass only
 557                              path = null; 
 558                          }
 559  
 560                      } else { // success if we made it this far
 561                          result.push(node);
 562                          if (firstOnly) {
 563                              return result;
 564                          }
 565                          break;
 566                      }
 567                  }
 568              }// while (tmpNode = node = nodes[++i]);
 569              node = tmpNode = null;
 570              return result;
 571          },
 572  
 573          combinators: {
 574              ' ': {
 575                  axis: 'parentNode'
 576              },
 577  
 578              '>': {
 579                  axis: 'parentNode',
 580                  direct: true
 581              },
 582  
 583  
 584              '+': {
 585                  axis: 'previousSibling',
 586                  direct: true
 587              }
 588          },
 589  
 590          _parsers: [
 591              {
 592                  name: ATTRIBUTES,
 593                  //re: /^\[(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,
 594                  re: /^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['"]?([^\uE004'"]*)['"]?\uE004/i,
 595                  fn: function(match, token) {
 596                      var operator = match[2] || '',
 597                          operators = Selector.operators,
 598                          escVal = (match[3]) ? match[3].replace(/\\/g, '') : '',
 599                          test;
 600  
 601                      // add prefiltering for ID and CLASS
 602                      if ((match[1] === 'id' && operator === '=') ||
 603                              (match[1] === 'className' &&
 604                              Y_DOCUMENT_ELEMENT.getElementsByClassName &&
 605                              (operator === '~=' || operator === '='))) {
 606                          token.prefilter = match[1];
 607  
 608  
 609                          match[3] = escVal; 
 610  
 611                          // escape all but ID for prefilter, which may run through QSA (via Dom.allById)
 612                          token[match[1]] = (match[1] === 'id') ? match[3] : escVal;
 613  
 614                      }
 615  
 616                      // add tests
 617                      if (operator in operators) {
 618                          test = operators[operator];
 619                          if (typeof test === 'string') {
 620                              match[3] = escVal.replace(Selector._reRegExpTokens, '\\$1');
 621                              test = new RegExp(test.replace('{val}', match[3]));
 622                          }
 623                          match[2] = test;
 624                      }
 625                      if (!token.last || token.prefilter !== match[1]) {
 626                          return match.slice(1);
 627                      }
 628                  }
 629  
 630              },
 631              {
 632                  name: TAG_NAME,
 633                  re: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
 634                  fn: function(match, token) {
 635                      var tag = match[1].toUpperCase();
 636                      token.tagName = tag;
 637  
 638                      if (tag !== '*' && (!token.last || token.prefilter)) {
 639                          return [TAG_NAME, '=', tag];
 640                      }
 641                      if (!token.prefilter) {
 642                          token.prefilter = 'tagName';
 643                      }
 644                  }
 645              },
 646              {
 647                  name: COMBINATOR,
 648                  re: /^\s*([>+~]|\s)\s*/,
 649                  fn: function(match, token) {
 650                  }
 651              },
 652              {
 653                  name: PSEUDOS,
 654                  re: /^:([\-\w]+)(?:\uE005['"]?([^\uE005]*)['"]?\uE006)*/i,
 655                  fn: function(match, token) {
 656                      var test = Selector[PSEUDOS][match[1]];
 657                      if (test) { // reorder match array and unescape special chars for tests
 658                          if (match[2]) {
 659                              match[2] = match[2].replace(/\\/g, '');
 660                          }
 661                          return [match[2], test]; 
 662                      } else { // selector token not supported (possibly missing CSS3 module)
 663                          return false;
 664                      }
 665                  }
 666              }
 667              ],
 668  
 669          _getToken: function(token) {
 670              return {
 671                  tagName: null,
 672                  id: null,
 673                  className: null,
 674                  attributes: {},
 675                  combinator: null,
 676                  tests: []
 677              };
 678          },
 679  
 680          /**
 681              Break selector into token units per simple selector.
 682              Combinator is attached to the previous token.
 683           */
 684          _tokenize: function(selector) {
 685              selector = selector || '';
 686              selector = Selector._replaceShorthand(Y_Lang.trim(selector)); 
 687              var token = Selector._getToken(),     // one token per simple selector (left selector holds combinator)
 688                  query = selector, // original query for debug report
 689                  tokens = [],    // array of tokens
 690                  found = false,  // whether or not any matches were found this pass
 691                  match,         // the regex match
 692                  test,
 693                  i, parser;
 694  
 695              /*
 696                  Search for selector patterns, store, and strip them from the selector string
 697                  until no patterns match (invalid selector) or we run out of chars.
 698  
 699                  Multiple attributes and pseudos are allowed, in any order.
 700                  for example:
 701                      'form:first-child[type=button]:not(button)[lang|=en]'
 702              */
 703  
 704              outer:
 705              do {
 706                  found = false; // reset after full pass
 707  
 708                  for (i = 0; (parser = Selector._parsers[i++]);) {
 709                      if ( (match = parser.re.exec(selector)) ) { // note assignment
 710                          if (parser.name !== COMBINATOR ) {
 711                              token.selector = selector;
 712                          }
 713                          selector = selector.replace(match[0], ''); // strip current match from selector
 714                          if (!selector.length) {
 715                              token.last = true;
 716                          }
 717  
 718                          if (Selector._attrFilters[match[1]]) { // convert class to className, etc.
 719                              match[1] = Selector._attrFilters[match[1]];
 720                          }
 721  
 722                          test = parser.fn(match, token);
 723                          if (test === false) { // selector not supported
 724                              found = false;
 725                              break outer;
 726                          } else if (test) {
 727                              token.tests.push(test);
 728                          }
 729  
 730                          if (!selector.length || parser.name === COMBINATOR) {
 731                              tokens.push(token);
 732                              token = Selector._getToken(token);
 733                              if (parser.name === COMBINATOR) {
 734                                  token.combinator = Selector.combinators[match[1]];
 735                              }
 736                          }
 737                          found = true;
 738  
 739  
 740                      }
 741                  }
 742              } while (found && selector.length);
 743  
 744              if (!found || selector.length) { // not fully parsed
 745                  tokens = [];
 746              }
 747              return tokens;
 748          },
 749  
 750          _replaceShorthand: function(selector) {
 751              var shorthand = Selector.shorthand,
 752                  esc = selector.match(Selector._re.esc), // pull escaped colon, brackets, etc. 
 753                  attrs,
 754                  pseudos,
 755                  re, i, len;
 756  
 757              if (esc) {
 758                  selector = selector.replace(Selector._re.esc, '\uE000');
 759              }
 760  
 761              attrs = selector.match(Selector._re.attr);
 762              pseudos = selector.match(Selector._re.pseudos);
 763  
 764              if (attrs) {
 765                  selector = selector.replace(Selector._re.attr, '\uE001');
 766              }
 767  
 768              if (pseudos) {
 769                  selector = selector.replace(Selector._re.pseudos, '\uE002');
 770              }
 771  
 772  
 773              for (re in shorthand) {
 774                  if (shorthand.hasOwnProperty(re)) {
 775                      selector = selector.replace(new RegExp(re, 'gi'), shorthand[re]);
 776                  }
 777              }
 778  
 779              if (attrs) {
 780                  for (i = 0, len = attrs.length; i < len; ++i) {
 781                      selector = selector.replace(/\uE001/, attrs[i]);
 782                  }
 783              }
 784  
 785              if (pseudos) {
 786                  for (i = 0, len = pseudos.length; i < len; ++i) {
 787                      selector = selector.replace(/\uE002/, pseudos[i]);
 788                  }
 789              }
 790  
 791              selector = selector.replace(/\[/g, '\uE003');
 792              selector = selector.replace(/\]/g, '\uE004');
 793  
 794              selector = selector.replace(/\(/g, '\uE005');
 795              selector = selector.replace(/\)/g, '\uE006');
 796  
 797              if (esc) {
 798                  for (i = 0, len = esc.length; i < len; ++i) {
 799                      selector = selector.replace('\uE000', esc[i]);
 800                  }
 801              }
 802  
 803              return selector;
 804          },
 805  
 806          _attrFilters: {
 807              'class': 'className',
 808              'for': 'htmlFor'
 809          },
 810  
 811          getters: {
 812              href: function(node, attr) {
 813                  return Y_DOM.getAttribute(node, attr);
 814              }
 815          }
 816      };
 817  
 818  Y_mix(Selector, SelectorCSS2, true);
 819  Selector.getters.src = Selector.getters.rel = Selector.getters.href;
 820  
 821  // IE wants class with native queries
 822  if (Selector.useNative && Y_DOC.querySelector) {
 823      Selector.shorthand['\\.([^\\s\\\\(\\[:]*)'] = '[class~=$1]';
 824  }
 825  
 826  /**
 827   * The selector css3 module provides support for css3 selectors.
 828   * @module dom
 829   * @submodule selector-css3
 830   * @for Selector
 831   */
 832  
 833  /*
 834      an+b = get every _a_th node starting at the _b_th
 835      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
 836      1n+b =  get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n")
 837      an+0 = get every _a_th element, "0" may be omitted 
 838  */
 839  
 840  Selector._reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;
 841  
 842  Selector._getNth = function(node, expr, tag, reverse) {
 843      Selector._reNth.test(expr);
 844      var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_)
 845          n = RegExp.$2, // "n"
 846          oddeven = RegExp.$3, // "odd" or "even"
 847          b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_
 848          result = [],
 849          siblings = Selector._children(node.parentNode, tag),
 850          op;
 851  
 852      if (oddeven) {
 853          a = 2; // always every other
 854          op = '+';
 855          n = 'n';
 856          b = (oddeven === 'odd') ? 1 : 0;
 857      } else if ( isNaN(a) ) {
 858          a = (n) ? 1 : 0; // start from the first or no repeat
 859      }
 860  
 861      if (a === 0) { // just the first
 862          if (reverse) {
 863              b = siblings.length - b + 1; 
 864          }
 865  
 866          if (siblings[b - 1] === node) {
 867              return true;
 868          } else {
 869              return false;
 870          }
 871  
 872      } else if (a < 0) {
 873          reverse = !!reverse;
 874          a = Math.abs(a);
 875      }
 876  
 877      if (!reverse) {
 878          for (var i = b - 1, len = siblings.length; i < len; i += a) {
 879              if ( i >= 0 && siblings[i] === node ) {
 880                  return true;
 881              }
 882          }
 883      } else {
 884          for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) {
 885              if ( i < len && siblings[i] === node ) {
 886                  return true;
 887              }
 888          }
 889      }
 890      return false;
 891  };
 892  
 893  Y_mix(Selector.pseudos, {
 894      'root': function(node) {
 895          return node === node.ownerDocument.documentElement;
 896      },
 897  
 898      'nth-child': function(node, expr) {
 899          return Selector._getNth(node, expr);
 900      },
 901  
 902      'nth-last-child': function(node, expr) {
 903          return Selector._getNth(node, expr, null, true);
 904      },
 905  
 906      'nth-of-type': function(node, expr) {
 907          return Selector._getNth(node, expr, node.tagName);
 908      },
 909       
 910      'nth-last-of-type': function(node, expr) {
 911          return Selector._getNth(node, expr, node.tagName, true);
 912      },
 913       
 914      'last-child': function(node) {
 915          var children = Selector._children(node.parentNode);
 916          return children[children.length - 1] === node;
 917      },
 918  
 919      'first-of-type': function(node) {
 920          return Selector._children(node.parentNode, node.tagName)[0] === node;
 921      },
 922       
 923      'last-of-type': function(node) {
 924          var children = Selector._children(node.parentNode, node.tagName);
 925          return children[children.length - 1] === node;
 926      },
 927       
 928      'only-child': function(node) {
 929          var children = Selector._children(node.parentNode);
 930          return children.length === 1 && children[0] === node;
 931      },
 932  
 933      'only-of-type': function(node) {
 934          var children = Selector._children(node.parentNode, node.tagName);
 935          return children.length === 1 && children[0] === node;
 936      },
 937  
 938      'empty': function(node) {
 939          return node.childNodes.length === 0;
 940      },
 941  
 942      'not': function(node, expr) {
 943          return !Selector.test(node, expr);
 944      },
 945  
 946      'contains': function(node, expr) {
 947          var text = node.innerText || node.textContent || '';
 948          return text.indexOf(expr) > -1;
 949      },
 950  
 951      'checked': function(node) {
 952          return (node.checked === true || node.selected === true);
 953      },
 954  
 955      enabled: function(node) {
 956          return (node.disabled !== undefined && !node.disabled);
 957      },
 958  
 959      disabled: function(node) {
 960          return (node.disabled);
 961      }
 962  });
 963  
 964  Y_mix(Selector.operators, {
 965      '^=': '^{val}', // Match starts with value
 966      '!=': function(node, attr, val) { return node[attr] !== val; }, // Match starts with value
 967      '$=': '{val}$', // Match ends with value
 968      '*=': '{val}' // Match contains value as substring 
 969  });
 970  
 971  Selector.combinators['~'] = {
 972      axis: 'previousSibling'
 973  };
 974  YAHOO.register("selector", YAHOO.util.Selector, {version: "2.9.0", build: "2800"});
 975  
 976  }, '2.9.0' ,{"requires": ["yui2-yahoo", "yui2-dom"]});


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