view_component_reflex 3.1.14.pre3 → 3.1.14.pre7

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