twine-rails 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/assets/javascripts/twine.coffee +50 -36
- data/lib/twine-rails.rb +0 -1
- data/lib/twine-rails/version.rb +1 -1
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 538a0c1b2f074d00d9402091cd8903e88a8c89f8
|
4
|
+
data.tar.gz: b966ba3ac32c35b34ab8cde4a05677e7d3b2ccfc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e272cf342cddbff047c8f3cff87f81a50631ab71559d3b17d7d12255689aa7fe72f1ed1b885060f04f1cb88f355a31efddf77ef5ae148a31977ce9c25438f099
|
7
|
+
data.tar.gz: 6d792404c98c19676b3d1f16b38d1e48874d4c691f8fe9c1a78e1b0a489c1475193ea1cf3181d994f018a3b6de1e90b83e4cd53d9ff75b31dfc40c98babe46f0
|
@@ -56,6 +56,7 @@
|
|
56
56
|
|
57
57
|
bind = (context, node, indexes, forceSaveContext) ->
|
58
58
|
currentBindingCallbacks = []
|
59
|
+
element = null
|
59
60
|
if node.bindingId
|
60
61
|
Twine.unbind(node)
|
61
62
|
|
@@ -69,13 +70,29 @@
|
|
69
70
|
element = findOrCreateElementForNode(node)
|
70
71
|
element.indexes = indexes
|
71
72
|
|
72
|
-
|
73
|
-
|
73
|
+
bindingConstructors = null
|
74
|
+
for attribute in node.attributes
|
75
|
+
type = attribute.name
|
76
|
+
type = type.slice(5) if isDataAttribute(type)
|
77
|
+
|
78
|
+
constructor = Twine.bindingTypes[type]
|
79
|
+
continue unless constructor
|
80
|
+
|
81
|
+
bindingConstructors ?= []
|
82
|
+
definition = attribute.value
|
83
|
+
if type == 'bind'
|
84
|
+
bindingConstructors.unshift([constructor, definition])
|
85
|
+
else
|
86
|
+
bindingConstructors.push([constructor, definition])
|
87
|
+
|
88
|
+
if bindingConstructors
|
89
|
+
element ?= findOrCreateElementForNode(node)
|
74
90
|
element.bindings ?= []
|
75
91
|
element.indexes ?= indexes
|
76
92
|
|
77
|
-
|
78
|
-
|
93
|
+
for [constructor, definition] in bindingConstructors
|
94
|
+
binding = constructor(node, context, definition, element)
|
95
|
+
element.bindings.push(binding) if binding
|
79
96
|
|
80
97
|
if newContextKey = Twine.getAttribute(node, 'context')
|
81
98
|
keypath = keypathForKey(node, newContextKey)
|
@@ -85,7 +102,7 @@
|
|
85
102
|
context = getValue(context, keypath) || setValue(context, keypath, {})
|
86
103
|
|
87
104
|
if element || newContextKey || forceSaveContext
|
88
|
-
element
|
105
|
+
element ?= findOrCreateElementForNode(node)
|
89
106
|
element.childContext = context
|
90
107
|
element.indexes ?= indexes if indexes?
|
91
108
|
|
@@ -108,7 +125,6 @@
|
|
108
125
|
findOrCreateElementForNode = (node) ->
|
109
126
|
node.bindingId ?= ++nodeCount
|
110
127
|
elements[node.bindingId] ?= {}
|
111
|
-
elements[node.bindingId]
|
112
128
|
|
113
129
|
# Queues a refresh of the DOM, batching up calls for the current synchronous block.
|
114
130
|
Twine.refresh = ->
|
@@ -187,7 +203,7 @@
|
|
187
203
|
addKey(rootContext) if node == rootNode
|
188
204
|
keys.join('.')
|
189
205
|
|
190
|
-
|
206
|
+
valuePropertyForNode = (node) ->
|
191
207
|
name = node.nodeName.toLowerCase()
|
192
208
|
if name in ['input', 'textarea', 'select']
|
193
209
|
if node.getAttribute('type') in ['checkbox', 'radio'] then 'checked' else 'value'
|
@@ -232,14 +248,7 @@
|
|
232
248
|
object[lastKey] = value
|
233
249
|
|
234
250
|
stringifyNodeAttributes = (node) ->
|
235
|
-
|
236
|
-
i = 0
|
237
|
-
result = ""
|
238
|
-
while i < nAttributes
|
239
|
-
attr = node.attributes.item(i)
|
240
|
-
result += "#{attr.nodeName}='#{attr.textContent}'"
|
241
|
-
i+=1
|
242
|
-
result
|
251
|
+
[].map.call(node.attributes, (attr) -> "#{attr.name}=#{JSON.stringify(attr.value)}").join(' ')
|
243
252
|
|
244
253
|
wrapFunctionString = (code, args, node) ->
|
245
254
|
if isKeypath(code) && keypath = keypathForKey(node, code)
|
@@ -249,7 +258,7 @@
|
|
249
258
|
($context, $root) -> getValue($context, keypath)
|
250
259
|
else
|
251
260
|
code = "return #{code}"
|
252
|
-
code = "with($arrayPointers) { #{code} }" if
|
261
|
+
code = "with($arrayPointers) { #{code} }" if nodeArrayIndexes(node)
|
253
262
|
code = "with($registry) { #{code} }" if requiresRegistry(args)
|
254
263
|
try
|
255
264
|
new Function(args, "with($context) { #{code} }")
|
@@ -258,14 +267,12 @@
|
|
258
267
|
|
259
268
|
requiresRegistry = (args) -> /\$registry/.test(args)
|
260
269
|
|
261
|
-
|
262
|
-
|
263
|
-
!!elements[node.bindingId]?.indexes?
|
270
|
+
nodeArrayIndexes = (node) ->
|
271
|
+
node.bindingId? && elements[node.bindingId]?.indexes
|
264
272
|
|
265
273
|
arrayPointersForNode = (node, context) ->
|
266
|
-
|
267
|
-
|
268
|
-
return {} unless indexes?
|
274
|
+
indexes = nodeArrayIndexes(node)
|
275
|
+
return {} unless indexes
|
269
276
|
|
270
277
|
result = {}
|
271
278
|
for key, index of indexes
|
@@ -273,7 +280,14 @@
|
|
273
280
|
result
|
274
281
|
|
275
282
|
isKeypath = (value) ->
|
276
|
-
value not in ['true', 'false', 'null', 'undefined']
|
283
|
+
value not in ['true', 'false', 'null', 'undefined'] && keypathRegex.test(value)
|
284
|
+
|
285
|
+
isDataAttribute = (value) ->
|
286
|
+
value[0] == 'd' &&
|
287
|
+
value[1] == 'a' &&
|
288
|
+
value[2] == 't' &&
|
289
|
+
value[3] == 'a' &&
|
290
|
+
value[4] == '-'
|
277
291
|
|
278
292
|
fireCustomChangeEvent = (node) ->
|
279
293
|
event = document.createEvent('CustomEvent')
|
@@ -282,8 +296,8 @@
|
|
282
296
|
|
283
297
|
Twine.bindingTypes =
|
284
298
|
bind: (node, context, definition) ->
|
285
|
-
|
286
|
-
value = node[
|
299
|
+
valueProp = valuePropertyForNode(node)
|
300
|
+
value = node[valueProp]
|
287
301
|
lastValue = undefined
|
288
302
|
teardown = undefined
|
289
303
|
|
@@ -296,9 +310,9 @@
|
|
296
310
|
return if newValue == lastValue # return if we can and avoid a DOM operation
|
297
311
|
|
298
312
|
lastValue = newValue
|
299
|
-
return if newValue == node[
|
313
|
+
return if newValue == node[valueProp]
|
300
314
|
|
301
|
-
node[
|
315
|
+
node[valueProp] = if checkedValueType then newValue == node.value else newValue
|
302
316
|
fireCustomChangeEvent(node)
|
303
317
|
|
304
318
|
return {refresh} unless isKeypath(definition)
|
@@ -308,10 +322,10 @@
|
|
308
322
|
return unless node.checked
|
309
323
|
setValue(context, keypath, node.value)
|
310
324
|
else
|
311
|
-
setValue(context, keypath, node[
|
325
|
+
setValue(context, keypath, node[valueProp])
|
312
326
|
|
313
327
|
keypath = keypathForKey(node, definition)
|
314
|
-
twoWayBinding =
|
328
|
+
twoWayBinding = valueProp != 'textContent' && node.type != 'hidden'
|
315
329
|
|
316
330
|
if keypath[0] == '$root'
|
317
331
|
context = rootContext
|
@@ -322,7 +336,7 @@
|
|
322
336
|
|
323
337
|
if twoWayBinding
|
324
338
|
changeHandler = ->
|
325
|
-
return if getValue(context, keypath) == this[
|
339
|
+
return if getValue(context, keypath) == this[valueProp]
|
326
340
|
refreshContext()
|
327
341
|
Twine.refreshImmediately()
|
328
342
|
$(node).on 'input keyup change', changeHandler
|
@@ -383,24 +397,24 @@
|
|
383
397
|
|
384
398
|
indexes
|
385
399
|
|
386
|
-
|
387
|
-
|
400
|
+
setupPropertyBinding = (attributeName, bindingName) ->
|
401
|
+
booleanProp = attributeName in ['checked', 'indeterminate', 'disabled', 'readOnly']
|
388
402
|
|
389
|
-
Twine.bindingTypes["bind-#{bindingName}"] = (node, context, definition) ->
|
403
|
+
Twine.bindingTypes["bind-#{bindingName.toLowerCase()}"] = (node, context, definition) ->
|
390
404
|
fn = wrapFunctionString(definition, '$context,$root,$arrayPointers', node)
|
391
405
|
lastValue = undefined
|
392
406
|
return refresh: ->
|
393
407
|
newValue = fn.call(node, context, rootContext, arrayPointersForNode(node, context))
|
394
|
-
newValue = !!newValue if
|
408
|
+
newValue = !!newValue if booleanProp
|
395
409
|
return if newValue == lastValue
|
396
410
|
node[attributeName] = lastValue = newValue
|
397
411
|
|
398
412
|
fireCustomChangeEvent(node) if attributeName == 'checked'
|
399
413
|
|
400
414
|
for attribute in ['placeholder', 'checked', 'indeterminate', 'disabled', 'href', 'title', 'readOnly', 'src']
|
401
|
-
|
415
|
+
setupPropertyBinding(attribute, attribute)
|
402
416
|
|
403
|
-
|
417
|
+
setupPropertyBinding('innerHTML', 'unsafe-html')
|
404
418
|
|
405
419
|
preventDefaultForEvent = (event) ->
|
406
420
|
(event.type == 'submit' || event.currentTarget.nodeName.toLowerCase() == 'a') &&
|
data/lib/twine-rails.rb
CHANGED
data/lib/twine-rails/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twine-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Li
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2016-
|
13
|
+
date: 2016-07-11 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: coffee-rails
|
@@ -26,6 +26,20 @@ dependencies:
|
|
26
26
|
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: '0'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: railties
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
type: :runtime
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
29
43
|
- !ruby/object:Gem::Dependency
|
30
44
|
name: bundler
|
31
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
100
|
version: '0'
|
87
101
|
requirements: []
|
88
102
|
rubyforge_project:
|
89
|
-
rubygems_version: 2.5.1
|
103
|
+
rubygems_version: 2.4.5.1
|
90
104
|
signing_key:
|
91
105
|
specification_version: 4
|
92
106
|
summary: Minimalistic two-way bindings
|