Requires

Provides

The new, superfast css selector engine.

  1. 11
  2. 12
  3. 13
(function(){ var local = {};

Feature / Bug detection

  1. 17
  2. 18
  3. 19
  4. 20
  5. 21
  6. 22
  7. 23
  8. 24
  9. 25
  10. 26
local.isNativeCode = function(fn){ return (/\{\s*\[native code\]\s*\}/).test('' + fn); }; local.isXML = function(document){ return (!!document.xmlVersion) || (!!document.xml) || (Object.prototype.toString.call(document) === '[object XMLDocument]') || (document.nodeType === 9 && document.documentElement.nodeName !== 'HTML'); }; local.setDocument = function(document){

convert elements / window arguments to document. if document cannot be extrapolated, the function returns.

  1. 30
  2. 31
  3. 32
  4. 33
if (document.nodeType === 9); // document else if (document.ownerDocument) document = document.ownerDocument; // node else if (document.navigator) document = document.document; // window else return;

check if it’s the old document

  1. 37
  2. 38
  3. 39
  4. 40
  5. 41
  6. 42
  7. 43
  8. 44
  9. 45
  10. 46
  11. 47
  12. 48
  13. 49
  14. 50
  15. 51
  16. 52
  17. 53
  18. 54
  19. 55
  20. 56
  21. 57
  22. 58
if (this.document === document) return; this.document = document; var root = this.root = document.documentElement; this.isXMLDocument = this.isXML(document); this.brokenStarGEBTN = this.starSelectsClosedQSA = this.idGetsName = this.brokenMixedCaseQSA = this.brokenGEBCN = this.brokenCheckedQSA = this.brokenEmptyAttributeQSA = this.isHTMLDocument = false; var starSelectsClosed, starSelectsComments, brokenSecondClassNameGEBCN, cachedGetElementsByClassName; var selected, id; var testNode = document.createElement('div'); root.appendChild(testNode);

on non-HTML documents innerHTML and getElementsById doesnt work properly

  1. 61
  2. 62
  3. 63
  4. 64
  5. 65
  6. 66
  7. 67
  8. 68
  9. 69
try { id = 'slick_getbyid_test'; testNode.innerHTML = '<a id="'+id+'"></a>'; this.isHTMLDocument = !!document.getElementById(id); } catch(e){}; if (this.isHTMLDocument){ testNode.style.display = 'none';

IE returns comment nodes for getElementsByTagName(‘*’) for some documents

  1. 72
  2. 73
testNode.appendChild(document.createComment('')); starSelectsComments = (testNode.getElementsByTagName('*').length > 0);

IE returns closed nodes (EG:“”) for getElementsByTagName(‘*’) for some documents

  1. 76
  2. 77
  3. 78
  4. 79
  5. 80
  6. 81
  7. 82
try { testNode.innerHTML = 'foo</foo>'; selected = testNode.getElementsByTagName('*'); starSelectsClosed = (selected && selected.length && selected[0].nodeName.charAt(0) == '/'); } catch(e){}; this.brokenStarGEBTN = starSelectsComments || starSelectsClosed;

IE 8 returns closed nodes (EG:“”) for querySelectorAll(‘*’) for some documents

  1. 85
  2. 86
  3. 87
  4. 88
  5. 89
if (testNode.querySelectorAll) try { testNode.innerHTML = 'foo</foo>'; selected = testNode.querySelectorAll('*'); this.starSelectsClosedQSA = (selected && selected.length && selected[0].nodeName.charAt(0) == '/'); } catch(e){};

IE returns elements with the name instead of just id for getElementsById for some documents

  1. 92
  2. 93
  3. 94
  4. 95
  5. 96
try { id = 'slick_id_gets_name'; testNode.innerHTML = '<a name="'+id+'"></a><b id="'+id+'"></b>'; this.idGetsName = document.getElementById(id) === testNode.firstChild; } catch(e){};

Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode

  1. 99
  2. 100
  3. 101
  4. 102
  5. 103
  6. 104
  7. 105
  8. 106
  9. 107
  10. 108
  11. 109
try { testNode.innerHTML = '<a class="MiXedCaSe"></a>'; this.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiXedCaSe').length; } catch(e){}; try { testNode.innerHTML = '<a class="f"></a><a class="b"></a>'; testNode.getElementsByClassName('b').length; testNode.firstChild.className = 'b'; cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2); } catch(e){};

Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one

  1. 112
  2. 113
  3. 114
  4. 115
  5. 116
  6. 117
try { testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>'; brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2); } catch(e){}; this.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN;

Webkit dont return selected options on querySelectorAll

  1. 120
  2. 121
  3. 122
  4. 123
try { testNode.innerHTML = '<select><option selected="selected">a</option></select>'; this.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0); } catch(e){};

IE returns incorrect results for attr[*$]=“” selectors on querySelectorAll

  1. 126
  2. 127
  3. 128
  4. 129
  5. 130
  6. 131
  7. 132
  8. 133
  9. 134
try { testNode.innerHTML = '<a class=""></a>'; this.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0); } catch(e){}; } root.removeChild(testNode); testNode = null;

hasAttribute

  1. 138
  2. 139
  3. 140
  4. 141
  5. 142
  6. 143
this.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) { return node.hasAttribute(attribute); } : function(node, attribute) { node = node.getAttributeNode(attribute); return !!(node && (node.specified || node.nodeValue)); };

contains FIXME: Add specs: local.contains should be different for xml and html documents?

  1. 147
  2. 148
  3. 149
  4. 150
  5. 151
  6. 152
  7. 153
  8. 154
  9. 155
  10. 156
this.contains = (root && this.isNativeCode(root.contains)) ? function(context, node){ return context.contains(node); } : (root && root.compareDocumentPosition) ? function(context, node){ return context === node || !!(context.compareDocumentPosition(node) & 16); } : function(context, node){ if (node) do { if (node === context) return true; } while ((node = node.parentNode)); return false; };

document order sorting credits to Sizzle (http://sizzlejs.com/)

  1. 161
  2. 162
  3. 163
  4. 164
  5. 165
  6. 166
  7. 167
  8. 168
  9. 169
  10. 170
  11. 171
  12. 172
  13. 173
  14. 174
  15. 175
  16. 176
  17. 177
  18. 178
  19. 179
this.documentSorter = (root.compareDocumentPosition) ? function(a, b){ if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0; return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; } : ('sourceIndex' in root) ? function(a, b){ if (!a.sourceIndex || !b.sourceIndex) return 0; return a.sourceIndex - b.sourceIndex; } : (document.createRange) ? function(a, b){ if (!a.ownerDocument || !b.ownerDocument) return 0; var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); aRange.setStart(a, 0); aRange.setEnd(a, 0); bRange.setStart(b, 0); bRange.setEnd(b, 0); return aRange.compareBoundaryPoints(Range.START_TO_END, bRange); } : null ; this.getUID = (this.isHTMLDocument) ? this.getUIDHTML : this.getUIDXML; };

Main Method

  1. 183
  2. 184
  3. 185
local.search = function(context, expression, append, first){ var found = this.found = (first) ? null : (append || []);

context checks

  1. 189
  2. 190
  3. 191
if (!context) return found; // No context if (context.navigator) context = context.document; // Convert the node from a window to a document else if (!context.nodeType) return found; // Reject misc junk input

setup

  1. 195
  2. 196
  3. 197
  4. 198
  5. 199
var parsed, i; var uniques = this.uniques = {}; if (this.document !== (context.ownerDocument || context)) this.setDocument(context);

should sort if there are nodes in append and if you pass multiple expressions. should remove duplicates if append already has items

  1. 203
var shouldUniques = !!(append && append.length);

avoid duplicating items already in the append array

  1. 206
if (shouldUniques) for (i = found.length; i--;) this.uniques[this.getUID(found[i])] = true;

expression checks

  1. 210
if (typeof expression == 'string'){ // expression is a string

Overrides

  1. 214
  2. 215
  3. 216
  4. 217
  5. 218
  6. 219
  7. 220
  8. 221
  9. 222
  10. 223
  11. 224
  12. 225
  13. 226
  14. 227
  15. 228
  16. 229
  17. 230
  18. 231
  19. 232
  20. 233
  21. 234
  22. 235
for (i = this.overrides.length; i--;){ var override = this.overrides[i]; if (override.regexp.test(expression)){ var result = override.method.call(context, expression, found, first); if (result === false) continue; if (result === true) return found; return result; } } parsed = this.Slick.parse(expression); if (!parsed.length) return found; } else if (expression == null){ // there is no expression return found; } else if (expression.Slick){ // expression is a parsed Slick object parsed = expression; } else if (this.contains(context.documentElement || context, expression)){ // expression is a node (found) ? found.push(expression) : found = expression; return found; } else { // other junk return found; }

cache elements for the nth selectors

  1. 241
  2. 242
  3. 243
  4. 244
this.posNTH = {}; this.posNTHLast = {}; this.posNTHType = {}; this.posNTHTypeLast = {};

if append is null and there is only a single selector with one expression use pushArray, else use pushUID

  1. 249
  2. 250
  3. 251
this.push = (!shouldUniques && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID; if (found == null) found = [];

default engine

  1. 255
  2. 256
  3. 257
  4. 258
  5. 259
  6. 260
  7. 261
  8. 262
  9. 263
  10. 264
  11. 265
  12. 266
  13. 267
  14. 268
  15. 269
  16. 270
  17. 271
  18. 272
  19. 273
  20. 274
  21. 275
  22. 276
  23. 277
  24. 278
  25. 279
  26. 280
  27. 281
  28. 282
  29. 283
  30. 284
  31. 285
  32. 286
  33. 287
  34. 288
  35. 289
  36. 290
  37. 291
  38. 292
  39. 293
  40. 294
  41. 295
  42. 296
  43. 297
  44. 298
var j, m, n; var combinator, tag, id, classList, classes, attributes, pseudos; var currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions; search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){ combinator = 'combinator:' + currentBit.combinator; if (!this[combinator]) continue search; tag = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase(); id = currentBit.id; classList = currentBit.classList; classes = currentBit.classes; attributes = currentBit.attributes; pseudos = currentBit.pseudos; lastBit = (j === (currentExpression.length - 1)); this.bitUniques = {}; if (lastBit){ this.uniques = uniques; this.found = found; } else { this.uniques = {}; this.found = []; } if (j === 0){ this[combinator](context, tag, id, classes, attributes, pseudos, classList); if (first && lastBit && found.length) break search; } else { if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){ this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList); if (found.length) break search; } else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList); } currentItems = this.found; } if (shouldUniques || (parsed.expressions.length > 1)) this.sort(found); return (first) ? (found[0] || null) : found; };

