twine-rails 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|