app/models/coupdoeil/hovercard.rb
# frozen_string_literal: true module Coupdoeil class Hovercard < AbstractController::Base abstract! include AbstractController::Rendering include AbstractController::Logger include AbstractController::Helpers include AbstractController::Translation include AbstractController::Callbacks include AbstractController::Caching include ActionView::Layouts include ActionView::Rendering include Rails.application.routes.url_helpers layout "hovercard" # so coupdoeil helpers are always available within hovercards helper Coupdoeil::ApplicationHelper @registry = Registry.new @default_options_by_method = {}.with_indifferent_access DEFAULT_OPTIONS_KEY = Object.new private_constant :DEFAULT_OPTIONS_KEY @default_options_by_method[DEFAULT_OPTIONS_KEY] = OptionsSet.new( offset: 0, placement: "auto", animation: "slide-in", cache: true, loading: :async, trigger: "hover" ) DoubleRenderError = Class.new(::AbstractController::DoubleRenderError) # See engine initialization for view paths class << self attr_reader :registry def hovercard_resource_name = @hovercard_resource_name ||= name.delete_suffix("Hovercard").underscore def with(...) = Setup.new(self).with_params(...) def inherited(subclass) super Coupdoeil::Hovercard.registry.register(subclass.hovercard_resource_name, subclass) subclass.instance_variable_set(:@default_options_by_method, @default_options_by_method.dup) end def default_options(...) = default_options_for(DEFAULT_OPTIONS_KEY, ...) def default_options_for(*action_names, **option_values) if option_values.blank? @default_options_by_method[action_names.first] || default_options else action_names.each do |action_name| options = @default_options_by_method[action_name] || default_options @default_options_by_method[action_name] = options.merge(OptionsSet.new(option_values)) end end end def method_missing(method_name, *args, &) return super unless action_methods.include?(method_name.name) raise ArgumentError, "expected no arguments" if args.any? Setup.new(self).with_type(method_name) end def respond_to_missing?(method, include_all = false) action_methods.include?(method.name) || super end end attr_reader :params def initialize(params, cp_view_context) super() @params = params @__cp_view_context = cp_view_context end def helpers = @__cp_view_context def controller = @__cp_view_context.controller def view_context super.tap do |context| context.extend ViewContextDelegation context.__cp_view_context = @__cp_view_context end end def render(...) return super unless response_body raise DoubleRenderError, "Render was called multiple times in this action. \ Also note that render does not terminate execution of the action." end def process(method_name, *) benchmark("processed hovercard #{self.class.hovercard_resource_name}/#{method_name}", silence: true) do ActiveSupport::Notifications.instrument("render_hovercard.coupdoeil") do super response_body || render(action_name) end end end end end