Utils

  1. 302
  2. 303
  3. 304
  4. 305
  5. 306
  6. 307
  7. 308
  8. 309
  9. 310
  10. 311
  11. 312
  12. 313
  13. 314
  14. 315
  15. 316
local.uidx = 1; local.uidk = 'slick:uniqueid'; local.getUIDXML = function(node){ var uid = node.getAttribute(this.uidk); if (!uid){ uid = this.uidx++; node.setAttribute(this.uidk, uid); } return uid; }; local.getUIDHTML = function(node){ return node.uniqueNumber || (node.uniqueNumber = this.uidx++); };

sort based on the setDocument documentSorter method.

  1. 320
  2. 321
  3. 322
  4. 323
  5. 324
local.sort = function(results){ if (!this.documentSorter) return results; results.sort(this.documentSorter); return results; };

  1. 328
  2. 329
  3. 330
  4. 331
  5. 332
  6. 333
  7. 334
  8. 335
  9. 336
  10. 337
  11. 338
  12. 339
  13. 340
  14. 341
  15. 342
  16. 343
  17. 344
  18. 345
  19. 346
  20. 347
  21. 348
  22. 349
  23. 350
  24. 351
  25. 352
  26. 353
  27. 354
  28. 355
  29. 356
  30. 357
  31. 358
  32. 359
  33. 360
  34. 361
  35. 362
  36. 363
  37. 364
  38. 365
  39. 366
  40. 367
  41. 368
  42. 369
  43. 370
  44. 371
  45. 372
  46. 373
  47. 374
  48. 375
  49. 376
  50. 377
  51. 378
  52. 379
