-
Notifications
You must be signed in to change notification settings - Fork 2
/
dombrew.js.coffee
125 lines (109 loc) · 3.97 KB
/
dombrew.js.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# DOMBrew builds DOM from a css like selector and a hash of attributes.
# @url https://github.com/glebm/DOMBrew
# @author Gleb Mazovetskiy
d = document
class Node
# {data: {someProp: 1}} => {"data-some-prop" => 1}
flattenHash = (attr) ->
for name, obj of attr
if typeof attr[name] == 'object'
attr[name + '-' + sub.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase()] = val for sub, val of obj
delete attr[name]
return
# Parses out css classes and id from string like:
# p#warning.big.yellow # => p # attr will contain {"id": "warning", "class": ['big', 'yellow']}
# #container # => div # attr will contain {"id": "container"}
# @returns node name (e.g. "span")
dotHashRe = /[.#]/
parseElem = (elem, attr) ->
return elem unless dotHashRe.test elem
attr['class'] ||= []
attr['class'] = [attr['class']] if typeof attr['class'] == 'string'
elem = "div#{elem}" if dotHashRe.test(elem.charAt(0))
pieces = elem.split(dotHashRe)
elemType = pieces.shift()
pos = elemType.length
classes = attr['class']
for piece in pieces
if elem.charAt(pos) == '#'
attr['id'] = piece
else
classes.push(piece)
pos += piece.length + 1
delete attr['class'] unless attr['class'].length
elemType
# joinValues(['a', 'b', 'c', null, '', undefined, true, 1]) => "a b c true 1"
# joinValues('a') => 'a'
joinValues = (value) ->
return value if typeof value != 'object'
r = []
i = -1
length = value.length
while (++i < length)
r.push(value[i]) if value[i]
r.join(' ')
constructor: (elem, attr, more) ->
attr = {} if !attr?
if elem.nodeType
# dom element
@e = elem
return
else if elem == ''
# text node
@e = d.createTextNode attr
return
else
# attr is text, more is attr
if typeof attr == "string"
more ||= {}
more.text = attr
attr = more
@e = d.createElement parseElem(elem, attr)
attr['class'] && (@e.className = joinValues(attr['class'])) && delete attr['class']
attr['text'] && (@e.innerText = joinValues(attr['text'])) && delete attr['text']
attr['html'] && (@e.innerHTML = joinValues(attr['html'])) && delete attr['html']
(s[prop] = value for prop, value of css when value?) if attr['css'] && (s = @e.style) && (css = attr['css']) && delete attr['css']
flattenHash(attr)
@e.setAttribute(name, value) for name, value of attr
# append(children... or [children])
append: ->
a = arguments
a = a[0] if a && a[0] && "splice" of a[0]
for node in a when node
('_brew' of node) && (node = node.dom())
@e.appendChild node
@
# prepend(children... or [children])
prepend: ->
a = arguments
a = a[0] if a && a[0] && "splice" of a[0]
for node in a when node
('_brew' of node) && (node = node.dom())
@e.insertBefore(node, @e.firstChild)
@
dom : -> @e
html : -> div = d.createElement('div'); div.appendChild(@e); div.innerHTML
Node::asDOM = Node::dom
Node::asHTML = Node::html
# Property to help us identify type
Node::_brew = 1
# DOMbrew(nodes... or [nodes])
@DOMBrew = D = ->
a = arguments
# If passed an array, wrap it in a DocumentFragment
if (typeof a[0] == 'object') && ('splice' of a[0]) # $b([nodes...]) form
nodes = a[0]
else if a.length > 1 && (typeof a[1] == 'object') && ('_brew' of a[1]) # $b(nodes...) form
nodes = a
if nodes
frag = d.createDocumentFragment()
frag.appendChild(if node.e then node.e else node) for node in nodes
a = [frag]
new Node(a[0], a[1], a[2])
# create text DOMBrew node
D.text = (text) -> new Node('', text)
D.VERSION = D.version = '1.5.0'
# innerText fix (Firefox)
if (navigator.appName != 'Microsoft Internet Explorer') && !('innerText' of HTMLElement.prototype) && ('__defineGetter__' of HTMLElement)
HTMLElement::__defineGetter__ "innerText", -> @textContent
HTMLElement::__defineSetter__ "innerText", (value) -> @textContent = value