turbo_boost-streams 0.0.5 → 0.0.6
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/README.md +1 -1
- data/app/assets/builds/@turbo-boost/streams.js +3 -4
- data/app/assets/builds/@turbo-boost/streams.js.map +4 -4
- data/app/javascript/index.js +4 -2
- data/app/javascript/invoke.js +102 -22
- data/app/javascript/{methods/mutate.js → morph.js} +4 -6
- data/lib/turbo_boost/streams/patches/tag_builder.rb +2 -3
- data/lib/turbo_boost/streams/tag_helper.rb +5 -4
- data/lib/turbo_boost/streams/version.rb +1 -1
- metadata +5 -6
- data/app/javascript/methods/dispatch.js +0 -6
data/app/javascript/index.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import invoke from './invoke'
|
1
|
+
import { invoke, invokeEvents } from './invoke'
|
2
2
|
|
3
3
|
if (!self['Turbo'])
|
4
4
|
throw new Error(
|
@@ -12,8 +12,10 @@ if (!Turbo['StreamActions'])
|
|
12
12
|
|
13
13
|
Turbo.StreamActions.invoke = invoke
|
14
14
|
self.TurboBoost = self.TurboBoost || {}
|
15
|
-
self.TurboBoost.Streams = { invoke }
|
15
|
+
self.TurboBoost.Streams = { invoke, invokeEvents }
|
16
16
|
|
17
17
|
console.info(
|
18
18
|
'@turbo-boost/streams has initialized and registered new stream actions with Turbo.'
|
19
19
|
)
|
20
|
+
|
21
|
+
export default self.TurboBoost.Streams
|
data/app/javascript/invoke.js
CHANGED
@@ -1,38 +1,118 @@
|
|
1
|
-
import
|
2
|
-
import mutate from './methods/mutate'
|
1
|
+
import morph from './morph'
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
export const invokeEvents = {
|
4
|
+
before: 'turbo-boost:stream:before-invoke',
|
5
|
+
after: 'turbo-boost:stream:after-invoke',
|
6
|
+
finish: 'turbo-boost:stream:finish-invoke'
|
7
|
+
}
|
8
|
+
|
9
|
+
// Invokes the callback on a single receiver with before/after events
|
10
|
+
function withInvokeEvents (receiver, detail, callback) {
|
11
|
+
const { object, target } = receiver
|
12
|
+
detail = detail || {}
|
13
|
+
detail = { ...detail, object: receiver.object }
|
14
|
+
const options = { detail, bubbles: true }
|
15
|
+
|
16
|
+
target.dispatchEvent(new CustomEvent(invokeEvents.before, options))
|
17
|
+
|
18
|
+
const result = callback(object)
|
19
|
+
options.detail.result = result
|
20
|
+
target.dispatchEvent(new CustomEvent(invokeEvents.after, options))
|
21
|
+
|
22
|
+
let promise
|
23
|
+
if (result instanceof Animation) promise = result.finished
|
24
|
+
if (result instanceof Promise) promise = result
|
25
|
+
|
26
|
+
if (promise)
|
27
|
+
promise.then(
|
28
|
+
() => {
|
29
|
+
options.detail.promise = 'fulfilled'
|
30
|
+
target.dispatchEvent(new CustomEvent(invokeEvents.finish, options))
|
31
|
+
},
|
32
|
+
() => {
|
33
|
+
options.detail.promise = 'rejected'
|
34
|
+
target.dispatchEvent(new CustomEvent(invokeEvents.finish, options))
|
35
|
+
}
|
36
|
+
)
|
37
|
+
else target.dispatchEvent(new CustomEvent(invokeEvents.finish, options))
|
38
|
+
}
|
39
|
+
|
40
|
+
function invokeDispatchEvent (method, args, receivers) {
|
41
|
+
const eventName = args[0]
|
42
|
+
const eventOptions = args[1]
|
43
|
+
const detail = { method, eventName, eventOptions }
|
44
|
+
receivers.forEach(receiver =>
|
45
|
+
withInvokeEvents(receiver, detail, object =>
|
46
|
+
object.dispatchEvent(new CustomEvent(eventName, eventOptions))
|
47
|
+
)
|
48
|
+
)
|
49
|
+
}
|
50
|
+
|
51
|
+
function invokeMorph (method, args, receivers) {
|
52
|
+
const html = args[0]
|
53
|
+
const detail = { method, html }
|
54
|
+
receivers.forEach(receiver =>
|
55
|
+
withInvokeEvents(receiver, detail, object => morph(object, html))
|
56
|
+
)
|
57
|
+
}
|
58
|
+
|
59
|
+
function invokeAssignment (method, args, receivers) {
|
60
|
+
const property = method.slice(0, -1).trim()
|
61
|
+
const value = args[0]
|
62
|
+
const detail = { method, property, value }
|
63
|
+
receivers.forEach(receiver =>
|
64
|
+
withInvokeEvents(receiver, detail, object => (object[property] = value))
|
65
|
+
)
|
66
|
+
}
|
67
|
+
|
68
|
+
function invokeMethod (method, args, receivers) {
|
69
|
+
const detail = { method, args }
|
70
|
+
receivers.forEach(receiver =>
|
71
|
+
withInvokeEvents(receiver, detail, object =>
|
72
|
+
object[method].apply(object, args)
|
73
|
+
)
|
74
|
+
)
|
75
|
+
}
|
76
|
+
|
77
|
+
// Performs an invocation on all receivers for the given method and args
|
78
|
+
function performInvoke (method, args, receivers) {
|
79
|
+
// dispatch ................................................................................................
|
6
80
|
if (method.match(/^dispatch(Event)?$/))
|
7
|
-
return
|
81
|
+
return invokeDispatchEvent(method, args, receivers)
|
8
82
|
|
9
|
-
// morph
|
10
|
-
if (method.match(/^morph|mutate$/))
|
83
|
+
// morph ...................................................................................................
|
84
|
+
if (method.match(/^morph|mutate$/))
|
85
|
+
return invokeMorph(method, args, receivers)
|
11
86
|
|
12
|
-
//
|
13
|
-
if (method.endsWith('='))
|
14
|
-
return receivers.forEach(r => (r[method.slice(0, -1).trim()] = args[0]))
|
87
|
+
// assignment ..............................................................................................
|
88
|
+
if (method.endsWith('=')) return invokeAssignment(method, args, receivers)
|
15
89
|
|
16
|
-
// method
|
17
|
-
|
90
|
+
// method ..................................................................................................
|
91
|
+
return invokeMethod(method, args, receivers)
|
18
92
|
}
|
19
93
|
|
20
|
-
function invoke () {
|
94
|
+
export function invoke () {
|
21
95
|
const payload = JSON.parse(this.templateContent.textContent)
|
22
|
-
const { id, selector, receiver, method, args } = payload
|
23
|
-
let receivers = [self]
|
24
|
-
if (selector)
|
96
|
+
const { id, selector, receiver, method, args, delay } = payload
|
97
|
+
let receivers = [{ object: self, target: self }]
|
98
|
+
if (selector)
|
99
|
+
receivers = Array.from(document.querySelectorAll(selector)).map(el => ({
|
100
|
+
object: el,
|
101
|
+
target: el
|
102
|
+
}))
|
25
103
|
|
26
104
|
if (receiver) {
|
27
105
|
receivers = receivers.map(r => {
|
28
|
-
let
|
106
|
+
let { object, target } = r
|
29
107
|
const chain = receiver.split('.')
|
30
|
-
while (chain.length > 0)
|
31
|
-
|
108
|
+
while (chain.length > 0) {
|
109
|
+
object = object[chain.shift()]
|
110
|
+
if (object.dispatchEvent) target = object
|
111
|
+
}
|
112
|
+
return { object, target }
|
32
113
|
})
|
33
114
|
}
|
34
115
|
|
35
|
-
|
116
|
+
if (delay > 0) setTimeout(() => performInvoke(method, args, receivers), delay)
|
117
|
+
else performInvoke(method, args, receivers)
|
36
118
|
}
|
37
|
-
|
38
|
-
export default invoke
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import alpine from 'alpinejs'
|
2
|
-
import
|
2
|
+
import alpineMorph from '@alpinejs/morph'
|
3
3
|
|
4
|
-
alpine.plugin(
|
4
|
+
alpine.plugin(alpineMorph)
|
5
5
|
|
6
6
|
const input = /INPUT/i
|
7
7
|
const inputTypes = /date|datetime-local|email|month|number|password|range|search|tel|text|time|url|week/i
|
@@ -18,8 +18,6 @@ function updating (el, toEl, childrenOnly, skip) {
|
|
18
18
|
if (protect) return skip()
|
19
19
|
}
|
20
20
|
|
21
|
-
function
|
22
|
-
|
21
|
+
export default function morph (element, html) {
|
22
|
+
alpine.morph(element, html, { updating })
|
23
23
|
}
|
24
|
-
|
25
|
-
export default mutate
|
@@ -8,8 +8,7 @@ require_relative "../tag_helper"
|
|
8
8
|
module TurboBoost::Streams::Patches::TagBuilder
|
9
9
|
include TurboBoost::Streams::TagHelper
|
10
10
|
|
11
|
-
def invoke(
|
12
|
-
|
13
|
-
TurboBoost::Streams::StringWrapper.new tag
|
11
|
+
def invoke(...)
|
12
|
+
TurboBoost::Streams::StringWrapper.new turbo_stream_invoke_tag(...)
|
14
13
|
end
|
15
14
|
end
|
@@ -1,17 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module TurboBoost::Streams::TagHelper
|
4
|
-
def turbo_stream_invoke_tag(method, args: [], selector: nil, camelize: true, id: nil)
|
4
|
+
def turbo_stream_invoke_tag(method, args: [], delay: 0, selector: nil, camelize: true, id: nil)
|
5
5
|
id = SecureRandom.uuid if id.blank?
|
6
6
|
payload = HashWithIndifferentAccess.new(id: id.to_s, selector: selector)
|
7
|
-
payload.merge! method_details(method, args: args, camelize: camelize)
|
7
|
+
payload.merge! method_details(method, args: args, delay: delay, camelize: camelize)
|
8
8
|
payload.select! { |_, v| v.present? }
|
9
9
|
%(<turbo-stream action="invoke" target="DOM"><template>#{payload.to_json}</template></turbo-stream>).html_safe
|
10
10
|
end
|
11
11
|
|
12
12
|
private
|
13
13
|
|
14
|
-
def method_details(method, args: [], camelize: true)
|
14
|
+
def method_details(method, args: [], delay: 0, camelize: true)
|
15
15
|
if camelize
|
16
16
|
method = camelize_method(method)
|
17
17
|
args = camelize_args(args)
|
@@ -22,7 +22,8 @@ module TurboBoost::Streams::TagHelper
|
|
22
22
|
HashWithIndifferentAccess.new(
|
23
23
|
receiver: method_parts[0..-2].join("."),
|
24
24
|
method: method_parts.last,
|
25
|
-
args: args
|
25
|
+
args: args,
|
26
|
+
delay: delay.to_i
|
26
27
|
)
|
27
28
|
end
|
28
29
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: turbo_boost-streams
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nate Hopkins (hopsoft)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-01-
|
11
|
+
date: 2023-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -311,8 +311,7 @@ files:
|
|
311
311
|
- app/assets/images/turbo-boost-mark.afdesign
|
312
312
|
- app/javascript/index.js
|
313
313
|
- app/javascript/invoke.js
|
314
|
-
- app/javascript/
|
315
|
-
- app/javascript/methods/mutate.js
|
314
|
+
- app/javascript/morph.js
|
316
315
|
- app/jobs/turbo_boost/streams/broadcast_invoke_job.rb
|
317
316
|
- lib/turbo_boost/streams.rb
|
318
317
|
- lib/turbo_boost/streams/engine.rb
|
@@ -338,14 +337,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
338
337
|
requirements:
|
339
338
|
- - ">="
|
340
339
|
- !ruby/object:Gem::Version
|
341
|
-
version: '
|
340
|
+
version: '2.7'
|
342
341
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
343
342
|
requirements:
|
344
343
|
- - ">="
|
345
344
|
- !ruby/object:Gem::Version
|
346
345
|
version: '0'
|
347
346
|
requirements: []
|
348
|
-
rubygems_version: 3.
|
347
|
+
rubygems_version: 3.4.1
|
349
348
|
signing_key:
|
350
349
|
specification_version: 4
|
351
350
|
summary: Take full control of the DOM with Turbo Streams
|