format :html do
# FIELDSET VIEWS
view :content_formgroup, cache: :never do
wrap_with :fieldset, edit_slot, class: classy("card-editor", "editor")
end
view :name_formgroup do
formgroup "name", editor: "name", help: false do
raw name_field
end
end
view :type_formgroup do
wrap_type_formgroup do
type_field class: "type-field edit-type-field"
end
end
view :edit_in_form, cache: :never, perms: :update, tags: :unknown_ok do
reset_form
@in_multi_card_editor = true
edit_slot
end
def wrap_type_formgroup
formgroup "type", editor: "type", class: "type-formgroup", help: false do
yield
end
end
def button_formgroup
wrap_with :div, class: "form-group" do
wrap_with :div, yield
end
end
def name_field
# value needed because otherwise gets wrong value if there are updates
text_field :name, value: card.name, autocomplete: "off"
end
def type_field args={}
typelist = Auth.createable_types
current_type = type_field_current_value args, typelist
options = options_from_collection_for_select typelist, :to_s, :to_s,
current_type
template.select_tag "card[type]", options, args
end
def type_field_current_value args, typelist
return if args.delete :no_current_type
if !card.new_card? && !typelist.include?(card.type_name)
# current type should be an option on existing cards,
# regardless of create perms
typelist.push(card.type_name).sort!
end
card.type_name_or_default
end
def content_field skip_rev_id=false
with_nest_mode :normal do
# by changing nest mode to normal, we ensure that editors (eg image
# previews) can render core views.
output [content_field_revision_tracking(skip_rev_id), _render_editor]
end
end
# SAMPLE editor view for override
# view :editor do
# text_area :content, rows: 5, class: "d0-card-content"
# end
def content_field_revision_tracking skip_rev_id
card.last_action_id_before_edit = card.last_action_id
return if !card || card.new_card? || skip_rev_id
hidden_field :last_action_id_before_edit, class: "current_revision_id"
end
def edit_slot
case
when inline_nests_editor? then _render_core
when multi_card_editor? then multi_card_edit(true)
when in_multi_card_editor? then editor_in_multi_card
else single_card_edit_field
end
end
# test: render nests within a normal rendering of the card's content? (as opposed to a standardized form)
def inline_nests_editor?
voo.editor == :inline_nests
end
# test: are we opening a new multi-card form?
def multi_card_editor?
nests_editor? || # editor configured in voo
voo.structure || voo.edit_structure || # structure configured in voo
card.structure || # structure in card rule
edit_fields.present? # list of fields in card rule
end
# test: are we already within a multi-card form?
def in_multi_card_editor?
@in_multi_card_editor.present?
end
def nests_editor?
voo.editor == :nests
end
def single_card_edit_field
if voo.show?(:type_formgroup) || voo.show?(:name_formgroup)
# display content field in formgroup for consistency with other fields
formgroup("", editor: :content, help: false) { content_field }
else
editor_wrap(:content) { content_field }
end
end
def editor_in_multi_card
add_junction_class
formgroup render_title,
editor: "content", help: true, class: classy("card-editor") do
[content_field, (form.hidden_field(:type_id) if card.new_card?)]
end
end
def multi_card_edit fields_only=false
nested_cards_for_edit(fields_only).map do |name, options|
options ||= {}
options[:hide] = [options[:hide], :toolbar].flatten.compact
nest name, options
end.join "\n"
end
# @param [Hash|Array] fields either an array with field names and/or field
# cards or a hash with the fields as keys and a hash with nest options as
# values
def process_edit_fields fields
fields.map do |field, opts|
field_nest field, opts
end.join "\n"
end
###
# If you use subfield cards to render a form for a new card
# then the subfield cards should be created on the new card not the existing
# card that build the form
def form
@form ||= begin
@form_root = true unless parent&.form_root
instantiate_builder(form_prefix, card, {})
end
end
def reset_form
@form = nil
form
end
def form_prefix
case
when (voo_prefix = form_prefix_from_voo) then voo_prefix # configured
when form_root? || !form_root || !parent then "card" # simple form
when parent.card == card then parent.form_prefix # card nests itself
else edit_in_form_prefix
end
end
def form_prefix_from_voo
voo&.live_options&.dig :input_name
end
def edit_in_form_prefix
"#{parent.form_prefix}[subcards][#{card.name.from form_context.card.name}]"
end
def form_context
(form_root? || !form_root) ? self : parent
end
def form_root?
@form_root == true
end
def form_root
return self if @form_root
parent ? parent.form_root : nil
end
def card_form action, opts={}
@form_root = true
success = opts.delete(:success)
form_for card, card_form_opts(action, opts) do |cform|
@form = cform
success_tags(success) + output(yield(cform))
end
end
# @param action [Symbol] :create or :update
# @param opts [Hash] html options
# @option opts [Boolean] :redirect (false) if true form is no "slotter"
def card_form_opts action, opts={}
url, action = card_form_url_and_action action
html_opts = card_form_html_opts action, opts
form_opts = { url: url, html: html_opts }
form_opts[:remote] = true unless html_opts.delete(:redirect)
form_opts
end
def card_form_html_opts action, opts={}
add_class opts, "card-form"
add_class opts, "slotter" unless opts[:redirect]
add_class opts, "autosave" if action == :update
opts[:recaptcha] ||= "on" if card.recaptcha_on?
opts.delete :recaptcha if opts[:recaptcha] == :off
opts
end
def card_form_url_and_action action
case action
when Symbol then [path(action: action), action]
when Hash then [path(action), action[:action]]
# for when non-action path args are required
else
raise Card::Error, "unsupported #card_form_url action: #{action}"
end
end
def editor_wrap type=nil
html_class = "editor"
html_class << " #{type}-editor" if type
wrap_with :div, class: html_class do
yield
end
end
# FIELD VIEWS
def add_junction_class
return unless card.name.junction?
class_up "card-editor", "RIGHT-#{card.name.tag_name.safe_key}"
end
end