motion 0.2.0 → 0.2.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/motion/action_cable_extentions.rb +6 -0
- data/lib/motion/action_cable_extentions/declarative_notifications.rb +96 -0
- data/lib/motion/action_cable_extentions/declarative_streams.rb +9 -43
- data/lib/motion/action_cable_extentions/synchronization.rb +34 -0
- data/lib/motion/channel.rb +11 -1
- data/lib/motion/component.rb +2 -0
- data/lib/motion/component/broadcasts.rb +38 -26
- data/lib/motion/component/motions.rb +20 -12
- data/lib/motion/component/periodic_timers.rb +66 -0
- data/lib/motion/component/rendering.rb +1 -10
- data/lib/motion/component_connection.rb +16 -0
- data/lib/motion/event.rb +9 -1
- data/lib/motion/markup_transformer.rb +5 -1
- data/lib/motion/serializer.rb +4 -0
- data/lib/motion/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63f815dc74ec8255bd6b7b07fae885691253e7903397ec2b6f1e79cc675c7261
|
4
|
+
data.tar.gz: 758239f08e068912a6e213773c0cc3d86338ecec6f738650f19f1a9d83656995
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dfc01de3b79448af437bc4a0386ab2a9800e75ecb7d0231dc565d2bb6e3a21699fc9d7e6b58932824f0dc9ced1c59ae4426e40b9486198f7d082dcf0a5d7ee68
|
7
|
+
data.tar.gz: 86223b046b0957a69d4d7301a0a6c5d85a51cdacd4b088eaa4b65fdd57643043bde5970aaa5de55fd093257b66f5cd2e06c320b891c02f7ec255ba1b3d7a824b
|
@@ -4,10 +4,16 @@ require "motion"
|
|
4
4
|
|
5
5
|
module Motion
|
6
6
|
module ActionCableExtentions
|
7
|
+
autoload :DeclarativeNotifications,
|
8
|
+
"motion/action_cable_extentions/declarative_notifications"
|
9
|
+
|
7
10
|
autoload :DeclarativeStreams,
|
8
11
|
"motion/action_cable_extentions/declarative_streams"
|
9
12
|
|
10
13
|
autoload :LogSuppression,
|
11
14
|
"motion/action_cable_extentions/log_suppression"
|
15
|
+
|
16
|
+
autoload :Synchronization,
|
17
|
+
"motion/action_cable_extentions/synchronization"
|
12
18
|
end
|
13
19
|
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "motion"
|
4
|
+
|
5
|
+
module Motion
|
6
|
+
module ActionCableExtentions
|
7
|
+
# Provides a `periodically_notify(broadcasts, to:)` API that can be used to
|
8
|
+
# declaratively specify when a handler should be called.
|
9
|
+
module DeclarativeNotifications
|
10
|
+
include Synchronization
|
11
|
+
|
12
|
+
def initialize(*)
|
13
|
+
super
|
14
|
+
|
15
|
+
# The current set of declarative notifications
|
16
|
+
@_declarative_notifications = {}
|
17
|
+
|
18
|
+
# The active timers for the declarative notifications
|
19
|
+
@_declarative_notifications_timers = {}
|
20
|
+
|
21
|
+
# The method we are routing declarative notifications to
|
22
|
+
@_declarative_notifications_target = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def declarative_notifications
|
26
|
+
@_declarative_notifications
|
27
|
+
end
|
28
|
+
|
29
|
+
def periodically_notify(notifications, via:)
|
30
|
+
(@_declarative_notifications.to_a - notifications.to_a)
|
31
|
+
.each do |notification, _interval|
|
32
|
+
_shutdown_declarative_notifcation_timer(notification)
|
33
|
+
end
|
34
|
+
|
35
|
+
(notifications.to_a - @_declarative_notifications.to_a)
|
36
|
+
.each do |notification, interval|
|
37
|
+
_setup_declarative_notifcation_timer(notification, interval)
|
38
|
+
end
|
39
|
+
|
40
|
+
@_declarative_notifications = notifications
|
41
|
+
@_declarative_notifications_target = via
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def stop_periodic_timers
|
47
|
+
super
|
48
|
+
|
49
|
+
@_declarative_notifications.clear
|
50
|
+
@_declarative_notifications_timers.clear
|
51
|
+
@_declarative_notifications_target = nil
|
52
|
+
end
|
53
|
+
|
54
|
+
# The only public interface in ActionCable for defining periodic timers is
|
55
|
+
# exposed at the class level. Looking at the source though, it is easy to
|
56
|
+
# see that new timers can be setup with `start_periodic_timer`. To ensure
|
57
|
+
# that we do not leak any timers, it is important to store these instances
|
58
|
+
# in `active_periodic_timers` so that ActionCable cleans them up for us
|
59
|
+
# when the channel shuts down. Also, periodic timers are not supported by
|
60
|
+
# the testing adapter, so we have to skip all of this in unit tests (it
|
61
|
+
# _will_ be covered in systems tests though).
|
62
|
+
#
|
63
|
+
# See `ActionCable::Channel::PeriodicTimers` for details.
|
64
|
+
def _setup_declarative_notifcation_timer(notification, interval)
|
65
|
+
return if connection.is_a?(ActionCable::Channel::ConnectionStub) ||
|
66
|
+
@_declarative_notifications_timers.include?(notification)
|
67
|
+
|
68
|
+
callback = proc do
|
69
|
+
synchronize_entrypoint! do
|
70
|
+
_handle_declarative_notifcation(notification)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
timer = start_periodic_timer(callback, every: interval)
|
75
|
+
|
76
|
+
@_declarative_notifications_timers[notification] = timer
|
77
|
+
active_periodic_timers << timer
|
78
|
+
end
|
79
|
+
|
80
|
+
def _shutdown_declarative_notifcation_timer(notification, *)
|
81
|
+
timer = @_declarative_notifications_timers.delete(notification)
|
82
|
+
return unless timer
|
83
|
+
|
84
|
+
timer.shutdown
|
85
|
+
active_periodic_timers.delete(timer)
|
86
|
+
end
|
87
|
+
|
88
|
+
def _handle_declarative_notifcation(notification)
|
89
|
+
return unless @_declarative_notifications_target &&
|
90
|
+
@_declarative_notifications.include?(notification)
|
91
|
+
|
92
|
+
send(@_declarative_notifications_target, notification)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -6,19 +6,13 @@ module Motion
|
|
6
6
|
module ActionCableExtentions
|
7
7
|
# Provides a `streaming_from(broadcasts, to:)` API that can be used to
|
8
8
|
# declaratively specify what `broadcasts` the channel is interested in
|
9
|
-
# receiving and `to` what method they should be routed.
|
10
|
-
# this module extends the "at most one executor at a time" property that
|
11
|
-
# naturally comes with actions to the streams that it sets up as well.
|
9
|
+
# receiving and `to` what method they should be routed.
|
12
10
|
module DeclarativeStreams
|
11
|
+
include Synchronization
|
12
|
+
|
13
13
|
def initialize(*)
|
14
14
|
super
|
15
15
|
|
16
|
-
# Allowing actions to be bound to streams (as this module provides)
|
17
|
-
# introduces the possibiliy of multiple threads accessing user code at
|
18
|
-
# the same time. Protect user code with a Monitor so we only have to
|
19
|
-
# worry about that here.
|
20
|
-
@_declarative_stream_monitor = Monitor.new
|
21
|
-
|
22
16
|
# Streams that we are currently interested in
|
23
17
|
@_declarative_streams = Set.new
|
24
18
|
|
@@ -30,19 +24,6 @@ module Motion
|
|
30
24
|
@_declarative_stream_proxies = Set.new
|
31
25
|
end
|
32
26
|
|
33
|
-
# Synchronize all ActionCable entry points (after initialization).
|
34
|
-
def subscribe_to_channel(*)
|
35
|
-
@_declarative_stream_monitor.synchronize { super }
|
36
|
-
end
|
37
|
-
|
38
|
-
def unsubscribe_from_channel(*)
|
39
|
-
@_declarative_stream_monitor.synchronize { super }
|
40
|
-
end
|
41
|
-
|
42
|
-
def perform_action(*)
|
43
|
-
@_declarative_stream_monitor.synchronize { super }
|
44
|
-
end
|
45
|
-
|
46
27
|
# Clean up declarative streams when all streams are stopped.
|
47
28
|
def stop_all_streams
|
48
29
|
super
|
@@ -73,32 +54,17 @@ module Motion
|
|
73
54
|
# TODO: I feel like the fact that we have to specify the coder here is
|
74
55
|
# a bug in ActionCable. It should be the default for this karg.
|
75
56
|
stream_from(broadcast, coder: ActiveSupport::JSON) do |message|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
# escape here as the internals of ActionCable will stop processing
|
80
|
-
# the broadcast.
|
81
|
-
|
82
|
-
_handle_exception_in_declarative_stream(broadcast, exception)
|
57
|
+
synchronize_entrypoint! do
|
58
|
+
_handle_incoming_broadcast_to_declarative_stream(broadcast, message)
|
59
|
+
end
|
83
60
|
end
|
84
61
|
end
|
85
62
|
|
86
63
|
def _handle_incoming_broadcast_to_declarative_stream(broadcast, message)
|
87
|
-
@
|
88
|
-
|
89
|
-
@_declarative_streams.include?(broadcast)
|
90
|
-
|
91
|
-
send(@_declarative_stream_target, broadcast, message)
|
92
|
-
end
|
93
|
-
end
|
64
|
+
return unless @_declarative_stream_target &&
|
65
|
+
@_declarative_streams.include?(broadcast)
|
94
66
|
|
95
|
-
|
96
|
-
logger.error(
|
97
|
-
"There was an exception while handling a broadcast to #{broadcast}" \
|
98
|
-
"on #{self.class}:\n" \
|
99
|
-
" #{exception.class}: #{exception.message}\n" \
|
100
|
-
"#{exception.backtrace.map { |line| " #{line}" }.join("\n")}"
|
101
|
-
)
|
67
|
+
send(@_declarative_stream_target, broadcast, message)
|
102
68
|
end
|
103
69
|
end
|
104
70
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "motion"
|
4
|
+
|
5
|
+
module Motion
|
6
|
+
module ActionCableExtentions
|
7
|
+
module Synchronization
|
8
|
+
def initialize(*)
|
9
|
+
super
|
10
|
+
|
11
|
+
@_monitor = Monitor.new
|
12
|
+
end
|
13
|
+
|
14
|
+
# Additional entrypoints added by other modules should wrap any entry
|
15
|
+
# points that they add with this.
|
16
|
+
def synchronize_entrypoint!(&block)
|
17
|
+
@_monitor.synchronize(&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Synchronize all standard ActionCable entry points.
|
21
|
+
def subscribe_to_channel(*)
|
22
|
+
synchronize_entrypoint! { super }
|
23
|
+
end
|
24
|
+
|
25
|
+
def unsubscribe_from_channel(*)
|
26
|
+
synchronize_entrypoint! { super }
|
27
|
+
end
|
28
|
+
|
29
|
+
def perform_action(*)
|
30
|
+
synchronize_entrypoint! { super }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/motion/channel.rb
CHANGED
@@ -6,6 +6,7 @@ require "motion"
|
|
6
6
|
|
7
7
|
module Motion
|
8
8
|
class Channel < ActionCable::Channel::Base
|
9
|
+
include ActionCableExtentions::DeclarativeNotifications
|
9
10
|
include ActionCableExtentions::DeclarativeStreams
|
10
11
|
include ActionCableExtentions::LogSuppression
|
11
12
|
|
@@ -56,10 +57,19 @@ module Motion
|
|
56
57
|
synchronize
|
57
58
|
end
|
58
59
|
|
60
|
+
def process_periodic_timer(timer)
|
61
|
+
component_connection.process_periodic_timer(timer)
|
62
|
+
synchronize
|
63
|
+
end
|
64
|
+
|
59
65
|
private
|
60
66
|
|
61
67
|
def synchronize
|
62
|
-
streaming_from
|
68
|
+
streaming_from component_connection.broadcasts,
|
69
|
+
to: :process_broadcast
|
70
|
+
|
71
|
+
periodically_notify component_connection.periodic_timers,
|
72
|
+
via: :process_periodic_timer
|
63
73
|
|
64
74
|
component_connection.if_render_required do |component|
|
65
75
|
transmit(renderer.render(component))
|
data/lib/motion/component.rb
CHANGED
@@ -7,6 +7,7 @@ require "motion"
|
|
7
7
|
require "motion/component/broadcasts"
|
8
8
|
require "motion/component/lifecycle"
|
9
9
|
require "motion/component/motions"
|
10
|
+
require "motion/component/periodic_timers"
|
10
11
|
require "motion/component/rendering"
|
11
12
|
|
12
13
|
module Motion
|
@@ -16,6 +17,7 @@ module Motion
|
|
16
17
|
include Broadcasts
|
17
18
|
include Lifecycle
|
18
19
|
include Motions
|
20
|
+
include PeriodicTimers
|
19
21
|
include Rendering
|
20
22
|
end
|
21
23
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require "active_support/concern"
|
4
4
|
require "active_support/core_ext/class/attribute"
|
5
5
|
require "active_support/core_ext/object/to_param"
|
6
|
+
require "active_support/core_ext/hash/except"
|
6
7
|
|
7
8
|
require "motion"
|
8
9
|
|
@@ -11,6 +12,31 @@ module Motion
|
|
11
12
|
module Broadcasts
|
12
13
|
extend ActiveSupport::Concern
|
13
14
|
|
15
|
+
# Analogous to `module_function` (available on both class and instance)
|
16
|
+
module ModuleFunctions
|
17
|
+
def stream_from(broadcast, handler)
|
18
|
+
self._broadcast_handlers =
|
19
|
+
_broadcast_handlers.merge(broadcast.to_s => handler.to_sym).freeze
|
20
|
+
end
|
21
|
+
|
22
|
+
def stop_streaming_from(broadcast)
|
23
|
+
self._broadcast_handlers =
|
24
|
+
_broadcast_handlers.except(broadcast.to_s).freeze
|
25
|
+
end
|
26
|
+
|
27
|
+
def stream_for(model, handler)
|
28
|
+
stream_from(broadcasting_for(model), handler)
|
29
|
+
end
|
30
|
+
|
31
|
+
def stop_streaming_for(model)
|
32
|
+
stop_streaming_from(broadcasting_for(model))
|
33
|
+
end
|
34
|
+
|
35
|
+
def broadcasts
|
36
|
+
_broadcast_handlers.keys
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
14
40
|
included do
|
15
41
|
class_attribute :_broadcast_handlers,
|
16
42
|
instance_reader: false,
|
@@ -20,26 +46,19 @@ module Motion
|
|
20
46
|
end
|
21
47
|
|
22
48
|
class_methods do
|
49
|
+
include ModuleFunctions
|
50
|
+
|
23
51
|
def broadcast_to(model, message)
|
24
52
|
ActionCable.server.broadcast(broadcasting_for(model), message)
|
25
53
|
end
|
26
54
|
|
27
|
-
def stream_from(broadcast, handler)
|
28
|
-
self._broadcast_handlers =
|
29
|
-
_broadcast_handlers.merge(broadcast.to_s => handler.to_sym).freeze
|
30
|
-
end
|
31
|
-
|
32
|
-
def stream_for(model, handler)
|
33
|
-
stream_from(broadcasting_for(model), handler)
|
34
|
-
end
|
35
|
-
|
36
55
|
def broadcasting_for(model)
|
37
56
|
serialize_broadcasting([name, model])
|
38
57
|
end
|
39
58
|
|
40
59
|
private
|
41
60
|
|
42
|
-
#
|
61
|
+
# This definition is copied from ActionCable::Channel::Broadcasting
|
43
62
|
def serialize_broadcasting(object)
|
44
63
|
if object.is_a?(Array)
|
45
64
|
object.map { |m| serialize_broadcasting(m) }.join(":")
|
@@ -51,31 +70,24 @@ module Motion
|
|
51
70
|
end
|
52
71
|
end
|
53
72
|
|
54
|
-
|
55
|
-
_broadcast_handlers.keys
|
56
|
-
end
|
73
|
+
include ModuleFunctions
|
57
74
|
|
58
75
|
def process_broadcast(broadcast, message)
|
59
76
|
return unless (handler = _broadcast_handlers[broadcast])
|
60
77
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
78
|
+
if method(handler).arity.zero?
|
79
|
+
send(handler)
|
80
|
+
else
|
81
|
+
send(handler, message)
|
82
|
+
end
|
66
83
|
end
|
67
84
|
|
68
|
-
|
69
|
-
self._broadcast_handlers =
|
70
|
-
_broadcast_handlers.merge(broadcast.to_s => handler.to_sym).freeze
|
71
|
-
end
|
85
|
+
private
|
72
86
|
|
73
|
-
def
|
74
|
-
|
87
|
+
def broadcasting_for(model)
|
88
|
+
self.class.broadcasting_for(model)
|
75
89
|
end
|
76
90
|
|
77
|
-
private
|
78
|
-
|
79
91
|
attr_writer :_broadcast_handlers
|
80
92
|
|
81
93
|
def _broadcast_handlers
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "active_support/concern"
|
4
4
|
require "active_support/core_ext/class/attribute"
|
5
|
+
require "active_support/core_ext/hash/except"
|
5
6
|
|
6
7
|
require "motion"
|
7
8
|
|
@@ -10,6 +11,23 @@ module Motion
|
|
10
11
|
module Motions
|
11
12
|
extend ActiveSupport::Concern
|
12
13
|
|
14
|
+
# Analogous to `module_function` (available on both class and instance)
|
15
|
+
module ModuleFunctions
|
16
|
+
def map_motion(motion, handler = motion)
|
17
|
+
self._motion_handlers =
|
18
|
+
_motion_handlers.merge(motion.to_s => handler.to_sym).freeze
|
19
|
+
end
|
20
|
+
|
21
|
+
def unmap_motion(motion)
|
22
|
+
self._motion_handlers =
|
23
|
+
_motion_handlers.except(motion.to_s).freeze
|
24
|
+
end
|
25
|
+
|
26
|
+
def motions
|
27
|
+
_motion_handlers.keys
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
13
31
|
included do
|
14
32
|
class_attribute :_motion_handlers,
|
15
33
|
instance_reader: false,
|
@@ -19,15 +37,10 @@ module Motion
|
|
19
37
|
end
|
20
38
|
|
21
39
|
class_methods do
|
22
|
-
|
23
|
-
self._motion_handlers =
|
24
|
-
_motion_handlers.merge(motion.to_s => handler.to_sym).freeze
|
25
|
-
end
|
40
|
+
include ModuleFunctions
|
26
41
|
end
|
27
42
|
|
28
|
-
|
29
|
-
_motion_handlers.keys
|
30
|
-
end
|
43
|
+
include ModuleFunctions
|
31
44
|
|
32
45
|
def process_motion(motion, event = nil)
|
33
46
|
unless (handler = _motion_handlers[motion])
|
@@ -41,11 +54,6 @@ module Motion
|
|
41
54
|
end
|
42
55
|
end
|
43
56
|
|
44
|
-
def map_motion(motion, handler = motion)
|
45
|
-
self._motion_handlers =
|
46
|
-
_motion_handlers.merge(motion.to_s => handler.to_sym).freeze
|
47
|
-
end
|
48
|
-
|
49
57
|
private
|
50
58
|
|
51
59
|
attr_writer :_motion_handlers
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
require "active_support/core_ext/class/attribute"
|
5
|
+
require "active_support/core_ext/hash/except"
|
6
|
+
|
7
|
+
require "motion"
|
8
|
+
|
9
|
+
module Motion
|
10
|
+
module Component
|
11
|
+
module PeriodicTimers
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
# Analogous to `module_function` (available on both class and instance)
|
15
|
+
module ModuleFunctions
|
16
|
+
def every(interval, handler, name: handler)
|
17
|
+
periodic_timer(name, handler, every: interval)
|
18
|
+
end
|
19
|
+
|
20
|
+
def periodic_timer(name, handler = name, every:)
|
21
|
+
self._periodic_timers =
|
22
|
+
_periodic_timers.merge(name.to_s => [handler.to_sym, every]).freeze
|
23
|
+
end
|
24
|
+
|
25
|
+
def stop_periodic_timer(name)
|
26
|
+
self._periodic_timers =
|
27
|
+
_periodic_timers.except(name.to_s).freeze
|
28
|
+
end
|
29
|
+
|
30
|
+
def periodic_timers
|
31
|
+
_periodic_timers.transform_values { |_handler, interval| interval }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
included do
|
36
|
+
class_attribute :_periodic_timers,
|
37
|
+
instance_reader: false,
|
38
|
+
instance_writer: false,
|
39
|
+
instance_predicate: false,
|
40
|
+
default: {}.freeze
|
41
|
+
end
|
42
|
+
|
43
|
+
class_methods do
|
44
|
+
include ModuleFunctions
|
45
|
+
end
|
46
|
+
|
47
|
+
include ModuleFunctions
|
48
|
+
|
49
|
+
def process_periodic_timer(name)
|
50
|
+
return unless (handler, _interval = _periodic_timers[name])
|
51
|
+
|
52
|
+
send(handler)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
attr_writer :_periodic_timers
|
58
|
+
|
59
|
+
def _periodic_timers
|
60
|
+
return @_periodic_timers if defined?(@_periodic_timers)
|
61
|
+
|
62
|
+
self.class._periodic_timers
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -24,16 +24,7 @@ module Motion
|
|
24
24
|
# * If it doesn't change every time the component's state changes,
|
25
25
|
# things may fall out of sync unless you also call `#rerender!`
|
26
26
|
def render_hash
|
27
|
-
|
28
|
-
#
|
29
|
-
# Is something with Ruby's built-in `hash` Good Enough(TM)?
|
30
|
-
#
|
31
|
-
# instance_variables
|
32
|
-
# .map { |ivar| instance_variable_get(ivar).hash }
|
33
|
-
# .reduce(0, &:^)
|
34
|
-
|
35
|
-
key, _state = Motion.serializer.serialize(self)
|
36
|
-
key
|
27
|
+
Motion.serializer.weak_digest(self)
|
37
28
|
end
|
38
29
|
|
39
30
|
def render_in(view_context)
|
@@ -64,6 +64,18 @@ module Motion
|
|
64
64
|
false
|
65
65
|
end
|
66
66
|
|
67
|
+
def process_periodic_timer(timer)
|
68
|
+
timing("Proccessed periodic timer #{timer}") do
|
69
|
+
component.process_periodic_timer timer
|
70
|
+
end
|
71
|
+
|
72
|
+
true
|
73
|
+
rescue => error
|
74
|
+
handle_error(error, "processing periodic timer #{timer}")
|
75
|
+
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
67
79
|
def if_render_required(&block)
|
68
80
|
timing("Rendered") do
|
69
81
|
next_render_hash = component.render_hash
|
@@ -83,6 +95,10 @@ module Motion
|
|
83
95
|
component.broadcasts
|
84
96
|
end
|
85
97
|
|
98
|
+
def periodic_timers
|
99
|
+
component.periodic_timers
|
100
|
+
end
|
101
|
+
|
86
102
|
private
|
87
103
|
|
88
104
|
attr_reader :log_helper
|
data/lib/motion/event.rb
CHANGED
@@ -34,8 +34,16 @@ module Motion
|
|
34
34
|
@target = Motion::Element.from_raw(raw["target"])
|
35
35
|
end
|
36
36
|
|
37
|
+
def current_target
|
38
|
+
return @current_target if defined?(@current_target)
|
39
|
+
|
40
|
+
@current_target = Motion::Element.from_raw(raw["currentTarget"])
|
41
|
+
end
|
42
|
+
|
43
|
+
alias element current_target
|
44
|
+
|
37
45
|
def form_data
|
38
|
-
|
46
|
+
element&.form_data
|
39
47
|
end
|
40
48
|
end
|
41
49
|
end
|
@@ -21,6 +21,8 @@ module Motion
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def add_state_to_html(component, html)
|
24
|
+
return html if html.blank?
|
25
|
+
|
24
26
|
key, state = serializer.serialize(component)
|
25
27
|
|
26
28
|
transform_root(component, html) do |root|
|
@@ -35,7 +37,9 @@ module Motion
|
|
35
37
|
fragment = Nokogiri::HTML::DocumentFragment.parse(html)
|
36
38
|
root, *unexpected_others = fragment.children
|
37
39
|
|
38
|
-
|
40
|
+
if !root || unexpected_others.any?(&:present?)
|
41
|
+
raise MultipleRootsError, component
|
42
|
+
end
|
39
43
|
|
40
44
|
yield root
|
41
45
|
|
data/lib/motion/serializer.rb
CHANGED
data/lib/motion/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: motion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alec Larsen
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-07-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -55,13 +55,16 @@ files:
|
|
55
55
|
- lib/generators/motion/templates/motion.rb
|
56
56
|
- lib/motion.rb
|
57
57
|
- lib/motion/action_cable_extentions.rb
|
58
|
+
- lib/motion/action_cable_extentions/declarative_notifications.rb
|
58
59
|
- lib/motion/action_cable_extentions/declarative_streams.rb
|
59
60
|
- lib/motion/action_cable_extentions/log_suppression.rb
|
61
|
+
- lib/motion/action_cable_extentions/synchronization.rb
|
60
62
|
- lib/motion/channel.rb
|
61
63
|
- lib/motion/component.rb
|
62
64
|
- lib/motion/component/broadcasts.rb
|
63
65
|
- lib/motion/component/lifecycle.rb
|
64
66
|
- lib/motion/component/motions.rb
|
67
|
+
- lib/motion/component/periodic_timers.rb
|
65
68
|
- lib/motion/component/rendering.rb
|
66
69
|
- lib/motion/component_connection.rb
|
67
70
|
- lib/motion/configuration.rb
|
@@ -82,7 +85,7 @@ metadata:
|
|
82
85
|
source_code_uri: https://github.com/unabridged/motion
|
83
86
|
post_install_message: |
|
84
87
|
Friendly reminder: When updating the motion gem, don't forget to update the
|
85
|
-
NPM package as well (`bin/yarn add '@unabridged/motion@0.2.
|
88
|
+
NPM package as well (`bin/yarn add '@unabridged/motion@0.2.1'`).
|
86
89
|
rdoc_options: []
|
87
90
|
require_paths:
|
88
91
|
- lib
|