class Volt::ViewBinding
Public Class Methods
new(volt_app, target, context, binding_name, binding_in_path, getter, content_template_path = nil)
click to toggle source
@param [String] binding_in_path is the path this binding was rendered from. Used to
lookup paths in ViewLookupForPath
@param [String|nil] content_template_path is the path to the template for the content
provided in the tag.
Calls superclass method
Volt::BaseBinding::new
# File lib/volt/page/bindings/view_binding.rb, line 13 def initialize(volt_app, target, context, binding_name, binding_in_path, getter, content_template_path = nil) super(volt_app, target, context, binding_name) @content_template_path = content_template_path # Setup the view lookup helper @view_lookup = Volt::ViewLookupForPath.new(volt_app.templates, binding_in_path) @current_template = nil # Run the initial render @computation = lambda do # Don't try to render if this has been removed if @context # Render update(*@context.instance_eval(&getter)) end end.watch! end
Public Instance Methods
call_ready()
click to toggle source
# File lib/volt/page/bindings/view_binding.rb, line 227 def call_ready if @controller # Set the current section on the controller if it wants so it can manipulate # the dom if needed. # Only assign sections for action's, so we don't get AttributeSections bound # also. if @controller.respond_to?(:section=) dom_section = @current_template.dom_section # Only assign dom sections that can be manipulated via the dom (so not the title for example) @controller.section = dom_section unless dom_section.is_a?(Volt::AttributeSection) end # Call the ready callback on the controller @current_controller_handler.call_action(nil, 'ready') end end
clear_grouped_controller()
click to toggle source
# File lib/volt/page/bindings/view_binding.rb, line 134 def clear_grouped_controller if @grouped_controller @grouped_controller.clear @grouped_controller = nil end end
create_controller_handler(full_path, controller_path)
click to toggle source
Create controller handler loads up a controller inside of the controller handler for the paths
# File lib/volt/page/bindings/view_binding.rb, line 181 def create_controller_handler(full_path, controller_path) # If arguments is nil, then an blank SubContext will be created args = [SubContext.new(@arguments, nil, true)] # get the controller class and action controller_class, action = ControllerHandler.get_controller_and_action(controller_path) generated_new = false new_controller = proc do # Mark that we needed to generate a new controller instance (not reused # from the group) generated_new = true # Setup the controller controller_class.new(@volt_app, *args) end # Fetch grouped controllers if we're grouping if @grouped_controller # Find the controller in the group, or create it controller = @grouped_controller.lookup_or_create(controller_class, &new_controller) else # Just create the controller controller = new_controller.call end handler = ControllerHandler.fetch(controller, action) if generated_new # Call the action stopped = handler.call_action controller.instance_variable_set('@chain_stopped', true) if stopped else stopped = controller.instance_variable_get('@chain_stopped') end [handler, generated_new, stopped] end
queue_clear_grouped_controller()
click to toggle source
On the next tick, we clear the grouped controller so that any changes to template paths will create a new controller and trigger the action.
# File lib/volt/page/bindings/view_binding.rb, line 121 def queue_clear_grouped_controller if Volt.in_browser? # In the browser, we want to keep a grouped controller around during a single run # of the event loop. To make that happen, we clear it on the next tick. `setImmediate(function() {` clear_grouped_controller `});` else # For the backend, clear it immediately clear_grouped_controller end end
remove()
click to toggle source
Called when the binding is removed from the page
Calls superclass method
Volt::BaseBinding#remove
# File lib/volt/page/bindings/view_binding.rb, line 246 def remove # Cleanup any starting controller remove_starting_controller @computation.stop @computation = nil remove_current_controller_and_template super end
remove_current_controller_and_template()
click to toggle source
# File lib/volt/page/bindings/view_binding.rb, line 141 def remove_current_controller_and_template # Remove existing controller and template and call _removed if @current_controller_handler @current_controller_handler.call_action('before', 'remove') end if @current_template @current_template.remove @current_template = nil end if @current_controller_handler @current_controller_handler.call_action('after', 'remove') end if @grouped_controller && @current_controller_handler # We remove the controller after all of the current rendering is done. Timers.next_tick do # Remove a reference for the controller in the group. @grouped_controller.remove(@current_controller_handler.controller.class) end end @controller = nil @current_controller_handler = nil end
remove_starting_controller()
click to toggle source
# File lib/volt/page/bindings/view_binding.rb, line 168 def remove_starting_controller # Clear any previously running wait for loads. This is for when the path changes # before the view actually renders. stop_waiting_for_load if @starting_controller_handler # Only call the after_..._removed because the dom never loaded. @starting_controller_handler.call_action('after', 'removed') @starting_controller_handler = nil end end
render_next_template(full_path, path)
click to toggle source
Called when the next template is ready to render
# File lib/volt/page/bindings/view_binding.rb, line 96 def render_next_template(full_path, path) remove_current_controller_and_template # Switch the current template @current_controller_handler = @starting_controller_handler @starting_controller_handler = nil # Also track the current controller directly @controller = @current_controller_handler.controller if full_path render_template(full_path || path) # rescue => e # Volt.logger.error("Error during render of template at #{path}: #{e.inspect}") # Volt.logger.error(e.backtrace) end
render_template(full_path)
click to toggle source
The context for templates can be either a controller, or the original context.
# File lib/volt/page/bindings/view_binding.rb, line 221 def render_template(full_path) @current_template = TemplateRenderer.new(@volt_app, @target, @controller, @binding_name, full_path) call_ready end
stop_waiting_for_load()
click to toggle source
# File lib/volt/page/bindings/view_binding.rb, line 112 def stop_waiting_for_load if @waiting_for_load @waiting_for_load.stop @waiting_for_load = nil end end
update(path, section_or_arguments = nil, options = {})
click to toggle source
update is called when the path string changes.
# File lib/volt/page/bindings/view_binding.rb, line 34 def update(path, section_or_arguments = nil, options = {}) Computation.run_without_tracking do @options = options # A blank path needs to load a missing template, otherwise it tries to load # the same template. path = path.blank? ? '---missing---' : path section = nil @arguments = nil if section_or_arguments.is_a?(String) # Render this as a section section = section_or_arguments else # Use the value passed in as the default arguments @arguments = section_or_arguments # Include content_template_path in attrs if @content_template_path @arguments ||= {} @arguments[:content_template_path] = @content_template_path @arguments[:content_controller] = @context end end # Sometimes we want multiple template bindings to share the same controller (usually # when displaying a :Title and a :Body), this instance tracks those. if @options && (controller_group = @options[:controller_group]) # Setup the grouped controller for the first time. @grouped_controller = GroupedControllers.new(controller_group) end # If a controller is already starting, but not yet started, then remove it. remove_starting_controller full_path, controller_path = @view_lookup.path_for_template(path, section) if full_path @starting_controller_handler, generated_new, chain_stopped = create_controller_handler(full_path, controller_path) # Check if chain was stopped when the action ran if chain_stopped # An action stopped the chain. When this happens, we stop running here. remove_starting_controller else # None of the actions stopped the chain # Wait until the controller is loaded before we actually render. @waiting_for_load = -> { @starting_controller_handler.controller.loaded? }.watch_until!(true) do render_next_template(full_path, path) end queue_clear_grouped_controller end else # if we don't have a full path, then we have a missing template render_next_template(full_path, path) end end end