Last active
September 18, 2018 10:24
-
-
Save tomasc/b440f84bb5c680f71df40d2cee983ca2 to your computer and use it in GitHub Desktop.
nested_fields
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default class Link__NestedFields extends Modulor.Plugin | |
@defaults = | |
debug: false | |
new_item_class_name: "bem(modulor_nested_fields, item, is_new)" | |
regexp: new RegExp("__INDEX_PLACEHOLDER__", 'g') # regexp: new RegExp("<%= Modulor::NestedFieldsBuilder::CHILD_INDEX_STRING %>", 'g') | |
@selector: "bems(modulor_link, nested_fields)" | |
on_init: -> | |
@$element.on "click.#{@options.name}", (e) => | |
e.preventDefault() | |
return unless @$element.is("bems(modulor_link, nested_fields, add)") | |
@add_new_item() | |
@$element.on "click.#{@options.name}", (e) => | |
e.preventDefault() | |
return unless @$element.is("bems(modulor_link, nested_fields, remove)") | |
@remove_item() | |
get_index: -> new Date().getTime() | |
get_item: -> @$element.closest("bems(modulor_nested_fields, item)") | |
get_items: -> @$element.find("bems(modulor_nested_fields, item)") | |
get_items_container: -> @$element.closest("bems(modulor_nested_fields)") | |
get_links: -> @$element.closest("bems(modulor_nested_fields, links)") | |
get_template: -> @$element.data('template').replace(@options.regexp, @get_index()) | |
add_new_item: -> | |
$template = $(@get_template()) | |
$template.addClass(@options.new_item_class_name) | |
@get_links().before($template) | |
remove_item: -> | |
$item = @get_item() | |
if $item.hasClass(@options.new_item_class_name) | |
$item.remove() | |
else | |
@$element.prev("input[type=hidden]").val("1") | |
$item.hide() | |
Link__NestedFields.register() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default class IsSortable extends Modulor.Plugin | |
@defaults = | |
debug: false | |
name: 'Modulor__NestedFields__IsSortable' | |
@selector: "bems(modulor_nested_fields, is_sortable)" | |
on_init: -> | |
return if @sortable | |
Sortable = await `import('sortablejs' /* webpackChunkName: "sortablejs" */)` | |
@sortable = new Sortable( | |
@element, | |
animation: 150, | |
draggable: "bems(modulor_nested_fields, item)", | |
ghostClass: "bem(modulor_nested_fields, item, ghost)", | |
handle: "bems(modulor_nested_fields, item, handle)", | |
onAdd: (e) => @update_item_positions(), | |
onUpdate: (e) => @update_item_positions(), | |
onRemove: (e) => @update_item_positions(), | |
) | |
@$element.on "update_item_positions.#{@options.name}", (e) => | |
e.stopPropagation() | |
@update_item_positions() | |
@update_item_positions() | |
on_destroy: -> | |
@sortable.destroy() if @sortable | |
get_items: -> @$element.find("bems(modulor_nested_fields, item)") | |
update_item_positions: -> | |
@get_items().each (i, el) => | |
$(el).find('input[name*="position"]').val(i+1) | |
IsSortable.register() | |
# make sure positions are updated everytime items are added or removed | |
Modulor.MutationObserver.register( | |
"bems(modulor_nested_fields, item)", | |
((el) => $(el).trigger('update_item_positions')), | |
(=> $("bems(modulor_nested_fields, is_sortable)").trigger('update_item_positions')) | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
en: | |
modulor/nested_fields_builder: | |
links: | |
add: 'Add %{model_name}' | |
remove: 'Remove' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# FORM | |
# = form.nested_fields_for :locations | |
# = form.nested_fields_for :locations, filtered_locations | |
# = form.nested_fields_for :locations, nil, sortable: true | |
# | |
# FIELDS | |
# partial at `locations/fields` | |
module ActionView | |
module Helpers | |
class FormBuilder | |
def nested_fields_for(record_name, record_object = nil, options = {}, &block) | |
Modulor::NestedFieldsBuilder.new(self, @template, record_name, record_object, options).nested_fields_for(&block) | |
end | |
end | |
end | |
end | |
module Modulor | |
class NestedFieldsBuilder < Struct.new(:builder, :template, :record_name, :record_object, :options) | |
CHILD_INDEX_STRING = '__INDEX_PLACEHOLDER__'.freeze | |
delegate :object, | |
:object_name, | |
:simple_fields_for, | |
to: :builder | |
delegate :content_tag, | |
:hidden_field_tag, | |
:link_to, | |
:render, | |
to: :template | |
def initialize(builder, template, record_name, record_object = nil, options = {}) | |
super(builder, template, record_name, record_object, options) | |
end | |
def nested_fields_for | |
dom_class = Bem.bem([:modulor_nested_fields, (:is_sortable if is_sortable?)]) | |
content_tag(:div, class: dom_class) do | |
[ | |
nested_fields_title, | |
simple_fields_for(record_name, record_object, options) do |fields| | |
dom_class = [Bem.bem(:modulor_nested_fields, :item), Bem.bem(relation.klass)] | |
dom_data = { id: fields.object.id.to_s } | |
content_tag(:div, class: dom_class, data: dom_data) do | |
nested_fields_item_handle.to_s.html_safe + | |
render(partial_path, fields: fields).html_safe + | |
link_to_remove(fields) | |
end.html_safe | |
end, | |
nested_fields_links | |
].reject(&:blank?).join.html_safe | |
end.html_safe | |
end | |
private | |
def is_sortable? | |
options[:sortable] == true | |
end | |
def partial_path | |
object.to_view_path("#{record_name}/fields") | |
end | |
def relation | |
object.reflect_on_association(record_name) | |
end | |
def nested_fields_title | |
dom_class = Bem.bem(:modulor_nested_fields, :title) | |
title = relation.klass.model_name.human.pluralize | |
content_tag(:div, title, class: dom_class).html_safe | |
end | |
def nested_fields_links | |
dom_class = Bem.bem(:modulor_nested_fields, :links) | |
content_tag(:div, link_to_add, class: dom_class).html_safe | |
end | |
def link_to_add | |
label = options.fetch(:label_add, ::I18n.t(:add, scope: %i(modulor/nested_fields_builder links), model_name: relation.klass.model_name.human)) | |
dom_class = Bem.bem([:modulor_link, :nested_fields, :add]) | |
dom_data = { template: CGI.escapeHTML(nested_fields_template).html_safe, turbolinks: 'false' } | |
link_to(label, '#', class: dom_class, data: dom_data).html_safe | |
end | |
def nested_fields_item_handle | |
return unless is_sortable? | |
dom_class = Bem.bem(:modulor_nested_fields, :item, :handle) | |
content_tag(:div, nil, class: dom_class).html_safe | |
end | |
def nested_fields_template | |
dom_class = [Bem.bem(:modulor_nested_fields, :item), Bem.bem(relation.klass)] | |
content_tag(:div, class: dom_class) do | |
nested_fields_template_string | |
end.html_safe | |
end | |
def nested_fields_template_string | |
simple_fields_for(record_name, relation.klass.new, child_index: CHILD_INDEX_STRING) do |fields| | |
nested_fields_item_handle.to_s.html_safe + | |
render(partial_path, fields: fields).html_safe + | |
link_to_remove(fields) | |
end.html_safe | |
end | |
def destroy_field_tag(fields) | |
return if fields.object.new_record? | |
hidden_field_tag("#{fields.object_name}[_destroy]", fields.object._destroy).html_safe | |
end | |
def link_to_remove(fields, options = {}) | |
label = options.fetch(:label, ::I18n.t(:remove, scope: %i(modulor/nested_fields_builder links))) | |
dom_class = Bem.bem([:modulor_link, :nested_fields, :remove]) | |
dom_data = { turbolinks: 'false' } | |
[ | |
destroy_field_tag(fields), | |
link_to(label, '#', class: dom_class, data: dom_data) | |
].reject(&:blank?).join.html_safe | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment