fix
This commit is contained in:
1
book/node_modules/slick/.npmignore
generated
vendored
Normal file
1
book/node_modules/slick/.npmignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.jshintrc
|
||||
106
book/node_modules/slick/README.md
generated
vendored
Normal file
106
book/node_modules/slick/README.md
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
# Slick
|
||||
|
||||
Slick is a standalone selector engine that is totally slick.
|
||||
Slick is split in 2 components: the Finder and the Parser. The Finder's job is to find nodes on a webpage, the Parser's job is to create a javascript object representation of any css selector.
|
||||
|
||||
Slick allows you to:
|
||||
|
||||
* Create your own custom pseudo-classes
|
||||
* Use the Parser by itself.
|
||||
* Find nodes in XML documents.
|
||||
|
||||
---
|
||||
|
||||
## The Finder
|
||||
|
||||
Find nodes in the DOM
|
||||
|
||||
### `search` context for selector
|
||||
|
||||
Search this context for any nodes that match this selector.
|
||||
|
||||
Expects:
|
||||
* selector: String or SelectorObject
|
||||
* (**optional**) context: document or node or array of documents or nodes
|
||||
* (**optional**) append: Array or Object with a push method
|
||||
|
||||
Returns: append argument or Array of 0 or more nodes
|
||||
|
||||
slick.search("#foo > bar.baz") → [<bar>, <bar>, <bar>]
|
||||
slick.search("li > a", [<ol>, <ul>]) → [<a>, <a>, <a>]
|
||||
slick.search("#foo > bar.baz", document, []) → [<bar>, <bar>, <bar>]
|
||||
|
||||
### `find` first in context with selector or null
|
||||
|
||||
Find the first node in document that matches selector or null if none are found.
|
||||
|
||||
Expects:
|
||||
* selector: String or SelectorObject
|
||||
* (**optional**) context: document or node or array of documents or nodes
|
||||
|
||||
Returns: Element or null
|
||||
|
||||
slick.find("#foo > bar.baz") → <bar>
|
||||
slick.find("#does-not-exist", node) → null
|
||||
|
||||
### node `matches` selector?
|
||||
|
||||
Does this node match this selector?
|
||||
|
||||
Expects:
|
||||
* node
|
||||
* node, String or SelectorObject
|
||||
|
||||
Returns: true or false
|
||||
|
||||
slick.matches(<div class=rocks>, "div.rocks") → true
|
||||
slick.matches(<div class=lame>, "div.rocks") → false
|
||||
slick.matches(<div class=lame>, <div class=rocks>) → false
|
||||
|
||||
### context `contains` node?
|
||||
|
||||
Does this context contain this node? Is the context a parent of this node?
|
||||
|
||||
Expects:
|
||||
* context: document or node
|
||||
* node: node
|
||||
|
||||
Returns: true or false
|
||||
|
||||
slick.contains(<ul>, <li>) → true
|
||||
slick.contains(<body>, <html>) → false
|
||||
|
||||
---
|
||||
|
||||
## The Parser
|
||||
|
||||
Parse a CSS selector string into a JavaScript object
|
||||
|
||||
### `parse` selector into object
|
||||
|
||||
Parse a CSS Selector String into a Selector Object.
|
||||
|
||||
Expects: String
|
||||
|
||||
Returns: SelectorObject
|
||||
|
||||
slick.parse("#foo > bar.baz") → SelectorObject
|
||||
|
||||
|
||||
### format
|
||||
|
||||
### `#foo > bar.baz`
|
||||
|
||||
[[
|
||||
{ "combinator":" ", "tag":"*", "id":"foo" },
|
||||
{ "combinator":">", "tag":"bar", "classList": ["baz"], "classes": [{"value":"baz", "match": RegExp }]}
|
||||
]]
|
||||
|
||||
### `h1, h2, ul > li, .things`
|
||||
|
||||
[
|
||||
[{ "combinator":" ", "tag": "h1" }],
|
||||
[{ "combinator":" ", "tag": "h2" }],
|
||||
[{ "combinator":" ", "tag": "ul" }, { "combinator": ">", "tag": "li" }],
|
||||
[{ "combinator":" ", "tag": "*", "classList": ["things"], "classes": [{"value": "things", "match": RegExp }] }]
|
||||
]
|
||||
829
book/node_modules/slick/finder.js
generated
vendored
Normal file
829
book/node_modules/slick/finder.js
generated
vendored
Normal file
@@ -0,0 +1,829 @@
|
||||
/*
|
||||
Slick Finder
|
||||
*/"use strict"
|
||||
|
||||
// Notable changes from Slick.Finder 1.0.x
|
||||
|
||||
// faster bottom -> up expression matching
|
||||
// prefers mental sanity over *obsessive compulsive* milliseconds savings
|
||||
// uses prototypes instead of objects
|
||||
// tries to use matchesSelector smartly, whenever available
|
||||
// can populate objects as well as arrays
|
||||
// lots of stuff is broken or not implemented
|
||||
|
||||
var parse = require("./parser")
|
||||
|
||||
// utilities
|
||||
|
||||
var index = 0,
|
||||
counter = document.__counter = (parseInt(document.__counter || -1, 36) + 1).toString(36),
|
||||
key = "uid:" + counter
|
||||
|
||||
var uniqueID = function(n, xml){
|
||||
if (n === window) return "window"
|
||||
if (n === document) return "document"
|
||||
if (n === document.documentElement) return "html"
|
||||
|
||||
if (xml) {
|
||||
var uid = n.getAttribute(key)
|
||||
if (!uid) {
|
||||
uid = (index++).toString(36)
|
||||
n.setAttribute(key, uid)
|
||||
}
|
||||
return uid
|
||||
} else {
|
||||
return n[key] || (n[key] = (index++).toString(36))
|
||||
}
|
||||
}
|
||||
|
||||
var uniqueIDXML = function(n) {
|
||||
return uniqueID(n, true)
|
||||
}
|
||||
|
||||
var isArray = Array.isArray || function(object){
|
||||
return Object.prototype.toString.call(object) === "[object Array]"
|
||||
}
|
||||
|
||||
// tests
|
||||
|
||||
var uniqueIndex = 0;
|
||||
|
||||
var HAS = {
|
||||
|
||||
GET_ELEMENT_BY_ID: function(test, id){
|
||||
id = "slick_" + (uniqueIndex++);
|
||||
// checks if the document has getElementById, and it works
|
||||
test.innerHTML = '<a id="' + id + '"></a>'
|
||||
return !!this.getElementById(id)
|
||||
},
|
||||
|
||||
QUERY_SELECTOR: function(test){
|
||||
// this supposedly fixes a webkit bug with matchesSelector / querySelector & nth-child
|
||||
test.innerHTML = '_<style>:nth-child(2){}</style>'
|
||||
|
||||
// checks if the document has querySelectorAll, and it works
|
||||
test.innerHTML = '<a class="MiX"></a>'
|
||||
|
||||
return test.querySelectorAll('.MiX').length === 1
|
||||
},
|
||||
|
||||
EXPANDOS: function(test, id){
|
||||
id = "slick_" + (uniqueIndex++);
|
||||
// checks if the document has elements that support expandos
|
||||
test._custom_property_ = id
|
||||
return test._custom_property_ === id
|
||||
},
|
||||
|
||||
// TODO: use this ?
|
||||
|
||||
// CHECKED_QUERY_SELECTOR: function(test){
|
||||
//
|
||||
// // checks if the document supports the checked query selector
|
||||
// test.innerHTML = '<select><option selected="selected">a</option></select>'
|
||||
// return test.querySelectorAll(':checked').length === 1
|
||||
// },
|
||||
|
||||
// TODO: use this ?
|
||||
|
||||
// EMPTY_ATTRIBUTE_QUERY_SELECTOR: function(test){
|
||||
//
|
||||
// // checks if the document supports the empty attribute query selector
|
||||
// test.innerHTML = '<a class=""></a>'
|
||||
// return test.querySelectorAll('[class*=""]').length === 1
|
||||
// },
|
||||
|
||||
MATCHES_SELECTOR: function(test){
|
||||
|
||||
test.className = "MiX"
|
||||
|
||||
// checks if the document has matchesSelector, and we can use it.
|
||||
|
||||
var matches = test.matchesSelector || test.mozMatchesSelector || test.webkitMatchesSelector
|
||||
|
||||
// if matchesSelector trows errors on incorrect syntax we can use it
|
||||
if (matches) try {
|
||||
matches.call(test, ':slick')
|
||||
} catch(e){
|
||||
// just as a safety precaution, also test if it works on mixedcase (like querySelectorAll)
|
||||
return matches.call(test, ".MiX") ? matches : false
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
|
||||
GET_ELEMENTS_BY_CLASS_NAME: function(test){
|
||||
test.innerHTML = '<a class="f"></a><a class="b"></a>'
|
||||
if (test.getElementsByClassName('b').length !== 1) return false
|
||||
|
||||
test.firstChild.className = 'b'
|
||||
if (test.getElementsByClassName('b').length !== 2) return false
|
||||
|
||||
// Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one
|
||||
test.innerHTML = '<a class="a"></a><a class="f b a"></a>'
|
||||
if (test.getElementsByClassName('a').length !== 2) return false
|
||||
|
||||
// tests passed
|
||||
return true
|
||||
},
|
||||
|
||||
// no need to know
|
||||
|
||||
// GET_ELEMENT_BY_ID_NOT_NAME: function(test, id){
|
||||
// test.innerHTML = '<a name="'+ id +'"></a><b id="'+ id +'"></b>'
|
||||
// return this.getElementById(id) !== test.firstChild
|
||||
// },
|
||||
|
||||
// this is always checked for and fixed
|
||||
|
||||
// STAR_GET_ELEMENTS_BY_TAG_NAME: function(test){
|
||||
//
|
||||
// // IE returns comment nodes for getElementsByTagName('*') for some documents
|
||||
// test.appendChild(this.createComment(''))
|
||||
// if (test.getElementsByTagName('*').length > 0) return false
|
||||
//
|
||||
// // IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for some documents
|
||||
// test.innerHTML = 'foo</foo>'
|
||||
// if (test.getElementsByTagName('*').length) return false
|
||||
//
|
||||
// // tests passed
|
||||
// return true
|
||||
// },
|
||||
|
||||
// this is always checked for and fixed
|
||||
|
||||
// STAR_QUERY_SELECTOR: function(test){
|
||||
//
|
||||
// // returns closed nodes (EG:"</foo>") for querySelector('*') for some documents
|
||||
// test.innerHTML = 'foo</foo>'
|
||||
// return !!(test.querySelectorAll('*').length)
|
||||
// },
|
||||
|
||||
GET_ATTRIBUTE: function(test){
|
||||
// tests for working getAttribute implementation
|
||||
var shout = "fus ro dah"
|
||||
test.innerHTML = '<a class="' + shout + '"></a>'
|
||||
return test.firstChild.getAttribute('class') === shout
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Finder
|
||||
|
||||
var Finder = function Finder(document){
|
||||
|
||||
this.document = document
|
||||
var root = this.root = document.documentElement
|
||||
this.tested = {}
|
||||
|
||||
// uniqueID
|
||||
|
||||
this.uniqueID = this.has("EXPANDOS") ? uniqueID : uniqueIDXML
|
||||
|
||||
// getAttribute
|
||||
|
||||
this.getAttribute = (this.has("GET_ATTRIBUTE")) ? function(node, name){
|
||||
|
||||
return node.getAttribute(name)
|
||||
|
||||
} : function(node, name){
|
||||
|
||||
node = node.getAttributeNode(name)
|
||||
return (node && node.specified) ? node.value : null
|
||||
|
||||
}
|
||||
|
||||
// hasAttribute
|
||||
|
||||
this.hasAttribute = (root.hasAttribute) ? function(node, attribute){
|
||||
|
||||
return node.hasAttribute(attribute)
|
||||
|
||||
} : function(node, attribute) {
|
||||
|
||||
node = node.getAttributeNode(attribute)
|
||||
return !!(node && node.specified)
|
||||
|
||||
}
|
||||
|
||||
// contains
|
||||
|
||||
this.contains = (document.contains && root.contains) ? function(context, node){
|
||||
|
||||
return context.contains(node)
|
||||
|
||||
} : (root.compareDocumentPosition) ? function(context, node){
|
||||
|
||||
return context === node || !!(context.compareDocumentPosition(node) & 16)
|
||||
|
||||
} : function(context, node){
|
||||
|
||||
do {
|
||||
if (node === context) return true
|
||||
} while ((node = node.parentNode))
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// sort
|
||||
// credits to Sizzle (http://sizzlejs.com/)
|
||||
|
||||
this.sorter = (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.failed = {}
|
||||
|
||||
var nativeMatches = this.has("MATCHES_SELECTOR")
|
||||
|
||||
if (nativeMatches) this.matchesSelector = function(node, expression){
|
||||
|
||||
if (this.failed[expression]) return null
|
||||
|
||||
try {
|
||||
return nativeMatches.call(node, expression)
|
||||
} catch(e){
|
||||
if (slick.debug) console.warn("matchesSelector failed on " + expression)
|
||||
this.failed[expression] = true
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this.has("QUERY_SELECTOR")){
|
||||
|
||||
this.querySelectorAll = function(node, expression){
|
||||
|
||||
if (this.failed[expression]) return true
|
||||
|
||||
var result, _id, _expression, _combinator, _node
|
||||
|
||||
|
||||
// non-document rooted QSA
|
||||
// credits to Andrew Dupont
|
||||
|
||||
if (node !== this.document){
|
||||
|
||||
_combinator = expression[0].combinator
|
||||
|
||||
_id = node.getAttribute("id")
|
||||
_expression = expression
|
||||
|
||||
if (!_id){
|
||||
_node = node
|
||||
_id = "__slick__"
|
||||
_node.setAttribute("id", _id)
|
||||
}
|
||||
|
||||
expression = "#" + _id + " " + _expression
|
||||
|
||||
|
||||
// these combinators need a parentNode due to how querySelectorAll works, which is:
|
||||
// finding all the elements that match the given selector
|
||||
// then filtering by the ones that have the specified element as an ancestor
|
||||
if (_combinator.indexOf("~") > -1 || _combinator.indexOf("+") > -1){
|
||||
|
||||
node = node.parentNode
|
||||
if (!node) result = true
|
||||
// if node has no parentNode, we return "true" as if it failed, without polluting the failed cache
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!result) try {
|
||||
result = node.querySelectorAll(expression.toString())
|
||||
} catch(e){
|
||||
if (slick.debug) console.warn("querySelectorAll failed on " + (_expression || expression))
|
||||
result = this.failed[_expression || expression] = true
|
||||
}
|
||||
|
||||
if (_node) _node.removeAttribute("id")
|
||||
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Finder.prototype.has = function(FEATURE){
|
||||
|
||||
var tested = this.tested,
|
||||
testedFEATURE = tested[FEATURE]
|
||||
|
||||
if (testedFEATURE != null) return testedFEATURE
|
||||
|
||||
var root = this.root,
|
||||
document = this.document,
|
||||
testNode = document.createElement("div")
|
||||
|
||||
testNode.setAttribute("style", "display: none;")
|
||||
|
||||
root.appendChild(testNode)
|
||||
|
||||
var TEST = HAS[FEATURE], result = false
|
||||
|
||||
if (TEST) try {
|
||||
result = TEST.call(document, testNode)
|
||||
} catch(e){}
|
||||
|
||||
if (slick.debug && !result) console.warn("document has no " + FEATURE)
|
||||
|
||||
root.removeChild(testNode)
|
||||
|
||||
return tested[FEATURE] = result
|
||||
|
||||
}
|
||||
|
||||
var combinators = {
|
||||
|
||||
" ": function(node, part, push){
|
||||
|
||||
var item, items
|
||||
|
||||
var noId = !part.id, noTag = !part.tag, noClass = !part.classes
|
||||
|
||||
if (part.id && node.getElementById && this.has("GET_ELEMENT_BY_ID")){
|
||||
item = node.getElementById(part.id)
|
||||
|
||||
// return only if id is found, else keep checking
|
||||
// might be a tad slower on non-existing ids, but less insane
|
||||
|
||||
if (item && item.getAttribute('id') === part.id){
|
||||
items = [item]
|
||||
noId = true
|
||||
// if tag is star, no need to check it in match()
|
||||
if (part.tag === "*") noTag = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!items){
|
||||
|
||||
if (part.classes && node.getElementsByClassName && this.has("GET_ELEMENTS_BY_CLASS_NAME")){
|
||||
items = node.getElementsByClassName(part.classList)
|
||||
noClass = true
|
||||
// if tag is star, no need to check it in match()
|
||||
if (part.tag === "*") noTag = true
|
||||
} else {
|
||||
items = node.getElementsByTagName(part.tag)
|
||||
// if tag is star, need to check it in match because it could select junk, boho
|
||||
if (part.tag !== "*") noTag = true
|
||||
}
|
||||
|
||||
if (!items || !items.length) return false
|
||||
|
||||
}
|
||||
|
||||
for (var i = 0; item = items[i++];)
|
||||
if ((noTag && noId && noClass && !part.attributes && !part.pseudos) || this.match(item, part, noTag, noId, noClass))
|
||||
push(item)
|
||||
|
||||
return true
|
||||
|
||||
},
|
||||
|
||||
">": function(node, part, push){ // direct children
|
||||
if ((node = node.firstChild)) do {
|
||||
if (node.nodeType == 1 && this.match(node, part)) push(node)
|
||||
} while ((node = node.nextSibling))
|
||||
},
|
||||
|
||||
"+": function(node, part, push){ // next sibling
|
||||
while ((node = node.nextSibling)) if (node.nodeType == 1){
|
||||
if (this.match(node, part)) push(node)
|
||||
break
|
||||
}
|
||||
},
|
||||
|
||||
"^": function(node, part, push){ // first child
|
||||
node = node.firstChild
|
||||
if (node){
|
||||
if (node.nodeType === 1){
|
||||
if (this.match(node, part)) push(node)
|
||||
} else {
|
||||
combinators['+'].call(this, node, part, push)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"~": function(node, part, push){ // next siblings
|
||||
while ((node = node.nextSibling)){
|
||||
if (node.nodeType === 1 && this.match(node, part)) push(node)
|
||||
}
|
||||
},
|
||||
|
||||
"++": function(node, part, push){ // next sibling and previous sibling
|
||||
combinators['+'].call(this, node, part, push)
|
||||
combinators['!+'].call(this, node, part, push)
|
||||
},
|
||||
|
||||
"~~": function(node, part, push){ // next siblings and previous siblings
|
||||
combinators['~'].call(this, node, part, push)
|
||||
combinators['!~'].call(this, node, part, push)
|
||||
},
|
||||
|
||||
"!": function(node, part, push){ // all parent nodes up to document
|
||||
while ((node = node.parentNode)) if (node !== this.document && this.match(node, part)) push(node)
|
||||
},
|
||||
|
||||
"!>": function(node, part, push){ // direct parent (one level)
|
||||
node = node.parentNode
|
||||
if (node !== this.document && this.match(node, part)) push(node)
|
||||
},
|
||||
|
||||
"!+": function(node, part, push){ // previous sibling
|
||||
while ((node = node.previousSibling)) if (node.nodeType == 1){
|
||||
if (this.match(node, part)) push(node)
|
||||
break
|
||||
}
|
||||
},
|
||||
|
||||
"!^": function(node, part, push){ // last child
|
||||
node = node.lastChild
|
||||
if (node){
|
||||
if (node.nodeType == 1){
|
||||
if (this.match(node, part)) push(node)
|
||||
} else {
|
||||
combinators['!+'].call(this, node, part, push)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"!~": function(node, part, push){ // previous siblings
|
||||
while ((node = node.previousSibling)){
|
||||
if (node.nodeType === 1 && this.match(node, part)) push(node)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Finder.prototype.search = function(context, expression, found){
|
||||
|
||||
if (!context) context = this.document
|
||||
else if (!context.nodeType && context.document) context = context.document
|
||||
|
||||
var expressions = parse(expression)
|
||||
|
||||
// no expressions were parsed. todo: is this really necessary?
|
||||
if (!expressions || !expressions.length) throw new Error("invalid expression")
|
||||
|
||||
if (!found) found = []
|
||||
|
||||
var uniques, push = isArray(found) ? function(node){
|
||||
found[found.length] = node
|
||||
} : function(node){
|
||||
found[found.length++] = node
|
||||
}
|
||||
|
||||
// if there is more than one expression we need to check for duplicates when we push to found
|
||||
// this simply saves the old push and wraps it around an uid dupe check.
|
||||
if (expressions.length > 1){
|
||||
uniques = {}
|
||||
var plush = push
|
||||
push = function(node){
|
||||
var uid = uniqueID(node)
|
||||
if (!uniques[uid]){
|
||||
uniques[uid] = true
|
||||
plush(node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// walker
|
||||
|
||||
var node, nodes, part
|
||||
|
||||
main: for (var i = 0; expression = expressions[i++];){
|
||||
|
||||
// querySelector
|
||||
|
||||
// TODO: more functional tests
|
||||
|
||||
// if there is querySelectorAll (and the expression does not fail) use it.
|
||||
if (!slick.noQSA && this.querySelectorAll){
|
||||
|
||||
nodes = this.querySelectorAll(context, expression)
|
||||
if (nodes !== true){
|
||||
if (nodes && nodes.length) for (var j = 0; node = nodes[j++];) if (node.nodeName > '@'){
|
||||
push(node)
|
||||
}
|
||||
continue main
|
||||
}
|
||||
}
|
||||
|
||||
// if there is only one part in the expression we don't need to check each part for duplicates.
|
||||
// todo: this might be too naive. while solid, there can be expression sequences that do not
|
||||
// produce duplicates. "body div" for instance, can never give you each div more than once.
|
||||
// "body div a" on the other hand might.
|
||||
if (expression.length === 1){
|
||||
|
||||
part = expression[0]
|
||||
combinators[part.combinator].call(this, context, part, push)
|
||||
|
||||
} else {
|
||||
|
||||
var cs = [context], c, f, u, p = function(node){
|
||||
var uid = uniqueID(node)
|
||||
if (!u[uid]){
|
||||
u[uid] = true
|
||||
f[f.length] = node
|
||||
}
|
||||
}
|
||||
|
||||
// loop the expression parts
|
||||
for (var j = 0; part = expression[j++];){
|
||||
f = []; u = {}
|
||||
// loop the contexts
|
||||
for (var k = 0; c = cs[k++];) combinators[part.combinator].call(this, c, part, p)
|
||||
// nothing was found, the expression failed, continue to the next expression.
|
||||
if (!f.length) continue main
|
||||
cs = f // set the contexts for future parts (if any)
|
||||
}
|
||||
|
||||
if (i === 0) found = f // first expression. directly set found.
|
||||
else for (var l = 0; l < f.length; l++) push(f[l]) // any other expression needs to push to found.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (uniques && found && found.length > 1) this.sort(found)
|
||||
|
||||
return found
|
||||
|
||||
}
|
||||
|
||||
Finder.prototype.sort = function(nodes){
|
||||
return this.sorter ? Array.prototype.sort.call(nodes, this.sorter) : nodes
|
||||
}
|
||||
|
||||
// TODO: most of these pseudo selectors include <html> and qsa doesnt. fixme.
|
||||
|
||||
var pseudos = {
|
||||
|
||||
|
||||
// TODO: returns different results than qsa empty.
|
||||
|
||||
'empty': function(){
|
||||
return !(this && this.nodeType === 1) && !(this.innerText || this.textContent || '').length
|
||||
},
|
||||
|
||||
'not': function(expression){
|
||||
return !slick.matches(this, expression)
|
||||
},
|
||||
|
||||
'contains': function(text){
|
||||
return (this.innerText || this.textContent || '').indexOf(text) > -1
|
||||
},
|
||||
|
||||
'first-child': function(){
|
||||
var node = this
|
||||
while ((node = node.previousSibling)) if (node.nodeType == 1) return false
|
||||
return true
|
||||
},
|
||||
|
||||
'last-child': function(){
|
||||
var node = this
|
||||
while ((node = node.nextSibling)) if (node.nodeType == 1) return false
|
||||
return true
|
||||
},
|
||||
|
||||
'only-child': function(){
|
||||
var prev = this
|
||||
while ((prev = prev.previousSibling)) if (prev.nodeType == 1) return false
|
||||
|
||||
var next = this
|
||||
while ((next = next.nextSibling)) if (next.nodeType == 1) return false
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
'first-of-type': function(){
|
||||
var node = this, nodeName = node.nodeName
|
||||
while ((node = node.previousSibling)) if (node.nodeName == nodeName) return false
|
||||
return true
|
||||
},
|
||||
|
||||
'last-of-type': function(){
|
||||
var node = this, nodeName = node.nodeName
|
||||
while ((node = node.nextSibling)) if (node.nodeName == nodeName) return false
|
||||
return true
|
||||
},
|
||||
|
||||
'only-of-type': function(){
|
||||
var prev = this, nodeName = this.nodeName
|
||||
while ((prev = prev.previousSibling)) if (prev.nodeName == nodeName) return false
|
||||
var next = this
|
||||
while ((next = next.nextSibling)) if (next.nodeName == nodeName) return false
|
||||
return true
|
||||
},
|
||||
|
||||
'enabled': function(){
|
||||
return !this.disabled
|
||||
},
|
||||
|
||||
'disabled': function(){
|
||||
return this.disabled
|
||||
},
|
||||
|
||||
'checked': function(){
|
||||
return this.checked || this.selected
|
||||
},
|
||||
|
||||
'selected': function(){
|
||||
return this.selected
|
||||
},
|
||||
|
||||
'focus': function(){
|
||||
var doc = this.ownerDocument
|
||||
return doc.activeElement === this && (this.href || this.type || slick.hasAttribute(this, 'tabindex'))
|
||||
},
|
||||
|
||||
'root': function(){
|
||||
return (this === this.ownerDocument.documentElement)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Finder.prototype.match = function(node, bit, noTag, noId, noClass){
|
||||
|
||||
// TODO: more functional tests ?
|
||||
|
||||
if (!slick.noQSA && this.matchesSelector){
|
||||
var matches = this.matchesSelector(node, bit)
|
||||
if (matches !== null) return matches
|
||||
}
|
||||
|
||||
// normal matching
|
||||
|
||||
if (!noTag && bit.tag){
|
||||
|
||||
var nodeName = node.nodeName.toLowerCase()
|
||||
if (bit.tag === "*"){
|
||||
if (nodeName < "@") return false
|
||||
} else if (nodeName != bit.tag){
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!noId && bit.id && node.getAttribute('id') !== bit.id) return false
|
||||
|
||||
var i, part
|
||||
|
||||
if (!noClass && bit.classes){
|
||||
|
||||
var className = this.getAttribute(node, "class")
|
||||
if (!className) return false
|
||||
|
||||
for (part in bit.classes) if (!RegExp('(^|\\s)' + bit.classes[part] + '(\\s|$)').test(className)) return false
|
||||
}
|
||||
|
||||
var name, value
|
||||
|
||||
if (bit.attributes) for (i = 0; part = bit.attributes[i++];){
|
||||
|
||||
var operator = part.operator,
|
||||
escaped = part.escapedValue
|
||||
|
||||
name = part.name
|
||||
value = part.value
|
||||
|
||||
if (!operator){
|
||||
|
||||
if (!this.hasAttribute(node, name)) return false
|
||||
|
||||
} else {
|
||||
|
||||
var actual = this.getAttribute(node, name)
|
||||
if (actual == null) return false
|
||||
|
||||
switch (operator){
|
||||
case '^=' : if (!RegExp( '^' + escaped ).test(actual)) return false; break
|
||||
case '$=' : if (!RegExp( escaped + '$' ).test(actual)) return false; break
|
||||
case '~=' : if (!RegExp('(^|\\s)' + escaped + '(\\s|$)').test(actual)) return false; break
|
||||
case '|=' : if (!RegExp( '^' + escaped + '(-|$)' ).test(actual)) return false; break
|
||||
|
||||
case '=' : if (actual !== value) return false; break
|
||||
case '*=' : if (actual.indexOf(value) === -1) return false; break
|
||||
default : return false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (bit.pseudos) for (i = 0; part = bit.pseudos[i++];){
|
||||
|
||||
name = part.name
|
||||
value = part.value
|
||||
|
||||
if (pseudos[name]) return pseudos[name].call(node, value)
|
||||
|
||||
if (value != null){
|
||||
if (this.getAttribute(node, name) !== value) return false
|
||||
} else {
|
||||
if (!this.hasAttribute(node, name)) return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
Finder.prototype.matches = function(node, expression){
|
||||
|
||||
var expressions = parse(expression)
|
||||
|
||||
if (expressions.length === 1 && expressions[0].length === 1){ // simplest match
|
||||
return this.match(node, expressions[0][0])
|
||||
}
|
||||
|
||||
// TODO: more functional tests ?
|
||||
|
||||
if (!slick.noQSA && this.matchesSelector){
|
||||
var matches = this.matchesSelector(node, expressions)
|
||||
if (matches !== null) return matches
|
||||
}
|
||||
|
||||
var nodes = this.search(this.document, expression, {length: 0})
|
||||
|
||||
for (var i = 0, res; res = nodes[i++];) if (node === res) return true
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
var finders = {}
|
||||
|
||||
var finder = function(context){
|
||||
var doc = context || document
|
||||
if (doc.ownerDocument) doc = doc.ownerDocument
|
||||
else if (doc.document) doc = doc.document
|
||||
|
||||
if (doc.nodeType !== 9) throw new TypeError("invalid document")
|
||||
|
||||
var uid = uniqueID(doc)
|
||||
return finders[uid] || (finders[uid] = new Finder(doc))
|
||||
}
|
||||
|
||||
// ... API ...
|
||||
|
||||
var slick = function(expression, context){
|
||||
return slick.search(expression, context)
|
||||
}
|
||||
|
||||
slick.search = function(expression, context, found){
|
||||
return finder(context).search(context, expression, found)
|
||||
}
|
||||
|
||||
slick.find = function(expression, context){
|
||||
return finder(context).search(context, expression)[0] || null
|
||||
}
|
||||
|
||||
slick.getAttribute = function(node, name){
|
||||
return finder(node).getAttribute(node, name)
|
||||
}
|
||||
|
||||
slick.hasAttribute = function(node, name){
|
||||
return finder(node).hasAttribute(node, name)
|
||||
}
|
||||
|
||||
slick.contains = function(context, node){
|
||||
return finder(context).contains(context, node)
|
||||
}
|
||||
|
||||
slick.matches = function(node, expression){
|
||||
return finder(node).matches(node, expression)
|
||||
}
|
||||
|
||||
slick.sort = function(nodes){
|
||||
if (nodes && nodes.length > 1) finder(nodes[0]).sort(nodes)
|
||||
return nodes
|
||||
}
|
||||
|
||||
slick.parse = parse;
|
||||
|
||||
// slick.debug = true
|
||||
// slick.noQSA = true
|
||||
|
||||
module.exports = slick
|
||||
5
book/node_modules/slick/index.js
generated
vendored
Normal file
5
book/node_modules/slick/index.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/*
|
||||
slick
|
||||
*/"use strict"
|
||||
|
||||
module.exports = "document" in global ? require("./finder") : { parse: require("./parser") }
|
||||
33
book/node_modules/slick/package.json
generated
vendored
Normal file
33
book/node_modules/slick/package.json
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "slick",
|
||||
"homepage": "https://github.com/kamicane/slick",
|
||||
"version": "1.12.2",
|
||||
"main": "./index.js",
|
||||
"description": "Standalone CSS Selector Finder and Parser.",
|
||||
"keywords": [
|
||||
"dom",
|
||||
"css",
|
||||
"selector",
|
||||
"finder",
|
||||
"parser"
|
||||
],
|
||||
"author": "Valerio Proietti <@kamicane> (http://mad4milk.net)",
|
||||
"contributors": [
|
||||
"Fabio Miranda Costa <@fabiomcosta>",
|
||||
"Thomas Aylott <@SubtleGradient>"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/kamicane/slick/issues"
|
||||
},
|
||||
"license": "MIT (http://mootools.net/license.txt)",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/kamicane/slick.git"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {},
|
||||
"optionalDependencies": {},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
}
|
||||
250
book/node_modules/slick/parser.js
generated
vendored
Normal file
250
book/node_modules/slick/parser.js
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
Slick Parser
|
||||
- originally created by the almighty Thomas Aylott <@subtlegradient> (http://subtlegradient.com)
|
||||
*/"use strict"
|
||||
|
||||
// Notable changes from Slick.Parser 1.0.x
|
||||
|
||||
// The parser now uses 2 classes: Expressions and Expression
|
||||
// `new Expressions` produces an array-like object containing a list of Expression objects
|
||||
// - Expressions::toString() produces a cleaned up expressions string
|
||||
// `new Expression` produces an array-like object
|
||||
// - Expression::toString() produces a cleaned up expression string
|
||||
// The only exposed method is parse, which produces a (cached) `new Expressions` instance
|
||||
// parsed.raw is no longer present, use .toString()
|
||||
// parsed.expression is now useless, just use the indices
|
||||
// parsed.reverse() has been removed for now, due to its apparent uselessness
|
||||
// Other changes in the Expressions object:
|
||||
// - classNames are now unique, and save both escaped and unescaped values
|
||||
// - attributes now save both escaped and unescaped values
|
||||
// - pseudos now save both escaped and unescaped values
|
||||
|
||||
var escapeRe = /([-.*+?^${}()|[\]\/\\])/g,
|
||||
unescapeRe = /\\/g
|
||||
|
||||
var escape = function(string){
|
||||
// XRegExp v2.0.0-beta-3
|
||||
// « https://github.com/slevithan/XRegExp/blob/master/src/xregexp.js
|
||||
return (string + "").replace(escapeRe, '\\$1')
|
||||
}
|
||||
|
||||
var unescape = function(string){
|
||||
return (string + "").replace(unescapeRe, '')
|
||||
}
|
||||
|
||||
var slickRe = RegExp(
|
||||
/*
|
||||
#!/usr/bin/env ruby
|
||||
puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
|
||||
__END__
|
||||
"(?x)^(?:\
|
||||
\\s* ( , ) \\s* # Separator \n\
|
||||
| \\s* ( <combinator>+ ) \\s* # Combinator \n\
|
||||
| ( \\s+ ) # CombinatorChildren \n\
|
||||
| ( <unicode>+ | \\* ) # Tag \n\
|
||||
| \\# ( <unicode>+ ) # ID \n\
|
||||
| \\. ( <unicode>+ ) # ClassName \n\
|
||||
| # Attribute \n\
|
||||
\\[ \
|
||||
\\s* (<unicode1>+) (?: \
|
||||
\\s* ([*^$!~|]?=) (?: \
|
||||
\\s* (?:\
|
||||
([\"']?)(.*?)\\9 \
|
||||
)\
|
||||
) \
|
||||
)? \\s* \
|
||||
\\](?!\\]) \n\
|
||||
| :+ ( <unicode>+ )(?:\
|
||||
\\( (?:\
|
||||
(?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\
|
||||
) \\)\
|
||||
)?\
|
||||
)"
|
||||
*/
|
||||
"^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
|
||||
.replace(/<combinator>/, '[' + escape(">+~`!@$%^&={}\\;</") + ']')
|
||||
.replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
|
||||
.replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
|
||||
)
|
||||
|
||||
// Part
|
||||
|
||||
var Part = function Part(combinator){
|
||||
this.combinator = combinator || " "
|
||||
this.tag = "*"
|
||||
}
|
||||
|
||||
Part.prototype.toString = function(){
|
||||
|
||||
if (!this.raw){
|
||||
|
||||
var xpr = "", k, part
|
||||
|
||||
xpr += this.tag || "*"
|
||||
if (this.id) xpr += "#" + this.id
|
||||
if (this.classes) xpr += "." + this.classList.join(".")
|
||||
if (this.attributes) for (k = 0; part = this.attributes[k++];){
|
||||
xpr += "[" + part.name + (part.operator ? part.operator + '"' + part.value + '"' : '') + "]"
|
||||
}
|
||||
if (this.pseudos) for (k = 0; part = this.pseudos[k++];){
|
||||
xpr += ":" + part.name
|
||||
if (part.value) xpr += "(" + part.value + ")"
|
||||
}
|
||||
|
||||
this.raw = xpr
|
||||
|
||||
}
|
||||
|
||||
return this.raw
|
||||
}
|
||||
|
||||
// Expression
|
||||
|
||||
var Expression = function Expression(){
|
||||
this.length = 0
|
||||
}
|
||||
|
||||
Expression.prototype.toString = function(){
|
||||
|
||||
if (!this.raw){
|
||||
|
||||
var xpr = ""
|
||||
|
||||
for (var j = 0, bit; bit = this[j++];){
|
||||
if (j !== 1) xpr += " "
|
||||
if (bit.combinator !== " ") xpr += bit.combinator + " "
|
||||
xpr += bit
|
||||
}
|
||||
|
||||
this.raw = xpr
|
||||
|
||||
}
|
||||
|
||||
return this.raw
|
||||
}
|
||||
|
||||
var replacer = function(
|
||||
rawMatch,
|
||||
|
||||
separator,
|
||||
combinator,
|
||||
combinatorChildren,
|
||||
|
||||
tagName,
|
||||
id,
|
||||
className,
|
||||
|
||||
attributeKey,
|
||||
attributeOperator,
|
||||
attributeQuote,
|
||||
attributeValue,
|
||||
|
||||
pseudoMarker,
|
||||
pseudoClass,
|
||||
pseudoQuote,
|
||||
pseudoClassQuotedValue,
|
||||
pseudoClassValue
|
||||
){
|
||||
|
||||
var expression, current
|
||||
|
||||
if (separator || !this.length){
|
||||
expression = this[this.length++] = new Expression
|
||||
if (separator) return ''
|
||||
}
|
||||
|
||||
if (!expression) expression = this[this.length - 1]
|
||||
|
||||
if (combinator || combinatorChildren || !expression.length){
|
||||
current = expression[expression.length++] = new Part(combinator)
|
||||
}
|
||||
|
||||
if (!current) current = expression[expression.length - 1]
|
||||
|
||||
if (tagName){
|
||||
|
||||
current.tag = unescape(tagName)
|
||||
|
||||
} else if (id){
|
||||
|
||||
current.id = unescape(id)
|
||||
|
||||
} else if (className){
|
||||
|
||||
var unescaped = unescape(className)
|
||||
|
||||
var classes = current.classes || (current.classes = {})
|
||||
if (!classes[unescaped]){
|
||||
classes[unescaped] = escape(className)
|
||||
var classList = current.classList || (current.classList = [])
|
||||
classList.push(unescaped)
|
||||
classList.sort()
|
||||
}
|
||||
|
||||
} else if (pseudoClass){
|
||||
|
||||
pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue
|
||||
|
||||
;(current.pseudos || (current.pseudos = [])).push({
|
||||
type : pseudoMarker.length == 1 ? 'class' : 'element',
|
||||
name : unescape(pseudoClass),
|
||||
escapedName : escape(pseudoClass),
|
||||
value : pseudoClassValue ? unescape(pseudoClassValue) : null,
|
||||
escapedValue : pseudoClassValue ? escape(pseudoClassValue) : null
|
||||
})
|
||||
|
||||
} else if (attributeKey){
|
||||
|
||||
attributeValue = attributeValue ? escape(attributeValue) : null
|
||||
|
||||
;(current.attributes || (current.attributes = [])).push({
|
||||
operator : attributeOperator,
|
||||
name : unescape(attributeKey),
|
||||
escapedName : escape(attributeKey),
|
||||
value : attributeValue ? unescape(attributeValue) : null,
|
||||
escapedValue : attributeValue ? escape(attributeValue) : null
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return ''
|
||||
|
||||
}
|
||||
|
||||
// Expressions
|
||||
|
||||
var Expressions = function Expressions(expression){
|
||||
this.length = 0
|
||||
|
||||
var self = this
|
||||
|
||||
var original = expression, replaced
|
||||
|
||||
while (expression){
|
||||
replaced = expression.replace(slickRe, function(){
|
||||
return replacer.apply(self, arguments)
|
||||
})
|
||||
if (replaced === expression) throw new Error(original + ' is an invalid expression')
|
||||
expression = replaced
|
||||
}
|
||||
}
|
||||
|
||||
Expressions.prototype.toString = function(){
|
||||
if (!this.raw){
|
||||
var expressions = []
|
||||
for (var i = 0, expression; expression = this[i++];) expressions.push(expression)
|
||||
this.raw = expressions.join(", ")
|
||||
}
|
||||
|
||||
return this.raw
|
||||
}
|
||||
|
||||
var cache = {}
|
||||
|
||||
var parse = function(expression){
|
||||
if (expression == null) return null
|
||||
expression = ('' + expression).replace(/^\s+|\s+$/g, '')
|
||||
return cache[expression] || (cache[expression] = new Expressions(expression))
|
||||
}
|
||||
|
||||
module.exports = parse
|
||||
Reference in New Issue
Block a user