view_component_reflex 3.1.14.pre2 → 3.1.14.pre3

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,12 +1,12 @@
1
- require "stimulus_reflex"
2
- require 'view_component_reflex/reflex_factory'
3
- require "view_component_reflex/state_adapter/base"
4
- require "view_component_reflex/state_adapter/session"
5
- require "view_component_reflex/state_adapter/memory"
6
- require "view_component_reflex/state_adapter/redis"
7
- require "view_component_reflex/reflex"
8
- require "view_component_reflex/engine"
9
-
10
- module ViewComponentReflex
11
- # Your code goes here...
12
- end
1
+ require "stimulus_reflex"
2
+ require 'view_component_reflex/reflex_factory'
3
+ require "view_component_reflex/state_adapter/base"
4
+ require "view_component_reflex/state_adapter/session"
5
+ require "view_component_reflex/state_adapter/memory"
6
+ require "view_component_reflex/state_adapter/redis"
7
+ require "view_component_reflex/reflex"
8
+ require "view_component_reflex/engine"
9
+
10
+ module ViewComponentReflex
11
+ # Your code goes here...
12
+ end
@@ -1,37 +1,37 @@
1
- module ViewComponentReflex
2
- class Engine < ::Rails::Engine
3
-
4
- mattr_accessor :state_adapter
5
- Engine.state_adapter = StateAdapter::Session
6
-
7
- config.to_prepare do
8
- StimulusReflex::Channel.class_eval do
9
- unless instance_methods.include?(:receive_original)
10
- alias_method :receive_original, :receive
11
- def receive(data)
12
- target = data["target"].to_s
13
- reflex_name, _ = target.split("#")
14
- reflex_name = reflex_name.camelize
15
- component_name = reflex_name.end_with?("Reflex") ? reflex_name[0...-6] : reflex_name
16
- component = begin
17
- component_name.constantize
18
- rescue
19
- # Since every reflex runs through this monkey patch, we're just going to ignore the ones that aren't for components
20
- end
21
-
22
- if component&.respond_to?(:init_stimulus_reflex)
23
- component.init_stimulus_reflex
24
- else
25
- Rails.logger.info "Tried to initialize view_component_reflex on #{component_name}, but it's not a view_component_reflex"
26
- end
27
- receive_original(data)
28
- end
29
- end
30
- end
31
- end
32
-
33
- def self.configure
34
- yield self if block_given?
35
- end
36
- end
37
- end
1
+ module ViewComponentReflex
2
+ class Engine < ::Rails::Engine
3
+
4
+ mattr_accessor :state_adapter
5
+ Engine.state_adapter = StateAdapter::Session
6
+
7
+ config.to_prepare do
8
+ StimulusReflex::Channel.class_eval do
9
+ unless instance_methods.include?(:receive_original)
10
+ alias_method :receive_original, :receive
11
+ def receive(data)
12
+ target = data["target"].to_s
13
+ reflex_name, _ = target.split("#")
14
+ reflex_name = reflex_name.camelize
15
+ component_name = reflex_name.end_with?("Reflex") ? reflex_name[0...-6] : reflex_name
16
+ component = begin
17
+ component_name.constantize
18
+ rescue
19
+ # Since every reflex runs through this monkey patch, we're just going to ignore the ones that aren't for components
20
+ end
21
+
22
+ if component&.respond_to?(:init_stimulus_reflex)
23
+ component.init_stimulus_reflex
24
+ else
25
+ Rails.logger.info "Tried to initialize view_component_reflex on #{component_name}, but it's not a view_component_reflex"
26
+ end
27
+ receive_original(data)
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ def self.configure
34
+ yield self if block_given?
35
+ end
36
+ end
37
+ end
@@ -1,225 +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
-
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"] = 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
- ]
184
- exposed_methods.each do |meth|
185
- @component.define_singleton_method(meth) do |*a|
186
- reflex.send(meth, *a)
187
- end
188
- end
189
-
190
- @component.define_singleton_method(:reflex) do
191
- reflex
192
- end
193
-
194
- @component
195
- end
196
-
197
- def set_state(new_state = {})
198
- state_adapter.set_state(request, controller, key, new_state)
199
- end
200
-
201
- def key
202
- element.dataset[:key]
203
- end
204
-
205
- def state_adapter
206
- ViewComponentReflex::Engine.state_adapter
207
- end
208
-
209
- def state
210
- state_adapter.state(request, key)
211
- end
212
-
213
- def initial_state
214
- state_adapter.state(request, "#{key}_initial")
215
- end
216
-
217
- def save_state
218
- new_state = {}
219
- component.safe_instance_variables.each do |k|
220
- new_state[k] = component.instance_variable_get(k)
221
- end
222
- set_state(new_state)
223
- end
224
- end
225
- 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