local.cacheNTH = {}; local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/; local.parseNTHArgument = function(argument){ var parsed = argument.match(this.matchNTH); if (!parsed) return false; var special = parsed[2] || false; var a = parsed[1] || 1; if (a == '-') a = -1; var b = +parsed[3] || 0; parsed = (special == 'n') ? {a: a, b: b} : (special == 'odd') ? {a: 2, b: 1} : (special == 'even') ? {a: 2, b: 0} : {a: 0, b: a}; return (this.cacheNTH[argument] = parsed); }; local.createNTHPseudo = function(child, sibling, positions, ofType){ return function(node, argument){ var uid = this.getUID(node); if (!this[positions][uid]){ var parent = node.parentNode; if (!parent) return false; var el = parent[child], count = 1; if (ofType){ var nodeName = node.nodeName; do { if (el.nodeName !== nodeName) continue; this[positions][this.getUID(el)] = count++; } while ((el = el[sibling])); } else { do { if (el.nodeType !== 1) continue; this[positions][this.getUID(el)] = count++; } while ((el = el[sibling])); } } argument = argument || 'n'; var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument); if (!parsed) return false; var a = parsed.a, b = parsed.b, pos = this[positions][uid]; if (a == 0) return b == pos; if (a > 0){ if (pos < b) return false; } else { if (b < pos) return false; } return ((pos - b) % a) == 0; }; };

  1. 383
  2. 384
  3. 385
  4. 386
  5. 387
  6. 388
  7. 389
  8. 390
  9. 391
  10. 392
  11. 393
  12. 394
  13. 395
  14. 396
  15. 397
