1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | var hasOwn = Object.prototype.hasOwnProperty
|
13 |
|
14 | function extend(obj, _super, extras) {
|
15 | obj.prototype = Object.create(_super.prototype)
|
16 | for (var key in extras) {
|
17 | obj.prototype[key] = extras[key]
|
18 | }
|
19 | obj.prototype.constructor = obj
|
20 | }
|
21 |
|
22 | function StyleMap(style) {
|
23 | var styleMap = this
|
24 | if (style) style.split(/\s*;\s*/g).map(function(val) {
|
25 | val = val.split(/\s*:\s*/)
|
26 | if(val[1]) styleMap[val[0]] = val[1]
|
27 | })
|
28 | }
|
29 |
|
30 | StyleMap.prototype.valueOf = function() {
|
31 | var styleMap = this
|
32 | return Object.keys(styleMap).map(function(key) {
|
33 | return key + ": " + styleMap[key]
|
34 | }).join("; ")
|
35 | }
|
36 |
|
37 | function Node(){}
|
38 |
|
39 | function getSibling(node, step) {
|
40 | var silbings = node.parentNode && node.parentNode.childNodes
|
41 | , index = silbings && silbings.indexOf(node)
|
42 |
|
43 | return silbings && index > -1 && silbings[ index + step ] || null
|
44 | }
|
45 |
|
46 | Node.prototype = {
|
47 | nodeName: null,
|
48 | parentNode: null,
|
49 | ownerDocument: null,
|
50 | childNodes: null,
|
51 | get nodeValue() {
|
52 | return this.nodeType === 3 || this.nodeType === 8 ? this.data : null
|
53 | },
|
54 | set nodeValue(text) {
|
55 | return this.nodeType === 3 || this.nodeType === 8 ? (this.data = text) : null
|
56 | },
|
57 | get textContent() {
|
58 | return this.hasChildNodes() ? this.childNodes.map(function(child) {
|
59 | return child[ child.nodeType == 3 ? "data" : "textContent" ]
|
60 | }).join("") : this.nodeType === 3 ? this.data : ""
|
61 | },
|
62 | set textContent(text) {
|
63 | if (this.nodeType === 3) return (this.data = text)
|
64 | for (var node = this; node.firstChild;) node.removeChild(node.firstChild)
|
65 | node.appendChild(node.ownerDocument.createTextNode(text))
|
66 | },
|
67 | get firstChild() {
|
68 | return this.childNodes && this.childNodes[0] || null
|
69 | },
|
70 | get lastChild() {
|
71 | return this.childNodes && this.childNodes[ this.childNodes.length - 1 ] || null
|
72 | },
|
73 | get previousSibling() {
|
74 | return getSibling(this, -1)
|
75 | },
|
76 | get nextSibling() {
|
77 | return getSibling(this, 1)
|
78 | },
|
79 | get innerHTML() {
|
80 | return Node.prototype.toString.call(this)
|
81 | },
|
82 | get outerHTML() {
|
83 | return this.toString()
|
84 | },
|
85 | get htmlFor() {
|
86 | return this["for"]
|
87 | },
|
88 | set htmlFor(value) {
|
89 | this["for"] = value
|
90 | },
|
91 | get className() {
|
92 | return this["class"] || ""
|
93 | },
|
94 | set className(value) {
|
95 | this["class"] = value
|
96 | },
|
97 | get style() {
|
98 | return this.styleMap || (this.styleMap = new StyleMap())
|
99 | },
|
100 | set style(value) {
|
101 | this.styleMap = new StyleMap(value)
|
102 | },
|
103 | hasChildNodes: function() {
|
104 | return this.childNodes && this.childNodes.length > 0
|
105 | },
|
106 | appendChild: function(el) {
|
107 | return this.insertBefore(el)
|
108 | },
|
109 | insertBefore: function(el, ref) {
|
110 | var node = this
|
111 | , childs = node.childNodes
|
112 |
|
113 | if (el.nodeType == 11) {
|
114 | while (el.firstChild) node.insertBefore(el.firstChild, ref)
|
115 | } else {
|
116 | if (el.parentNode) el.parentNode.removeChild(el)
|
117 | el.parentNode = node
|
118 |
|
119 |
|
120 | childs.splice(ref ? childs.indexOf(ref) : childs.length, 0, el)
|
121 | }
|
122 | return el
|
123 | },
|
124 | removeChild: function(el) {
|
125 | var node = this
|
126 | , index = node.childNodes.indexOf(el)
|
127 | if (index == -1) throw new Error("NOT_FOUND_ERR")
|
128 |
|
129 | node.childNodes.splice(index, 1)
|
130 | el.parentNode = null
|
131 | return el
|
132 | },
|
133 | replaceChild: function(el, ref) {
|
134 | this.insertBefore(el, ref)
|
135 | return this.removeChild(ref)
|
136 | },
|
137 | cloneNode: function(deep) {
|
138 | var key
|
139 | , node = this
|
140 | , clone = new node.constructor(node.tagName || node.data)
|
141 | clone.ownerDocument = node.ownerDocument
|
142 |
|
143 | if (node.hasAttribute) {
|
144 | for (key in node) if (node.hasAttribute(key)) clone[key] = node[key].valueOf()
|
145 | }
|
146 |
|
147 | if (deep && node.hasChildNodes()) {
|
148 | node.childNodes.forEach(function(child) {
|
149 | clone.appendChild(child.cloneNode(deep))
|
150 | })
|
151 | }
|
152 | return clone
|
153 | },
|
154 | toString: function() {
|
155 | return this.hasChildNodes() ? this.childNodes.reduce(function(memo, node) {
|
156 | return memo + node
|
157 | }, "") : ""
|
158 | }
|
159 | }
|
160 |
|
161 |
|
162 | function DocumentFragment() {
|
163 | this.childNodes = []
|
164 | }
|
165 |
|
166 | extend(DocumentFragment, Node, {
|
167 | nodeType: 11,
|
168 | nodeName: "#document-fragment"
|
169 | })
|
170 |
|
171 | function Attribute(node, name) {
|
172 | this.name = name.toLowerCase()
|
173 |
|
174 | Object.defineProperty(this, "value", {
|
175 | get: function() {return node.getAttribute(name)},
|
176 | set: function(val) {node.setAttribute(name, val)}
|
177 | })
|
178 | }
|
179 | Attribute.prototype.toString = function() {
|
180 | if (!this.value) return this.name
|
181 |
|
182 | return this.name + '="' + this.value.replace(/&/g, "&").replace(/"/g, """) + '"'
|
183 | }
|
184 |
|
185 | function HTMLElement(tag) {
|
186 | var element = this
|
187 | element.nodeName = element.tagName = tag.toUpperCase()
|
188 | element.localName = tag.toLowerCase()
|
189 | element.childNodes = []
|
190 | }
|
191 |
|
192 | function findEl(node, sel, first) {
|
193 | var el
|
194 | , i = 0
|
195 | , out = []
|
196 | , els = node.getElementsByTagName("*")
|
197 | , fn = selectorFn(sel.split(/\s*,\s*/).map(selectorFnStr).join("||"))
|
198 |
|
199 | for (; (el = els[i++]); ) if (fn(el)) {
|
200 | if (first) return el
|
201 | out.push(el)
|
202 | }
|
203 | return first ? null : out
|
204 | }
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 | var voidElements = {
|
211 | AREA:1, BASE:1, BR:1, COL:1, EMBED:1, HR:1, IMG:1, INPUT:1,
|
212 | KEYGEN:1, LINK:1, MENUITEM:1, META:1, PARAM:1, SOURCE:1, TRACK:1, WBR:1
|
213 | }
|
214 | , pseudoClasses = {
|
215 | "empty": "!_.hasChildNodes()",
|
216 | "first-child": "_.parentNode&&_.parentNode.firstChild==_",
|
217 | "last-child" : "_.parentNode&&_.parentNode.lastChild==_",
|
218 | "link": "_.nodeName=='A'&&_.getAttribute('href')"
|
219 | }
|
220 | , selectorRe = /([.#:[])([-\w]+)(?:=((["'\/])(?:\\?.)*?\4|[-\w]+)]])?/g
|
221 | , lastSelectorRe = /(\s*[>+]?\s*)((["'\/])(?:\\?.)*?\2|[^\s+>])+$/
|
222 | , fnCache = {}
|
223 |
|
224 | function escapeAttributeName(name) {
|
225 | name = name.toLowerCase()
|
226 | if (name === "constructor" || name === "attributes") return name.toUpperCase()
|
227 | return name
|
228 | }
|
229 |
|
230 | function selectorFnStr(sel) {
|
231 | var rules = ["_"]
|
232 | , tag = sel.replace(selectorRe, function(_, op, key, val, quotation) {
|
233 | if (quotation) val = val.slice(1, -1)
|
234 | rules.push(
|
235 | op == "." ? "(' '+_.className+' ').indexOf(' " + key + " ')>-1" :
|
236 | op == "#" ? "_.id=='" + key + "'" :
|
237 | op == ":" && pseudoClasses[key] ||
|
238 | "_.getAttribute('" + key + "')" + (val ? "=='" + val.replace(/'/g, "\\'") + "'" : "")
|
239 | )
|
240 | return ""
|
241 | })
|
242 |
|
243 | if (tag && tag != "*") rules.unshift("_.nodeName=='" + tag.toUpperCase() + "'")
|
244 | return rules.join("&&")
|
245 | }
|
246 |
|
247 | function selectorFn(str) {
|
248 |
|
249 | return fnCache[str] ||
|
250 | (fnCache[str] = Function("_", "return " + str))
|
251 | }
|
252 |
|
253 | extend(HTMLElement, Node, {
|
254 | matches: function(sel) {
|
255 | var relation, from
|
256 | , parentSel = sel.replace(lastSelectorRe, function(_, _rel, a, b, start) {
|
257 | from = start + _rel.length
|
258 | relation = _rel.trim()
|
259 | return ""
|
260 | })
|
261 | , next = relation == ">" ? this.parentNode : relation == "+" ? this.previousSibling : this
|
262 | , fn = selectorFn(selectorFnStr(sel.slice(from)))
|
263 |
|
264 | if (!fn(this)) return false
|
265 |
|
266 | if (parentSel) {
|
267 | if (!relation) return !!(next.parentNode && next.parentNode.closest && next.parentNode.closest(parentSel))
|
268 | return next && next.matches && next.matches(parentSel) || false
|
269 | }
|
270 | return true
|
271 | },
|
272 | closest: function(sel) {
|
273 | for (var el = this; el; el = el.parentNode) if (el.matches && el.matches(sel)) return el
|
274 | return null
|
275 | },
|
276 | namespaceURI: "http://www.w3.org/1999/xhtml",
|
277 | nodeType: 1,
|
278 | localName: null,
|
279 | tagName: null,
|
280 | styleMap: null,
|
281 | hasAttribute: function(name) {
|
282 | name = escapeAttributeName(name)
|
283 | return name == "style" && !!this.style.valueOf() || hasOwn.call(this, name)
|
284 | },
|
285 | getAttribute: function(name) {
|
286 | name = escapeAttributeName(name)
|
287 | return this.hasAttribute(name) ? "" + this[name] : null
|
288 | },
|
289 | setAttribute: function(name, value) {
|
290 | name = escapeAttributeName(name)
|
291 | this[name] = "" + value
|
292 | },
|
293 | removeAttribute: function(name) {
|
294 | name = escapeAttributeName(name)
|
295 | this[name] = ""
|
296 | delete this[name]
|
297 | },
|
298 | getElementById: function(id) {
|
299 | if (this.id == id) return this
|
300 | for (var el, found, i = 0; !found && (el = this.childNodes[i++]);) {
|
301 | if (el.nodeType == 1) found = el.getElementById(id)
|
302 | }
|
303 | return found || null
|
304 | },
|
305 | getElementsByTagName: function(tag) {
|
306 | var el, els = [], next = this.firstChild
|
307 | tag = tag === "*" ? 1 : tag.toUpperCase()
|
308 | for (var i = 0, key = tag === 1 ? "nodeType" : "nodeName"; (el = next); ) {
|
309 | if (el[key] === tag) els[i++] = el
|
310 | next = el.firstChild || el.nextSibling
|
311 | while (!next && ((el = el.parentNode) !== this)) next = el.nextSibling
|
312 | }
|
313 | return els
|
314 | },
|
315 | querySelector: function(sel) {
|
316 | return findEl(this, sel, 1)
|
317 | },
|
318 | querySelectorAll: function(sel) {
|
319 | return findEl(this, sel)
|
320 | },
|
321 | toString: function() {
|
322 | var attrs = this.attributes.join(" ")
|
323 | return "<" + this.localName + (attrs ? " " + attrs : "") + ">" +
|
324 | (voidElements[this.tagName] ? "" : this.innerHTML + "</" + this.localName + ">")
|
325 | }
|
326 | })
|
327 |
|
328 | Object.defineProperty(HTMLElement.prototype, "attributes", {
|
329 | get: function() {
|
330 | var key
|
331 | , attrs = []
|
332 | , element = this
|
333 | for (key in element) if (key === escapeAttributeName(key) && element.hasAttribute(key))
|
334 | attrs.push(new Attribute(element, escapeAttributeName(key)))
|
335 | return attrs
|
336 | }
|
337 | })
|
338 |
|
339 | function ElementNS(namespace, tag) {
|
340 | var element = this
|
341 | element.namespaceURI = namespace
|
342 | element.nodeName = element.tagName = element.localName = tag
|
343 | element.childNodes = []
|
344 | }
|
345 |
|
346 | ElementNS.prototype = HTMLElement.prototype
|
347 |
|
348 | function Text(data) {
|
349 | this.data = data
|
350 | }
|
351 |
|
352 | extend(Text, Node, {
|
353 | nodeType: 3,
|
354 | nodeName: "#text",
|
355 | toString: function() {
|
356 | return ("" + this.data).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
|
357 | }
|
358 | })
|
359 |
|
360 | function Comment(data) {
|
361 | this.data = data
|
362 | }
|
363 |
|
364 | extend(Comment, Node, {
|
365 | nodeType: 8,
|
366 | nodeName: "#comment",
|
367 | toString: function() {
|
368 | return "<!--" + this.data + "-->"
|
369 | }
|
370 | })
|
371 |
|
372 | function Document() {
|
373 | this.childNodes = []
|
374 | this.documentElement = this.createElement("html")
|
375 | this.appendChild(this.documentElement)
|
376 | this.body = this.createElement("body")
|
377 | this.documentElement.appendChild(this.body)
|
378 | }
|
379 |
|
380 | function own(Element) {
|
381 | return function($1, $2) {
|
382 | var node = new Element($1, $2)
|
383 | node.ownerDocument = this
|
384 | return node
|
385 | }
|
386 | }
|
387 |
|
388 | extend(Document, Node, {
|
389 | nodeType: 9,
|
390 | nodeName: "#document",
|
391 | createElement: own(HTMLElement),
|
392 | createElementNS: own(ElementNS),
|
393 | createTextNode: own(Text),
|
394 | createComment: own(Comment),
|
395 | createDocumentFragment: own(DocumentFragment),
|
396 | getElementById: HTMLElement.prototype.getElementById,
|
397 | getElementsByTagName: HTMLElement.prototype.getElementsByTagName,
|
398 | querySelector: HTMLElement.prototype.querySelector,
|
399 | querySelectorAll: HTMLElement.prototype.querySelectorAll
|
400 | })
|
401 |
|
402 | module.exports = {
|
403 | document: new Document(),
|
404 | Document: Document,
|
405 | HTMLElement: HTMLElement
|
406 | }
|
407 |
|