view_component_reflex 3.1.1 → 3.1.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.
@@ -0,0 +1,19 @@
1
+ module ViewComponentReflex
2
+ class NullBroadcaster < StimulusReflex::Broadcaster
3
+ def broadcast(_, data)
4
+ nil
5
+ end
6
+
7
+ def nothing?
8
+ true
9
+ end
10
+
11
+ def to_sym
12
+ :nothing
13
+ end
14
+
15
+ def to_s
16
+ "Nothing"
17
+ end
18
+ end
19
+ end
@@ -1,198 +1,202 @@
1
- module ViewComponentReflex
2
- class Reflex < StimulusReflex::Reflex
3
-
4
- class << self
5
- attr_accessor :component_class
6
- end
7
-
8
- def refresh!(primary_selector = nil, *rest)
9
- save_state
10
-
11
- if primary_selector.nil? && !component.can_render_to_string?
12
- primary_selector = selector
13
- end
14
- if primary_selector
15
- prevent_refresh!
16
-
17
- controller.process(params[:action])
18
- document = Nokogiri::HTML(controller.response.body)
19
- [primary_selector, *rest].each do |s|
20
- html = document.css(s)
21
- if html.present?
22
- CableReady::Channels.instance[stream].morph(
23
- selector: s,
24
- html: html.inner_html,
25
- children_only: true,
26
- permanent_attribute_name: "data-reflex-permanent",
27
- stimulus_reflex: stimulus_reflex_data
28
- )
29
- end
30
- end
31
- else
32
- refresh_component!
33
- end
34
- cable_ready.broadcast
35
- end
36
-
37
- def stream
38
- @stream ||= stream_name
39
- end
40
-
41
- def stream_to(channel)
42
- @stream = channel
43
- end
44
-
45
- def refresh_component!
46
- component.tap do |k|
47
- k.define_singleton_method(:key) do
48
- element.dataset[:key]
49
- end
50
- end
51
- document = Nokogiri::HTML(component.render_in(controller.view_context))
52
- CableReady::Channels.instance[stream].morph(
53
- selector: selector,
54
- children_only: true,
55
- html: document.css(selector).inner_html,
56
- permanent_attribute_name: "data-reflex-permanent",
57
- stimulus_reflex: stimulus_reflex_data
58
- )
59
- end
60
-
61
- def stimulus_reflex_data
62
- {
63
- reflex_id: reflex_id,
64
- xpath: xpath,
65
- target: target,
66
- c_xpath: c_xpath,
67
- reflex_controller: reflex_controller,
68
- url: url,
69
- morph: :page,
70
- attrs: {
71
- key: element.dataset[:key]
72
- }
73
- }
74
- end
75
-
76
- def target
77
- "#{component_class}##{method_name}"
78
- end
79
-
80
- def refresh_all!
81
- refresh!("body")
82
- end
83
-
84
- def selector
85
- "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]"
86
- end
87
-
88
- # SR's delegate_call_to_reflex in channel.rb
89
- # uses method to gather the method parameters, but since we're abusing
90
- # method_missing here, that'll always fail
91
- def method(name)
92
- component.method(name.to_sym)
93
- end
94
-
95
- def respond_to_missing?(name, _ = false)
96
- !!name.to_proc
97
- end
98
-
99
- # this is copied out of stimulus_reflex/reflex.rb and modified
100
- def morph(selectors, html = "")
101
- case selectors
102
- when :nothing
103
- @broadcaster = StimulusReflex::NothingBroadcaster.new(self)
104
- else
105
- @broadcaster = StimulusReflex::SelectorBroadcaster.new(self) unless broadcaster.selector?
106
- broadcaster.morphs << [selectors, html]
107
- end
108
- end
109
-
110
- def method_missing(name, *args)
111
- morph :nothing
112
- super unless respond_to_missing?(name)
113
- state.each do |k, v|
114
- component.instance_variable_set(k, v)
115
- end
116
- name.to_proc.call(component, *args)
117
- refresh! unless @prevent_refresh
118
- end
119
-
120
- def prevent_refresh!
121
- @prevent_refresh = true
122
- end
123
-
124
- private
125
-
126
- def component_class
127
- self.class.component_class
128
- end
129
-
130
- def stimulus_controller
131
- component_class.stimulus_controller
132
- end
133
-
134
- def stimulate(target, data)
135
- data_to_receive = {}
136
-
137
- stimulus_reflex_data.each do |k, v|
138
- data_to_receive[k.to_s.camelize(:lower)] = v
139
- end
140
-
141
- data_to_receive["dataset"] = data.each_with_object({}) do |(k, v), o|
142
- o["data-#{k}"] = v
143
- end
144
-
145
- data_to_receive["attrs"] = element.attributes.to_h.symbolize_keys
146
- data_to_receive["target"] = target
147
-
148
- channel.receive data_to_receive
149
- end
150
-
151
- def component
152
- return @component if @component
153
- @component = component_class.allocate
154
- reflex = self
155
- exposed_methods = [
156
- :params,
157
- :request,
158
- :connection,
159
- :element,
160
- :refresh!,
161
- :refresh_all!,
162
- :stimulus_controller,
163
- :session,
164
- :prevent_refresh!,
165
- :selector,
166
- :stimulate,
167
- :stream_to
168
- ]
169
- exposed_methods.each do |meth|
170
- @component.define_singleton_method(meth) do |*a|
171
- reflex.send(meth, *a)
172
- end
173
- end
174
-
175
- @component.define_singleton_method(:reflex) do
176
- reflex
177
- end
178
-
179
- @component
180
- end
181
-
182
- def set_state(new_state = {})
183
- ViewComponentReflex::Engine.state_adapter.set_state(request, controller, element.dataset[:key], new_state)
184
- end
185
-
186
- def state
187
- ViewComponentReflex::Engine.state_adapter.state(request, element.dataset[:key])
188
- end
189
-
190
- def save_state
191
- new_state = {}
192
- component.safe_instance_variables.each do |k|
193
- new_state[k] = component.instance_variable_get(k)
194
- end
195
- set_state(new_state)
196
- end
197
- end
198
- end
1
+ module ViewComponentReflex
2
+ class Reflex < StimulusReflex::Reflex
3
+
4
+ class << self
5
+ attr_accessor :component_class
6
+ end
7
+
8
+ def refresh!(primary_selector = nil, *rest)
9
+ save_state
10
+
11
+ if primary_selector.nil? && !component.can_render_to_string?
12
+ primary_selector = selector
13
+ end
14
+ if primary_selector
15
+ prevent_refresh!
16
+
17
+ controller.process(params[:action])
18
+ document = Nokogiri::HTML(controller.response.body)
19
+ [primary_selector, *rest].each do |s|
20
+ html = document.css(s)
21
+ if html.present?
22
+ CableReady::Channels.instance[stream].morph(
23
+ selector: s,
24
+ html: html.inner_html,
25
+ children_only: true,
26
+ permanent_attribute_name: "data-reflex-permanent",
27
+ stimulus_reflex: stimulus_reflex_data
28
+ )
29
+ end
30
+ end
31
+ else
32
+ refresh_component!
33
+ end
34
+ CableReady::Channels.instance[stream].broadcast
35
+ end
36
+
37
+ def stream
38
+ @stream ||= stream_name
39
+ end
40
+
41
+ def stream_to(channel)
42
+ @stream = channel
43
+ end
44
+
45
+ def refresh_component!
46
+ component.tap do |k|
47
+ k.define_singleton_method(:key) do
48
+ element.dataset[:key]
49
+ end
50
+ end
51
+ document = Nokogiri::HTML(component.render_in(controller.view_context))
52
+ CableReady::Channels.instance[stream].morph(
53
+ selector: selector,
54
+ children_only: true,
55
+ html: document.css(selector).inner_html,
56
+ permanent_attribute_name: "data-reflex-permanent",
57
+ stimulus_reflex: stimulus_reflex_data
58
+ )
59
+ end
60
+
61
+ def stimulus_reflex_data
62
+ {
63
+ reflex_id: reflex_id,
64
+ xpath_controller: xpath_controller,
65
+ xpath_element: xpath_element,
66
+ target: target,
67
+ reflex_controller: reflex_controller,
68
+ url: url,
69
+ morph: :page,
70
+ attrs: {
71
+ key: element.dataset[:key]
72
+ }
73
+ }
74
+ end
75
+
76
+ def target
77
+ "#{component_class}##{method_name}"
78
+ end
79
+
80
+ def refresh_all!
81
+ refresh!("body")
82
+ end
83
+
84
+ def selector
85
+ "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]"
86
+ end
87
+
88
+ # SR's delegate_call_to_reflex in channel.rb
89
+ # uses method to gather the method parameters, but since we're abusing
90
+ # method_missing here, that'll always fail
91
+ def method(name)
92
+ component.method(name.to_sym)
93
+ end
94
+
95
+ def respond_to_missing?(name, _ = false)
96
+ !!name.to_proc
97
+ end
98
+
99
+ # this is copied out of stimulus_reflex/reflex.rb and modified
100
+ def morph(selectors, html = "")
101
+ case selectors
102
+ when :nothing
103
+ @broadcaster = StimulusReflex::NothingBroadcaster.new(self)
104
+ when :null
105
+ @broadcaster = NullBroadcaster.new(self)
106
+ else
107
+ @broadcaster = StimulusReflex::SelectorBroadcaster.new(self) unless broadcaster.selector?
108
+ broadcaster.morphs << [selectors, html]
109
+ end
110
+ end
111
+
112
+ def method_missing(name, *args, &blk)
113
+ morph :null
114
+ super unless respond_to_missing?(name)
115
+ state.each do |k, v|
116
+ component.instance_variable_set(k, v)
117
+ end
118
+
119
+ component.send(name, *args, &blk)
120
+
121
+ refresh! unless @prevent_refresh
122
+ end
123
+
124
+ def prevent_refresh!
125
+ @prevent_refresh = true
126
+ end
127
+
128
+ private
129
+
130
+ def component_class
131
+ self.class.component_class
132
+ end
133
+
134
+ def stimulus_controller
135
+ component_class.stimulus_controller
136
+ end
137
+
138
+ def stimulate(target, data)
139
+ data_to_receive = {}
140
+
141
+ stimulus_reflex_data.each do |k, v|
142
+ data_to_receive[k.to_s.camelize(:lower)] = v
143
+ end
144
+
145
+ data_to_receive["dataset"] = data.each_with_object({}) do |(k, v), o|
146
+ o["data-#{k}"] = v
147
+ end
148
+
149
+ data_to_receive["attrs"] = element.attributes.to_h.symbolize_keys
150
+ data_to_receive["target"] = target
151
+
152
+ channel.receive data_to_receive
153
+ end
154
+
155
+ def component
156
+ return @component if @component
157
+ @component = component_class.allocate
158
+ reflex = self
159
+ exposed_methods = [
160
+ :params,
161
+ :request,
162
+ :connection,
163
+ :element,
164
+ :refresh!,
165
+ :refresh_all!,
166
+ :stimulus_controller,
167
+ :session,
168
+ :prevent_refresh!,
169
+ :selector,
170
+ :stimulate,
171
+ :stream_to
172
+ ]
173
+ exposed_methods.each do |meth|
174
+ @component.define_singleton_method(meth) do |*a|
175
+ reflex.send(meth, *a)
176
+ end
177
+ end
178
+
179
+ @component.define_singleton_method(:reflex) do
180
+ reflex
181
+ end
182
+
183
+ @component
184
+ end
185
+
186
+ def set_state(new_state = {})
187
+ ViewComponentReflex::Engine.state_adapter.set_state(request, controller, element.dataset[:key], new_state)
188
+ end
189
+
190
+ def state
191
+ ViewComponentReflex::Engine.state_adapter.state(request, element.dataset[:key])
192
+ end
193
+
194
+ def save_state
195
+ new_state = {}
196
+ component.safe_instance_variables.each do |k|
197
+ new_state[k] = component.instance_variable_get(k)
198
+ end
199
+ set_state(new_state)
200
+ end
201
+ end
202
+ end
@@ -1,61 +1,61 @@
1
- module ViewComponentReflex
2
- class ReflexFactory
3
- def initialize(component)
4
- @component = component
5
- @new = false
6
- reflex.component_class = component
7
- end
8
-
9
- def nested?
10
- @nested ||= @component.name.include?("::")
11
- end
12
-
13
- def reflex_name
14
- @reflex_name ||= if nested?
15
- @component.name.split("::").last
16
- else
17
- @component.name
18
- end + "Reflex"
19
- end
20
-
21
- def new?
22
- @new
23
- end
24
-
25
- def reflex
26
- @reflex ||= if nested?
27
- reflex_from_nested_component
28
- else
29
- reflex_from_component
30
- end
31
- end
32
-
33
- def reflex_instance
34
- @reflex_instance ||= Class.new(@component.reflex_base_class)
35
- end
36
-
37
- def reflex_from_nested_component
38
- parent = if @component.respond_to? :module_parent
39
- @component.module_parent
40
- else
41
- @component.parent
42
- end
43
-
44
- if parent.const_defined?(reflex_name)
45
- parent.const_get(reflex_name)
46
- else
47
- @new = true
48
- parent.const_set(reflex_name, reflex_instance)
49
- end
50
- end
51
-
52
- def reflex_from_component
53
- if Object.const_defined?(reflex_name)
54
- Object.const_get(reflex_name)
55
- else
56
- @new = true
57
- Object.const_set(reflex_name, reflex_instance)
58
- end
59
- end
60
- end
61
- end
1
+ module ViewComponentReflex
2
+ class ReflexFactory
3
+ def initialize(component)
4
+ @component = component
5
+ @new = false
6
+ reflex.component_class = component
7
+ end
8
+
9
+ def nested?
10
+ @nested ||= @component.name.include?("::")
11
+ end
12
+
13
+ def reflex_name
14
+ @reflex_name ||= if nested?
15
+ @component.name.split("::").last
16
+ else
17
+ @component.name
18
+ end + "Reflex"
19
+ end
20
+
21
+ def new?
22
+ @new
23
+ end
24
+
25
+ def reflex
26
+ @reflex ||= if nested?
27
+ reflex_from_nested_component
28
+ else
29
+ reflex_from_component
30
+ end
31
+ end
32
+
33
+ def reflex_instance
34
+ @reflex_instance ||= Class.new(@component.reflex_base_class)
35
+ end
36
+
37
+ def reflex_from_nested_component
38
+ parent = if @component.respond_to? :module_parent
39
+ @component.module_parent
40
+ else
41
+ @component.parent
42
+ end
43
+
44
+ if parent.const_defined?(reflex_name)
45
+ parent.const_get(reflex_name)
46
+ else
47
+ @new = true
48
+ parent.const_set(reflex_name, reflex_instance)
49
+ end
50
+ end
51
+
52
+ def reflex_from_component
53
+ if Object.const_defined?(reflex_name)
54
+ Object.const_get(reflex_name)
55
+ else
56
+ @new = true
57
+ Object.const_set(reflex_name, reflex_instance)
58
+ end
59
+ end
60
+ end
61
+ end