local.pushArray = function(node, tag, id, classes, attributes, pseudos){ if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node); }; local.pushUID = function(node, tag, id, classes, attributes, pseudos){ var uid = this.getUID(node); if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){ this.uniques[uid] = true; this.found.push(node); } }; local.matchNode = function(node, selector){ var parsed = this.Slick.parse(selector); if (!parsed) return true;

simple (single) selectors

  1. 400
  2. 401
  3. 402
  4. 403
  5. 404
  6. 405
  7. 406
  8. 407
  9. 408
  10. 409
  11. 410
  12. 411
  13. 412
  14. 413
  15. 414
  16. 415
  17. 416
  18. 417
  19. 418
  20. 419
  21. 420
  22. 421
  23. 422
  24. 423
  25. 424
  26. 425
  27. 426
  28. 427
  29. 428
  30. 429
  31. 430
  32. 431
  33. 432
  34. 433
  35. 434
  36. 435
  37. 436
  38. 437
  39. 438
  40. 439
  41. 440
  42. 441
  43. 442
  44. 443
  45. 444
  46. 445
  47. 446
  48. 447
  49. 448
  50. 449
  51. 450
  52. 451
  53. 452
  54. 453
  55. 454
  56. 455
if(parsed.length == 1 && parsed.expressions[0].length == 1){ var exp = parsed.expressions[0][0]; return this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos); } var nodes = this.search(this.document, parsed); for (var i = 0, item; item = nodes[i++];){ if (item === node) return true; } return false; }; local.matchPseudo = function(node, name, argument){ var pseudoName = 'pseudo:' + name; if (this[pseudoName]) return this[pseudoName](node, argument); var attribute = this.getAttribute(node, name); return (argument) ? argument == attribute : !!attribute; }; local.matchSelector = function(node, tag, id, classes, attributes, pseudos){ if (tag){ if (tag == '*'){ if (node.nodeName < '@') return false; // Fix for comment nodes and closed nodes } else { if (node.nodeName != tag) return false; } } if (id && node.getAttribute('id') != id) return false; var i, part, cls; if (classes) for (i = classes.length; i--;){ cls = ('className' in node) ? node.className : node.getAttribute('class'); if (!(cls && classes[i].regexp.test(cls))) return false; } if (attributes) for (i = attributes.length; i--;){ part = attributes[i]; if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false; } if (pseudos) for (i = pseudos.length; i--;){ part = pseudos[i]; if (!this.matchPseudo(node, part.key, part.value)) return false; } return true; }; var combinators = { ' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level var i, item, children; if (this.isHTMLDocument){ getById: if (id){ item = this.document.getElementById(id); if ((!item && node.all) || (this.idGetsName && item && item.getAttributeNode('id').nodeValue != id)){

all[id] returns all the elements with that name or id inside node if theres just one it will return the element, else it will be a collection

  1. 458
  2. 459
  3. 460
  4. 461
  5. 462
  6. 463
  7. 464
  8. 465
  9. 466
  10. 467
children = node.all[id]; if (!children) return; if (!children[0]) children = [children]; for (i = 0; item = children[i++];) if (item.getAttributeNode('id').nodeValue == id){ this.push(item, tag, null, classes, attributes, pseudos); break; } return; } if (!item){

if the context is in the dom we return, else we will try GEBTN, breaking the getById label

  1. 469
  2. 470
  3. 471
  4. 472
  5. 473
  6. 474
  7. 475
  8. 476
  9. 477
  10. 478
  11. 479
  12. 480
  13. 481
  14. 482
  15. 483
  16. 484
  17. 485
  18. 486
  19. 487
  20. 488
  21. 489
  22. 490
  23. 491
  24. 492
  25. 493
  26. 494
  27. 495
  28. 496
  29. 497
  30. 498
  31. 499
  32. 500
  33. 501
  34. 502
  35. 503
  36. 504
  37. 505
  38. 506
  39. 507
  40. 508
  41. 509
  42. 510
  43. 511
  44. 512
  45. 513
  46. 514
  47. 515
  48. 516
  49. 517
  50. 518
  51. 519
  52. 520
  53. 521
  54. 522
  55. 523
  56. 524
  57. 525
  58. 526
  59. 527
  60. 528
  61. 529
  62. 530
  63. 531
  64. 532
  65. 533
  66. 534
  67. 535
  68. 536
  69. 537
  70. 538
  71. 539
  72. 540
  73. 541
  74. 542
  75. 543
  76. 544
  77. 545
  78. 546
  79. 547
  80. 548
  81. 549
  82. 550
  83. 551
  84. 552
  85. 553
  86. 554
  87. 555
  88. 556
  89. 557
  90. 558
  91. 559
  92. 560
  93. 561
  94. 562
  95. 563
  96. 564
  97. 565
  98. 566
  99. 567
  100. 568
  101. 569
if (this.contains(this.document.documentElement, node)) return; else break getById; } else if (this.document !== node && !this.contains(node, item)) return; this.push(item, tag, null, classes, attributes, pseudos); return; } getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBCN){ children = node.getElementsByClassName(classList.join(' ')); if (!(children && children.length)) break getByClass; for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos); return; } } getByTag: { children = node.getElementsByTagName(tag); if (!(children && children.length)) break getByTag; if (!this.brokenStarGEBTN) tag = null; for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos); } }, '>': function(node, tag, id, classes, attributes, pseudos){ // direct children if ((node = node.firstChild)) do { if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos); } while ((node = node.nextSibling)); }, '+': function(node, tag, id, classes, attributes, pseudos){ // next sibling while ((node = node.nextSibling)) if (node.nodeType === 1){ this.push(node, tag, id, classes, attributes, pseudos); break; } }, '^': function(node, tag, id, classes, attributes, pseudos){ // first child node = node.firstChild; if (node){ if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos); else this['combinator:+'](node, tag, id, classes, attributes, pseudos); } }, '~': function(node, tag, id, classes, attributes, pseudos){ // next siblings while ((node = node.nextSibling)){ if (node.nodeType !== 1) continue; var uid = this.getUID(node); if (this.bitUniques[uid]) break; this.bitUniques[uid] = true; this.push(node, tag, id, classes, attributes, pseudos); } }, '++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling this['combinator:+'](node, tag, id, classes, attributes, pseudos); this['combinator:!+'](node, tag, id, classes, attributes, pseudos); }, '~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings this['combinator:~'](node, tag, id, classes, attributes, pseudos); this['combinator:!~'](node, tag, id, classes, attributes, pseudos); }, '!': function(node, tag, id, classes, attributes, pseudos){ // all parent nodes up to document while ((node = node.parentNode)) if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos); }, '!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level) node = node.parentNode; if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos); }, '!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling while ((node = node.previousSibling)) if (node.nodeType === 1){ this.push(node, tag, id, classes, attributes, pseudos); break; } }, '!^': function(node, tag, id, classes, attributes, pseudos){ // last child node = node.lastChild; if (node){ if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos); else this['combinator:!+'](node, tag, id, classes, attributes, pseudos); } }, '!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings while ((node = node.previousSibling)){ if (node.nodeType !== 1) continue; var uid = this.getUID(node); if (this.bitUniques[uid]) break; this.bitUniques[uid] = true; this.push(node, tag, id, classes, attributes, pseudos); } } }; for (var c in combinators) local['combinator:' + c] = combinators[c]; var pseudos = {

  1. 573
  2. 574
  3. 575
  4. 576
  5. 577
  6. 578
  7. 579
  8. 580
  9. 581
  10. 582
  11. 583
  12. 584
  13. 585
  14. 586
  15. 587
  16. 588
  17. 589
  18. 590
  19. 591
  20. 592
  21. 593
  22. 594
  23. 595
  24. 596
  25. 597
  26. 598
  27. 599
  28. 600
  29. 601
  30. 602
'empty': function(node){ var child = node.firstChild; return !(child && child.nodeType == 1) && !(node.innerText || node.textContent || '').length; }, 'not': function(node, expression){ return !this.matchNode(node, expression); }, 'contains': function(node, text){ return (node.innerText || node.textContent || '').indexOf(text) > -1; }, 'first-child': function(node){ while ((node = node.previousSibling)) if (node.nodeType === 1) return false; return true; }, 'last-child': function(node){ while ((node = node.nextSibling)) if (node.nodeType === 1) return false; return true; }, 'only-child': function(node){ var prev = node; while ((prev = prev.previousSibling)) if (prev.nodeType === 1) return false; var next = node; while ((next = next.nextSibling)) if (next.nodeType === 1) return false; return true; },

  1. 606
  2. 607
  3. 608
  4. 609
  5. 610
  6. 611
  7. 612
  8. 613
  9. 614
  10. 615
  11. 616
  12. 617
  13. 618
  14. 619
  15. 620
  16. 621
  17. 622
  18. 623
  19. 624
'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'), 'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHLast'), 'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType', true), 'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true), 'index': function(node, index){ return this['pseudo:nth-child'](node, '' + index + 1); }, 'even': function(node, argument){ return this['pseudo:nth-child'](node, '2n'); }, 'odd': function(node, argument){ return this['pseudo:nth-child'](node, '2n+1'); },

  1. 630
  2. 631
  3. 632
  4. 633
  5. 634
  6. 635
  7. 636
  8. 637
  9. 638
  10. 639
  11. 640
  12. 641
  13. 642
  14. 643
  15. 644
  16. 645
  17. 646
  18. 647
  19. 648
