view_component_reflex 3.3.5 → 3.3.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.
@@ -1,228 +1,228 @@
1
- module ViewComponentReflex
2
- class Reflex < StimulusReflex::Reflex
3
- class << self
4
- attr_accessor :component_class
5
- end
6
-
7
- # pretty sure I can't memoize this because we need
8
- # to re-render every time
9
- def controller_document
10
- controller.process(params[:action])
11
- Nokogiri::HTML(controller.response.body)
12
- end
13
-
14
- def cable_ready
15
- CableReady::Channels.instance[stream]
16
- end
17
-
18
- def refresh!(primary_selector = nil, *rest)
19
- save_state
20
-
21
- if primary_selector.nil? && !component.can_render_to_string?
22
- primary_selector = selector
23
- end
24
- if primary_selector
25
- prevent_refresh!
26
-
27
- document = controller_document
28
- [primary_selector, *rest].each do |s|
29
- html = document.css(s)
30
- if html.present?
31
- cable_ready.morph(
32
- selector: s,
33
- html: html.inner_html,
34
- children_only: true,
35
- permanent_attribute_name: "data-reflex-permanent",
36
- reflex_id: reflex_id
37
- )
38
- end
39
- end
40
- else
41
- refresh_component!
42
- end
43
- cable_ready.broadcast
44
- end
45
-
46
- def stream
47
- @stream ||= stream_name
48
- end
49
-
50
- def stream_to(channel)
51
- @stream = channel
52
- end
53
-
54
- def inject_key_into_component
55
- component.tap do |k|
56
- k.define_singleton_method(:initialize_component) do
57
- @key = element.dataset[:key]
58
- end
59
- end
60
- end
61
-
62
- def component_document
63
- Nokogiri::HTML(component.render_in(controller.view_context))
64
- end
65
-
66
- def refresh_component!
67
- cable_ready.morph(
68
- selector: selector,
69
- children_only: true,
70
- html: component_document.css(selector).to_html,
71
- permanent_attribute_name: "data-reflex-permanent",
72
- reflex_id: reflex_id
73
- )
74
- end
75
-
76
- def default_morph
77
- save_state
78
- html = if component.can_render_to_string?
79
- component_document.css(selector).to_html
80
- else
81
- controller_document.css(selector).to_html
82
- end
83
- morph selector, html
84
- end
85
-
86
- def stimulus_reflex_data
87
- {
88
- reflex_id: reflex_id,
89
- xpath_controller: xpath_controller,
90
- xpath_element: xpath_element,
91
- target: target,
92
- reflex_controller: reflex_controller,
93
- version: version,
94
- url: url,
95
- morph: :page,
96
- attrs: {
97
- key: element.dataset[:key]
98
- }
99
- }
100
- end
101
-
102
- def target
103
- "#{component_class}##{method_name}"
104
- end
105
-
106
- def refresh_all!
107
- refresh!("body")
108
- end
109
-
110
- def selector
111
- "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]"
112
- end
113
-
114
- def delegate_call_to_reflex(name, *args, &blk)
115
- component.adapter.extend_reflex(self)
116
-
117
- state.each do |k, v|
118
- component.instance_variable_set(k, v)
119
- end
120
-
121
- component.send(name, *args, &blk)
122
-
123
- if @prevent_refresh
124
- morph :nothing
125
- else
126
- default_morph
127
- end
128
- end
129
-
130
- def prevent_refresh!
131
- @prevent_refresh = true
132
- end
133
-
134
- private
135
-
136
- def component_class
137
- self.class.component_class
138
- end
139
-
140
- def stimulus_controller
141
- component_class.stimulus_controller
142
- end
143
-
144
- def stimulate(target, data)
145
- data_to_receive = {
146
- "dataset" => {
147
- "datasetAll" => {},
148
- "dataset" => {}
149
- }
150
- }
151
-
152
- stimulus_reflex_data.each do |k, v|
153
- data_to_receive[k.to_s.camelize(:lower)] = v
154
- end
155
-
156
- data_to_receive["dataset"]["dataset"] = data.each_with_object({}) do |(k, v), o|
157
- o["data-#{k}"] = v
158
- end
159
-
160
- data_to_receive["attrs"] = element.attributes.to_h.symbolize_keys
161
- data_to_receive["target"] = target
162
-
163
- channel.receive data_to_receive
164
- end
165
-
166
- def component
167
- return @component if @component
168
- @component = component_class.allocate
169
- reflex = self
170
- exposed_methods = [
171
- :params,
172
- :request,
173
- :connection,
174
- :element,
175
- :refresh!,
176
- :refresh_all!,
177
- :stimulus_controller,
178
- :session,
179
- :prevent_refresh!,
180
- :selector,
181
- :stimulate,
182
- :stream_to,
183
- :cable_ready
184
- ]
185
- exposed_methods.each do |meth|
186
- @component.define_singleton_method(meth) do |*a|
187
- reflex.send(meth, *a)
188
- end
189
- end
190
-
191
- @component.define_singleton_method(:reflex) do
192
- reflex
193
- end
194
-
195
- inject_key_into_component
196
-
197
- @component
198
- end
199
-
200
- def set_state(new_state = {})
201
- state_adapter.set_state(request, controller, key, new_state)
202
- end
203
-
204
- def key
205
- element.dataset[:key]
206
- end
207
-
208
- def state_adapter
209
- component.adapter
210
- end
211
-
212
- def state
213
- state_adapter.state(request, key)
214
- end
215
-
216
- def initial_state
217
- state_adapter.state(request, "#{key}_initial")
218
- end
219
-
220
- def save_state
221
- new_state = {}
222
- component.safe_instance_variables.each do |k|
223
- new_state[k] = component.instance_variable_get(k)
224
- end
225
- set_state(new_state)
226
- end
227
- end
228
- end
1
+ module ViewComponentReflex
2
+ class Reflex < StimulusReflex::Reflex
3
+ class << self
4
+ attr_accessor :component_class
5
+ end
6
+
7
+ # pretty sure I can't memoize this because we need
8
+ # to re-render every time
9
+ def controller_document
10
+ controller.process(params[:action])
11
+ Nokogiri::HTML(controller.response.body)
12
+ end
13
+
14
+ def cable_ready
15
+ CableReady::Channels.instance[stream]
16
+ end
17
+
18
+ def refresh!(primary_selector = nil, *rest)
19
+ save_state
20
+
21
+ if primary_selector.nil? && !component.can_render_to_string?
22
+ primary_selector = selector
23
+ end
24
+ if primary_selector
25
+ prevent_refresh!
26
+
27
+ document = controller_document
28
+ [primary_selector, *rest].each do |s|
29
+ html = document.css(s)
30
+ if html.present?
31
+ cable_ready.morph(
32
+ selector: s,
33
+ html: html.inner_html,
34
+ children_only: true,
35
+ permanent_attribute_name: "data-reflex-permanent",
36
+ reflex_id: reflex_id
37
+ )
38
+ end
39
+ end
40
+ else
41
+ refresh_component!
42
+ end
43
+ cable_ready.broadcast
44
+ end
45
+
46
+ def stream
47
+ @stream ||= stream_name
48
+ end
49
+
50
+ def stream_to(channel)
51
+ @stream = channel
52
+ end
53
+
54
+ def inject_key_into_component
55
+ component.tap do |k|
56
+ k.define_singleton_method(:initialize_component) do
57
+ @key = element.dataset[:key]
58
+ end
59
+ end
60
+ end
61
+
62
+ def component_document
63
+ Nokogiri::HTML(component.render_in(controller.view_context))
64
+ end
65
+
66
+ def refresh_component!
67
+ cable_ready.morph(
68
+ selector: selector,
69
+ children_only: true,
70
+ html: component_document.css(selector).to_html,
71
+ permanent_attribute_name: "data-reflex-permanent",
72
+ reflex_id: reflex_id
73
+ )
74
+ end
75
+
76
+ def default_morph
77
+ save_state
78
+ html = if component.can_render_to_string?
79
+ component_document.css(selector).to_html
80
+ else
81
+ controller_document.css(selector).to_html
82
+ end
83
+ morph selector, html
84
+ end
85
+
86
+ def stimulus_reflex_data
87
+ {
88
+ reflex_id: reflex_id,
89
+ xpath_controller: xpath_controller,
90
+ xpath_element: xpath_element,
91
+ target: target,
92
+ reflex_controller: reflex_controller,
93
+ version: version,
94
+ url: url,
95
+ morph: :page,
96
+ attrs: {
97
+ key: element.dataset[:key]
98
+ }
99
+ }
100
+ end
101
+
102
+ def target
103
+ "#{component_class}##{method_name}"
104
+ end
105
+
106
+ def refresh_all!
107
+ refresh!("body")
108
+ end
109
+
110
+ def selector
111
+ "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]"
112
+ end
113
+
114
+ def delegate_call_to_reflex(name, *args, &blk)
115
+ component.adapter.extend_reflex(self)
116
+
117
+ state.each do |k, v|
118
+ component.instance_variable_set(k, v)
119
+ end
120
+
121
+ component.send(name, *args, &blk)
122
+
123
+ if @prevent_refresh
124
+ morph :nothing
125
+ else
126
+ default_morph
127
+ end
128
+ end
129
+
130
+ def prevent_refresh!
131
+ @prevent_refresh = true
132
+ end
133
+
134
+ private
135
+
136
+ def component_class
137
+ self.class.component_class
138
+ end
139
+
140
+ def stimulus_controller
141
+ component_class.stimulus_controller
142
+ end
143
+
144
+ def stimulate(target, data)
145
+ data_to_receive = {
146
+ "dataset" => {
147
+ "datasetAll" => {},
148
+ "dataset" => {}
149
+ }
150
+ }
151
+
152
+ stimulus_reflex_data.each do |k, v|
153
+ data_to_receive[k.to_s.camelize(:lower)] = v
154
+ end
155
+
156
+ data_to_receive["dataset"]["dataset"] = data.each_with_object({}) do |(k, v), o|
157
+ o["data-#{k}"] = v
158
+ end
159
+
160
+ data_to_receive["attrs"] = element.attributes.to_h.symbolize_keys
161
+ data_to_receive["target"] = target
162
+
163
+ channel.receive data_to_receive
164
+ end
165
+
166
+ def component
167
+ return @component if @component
168
+ @component = component_class.allocate
169
+ reflex = self
170
+ exposed_methods = [
171
+ :params,
172
+ :request,
173
+ :connection,
174
+ :element,
175
+ :refresh!,
176
+ :refresh_all!,
177
+ :stimulus_controller,
178
+ :session,
179
+ :prevent_refresh!,
180
+ :selector,
181
+ :stimulate,
182
+ :stream_to,
183
+ :cable_ready
184
+ ]
185
+ exposed_methods.each do |meth|
186
+ @component.define_singleton_method(meth) do |*a|
187
+ reflex.send(meth, *a)
188
+ end
189
+ end
190
+
191
+ @component.define_singleton_method(:reflex) do
192
+ reflex
193
+ end
194
+
195
+ inject_key_into_component
196
+
197
+ @component
198
+ end
199
+
200
+ def set_state(new_state = {})
201
+ state_adapter.set_state(request, controller, key, new_state)
202
+ end
203
+
204
+ def key
205
+ element.dataset[:key]
206
+ end
207
+
208
+ def state_adapter
209
+ component.adapter
210
+ end
211
+
212
+ def state
213
+ state_adapter.state(request, key)
214
+ end
215
+
216
+ def initial_state
217
+ state_adapter.state(request, "#{key}_initial")
218
+ end
219
+
220
+ def save_state
221
+ new_state = {}
222
+ component.safe_instance_variables.each do |k|
223
+ new_state[k] = component.instance_variable_get(k)
224
+ end
225
+ set_state(new_state)
226
+ end
227
+ end
228
+ end
@@ -1,77 +1,77 @@
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 ||= build_reflex_instance
35
- end
36
-
37
- ##
38
- # Beyond just creating the <Component>Reflex class, we need to define all the component methods on the reflex
39
- # class.
40
- # This replaces the old method_missing implementation, and passes more strict validation of recent SR versions
41
- def build_reflex_instance
42
- reflex_methods = @component.instance_methods - @component.superclass.instance_methods - [:call, :"_call_#{@component.name.underscore}"]
43
-
44
- Class.new(@component.reflex_base_class).tap do |klass|
45
- reflex_methods.each do |m|
46
- klass.define_method(m) do |*args, &blk|
47
- delegate_call_to_reflex(method_name, *args, &blk)
48
- end
49
- end
50
- end
51
- end
52
-
53
- def reflex_from_nested_component
54
- parent = if @component.respond_to? :module_parent
55
- @component.module_parent
56
- else
57
- @component.parent
58
- end
59
-
60
- if parent.const_defined?(reflex_name)
61
- parent.const_get(reflex_name)
62
- else
63
- @new = true
64
- parent.const_set(reflex_name, reflex_instance)
65
- end
66
- end
67
-
68
- def reflex_from_component
69
- if Object.const_defined?(reflex_name)
70
- Object.const_get(reflex_name)
71
- else
72
- @new = true
73
- Object.const_set(reflex_name, reflex_instance)
74
- end
75
- end
76
- end
77
- 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 ||= build_reflex_instance
35
+ end
36
+
37
+ ##
38
+ # Beyond just creating the <Component>Reflex class, we need to define all the component methods on the reflex
39
+ # class.
40
+ # This replaces the old method_missing implementation, and passes more strict validation of recent SR versions
41
+ def build_reflex_instance
42
+ reflex_methods = @component.instance_methods - @component.superclass.instance_methods - [:call, :"_call_#{@component.name.underscore}"]
43
+
44
+ Class.new(@component.reflex_base_class).tap do |klass|
45
+ reflex_methods.each do |m|
46
+ klass.define_method(m) do |*args, &blk|
47
+ delegate_call_to_reflex(m, *args, &blk)
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ def reflex_from_nested_component
54
+ parent = if @component.respond_to? :module_parent
55
+ @component.module_parent
56
+ else
57
+ @component.parent
58
+ end
59
+
60
+ if parent.const_defined?(reflex_name)
61
+ parent.const_get(reflex_name)
62
+ else
63
+ @new = true
64
+ parent.const_set(reflex_name, reflex_instance)
65
+ end
66
+ end
67
+
68
+ def reflex_from_component
69
+ if Object.const_defined?(reflex_name)
70
+ Object.const_get(reflex_name)
71
+ else
72
+ @new = true
73
+ Object.const_set(reflex_name, reflex_instance)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -1,42 +1,42 @@
1
- module ViewComponentReflex
2
- module StateAdapter
3
- class Base
4
-
5
- def self.state(request, key)
6
- # stub
7
- end
8
-
9
- def self.set_state(request, controller, key, new_state)
10
- # stub
11
- end
12
-
13
- def self.store_state(request, key, new_state = {})
14
- # stub
15
- end
16
-
17
- def self.wrap_write_async
18
- yield
19
- end
20
-
21
- def self.extend_component(component)
22
- # stub
23
- end
24
-
25
- def self.extend_reflex(component)
26
- # stub
27
- end
28
-
29
- private
30
-
31
- def self.extract_id(request)
32
- session = request&.session
33
- if session.respond_to? :id
34
- session.id.to_s
35
- else
36
- nil
37
- end
38
- end
39
-
40
- end
41
- end
42
- end
1
+ module ViewComponentReflex
2
+ module StateAdapter
3
+ class Base
4
+
5
+ def self.state(request, key)
6
+ # stub
7
+ end
8
+
9
+ def self.set_state(request, controller, key, new_state)
10
+ # stub
11
+ end
12
+
13
+ def self.store_state(request, key, new_state = {})
14
+ # stub
15
+ end
16
+
17
+ def self.wrap_write_async
18
+ yield
19
+ end
20
+
21
+ def self.extend_component(component)
22
+ # stub
23
+ end
24
+
25
+ def self.extend_reflex(component)
26
+ # stub
27
+ end
28
+
29
+ private
30
+
31
+ def self.extract_id(request)
32
+ session = request&.session
33
+ if session.respond_to? :id
34
+ session.id.to_s
35
+ else
36
+ nil
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+ end