class ViewComponentReflex::Reflex

Attributes

component_class[RW]

Public Instance Methods

component_document() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 50
def component_document
  component.tap do |k|
    k.define_singleton_method(:initialize_component) do
      @key = element.dataset[:key]
    end
  end

  document = Nokogiri::HTML(component.render_in(controller.view_context))
end
controller_document() click to toggle source

pretty sure I can't memoize this because we need to re-render every time

# File lib/view_component_reflex/reflex.rb, line 10
def controller_document
  controller.process(params[:action])
  Nokogiri::HTML(controller.response.body)
end
default_morph() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 69
def default_morph
  save_state
  html = if component.can_render_to_string?
    component_document.css(selector).to_html
  else
    controller_document.css(selector).to_html
  end
  morph selector, html
end
method(name) click to toggle source

SR's delegate_call_to_reflex in channel.rb uses method to gather the method parameters, but since we're abusing method_missing here, that'll always fail

# File lib/view_component_reflex/reflex.rb, line 109
def method(name)
  component.method(name.to_sym)
end
method_missing(name, *args, &blk) click to toggle source
Calls superclass method
# File lib/view_component_reflex/reflex.rb, line 117
def method_missing(name, *args, &blk)
  super unless respond_to_missing?(name)

  state.each do |k, v|
    component.instance_variable_set(k, v)
  end

  component.send(name, *args, &blk)
  
  if @prevent_refresh
    morph :nothing
  else
    default_morph      
  end
end
prevent_refresh!() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 133
def prevent_refresh!
  @prevent_refresh = true
end
refresh!(primary_selector = nil, *rest) click to toggle source
# File lib/view_component_reflex/reflex.rb, line 15
def refresh!(primary_selector = nil, *rest)
  save_state

  if primary_selector.nil? && !component.can_render_to_string?
    primary_selector = selector
  end
  if primary_selector
    prevent_refresh!
    
    document = controller_document
    [primary_selector, *rest].each do |s|
      html = document.css(s)
      if html.present?
        CableReady::Channels.instance[stream].morph(
          selector: s,
          html: html.inner_html,
          children_only: true,
          permanent_attribute_name: "data-reflex-permanent",
        )
      end
    end
  else
    refresh_component!
  end
  CableReady::Channels.instance[stream].broadcast
end
refresh_all!() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 98
def refresh_all!
  refresh!("body")
end
refresh_component!() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 60
def refresh_component!
  CableReady::Channels.instance[stream].morph(
    selector: selector,
    children_only: true,
    html: component_document.css(selector).inner_html,
    permanent_attribute_name: "data-reflex-permanent",
  )
end
respond_to_missing?(name, _ = false) click to toggle source
# File lib/view_component_reflex/reflex.rb, line 113
def respond_to_missing?(name, _ = false)
  !!name.to_proc
end
selector() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 102
def selector
  "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]"
end
stimulus_reflex_data() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 79
def stimulus_reflex_data
  {
    reflex_id: reflex_id,
    xpath_controller: xpath_controller,
    xpath_element: xpath_element,
    target: target,
    reflex_controller: reflex_controller,
    url: url,
    morph: :page,
    attrs: {
      key: element.dataset[:key]
    }
  }
end
stream() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 42
def stream
  @stream ||= stream_name
end
stream_to(channel) click to toggle source
# File lib/view_component_reflex/reflex.rb, line 46
def stream_to(channel)
  @stream = channel
end
target() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 94
def target
  "#{component_class}##{method_name}"
end

Private Instance Methods

component() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 164
def component
  return @component if @component
  @component = component_class.allocate
  reflex = self
  exposed_methods = [
    :params,
    :request,
    :connection,
    :element,
    :refresh!,
    :refresh_all!,
    :stimulus_controller,
    :session,
    :prevent_refresh!,
    :selector,
    :stimulate,
    :stream_to
  ]
  exposed_methods.each do |meth|
    @component.define_singleton_method(meth) do |*a|
      reflex.send(meth, *a)
    end
  end

  @component.define_singleton_method(:reflex) do
    reflex
  end

  @component
end
component_class() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 139
def component_class
  self.class.component_class
end
initial_state() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 211
def initial_state
  state_adapter.state(request, "#{key}_initial")
end
key() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 199
def key
  element.dataset[:key]
end
save_state() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 215
def save_state
  new_state = {}
  component.safe_instance_variables.each do |k|
    new_state[k] = component.instance_variable_get(k)
  end
  set_state(new_state)
end
set_state(new_state = {}) click to toggle source
# File lib/view_component_reflex/reflex.rb, line 195
def set_state(new_state = {})
  state_adapter.set_state(request, controller, key, new_state)
end
state() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 207
def state
  state_adapter.state(request, key)
end
state_adapter() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 203
def state_adapter
  ViewComponentReflex::Engine.state_adapter
end
stimulate(target, data) click to toggle source
# File lib/view_component_reflex/reflex.rb, line 147
def stimulate(target, data)
  data_to_receive = {}

  stimulus_reflex_data.each do |k, v|
    data_to_receive[k.to_s.camelize(:lower)] = v
  end

  data_to_receive["dataset"] = data.each_with_object({}) do |(k, v), o|
    o["data-#{k}"] = v
  end

  data_to_receive["attrs"] = element.attributes.to_h.symbolize_keys
  data_to_receive["target"] = target

  channel.receive data_to_receive
end
stimulus_controller() click to toggle source
# File lib/view_component_reflex/reflex.rb, line 143
def stimulus_controller
  component_class.stimulus_controller
end