'first-of-type': function(node){ var nodeName = node.nodeName; while ((node = node.previousSibling)) if (node.nodeName === nodeName) return false; return true; }, 'last-of-type': function(node){ var nodeName = node.nodeName; while ((node = node.nextSibling)) if (node.nodeName === nodeName) return false; return true; }, 'only-of-type': function(node){ var prev = node, nodeName = node.nodeName; while ((prev = prev.previousSibling)) if (prev.nodeName === nodeName) return false; var next = node; while ((next = next.nextSibling)) if (next.nodeName === nodeName) return false; return true; },

custom pseudos

  1. 654
  2. 655
  3. 656
  4. 657
  5. 658
  6. 659
  7. 660
  8. 661
  9. 662
  10. 663
  11. 664
  12. 665
  13. 666
  14. 667
  15. 668
  16. 669
  17. 670
  18. 671
  19. 672
  20. 673
  21. 674
  22. 675
  23. 676
'enabled': function(node){ return (node.disabled === false); }, 'disabled': function(node){ return (node.disabled === true); }, 'checked': function(node){ return node.checked || node.selected; }, 'focus': function(node){ return this.isHTMLDocument && this.document.activeElement === node && (node.href || node.type || this.hasAttribute(node, 'tabindex')); }, 'root': function(node){ return (node === this.root); }, 'selected': function(node){ return node.selected; }

  1. 679
  2. 680
  3. 681
}; for (var p in pseudos) local['pseudo:' + p] = pseudos[p];

