view_component_reflex 3.1.10 → 3.1.11

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