git ssb

1+

Matt McKegg / mutant



Tree: 880a92caf2ae2e1a7551e7a500794c09adf5880b

Files: 880a92caf2ae2e1a7551e7a500794c09adf5880b / lib / apply-properties.js

3819 bytesRaw
1var isObservable = require('../is-observable')
2var Set = require('../set')
3var watch = require('../watch')
4
5module.exports = applyProperties
6
7function applyProperties (target, properties, data) {
8 var classList = Set()
9 if (target.className) {
10 classList.add(target.className)
11 }
12
13 for (var key in properties) {
14 var valueOrObs = properties[key]
15 var value = resolve(valueOrObs)
16
17 if (key === 'style') {
18 // TODO: handle observable at root for style objects
19 for (var k in value) {
20 var styleObs = isObservable(value[k]) ? value[k] : null
21 if (styleObs) {
22 data.bindings.push(new Binding(bindStyle, target, styleObs, k))
23 } else {
24 target.style.setProperty(k, value[k])
25 }
26 }
27 } else if (key === 'hooks') {
28 if (Array.isArray(value)) {
29 value.forEach(function (v) {
30 data.bindings.push(new HookBinding(v, target))
31 })
32 }
33 } else if (key === 'attributes') {
34 for (var k in value) {
35 var attrObs = isObservable(value[k]) ? value[k] : null
36 if (attrObs) {
37 data.bindings.push(new Binding(bindAttr, target, attrObs, k))
38 } else {
39 target.setAttribute(k, value[k])
40 }
41 }
42 } else if (key === 'events') {
43 for (var name in value) {
44 target.addEventListener(name, value[name], false)
45 }
46 } else if (key.slice(0, 3) === 'ev-') {
47 target.addEventListener(key.slice(3), value, false)
48 } else if (key === 'className' || key === 'classList') {
49 if (Array.isArray(valueOrObs)) {
50 valueOrObs.forEach(function (v) {
51 classList.add(v)
52 })
53 } else {
54 classList.add(valueOrObs)
55 }
56 } else {
57 target[key] = value
58 var obs = isObservable(valueOrObs) ? valueOrObs : null
59 if (obs) {
60 data.bindings.push(new Binding(bind, target, obs, key))
61 }
62 }
63 }
64
65 if (classList.getLength()) {
66 data.bindings.push(new Binding(bindClassList, target, classList, 'className'))
67 }
68}
69
70function bindClassList (target, obs, key) {
71 return watch(obs, function (value) {
72 value = [].concat.apply([], value).filter(present).join(' ')
73 if (value || target[key]) {
74 target[key] = value
75 }
76 })
77}
78
79function bindStyle (target, styleObs, key) {
80 return watch(styleObs, function (value) {
81 target.style.setProperty(key, value)
82 })
83}
84
85function bindAttr (target, attrObs, key) {
86 return watch(attrObs, function (value) {
87 if (value == null) {
88 target.removeAttribute(key)
89 } else {
90 target.setAttribute(key, value)
91 }
92 })
93}
94
95function bind (target, obs, key) {
96 return watch(obs, function (toValue) {
97 var fromValue = target.getAttribute(key)
98 if (fromValue !== toValue) {
99 target.setAttribute(key, toValue)
100 }
101 })
102}
103
104function present (val) {
105 return val != null
106}
107
108function resolve (source) {
109 return typeof source === 'function' ? source() : source
110}
111
112function Binding (fn, element, source, key) {
113 this.element = element
114 this.source = source
115 this.key = key
116 this.fn = fn
117 this.bound = false
118}
119
120Binding.prototype = {
121 bind: function () {
122 if (!this.bound) {
123 this._release = this.fn(this.element, this.source, this.key)
124 this.bound = true
125 }
126 },
127 unbind: function () {
128 if (this.bound) {
129 this._release()
130 this._release = null
131 this.bound = false
132 }
133 }
134}
135
136function HookBinding (fn, element) {
137 this.element = element
138 this.fn = fn
139 this.bound = false
140}
141
142HookBinding.prototype = {
143 bind: function () {
144 if (!this.bound) {
145 this._release = this.fn(this.element)
146 this.bound = true
147 }
148 },
149 unbind: function () {
150 if (this.bound && typeof this._release === 'function') {
151 this._release()
152 this._release = null
153 this.bound = false
154 }
155 }
156}
157

Built with git-ssb-web