attributes methods

  1. 685
  2. 686
  3. 687
  4. 688
  5. 689
  6. 690
  7. 691
  8. 692
  9. 693
  10. 694
  11. 695
  12. 696
  13. 697
  14. 698
  15. 699
  16. 700
  17. 701
  18. 702
  19. 703
  20. 704
  21. 705
local.attributeGetters = { 'class': function(){ return ('className' in this) ? this.className : this.getAttribute('class'); }, 'for': function(){ return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for'); }, 'href': function(){ return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('href'); }, 'style': function(){ return (this.style) ? this.style.cssText : this.getAttribute('style'); } }; local.getAttribute = function(node, name){

FIXME: check if getAttribute() will get input elements on a form on this browser getAttribute is faster than getAttributeNode().nodeValue

  1. 708
  2. 709
  3. 710
  4. 711
  5. 712
var method = this.attributeGetters[name]; if (method) return method.call(node); var attributeNode = node.getAttributeNode(name); return attributeNode ? attributeNode.nodeValue : null; };

overrides

  1. 716
  2. 717
  3. 718
  4. 719
  5. 720
local.overrides = []; local.override = function(regexp, method){ this.overrides.push({regexp: regexp, method: method}); };

  1. 726
  2. 727
  3. 728
  4. 729
  5. 730
  6. 731
  7. 732
  8. 733
  9. 734
  10. 735
  11. 736
  12. 737
  13. 738
  14. 739
  15. 740
  16. 741
  17. 742
  18. 743
  19. 744
  20. 745
  21. 746
  22. 747
  23. 748
  24. 749
  25. 750
  26. 751
  27. 752
  28. 753
  29. 754
var reEmptyAttribute = /\[.*[*$^]=(?:["']{2})?\]/; local.override(/./, function(expression, found, first){ //querySelectorAll override if (!this.querySelectorAll || this.nodeType != 9 || !local.isHTMLDocument || local.brokenMixedCaseQSA || (local.brokenCheckedQSA && expression.indexOf(':checked') > -1) || (local.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression)) || Slick.disableQSA) return false; var nodes, node; try { if (first) return this.querySelector(expression) || null; else nodes = this.querySelectorAll(expression); } catch(error){ return false; } var i, hasOthers = !!(found.length); if (local.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){ if (node.nodeName > '@' && (!hasOthers || !local.uniques[local.getUIDHTML(node)])) found.push(node); } else for (i = 0; node = nodes[i++];){ if (!hasOthers || !local.uniques[local.getUIDHTML(node)]) found.push(node); } if (hasOthers) local.sort(found); return true; });

  1. 760
  2. 761
  3. 762
  4. 763
  5. 764
  6. 765
  7. 766
  8. 767
  9. 768
  10. 769
  11. 770
  12. 771
  13. 772
  14. 773
  15. 774
  16. 775
  17. 776
local.override(/^[\w-]+$|^\*$/, function(expression, found, first){ // tag override var tag = expression; if (tag == '*' && local.brokenStarGEBTN) return false; var nodes = this.getElementsByTagName(tag); if (first) return nodes[0] || null; var i, node, hasOthers = !!(found.length); for (i = 0; node = nodes[i++];){ if (!hasOthers || !local.uniques[local.getUID(node)]) found.push(node); } if (hasOthers) local.sort(found); return true; });

  1. 782
  2. 783
  3. 784
  4. 785
  5. 786
  6. 787
  7. 788
  8. 789
  9. 790
  10. 791
  11. 792
  12. 793
  13. 794
  14. 795
  15. 796
  16. 797
  17. 798
  18. 799
  19. 800
  20. 801
  21. 802
  22. 803
  23. 804
local.override(/^\.[\w-]+$/, function(expression, found, first){ // class override if (!local.isHTMLDocument || (!this.getElementsByClassName && this.querySelectorAll)) return false; var nodes, node, i, hasOthers = !!(found && found.length), className = expression.substring(1); if (this.getElementsByClassName && !local.brokenGEBCN){ nodes = this.getElementsByClassName(className); if (first) return nodes[0] || null; for (i = 0; node = nodes[i++];){ if (!hasOthers || !local.uniques[local.getUIDHTML(node)]) found.push(node); } } else { var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(className) +'(\\s|$)'); nodes = this.getElementsByTagName('*'); for (i = 0; node = nodes[i++];){ className = node.className; if (!className || !matchClass.test(className)) continue; if (first) return node; if (!hasOthers || !local.uniques[local.getUIDHTML(node)]) found.push(node); } } if (hasOthers) local.sort(found); return (first) ? null : true; });

  1. 810
  2. 811
  3. 812
  4. 813
  5. 814
  6. 815
  7. 816
  8. 817
  9. 818
  10. 819
  11. 820
  12. 821
local.override(/^#[\w-]+$/, function(expression, found, first){ // ID override if (!local.isHTMLDocument || this.nodeType != 9) return false; var id = expression.substring(1), el = this.getElementById(id); if (!el) return found; if (local.idGetsName && el.getAttributeNode('id').nodeValue != id) return false; if (first) return el || null; var hasOthers = !!(found.length); if (!hasOthers || !local.uniques[local.getUIDHTML(el)]) found.push(el); if (hasOthers) local.sort(found); return true; });

  1. 827
if (typeof document != 'undefined') local.setDocument(document);

Slick

  1. 831
  2. 832
  3. 833
var Slick = local.Slick = (this.Slick || {}); Slick.version = '0.9dev';

Slick finder

  1. 837
  2. 838
  3. 839
  4. 840
  5. 841
  6. 842
  7. 843
Slick.search = function(context, expression, append){ return local.search(context, expression, append); }; Slick.find = function(context, expression){ return local.search(context, expression, null, true); };

Slick containment checker

  1. 847
  2. 848
  3. 849
  4. 850
Slick.contains = function(container, node){ local.setDocument(container); return local.contains(container, node); };

Slick attribute getter

  1. 854
  2. 855
  3. 856
Slick.getAttribute = function(node, name){ return local.getAttribute(node, name); };

Slick matcher

  1. 860
  2. 861
  3. 862
  4. 863
  5. 864
  6. 865
  7. 866
Slick.match = function(node, selector){ if (!(node && selector)) return false; if (!selector || selector === node) return true; if (typeof selector != 'string') return false; local.setDocument(node); return local.matchNode(node, selector); };

Slick attribute accessor

  1. 870
  2. 871
  3. 872
  4. 873
  5. 874
  6. 875
  7. 876
  8. 877
Slick.defineAttributeGetter = function(name, fn){ local.attributeGetters[name] = fn; return this; }; Slick.lookupAttributeGetter = function(name){ return local.attributeGetters[name]; };

Slick pseudo accessor

  1. 881
  2. 882
  3. 883
  4. 884
  5. 885
  6. 886
  7. 887
  8. 888
  9. 889
  10. 890
  11. 891
  12. 892
  13. 893
  14. 894
Slick.definePseudo = function(name, fn){ local['pseudo:' + name] = function(node, argument){ return fn.call(node, argument); }; return this; }; Slick.lookupPseudo = function(name){ var pseudo = local['pseudo:' + name]; if (pseudo) return function(argument){ return pseudo.call(this, argument); }; return null; };

Slick overrides accessor

  1. 898
  2. 899
  3. 900
  4. 901
  5. 902
  6. 903
  7. 904
  8. 905
  9. 906
  10. 907
  11. 908
  12. 909
  13. 910
  14. 911
Slick.override = function(regexp, fn){ local.override(regexp, fn); return this; }; Slick.isXML = local.isXML; Slick.uidOf = function(node){ return local.getUIDHTML(node); }; if (!this.Slick) this.Slick = Slick; }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);