git ssb

1+

Matt McKegg / mutant



Tree: 5be33c01238870a66c608fed4ece3fbc43069a51

Files: 5be33c01238870a66c608fed4ece3fbc43069a51 / lib / apply-properties.js

4131 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 (containsObservables(classList)) {
66 data.bindings.push(new Binding(bindClassList, target, classList, 'className'))
67 } else {
68 // OPTIMISATION: no need to create a binding if the list is never going to change
69 target.className = classList().join(' ')
70 }
71}
72
73function containsObservables (obs) {
74 for (var i = 0, len = obs.getLength(); i < len; i++) {
75 if (isObservable(obs.get(i))) {
76 return true
77 }
78 }
79}
80
81function bindClassList (target, obs, key) {
82 return watch(obs, function (value) {
83 value = [].concat.apply([], value).filter(present).join(' ')
84 if (value || target[key]) {
85 target[key] = value
86 }
87 })
88}
89
90function bindStyle (target, styleObs, key) {
91 return watch(styleObs, function (value) {
92 target.style.setProperty(key, value)
93 })
94}
95
96function bindAttr (target, attrObs, key) {
97 return watch(attrObs, function (value) {
98 if (value == null) {
99 target.removeAttribute(key)
100 } else {
101 target.setAttribute(key, value)
102 }
103 })
104}
105
106function bind (target, obs, key) {
107 return watch(obs, function (toValue) {
108 var fromValue = target.getAttribute(key)
109 if (fromValue !== toValue) {
110 target.setAttribute(key, toValue)
111 }
112 })
113}
114
115function present (val) {
116 return val != null
117}
118
119function resolve (source) {
120 return typeof source === 'function' ? source() : source
121}
122
123function Binding (fn, element, source, key) {
124 this.element = element
125 this.source = source
126 this.key = key
127 this.fn = fn
128 this.bound = false
129}
130
131Binding.prototype = {
132 bind: function () {
133 if (!this.bound) {
134 this._release = this.fn(this.element, this.source, this.key)
135 this.bound = true
136 }
137 },
138 unbind: function () {
139 if (this.bound) {
140 this._release()
141 this._release = null
142 this.bound = false
143 }
144 }
145}
146
147function HookBinding (fn, element) {
148 this.element = element
149 this.fn = fn
150 this.bound = false
151}
152
153HookBinding.prototype = {
154 bind: function () {
155 if (!this.bound) {
156 this._release = this.fn(this.element)
157 this.bound = true
158 }
159 },
160 unbind: function () {
161 if (this.bound && typeof this._release === 'function') {
162 this._release()
163 this._release = null
164 this.bound = false
165 }
166 }
167}
168

Built with git-ssb-web