class Pakyow::Presenter::Presenters::Form
Constants
- ACTION_METHODS
- ID_LABEL
@api private
- SUPPORTED_ACTIONS
Public Class Methods
connect_input_to_label(input, label)
click to toggle source
@api private
# File lib/pakyow/presenter/presenters/form.rb, line 25 def connect_input_to_label(input, label) if false || input.attributes[:id].to_s.empty? id = SecureRandom.hex(4) input.attributes[:id] = id else id = input.attributes[:id] end label.attributes[:for] = id end
pluralize_field_name(field)
click to toggle source
@api private
# File lib/pakyow/presenter/presenters/form.rb, line 18 def pluralize_field_name(field) unless field.attributes[:name].to_s.end_with?("[]") || field.attributes[:name].to_s.empty? field.attributes[:name] = "#{field.attributes[:name]}[]" end end
Public Instance Methods
action=(action)
click to toggle source
Sets the form action (where it submits to).
# File lib/pakyow/presenter/presenters/form.rb, line 59 def action=(action) if action.is_a?(Symbol) if endpoint = app.endpoints.find(name: action) view.object.set_label(:endpoint, action) view.object.set_label(:endpoint_object, endpoint) view.object.set_label(:endpoint_params, {}) Endpoint.new(__getobj__).setup end else attrs[:action] = action end end
create(object = {}) { |self| ... }
click to toggle source
Setup the form for creating an object.
# File lib/pakyow/presenter/presenters/form.rb, line 154 def create(object = {}) yield self if block_given? setup_form_for_binding(:create, object) end
delete(object) { |self| ... }
click to toggle source
Setup the form for removing an object.
# File lib/pakyow/presenter/presenters/form.rb, line 175 def delete(object) yield self if block_given? setup_form_for_binding(:delete, object) end
grouped_options_for(field, options = nil) { || ... }
click to toggle source
Populates a select field with grouped options.
# File lib/pakyow/presenter/presenters/form.rb, line 115 def grouped_options_for(field, options = nil) unless field_presenter = find(field) raise ArgumentError.new("could not find field named `#{field}'") end unless grouped_options_for_allowed?(field_presenter) raise ArgumentError.new("expected `#{field}' to be a select field") end options = options || yield case field_presenter.object.tagname when "select" create_grouped_select_options(options, field_presenter) end end
id()
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 53 def id label(ID_LABEL) end
method=(method)
click to toggle source
Sets the form method. Automatically handles method overrides by prepending a hidden field named `pw-http-method` when method
is not get or post, setting the form method to post
.
# File lib/pakyow/presenter/presenters/form.rb, line 75 def method=(method) method = method.to_s.downcase if method_override_required?(method) attrs[:method] = "post" find_or_create_method_override_input.attributes[:value] = method else attrs[:method] = method end end
method_missing(method_name, *args, &block)
click to toggle source
Delegate private methods.
# File lib/pakyow/presenter/presenters/form.rb, line 188 def method_missing(method_name, *args, &block) __getobj__.send(method_name, *args, &block) end
object_for_form()
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 47 def object_for_form if labeled?(:binding) presentables[channeled_binding_name] end end
options_for(field, options = nil) { |field_presenter| ... }
click to toggle source
Populates a select field with options.
# File lib/pakyow/presenter/presenters/form.rb, line 88 def options_for(field, options = nil) unless field_presenter = find(Support.inflector.singularize(field)) || find(Support.inflector.pluralize(field)) raise ArgumentError.new("could not find field named `#{field}'") end unless options_for_allowed?(field_presenter) raise ArgumentError.new("expected `#{field}' to be a select field, checkbox, radio button, or binding") end options = if block_given? yield(field_presenter) else options end case field_presenter.object.tagname when "select" create_select_options(options, field_presenter) when "input" create_input_options(options, field_presenter) else create_options(options, field_presenter) end end
pp(*args)
click to toggle source
Fixes an issue using pp inside a delegator.
# File lib/pakyow/presenter/presenters/form.rb, line 182 def pp(*args) Kernel.pp(*args) end
replace(object) { |self| ... }
click to toggle source
Setup the form for replacing an object.
# File lib/pakyow/presenter/presenters/form.rb, line 168 def replace(object) yield self if block_given? setup_form_for_binding(:replace, object) end
respond_to_missing?(method_name, include_private = false)
click to toggle source
Calls superclass method
# File lib/pakyow/presenter/presenters/form.rb, line 192 def respond_to_missing?(method_name, include_private = false) super || __getobj__.respond_to?(method_name, true) end
setup(object = {}) { |self| ... }
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 131 def setup(object = {}) use_binding_nodes use_global_options if block_given? yield self end bind(object) setup! self end
setup?()
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 144 def setup? view.object.labeled?(:__form_setup) end
update(object) { |self| ... }
click to toggle source
Setup the form for updating an object.
# File lib/pakyow/presenter/presenters/form.rb, line 161 def update(object) yield self if block_given? setup_form_for_binding(:update, object) end
Private Instance Methods
add_options_to_select(options, field_presenter)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 513 def add_options_to_select(options, field_presenter) # remove existing options field_presenter.clear # add generated options field_presenter.append(html_safe(options.to_xml)) end
create_grouped_select_options(values, field_presenter)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 295 def create_grouped_select_options(values, field_presenter) options = Oga::XML::Document.new values.each do |group_name, grouped_values| group = Oga::XML::Element.new(name: "optgroup") group.set("label", ensure_html_safety(group_name.to_s)) options.children << group grouped_values.each do |value| group.children << create_select_option(value, field_presenter) end end add_options_to_select(options, field_presenter) end
create_input_options(values, field_presenter)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 333 def create_input_options(values, field_presenter) if values.is_a?(Array) && field_presenter.attributes[:type] != "radio" self.class.pluralize_field_name(field_presenter.object) end values = Array.ensure(values).compact if values.any? field_view = field_presenter.view field_template = field_view.soft_copy insertable_field = field_view current_field = field_view values.each do |value| current_field.attributes[:value] = option_value(value, field_presenter.view).to_s unless current_field.equal?(field_view) insertable_field.after(current_field) insertable_field = current_field end current_field = field_template.soft_copy end else field_presenter.remove end end
create_options(original_values, field_presenter)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 361 def create_options(original_values, field_presenter) values = Array.ensure(original_values).compact if values.any? field_view = field_presenter.view template = field_view.soft_copy insertable = field_view current = field_view values.each do |value| if treat_as_nested?(current, value) # We bind to a view here to avoid checking the value when setting up the option. # View.from_object(current.object).bind(value) # Set the field names appropriately. # current.object.each_significant_node(:field) do |field| name = "#{view.object.label(:binding)}[#{current.label(:binding)}]" name = if original_values.is_a?(Array) "#{name}[][#{field.label(:binding)}]" else "#{name}[#{field.label(:binding)}]" end field.attributes[:name] = name end # Insert a hidden field to identify the data on submission. # if key = option_value_keys(current, value).find { |k| value.include?(k) } id_input = Oga::XML::Element.new(name: "input") id_input.set(:type, "hidden") name = "#{view.object.label(:binding)}[#{current.label(:binding)}]" name = if original_values.is_a?(Array) "#{name}[][#{key}]" else "#{name}[#{key}]" end id_input.set(:name, name) id_input.set(:value, presentables[:__verifier].sign( ensure_html_safety(value[key].to_s) )) current.prepend(html_safe(id_input.to_xml)) end else if input = current.object.find_first_significant_node(:field) input.attributes[:name] = "#{view.object.label(:binding)}[#{current.label(:binding)}]" if original_values.is_a?(Array) && input.attributes[:type] != "radio" self.class.pluralize_field_name(input) end input.attributes[:value] = ensure_html_safety(option_value(value, current).to_s) end if label = current.object.find_first_significant_node(:label) label.html = ensure_html_safety(label_value(value, label).to_s) label.set_label(:bound, true) end if input && label self.class.connect_input_to_label(input, label) end end unless current.equal?(field_view) insertable.after(current) insertable = current end current.object.set_label(:bound, true) current = template.soft_copy end else field_presenter.remove end end
create_select_option(value, view)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 311 def create_select_option(value, view) option_binding = if option = view.object.find_first_significant_node(:option) option.label(:binding) else nil end Oga::XML::Element.new(name: "option").tap do |option_node| option_node.set("value", ensure_html_safety(option_value(value, view).to_s)) display_value = if value.is_a?(Array) value[1] elsif option_binding && value.respond_to?(:[]) value[option_binding.to_sym] else nil end option_node.inner_text = ensure_html_safety(display_value.to_s) end end
create_select_options(values, field_presenter)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 285 def create_select_options(values, field_presenter) options = Oga::XML::Document.new Array.ensure(values).compact.each do |value| options.children << create_select_option(value, field_presenter) end add_options_to_select(options, field_presenter) end
find_or_create_method_override_input()
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 276 def find_or_create_method_override_input unless input = view.object.find_first_significant_node(:method_override) prepend(method_override_input) input = view.object.find_first_significant_node(:method_override) end input end
form_action_for_binding(action, object)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 244 def form_action_for_binding(action, object) [ Support.inflector.singularize(label(:binding)).to_sym, Support.inflector.pluralize(label(:binding)).to_sym ].map { |possible_endpoint_name| params = Hash[label(:binding_info).to_h.map { |key, value| [:"#{key}_id", value] }].merge(object.to_h) endpoint_path = label(:binding_info).to_h.keys.map { |key| Support.inflector.pluralize(key).to_sym } endpoint_path << possible_endpoint_name endpoint_path.uniq! app.endpoints.path_to(*endpoint_path, action, **params) }.compact.first end
grouped_options_for_allowed?(field_presenter)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 509 def grouped_options_for_allowed?(field_presenter) field_presenter.object.tagname == "select" end
label_value(value, view)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 474 def label_value(value, view) if value.is_a?(Array) value[1] elsif value.is_a?(String) value elsif view.labeled?(:binding) && value.respond_to?(:[]) value[view.label(:binding)] else nil end end
method_for_action(action)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 264 def method_for_action(action) ACTION_METHODS[action] end
method_override_input()
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 272 def method_override_input html_safe("<input type=\"hidden\" name=\"pw-http-method\">") end
method_override_required?(method)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 268 def method_override_required?(method) method != "get" && method != "post" end
option_value(value, view)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 456 def option_value(value, view) if value.is_a?(Array) value[0] elsif value.is_a?(String) value elsif value.respond_to?(:[]) option_value_keys(view, value).each do |key| if value.include?(key) return value[key] end end nil else value.to_s end end
option_value_keys(view, value, include_binding_prop = true)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 486 def option_value_keys(view, value, include_binding_prop = true) [].tap do |keys| if include_binding_prop keys << view.object.label(:binding_prop) end if value.class.respond_to?(:primary_key_field) keys << value.class.primary_key_field end keys << :id end.compact end
options_for_allowed?(field_presenter)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 500 def options_for_allowed?(field_presenter) field_presenter.object.tagname == "select" || ( field_presenter.object.tagname == "input" && ( field_presenter.object.attributes[:type] == "checkbox" || field_presenter.object.attributes[:type] == "radio" ) || field_presenter.object.significant?(:binding) ) end
setup!()
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 148 def setup! view.object.set_label(:__form_setup, true) end
setup_form_for_binding(action, object)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 198 def setup_form_for_binding(action, object) setup(object) do if SUPPORTED_ACTIONS.include?(action) unless labeled?(:endpoint) if self.action = form_action_for_binding(action, object) self.method = method_for_action(action) end end else raise ArgumentError.new("expected action to be one of: #{SUPPORTED_ACTIONS.join(", ")}") end end end
treat_as_nested?(view, value)
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 443 def treat_as_nested?(view, value) if value.is_a?(Array) false else keys = option_value_keys(view, value, false) view.object.each_significant_node(:field) do |field| return true if field.labeled?(:binding) && !keys.include?(field.label(:binding)) end false end end
use_binding_nodes()
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 212 def use_binding_nodes view.object.set_label(:bound, true) view.object.each_significant_node(:binding, descend: true) do |object| if Pakyow::Presenter::Views::Form::FIELD_TAGS.include?(object.tagname) object.set_label(:bound, true) end end end
use_global_options()
click to toggle source
# File lib/pakyow/presenter/presenters/form.rb, line 222 def use_global_options __getobj__.class.__global_options.each do |form_binding, options| form = if view.object.tagname == "form" && view.binding_name == form_binding self else form(form_binding) end if form options.each do |field_binding, metadata| if metadata[:block] form.options_for(field_binding) do |context| instance_exec(context, &metadata[:block]) end else form.options_for(field_binding, metadata[:options]) end end end end end