view_component_reflex 2.5.0 → 3.0.1

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