diff --git a/app/assets/stylesheets/Admin.scss b/app/assets/stylesheets/Admin.scss index ee2d668f7d..aef9b29a8d 100644 --- a/app/assets/stylesheets/Admin.scss +++ b/app/assets/stylesheets/Admin.scss @@ -9,7 +9,7 @@ $LOGO_BG_COLOR: yellow; $LOGO_HOVER_FG_COLOR: purple; $LOGO_HOVER_BG_COLOR: yellow; -$LEFT_BAR_BORDER_COLOR: #545454; // gray +$LEFT_BAR_BORDER_COLOR: #535454; // gray $LEFT_BAR_BORDER_RADIUS: 0px; $LEFT_BAR_HEADER_FG_COLOR: black; $LEFT_BAR_HEADER_BG_COLOR: yellow; diff --git a/app/assets/stylesheets/Agaricus.scss b/app/assets/stylesheets/Agaricus.scss index 3658b0575d..de32becc3c 100644 --- a/app/assets/stylesheets/Agaricus.scss +++ b/app/assets/stylesheets/Agaricus.scss @@ -1,7 +1,7 @@ @import "defaults"; $augustus_cap: #ECCF95; -$brasiliensis_gills_1: #A06362; // #A06463 +$brasiliensis_gills_1: #BF6362; // #A06463 $brasiliensis_gills_2: #743931; $campestris_cap: #F6F0F2; $cupreobrunneus_gills: #3B2821; diff --git a/app/assets/stylesheets/Amanita.scss b/app/assets/stylesheets/Amanita.scss index b790f04f51..8439d52e28 100644 --- a/app/assets/stylesheets/Amanita.scss +++ b/app/assets/stylesheets/Amanita.scss @@ -13,7 +13,7 @@ $calyptroderma_middle_cap: #c18346; $muscaria_background: #cc2616; $muscaria_foreground: #fff8c6; $velosa_background: #dd9d5f; -$velosa_light_veil: #fce9d3; // faebd4 +$velosa_light_veil: #f9e9d3; // faebd4 $velosa_dark_veil: #f4d5a6; $novinupta_background: #d1afa5; $pachycolea_background: #383138; diff --git a/app/assets/stylesheets/BlackOnWhite.scss b/app/assets/stylesheets/BlackOnWhite.scss index 8a5fe17a1d..beb7ee2336 100644 --- a/app/assets/stylesheets/BlackOnWhite.scss +++ b/app/assets/stylesheets/BlackOnWhite.scss @@ -4,7 +4,7 @@ $LOGO_BORDER_COLOR: #DDDDDD; $LEFT_BAR_BORDER_COLOR: #DDDDDD; -$TOP_BAR_BORDER_COLOR: #D9DaDa; +$TOP_BAR_BORDER_COLOR: #D9D9Da; $LIST_BORDER_COLOR: #DDDDDD; $BUTTON_HOVER_BORDER_COLOR: #CCCCCC; $BUTTON_BG_COLOR: #CCCCCC; diff --git a/app/assets/stylesheets/Cantharellaceae.scss b/app/assets/stylesheets/Cantharellaceae.scss index c8547a05a9..5fc8c120c1 100644 --- a/app/assets/stylesheets/Cantharellaceae.scss +++ b/app/assets/stylesheets/Cantharellaceae.scss @@ -11,7 +11,7 @@ $tubaeformis_hymenium: #c2914c; $tubaeformis_bright_stipe: #ffb230; $tubaeformis_dark_stipe: #4b2e0c; $tubaeformis_light_stipe: #e5bb67; -$cornucopioides_dark_hymenium: #12120c; // image 465 #10110b +$cornucopioides_dark_hymenium: #12120d; // image 465 #10110b $cornucopioides_light_hymenium: #9b9690; $cornucopioides_dark_cap: #4f4337; $cornucopioides_light_cap: #826c57; diff --git a/app/assets/stylesheets/Hygrocybe.scss b/app/assets/stylesheets/Hygrocybe.scss index da30be5b27..6546aca668 100644 --- a/app/assets/stylesheets/Hygrocybe.scss +++ b/app/assets/stylesheets/Hygrocybe.scss @@ -1,6 +1,6 @@ @import "defaults"; -$conica_stain: #34352d; // #37372f +$conica_stain: #34342d; // #37372f $conica_cap_red: #a31404; $conica_cap_orange: #dd6226; $conica_cap_yellow: #ffbf01; diff --git a/app/assets/stylesheets/Sudo.scss b/app/assets/stylesheets/Sudo.scss index 03adfe837c..06ffc4e641 100644 --- a/app/assets/stylesheets/Sudo.scss +++ b/app/assets/stylesheets/Sudo.scss @@ -1,6 +1,6 @@ @import "defaults"; -$BODY_BG_COLOR: #DE7300; // #DD7700 +$BODY_BG_COLOR: #DE7200; // #DD7700 $LOGO_BORDER_COLOR: black; $LOGO_BORDER_WIDTH: 2px; // vs 1px in default diff --git a/app/assets/stylesheets/mo/_icons.scss b/app/assets/stylesheets/mo/_icons.scss index 82c0b4ddc6..6e96d3a9ee 100644 --- a/app/assets/stylesheets/mo/_icons.scss +++ b/app/assets/stylesheets/mo/_icons.scss @@ -99,11 +99,13 @@ } // This is for the stateful icon_link_to helper -.icon-link { +.icon-link, +.panel-collapse-trigger { .active-icon, .active-label { display: none; } - &.active { + &.active, + &.collapsed { .link-icon:not(.active-icon), .sr-only:not(.active-label) { display: none; diff --git a/app/helpers/autocompleter_helper.rb b/app/helpers/autocompleter_helper.rb index aeb7cddca1..309c480701 100644 --- a/app/helpers/autocompleter_helper.rb +++ b/app/helpers/autocompleter_helper.rb @@ -21,33 +21,39 @@ def autocompleter_field(**args) data: { autocompleter_target: "input" } }.deep_merge(args.except(*autocompleter_outer_args)) ac_args[:class] = class_names("dropdown", args[:class]) - ac_args[:wrap_data] = autocompleter_wrap_data(args) + # inner form-group wrap, because dropdown is position-absolute + ac_args[:wrap_data] = { autocompleter_target: "wrap" } ac_args[:label_after] = autocompleter_label_after(args) ac_args[:label_end] = autocompleter_label_end(args) - ac_args[:append] = autocompleter_append(args) - - if args[:textarea] == true - text_area_with_label(**ac_args) - else - text_field_with_label(**ac_args) + ac_args[:append] = autocompleter_dropdown + + tag.div(id: args[:controller_id], + data: autocompleter_controller_data(args)) do + if args[:textarea] == true + concat(text_area_with_label(**ac_args)) + else + concat(text_field_with_label(**ac_args)) + end + concat(args[:append]) end end # Any arg not on this list gets sent to the text field/area. def autocompleter_outer_args - [:wrap_data, :type, :separator, :textarea, :hidden_value, :hidden_data, - :create_text, :keep_text, :edit_text, :find_text, :create, :create_path, - :map_outlet, :geocode_outlet] + [:controller_data, :controller_id, :type, :separator, :textarea, + :hidden_value, :hidden_data, :create_text, :keep_text, :edit_text, + :find_text, :create, :create_path, :map_outlet, :geocode_outlet].freeze end - def autocompleter_wrap_data(args) + # This data goes on the outer div (controller element), not the input field. + def autocompleter_controller_data(args) { - controller: :autocompleter, type: args[:type], + controller: :autocompleter, + type: args[:type], separator: args[:separator], autocompleter_map_outlet: args[:map_outlet], - autocompleter_geocode_outlet: args[:geocode_outlet], - autocompleter_target: "wrap" - }.deep_merge(args[:wrap_data] || {}) + autocompleter_geocode_outlet: args[:geocode_outlet] + }.deep_merge(args[:outer_data] || {}) end def autocompleter_label_after(args) @@ -68,13 +74,6 @@ def autocompleter_label_end(args) end end - def autocompleter_append(args) - capture do - concat(autocompleter_dropdown) - concat(args[:append]) - end - end - def autocompleter_has_id_indicator link_icon(:check, title: :autocompleter_has_id.l, class: "ml-3 px-2 text-success has-id-indicator", diff --git a/app/helpers/content_helper.rb b/app/helpers/content_helper.rb index 40049b853d..2f89fc7254 100644 --- a/app/helpers/content_helper.rb +++ b/app/helpers/content_helper.rb @@ -76,212 +76,4 @@ def content_tag_unless(condition, name, content_or_options_with_block = nil, content_tag_if(!condition, name, content_or_options_with_block, options, escape, &block) end - - # Wrap an html object in '' tag. This has the effect of - # giving it context help (mouse-over popup) in most modern browsers. - # - # <%= help_tooltip(label, title: "Click here to do something.") %> - # - def help_tooltip(label, **args) - args[:data] ||= {} - tag.span(label, title: args[:title], - class: class_names("context-help", args[:class]), - data: { toggle: "tooltip" }.merge(args[:data])) - end - - # make a help-note styled element, like a div, p, or span - def help_note(element = :span, string = "") - content_tag(element, string, class: "help-note mr-3") - end - - # make a help-block styled element, like a div, p - def help_block(element = :div, string = "", **args, &block) - content = block ? capture(&block) : string - html_options = { - class: class_names("help-block", args[:class]) - }.deep_merge(args.except(:class)) - - content_tag(element, html_options) { content } - end - - # draw a help block with an arrow - def help_block_with_arrow(direction = nil, **args, &block) - div_class = "well well-sm help-block position-relative" - div_class += " mt-3" if direction == "up" - - tag.div(class: div_class, id: args[:id]) do - concat(capture(&block).to_s) - if direction - arrow_class = "arrow-#{direction}" - arrow_class += " hidden-xs" unless args[:mobile] - concat(tag.div("", class: arrow_class)) - end - end - end - - def collapse_help_block(direction = nil, string = nil, **args, &block) - div_class = "well well-sm help-block position-relative" - div_class += " mt-3" if direction == "up" - content = block ? capture(&block) : string - - tag.div(class: "collapse", id: args[:id]) do - tag.div(class: div_class) do - concat(content) - if direction - arrow_class = "arrow-#{direction}" - arrow_class += " hidden-xs" unless args[:mobile] - concat(tag.div("", class: arrow_class)) - end - end - end - end - - def collapse_info_trigger(id, **args) - link_to(link_icon(:question), "##{id}", - class: class_names("info-collapse-trigger", args[:class]), - role: "button", data: { toggle: "collapse" }, - aria: { expanded: "false", controls: id }) - end - - def panel_block(**args, &block) - heading = panel_block_heading(args) - footer = panel_block_footer(args) - content = capture(&block).to_s - - tag.div( - class: class_names("panel panel-default", args[:class]), - **args.except(:class, :inner_class, :inner_id, :heading, :heading_links) - ) do - concat(heading) - if content.present? - concat(tag.div(class: class_names("panel-body", args[:inner_class]), - id: args[:inner_id]) do - concat(content) - end) - end - concat(footer) - end - end - - def panel_block_heading(args) - if args[:heading] - tag.div(class: "panel-heading") do - tag.h4(class: "panel-title") do - els = [args[:heading]] - if args[:heading_links].present? - els << tag.span(args[:heading_links], class: "float-right") - end - els.safe_join - end - end - else - "" - end - end - - def panel_block_footer(args) - if args[:footer] - tag.div(class: "panel-footer") do - args[:footer] - end - else - "" - end - end - - def alert_block(level = :warning, string = "") - content_tag(:div, string, class: "alert alert-#{level}") - end - - # Create a div for notes. - # - # <%= notes_panel(html) %> - # - # <% notes_panel() do %> - # Render stuff in here. Note lack of "=" in line above. - # <% end %> - # - def notes_panel(msg = nil, &block) - msg = capture(&block) if block - result = tag.div(msg, class: "panel-body") - wrapper = tag.div(result, class: "panel panel-default dotted-border") - if block - concat(wrapper) - else - wrapper - end - end - - # Bootstrap tablist - def tab_nav(**args, &block) - if args[:tabs] - content = capture do - args[:tabs].each do |tab| - concat(tab_item(tab[:name], id: tab[:id], active: tab[:active])) - end - end - elsif block - content = capture(&block).to_s - else - content = "" - end - style = args[:style] || "pills" - - tag.ul( - role: "tablist", - class: class_names("nav nav-#{style}", args[:class]), - **args.except(:class, :style) - ) do - content - end - end - - # Bootstrap "tab" item in ul/li tablist - def tab_item(name, **args) - active = args[:active] ? "active" : nil - disabled = args[:disabled] ? "disabled" : nil - - tag.li( - role: "presentation", - class: class_names(active, disabled, args[:class]) - ) do - tab_link(name, **args.except(:active, :disabled, :class)) - end - end - - # Bootstrap tab - just the link. Use for independent tab (e.g. button). - def tab_link(name, **args) - classes = args[:button] ? "btn btn-default" : "nav-link" - - link_to( - name, "##{args[:id]}-tab-pane", - role: "tab", id: "#{args[:id]}-tab", class: classes, - data: { toggle: "tab" }, aria: { controls: "#{args[:id]}-tab-pane" } - ) - end - - # Bootstrap tabpanel wrapper - def tab_content(**args, &block) - content = capture(&block).to_s - - tag.div(class: class_names("tab-content", args[:class]), - **args.except(:class)) do - content - end - end - - # Bootstrap tabpanel - def tab_panel(**args, &block) - content = capture(&block).to_s - active = args[:active] ? "in active" : nil - - tag.div( - role: "tabpanel", id: "#{args[:id]}-tab-pane", - class: class_names("tab-pane fade", active, args[:class]), - aria: { labelledby: "#{args[:id]}-tab" }, - **args.except(:class, :id) - ) do - content - end - end end diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index e3eda3da22..a55be8171d 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -92,14 +92,14 @@ def check_box_with_label(**args) wrap_class = form_group_wrap_class(args, "checkbox") tag.div(class: wrap_class) do - args[:form].label(args[:field]) do + concat(args[:form].label(args[:field]) do concat(args[:form].check_box(args[:field], opts)) concat(args[:label]) if args[:between].present? concat(tag.div(class: "d-inline-block ml-3") { args[:between] }) end - concat(args[:append]) if args[:append].present? - end + end) + concat(args[:append]) if args[:append].present? end end @@ -126,14 +126,14 @@ def radio_with_label(**args) wrap_class = form_group_wrap_class(args, "radio") tag.div(class: wrap_class) do - args[:form].label("#{args[:field]}_#{args[:value]}") do + concat(args[:form].label("#{args[:field]}_#{args[:value]}") do concat(args[:form].radio_button(args[:field], args[:value], opts)) concat(args[:label]) if args[:between].present? concat(tag.div(class: "d-inline-block ml-3") { args[:between] }) end - concat(args[:append]) if args[:append].present? - end + end) + concat(args[:append]) if args[:append].present? end end @@ -164,7 +164,7 @@ def text_field_with_label(**args) label_opts = field_label_opts(args) label_opts[:class] = class_names(label_opts[:class], args[:label_class]) - tag.div(class: wrap_class, data: wrap_data, id: args[:wrap_id]) do + tag.div(class: wrap_class, data: wrap_data) do concat(text_label_row(args, label_opts)) if args[:addon].present? # text addon, not interactive concat(tag.div(class: "input-group") do diff --git a/app/helpers/link_helper.rb b/app/helpers/link_helper.rb index 8048896771..3ca7578549 100644 --- a/app/helpers/link_helper.rb +++ b/app/helpers/link_helper.rb @@ -181,7 +181,11 @@ def link_icon(type, **args) print: "print", globe: "globe", find_on_map: "screenshot", - apply: "check" + apply: "check", + chevron_down: "chevron-down", + chevron_up: "chevron-up", + chevron_left: "chevron-left", + chevron_right: "chevron-right" }.freeze # button to destroy object diff --git a/app/helpers/panel_helper.rb b/app/helpers/panel_helper.rb new file mode 100644 index 0000000000..5f265b4bc2 --- /dev/null +++ b/app/helpers/panel_helper.rb @@ -0,0 +1,282 @@ +# frozen_string_literal: true + +# helpers for bootstrap panels +module PanelHelper + # For a collapsing panel_block, pass an HTML id for args[:collapse] and + # args[:collapse_show] to show it open by default. + # Pass args[:panel_bodies] to create multiple panel bodies, or args[:content] + # to pass preformatted content instead of building `panel-body` here. + def panel_block(**args, &block) + heading = panel_heading(args) + footer = panel_footer(args) + content = block ? capture(&block).to_s : "" + + tag.div( + class: class_names("panel panel-default", args[:class]), + **args.except(*panel_inner_args) + ) do + concat(heading) + if args[:panel_bodies].present? + concat(panel_bodies(args)) + elsif args[:collapse].present? + concat(panel_collapse_body(args, content)) + else + concat(panel_body(args, content)) + end + concat(footer) + end + end + + # Args passed to panel components that are not applied to the outer div. + def panel_inner_args + [:class, :inner_class, :inner_id, :heading, :heading_links, :panel_bodies, + :collapse, :open, :footer].freeze + end + + def panel_heading(args) + return "" unless args[:heading] + + tag.div(class: "panel-heading") do + if args[:collapse].present? + panel_heading_collapse_elements(args) + else + panel_heading_elements(args) + end + end + end + + def panel_heading_elements(args) + els = [args[:heading]] + if args[:heading_links].present? + els << tag.span(args[:heading_links], class: "float-right") + end + + tag.h4(class: "panel-title") { els.safe_join } + end + + # The whole heading is a link that toggles the panel collapse. + # NOTE: args[:open] should be a boolean + def panel_heading_collapse_elements(args) + collapsed = args[:open] ? "" : "collapsed" + + tag.h4(class: "panel-title") do + link_to( + "##{args[:collapse]}", + class: class_names("panel-collapse-trigger", collapsed), + role: "button", data: { toggle: "collapse" }, + aria: { expanded: args[:open], controls: args[:collapse] } + ) do + [args[:heading], + tag.span(panel_collapse_icons, class: "float-right")].safe_join + end + end + end + + # The caret icon that indicates toggling the panel open/collapsed. + def panel_collapse_icons + [link_icon(:chevron_down, title: :OPEN.l, class: "active-icon"), + link_icon(:chevron_up, title: :CLOSE.l)].safe_join + end + + # Some panels need multiple panel bodies. + def panel_bodies(args) + args[:panel_bodies].map do |body| + panel_body(args, body) + end.safe_join + end + + def panel_collapse_body(args, content) + open = args[:open] ? "in" : "" + + tag.div(class: class_names("panel-collapse collapse", open), + id: args[:collapse]) do + concat(panel_body(args, content)) + end + end + + def panel_body(args, content) + return "" if content.blank? + return content if args[:formatted_content] + + tag.div(class: class_names("panel-body", args[:inner_class]), + id: args[:inner_id]) do + concat(content) + end + end + + def panel_footer(args) + if args[:footer] + tag.div(class: "panel-footer") do + args[:footer] + end + else + "" + end + end + + def alert_block(level = :warning, string = "") + content_tag(:div, string, class: "alert alert-#{level}") + end + + # Create a div for notes. + # + # <%= notes_panel(html) %> + # + # <% notes_panel() do %> + # Render stuff in here. Note lack of "=" in line above. + # <% end %> + # + def notes_panel(msg = nil, &block) + msg = capture(&block) if block + result = tag.div(msg, class: "panel-body") + wrapper = tag.div(result, class: "panel panel-default dotted-border") + if block + concat(wrapper) + else + wrapper + end + end + + # Help tooltip, note, block. + # + # Help tooltip is a span with a title attribute. This has the effect of + # giving it context help (mouse-over popup) in most modern browsers. + # + # <%= help_tooltip(label, title: "Click here to do something.") %> + # + def help_tooltip(label, **args) + args[:data] ||= {} + tag.span(label, title: args[:title], + class: class_names("context-help", args[:class]), + data: { toggle: "tooltip" }.merge(args[:data])) + end + + # make a help-note styled element, like a div, p, or span + def help_note(element = :span, string = "") + content_tag(element, string, class: "help-note mr-3") + end + + # make a help-block styled element, like a div, p + def help_block(element = :div, string = "", **args, &block) + content = block ? capture(&block) : string + html_options = { + class: class_names("help-block", args[:class]) + }.deep_merge(args.except(:class)) + + content_tag(element, html_options) { content } + end + + # draw a help block with an arrow + def help_block_with_arrow(direction = nil, **args, &block) + div_class = "well well-sm help-block position-relative" + div_class += " mt-3" if direction == "up" + + tag.div(class: div_class, id: args[:id]) do + concat(capture(&block).to_s) + if direction + arrow_class = "arrow-#{direction}" + arrow_class += " hidden-xs" unless args[:mobile] + concat(tag.div("", class: arrow_class)) + end + end + end + + def collapse_help_block(direction = nil, string = nil, **args, &block) + div_class = "well well-sm help-block position-relative" + div_class += " mt-3" if direction == "up" + content = block ? capture(&block) : string + + tag.div(class: "collapse", id: args[:id]) do + tag.div(class: div_class) do + concat(content) + if direction + arrow_class = "arrow-#{direction}" + arrow_class += " hidden-xs" unless args[:mobile] + concat(tag.div("", class: arrow_class)) + end + end + end + end + + def collapse_info_trigger(id, **args) + link_to(link_icon(:question), "##{id}", + class: class_names("info-collapse-trigger", args[:class]), + role: "button", data: { toggle: "collapse" }, + aria: { expanded: "false", controls: id }) + end + + # BOOTSTRAP TABBED CONTENT + # + # Bootstrap tablist + def tab_nav(**args, &block) + if args[:tabs] + content = capture do + args[:tabs].each do |tab| + concat(tab_item(tab[:name], id: tab[:id], active: tab[:active])) + end + end + elsif block + content = capture(&block).to_s + else + content = "" + end + style = args[:style] || "pills" + + tag.ul( + role: "tablist", + class: class_names("nav nav-#{style}", args[:class]), + **args.except(:class, :style) + ) do + content + end + end + + # Bootstrap "tab" item in ul/li tablist + def tab_item(name, **args) + active = args[:active] ? "active" : nil + disabled = args[:disabled] ? "disabled" : nil + + tag.li( + role: "presentation", + class: class_names(active, disabled, args[:class]) + ) do + tab_link(name, **args.except(:active, :disabled, :class)) + end + end + + # Bootstrap tab - just the link. Use for independent tab (e.g. button). + def tab_link(name, **args) + classes = args[:button] ? "btn btn-default" : "nav-link" + + link_to( + name, "##{args[:id]}-tab-pane", + role: "tab", id: "#{args[:id]}-tab", class: classes, + data: { toggle: "tab" }, aria: { controls: "#{args[:id]}-tab-pane" } + ) + end + + # Bootstrap tabpanel wrapper + def tab_content(**args, &block) + content = capture(&block).to_s + + tag.div(class: class_names("tab-content", args[:class]), + **args.except(:class)) do + content + end + end + + # Bootstrap tabpanel + def tab_panel(**args, &block) + content = capture(&block).to_s + active = args[:active] ? "in active" : nil + + tag.div( + role: "tabpanel", id: "#{args[:id]}-tab-pane", + class: class_names("tab-pane fade", active, args[:class]), + aria: { labelledby: "#{args[:id]}-tab" }, + **args.except(:class, :id) + ) do + content + end + end +end diff --git a/app/javascript/controllers/advanced-search_controller.js b/app/javascript/controllers/advanced-search_controller.js index 74354491ff..88b73f7bbd 100644 --- a/app/javascript/controllers/advanced-search_controller.js +++ b/app/javascript/controllers/advanced-search_controller.js @@ -5,7 +5,7 @@ export default class extends Controller { static targets = ["searchModel", "filter"] connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "advanced-search-connected"; this.disableUnusedFilters(); } diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 8402522114..4dd0b242b8 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -149,7 +149,7 @@ export default class extends Controller { // The select target is not the element, but a element is its target. static targets = ["input", "select", "pulldown", "list", "hidden", "wrap", - "createBtn", "hasIdIndicator", "keepBtn", "mapWrap"] + "createBtn", "hasIdIndicator", "keepBtn", "mapWrap", "collapseFields"] static outlets = ["map"] initialize() { @@ -174,7 +174,7 @@ export default class extends Controller { } connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "autocompleter-connected"; // Figure out a few browser-dependent dimensions. this.getScrollBarWidth; @@ -479,6 +479,11 @@ export default class extends Controller { const old_val = this.old_value; const new_val = this.inputTarget.value; // this.debug("ourChange(" + this.inputTarget.value + ")"); + if (new_val.length > 0) { + this.cssUncollapseFields(); + } else { + this.cssCollapseFields(); + } if (new_val != old_val) { this.old_value = new_val; if (do_refresh) { @@ -1026,6 +1031,18 @@ export default class extends Controller { } } + cssCollapseFields() { + if (!this.hasCollapseFieldsTarget) return; + + $(this.collapseFieldsTarget).collapse('hide'); + } + + cssUncollapseFields() { + if (!this.hasCollapseFieldsTarget) return; + + $(this.collapseFieldsTarget).collapse('show'); + } + storeCurrentHiddenData() { this.verbose("autocompleter:storeCurrentHiddenData()"); this.stored_id = parseInt(this.hiddenTarget.value); // value is a string diff --git a/app/javascript/controllers/banner_controller.js b/app/javascript/controllers/banner_controller.js index 4c4dfe27ea..7ac360d090 100644 --- a/app/javascript/controllers/banner_controller.js +++ b/app/javascript/controllers/banner_controller.js @@ -3,7 +3,7 @@ import { Controller } from "@hotwired/stimulus" // Connects to data-controller="banner" export default class extends Controller { connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "banner-connected"; } setCookie({ params: { time } }) { diff --git a/app/javascript/controllers/donate_controller.js b/app/javascript/controllers/donate_controller.js index a82d330456..992de05b2e 100644 --- a/app/javascript/controllers/donate_controller.js +++ b/app/javascript/controllers/donate_controller.js @@ -5,7 +5,7 @@ export default class extends Controller { static targets = ['otherCheck', 'otherAmount'] connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "donate-connected"; } checkOther() { diff --git a/app/javascript/controllers/field-slip-job_controller.js b/app/javascript/controllers/field-slip-job_controller.js index f65fbac72b..f111256fd2 100644 --- a/app/javascript/controllers/field-slip-job_controller.js +++ b/app/javascript/controllers/field-slip-job_controller.js @@ -16,7 +16,7 @@ export default class extends Controller { connect() { // Just a "sanity check" convention, so you can tell "is this thing on?" - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "field-slip-job-connected"; this.status_id = this.element.dataset.status this.start_timer_sending_requests() diff --git a/app/javascript/controllers/file-input_controller.js b/app/javascript/controllers/file-input_controller.js index 4ecdfd356f..7a3c3d3b02 100644 --- a/app/javascript/controllers/file-input_controller.js +++ b/app/javascript/controllers/file-input_controller.js @@ -5,7 +5,7 @@ export default class extends Controller { static targets = ['input', 'name'] connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "file-input-connected"; this.max_size = Number(this.inputTarget.dataset.maxUploadSize); this.error_msg = this.inputTarget.dataset.maxUploadMsg; this.old_callback = this.inputTarget.onchange; diff --git a/app/javascript/controllers/form-exif_controller.js b/app/javascript/controllers/form-exif_controller.js index 34c073ac5c..d966c80f9d 100644 --- a/app/javascript/controllers/form-exif_controller.js +++ b/app/javascript/controllers/form-exif_controller.js @@ -13,11 +13,11 @@ const internalConfig = { // (formerly "observation_images" section of the form) // Connects to data-controller="form-exif" export default class extends Controller { - static targets = ["carousel", "item", "useExifBtn"] + static targets = ["carousel", "item", "useExifBtn", "collapseFields"] static outlets = ["autocompleter", "map"] connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "form-exif-connected"; Object.assign(this, internalConfig); Object.assign(this.localized_text, @@ -68,25 +68,32 @@ export default class extends Controller { } populateExifGPS(itemElement, exif_data) { - const _exif_lat = itemElement.querySelector(".exif_lat"), + const _exif_gps = itemElement.querySelector(".exif_gps"), + _exif_no_gps = itemElement.querySelector(".exif_no_gps"), + _exif_lat = itemElement.querySelector(".exif_lat"), _exif_lng = itemElement.querySelector(".exif_lng"), _exif_alt = itemElement.querySelector(".exif_alt"), _use_exif_button = itemElement.querySelector('.use_exif_btn'); // Geocode Logic // check if there is geodata on the image - if (exif_data.GPSLatitude && exif_data.GPSLongitude) { + if (exif_data.GPSLatitude && exif_data.GPSLatitude.description && + exif_data.GPSLongitude && exif_data.GPSLongitude.description) { const latLngAlt = this.getLatLngEXIF(exif_data), { lat, lng, alt } = latLngAlt; // Set item's data-geocode attribute so we can have a record itemElement.dataset.geocode = JSON.stringify(latLngAlt); - // These are not inputs, they're spans so we can't set the value + // These are spans, not inputs — set innerText, not value _exif_lat.innerText = lat == null ? lat : lat.toFixed(4); _exif_lng.innerText = lng == null ? lng : lng.toFixed(4); _exif_alt.innerText = alt == null ? alt : alt.toFixed(0); _use_exif_button.classList.remove('d-none'); + } else { + // Show the "no GPS" message + _exif_gps.classList.add("d-none"); + _exif_no_gps.classList.remove("d-none"); } } @@ -185,6 +192,15 @@ export default class extends Controller { } // disables the button, even when called programmatically this.selectExifButton(element); + // show the geolocation fields + this.showFields(); + } + + // show the geolocation fields + showFields() { + if (this.hasCollapseFieldsTarget) { + $(this.collapseFieldsTarget).collapse('show'); + } } // Disables this button but enables others, kind of like a radio. Happens on diff --git a/app/javascript/controllers/form-images_controller.js b/app/javascript/controllers/form-images_controller.js index b08c398756..83a520ece1 100644 --- a/app/javascript/controllers/form-images_controller.js +++ b/app/javascript/controllers/form-images_controller.js @@ -54,7 +54,7 @@ export default class extends Controller { } connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "form-images-connected"; Object.assign(this, internalConfig); Object.assign(this.localized_text, diff --git a/app/javascript/controllers/geocode_controller.js b/app/javascript/controllers/geocode_controller.js index 1284151180..892b06ee9c 100644 --- a/app/javascript/controllers/geocode_controller.js +++ b/app/javascript/controllers/geocode_controller.js @@ -13,7 +13,7 @@ export default class extends Controller { static outlets = ["autocompleter"] connect() { - this.element.dataset.stimulus = "connected" + this.element.dataset.stimulus = "geocode-connected" // These private vars are for keeping track of user inputs to a form // that should update the form after a timeout. diff --git a/app/javascript/controllers/lazyload_controller.js b/app/javascript/controllers/lazyload_controller.js index b1904eb2fa..bc417a64f5 100644 --- a/app/javascript/controllers/lazyload_controller.js +++ b/app/javascript/controllers/lazyload_controller.js @@ -3,7 +3,7 @@ import { Controller } from "@hotwired/stimulus" // Connects to data-controller="lazyload" export default class extends Controller { connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "lazyload-connected"; if (window.lazyLoadInstance != undefined) window.lazyLoadInstance.update(); diff --git a/app/javascript/controllers/lightgallery_controller.js b/app/javascript/controllers/lightgallery_controller.js index 4e4fda18ce..ca522def36 100644 --- a/app/javascript/controllers/lightgallery_controller.js +++ b/app/javascript/controllers/lightgallery_controller.js @@ -5,7 +5,7 @@ import lgZoom from 'lightgallery/plugins/zoom' // Connects to data-controller="lightgallery", currently "#content" export default class extends Controller { connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "lightgallery-connected"; lightGallery(this.element, { selector: '.theater-btn', diff --git a/app/javascript/controllers/links_controller.js b/app/javascript/controllers/links_controller.js index 4a775a7eb3..c57e95a9b8 100644 --- a/app/javascript/controllers/links_controller.js +++ b/app/javascript/controllers/links_controller.js @@ -3,7 +3,7 @@ import { Controller } from "@hotwired/stimulus" // Connects to data-controller="links" export default class extends Controller { connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "links-connected"; } disable(e) { diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index 2a115b765b..207085ba67 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -15,7 +15,7 @@ export default class extends GeocodeController { "autocompleter"] connect() { - this.element.dataset.stimulus = "connected" + this.element.dataset.stimulus = "map-connected" this.map_type = this.mapDivTarget.dataset.mapType this.editable = (this.mapDivTarget.dataset.editable === "true") this.opened = this.element.dataset.mapOpen === "true" diff --git a/app/javascript/controllers/matrix-table_controller.js b/app/javascript/controllers/matrix-table_controller.js index 44e3090305..3ab0fac1ee 100644 --- a/app/javascript/controllers/matrix-table_controller.js +++ b/app/javascript/controllers/matrix-table_controller.js @@ -3,7 +3,7 @@ import { Controller } from "@hotwired/stimulus" // Connects to data-controller="matrix-table" export default class extends Controller { connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "matrix-table-connected"; this.matrixBoxes = document.querySelectorAll('.matrix-box') this.boxes = document.querySelectorAll('.matrix-box .panel-sizing') diff --git a/app/javascript/controllers/modal-toggle_controller.js b/app/javascript/controllers/modal-toggle_controller.js index 9290da4a0c..a3ed06b854 100644 --- a/app/javascript/controllers/modal-toggle_controller.js +++ b/app/javascript/controllers/modal-toggle_controller.js @@ -7,10 +7,11 @@ import { get } from "@rails/request.js" // For example, you can start entering a collection number, close the modal, // open a herbarium record form, close it and go back to the collection number // and find the form form as you left it, or vice versa, until you submit. +// Connects to data-controller="modal-toggle" export default class extends Controller { connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "modal-toggle-connected"; this.modalSelector = this.element.dataset.modal this.destination = this.element.getAttribute("href") } diff --git a/app/javascript/controllers/modal_controller.js b/app/javascript/controllers/modal_controller.js index 0740c84292..ea0738fa44 100644 --- a/app/javascript/controllers/modal_controller.js +++ b/app/javascript/controllers/modal_controller.js @@ -7,7 +7,7 @@ export default class extends Controller { connect() { // console.log("Hello Modal " + this.element.id); - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "modal-connected"; } // Modal is only removed in the event that the page section updates. diff --git a/app/javascript/controllers/name-list_controller.js b/app/javascript/controllers/name-list_controller.js index 96738b2c18..609d9a747b 100644 --- a/app/javascript/controllers/name-list_controller.js +++ b/app/javascript/controllers/name-list_controller.js @@ -43,7 +43,7 @@ export default class extends Controller { } connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "name-list-connected"; // These are the div elements for each column. this.DIVS = { diff --git a/app/javascript/controllers/name-panels_controller.js b/app/javascript/controllers/name-panels_controller.js index e6863dfe3b..dfe89a1dbd 100644 --- a/app/javascript/controllers/name-panels_controller.js +++ b/app/javascript/controllers/name-panels_controller.js @@ -7,7 +7,7 @@ export default class extends Controller { static targets = ['classification', 'lifeform'] connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "name-panels-connected"; this.equalizePanelHeights() } diff --git a/app/javascript/controllers/naming-reason_controller.js b/app/javascript/controllers/naming-reason_controller.js index ae878ec301..7431894fba 100644 --- a/app/javascript/controllers/naming-reason_controller.js +++ b/app/javascript/controllers/naming-reason_controller.js @@ -1,8 +1,6 @@ import { Controller } from "@hotwired/stimulus" import { delegate, abnegate } from 'jquery-events-to-dom-events' -// Connects to data-controller="naming-reason" - // https://github.com/leastbad/jquery-events-to-dom-events // We use a Stimulus action that listens to `$shown.bs.collapse` on the div // (note the `$`). This depends on using `delegate` from the imported library @@ -11,11 +9,12 @@ import { delegate, abnegate } from 'jquery-events-to-dom-events' // // If moving to BS 5, can remove. +// Connects to data-controller="naming-reason" export default class extends Controller { static targets = ['collapse', 'input'] connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "naming-reason-connected"; this.delegate = delegate('shown.bs.collapse') } diff --git a/app/javascript/controllers/naming-vote_controller.js b/app/javascript/controllers/naming-vote_controller.js index aeb3123c50..ce4ae2e74f 100644 --- a/app/javascript/controllers/naming-vote_controller.js +++ b/app/javascript/controllers/naming-vote_controller.js @@ -2,6 +2,8 @@ import { Controller } from "@hotwired/stimulus" // Controller deals with naming vote select bindings ** per select. ** // the controller is on the
+ +// Connects to data-controller="naming-vote" export default class extends Controller { static targets = ["select", "submit"] @@ -11,7 +13,7 @@ export default class extends Controller { connect() { // console.log("Hello Modal"); - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "naming-vote-connected"; // The localized text is for the modal progress caption. Object.assign(this.localized_text, JSON.parse(this.element.dataset.localization)); diff --git a/app/javascript/controllers/nav-active_controller.js b/app/javascript/controllers/nav-active_controller.js index 4ff0ebda5f..26780431e2 100644 --- a/app/javascript/controllers/nav-active_controller.js +++ b/app/javascript/controllers/nav-active_controller.js @@ -6,7 +6,7 @@ export default class extends Controller { static targets = ['link'] connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "nav-active-connected"; this.pickActive(); } diff --git a/app/javascript/controllers/nav_controller.js b/app/javascript/controllers/nav_controller.js index 61766e685a..18dd41718d 100644 --- a/app/javascript/controllers/nav_controller.js +++ b/app/javascript/controllers/nav_controller.js @@ -5,7 +5,7 @@ export default class extends Controller { static targets = ['hamburger', 'search', 'container', 'offcanvas', 'topNav'] connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "nav-connected"; } // HAMBURGER HELPER action to toggle offcanvas left nav diff --git a/app/javascript/controllers/reviewed-toggle_controller.js b/app/javascript/controllers/reviewed-toggle_controller.js index 2805c4cdf3..b0e3eb4afc 100644 --- a/app/javascript/controllers/reviewed-toggle_controller.js +++ b/app/javascript/controllers/reviewed-toggle_controller.js @@ -6,7 +6,7 @@ export default class extends Controller { static targets = ['toggle'] connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "reviewed-toggle-connected"; } // https://stackoverflow.com/questions/68624668/how-can-i-submit-a-form-on-input-change-with-turbo-streams diff --git a/app/javascript/controllers/section-update_controller.js b/app/javascript/controllers/section-update_controller.js index 38519e5cf7..f8a5f4b80b 100644 --- a/app/javascript/controllers/section-update_controller.js +++ b/app/javascript/controllers/section-update_controller.js @@ -6,7 +6,7 @@ export default class extends Controller { // this is a handler for page elements that get updated // on successful form submit, so it "cleans up" connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "section-update-connected"; // Note: this is simpler than adding an action on every frame. hides modal this.element.addEventListener("turbo:frame-render", this.updated()); diff --git a/app/javascript/controllers/specimen_controller.js b/app/javascript/controllers/specimen_controller.js deleted file mode 100644 index 51dde8d910..0000000000 --- a/app/javascript/controllers/specimen_controller.js +++ /dev/null @@ -1,30 +0,0 @@ -import { Controller } from "@hotwired/stimulus" - -// Connects to data-controller="specimen" -export default class extends Controller { - static targets = ["checkbox", "fields"] - - connect() { - this.element.dataset.stimulus = "connected"; - - this.showPref = this.element.dataset.userPref - if (this.hasFieldsTarget && this.showPref) { - this.hideShowFields() - } - } - - // Only show if user prefers - hideShowFields() { - if (this.checkboxTarget.checked) { - this.fieldsTarget.classList.remove("hidden") - $(this.fieldsTarget).show() - } else { - $(this.fieldsTarget).hide() - } - } - - // This checks "specimen" anyway if people add a CN or HR. - checkCheckbox() { - this.checkboxTarget.setAttribute("checked", true) - } -} diff --git a/app/javascript/controllers/suggestions_controller.js b/app/javascript/controllers/suggestions_controller.js index f68a978ca1..6838e3dba2 100644 --- a/app/javascript/controllers/suggestions_controller.js +++ b/app/javascript/controllers/suggestions_controller.js @@ -10,7 +10,7 @@ export default class extends Controller { } connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "suggestions-connected"; this.progressModal = document.getElementById("mo_ajax_progress") this.progressCaption = document.getElementById("mo_ajax_progress_caption") diff --git a/app/javascript/controllers/thumbnail-map_controller.js b/app/javascript/controllers/thumbnail-map_controller.js index 508f5d6dc7..b9d7c0dc57 100644 --- a/app/javascript/controllers/thumbnail-map_controller.js +++ b/app/javascript/controllers/thumbnail-map_controller.js @@ -5,7 +5,7 @@ export default class extends Controller { static targets = ["mapContainer", "map", "globe"] connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "thumbnail-map-connected"; this.map_url = this.element.dataset.mapUrl this.coords = JSON.parse(this.element.dataset.coordinates) diff --git a/app/javascript/controllers/translation_controller.js b/app/javascript/controllers/translation_controller.js index 4c646fcee4..9615c72d60 100644 --- a/app/javascript/controllers/translation_controller.js +++ b/app/javascript/controllers/translation_controller.js @@ -8,7 +8,7 @@ export default class extends Controller { ] connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "translate-connected"; this.LOCALE = this.element.dataset.locale; this.CONFIRM_STRING = this.element.dataset.confirmString; diff --git a/app/javascript/controllers/year-input_controller.js b/app/javascript/controllers/year-input_controller.js index 4ed344bce5..b320ea2258 100644 --- a/app/javascript/controllers/year-input_controller.js +++ b/app/javascript/controllers/year-input_controller.js @@ -3,7 +3,7 @@ import { Controller } from "@hotwired/stimulus" // Connects to data-controller="year-input" export default class extends Controller { connect() { - this.element.dataset.stimulus = "connected"; + this.element.dataset.stimulus = "year-input-connected"; this.id = this.element.getAttribute("id"); // console.log(this.id) diff --git a/app/views/controllers/field_slips/_obs_thumbnail.erb b/app/views/controllers/field_slips/_obs_thumbnail.erb index 92683315e8..1f0ff94f4a 100644 --- a/app/views/controllers/field_slips/_obs_thumbnail.erb +++ b/app/views/controllers/field_slips/_obs_thumbnail.erb @@ -1,5 +1,5 @@ <%= tag.div(class: "panel panel-default") do - concat(panel_block_heading( + concat(panel_heading( heading: submit_button(form: form, button: button) )) concat(tag.div(class: "thumbnail-container") do diff --git a/app/views/controllers/names/synonyms/deprecate/new.html.erb b/app/views/controllers/names/synonyms/deprecate/new.html.erb index 86c7ea9f9e..ff1bb067f3 100644 --- a/app/views/controllers/names/synonyms/deprecate/new.html.erb +++ b/app/views/controllers/names/synonyms/deprecate/new.html.erb @@ -9,10 +9,10 @@ action = { controller: "/names/synonyms/deprecate", action: :create, feedback_locals = { button_name: :SUBMIT.l, given_name: @given_name, + names: @names, valid_names: @valid_names, suggest_corrections: @suggest_corrections, - parent_deprecated: @parent_deprecated, - names: @names + parent_deprecated: @parent_deprecated } deprecate_comments_help = capture do @@ -26,7 +26,7 @@ end <%= submit_button(form: f, button: :SUBMIT.l, center: true) %> <%= render(partial: "shared/form_name_feedback", - locals: feedback_locals.merge({ f: f })) if @given_name.present? %> + locals: feedback_locals) if @given_name.present? %> <%= autocompleter_field( form: f, field: :proposed_name, type: :name, diff --git a/app/views/controllers/observations/_form.html.erb b/app/views/controllers/observations/_form.html.erb index 2c959fd666..25be05f0d8 100644 --- a/app/views/controllers/observations/_form.html.erb +++ b/app/views/controllers/observations/_form.html.erb @@ -1,11 +1,22 @@ -<%# locals: (action:) -%> <% +# Declaring permitted locals in a magic comment doesn't work here (?) create = (action == :create) method = create ? :post : :patch button_name = create ? :CREATE.l : :SAVE_EDITS.l -include_naming = create ? true : false has_specimen = create ? false : @observation.herbarium_records.length > 0 logging_optional = create ? false : true +naming_locals = { + create:, + button_name:, + show_reasons: false, + unfocused: true, + name_help: :form_naming_name_help_leave_blank.t +} +notes_fields = @observation.form_notes_parts(@user) +notes_open = (create && notes_fields.length > 1) || @observation.notes.present? +show_projects = @projects.any? || @error_checked_projects.any? || + @suspect_checked_projects.any? +show_lists = @lists.any? # Data for the form-images Stimulus controller. # Controller element is the form, so image dropzone can cover the whole form. @@ -20,7 +31,7 @@ image_upload_localization = { something_went_wrong: :form_observations_upload_error.t }.to_json # Outlets are how the stimulus controllers call each others' methods. -data = { +form_element_data = { controller: "form-images form-exif map", map_autocompleter_outlet: "#observation_location_autocompleter", map_open: false, @@ -32,7 +43,6 @@ data = { form_images_target: "form", exif_used: create ? false : true } -projects_lists = @projects.any? || @lists.any? %> <%= form_with( @@ -43,26 +53,69 @@ projects_lists = @projects.any? || @lists.any? method:, multipart: true, id: "observation_form", - data: + data: form_element_data ) do |f| %> - <%= if @field_code - tag.p("#{:form_observations_field_code.t} #{@field_code}") + <% if @field_code %> + <%= tag.p("#{:form_observations_field_code.t} #{@field_code}") %> + <%= hidden_field_tag(:field_code, @field_code) %> + <% end %> + + <%= panel_block( + heading: "#{:IMAGES.l} + #{:show_observation_details.l}", + id: "observation_images_details", formatted_content: true, + collapse: "observation_images_details_inner", open: true + ) do + concat(render(partial: "observations/form/images", locals: { f: })) + concat(render(partial: "observations/form/details", + locals: { f:, action:, button_name:, location: @location, + logging_optional: })) + end %> + + <%= panel_block( + heading: "#{:IDENTIFICATION.l} + #{:SPECIMEN.l}", + id: "observation_naming_specimen", # @given_name.present? + collapse: "observation_naming_specimen_inner", open: create + ) do + tag.div(class: "row mt-3") do + concat(tag.div(class: "col-xs-12 col-md-6") do + render(partial: "observations/namings/fields", locals: naming_locals) + end) if create + concat(tag.div(class: "col-xs-12 col-md-6") do + render(partial: "observations/form/specimen_section", + locals: { f:, action: }) + end) + end end %> - <%= hidden_field_tag(:field_code, @field_code) %> - <%= tab_content do %> - <%= render(partial: "observations/form/record_step", - locals: { f:, button_name:, location: @location, - logging_optional: }) %> + <%= submit_button(form: f, button: button_name, center: true) %> + + <%= panel_block( + heading: :NOTES.l, id: "observation_notes", + collapse: "observation_notes_inner", open: notes_open + ) do + render(partial: "shared/notes_fields", + locals: { form: f, fields: notes_fields }) + end %> - <%= render(partial: "observations/form/identify_step", - locals: { f:, action:, button_name:, include_naming: }) %> + <% if show_projects %> + <%= panel_block( + heading: :PROJECTS.l, id: "observation_projects", + collapse: "observation_projects_inner", + open: @project_checks.any? + ) do + render(partial: "observations/form/projects", locals: { button_name: }) + end %> + <% end %> - <% if projects_lists %> - <%= render(partial: "observations/form/add_to_step", - locals: { f:, button_name: }) %> - <% end %> + <% if show_lists %> + <%= panel_block( + heading: :SPECIES_LISTS.l, id: "observation_lists", + collapse: "observation_lists_inner", + open: @list_checks.any? + ) do + render(partial: "observations/form/species_lists") + end %> <% end %> <% end %> diff --git a/app/views/controllers/observations/form/_add_to_step.erb b/app/views/controllers/observations/form/_add_to_step.erb deleted file mode 100644 index 47f2d195d8..0000000000 --- a/app/views/controllers/observations/form/_add_to_step.erb +++ /dev/null @@ -1,30 +0,0 @@ -<%# locals: (f:, button_name:) -%> -<%# Add to Project and List section of create_observation form %> - -<%= tab_panel(id: "add_to") do %> - <%= panel_block(id: "observation_projects_and_lists", - heading: "#{:PROJECTS.l} + #{:SPECIES_LISTS.l}") do %> - - <%= tag.div(class: "row mt-3") do %> - <% if @projects.any? %> - <%= tag.div(class: "col-xs-12 col-sm-6") do - render(partial: "observations/form/projects", - locals: { button_name: }) - end %> - <% end %> - <% if @lists.any? %> - <%= tag.div(class: "col-xs-12 col-sm-6") do - render(partial: "observations/form/species_lists") - end %> - <% end %> - <% end %> - - <%= tag.div(class: "row mt-5 text-center", id: "step-nav-3") do - [ - tab_link(:BACK.l, id: "identify", button: true), - submit_button(form: f, button: button_name) - ].safe_join(" ") - end %> - <% end %> -<% end %> - diff --git a/app/views/controllers/observations/form/_details.html.erb b/app/views/controllers/observations/form/_details.html.erb index 9471ea8834..8d5733b808 100644 --- a/app/views/controllers/observations/form/_details.html.erb +++ b/app/views/controllers/observations/form/_details.html.erb @@ -1,7 +1,7 @@ -<%# locals: (f:, button_name:, location:, logging_optional:) -%> +<%# locals: (f:, action:, button_name:, location:, logging_optional:, include_naming: false) -%> <%# When and Where (location) section of create_observation form - including location autocomplete, map, lat/long/alt %> + including location autocomplete, map, lat/long/alt, naming %> <% t_s = { lat: { abbr: :LAT.l, full: :LATITUDE.l, addon: "º" }, @@ -21,44 +21,13 @@ t_s = { <%= tag.div(id: "observation_where") do %> - <%= tag.p do - [tag.strong("#{:WHERE_GROUP.l}:"), - collapse_info_trigger("geolocation_help")].safe_join(" ") - end %> - - - <%= tag.div(class: "row no-gutters", - id: "observation_lat_lng_alt") do %> - <% [:lat, :lng, :alt].each do |key| %> - <%= tag.div(class: "col-xs-4") do - text_field_with_label( - form: f, field: key, class: "mb-0", addon: t_s[key][:addon], - label: [ - tag.span("#{t_s[key][:full]}:", class: "d-none d-sm-inline"), - tag.span("#{t_s[key][:abbr]}:", class: "d-inline d-sm-none") - ].safe_join, - data: { map_target: "#{key}Input", action: "map#bufferInputs" } - ) - end %> - <% end %> - <% end %> - - <%= collapse_help_block(nil, id: "geolocation_help") do %> - <%= tag.p(:form_observations_click_point.l) %> - <%= tag.p(:form_observations_lat_long_help.t) %> - <% end %> - - <%= check_box_with_label(form: f, field: :gps_hidden, - label: :form_observations_gps_hidden.l) %> - - <%= render(partial: "shared/form_location_feedback", locals: { button: button_name } ) %> <%= autocompleter_field( - form: f, field: :place_name, type: :location, + form: f, field: :place_name, type: :location, class: "mb-0", label: [tag.span("#{:WHERE.l}:", class: "unconstrained-label"), tag.span("#{:form_observations_locality_contains.l}:", class: "constrained-label"), @@ -76,7 +45,7 @@ t_s = { # find_text: :form_locations_find_on_map.l, # Be precise about which map controller to connect to: map_outlet: "#observation_form", - wrap_id: "observation_location_autocompleter", + controller_id: "observation_location_autocompleter", # Action ok because there's only one form-exif controller on the page, # and it should only affect this autocompleter: data: { @@ -93,30 +62,73 @@ t_s = { <%= check_box_with_label( form: f, field: :is_collection_location, label: :form_observations_is_collection_location.l, - help: :form_observations_is_collection_location_help.t + help: :form_observations_is_collection_location_help.t, + class: "ml-5 mb-5" ) %> + + <%= check_box_with_label( + form: f, field: :has_geolocation, # field is ignored + label: "#{:GEOLOCATION.l}:", + help: :form_observations_lat_long_help.t, + data: { toggle: "collapse", target: "#observation_geolocation" }, + aria: { controls: "observation_geolocation", + expanded: @observation.lat } + ) %> + + <%= tag.div(id: "observation_geolocation", + class: class_names("collapse", ("in" if @observation.lat)), + data: { form_exif_target: "collapseFields" }) do %> + + <%= tag.p(:form_observations_click_point.l) %> + + <%= tag.div(class: "row no-gutters", + id: "observation_lat_lng_alt") do %> + <% [:lat, :lng, :alt].each do |key| %> + <%= tag.div(class: "col-xs-4") do + text_field_with_label( + form: f, field: key, class: "mb-0", addon: t_s[key][:addon], + label: [ + tag.span("#{t_s[key][:full]}:", + class: "d-none d-sm-inline"), + tag.span("#{t_s[key][:abbr]}:", + class: "d-inline d-sm-none") + ].safe_join, + data: { map_target: "#{key}Input", + action: "map#bufferInputs" } + ) + end %> + <% end %> + <% end %> + + <%= check_box_with_label( + form: f, field: :gps_hidden, label: :form_observations_gps_hidden.l, + class: "ml-5 mb-5" + ) %> + + <%# collapse_help_block(nil, id: "geolocation_help") do %> + <%# tag.p(:form_observations_lat_long_help.t) %> + <% end %> + + <% if logging_optional %> <%= check_box_with_label( form: f, field: :log_change, checked: "checked", label: :form_observations_log_change.t ) %> <% end %> - <% end %> <% end %> - <%= tag.div(class: "col-xs-12 col-md-6", - id: "observation_geolocation") do %> + <%= tag.div(class: "col-xs-12 col-md-6") do %> <%= render( - partial: "shared/form_location_map", - locals: { id: "observation_form_map", map_type: "observation" } - ) %> + partial: "shared/form_location_map", + locals: { id: "observation_form_map", map_type: "observation" } + ) %> <% end %> - <% end %> <% end %> diff --git a/app/views/controllers/observations/form/_identify_step.erb b/app/views/controllers/observations/form/_identify_step.erb deleted file mode 100644 index 0f8f794740..0000000000 --- a/app/views/controllers/observations/form/_identify_step.erb +++ /dev/null @@ -1,38 +0,0 @@ -<%# locals: (f:, action:, button_name:, include_naming:) -%> - -<%= tab_panel(id: "identify") do %> - <%= panel_block(id: "observation_identification", - heading: "#{:IDENTIFICATION.l} + #{:NOTES.l}") do %> - <%= tag.div(class: "row mt-3") do %> - <%= tag.div(class: "col-xs-12 col-lg-6") do %> - <% if include_naming - naming_locals = { - f: f, - action: action, - button_name: button_name, - show_reasons: false, - unfocused: true, - name_help: :form_naming_name_help_leave_blank.t - } %> - <%= render(partial: "observations/namings/fields", - locals: naming_locals) %> - <% end %> - <%= render(partial: "observations/form/specimen_section", - locals: { f:, action: }) %> - <% end %> - <%= tag.div(class: "col-xs-12 col-lg-6") do %> - <%= render(partial: "shared/notes_fields", - locals: { form: f, - fields: @observation.form_notes_parts(@user) }) %> - <% end %> - <% end %> - - <%= tag.div(class: "row mt-5 text-center", id: "step-nav-2") do - [ - tab_link(:BACK.l, id: "record", button: true), - tab_link(:NEXT.l, id: "add_to", button: true), - submit_button(form: f, button: button_name) - ].safe_join(" ") - end %> - <% end %> -<% end %> diff --git a/app/views/controllers/observations/form/_images.html.erb b/app/views/controllers/observations/form/_images.html.erb index ed2b3db2d1..e7676c021a 100644 --- a/app/views/controllers/observations/form/_images.html.erb +++ b/app/views/controllers/observations/form/_images.html.erb @@ -12,13 +12,6 @@ i.e. not observation[good_image_ids]. It's a top-level field. --%> <%= tag.div(id: "observation_images") do %> - <%= hidden_field_tag(:good_image_ids, - @good_images.map { |img| img.id }.join(" "), - data: { form_images_target: "goodImageIds" }) %> - - <%= f.hidden_field(:thumb_image_id, - data: { form_images_target: "thumbImageId" }) %> - <%= tag.div(class: "panel-body border-bottom") do [ tag.h4(:IMAGES.l, class: "panel-title d-inline-block mr-4"), @@ -32,7 +25,12 @@ i.e. not observation[good_image_ids]. It's a top-level field. --%> data: { action: "change->form-images#addSelectedFiles" } ) ].safe_join - end + end, + hidden_field_tag(:good_image_ids, + @good_images.map { |img| img.id }.join(" "), + data: { form_images_target: "goodImageIds" }), + f.hidden_field(:thumb_image_id, + data: { form_images_target: "thumbImageId" }) ].safe_join end %> diff --git a/app/views/controllers/observations/form/_projects.html.erb b/app/views/controllers/observations/form/_projects.html.erb index 63a002ba13..3aa8931b18 100644 --- a/app/views/controllers/observations/form/_projects.html.erb +++ b/app/views/controllers/observations/form/_projects.html.erb @@ -20,7 +20,7 @@ if @suspect_checked_projects.any? end %> -<%= tag.div(id: "observation_projects") do %> +<%# tag.div(id: "observation_projects") do %> <%= fields_for(:project) do |f_p| %> <% if error_messages.present? || suspect_messages.present? %> @@ -71,5 +71,5 @@ end <% end %> <% end %> -<% end %> +<%# end %> diff --git a/app/views/controllers/observations/form/_record_step.erb b/app/views/controllers/observations/form/_record_step.erb deleted file mode 100644 index a49bdf2488..0000000000 --- a/app/views/controllers/observations/form/_record_step.erb +++ /dev/null @@ -1,26 +0,0 @@ -<%# locals: (f:, button_name:, location:, logging_optional:) -%> -<%# NOTE: not using panel_block helper, because it has three panel-body divs %> - -<%= tab_panel(id: "record", active: true) do %> - <%= tag.div( - id: "observation_images_details", class: "panel panel-default" - ) do %> - - <%= tag.div(class: "panel-heading") do - tag.h4("#{:IMAGES.l} + #{:show_observation_details.l}", - class: "panel-title") - end %> - - <%= render(partial: "observations/form/images", locals: { f: f }) %> - - <%= render(partial: "observations/form/details", - locals: { f:, button_name:, location:, logging_optional: }) %> - - <%= tag.div(class: "panel-body mt-4") do - tag.div(class: "text-center", id: "step-nav-1") do - tab_link(:NEXT.l, id: "identify", button: true) - end - end %> - - <% end %> -<% end %> diff --git a/app/views/controllers/observations/form/_species_lists.html.erb b/app/views/controllers/observations/form/_species_lists.html.erb index 1172d3fc85..16e147d639 100644 --- a/app/views/controllers/observations/form/_species_lists.html.erb +++ b/app/views/controllers/observations/form/_species_lists.html.erb @@ -1,6 +1,6 @@ <%# species_list section of create_observation form %> -<%= tag.div(id: "observation_projects") do %> +<%# tag.div(id: "observation_lists") do %> <%= fields_for(:list) do |f_l| %> <%= tag.div do @@ -23,4 +23,4 @@ <% end %> <% end %> -<% end %> +<%# end %> diff --git a/app/views/controllers/observations/form/_specimen_section.html.erb b/app/views/controllers/observations/form/_specimen_section.html.erb index 4fae2a6b43..ae96a32c6d 100644 --- a/app/views/controllers/observations/form/_specimen_section.html.erb +++ b/app/views/controllers/observations/form/_specimen_section.html.erb @@ -3,17 +3,15 @@ <%# Specimen section of create_observation form, for collection_number and herbarium_record. Fields hidden unless box checked. %> -<%= tag.div(id: "observation_specimen_section", - data: { controller: "specimen", - user_pref: (!@user.try(&:hide_specimen_stuff?)) }) do %> +<%= tag.div(id: "observation_specimen_section") do %> <%= tag.div(class: "mt-3") do %> <%= check_box_with_label( form: f, field: :specimen, label: :form_observations_specimen_available.t, help: :form_observations_specimen_available_help.t, - data: { specimen_target: "checkbox", - action: "change->specimen#hideShowFields" } + data: { toggle: "collapse", target: "#specimen_fields" }, + aria: { controls: "specimen_fields", expanded: @observation.specimen } ) %> <% if action == :update %> @@ -26,11 +24,12 @@ herbarium_record. Fields hidden unless box checked. %> <% if action == :create %> - <%= tag.div(id: "specimen_fields", - class: ("hidden" if !@observation.specimen), - data: { specimen_target: "fields" }) do %> - <%= render(partial: "observations/form/collection_number") %> - <%= render(partial: "observations/form/herbarium_record") %> + <%= tag.div( + id: "specimen_fields", + class: class_names("collapse", ("in" if @observation.specimen)) + ) do %> + <%= render(partial: "observations/form/specimen/collection_number") %> + <%= render(partial: "observations/form/specimen/herbarium_record") %> <% end %> <% end %> diff --git a/app/views/controllers/observations/form/images/_camera_info.erb b/app/views/controllers/observations/form/images/_camera_info.erb index a2e108c974..1d5e322454 100644 --- a/app/views/controllers/observations/form/images/_camera_info.erb +++ b/app/views/controllers/observations/form/images/_camera_info.erb @@ -1,24 +1,27 @@ <%# locals: (img_id: "", lat: "", lng: "", alt: "", date: "", file_name: "", file_size: "") -%> +<% +# on new form, lat will not be present until form-exif reads it from the image +gps = tag.span(class: "exif_gps") do + [ + tag.strong("#{:LAT.l}: ") + tag.span(lat, class: "exif_lat"), + tag.strong("#{:LNG.l}: ") + tag.span(lng, class: "exif_lng"), + tag.strong("#{:ALT.l}: ") + tag.span(alt, class: "exif_alt") + " m" + ].safe_join(", ") +end +no_gps = tag.span("#{:image_no_geolocation.l}", class: "exif_no_gps d-none") +%> + <%= -tag.div(class: "well well-sm position-relative", - id: "camera_info_#{img_id}") do +tag.div(class: "well well-sm position-relative", id: "camera_info_#{img_id}") do [ label_tag("camera_info_#{img_id}", :image_camera_info.l), tag.div(class: "form-group") do [ tag.div do - [ - tag.strong("#{:DATE.l}: "), # :form_images_camera_date.t - carousel_exif_to_image_date_button(date: date) - ].safe_join - end, - tag.div do - [ - tag.strong("#{:LAT.l}: ") + tag.span(lat, class: "exif_lat"), - tag.strong("#{:LNG.l}: ") + tag.span(lng, class: "exif_lng"), - tag.strong("#{:ALT.l}: ") + tag.span(alt, class: "exif_alt") + " m" - ].safe_join(", ") + [tag.strong("#{:DATE.l}: "), # :form_images_camera_date.t + carousel_exif_to_image_date_button(date: date)].safe_join end, + tag.div { [gps, no_gps].safe_join }, carousel_transfer_exif_button(has_exif: date.present? || lat.present?) ].safe_join end, diff --git a/app/views/controllers/observations/form/_collection_number.html.erb b/app/views/controllers/observations/form/specimen/_collection_number.html.erb similarity index 100% rename from app/views/controllers/observations/form/_collection_number.html.erb rename to app/views/controllers/observations/form/specimen/_collection_number.html.erb diff --git a/app/views/controllers/observations/form/_herbarium_record.html.erb b/app/views/controllers/observations/form/specimen/_herbarium_record.html.erb similarity index 100% rename from app/views/controllers/observations/form/_herbarium_record.html.erb rename to app/views/controllers/observations/form/specimen/_herbarium_record.html.erb diff --git a/app/views/controllers/observations/namings/_fields.erb b/app/views/controllers/observations/namings/_fields.erb index 3c1ac6ee3c..bc1b156e10 100644 --- a/app/views/controllers/observations/namings/_fields.erb +++ b/app/views/controllers/observations/namings/_fields.erb @@ -1,18 +1,17 @@ +<%# locals: (create:, button_name:, show_reasons: false, unfocused: false, name_help: :form_naming_name_help.t, context: "blank" ) -%> + <% # This is included by obs form, naming new/edit form + lightbox identifier - -unfocused ||= false -focus_on_name = !unfocused && (button_name != :CREATE.l || @given_name.empty?) -focus_on_vote = !unfocused && (button_name == :CREATE.l && @given_name.present?) +focus_on_name = !unfocused && (!create || @given_name.empty?) +focus_on_vote = !unfocused && (create && @given_name.present?) feedback_locals = { - f: f, button_name: button_name, given_name: @given_name, + names: @names, valid_names: @valid_names, suggest_corrections: @suggest_corrections, - parent_deprecated: @parent_deprecated, - names: @names + parent_deprecated: @parent_deprecated } menu = unless @vote&.value&.nonzero? Vote.opinion_menu @@ -20,23 +19,19 @@ menu = unless @vote&.value&.nonzero? Vote.confidence_menu end confidences = options_for_select(menu, @vote&.value) -select_opts = { include_blank: ["new", "create"].include?(action_name) } -context ||= "blank" -name_help ||= :form_naming_name_help.t +select_opts = { include_blank: create } %> -<%= -[ - tag.div do - render(partial: "shared/form_name_feedback", - locals: feedback_locals) if @given_name.present? - end, - fields_for(:naming) do |f_n| +<% if @given_name.present? %> + <%= tag.div do + render(partial: "shared/form_name_feedback", locals: feedback_locals) + end %> +<% end %> + +<%= fields_for(:naming) do |f_n| %> + <% vote_reasons = tag.div(data: { autocompleter_target: "collapseFields" }, + class: ("collapse" if context == "blank")) do [ - autocompleter_field( - form: f_n, field: :name, type: :name, label: "#{:WHAT.t}:", - value: @given_name, autofocus: focus_on_name, help: name_help - ), f_n.fields_for(:vote) do |f_v| select_with_label(form: f_v, field: :value, options: confidences, select_opts: select_opts, @@ -47,7 +42,12 @@ name_help ||= :form_naming_name_help.t naming_form_reasons_fields(f_r, @reasons) end ].safe_join - end, - hidden_field_tag(:context, context) -].safe_join -%> + end %> + <%= autocompleter_field( + form: f_n, field: :name, type: :name, label: "#{:WHAT.t}:", + value: @given_name, autofocus: focus_on_name, help: name_help, + append: vote_reasons + ) %> +<% end %> + +<%= hidden_field_tag(:context, context) %> diff --git a/app/views/controllers/observations/namings/_form.erb b/app/views/controllers/observations/namings/_form.erb index 05a89d8eb0..2cd54b4afb 100644 --- a/app/views/controllers/observations/namings/_form.erb +++ b/app/views/controllers/observations/namings/_form.erb @@ -1,9 +1,12 @@ +<%# locals: (local:, show_reasons: true, form_locals: {}) -%> + <% # Fields must be separate because they're included in the obs form too. # HTML ID's may seem overly precise, but there may be more than one of # these forms open on a page if modal. IDs must be unique. case action_name when "new", "create" + create = true button_name = :CREATE.l method = :post id = "obs_#{@observation.id}_naming_form" @@ -11,6 +14,7 @@ when "new", "create" approved_name: @given_name, q: get_query_param) when "edit", "update" + create = false button_name = :SAVE_EDITS.l method = :patch id = "obs_#{@observation.id}_naming_#{@naming.id}_form" @@ -20,23 +24,23 @@ when "edit", "update" q: get_query_param) end +# `local` true means do not send via Turbo. form_args = { model: @naming, url: url, method: method, id: id } -if local_assigns[:local] == true +if local form_args = form_args.merge({ local: true }) else form_args = form_args.deep_merge({ data: { turbo: true } }) end -# Note: the form needs local_assigns[:form_locals]. -# I can't find where show_reasons is ever false - AN 20230801 -form_locals = local_assigns[:form_locals] || {} +# `naming_locals`: modal forms can accept a `form_locals` local. The controller +# may send `context` (i.e. where the form appears), which defaults to "blank". +# `show_reasons` is false on the obs form, true on the naming form. +naming_locals = { create:, button_name:, show_reasons: }.merge(form_locals) %> <%= form_with(**form_args) do |f| %> + <%= render(partial: "observations/namings/fields", locals: naming_locals) %> <%= submit_button(form: f, button: button_name, center: true) %> - <%= render(partial: "observations/namings/fields", - locals: { f: f, button_name: button_name }.merge(form_locals)) %> - <% end # form %> diff --git a/app/views/controllers/observations/namings/edit.html.erb b/app/views/controllers/observations/namings/edit.html.erb index 715ab3e8c9..e8a752b14c 100644 --- a/app/views/controllers/observations/namings/edit.html.erb +++ b/app/views/controllers/observations/namings/edit.html.erb @@ -13,8 +13,7 @@ add_tab_set(naming_form_edit_tabs(obs: @observation))
<%= render(partial: "observations/namings/form", - locals: { action: :update, show_reasons: true, - local: true }) %> + locals: { show_reasons: true, local: true }) %>
diff --git a/app/views/controllers/observations/namings/new.html.erb b/app/views/controllers/observations/namings/new.html.erb index c4ff406d8d..161f4aa7cf 100644 --- a/app/views/controllers/observations/namings/new.html.erb +++ b/app/views/controllers/observations/namings/new.html.erb @@ -13,8 +13,7 @@ add_tab_set(naming_form_new_tabs(obs: @observation))
<%= render(partial: "observations/namings/form", - locals: { action: :create, show_reasons: true, - local: true }) %> + locals: { show_reasons: true, local: true }) %>
diff --git a/app/views/controllers/shared/_form_location_map.erb b/app/views/controllers/shared/_form_location_map.erb index 0fb5a0a0e4..1831402983 100644 --- a/app/views/controllers/shared/_form_location_map.erb +++ b/app/views/controllers/shared/_form_location_map.erb @@ -22,7 +22,8 @@ on an ancestor element that also contains the inputs tag.span(:form_observations_hide_map.l, class: "map-hide mx-2") ].safe_join, name: "map_toggle", class: "map-toggle", - data: { map_target: "toggleMapBtn", action: "map#toggleMap", + data: { map_target: "toggleMapBtn", + action: "map#toggleMap form-exif#showFields", toggle: "collapse", target: "##{id}" }, aria: { expanded: "false", controls: id } ) %> diff --git a/app/views/controllers/shared/_form_name_feedback.erb b/app/views/controllers/shared/_form_name_feedback.erb index 5ae008500f..be83f5e852 100644 --- a/app/views/controllers/shared/_form_name_feedback.erb +++ b/app/views/controllers/shared/_form_name_feedback.erb @@ -1,6 +1,8 @@ +<%# locals: (given_name:, button_name:, names:, valid_names:, suggest_corrections:, parent_deprecated:) -%> + <%# -Handling deprecated, new & multiple Names -Used by Name and Naming create and edit pages +Feedback if the user entered deprecated, new or multiple Names +Used by Observation, Name and Naming create and edit pages Does two things: Describes the issue - Deprecated, Parent Deprecated, or Not Recognized Adds Help how to proceed - depends on issue and the button @@ -12,18 +14,11 @@ names - Name(s) corresponding to given_name valid_names - Name(s) that are valid synonyms suggest_corrections - t/f whether to suggest correction(s) parent_deprecated - t/f - -TODO: -Differentiate warning (valid_names) from error (!valid_names) -A conditional to watch is `if @params[:given_name].present?`. -Also, views/observations/namings/fields is doing too much work, -the multiple local_assigns for this partial should be set upstream. %> <%= +##### Warnings ##### if valid_names - ##### Warnings ##### - tag.div(class: "alert alert-warning", id: "name_messages") do concat(tag.div do if suggest_corrections || names.blank? diff --git a/app/views/controllers/shared/_notes_fields.html.erb b/app/views/controllers/shared/_notes_fields.html.erb index baeeb2d1df..88592fef63 100644 --- a/app/views/controllers/shared/_notes_fields.html.erb +++ b/app/views/controllers/shared/_notes_fields.html.erb @@ -1,6 +1,7 @@ -<%# Notes section of any form %> +<%# locals: (form:, fields:) -%> <% +# Notes section of any form # Users may have custom notes "parts". This prints a single large textarea and # textile help block if there's only one notes part. Otherwise, it prints # smaller textareas and a general textile help link. diff --git a/config/locales/en.txt b/config/locales/en.txt index b0cdd0b90a..fc7438f47c 100644 --- a/config/locales/en.txt +++ b/config/locales/en.txt @@ -1741,6 +1741,7 @@ image_exif_copied: Info copied image_use_exif: Use this info image_camera_info: Camera info + image_no_geolocation: No geolocation found image_file_name: File name image_file_size: File size