view_component_reflex 2.3.2 → 2.3.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,192 +1,198 @@
1
- module ViewComponentReflex
2
- class Component < ViewComponent::Base
3
- class << self
4
- def init_stimulus_reflex
5
- factory = ViewComponentReflex::ReflexFactory.new(self)
6
- @stimulus_reflex ||= factory.reflex
7
- wire_up_callbacks if factory.new?
8
- end
9
-
10
- def reflex_base_class(new_base_class = nil)
11
- if new_base_class.nil?
12
- @reflex_base_class ||= ViewComponentReflex::Reflex
13
- else
14
- if new_base_class <= ViewComponentReflex::Reflex
15
- @reflex_base_class = new_base_class
16
- else
17
- raise StandardError.new("The reflex base class must inherit from ViewComponentReflex::Reflex")
18
- end
19
- end
20
- end
21
-
22
- def queue_callback(key, args, blk)
23
- callbacks(key).push({
24
- args: args,
25
- blk: blk
26
- })
27
- end
28
-
29
- def callbacks(key)
30
- @callbacks ||= {}
31
- @callbacks[key] ||= []
32
- end
33
-
34
- def register_callbacks(key)
35
- callbacks(key).each do |cb|
36
- @stimulus_reflex.send("#{key}_reflex", *cb[:args], &cb[:blk])
37
- end
38
- end
39
-
40
- def before_reflex(*args, &blk)
41
- queue_callback(:before, args, blk)
42
- end
43
-
44
- def after_reflex(*args, &blk)
45
- queue_callback(:after, args, blk)
46
- end
47
-
48
- def around_reflex(*args, &blk)
49
- queue_callback(:around, args, blk)
50
- end
51
-
52
- def wire_up_callbacks
53
- register_callbacks(:before)
54
- register_callbacks(:after)
55
- register_callbacks(:around)
56
- end
57
- end
58
-
59
- def self.stimulus_controller
60
- name.chomp("Component").underscore.dasherize
61
- end
62
-
63
- def stimulus_reflex?
64
- helpers.controller.instance_variable_get(:@stimulus_reflex)
65
- end
66
-
67
- def component_controller(opts_or_tag = :div, opts = {}, &blk)
68
- init_key
69
-
70
- tag = :div
71
- options = if opts_or_tag.is_a? Hash
72
- opts_or_tag
73
- else
74
- tag = opts_or_tag
75
- opts
76
- end
77
- options[:data] = {
78
- controller: self.class.stimulus_controller,
79
- key: key,
80
- **(options[:data] || {})
81
- }
82
- content_tag tag, capture(&blk), options
83
- end
84
-
85
- def can_render_to_string?
86
- omitted_from_state.empty?
87
- end
88
-
89
- # key is required if you're using state
90
- # We can't initialize the session state in the initial method
91
- # because it doesn't have a view_context yet
92
- # This is the next best place to do it
93
- def init_key
94
- # we want the erb file that renders the component. `caller` gives the file name,
95
- # and line number, which should be unique. We hash it to make it a nice number
96
- key = caller.select { |p| p.match? /.\.html\.(haml|erb|slim)/ }[1]&.hash.to_s
97
- key += collection_key.to_s if collection_key
98
- @key = key
99
- end
100
-
101
- # Helper to use to create the proper reflex data attributes for an element
102
- def reflex_data_attributes(reflex)
103
- action, method = reflex.to_s.split("->")
104
- if method.nil?
105
- method = action
106
- action = "click"
107
- end
108
-
109
- {
110
- reflex: "#{action}->#{self.class.name}##{method}",
111
- key: key
112
- }
113
- end
114
-
115
- def reflex_tag(reflex, name, content_or_options_with_block = {}, options = {}, escape = true, &block)
116
- if content_or_options_with_block.is_a?(Hash)
117
- merge_data_attributes(content_or_options_with_block, reflex_data_attributes(reflex))
118
- else
119
- merge_data_attributes(options, reflex_data_attributes(reflex))
120
- end
121
- content_tag(name, content_or_options_with_block, options, escape, &block)
122
- end
123
-
124
- def collection_key
125
- nil
126
- end
127
-
128
- def permit_parameter?(initial_param, new_param)
129
- initial_param != new_param
130
- end
131
-
132
- def omitted_from_state
133
- []
134
- end
135
-
136
- def key
137
- # initialize session state
138
- if !stimulus_reflex? || ViewComponentReflex::Engine.state_adapter.state(request, @key).empty?
139
-
140
- new_state = create_safe_state
141
-
142
- ViewComponentReflex::Engine.state_adapter.store_state(request, @key, new_state)
143
- ViewComponentReflex::Engine.state_adapter.store_state(request, "#{@key}_initial", new_state)
144
- else
145
- initial_state = ViewComponentReflex::Engine.state_adapter.state(request, "#{@key}_initial")
146
- ViewComponentReflex::Engine.state_adapter.state(request, @key).each do |k, v|
147
- instance_value = instance_variable_get(k)
148
- if permit_parameter?(initial_state[k], instance_value)
149
- ViewComponentReflex::Engine.state_adapter.set_state(request, controller, "#{@key}_initial", {k => instance_value})
150
- ViewComponentReflex::Engine.state_adapter.set_state(request, controller, @key, {k => instance_value})
151
- else
152
- instance_variable_set(k, v)
153
- end
154
- end
155
- end
156
- @key
157
- end
158
-
159
- def safe_instance_variables
160
- instance_variables - unsafe_instance_variables
161
- end
162
-
163
- private
164
-
165
- def unsafe_instance_variables
166
- [
167
- :@view_context, :@lookup_context, :@view_renderer, :@view_flow,
168
- :@virtual_path, :@variant, :@current_template, :@output_buffer, :@key,
169
- :@helpers, :@controller, :@request, :@tag_builder
170
- ]
171
- end
172
-
173
- def create_safe_state
174
- new_state = {}
175
-
176
- # this will almost certainly break
177
- safe_instance_variables.each do |k|
178
- new_state[k] = instance_variable_get(k) unless omitted_from_state.include?(k)
179
- end
180
- new_state
181
- end
182
-
183
- def merge_data_attributes(options, attributes)
184
- data = options[:data]
185
- if data.nil?
186
- options[:data] = attributes
187
- else
188
- options[:data].merge! attributes
189
- end
190
- end
191
- end
192
- end
1
+ module ViewComponentReflex
2
+ class Component < ViewComponent::Base
3
+ class << self
4
+ def init_stimulus_reflex
5
+ factory = ViewComponentReflex::ReflexFactory.new(self)
6
+ @stimulus_reflex ||= factory.reflex
7
+ wire_up_callbacks if factory.new?
8
+ end
9
+
10
+ def reflex_base_class(new_base_class = nil)
11
+ if new_base_class.nil?
12
+ @reflex_base_class ||= ViewComponentReflex::Reflex
13
+ else
14
+ if new_base_class <= ViewComponentReflex::Reflex
15
+ @reflex_base_class = new_base_class
16
+ else
17
+ raise StandardError.new("The reflex base class must inherit from ViewComponentReflex::Reflex")
18
+ end
19
+ end
20
+ end
21
+
22
+ def queue_callback(key, args, blk)
23
+ callbacks(key).push({
24
+ args: args,
25
+ blk: blk
26
+ })
27
+ end
28
+
29
+ def callbacks(key)
30
+ @callbacks ||= {}
31
+ @callbacks[key] ||= []
32
+ end
33
+
34
+ def register_callbacks(key)
35
+ callbacks(key).each do |cb|
36
+ @stimulus_reflex.send("#{key}_reflex", *cb[:args], &cb[:blk])
37
+ end
38
+ end
39
+
40
+ def before_reflex(*args, &blk)
41
+ queue_callback(:before, args, blk)
42
+ end
43
+
44
+ def after_reflex(*args, &blk)
45
+ queue_callback(:after, args, blk)
46
+ end
47
+
48
+ def around_reflex(*args, &blk)
49
+ queue_callback(:around, args, blk)
50
+ end
51
+
52
+ def wire_up_callbacks
53
+ register_callbacks(:before)
54
+ register_callbacks(:after)
55
+ register_callbacks(:around)
56
+ end
57
+ end
58
+
59
+ def self.stimulus_controller
60
+ name.chomp("Component").underscore.dasherize
61
+ end
62
+
63
+ def stimulus_reflex?
64
+ helpers.controller.instance_variable_get(:@stimulus_reflex)
65
+ end
66
+
67
+ def component_controller(opts_or_tag = :div, opts = {}, &blk)
68
+ init_key
69
+
70
+ tag = :div
71
+ options = if opts_or_tag.is_a? Hash
72
+ opts_or_tag
73
+ else
74
+ tag = opts_or_tag
75
+ opts
76
+ end
77
+
78
+ options[:data] = {
79
+ controller: self.class.stimulus_controller,
80
+ key: key,
81
+ **(options[:data] || {})
82
+ }
83
+ content_tag tag, capture(&blk), options
84
+ end
85
+
86
+ def can_render_to_string?
87
+ omitted_from_state.empty?
88
+ end
89
+
90
+ # key is required if you're using state
91
+ # We can't initialize the session state in the initial method
92
+ # because it doesn't have a view_context yet
93
+ # This is the next best place to do it
94
+ def init_key
95
+ # we want the erb file that renders the component. `caller` gives the file name,
96
+ # and line number, which should be unique. We hash it to make it a nice number
97
+ erb_file = caller.select { |p| p.match? /.\.html\.(haml|erb|slim)/ }[1]
98
+ key = if erb_file
99
+ Digest::SHA2.hexdigest(erb_file.split(":in")[0])
100
+ else
101
+ ""
102
+ end
103
+ key += collection_key.to_s if collection_key
104
+ @key = key
105
+ end
106
+
107
+ # Helper to use to create the proper reflex data attributes for an element
108
+ def reflex_data_attributes(reflex)
109
+ action, method = reflex.to_s.split("->")
110
+ if method.nil?
111
+ method = action
112
+ action = "click"
113
+ end
114
+
115
+ {
116
+ reflex: "#{action}->#{self.class.name}##{method}",
117
+ key: key
118
+ }
119
+ end
120
+
121
+ def reflex_tag(reflex, name, content_or_options_with_block = {}, options = {}, escape = true, &block)
122
+ if content_or_options_with_block.is_a?(Hash)
123
+ merge_data_attributes(content_or_options_with_block, reflex_data_attributes(reflex))
124
+ else
125
+ merge_data_attributes(options, reflex_data_attributes(reflex))
126
+ end
127
+ content_tag(name, content_or_options_with_block, options, escape, &block)
128
+ end
129
+
130
+ def collection_key
131
+ nil
132
+ end
133
+
134
+ def permit_parameter?(initial_param, new_param)
135
+ initial_param != new_param
136
+ end
137
+
138
+ def omitted_from_state
139
+ []
140
+ end
141
+
142
+ def key
143
+ # initialize session state
144
+ if !stimulus_reflex? || ViewComponentReflex::Engine.state_adapter.state(request, @key).empty?
145
+
146
+ new_state = create_safe_state
147
+
148
+ ViewComponentReflex::Engine.state_adapter.store_state(request, @key, new_state)
149
+ ViewComponentReflex::Engine.state_adapter.store_state(request, "#{@key}_initial", new_state)
150
+ else
151
+ initial_state = ViewComponentReflex::Engine.state_adapter.state(request, "#{@key}_initial")
152
+ ViewComponentReflex::Engine.state_adapter.state(request, @key).each do |k, v|
153
+ instance_value = instance_variable_get(k)
154
+ if permit_parameter?(initial_state[k], instance_value)
155
+ ViewComponentReflex::Engine.state_adapter.set_state(request, controller, "#{@key}_initial", {k => instance_value})
156
+ ViewComponentReflex::Engine.state_adapter.set_state(request, controller, @key, {k => instance_value})
157
+ else
158
+ instance_variable_set(k, v)
159
+ end
160
+ end
161
+ end
162
+ @key
163
+ end
164
+
165
+ def safe_instance_variables
166
+ instance_variables - unsafe_instance_variables
167
+ end
168
+
169
+ private
170
+
171
+ def unsafe_instance_variables
172
+ [
173
+ :@view_context, :@lookup_context, :@view_renderer, :@view_flow,
174
+ :@virtual_path, :@variant, :@current_template, :@output_buffer, :@key,
175
+ :@helpers, :@controller, :@request, :@tag_builder
176
+ ]
177
+ end
178
+
179
+ def create_safe_state
180
+ new_state = {}
181
+
182
+ # this will almost certainly break
183
+ safe_instance_variables.each do |k|
184
+ new_state[k] = instance_variable_get(k) unless omitted_from_state.include?(k)
185
+ end
186
+ new_state
187
+ end
188
+
189
+ def merge_data_attributes(options, attributes)
190
+ data = options[:data]
191
+ if data.nil?
192
+ options[:data] = attributes
193
+ else
194
+ options[:data].merge! attributes
195
+ end
196
+ end
197
+ end
198
+ end
@@ -1,10 +1,10 @@
1
- require "stimulus_reflex"
2
- require 'view_component_reflex/reflex_factory'
3
- require "view_component_reflex/state_adapter/session"
4
- require "view_component_reflex/state_adapter/memory"
5
- require "view_component_reflex/reflex"
6
- require "view_component_reflex/engine"
7
-
8
- module ViewComponentReflex
9
- # Your code goes here...
10
- end
1
+ require "stimulus_reflex"
2
+ require 'view_component_reflex/reflex_factory'
3
+ require "view_component_reflex/state_adapter/session"
4
+ require "view_component_reflex/state_adapter/memory"
5
+ require "view_component_reflex/reflex"
6
+ require "view_component_reflex/engine"
7
+
8
+ module ViewComponentReflex
9
+ # Your code goes here...
10
+ end
@@ -1,36 +1,36 @@
1
- module ViewComponentReflex
2
- class Engine < ::Rails::Engine
3
- class << self
4
- mattr_accessor :state_adapter
5
-
6
- self.state_adapter = StateAdapter::Session
7
- end
8
-
9
- config.to_prepare do
10
- StimulusReflex::Channel.class_eval do
11
- unless instance_methods.include?(:receive_original)
12
- alias_method :receive_original, :receive
13
- def receive(data)
14
- target = data["target"].to_s
15
- reflex_name, _ = target.split("#")
16
- reflex_name = reflex_name.camelize
17
- component_name = reflex_name.end_with?("Reflex") ? reflex_name[0...-6] : reflex_name
18
- if component_name.end_with?("Component")
19
- begin
20
- component_name.constantize.init_stimulus_reflex
21
- rescue
22
- p "Tried to initialize view_component_reflex on #{component_name}, but it's not a view_component_reflex"
23
- end
24
-
25
- end
26
- receive_original(data)
27
- end
28
- end
29
- end
30
- end
31
-
32
- def self.configure
33
- yield self if block_given?
34
- end
35
- end
36
- end
1
+ module ViewComponentReflex
2
+ class Engine < ::Rails::Engine
3
+ class << self
4
+ mattr_accessor :state_adapter
5
+
6
+ self.state_adapter = StateAdapter::Session
7
+ end
8
+
9
+ config.to_prepare do
10
+ StimulusReflex::Channel.class_eval do
11
+ unless instance_methods.include?(:receive_original)
12
+ alias_method :receive_original, :receive
13
+ def receive(data)
14
+ target = data["target"].to_s
15
+ reflex_name, _ = target.split("#")
16
+ reflex_name = reflex_name.camelize
17
+ component_name = reflex_name.end_with?("Reflex") ? reflex_name[0...-6] : reflex_name
18
+ if component_name.end_with?("Component")
19
+ begin
20
+ component_name.constantize.init_stimulus_reflex
21
+ rescue
22
+ p "Tried to initialize view_component_reflex on #{component_name}, but it's not a view_component_reflex"
23
+ end
24
+
25
+ end
26
+ receive_original(data)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ def self.configure
33
+ yield self if block_given?
34
+ end
35
+ end
36
+ end