From cd40a68f2a6441d384bae31f7bd25919aeef10d5 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Fri, 26 Jul 2024 10:25:14 -0700 Subject: [PATCH 01/89] Initial form refactor --- app/views/controllers/herbaria/_form.html.erb | 80 ++++++++++--------- app/views/controllers/herbaria/edit.html.erb | 2 +- app/views/controllers/herbaria/new.html.erb | 2 +- 3 files changed, 43 insertions(+), 41 deletions(-) diff --git a/app/views/controllers/herbaria/_form.html.erb b/app/views/controllers/herbaria/_form.html.erb index da589eb12e..1bf0fef27a 100644 --- a/app/views/controllers/herbaria/_form.html.erb +++ b/app/views/controllers/herbaria/_form.html.erb @@ -1,70 +1,72 @@ +<%# locals: (action:) -%> +<% +create = (action == :create) +button_name = create ? :CREATE.l : :SAVE.l +help = ac_help = nil +if @herbarium.personal_user_id == @user.id + help = :edit_herbarium_this_is_personal_herbarium.tp +end +if in_admin_mode? && !create + top_users = herbarium_top_users(@herbarium.id) + if top_users.empty? + admin_help = :edit_herbarium_no_herbarium_records.l + else + admin_help = capture do + top_users.each do |name, login, count| + concat(tag.div(:edit_herbarium_user_records.t( + name: "#{name} (#{login})", num: count + ))) + end + end + end +end +%> + <%= form_with(model: @herbarium, id: "herbarium_form") do |f| %> - <%= submit_button(form: f, button: button_name.t, center: true) %> + <%= submit_button(form: f, button: button_name, center: true) %> <%= f.hidden_field :back, value: @back %> <%= f.hidden_field :q, value: get_query_param %> <%= text_field_with_label(form: f, field: :name, label: :NAME.t + ":", - between: :required) %> + between: :required, help:) %> <% if in_admin_mode? %> <%= autocompleter_field(form: f, field: :personal_user_name, type: :user, label: :edit_herbarium_admin_make_personal.t, - inline: true) %> - - <% if button_name != :CREATE %> - <%= help_block_with_arrow("up") do %> - <% top_users = herbarium_top_users(@herbarium.id) - top_users.each do |name, login, count| %> - <%= :edit_herbarium_user_records.t( - name: "#{name} (#{login})", num: count - ) %>
- <% end %> - <%= :edit_herbarium_no_herbarium_records.t if top_users.empty? %> - <% end %> - <% end %> - - <% else %> - <% if @herbarium.personal_user_id == @user.id %> - <%= content_tag(:div, class: "form-group") do - help_block(:div, :edit_herbarium_this_is_personal_herbarium.tp) - end %> - <% end %> - - <% if button_name == :CREATE || @herbarium.can_make_personal?(@user) %> - <%= check_box_with_label(form: f, field: :personal, - label: :create_herbarium_personal.t) %> - <%= help_block_with_arrow("up") do %> - <%= :create_herbarium_personal_help.t( - name: @user.personal_herbarium_name - ) %> - <% end %> - <% end %> + help: admin_help, inline: true) %> + <% elsif action == :create || @herbarium.can_make_personal?(@user) %> + <%= check_box_with_label( + form: f, field: :personal, label: :create_herbarium_personal.l, + help: :create_herbarium_personal_help.t( + name: @user.personal_herbarium_name + ) + ) %> <% end %> <% if !@herbarium.personal_user_id %> <%= text_field_with_label(form: f, field: :code, size: 8, inline: true, - label: :create_herbarium_code.t + ":", + label: :create_herbarium_code.l + ":", + help: :create_herbarium_code_help.t, between: :optional) %> - <%= help_block_with_arrow("up") do :create_herbarium_code_help.t end %> <% end %> <%= autocompleter_field(form: f, field: :place_name, type: :location, - label: :LOCATION.t + ":", between: :optional) %> + label: :LOCATION.l + ":", between: :optional) %> <%= text_field_with_label(form: f, field: :email, - label: :create_herbarium_email.t + ":", + label: :create_herbarium_email.l + ":", between: :optional) %> <%= text_area_with_label(form: f, field: :mailing_address, rows: 5, - label: :create_herbarium_mailing_address.t + ":", + label: :create_herbarium_mailing_address.l + ":", between: :optional) %> <%= text_area_with_label(form: f, field: :description, rows: 10, - label: :NOTES.t + ":", + label: :NOTES.l + ":", between: :optional) %> - <%= submit_button(form: f, button: button_name.t, center: true) %> + <%= submit_button(form: f, button: button_name, center: true) %> <% end %> diff --git a/app/views/controllers/herbaria/edit.html.erb b/app/views/controllers/herbaria/edit.html.erb index 48c39fa337..f3bad93861 100644 --- a/app/views/controllers/herbaria/edit.html.erb +++ b/app/views/controllers/herbaria/edit.html.erb @@ -4,4 +4,4 @@ add_page_title(:edit_herbarium_title.l) add_tab_set(herbarium_form_edit_tabs(herbarium: @herbarium)) %> -<%= render(partial: "herbaria/form", locals: { button_name: :SAVE }) %> +<%= render(partial: "herbaria/form", locals: { action: :update }) %> diff --git a/app/views/controllers/herbaria/new.html.erb b/app/views/controllers/herbaria/new.html.erb index 81714fe2b5..f90082aaa8 100644 --- a/app/views/controllers/herbaria/new.html.erb +++ b/app/views/controllers/herbaria/new.html.erb @@ -5,4 +5,4 @@ add_page_title(:create_herbarium_title.l) add_tab_set(herbarium_form_new_tabs) %> -<%= render(partial: "herbaria/form", locals: { button_name: :CREATE }) %> +<%= render(partial: "herbaria/form", locals: { action: :create }) %> From 48d7ccb1215348e9443ef3bdaa3712e28bf4e04f Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 27 Jul 2024 00:32:21 -0700 Subject: [PATCH 02/89] Fix modal_identifier h_r --- app/controllers/herbarium_records_controller.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/controllers/herbarium_records_controller.rb b/app/controllers/herbarium_records_controller.rb index 071778a4e8..b837a705bf 100644 --- a/app/controllers/herbarium_records_controller.rb +++ b/app/controllers/herbarium_records_controller.rb @@ -453,8 +453,7 @@ def render_herbarium_records_section_update def reload_herbarium_record_modal_form_and_flash render( partial: "shared/modal_form_reload", - locals: { identifier: "herbarium_record", - form: "herbarium_records/form" } + locals: { identifier: modal_identifier, form: "herbarium_records/form" } ) and return true end end From 943ccd93f238aa41cf9749894d9fdcdeb484ec09 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 27 Jul 2024 00:33:01 -0700 Subject: [PATCH 03/89] Add turbo modal handlers for new/edit --- app/controllers/herbaria_controller.rb | 40 ++++++++++++++++ .../herbaria/{_form.html.erb => _form.erb} | 48 ++++++++++++------- 2 files changed, 71 insertions(+), 17 deletions(-) rename app/views/controllers/herbaria/{_form.html.erb => _form.erb} (56%) diff --git a/app/controllers/herbaria_controller.rb b/app/controllers/herbaria_controller.rb index 912470f780..2a845e9748 100644 --- a/app/controllers/herbaria_controller.rb +++ b/app/controllers/herbaria_controller.rb @@ -99,6 +99,10 @@ def show def new @herbarium = Herbarium.new + respond_to do |format| + format.turbo_stream { render_modal_herbarium_form } + format.html + end end def edit @@ -109,6 +113,34 @@ def edit @herbarium.place_name = @herbarium.location.try(&:name) @herbarium.personal = @herbarium.personal_user_id.present? @herbarium.personal_user_name = @herbarium.personal_user.try(&:login) + respond_to do |format| + format.turbo_stream { render_modal_herbarium_form } + format.html + end + end + + def render_modal_herbarium_record_form + render(partial: "shared/modal_form", + locals: { title: modal_title, identifier: modal_identifier, + form: "herbaria/form" }) and return + end + + def modal_identifier + case action_name + when "new", "create" + "herbarium" + when "edit", "update" + "herbarium_#{@herbarium.id}" + end + end + + def modal_title + case action_name + when "new", "create" + :create_herbarium_title.l + when "edit", "update" + :edit_herbarium_title.l + end end # ---------- Actions to Modify data: (create, update, destroy, etc.) --------- @@ -339,6 +371,14 @@ def redirect_to_create_location true end + # this updates both the form and the flash + def reload_herbarium_modal_form_and_flash + render( + partial: "shared/modal_form_reload", + locals: { identifier: modal_identifier, form: "herbaria/form" } + ) and return true + end + def herbarium_params return {} unless params[:herbarium] diff --git a/app/views/controllers/herbaria/_form.html.erb b/app/views/controllers/herbaria/_form.erb similarity index 56% rename from app/views/controllers/herbaria/_form.html.erb rename to app/views/controllers/herbaria/_form.erb index 1bf0fef27a..46a1ff9200 100644 --- a/app/views/controllers/herbaria/_form.html.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -45,27 +45,41 @@ end ) %> <% end %> - <% if !@herbarium.personal_user_id %> - <%= text_field_with_label(form: f, field: :code, size: 8, inline: true, - label: :create_herbarium_code.l + ":", - help: :create_herbarium_code_help.t, - between: :optional) %> - <% end %> + <%= js_button( + button: :more_options.l, id: "more_options_button", + name: "more_options_button", + data: { toggle: "collapse", target: "#herbarium_options" }, + aria: { expanded: "false", controls: "herbarium_options" } + ) %> - <%= autocompleter_field(form: f, field: :place_name, type: :location, - label: :LOCATION.l + ":", between: :optional) %> + <%= tag.div( + id: "herbarium_options", + class: "collapse", + aria: { expanded: "false", controlled_by: "more_options_button" } + ) do %> - <%= text_field_with_label(form: f, field: :email, - label: :create_herbarium_email.l + ":", - between: :optional) %> + <% if !@herbarium.personal_user_id %> + <%= text_field_with_label(form: f, field: :code, size: 8, inline: true, + label: :create_herbarium_code.l + ":", + help: :create_herbarium_code_help.t, + between: :optional) %> + <% end %> - <%= text_area_with_label(form: f, field: :mailing_address, rows: 5, - label: :create_herbarium_mailing_address.l + ":", - between: :optional) %> + <%= autocompleter_field(form: f, field: :place_name, type: :location, + label: :LOCATION.l + ":", between: :optional) %> + + <%= text_field_with_label(form: f, field: :email, + label: :create_herbarium_email.l + ":", + between: :optional) %> - <%= text_area_with_label(form: f, field: :description, rows: 10, - label: :NOTES.l + ":", - between: :optional) %> + <%= text_area_with_label(form: f, field: :mailing_address, rows: 5, + label: :create_herbarium_mailing_address.l + ":", + between: :optional) %> + + <%= text_area_with_label(form: f, field: :description, rows: 10, + label: :NOTES.l + ":", + between: :optional) %> + <% end %> <%= submit_button(form: f, button: button_name, center: true) %> From 11d73e61fdeda7d5ef06fe4ee6690a217ae99c78 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 27 Jul 2024 17:56:11 -0700 Subject: [PATCH 04/89] Attempt to use map controller in form --- app/views/controllers/herbaria/_form.erb | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 46a1ff9200..cc6ead4c75 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -54,7 +54,8 @@ end <%= tag.div( id: "herbarium_options", - class: "collapse", + class: "collapse map-outlet", + data: { controller: "map" }, aria: { expanded: "false", controlled_by: "more_options_button" } ) do %> @@ -65,8 +66,17 @@ end between: :optional) %> <% end %> - <%= autocompleter_field(form: f, field: :place_name, type: :location, - label: :LOCATION.l + ":", between: :optional) %> + <%= autocompleter_field( + form: f, field: :place_name, type: :location, + label: :LOCATION.l + ":", between: :optional, + hidden_data: { map_target: "locationId", + north: location&.north, south: location&.south, + east: location&.east, west: location&.west }, + create_text: :form_observations_create_locality.l, + data: { + map_target: "placeInput", + action: "map:googlePrimer@window->autocompleter#refreshGooglePrimer" } + ) %> <%= text_field_with_label(form: f, field: :email, label: :create_herbarium_email.l + ":", From 2dba63fe431cc792c3dd74dab8641ccab61a0cf8 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 28 Jul 2024 11:12:32 -0700 Subject: [PATCH 05/89] Update _form.erb --- app/views/controllers/herbaria/_form.erb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index cc6ead4c75..6acd1f3081 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -69,9 +69,7 @@ end <%= autocompleter_field( form: f, field: :place_name, type: :location, label: :LOCATION.l + ":", between: :optional, - hidden_data: { map_target: "locationId", - north: location&.north, south: location&.south, - east: location&.east, west: location&.west }, + hidden_data: { map_target: "locationId" }, create_text: :form_observations_create_locality.l, data: { map_target: "placeInput", From b683974ed7d6b155381b945a529c4525429a90de Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 30 Jul 2024 16:06:30 -0700 Subject: [PATCH 06/89] Update _form.erb --- app/views/controllers/herbaria/_form.erb | 72 +++++++++++------------- 1 file changed, 32 insertions(+), 40 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 6acd1f3081..12fe40bebf 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -22,7 +22,10 @@ if in_admin_mode? && !create end %> -<%= form_with(model: @herbarium, id: "herbarium_form") do |f| %> +<%= form_with( + model: @herbarium, id: "herbarium_form", + data: { controller: "geocode" } +) do |f| %> <%= submit_button(form: f, button: button_name, center: true) %> @@ -33,61 +36,50 @@ end between: :required, help:) %> <% if in_admin_mode? %> + <%= autocompleter_field(form: f, field: :personal_user_name, type: :user, label: :edit_herbarium_admin_make_personal.t, help: admin_help, inline: true) %> + <% elsif action == :create || @herbarium.can_make_personal?(@user) %> + <%= check_box_with_label( form: f, field: :personal, label: :create_herbarium_personal.l, help: :create_herbarium_personal_help.t( name: @user.personal_herbarium_name ) ) %> - <% end %> - <%= js_button( - button: :more_options.l, id: "more_options_button", - name: "more_options_button", - data: { toggle: "collapse", target: "#herbarium_options" }, - aria: { expanded: "false", controls: "herbarium_options" } - ) %> - - <%= tag.div( - id: "herbarium_options", - class: "collapse map-outlet", - data: { controller: "map" }, - aria: { expanded: "false", controlled_by: "more_options_button" } - ) do %> - - <% if !@herbarium.personal_user_id %> - <%= text_field_with_label(form: f, field: :code, size: 8, inline: true, - label: :create_herbarium_code.l + ":", - help: :create_herbarium_code_help.t, - between: :optional) %> - <% end %> - - <%= autocompleter_field( - form: f, field: :place_name, type: :location, - label: :LOCATION.l + ":", between: :optional, - hidden_data: { map_target: "locationId" }, - create_text: :form_observations_create_locality.l, - data: { - map_target: "placeInput", - action: "map:googlePrimer@window->autocompleter#refreshGooglePrimer" } - ) %> + <% end %> - <%= text_field_with_label(form: f, field: :email, - label: :create_herbarium_email.l + ":", + <% if !@herbarium.personal_user_id %> + <%= text_field_with_label(form: f, field: :code, size: 8, inline: true, + label: :create_herbarium_code.l + ":", + help: :create_herbarium_code_help.t, between: :optional) %> + <% end %> - <%= text_area_with_label(form: f, field: :mailing_address, rows: 5, - label: :create_herbarium_mailing_address.l + ":", - between: :optional) %> + <%= autocompleter_field( + form: f, field: :place_name, type: :location, + label: :LOCATION.l + ":", between: :optional, + hidden_data: { map_target: "locationId" }, + create_text: :form_observations_create_locality.l, + data: { + map_target: "placeInput", + action: "map:googlePrimer@window->autocompleter#refreshGooglePrimer" } + ) %> - <%= text_area_with_label(form: f, field: :description, rows: 10, - label: :NOTES.l + ":", + <%= text_field_with_label(form: f, field: :email, + label: :create_herbarium_email.l + ":", between: :optional) %> - <% end %> + + <%= text_area_with_label(form: f, field: :mailing_address, rows: 5, + label: :create_herbarium_mailing_address.l + ":", + between: :optional) %> + + <%= text_area_with_label(form: f, field: :description, rows: 10, + label: :NOTES.l + ":", + between: :optional) %> <%= submit_button(form: f, button: button_name, center: true) %> From 9e306153ad613af24469a2f84dd88ec1947d8361 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 30 Jul 2024 16:07:05 -0700 Subject: [PATCH 07/89] Update _form.erb --- app/views/controllers/herbaria/_form.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 12fe40bebf..bab2e580c2 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -66,7 +66,7 @@ end create_text: :form_observations_create_locality.l, data: { map_target: "placeInput", - action: "map:googlePrimer@window->autocompleter#refreshGooglePrimer" } + action: "geocode:googlePrimer@window->autocompleter#refreshGooglePrimer" } ) %> <%= text_field_with_label(form: f, field: :email, From 5ac2376207727e8d2086739386a1743427b20501 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 30 Jul 2024 17:54:40 -0700 Subject: [PATCH 08/89] restore .map-outlet --- app/views/controllers/herbaria/_form.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index bab2e580c2..1ad246d38e 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -23,7 +23,7 @@ end %> <%= form_with( - model: @herbarium, id: "herbarium_form", + model: @herbarium, id: "herbarium_form", class: "map-outlet", data: { controller: "geocode" } ) do |f| %> From be1a4e9cfaee7f48d11295e635f3149d00db9353 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 30 Jul 2024 17:54:57 -0700 Subject: [PATCH 09/89] field_options between_end --- app/helpers/forms_helper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index 28646c36eb..b820e8d926 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -649,9 +649,9 @@ def check_for_help_block(args) # be excluded separately (not here) def separate_field_options_from_args(args, extras = []) exceptions = [ - :form, :field, :label, :class, :width, :inline, :between, :append, - :help, :addon, :optional, :required, :monospace, :type, :wrap_data, - :button, :button_data + :form, :field, :label, :class, :width, :inline, :between, :between_end, + :append, :help, :addon, :optional, :required, :monospace, :type, + :wrap_data, :button, :button_data ] + extras args.clone.except(*exceptions) From c66eb062c4f0073c09dc08ae51e7d7faade70d21 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 30 Jul 2024 21:13:43 -0700 Subject: [PATCH 10/89] Update observation_form_system_test.rb --- test/system/observation_form_system_test.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/system/observation_form_system_test.rb b/test/system/observation_form_system_test.rb index 53b73b330a..65c08d2bb6 100644 --- a/test/system/observation_form_system_test.rb +++ b/test/system/observation_form_system_test.rb @@ -129,10 +129,10 @@ def test_autofill_location_from_geotagged_image_nothing_matches # check new observation form defaults assert_date_is_now assert_geolocation_is_empty - last_obs = Observation.where(user_id: User.current.id). - order(:created_at).last + last_obs = Observation.recent_by_user(User.current).last assert_selector("#observation_place_name", wait: 6) assert_selector("#observation_location_id", visible: :all) + sleep(0.5) assert_field("observation_place_name", with: last_obs.where) assert_field("observation_location_id", with: last_obs.location_id, type: :hidden) @@ -176,8 +176,7 @@ def test_autofill_location_from_geotagged_image_matching_location # check new observation form defaults assert_date_is_now assert_geolocation_is_empty - last_obs = Observation.where(user_id: User.current.id). - order(:created_at).last + last_obs = Observation.recent_by_user(User.current).last # This is currently "Falmouth, Massachusetts, USA" assert_field("observation_place_name", with: last_obs.where) assert_field("observation_location_id", with: last_obs.location_id, From af6d20db4473e32ebc0c2271322c106fa47f19be Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 30 Jul 2024 21:29:45 -0700 Subject: [PATCH 11/89] geocode_targets --- app/views/controllers/herbaria/_form.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 1ad246d38e..18226a79af 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -62,10 +62,10 @@ end <%= autocompleter_field( form: f, field: :place_name, type: :location, label: :LOCATION.l + ":", between: :optional, - hidden_data: { map_target: "locationId" }, + hidden_data: { geocode_target: "locationId" }, create_text: :form_observations_create_locality.l, data: { - map_target: "placeInput", + geocode_target: "placeInput", action: "geocode:googlePrimer@window->autocompleter#refreshGooglePrimer" } ) %> From 436d494ad02af6b37675f213115ccd97d86c7a82 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 31 Jul 2024 15:44:18 -0700 Subject: [PATCH 12/89] hidden fields partial --- .../controllers/locations/form/_bounds_hidden_fields.erb | 8 ++++++++ app/views/controllers/observations/form/_details.html.erb | 8 ++------ 2 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 app/views/controllers/locations/form/_bounds_hidden_fields.erb diff --git a/app/views/controllers/locations/form/_bounds_hidden_fields.erb b/app/views/controllers/locations/form/_bounds_hidden_fields.erb new file mode 100644 index 0000000000..a29a49b2d2 --- /dev/null +++ b/app/views/controllers/locations/form/_bounds_hidden_fields.erb @@ -0,0 +1,8 @@ +<%# locals: (location: nil, target_type: :geocode_target) -%> + +<%= fields_for(:location) do |f_l| %> + <% %w[north south east west low high].each do |key| %> + <%= f_l.hidden_field(:"#{key}", value: location&.send(key) || nil, + data: { target_type.to_sym => "#{key}Input" }) %> + <% end %> +<% end %> diff --git a/app/views/controllers/observations/form/_details.html.erb b/app/views/controllers/observations/form/_details.html.erb index c58c4b5b70..564cf32b76 100644 --- a/app/views/controllers/observations/form/_details.html.erb +++ b/app/views/controllers/observations/form/_details.html.erb @@ -86,12 +86,8 @@ t_s = { } ) %> - <%= fields_for(:location) do |f_l| %> - <% %w[north south east west low high].each do |key| %> - <%= f_l.hidden_field(:"#{key}", value: @location&.send(key) || nil, - data: { map_target: "#{key}Input" }) %> - <% end %> - <% end %> + <%= render(partial: "locations/form/bounds_hidden_fields", + locals: { location: @location, target_type: :map_target }) %> From 5d2897e2af14c906bb3510829b7524326fecac4d Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 31 Jul 2024 18:18:29 -0700 Subject: [PATCH 13/89] bounds_fields partial --- app/views/controllers/herbaria/_form.erb | 11 +++++++++-- ...th_east_west_alt_fields.erb => _bounds_fields.erb} | 0 .../locations/form/_bounds_hidden_fields.erb | 6 ++++-- app/views/controllers/locations/form/_fields.erb | 2 +- .../controllers/observations/form/_details.html.erb | 2 +- 5 files changed, 15 insertions(+), 6 deletions(-) rename app/views/controllers/locations/form/{_north_south_east_west_alt_fields.erb => _bounds_fields.erb} (100%) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 18226a79af..f4dac9c0bd 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -61,14 +61,21 @@ end <%= autocompleter_field( form: f, field: :place_name, type: :location, - label: :LOCATION.l + ":", between: :optional, + label: [tag.span("#{:LOCATION.l}:", class: "unconstrained-label"), + tag.span("#{:form_observations_create_locality.l}:", + class: "create-label")].safe_join(" "), + between: :optional, hidden_data: { geocode_target: "locationId" }, create_text: :form_observations_create_locality.l, data: { geocode_target: "placeInput", - action: "geocode:googlePrimer@window->autocompleter#refreshGooglePrimer" } + action: "geocode:googlePrimer@window->autocompleter#refreshGooglePrimer" + } ) %> + <%= render(partial: "locations/form/bounds_hidden_fields", + locals: { location: @location, target_type: :geocode }) %> + <%= text_field_with_label(form: f, field: :email, label: :create_herbarium_email.l + ":", between: :optional) %> diff --git a/app/views/controllers/locations/form/_north_south_east_west_alt_fields.erb b/app/views/controllers/locations/form/_bounds_fields.erb similarity index 100% rename from app/views/controllers/locations/form/_north_south_east_west_alt_fields.erb rename to app/views/controllers/locations/form/_bounds_fields.erb diff --git a/app/views/controllers/locations/form/_bounds_hidden_fields.erb b/app/views/controllers/locations/form/_bounds_hidden_fields.erb index a29a49b2d2..79a26adf3e 100644 --- a/app/views/controllers/locations/form/_bounds_hidden_fields.erb +++ b/app/views/controllers/locations/form/_bounds_hidden_fields.erb @@ -2,7 +2,9 @@ <%= fields_for(:location) do |f_l| %> <% %w[north south east west low high].each do |key| %> - <%= f_l.hidden_field(:"#{key}", value: location&.send(key) || nil, - data: { target_type.to_sym => "#{key}Input" }) %> + <%= f_l.hidden_field( + :"#{key}", value: location&.send(key) || nil, + data: { "#{target_type}_target".to_sym => "#{key}Input" } + ) %> <% end %> <% end %> diff --git a/app/views/controllers/locations/form/_fields.erb b/app/views/controllers/locations/form/_fields.erb index fb0901a06a..ad535a11e0 100644 --- a/app/views/controllers/locations/form/_fields.erb +++ b/app/views/controllers/locations/form/_fields.erb @@ -8,7 +8,7 @@ button_data: { map_target: "showBoxBtn", action: "map#showBox" } ) %> -<%= render(partial: "locations/form/north_south_east_west_alt_fields", +<%= render(partial: "locations/form/bounds_fields", locals: { f: f }) %> <% if in_admin_mode? %> diff --git a/app/views/controllers/observations/form/_details.html.erb b/app/views/controllers/observations/form/_details.html.erb index 564cf32b76..348ba95272 100644 --- a/app/views/controllers/observations/form/_details.html.erb +++ b/app/views/controllers/observations/form/_details.html.erb @@ -87,7 +87,7 @@ t_s = { ) %> <%= render(partial: "locations/form/bounds_hidden_fields", - locals: { location: @location, target_type: :map_target }) %> + locals: { location: @location, target_type: :map }) %> From 6179906fc99184b933432b84f7bc0664fa461cf3 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 31 Jul 2024 22:17:55 -0700 Subject: [PATCH 14/89] Be sure there is a hidden id before assigning .has-id --- app/javascript/controllers/autocompleter_controller.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index fdf36438d6..7c3cad6dd1 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -330,7 +330,7 @@ export default class extends Controller { const hiddenId = parseInt(this.hiddenTarget.value); - if (hiddenId !== NaN && hiddenId != 0) { + if (hiddenId && hiddenId !== NaN && hiddenId != 0) { this.wrapTarget.classList.add('has-id'); } else { this.wrapTarget.classList.remove('has-id'); @@ -578,7 +578,11 @@ export default class extends Controller { this.verbose("autocompleter:doing_google_refresh()"); this.old_value = this.inputTarget.value; // async, anything after this executes immediately - this.mapOutlet.geolocatePlaceName(true); + if (this.hasGeocodeOutlet) { + this.geocodeOutlet.geolocatePlaceName(true); + } else if (this.hasMapOutlet) { + this.mapOutlet.geolocatePlaceName(true); + } // still necessary if primer unchanged, as likely? // this.populateMatches(); // this.drawPulldown(); From e0e41cab311644e0186d9574bc73115a468c3d5c Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 31 Jul 2024 22:19:01 -0700 Subject: [PATCH 15/89] ac geocode_outlet arg --- app/helpers/forms_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index 3cbb0f35f2..649ad09998 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -218,6 +218,7 @@ def autocompleter_field(**args) ac_args[:wrap_data] = { controller: :autocompleter, type: args[:type], separator: args[:separator], autocompleter_map_outlet: args[:map_outlet], + autocompleter_geocode_outlet: args[:geocode_outlet], autocompleter_target: "wrap" } ac_args[:between] = capture do concat(args[:between]) From 5797ea43f2627d9c1aa3347605ceab7ddc0c6841 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 31 Jul 2024 22:19:20 -0700 Subject: [PATCH 16/89] herbaria form - geocode_outlet --- app/views/controllers/herbaria/_form.erb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index f4dac9c0bd..6f1db95a34 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -67,6 +67,7 @@ end between: :optional, hidden_data: { geocode_target: "locationId" }, create_text: :form_observations_create_locality.l, + geocode_outlet: ".geocode-outlet", data: { geocode_target: "placeInput", action: "geocode:googlePrimer@window->autocompleter#refreshGooglePrimer" From 939af867d97f000b57b3d9aed149f078792df191 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Thu, 1 Aug 2024 19:15:10 -0700 Subject: [PATCH 17/89] hardcode map-outlet, geocode-outlet --- app/helpers/forms_helper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index 649ad09998..5332133b8d 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -213,12 +213,12 @@ def autocompleter_field(**args) data: { autocompleter_target: "input" } }.deep_merge(args.except(:type, :separator, :textarea, :hidden, :hidden_data, :create_text, - :keep_text, :edit_text)) + :keep_text, :edit_text, :find_text)) ac_args[:class] = class_names("dropdown", args[:class]) ac_args[:wrap_data] = { controller: :autocompleter, type: args[:type], separator: args[:separator], - autocompleter_map_outlet: args[:map_outlet], - autocompleter_geocode_outlet: args[:geocode_outlet], + autocompleter_map_outlet: ".map-outlet", + autocompleter_geocode_outlet: ".geocode-outlet", autocompleter_target: "wrap" } ac_args[:between] = capture do concat(args[:between]) From 18a09726258676acf200283337344563fec97461 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Thu, 1 Aug 2024 19:15:37 -0700 Subject: [PATCH 18/89] herbaria form - Use geocode-outlet --- app/views/controllers/herbaria/_form.erb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 6f1db95a34..bbb11b6357 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -23,7 +23,7 @@ end %> <%= form_with( - model: @herbarium, id: "herbarium_form", class: "map-outlet", + model: @herbarium, id: "herbarium_form", class: "geocode-outlet", data: { controller: "geocode" } ) do |f| %> @@ -67,7 +67,6 @@ end between: :optional, hidden_data: { geocode_target: "locationId" }, create_text: :form_observations_create_locality.l, - geocode_outlet: ".geocode-outlet", data: { geocode_target: "placeInput", action: "geocode:googlePrimer@window->autocompleter#refreshGooglePrimer" From 428c3bb519372c9240c605c9d266beabc6dbda9e Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Thu, 1 Aug 2024 19:15:56 -0700 Subject: [PATCH 19/89] Update _details.html.erb Remove map_outlet arg --- app/views/controllers/observations/form/_details.html.erb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/controllers/observations/form/_details.html.erb b/app/views/controllers/observations/form/_details.html.erb index 348ba95272..7cceeec8f0 100644 --- a/app/views/controllers/observations/form/_details.html.erb +++ b/app/views/controllers/observations/form/_details.html.erb @@ -75,7 +75,6 @@ t_s = { keep_text: :form_observations_use_locality.l, edit_text: :form_observations_edit_locality.l, # find_text: :form_locations_find_on_map.l, - map_outlet: ".map-outlet", data: { map_target: "placeInput", action: [ From 1ccdc7efe91daef89df18882e48dd62c897aaf85 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Thu, 1 Aug 2024 19:16:21 -0700 Subject: [PATCH 20/89] Add debugging --- app/javascript/controllers/autocompleter_controller.js | 2 +- app/javascript/controllers/geocode_controller.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 7c3cad6dd1..4100195cde 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -1547,7 +1547,7 @@ export default class extends Controller { } verbose(str) { - // console.log(str); + console.log(str); // document.getElementById("log"). // insertAdjacentText("beforeend", str + "
"); } diff --git a/app/javascript/controllers/geocode_controller.js b/app/javascript/controllers/geocode_controller.js index a71ef60356..6dcfc24b43 100644 --- a/app/javascript/controllers/geocode_controller.js +++ b/app/javascript/controllers/geocode_controller.js @@ -291,6 +291,7 @@ export default class extends Controller { // Convert from human readable and do a rough check if they make sense validateLatLngInputs(update = false) { + this.verbose("geocode:validateLatLngInputs") if (!this.hasLatInputTarget || !this.hasLngInputTarget || !this.latInputTarget.value || !this.lngInputTarget.value) return false @@ -429,7 +430,7 @@ export default class extends Controller { } verbose(str) { - // console.log(str); + console.log(str); // document.getElementById("log"). // insertAdjacentText("beforeend", str + "
"); } From cd3cb2a5e43fb94e75df8315dd56a5f607273a37 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Thu, 1 Aug 2024 23:24:57 -0700 Subject: [PATCH 21/89] missing functions geocode --- app/javascript/controllers/geocode_controller.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/javascript/controllers/geocode_controller.js b/app/javascript/controllers/geocode_controller.js index 6dcfc24b43..34801a7a73 100644 --- a/app/javascript/controllers/geocode_controller.js +++ b/app/javascript/controllers/geocode_controller.js @@ -259,6 +259,14 @@ export default class extends Controller { ] } + // Computes the center of a Google Maps Rectangle's LatLngBoundsLiteral object + centerFromBounds(bounds) { + let lat = (bounds?.north + bounds?.south) / 2.0 + let lng = (bounds?.east + bounds?.west) / 2.0 + if (bounds?.west > bounds?.east) { lng += 180 } + return { lat: lat, lng: lng } + } + // takes a LatLngBoundsLiteral object {south:, west:, north:, east:} updateBoundsInputs(bounds) { if (!this.hasSouthInputTarget) return false @@ -369,6 +377,13 @@ export default class extends Controller { } } + clearAutocompleterSwapBuffer() { + if (this.autocomplete_buffer) { + clearTimeout(this.autocomplete_buffer) + this.autocomplete_buffer = 0 + } + } + // Sorts the LocationElevationResponse.results.elevation objects and // computes the high and low of these results using bounds and center highAndLowOf(results) { From 398bdc3344b0b68ef4f0e38d82f509ef633b9834 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Thu, 1 Aug 2024 23:27:25 -0700 Subject: [PATCH 22/89] Update map_controller.js --- app/javascript/controllers/map_controller.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index 282293ea13..52f490cd2d 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -362,13 +362,6 @@ export default class extends GeocodeController { } } - clearAutocompleterSwapBuffer() { - if (this.autocomplete_buffer) { - clearTimeout(this.autocomplete_buffer) - this.autocomplete_buffer = 0 - } - } - clearMarkerDrawBuffer() { if (this.marker_draw_buffer) { clearTimeout(this.marker_draw_buffer) @@ -608,14 +601,6 @@ export default class extends GeocodeController { return corners } - // Computes the center of a Google Maps Rectangle's LatLngBoundsLiteral object - centerFromBounds(bounds) { - let lat = (bounds?.north + bounds?.south) / 2.0 - let lng = (bounds?.east + bounds?.west) / 2.0 - if (bounds?.west > bounds?.east) { lng += 180 } - return { lat: lat, lng: lng } - } - // // COORDINATES - ELEVATION // From 71cfe0aa5f4e0b8ab4fc69198975c7c459c5bfe1 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 3 Aug 2024 00:10:28 -0700 Subject: [PATCH 23/89] Update autocompleter_controller.js Sort out .has-id, mapOutletConnected --- .../controllers/autocompleter_controller.js | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 4100195cde..dae7b4cd81 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -235,7 +235,7 @@ export default class extends Controller { this.prepareInputElement(); this.prepareHiddenInput(); if (!this.hasKeepBtnTarget || - !this.keepBtnTarget.classList.contains('active')) { + !this.keepBtnTarget?.classList?.contains('active')) { this.clearHiddenId(); } this.constrainedSelectionUI(); @@ -291,7 +291,7 @@ export default class extends Controller { } else { outlet.lockBoxBtnTarget.classList.remove("d-none"); } - this.createBtnTarget.classList.add('d-none'); + // this.createBtnTarget.classList.add('d-none'); // this.dispatchHiddenIdEvents(); } @@ -301,11 +301,11 @@ export default class extends Controller { if (outlet.rectangle) outlet.rectangle.setEditable(false); // Make the map show box button back into a create button - delete this.createBtnTarget.dataset.mapTarget; - const create_action = this.createBtnTarget.dataset.action - .replace("map#showBox:prevent", "autocompleter#swapCreate:prevent"); - this.createBtnTarget.dataset.action = create_action; - this.createBtnTarget.classList.remove('d-none'); + // delete this.createBtnTarget.dataset.mapTarget; + // const create_action = this.createBtnTarget.dataset.action + // .replace("map#showBox:prevent", "autocompleter#swapCreate:prevent"); + // this.createBtnTarget.dataset.action = create_action; + // this.createBtnTarget.classList.remove('d-none'); // this.dispatchHiddenIdEvents(); outlet.northInputTarget.value = ''; @@ -328,13 +328,8 @@ export default class extends Controller { // Attach events this.addEventListeners(); - const hiddenId = parseInt(this.hiddenTarget.value); - - if (hiddenId && hiddenId !== NaN && hiddenId != 0) { - this.wrapTarget.classList.add('has-id'); - } else { - this.wrapTarget.classList.remove('has-id'); - } + const hidden_id = parseInt(this.hiddenTarget.value); + this.hasIdOrNo(hidden_id); } // When swapping autocompleter types, swap the hidden input identifiers. @@ -974,9 +969,7 @@ export default class extends Controller { this.hiddenTarget.dataset[key] = match[key]; }); - if (match['id'] !== 0) { - this.wrapTarget.classList.add('has-id'); - } + this.hasIdOrNo(parseInt(match['id'])); this.dispatchHiddenIdEvents(); } @@ -996,6 +989,14 @@ export default class extends Controller { this.dispatchHiddenIdEvents(); } + hasIdOrNo(hidden_id) { + if (hidden_id && hidden_id !== NaN && hidden_id != 0) { + this.wrapTarget.classList.add('has-id'); + } else { + this.wrapTarget.classList.remove('has-id'); + } + } + storeCurrentHiddenData() { this.verbose("autocompleter:storeCurrentHiddenData()"); this.stored_id = parseInt(this.hiddenTarget.value); // value is a string @@ -1019,7 +1020,7 @@ export default class extends Controller { clearTimeout(this.data_timer); this.data_timer = setTimeout(() => { this.verbose("autocompleter: dispatching hiddenIdDataChanged"); - this.wrapTarget.classList.remove('has-id'); + this.hasIdOrNo(hidden_id); if (this.hasKeepBtnTarget) { this.keepBtnTarget.classList.remove('active'); } From d80e74a5973e64223384375f17c4b37595248004 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 3 Aug 2024 00:21:15 -0700 Subject: [PATCH 24/89] geocode bug fixed, but it's not setting id to -1 --- app/javascript/controllers/geocode_controller.js | 8 ++++---- app/views/controllers/herbaria/_form.erb | 6 +++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/javascript/controllers/geocode_controller.js b/app/javascript/controllers/geocode_controller.js index 34801a7a73..6f05fd4fcd 100644 --- a/app/javascript/controllers/geocode_controller.js +++ b/app/javascript/controllers/geocode_controller.js @@ -166,10 +166,10 @@ export default class extends Controller { const extents = results[0].geometry.bounds?.toJSON() // may not exist const center = results[0].geometry.location.toJSON() - if (viewport) - this.map.fitBounds(viewport) - if (this.map) - this.placeClosestRectangle(viewport, extents) + if (this.map) { + if (viewport) this.map.fitBounds(viewport) + this.placeClosestRectangle(viewport, extents) // viewport is optional + } this.updateFields(viewport, extents, center) // For non-autocompleted place input in the location form this.updatePlaceInputTarget(results[0]) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index bbb11b6357..6d2e3a997c 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -24,7 +24,11 @@ end <%= form_with( model: @herbarium, id: "herbarium_form", class: "geocode-outlet", - data: { controller: "geocode" } + data: { + controller: "geocode", + action: + "autocompleter:hiddenIdDataChanged@window->geocode#geolocatePlaceName" + } ) do |f| %> <%= submit_button(form: f, button: button_name, center: true) %> From 9c83dc899f25ec571735cd2fb32df89f131aff44 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 3 Aug 2024 14:26:50 -0700 Subject: [PATCH 25/89] Guard functions: tryToGeolocate and tryToGeocode (used in checkForBox) --- .../controllers/geocode_controller.js | 22 ++++++++++++++----- app/javascript/controllers/map_controller.js | 18 +++++++-------- app/views/controllers/herbaria/_form.erb | 3 +-- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/app/javascript/controllers/geocode_controller.js b/app/javascript/controllers/geocode_controller.js index 6f05fd4fcd..7ed95b687b 100644 --- a/app/javascript/controllers/geocode_controller.js +++ b/app/javascript/controllers/geocode_controller.js @@ -42,12 +42,18 @@ export default class extends Controller { }) } + tryToGeocode() { + let location + + if (location = this.validateLatLngInputs(false) && + JSON.stringify(location) !== JSON.stringify(this.lastGeocodedLatLng)) { + this.geocodeLatLng(location) + } + } + // Geocode a lat/lng location. If we have multiple results, we'll dispatch // Send the location from validateLatLngInputs(false) to avoid duplicate calls geocodeLatLng(location) { - if (JSON.stringify(location) == JSON.stringify(this.lastGeocodedLatLng)) - return - this.lastGeocodedLatLng = location this.verbose("geocode:geocodeLatLng") this.verbose(location) @@ -66,10 +72,16 @@ export default class extends Controller { }); } - geolocatePlaceName() { + tryToGeolocate() { let address = this.placeInputTarget.value - if (address === this.lastGeolocatedAddress) return + if (this.ignorePlaceInput === false && address !== "" + && address !== this.lastGeolocatedAddress) { + this.geolocatePlaceName(address) + } + } + + geolocatePlaceName(address) { this.lastGeolocatedAddress = address this.verbose("geocode:geolocatePlaceName") this.verbose(address) diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index 52f490cd2d..99f3b2ce4b 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -387,25 +387,23 @@ export default class extends GeocodeController { checkForBox() { // this.showBoxBtnTarget.disabled = true this.verbose("map:checkForBox") - let id, location - if (this.hasLocationIdTarget && (id = this.locationIdTarget.value)) { - this.mapLocationBounds() + let id + if (id = this?.locationIdTarget?.value) { + this.mapLocationIdData() // Only geocode lat/lng if we have no location_id and not ignoring place } else if (["location", "hybrid"].includes(this.map_type)) { - if (location = this.validateLatLngInputs(false) && - this.ignorePlaceInput !== false) { - this.geocodeLatLng(location) // multiple possible results + if (this.ignorePlaceInput !== false) { + this.tryToGeocode() // multiple possible results // ...and only geolocate placeName if we have no lat/lng - } else if (this.ignorePlaceInput === false) { - // ...and only geolocate placeName if we have no lat/lng - this.geolocatePlaceName() // 1 result + } else { + this.tryToGeolocate() } } if (this.rectangle) this.rectangle.setVisible(true) } // The locationIdTarget should have the bounds in its dataset - mapLocationBounds() { + mapLocationIdData() { if (!this.hasLocationIdTarget || !this.locationIdTarget.dataset.north) return false diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 6d2e3a997c..71593c5d14 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -26,8 +26,7 @@ end model: @herbarium, id: "herbarium_form", class: "geocode-outlet", data: { controller: "geocode", - action: - "autocompleter:hiddenIdDataChanged@window->geocode#geolocatePlaceName" + action: "autocompleter:hiddenIdDataChanged@window->geocode#tryToGeolocate" } ) do |f| %> From 918c5ebdf74da214ca949cadac780e1634c6c6c0 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 3 Aug 2024 15:01:02 -0700 Subject: [PATCH 26/89] reorg autocompleter_field --- app/helpers/forms_helper.rb | 41 ++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index 5332133b8d..6ff16bdc19 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -208,6 +208,17 @@ def text_field_with_label(**args) # crap off. (documented on SO) # def autocompleter_field(**args) + ac_args = autocompleter_field_args(**args) + + if args[:textarea] == true + text_area_with_label(**ac_args) + else + text_field_with_label(**ac_args) + end + end + + # rubocop:disable Metrics/AbcSize + def autocompleter_field_args(**args) ac_args = { placeholder: :start_typing.l, autocomplete: "off", data: { autocompleter_target: "input" } @@ -221,26 +232,24 @@ def autocompleter_field(**args) autocompleter_geocode_outlet: ".geocode-outlet", autocompleter_target: "wrap" } ac_args[:between] = capture do - concat(args[:between]) - concat(autocompleter_has_id_indicator) - concat(autocompleter_find_button(args)) if args[:find_text] - concat(autocompleter_keep_button(args)) if args[:keep_text] - concat(autocompleter_hidden_field(**args)) if args[:form] + [ + args[:between], + autocompleter_has_id_indicator, + autocompleter_find_button(args), + autocompleter_keep_button(args), + autocompleter_hidden_field(**args) + ].safe_join end ac_args[:between_end] = capture do - autocompleter_create_button(args) if args[:create_text] + autocompleter_create_button(args) end ac_args[:append] = capture do concat(autocompleter_dropdown) concat(args[:append]) end - - if args[:textarea] == true - text_area_with_label(**ac_args) - else - text_field_with_label(**ac_args) - end + ac_args end + # rubocop:enable Metrics/AbcSize def autocompleter_has_id_indicator link_icon(:check, title: :autocompleter_has_id.l, @@ -249,6 +258,8 @@ def autocompleter_has_id_indicator end def autocompleter_create_button(args) + return unless args[:create_text] + icon_link_to( args[:create_text], "#", icon: :plus, show_text: true, icon_class: "text-primary", @@ -259,6 +270,8 @@ def autocompleter_create_button(args) end def autocompleter_find_button(args) + return unless args[:find_text] + icon_link_to( args[:find_text], "#", icon: :find_on_map, show_text: false, icon_class: "text-primary", @@ -269,6 +282,8 @@ def autocompleter_find_button(args) end def autocompleter_keep_button(args) + return unless args[:keep_text] + icon_link_to( args[:keep_text], "#", icon: :apply, show_text: false, icon_class: "text-primary", @@ -282,6 +297,8 @@ def autocompleter_keep_button(args) # minimum args :form, :type. # Send :hidden to fill the id, :hidden_data to merge with hidden field data def autocompleter_hidden_field(**args) + return unless args[:form].present? && args[:type].present? && args[:hidden] + model = autocompleter_type_to_model(args[:type]) data = { autocompleter_target: "hidden" }.merge(args[:hidden_data] || {}) args[:form].hidden_field(:"#{model}_id", value: args[:hidden], data:) From 339d205deda084c3fcf03d4eee34a92d0e9c4e85 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 3 Aug 2024 15:01:12 -0700 Subject: [PATCH 27/89] Move commit button --- app/views/controllers/herbaria/_form.erb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 71593c5d14..2d6c0734ba 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -30,10 +30,8 @@ end } ) do |f| %> - <%= submit_button(form: f, button: button_name, center: true) %> - - <%= f.hidden_field :back, value: @back %> - <%= f.hidden_field :q, value: get_query_param %> + <%= f.hidden_field(:back, value: @back) %> + <%= f.hidden_field(:q, value: get_query_param) %> <%= text_field_with_label(form: f, field: :name, label: :NAME.t + ":", between: :required, help:) %> @@ -55,6 +53,8 @@ end <% end %> + <%= submit_button(form: f, button: button_name, center: true) %> + <% if !@herbarium.personal_user_id %> <%= text_field_with_label(form: f, field: :code, size: 8, inline: true, label: :create_herbarium_code.l + ":", @@ -84,12 +84,12 @@ end between: :optional) %> <%= text_area_with_label(form: f, field: :mailing_address, rows: 5, - label: :create_herbarium_mailing_address.l + ":", - between: :optional) %> + label: :create_herbarium_mailing_address.l + ":", + between: :optional) %> <%= text_area_with_label(form: f, field: :description, rows: 10, - label: :NOTES.l + ":", - between: :optional) %> + label: :NOTES.l + ":", + between: :optional) %> <%= submit_button(form: f, button: button_name, center: true) %> From a795e956d14238dc1f4d8e4c8c2f7465be897ad3 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 3 Aug 2024 15:01:28 -0700 Subject: [PATCH 28/89] Remove `skip` for system tests --- test/system/location_form_system_test.rb | 1 - test/system/observation_comment_system_test.rb | 1 - test/system/observation_form_system_test.rb | 3 --- 3 files changed, 5 deletions(-) diff --git a/test/system/location_form_system_test.rb b/test/system/location_form_system_test.rb index c9df241d3b..49225adfec 100644 --- a/test/system/location_form_system_test.rb +++ b/test/system/location_form_system_test.rb @@ -4,7 +4,6 @@ class LocationFormSystemTest < ApplicationSystemTestCase def test_format_new_location_name - skip("This test is inconsistent when run in CI") # browser = page.driver.browser rolf = users("rolf") login!(rolf) diff --git a/test/system/observation_comment_system_test.rb b/test/system/observation_comment_system_test.rb index 5142da3731..079189f035 100644 --- a/test/system/observation_comment_system_test.rb +++ b/test/system/observation_comment_system_test.rb @@ -8,7 +8,6 @@ class ObservationCommentSystemTest < ApplicationSystemTestCase # Katrina edits the comment, rolf should get the change immediately. # Katrina deletes the comment, rolf should get the deletion immediately. def test_add_and_edit_comment - skip("This test is inconsistent when run in CI") rolf = users("rolf") katrina = users("katrina") obs = observations(:coprinus_comatus_obs) diff --git a/test/system/observation_form_system_test.rb b/test/system/observation_form_system_test.rb index 8b71e12d34..65c08d2bb6 100644 --- a/test/system/observation_form_system_test.rb +++ b/test/system/observation_form_system_test.rb @@ -119,7 +119,6 @@ def test_trying_to_create_duplicate_location_just_uses_existing_location end def test_autofill_location_from_geotagged_image_nothing_matches - skip("This test is inconsistent when run in CI") setup_image_dirs # in general_extensions login!(katrina) @@ -229,8 +228,6 @@ def test_autofill_location_from_geotagged_image_matching_location end def test_post_edit_and_destroy_with_details_and_location - skip("This test is inconsistent when run in CI") - # browser = page.driver.browser setup_image_dirs # in general_extensions From ad9a0d66bcfc917d31f4d6149c3d25bc6f04b027 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 3 Aug 2024 23:27:44 -0700 Subject: [PATCH 29/89] Clean up recent changes --- .../controllers/autocompleter_controller.js | 20 ++++++------------- .../controllers/geocode_controller.js | 5 +++-- app/javascript/controllers/map_controller.js | 2 +- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index dae7b4cd81..1524a4de6f 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -283,16 +283,13 @@ export default class extends Controller { if (!outlet.opened) outlet.toggleMapBtnTarget.click(); // set the map type so box is editable outlet.map_type = "hybrid"; // only if location_google - // outlet.marker.setDraggable(false); messes up map - // outlet.marker.setClickable(false); messes up map + let location if (location = outlet.validateLatLngInputs(false)) { outlet.geocodeLatLng(location); } else { outlet.lockBoxBtnTarget.classList.remove("d-none"); } - // this.createBtnTarget.classList.add('d-none'); - // this.dispatchHiddenIdEvents(); } mapOutletDisconnected(outlet, element) { @@ -300,14 +297,6 @@ export default class extends Controller { outlet.map_type = "observation"; if (outlet.rectangle) outlet.rectangle.setEditable(false); - // Make the map show box button back into a create button - // delete this.createBtnTarget.dataset.mapTarget; - // const create_action = this.createBtnTarget.dataset.action - // .replace("map#showBox:prevent", "autocompleter#swapCreate:prevent"); - // this.createBtnTarget.dataset.action = create_action; - // this.createBtnTarget.classList.remove('d-none'); - - // this.dispatchHiddenIdEvents(); outlet.northInputTarget.value = ''; outlet.southInputTarget.value = ''; outlet.eastInputTarget.value = ''; @@ -328,8 +317,11 @@ export default class extends Controller { // Attach events this.addEventListeners(); - const hidden_id = parseInt(this.hiddenTarget.value); - this.hasIdOrNo(hidden_id); + let hidden_id + if (this.hasHiddenTarget && + (hidden_id = parseInt(this.hiddenTarget.value))) { + this.hasIdOrNo(hidden_id); + } } // When swapping autocompleter types, swap the hidden input identifiers. diff --git a/app/javascript/controllers/geocode_controller.js b/app/javascript/controllers/geocode_controller.js index 7ed95b687b..a18f746516 100644 --- a/app/javascript/controllers/geocode_controller.js +++ b/app/javascript/controllers/geocode_controller.js @@ -3,8 +3,9 @@ import { Loader } from "@googlemaps/js-api-loader" import { convert } from "geo-coordinates-parser" // Connects to data-controller="geocode" -// The connected element should contain a location autocompleter and -// bounding box/elevation inputs. +// Sort of the "lite" version of the map controller: no map, no markers, but it +// can geocode and get elevations. The connected element should contain a +// location autocompleter and bounding box/elevation inputs. export default class extends Controller { static targets = ["southInput", "westInput", "northInput", "eastInput", "highInput", "lowInput", "placeInput", "locationId", diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index 99f3b2ce4b..872b9ff186 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -388,7 +388,7 @@ export default class extends GeocodeController { // this.showBoxBtnTarget.disabled = true this.verbose("map:checkForBox") let id - if (id = this?.locationIdTarget?.value) { + if (this.hasLocationIdTarget && (id = this.locationIdTarget.value)) { this.mapLocationIdData() // Only geocode lat/lng if we have no location_id and not ignoring place } else if (["location", "hybrid"].includes(this.map_type)) { From 39afc504ff5970d4f14820bee4d4830636e752cc Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 3 Aug 2024 23:40:04 -0700 Subject: [PATCH 30/89] Fix missing hidden field --- app/helpers/forms_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index 6ff16bdc19..801cc8831e 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -297,7 +297,7 @@ def autocompleter_keep_button(args) # minimum args :form, :type. # Send :hidden to fill the id, :hidden_data to merge with hidden field data def autocompleter_hidden_field(**args) - return unless args[:form].present? && args[:type].present? && args[:hidden] + return unless args[:form].present? && args[:type].present? model = autocompleter_type_to_model(args[:type]) data = { autocompleter_target: "hidden" }.merge(args[:hidden_data] || {}) From f662e761c9a513a1e1d7de340a3427a8f1a053f7 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 4 Aug 2024 10:54:54 -0700 Subject: [PATCH 31/89] Change ac arg to `hidden_value` --- app/helpers/forms_helper.rb | 4 ++-- app/views/controllers/observations/form/_details.html.erb | 2 +- .../controllers/observations/form/_herbarium_record.html.erb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index 8369c0c93e..055a2def31 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -214,7 +214,7 @@ def autocompleter_field(**args) placeholder: :start_typing.l, autocomplete: "off", data: { autocompleter_target: "input" } }.deep_merge(args.except(:type, :separator, :textarea, - :hidden, :hidden_data, :create_text, + :hidden_value, :hidden_data, :create_text, :keep_text, :edit_text, :find_text)) ac_args[:class] = class_names("dropdown", args[:class]) ac_args[:wrap_data] = { controller: :autocompleter, type: args[:type], @@ -332,7 +332,7 @@ def autocompleter_hidden_field(**args) model = autocompleter_type_to_model(args[:type]) data = { autocompleter_target: "hidden" }.merge(args[:hidden_data] || {}) - args[:form].hidden_field(:"#{model}_id", value: args[:hidden], data:) + args[:form].hidden_field(:"#{model}_id", value: args[:hidden_value], data:) end def autocompleter_type_to_model(type) diff --git a/app/views/controllers/observations/form/_details.html.erb b/app/views/controllers/observations/form/_details.html.erb index 7cceeec8f0..ba51570762 100644 --- a/app/views/controllers/observations/form/_details.html.erb +++ b/app/views/controllers/observations/form/_details.html.erb @@ -66,7 +66,7 @@ t_s = { tag.span("#{:form_observations_create_locality.l}:", class: "create-label")].safe_join(" "), help: observation_location_help, - hidden: location&.id, + hidden_value: location&.id, hidden_data: { map_target: "locationId", north: location&.north, south: location&.south, east: location&.east, west: location&.west }, diff --git a/app/views/controllers/observations/form/_herbarium_record.html.erb b/app/views/controllers/observations/form/_herbarium_record.html.erb index 26bfc0adec..8504c75967 100644 --- a/app/views/controllers/observations/form/_herbarium_record.html.erb +++ b/app/views/controllers/observations/form/_herbarium_record.html.erb @@ -4,7 +4,7 @@ <% fields_for(:herbarium_record) do |fhr| %> <%= autocompleter_field( form: fhr, field: :herbarium_name, type: :herbarium, - value: @herbarium_name, hidden: @herbarium_id, + value: @herbarium_name, hidden_value: @herbarium_id, label: "#{:herbarium_record_herbarium_name.t}:", help: :form_observations_herbarium_record_help.t ) %> From 45d6fc4adfe3e982762faf83853e1b4ff98edacb Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 4 Aug 2024 10:55:14 -0700 Subject: [PATCH 32/89] Re-remove field_args --- app/helpers/forms_helper.rb | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index 055a2def31..3f346e8478 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -248,40 +248,6 @@ def autocompleter_field(**args) # rubocop:enable Metrics/AbcSize # rubocop:enable Metrics/MethodLength - # rubocop:disable Metrics/AbcSize - def autocompleter_field_args(**args) - ac_args = { - placeholder: :start_typing.l, autocomplete: "off", - data: { autocompleter_target: "input" } - }.deep_merge(args.except(:type, :separator, :textarea, - :hidden, :hidden_data, :create_text, - :keep_text, :edit_text, :find_text)) - ac_args[:class] = class_names("dropdown", args[:class]) - ac_args[:wrap_data] = { controller: :autocompleter, type: args[:type], - separator: args[:separator], - autocompleter_map_outlet: ".map-outlet", - autocompleter_geocode_outlet: ".geocode-outlet", - autocompleter_target: "wrap" } - ac_args[:between] = capture do - [ - args[:between], - autocompleter_has_id_indicator, - autocompleter_find_button(args), - autocompleter_keep_button(args), - autocompleter_hidden_field(**args) - ].safe_join - end - ac_args[:between_end] = capture do - autocompleter_create_button(args) - end - ac_args[:append] = capture do - concat(autocompleter_dropdown) - concat(args[:append]) - end - ac_args - end - # rubocop:enable Metrics/AbcSize - def autocompleter_has_id_indicator link_icon(:check, title: :autocompleter_has_id.l, class: "ml-3 px-2 text-success has-id-indicator", From e3ebce25a2195a0a58e7697552bae3efd09317d1 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 4 Aug 2024 11:26:12 -0700 Subject: [PATCH 33/89] Change CSS class name from .observation-form-map to .form-map --- app/assets/stylesheets/mo/_maps.scss | 2 +- app/views/controllers/observations/form/_details.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/mo/_maps.scss b/app/assets/stylesheets/mo/_maps.scss index 58e2f0189a..ec76efb699 100644 --- a/app/assets/stylesheets/mo/_maps.scss +++ b/app/assets/stylesheets/mo/_maps.scss @@ -2,7 +2,7 @@ // thumbnail & google map styles // -.observation-form-map { +.form-map { height: 400px; width: 100%; background-position: center center; diff --git a/app/views/controllers/observations/form/_details.html.erb b/app/views/controllers/observations/form/_details.html.erb index ba51570762..146bfe049b 100644 --- a/app/views/controllers/observations/form/_details.html.erb +++ b/app/views/controllers/observations/form/_details.html.erb @@ -112,7 +112,7 @@ t_s = { id: "observation_geolocation") do %> <%= tag.div( "", id: "observation_form_map", - class: "observation-form-map collapse", + class: "form-map collapse", data: { indicator_url: asset_path('indicator.gif'), location_format: User.current_location_format, map_target: "mapDiv", editable: true, From e516b03ce701d02479eed880e150ef40bb33aa60 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 4 Aug 2024 11:26:34 -0700 Subject: [PATCH 34/89] Switch herbarium form to map controller --- app/views/controllers/herbaria/_form.erb | 37 ++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 2d6c0734ba..9104c55435 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -25,8 +25,8 @@ end <%= form_with( model: @herbarium, id: "herbarium_form", class: "geocode-outlet", data: { - controller: "geocode", - action: "autocompleter:hiddenIdDataChanged@window->geocode#tryToGeolocate" + controller: "map", + action: "autocompleter:hiddenIdDataChanged@window->map#showBox" } ) do |f| %> @@ -79,6 +79,39 @@ end <%= render(partial: "locations/form/bounds_hidden_fields", locals: { location: @location, target_type: :geocode }) %> + + <%= tag.div(id: "herbarium_geolocation") do %> + <%= tag.div( + "", id: "herbarium_form_map", + class: "form-map collapse", + data: { indicator_url: asset_path('indicator.gif'), + location_format: User.current_location_format, + map_target: "mapDiv", editable: true, + map_type: "location" } + ) %> + <%= tag.div(class: "btn-group my-3", role: "group", + data: { map_target: "controlWrap" }) do %> + <%= js_button( + button: [ + link_icon(:globe), + tag.span(:form_observations_open_map.l, class: "map-show mx-2"), + 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", + toggle: "collapse", target: "#herbarium_form_map" }, + aria: { expanded: "false", controls: "herbarium_form_map" } + ) %> + <%= js_button( + button: :form_observations_clear_map.l, + name: "map_clear", class: "map-clear", + data: { map_target: "mapClearBtn", + action: "map#clearMap form-exif#reenableButtons" } + ) %> + <% end %> + <% end %> + + <%= text_field_with_label(form: f, field: :email, label: :create_herbarium_email.l + ":", between: :optional) %> From 0350ebdbcfbae9c2c6ebb97c6f5ee22e8e4eeefb Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 4 Aug 2024 11:40:11 -0700 Subject: [PATCH 35/89] `bounds_hidden_fields` partial: change local arg to `target_controller` --- .../controllers/locations/form/_bounds_hidden_fields.erb | 4 ++-- app/views/controllers/observations/form/_details.html.erb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/controllers/locations/form/_bounds_hidden_fields.erb b/app/views/controllers/locations/form/_bounds_hidden_fields.erb index 79a26adf3e..3b59f8e953 100644 --- a/app/views/controllers/locations/form/_bounds_hidden_fields.erb +++ b/app/views/controllers/locations/form/_bounds_hidden_fields.erb @@ -1,10 +1,10 @@ -<%# locals: (location: nil, target_type: :geocode_target) -%> +<%# locals: (location: nil, target_controller: :geocode) -%> <%= fields_for(:location) do |f_l| %> <% %w[north south east west low high].each do |key| %> <%= f_l.hidden_field( :"#{key}", value: location&.send(key) || nil, - data: { "#{target_type}_target".to_sym => "#{key}Input" } + data: { "#{target_controller}_target".to_sym => "#{key}Input" } ) %> <% end %> <% end %> diff --git a/app/views/controllers/observations/form/_details.html.erb b/app/views/controllers/observations/form/_details.html.erb index 146bfe049b..d0fc5200a8 100644 --- a/app/views/controllers/observations/form/_details.html.erb +++ b/app/views/controllers/observations/form/_details.html.erb @@ -86,7 +86,7 @@ t_s = { ) %> <%= render(partial: "locations/form/bounds_hidden_fields", - locals: { location: @location, target_type: :map }) %> + locals: { location: @location, target_controller: :map }) %> From f85cbc11089789e88440b0a4997109b11487b9af Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 4 Aug 2024 11:40:15 -0700 Subject: [PATCH 36/89] Update _form.erb --- app/views/controllers/herbaria/_form.erb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 9104c55435..a49d7f5a5b 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -68,16 +68,16 @@ end tag.span("#{:form_observations_create_locality.l}:", class: "create-label")].safe_join(" "), between: :optional, - hidden_data: { geocode_target: "locationId" }, + hidden_data: { map_target: "locationId" }, create_text: :form_observations_create_locality.l, data: { - geocode_target: "placeInput", - action: "geocode:googlePrimer@window->autocompleter#refreshGooglePrimer" + map_target: "placeInput", + action: "map:googlePrimer@window->autocompleter#refreshGooglePrimer" } ) %> <%= render(partial: "locations/form/bounds_hidden_fields", - locals: { location: @location, target_type: :geocode }) %> + locals: { location: @location, target_controller: :map }) %> <%= tag.div(id: "herbarium_geolocation") do %> From 4cf8bdc22fe88987d1cf8c27fa48a1afe74421f0 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 4 Aug 2024 11:57:51 -0700 Subject: [PATCH 37/89] Fix two stimulus errors --- app/javascript/controllers/autocompleter_controller.js | 2 +- app/javascript/controllers/map_controller.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index dba1728078..e713a2d0aa 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -287,7 +287,7 @@ export default class extends Controller { let location if (location = outlet.validateLatLngInputs(false)) { outlet.geocodeLatLng(location); - } else { + } else if (outlet.hasLockBoxBtnTarget) { outlet.lockBoxBtnTarget.classList.remove("d-none"); } } diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index 872b9ff186..3ddea44be9 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -138,6 +138,8 @@ export default class extends GeocodeController { // set.center is an array [lat, lng] // the `key` of each set is an array [x,y,w,h] buildOverlays() { + if (!this.collection) return + for (const [_xywh, set] of Object.entries(this.collection.sets)) { // this.verbose({ set }) // NOTE: according to the MapSet class, location sets are always is_box. From e4905112f8d5c8ee9bc52c17c1a924b0470d316e Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 4 Aug 2024 11:58:01 -0700 Subject: [PATCH 38/89] Update _form.erb --- app/views/controllers/herbaria/_form.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index a49d7f5a5b..3519cc7703 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -80,7 +80,7 @@ end locals: { location: @location, target_controller: :map }) %> - <%= tag.div(id: "herbarium_geolocation") do %> + <%= tag.div(id: "herbarium_geolocation", class: "mb-5") do %> <%= tag.div( "", id: "herbarium_form_map", class: "form-map collapse", From 250f95e7c4f997e168f3765ac2a5a15c96d909c4 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 4 Aug 2024 12:00:15 -0700 Subject: [PATCH 39/89] CSS for .form-map --- app/assets/stylesheets/Admin.scss | 2 +- app/assets/stylesheets/Agaricus.scss | 4 ++-- app/assets/stylesheets/Amanita.scss | 2 +- app/assets/stylesheets/BlackOnWhite.scss | 2 +- app/assets/stylesheets/Cantharellaceae.scss | 2 +- app/assets/stylesheets/Hygrocybe.scss | 2 +- app/assets/stylesheets/Sudo.scss | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/assets/stylesheets/Admin.scss b/app/assets/stylesheets/Admin.scss index bf0e0ff2f9..46e50cbbfd 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: #545555; // gray +$LEFT_BAR_BORDER_COLOR: #545455; // 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 c7d5dbcd37..3ebe0a66d9 100644 --- a/app/assets/stylesheets/Agaricus.scss +++ b/app/assets/stylesheets/Agaricus.scss @@ -1,7 +1,7 @@ @import "defaults"; -$augustus_cap: #EaCe93; // #ECCF95 -$brasiliensis_gills_1: #A06463; +$augustus_cap: #ECCF95; +$brasiliensis_gills_1: #A06363; // #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 44725ef795..516cd50bee 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: #fbead3; // faebd4 +$velosa_light_veil: #fcead3; // 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 e538748a26..0d6c3f68cc 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: #DFDfDD; +$TOP_BAR_BORDER_COLOR: #DFDfDf; $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 b9948d2268..4f2d17ce82 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: #11120b; // image 465 #10110b +$cornucopioides_dark_hymenium: #11120c; // 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 dc7062c8db..f8bb628f73 100644 --- a/app/assets/stylesheets/Hygrocybe.scss +++ b/app/assets/stylesheets/Hygrocybe.scss @@ -1,6 +1,6 @@ @import "defaults"; -$conica_stain: #35362d; // #37372f +$conica_stain: #35352d; // #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 b091bf1cec..5247c013ea 100644 --- a/app/assets/stylesheets/Sudo.scss +++ b/app/assets/stylesheets/Sudo.scss @@ -1,6 +1,6 @@ @import "defaults"; -$BODY_BG_COLOR: #DE7500; // #DD7700 +$BODY_BG_COLOR: #DE7400; // #DD7700 $LOGO_BORDER_COLOR: black; $LOGO_BORDER_WIDTH: 2px; // vs 1px in default From 52fc7506c097a6b01db2380dac60adccb56db035 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 4 Aug 2024 12:16:03 -0700 Subject: [PATCH 40/89] remove outlet from form --- app/views/controllers/herbaria/_form.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 3519cc7703..473a04281c 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -23,7 +23,7 @@ end %> <%= form_with( - model: @herbarium, id: "herbarium_form", class: "geocode-outlet", + model: @herbarium, id: "herbarium_form", data: { controller: "map", action: "autocompleter:hiddenIdDataChanged@window->map#showBox" From 3085024f78396f2dd6ed2aa7006dac803864ff6c Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 4 Aug 2024 12:16:07 -0700 Subject: [PATCH 41/89] Update BlackOnWhite.scss --- app/assets/stylesheets/BlackOnWhite.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/BlackOnWhite.scss b/app/assets/stylesheets/BlackOnWhite.scss index 0d6c3f68cc..737674834e 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: #DFDfDf; +$TOP_BAR_BORDER_COLOR: #DaDaDa; $LIST_BORDER_COLOR: #DDDDDD; $BUTTON_HOVER_BORDER_COLOR: #CCCCCC; $BUTTON_BG_COLOR: #CCCCCC; From 4ca74a77a6e72719d6a0aa4e46b37182b4d590a3 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 4 Aug 2024 12:25:12 -0700 Subject: [PATCH 42/89] Split form_location_map partial --- app/views/controllers/herbaria/_form.erb | 30 ++----------------- .../observations/form/_details.html.erb | 30 ++----------------- .../controllers/shared/_form_location_map.erb | 30 +++++++++++++++++++ 3 files changed, 35 insertions(+), 55 deletions(-) create mode 100644 app/views/controllers/shared/_form_location_map.erb diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 473a04281c..a658cebcae 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -81,34 +81,8 @@ end <%= tag.div(id: "herbarium_geolocation", class: "mb-5") do %> - <%= tag.div( - "", id: "herbarium_form_map", - class: "form-map collapse", - data: { indicator_url: asset_path('indicator.gif'), - location_format: User.current_location_format, - map_target: "mapDiv", editable: true, - map_type: "location" } - ) %> - <%= tag.div(class: "btn-group my-3", role: "group", - data: { map_target: "controlWrap" }) do %> - <%= js_button( - button: [ - link_icon(:globe), - tag.span(:form_observations_open_map.l, class: "map-show mx-2"), - 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", - toggle: "collapse", target: "#herbarium_form_map" }, - aria: { expanded: "false", controls: "herbarium_form_map" } - ) %> - <%= js_button( - button: :form_observations_clear_map.l, - name: "map_clear", class: "map-clear", - data: { map_target: "mapClearBtn", - action: "map#clearMap form-exif#reenableButtons" } - ) %> - <% end %> + <%= render(partial: "shared/form_location_map", + locals: { id: "herbarium_form_map" }) %> <% end %> diff --git a/app/views/controllers/observations/form/_details.html.erb b/app/views/controllers/observations/form/_details.html.erb index d0fc5200a8..855491a2de 100644 --- a/app/views/controllers/observations/form/_details.html.erb +++ b/app/views/controllers/observations/form/_details.html.erb @@ -110,34 +110,10 @@ t_s = { <%= tag.div(class: "col-xs-12 col-md-6", id: "observation_geolocation") do %> - <%= tag.div( - "", id: "observation_form_map", - class: "form-map collapse", - data: { indicator_url: asset_path('indicator.gif'), - location_format: User.current_location_format, - map_target: "mapDiv", editable: true, - map_type: "observation" } + <%= render( + partial: "shared/form_location_map", + locals: { id: "observation_form_map", map_type: "observation" } ) %> - <%= tag.div(class: "btn-group my-3", role: "group", - data: { map_target: "controlWrap" }) do %> - <%= js_button( - button: [ - link_icon(:globe), - tag.span(:form_observations_open_map.l, class: "map-show mx-2"), - 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", - toggle: "collapse", target: "#observation_form_map" }, - aria: { expanded: "false", controls: "observation_form_map" } - ) %> - <%= js_button( - button: :form_observations_clear_map.l, - name: "map_clear", class: "map-clear", - data: { map_target: "mapClearBtn", - action: "map#clearMap form-exif#reenableButtons" } - ) %> - <% end %> <% end %> diff --git a/app/views/controllers/shared/_form_location_map.erb b/app/views/controllers/shared/_form_location_map.erb new file mode 100644 index 0000000000..b62552689c --- /dev/null +++ b/app/views/controllers/shared/_form_location_map.erb @@ -0,0 +1,30 @@ +<%# locals: (id: "", map_type: "location") -%> + +<%= tag.div( + "", id:, + class: "form-map collapse", + data: { indicator_url: asset_path('indicator.gif'), + location_format: User.current_location_format, + map_target: "mapDiv", editable: true, + map_type: } +) %> +<%= tag.div(class: "btn-group my-3", role: "group", + data: { map_target: "controlWrap" }) do %> + <%= js_button( + button: [ + link_icon(:globe), + tag.span(:form_observations_open_map.l, class: "map-show mx-2"), + 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", + toggle: "collapse", target: "##{id}" }, + aria: { expanded: "false", controls: id } + ) %> + <%= js_button( + button: :form_observations_clear_map.l, + name: "map_clear", class: "map-clear", + data: { map_target: "mapClearBtn", + action: "map#clearMap form-exif#reenableButtons" } + ) %> +<% end %> From 10abed0e8be839b047ee312487e3a2683423869b Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Mon, 5 Aug 2024 16:15:46 -0700 Subject: [PATCH 43/89] autocompleter - new behavior for create mode Create mode shows or hides the whole map interface when location optional New target for map - autocompleter, to check when location is optional forms_helper: text_label_row and ac wrap_data --- app/assets/stylesheets/Admin.scss | 2 +- app/assets/stylesheets/Agaricus.scss | 2 +- app/assets/stylesheets/Amanita.scss | 2 +- app/assets/stylesheets/BlackOnWhite.scss | 2 +- app/assets/stylesheets/Cantharellaceae.scss | 2 +- app/assets/stylesheets/Hygrocybe.scss | 2 +- app/assets/stylesheets/Sudo.scss | 2 +- app/assets/stylesheets/mo/_autocomplete.scss | 14 ++- app/helpers/forms_helper.rb | 98 ++++++++++--------- .../controllers/autocompleter_controller.js | 32 ++++-- app/javascript/controllers/map_controller.js | 21 ++-- 11 files changed, 109 insertions(+), 70 deletions(-) diff --git a/app/assets/stylesheets/Admin.scss b/app/assets/stylesheets/Admin.scss index 46e50cbbfd..ee2d668f7d 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: #545455; // gray +$LEFT_BAR_BORDER_COLOR: #545454; // 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 3ebe0a66d9..3658b0575d 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: #A06363; // #A06463 +$brasiliensis_gills_1: #A06362; // #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 516cd50bee..b790f04f51 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: #fcead3; // faebd4 +$velosa_light_veil: #fce9d3; // 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 737674834e..8a5fe17a1d 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: #DaDaDa; +$TOP_BAR_BORDER_COLOR: #D9DaDa; $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 4f2d17ce82..c8547a05a9 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: #11120c; // image 465 #10110b +$cornucopioides_dark_hymenium: #12120c; // 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 f8bb628f73..da30be5b27 100644 --- a/app/assets/stylesheets/Hygrocybe.scss +++ b/app/assets/stylesheets/Hygrocybe.scss @@ -1,6 +1,6 @@ @import "defaults"; -$conica_stain: #35352d; // #37372f +$conica_stain: #34352d; // #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 5247c013ea..03adfe837c 100644 --- a/app/assets/stylesheets/Sudo.scss +++ b/app/assets/stylesheets/Sudo.scss @@ -1,6 +1,6 @@ @import "defaults"; -$BODY_BG_COLOR: #DE7400; // #DD7700 +$BODY_BG_COLOR: #DE7300; // #DD7700 $LOGO_BORDER_COLOR: black; $LOGO_BORDER_WIDTH: 2px; // vs 1px in default diff --git a/app/assets/stylesheets/mo/_autocomplete.scss b/app/assets/stylesheets/mo/_autocomplete.scss index 885c5bb58f..e7e75d7ce3 100644 --- a/app/assets/stylesheets/mo/_autocomplete.scss +++ b/app/assets/stylesheets/mo/_autocomplete.scss @@ -6,16 +6,20 @@ .has-id-indicator { display: none; } -.create-button { - display: inline-block; -} - .has-id { .has-id-indicator { display: inline-block; } +} + +// initially we may not have id, but we also don't offer create +// until they've typed something +.create-button { + display: none; +} +.offer-create { .create-button { - display: none; + display: inline-block; } } diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index 3f346e8478..e38bec3bb2 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -165,17 +165,7 @@ def text_field_with_label(**args) label_opts[:class] = class_names(label_opts[:class], args[:label_class]) tag.div(class: wrap_class, data: wrap_data) do - # The label row is complicated, many potential buttons here. `between` - # comes right after the label on left, `between_end` is right justified - concat(tag.div(class: "d-flex justify-content-between") do - concat(tag.div do - concat(args[:form].label(args[:field], args[:label], label_opts)) - concat(args[:between]) if args[:between].present? - end) - concat(tag.div do - concat(args[:between_end]) if args[:between_end].present? - end) - end) + concat(text_label_row(args, label_opts)) if args[:addon].present? # text addon, not interactive concat(tag.div(class: "input-group") do concat(args[:form].text_field(args[:field], opts)) @@ -196,6 +186,42 @@ def text_field_with_label(**args) end end + # Bootstrap text_area + def text_area_with_label(**args) + args = auto_label_if_form_is_account_prefs(args) + args = check_for_optional_or_required_note(args) + args = check_for_help_block(args) + opts = separate_field_options_from_args(args) + opts[:class] = "form-control" + opts[:class] += " text-monospace" if args[:monospace].present? + + wrap_class = form_group_wrap_class(args) + wrap_data = args[:wrap_data] || {} + label_opts = field_label_opts(args) + + tag.div(class: wrap_class, data: wrap_data) do + concat(text_label_row(args, label_opts)) + concat(args[:form].text_area(args[:field], opts)) + concat(args[:append]) if args[:append].present? + end + end + + # The label row for autocompleters is potentially complicated, many buttons. + # Content for `between` and `label_after` come right after the label on left, + # content for `label_end` is at the end of the same line, right justified. + def text_label_row(args, label_opts) + tag.div(class: "d-flex justify-content-between") do + concat(tag.div do + concat(args[:form].label(args[:field], args[:label], label_opts)) + concat(args[:between]) if args[:between].present? + concat(args[:label_after]) if args[:label_after].present? + end) + concat(tag.div do + concat(args[:label_end]) if args[:label_end].present? + end) + end + end + # MO's autocompleter_field is a text_field that fetches suggestions from the # db for the requested model. (For a textarea, pass textarea: true.) The # stimulus controller handles keyboard and mouse interactions, does the @@ -213,25 +239,26 @@ def autocompleter_field(**args) ac_args = { placeholder: :start_typing.l, autocomplete: "off", data: { autocompleter_target: "input" } - }.deep_merge(args.except(:type, :separator, :textarea, + }.deep_merge(args.except(:wrap_data, :type, :separator, :textarea, :hidden_value, :hidden_data, :create_text, :keep_text, :edit_text, :find_text)) ac_args[:class] = class_names("dropdown", args[:class]) - ac_args[:wrap_data] = { controller: :autocompleter, type: args[:type], - separator: args[:separator], - autocompleter_map_outlet: ".map-outlet", - autocompleter_geocode_outlet: ".geocode-outlet", - autocompleter_target: "wrap" } - ac_args[:between] = capture do + ac_args[:wrap_data] = { + controller: :autocompleter, type: args[:type], + separator: args[:separator], + autocompleter_map_outlet: ".map-outlet", + autocompleter_geocode_outlet: ".geocode-outlet", + autocompleter_target: "wrap" + }.deep_merge(args[:wrap_data] || {}) + ac_args[:label_after] = capture do [ - args[:between], autocompleter_has_id_indicator, autocompleter_find_button(args), autocompleter_keep_button(args), autocompleter_hidden_field(**args) ].safe_join end - ac_args[:between_end] = capture do + ac_args[:label_end] = capture do autocompleter_create_button(args) end ac_args[:append] = capture do @@ -328,27 +355,6 @@ def autocompleter_dropdown end end - # Bootstrap text_area - def text_area_with_label(**args) - args = auto_label_if_form_is_account_prefs(args) - args = check_for_optional_or_required_note(args) - args = check_for_help_block(args) - opts = separate_field_options_from_args(args) - opts[:class] = "form-control" - opts[:class] += " text-monospace" if args[:monospace].present? - - wrap_class = form_group_wrap_class(args) - wrap_data = args[:wrap_data] || {} - label_opts = field_label_opts(args) - - tag.div(class: wrap_class, data: wrap_data) do - concat(args[:form].label(args[:field], args[:label], label_opts)) - concat(args[:between]) if args[:between].present? - concat(args[:form].text_area(args[:field], opts)) - concat(args[:append]) if args[:append].present? - end - end - # Bootstrap select. # Works for select_year but not date_select, which generates multiple selects def select_with_label(**args) @@ -634,7 +640,7 @@ def check_for_optional_or_required_note(args) keys = [:optional, :required].freeze positions.each do |pos| keys.each do |key| - args[pos] = help_note(:span, "(#{key.t})") if args[pos] == key + args[pos] = help_note(:span, "(#{key.l})") if args[pos] == key end end args @@ -648,8 +654,8 @@ def check_for_help_block(args) id = "#{args[:form].object_name}_#{args[:field]}_help" args[:between] = capture do - concat(collapse_info_trigger(id)) concat(args[:between]) + concat(collapse_info_trigger(id)) end args[:append] = capture do concat(args[:append]) @@ -665,9 +671,9 @@ def check_for_help_block(args) # be excluded separately (not here) def separate_field_options_from_args(args, extras = []) exceptions = [ - :form, :field, :label, :class, :width, :inline, :between, :between_end, - :append, :help, :addon, :optional, :required, :monospace, :type, - :wrap_data, :button, :button_data + :form, :field, :label, :class, :width, :inline, :between, :label_after, + :label_end, :append, :help, :addon, :optional, :required, :monospace, + :type, :wrap_data, :button, :button_data ] + extras args.clone.except(*exceptions) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index e713a2d0aa..7b5ee2a93d 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"] + "createBtn", "hasIdIndicator", "keepBtn", "mapWrap"] static outlets = ["map"] initialize() { @@ -247,6 +247,7 @@ export default class extends Controller { if (this.TYPE === "location_google") { this.inputTarget.closest("form").classList.add(outlet_class); this.element.classList.add('create'); + this.element.classList.remove('offer-create'); this.element.classList.remove('constrained'); } else if (this.ACT_LIKE_SELECT) { this.inputTarget.closest("form").classList.remove(outlet_class); @@ -280,7 +281,8 @@ export default class extends Controller { mapOutletConnected(outlet, element) { this.verbose("autocompleter:mapOutletConnected()"); // open the map if not already open - if (!outlet.opened) outlet.toggleMapBtnTarget.click(); + if (!outlet.opened && !outlet.hasAutocompleterTarget) + outlet.toggleMapBtnTarget.click(); // set the map type so box is editable outlet.map_type = "hybrid"; // only if location_google @@ -318,7 +320,7 @@ export default class extends Controller { this.addEventListeners(); const hidden_id = parseInt(this.hiddenTarget.value); - this.hasIdOrNo(hidden_id); + this.cssHasIdOrNo(hidden_id); } // When swapping autocompleter types, swap the hidden input identifiers. @@ -958,7 +960,7 @@ export default class extends Controller { this.hiddenTarget.dataset[key] = match[key]; }); - this.hasIdOrNo(parseInt(match['id'])); + this.cssHasIdOrNo(parseInt(match['id'])); this.dispatchHiddenIdEvents(); } @@ -978,11 +980,29 @@ export default class extends Controller { this.dispatchHiddenIdEvents(); } - hasIdOrNo(hidden_id) { + // Respond to the state of the hidden input. Initially we may not have id, but + // we also don't offer create until they've typed something. + cssHasIdOrNo(hidden_id) { + this.verbose("autocompleter:cssHasIdOrNo()"); + if (hidden_id && hidden_id !== NaN && hidden_id != 0) { this.wrapTarget.classList.add('has-id'); + this.wrapTarget.classList.remove('offer-create'); } else { this.wrapTarget.classList.remove('has-id'); + if (this.inputTarget.value && + !this.wrapTarget.classList.contains('create')) { + this.wrapTarget.classList.add('offer-create'); + } + } + // On forms where a map may not be relevant, we also show/hide the map. + // Only show if we're in "create" mode. + if (this.hasMapWrapTarget) { + if (this.wrapTarget.classList.contains('create')) { + this.mapWrapTarget.classList.remove('d-none'); + } else { + this.mapWrapTarget.classList.add('d-none'); + } } } @@ -1009,7 +1029,7 @@ export default class extends Controller { clearTimeout(this.data_timer); this.data_timer = setTimeout(() => { this.verbose("autocompleter: dispatching hiddenIdDataChanged"); - this.hasIdOrNo(hidden_id); + this.cssHasIdOrNo(hidden_id); if (this.hasKeepBtnTarget) { this.keepBtnTarget.classList.remove('active'); } diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index 3ddea44be9..f93d65b6c8 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -11,7 +11,8 @@ export default class extends GeocodeController { static targets = ["mapDiv", "southInput", "westInput", "northInput", "eastInput", "highInput", "lowInput", "placeInput", "locationId", "getElevation", "mapClearBtn", "controlWrap", "toggleMapBtn", - "latInput", "lngInput", "altInput", "showBoxBtn", "lockBoxBtn"] + "latInput", "lngInput", "altInput", "showBoxBtn", "lockBoxBtn", + "autocompleter"] connect() { this.element.dataset.stimulus = "connected" @@ -373,10 +374,15 @@ export default class extends GeocodeController { // Action to map an MO location, or geocode a location from a place name. // Can be called directly from a button, so check for input values. - // Now fired from location id, including when it's zero + // Now fired when locationIdTarget changes, including when it's zero showBox() { - if (!this.opened || - !this.hasPlaceInputTarget || !this.placeInputTarget.value) + if (!(this.opened && this.hasPlaceInputTarget && + this.placeInputTarget.value)) + return false + + // Forms where location is optional: stay mum unless we're in create mode + if (this.hasAutocompleterTarget && + !this.autocompleterTarget.classList.contains("create")) return false this.verbose("map:showBox") @@ -531,11 +537,14 @@ export default class extends GeocodeController { // Action called from the "Clear Map" button clearMap() { const inputTargets = [ - this.latInputTarget, this.lngInputTarget, this.altInputTarget, this.placeInputTarget, this.northInputTarget, this.southInputTarget, this.eastInputTarget, this.westInputTarget, this.highInputTarget, this.lowInputTarget ] + if (this.hasLatInputTarget) { inputTargets.push(this.latInputTarget) } + if (this.hasLngInputTarget) { inputTargets.push(this.lngInputTarget) } + if (this.hasAltInputTarget) { inputTargets.push(this.altInputTarget) } + inputTargets.forEach((element) => { element.value = '' }) this.ignorePlaceInput = false // turn string geolocation back on @@ -624,7 +633,7 @@ export default class extends GeocodeController { } verbose(str) { - // console.log(str); + console.log(str); // document.getElementById("log"). // insertAdjacentText("beforeend", str + "
"); } From 54511a9ee42874be5baa23c58922c2aab35ec667 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Mon, 5 Aug 2024 16:16:14 -0700 Subject: [PATCH 44/89] Herbarium form - add map to form --- app/views/controllers/herbaria/_form.erb | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index a658cebcae..d401fd30a6 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -23,7 +23,7 @@ end %> <%= form_with( - model: @herbarium, id: "herbarium_form", + model: @herbarium, id: "herbarium_form", class: "map-outlet", data: { controller: "map", action: "autocompleter:hiddenIdDataChanged@window->map#showBox" @@ -62,12 +62,24 @@ end between: :optional) %> <% end %> + + <% append = capture do + tag.div(id: "herbarium_geolocation", class: "mb-5 d-none", + data: { autocompleter_target: "mapWrap" }) do + render(partial: "shared/form_location_map", + locals: { id: "herbarium_form_map" }) + end + end %> + + <%= autocompleter_field( form: f, field: :place_name, type: :location, label: [tag.span("#{:LOCATION.l}:", class: "unconstrained-label"), tag.span("#{:form_observations_create_locality.l}:", - class: "create-label")].safe_join(" "), + class: "create-label")].safe_join(" "), + wrap_data: { map_target: "autocompleter" }, between: :optional, + append:, hidden_data: { map_target: "locationId" }, create_text: :form_observations_create_locality.l, data: { @@ -79,12 +91,6 @@ end <%= render(partial: "locations/form/bounds_hidden_fields", locals: { location: @location, target_controller: :map }) %> - - <%= tag.div(id: "herbarium_geolocation", class: "mb-5") do %> - <%= render(partial: "shared/form_location_map", - locals: { id: "herbarium_form_map" }) %> - <% end %> - <%= text_field_with_label(form: f, field: :email, label: :create_herbarium_email.l + ":", From d72132eb12d7253e2570721ee97b7e50c8aff9a7 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Mon, 5 Aug 2024 18:42:06 -0700 Subject: [PATCH 45/89] Build out autocompleter_modal_create_link --- app/helpers/forms_helper.rb | 20 ++++++++++++++++--- app/helpers/tabs/herbaria_helper.rb | 4 ++-- .../form/_herbarium_record.html.erb | 4 +++- config/locales/en.txt | 2 +- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index 5c3daa71d5..da97bad609 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -242,7 +242,8 @@ def autocompleter_field(**args) data: { autocompleter_target: "input" } }.deep_merge(args.except(:wrap_data, :type, :separator, :textarea, :hidden_value, :hidden_data, :create_text, - :keep_text, :edit_text, :find_text)) + :keep_text, :edit_text, :find_text, :create, + :create_path)) ac_args[:class] = class_names("dropdown", args[:class]) ac_args[:wrap_data] = { controller: :autocompleter, type: args[:type], @@ -260,7 +261,8 @@ def autocompleter_field(**args) ].safe_join end ac_args[:label_end] = capture do - autocompleter_create_button(args) + concat(autocompleter_create_button(args)) + concat(autocompleter_modal_create_link(args)) end ac_args[:append] = capture do concat(autocompleter_dropdown) @@ -281,7 +283,7 @@ def autocompleter_has_id_indicator end def autocompleter_create_button(args) - return unless args[:create_text] + return if !args[:create_text] || args[:create].present? icon_link_to( args[:create_text], "#", @@ -292,6 +294,18 @@ def autocompleter_create_button(args) ) end + def autocompleter_modal_create_link(args) + return unless args[:create_text] && args[:create].present? && + args[:create_path].present? + + modal_link_to( + args[:create], args[:create_text], args[:create_path], + icon: :plus, show_text: true, icon_class: "text-primary", + name: "create_#{args[:type]}", class: "ml-3 create-link", + data: { autocompleter_target: "createBtn" } + ) + end + def autocompleter_find_button(args) return unless args[:find_text] diff --git a/app/helpers/tabs/herbaria_helper.rb b/app/helpers/tabs/herbaria_helper.rb index 29c4a812d6..2adbb0f957 100644 --- a/app/helpers/tabs/herbaria_helper.rb +++ b/app/helpers/tabs/herbaria_helper.rb @@ -71,12 +71,12 @@ def herbaria_curator_request_tabs(herbarium:) end def new_herbarium_tab - [:create_herbarium.t, add_query_param(new_herbarium_path), + [:create_herbarium.l, add_query_param(new_herbarium_path), { class: tab_id(__method__.to_s) }] end def edit_herbarium_tab(herbarium) - [:edit_herbarium.t, + [:edit_herbarium.l, add_query_param(edit_herbarium_path(herbarium.id)), { class: tab_id(__method__.to_s) }] end diff --git a/app/views/controllers/observations/form/_herbarium_record.html.erb b/app/views/controllers/observations/form/_herbarium_record.html.erb index 8504c75967..b9c7ea39af 100644 --- a/app/views/controllers/observations/form/_herbarium_record.html.erb +++ b/app/views/controllers/observations/form/_herbarium_record.html.erb @@ -6,7 +6,9 @@ form: fhr, field: :herbarium_name, type: :herbarium, value: @herbarium_name, hidden_value: @herbarium_id, label: "#{:herbarium_record_herbarium_name.t}:", - help: :form_observations_herbarium_record_help.t + help: :form_observations_herbarium_record_help.t, + create_text: :create_herbarium.l, create: "fungarium", + create_path: new_herbarium_path ) %> <%= text_field_with_label( form: fhr, field: :accession_number, value: @accession_number, diff --git a/config/locales/en.txt b/config/locales/en.txt index b0cdd0b90a..5b201f063a 100644 --- a/config/locales/en.txt +++ b/config/locales/en.txt @@ -2606,7 +2606,7 @@ show_herbarium_request_sent: Request has been sent to admins. We'll get back to you as soon as possible. # herbaria/create - create_herbarium: Create New Fungarium + create_herbarium: Create Fungarium create_herbarium_title: Create New Fungarium create_herbarium_personal: Check this box if this is your personal fungarium create_herbarium_personal_help: Each user can have one personal fungarium that they have curator privileges for. By default it is called "[name]", but you can change that name to anything you like. From 2e781c54a14baa5bb7da628e054f0a14623ea459 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Mon, 5 Aug 2024 18:43:27 -0700 Subject: [PATCH 46/89] Update herbaria_controller.rb --- app/controllers/herbaria_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/herbaria_controller.rb b/app/controllers/herbaria_controller.rb index 2a845e9748..8d65c62ad8 100644 --- a/app/controllers/herbaria_controller.rb +++ b/app/controllers/herbaria_controller.rb @@ -119,7 +119,7 @@ def edit end end - def render_modal_herbarium_record_form + def render_modal_herbarium_form render(partial: "shared/modal_form", locals: { title: modal_title, identifier: modal_identifier, form: "herbaria/form" }) and return From 34d69f6e5a11c952d0d319c71a4da58d57572bd4 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 6 Aug 2024 00:11:15 -0700 Subject: [PATCH 47/89] ac/map Stimulus bugs --- app/javascript/controllers/autocompleter_controller.js | 7 +++++-- app/javascript/controllers/map_controller.js | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 7b5ee2a93d..da2b032e5b 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -552,6 +552,8 @@ export default class extends Controller { // If we don't have lat/lngs, just draw the pulldown. scheduleGoogleRefresh() { if (this.hasMapOutlet && + this.mapOutlet.hasLatInputTarget && + this.mapOutlet.hasLngInputTarget && this.mapOutlet?.latInputTarget.value && this.mapOutlet?.lngInputTarget.value) { this.drawPulldown(); @@ -562,12 +564,13 @@ export default class extends Controller { this.clearRefresh(); this.refresh_timer = setTimeout((() => { this.verbose("autocompleter:doing_google_refresh()"); + this.verbose(this.inputTarget.value); this.old_value = this.inputTarget.value; // async, anything after this executes immediately if (this.hasGeocodeOutlet) { - this.geocodeOutlet.geolocatePlaceName(true); + this.geocodeOutlet.geolocatePlaceName(this.inputTarget.value); } else if (this.hasMapOutlet) { - this.mapOutlet.geolocatePlaceName(true); + this.mapOutlet.geolocatePlaceName(this.inputTarget.value); } // still necessary if primer unchanged, as likely? // this.populateMatches(); diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index f93d65b6c8..d38ce868b0 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -479,9 +479,9 @@ export default class extends GeocodeController { // input has been prepopulated and uses that to focus map and drop a marker. calculateMarker(event) { this.verbose("map:calculateMarker") - if (this.map == undefined || - this.latInputTarget.value === '' || this.lngInputTarget.value === '' - ) return false + if (this.map == undefined || !this.hasLatInputTarget || + this.latInputTarget.value === '' || this.lngInputTarget.value === '') + return false let location if (event?.detail?.request_params) { From bad5526a32622aa82722fb6cf812d19eda8ac28b Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 6 Aug 2024 00:11:28 -0700 Subject: [PATCH 48/89] Update herbaria_controller.rb add modal_form_action --- app/controllers/herbaria_controller.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/controllers/herbaria_controller.rb b/app/controllers/herbaria_controller.rb index 8d65c62ad8..5c19b0eb57 100644 --- a/app/controllers/herbaria_controller.rb +++ b/app/controllers/herbaria_controller.rb @@ -121,7 +121,8 @@ def edit def render_modal_herbarium_form render(partial: "shared/modal_form", - locals: { title: modal_title, identifier: modal_identifier, + locals: { title: modal_title, action: modal_form_action, + identifier: modal_identifier, form: "herbaria/form" }) and return end @@ -143,6 +144,13 @@ def modal_title end end + def modal_form_action + case action_name + when "new", "create" then :create + when "edit", "update" then :update + end + end + # ---------- Actions to Modify data: (create, update, destroy, etc.) --------- def create From 04121fa9e739a7810a836a75a0556c35b046ad48 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 6 Aug 2024 00:11:44 -0700 Subject: [PATCH 49/89] Update _herbarium_record.html.erb Fix type: "herbarium" --- .../controllers/observations/form/_herbarium_record.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/controllers/observations/form/_herbarium_record.html.erb b/app/views/controllers/observations/form/_herbarium_record.html.erb index b9c7ea39af..0851b92772 100644 --- a/app/views/controllers/observations/form/_herbarium_record.html.erb +++ b/app/views/controllers/observations/form/_herbarium_record.html.erb @@ -7,7 +7,7 @@ value: @herbarium_name, hidden_value: @herbarium_id, label: "#{:herbarium_record_herbarium_name.t}:", help: :form_observations_herbarium_record_help.t, - create_text: :create_herbarium.l, create: "fungarium", + create_text: :create_herbarium.l, create: "herbarium", create_path: new_herbarium_path ) %> <%= text_field_with_label( From 113a4b5deedef093f5b3b16da17cd004cbc6b301 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 6 Aug 2024 10:39:56 -0700 Subject: [PATCH 50/89] Remove top tab "create fungarium" from form --- app/helpers/tabs/observations_helper.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/helpers/tabs/observations_helper.rb b/app/helpers/tabs/observations_helper.rb index 730a3af926..eb0e57120d 100644 --- a/app/helpers/tabs/observations_helper.rb +++ b/app/helpers/tabs/observations_helper.rb @@ -211,7 +211,8 @@ def observations_download_as_csv_tab(query) # FORMS def observation_form_new_tabs - [new_herbarium_tab] + # [new_herbarium_tab] + [] end def observation_form_edit_tabs(obs:) From b145d4dfc9a6c499dc605cd53403d49f8ad08b58 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 6 Aug 2024 11:13:04 -0700 Subject: [PATCH 51/89] Disable rubocop for already existing methods --- app/controllers/herbaria_controller.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/controllers/herbaria_controller.rb b/app/controllers/herbaria_controller.rb index 5c19b0eb57..dbbd33d5bc 100644 --- a/app/controllers/herbaria_controller.rb +++ b/app/controllers/herbaria_controller.rb @@ -45,6 +45,7 @@ # See https://tinyurl.com/ynapvpt7 # View and modify Herbaria (displayed as "Fungaria") +# rubocop:disable Metrics/ClassLength class HerbariaController < ApplicationController before_action :login_required # only: [:create, :destroy, :edit, :new, :update] @@ -105,10 +106,10 @@ def new end end + # rubocop:disable Metrics/AbcSize def edit @herbarium = find_or_goto_index(Herbarium, params[:id]) - return unless @herbarium - return unless make_sure_can_edit! + return unless @herbarium && make_sure_can_edit! @herbarium.place_name = @herbarium.location.try(&:name) @herbarium.personal = @herbarium.personal_user_id.present? @@ -118,6 +119,7 @@ def edit format.html end end + # rubocop:enable Metrics/AbcSize def render_modal_herbarium_form render(partial: "shared/modal_form", @@ -285,6 +287,7 @@ def validate_personal_herbarium! true end + # rubocop:disable Metrics/AbcSize def validate_admin_personal_user! return true unless in_admin_mode? return true if nonpersonal! @@ -309,6 +312,7 @@ def validate_admin_personal_user! @herbarium.add_curator(user) @herbarium.personal_user_id = user.id end + # rubocop:enable Metrics/AbcSize # Return true/false if @herbarium nonpersonal/personal, # making it nonpersonal & flashing message if possible @@ -395,3 +399,4 @@ def herbarium_params :place_name, :personal, :personal_user_name) end end +# rubocop:enable Metrics/ClassLength From 568b8506024a8e24f1b6c040ad40df480eaa63b5 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 6 Aug 2024 11:19:10 -0700 Subject: [PATCH 52/89] Update herbaria_controller.rb --- app/controllers/herbaria_controller.rb | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/app/controllers/herbaria_controller.rb b/app/controllers/herbaria_controller.rb index dbbd33d5bc..91defee666 100644 --- a/app/controllers/herbaria_controller.rb +++ b/app/controllers/herbaria_controller.rb @@ -106,20 +106,22 @@ def new end end - # rubocop:disable Metrics/AbcSize def edit @herbarium = find_or_goto_index(Herbarium, params[:id]) return unless @herbarium && make_sure_can_edit! - @herbarium.place_name = @herbarium.location.try(&:name) - @herbarium.personal = @herbarium.personal_user_id.present? - @herbarium.personal_user_name = @herbarium.personal_user.try(&:login) + set_up_herbarium_for_edit respond_to do |format| format.turbo_stream { render_modal_herbarium_form } format.html end end - # rubocop:enable Metrics/AbcSize + + def set_up_herbarium_for_edit + @herbarium.place_name = @herbarium.location.try(&:name) + @herbarium.personal = @herbarium.personal_user_id.present? + @herbarium.personal_user_name = @herbarium.personal_user.try(&:login) + end def render_modal_herbarium_form render(partial: "shared/modal_form", @@ -287,7 +289,6 @@ def validate_personal_herbarium! true end - # rubocop:disable Metrics/AbcSize def validate_admin_personal_user! return true unless in_admin_mode? return true if nonpersonal! @@ -308,11 +309,14 @@ def validate_admin_personal_user! flash_notice( :edit_herbarium_successfully_made_personal.t(user: user.login) ) + update_personal_herbarium(user) + end + + def update_personal_herbarium(user) @herbarium.curators.clear @herbarium.add_curator(user) @herbarium.personal_user_id = user.id end - # rubocop:enable Metrics/AbcSize # Return true/false if @herbarium nonpersonal/personal, # making it nonpersonal & flashing message if possible From 6841790d39e329ee6254142f579fe96a21411903 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 6 Aug 2024 17:23:37 -0700 Subject: [PATCH 53/89] Give autocompleters custom map outlets to avoid confusion --- app/helpers/autocompleter_helper.rb | 169 ++++++++++++++++++ app/helpers/forms_helper.rb | 145 --------------- .../controllers/autocompleter_controller.js | 8 +- app/javascript/controllers/map_controller.js | 3 + app/views/controllers/herbaria/_form.erb | 6 +- app/views/controllers/locations/_form.erb | 5 +- .../observations/form/_details.html.erb | 1 + 7 files changed, 186 insertions(+), 151 deletions(-) create mode 100644 app/helpers/autocompleter_helper.rb diff --git a/app/helpers/autocompleter_helper.rb b/app/helpers/autocompleter_helper.rb new file mode 100644 index 0000000000..a12d9dd7ba --- /dev/null +++ b/app/helpers/autocompleter_helper.rb @@ -0,0 +1,169 @@ +# frozen_string_literal: true + +# rubocop:disable Metrics/AbcSize +module AutocompleterHelper + # MO's autocompleter_field is a text_field that fetches suggestions from the + # db for the requested model. (For a textarea, pass textarea: true.) + # + # The stimulus controller handles keyboard and mouse interactions, does the + # fetching, and draws the dropdown menu. `args` allow incoming data attributes + # to deep_merge with controller data. + # + # We attempt to disable browser autocomplete via `autocomplete="off"` — the + # W3C standard API, but it has never been honored by Chrome or Safari. Chrome + # seems to be in a race to defeat the evolving hacks by developers to disable + # inappropriate autocompletes, and Safari is not much better - you just can't + # turn their crap off. (documented on SO) + # + def autocompleter_field(**args) + ac_args = { + placeholder: :start_typing.l, autocomplete: "off", + 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) + 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) + end + end + + 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] + end + + def autocompleter_wrap_data(args) + { + 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] || {}) + end + + def autocompleter_label_after(args) + capture do + [ + autocompleter_has_id_indicator, + autocompleter_find_button(args), + autocompleter_keep_button(args), + autocompleter_hidden_field(**args) + ].safe_join + end + end + + def autocompleter_label_end(args) + capture do + concat(autocompleter_create_button(args)) + concat(autocompleter_modal_create_link(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", + data: { autocompleter_target: "hasIdIndicator" }) + end + + def autocompleter_create_button(args) + return if !args[:create_text] || args[:create].present? + + icon_link_to( + args[:create_text], "#", + icon: :plus, show_text: true, icon_class: "text-primary", + name: "create_#{args[:type]}", class: "ml-3 create-button", + data: { autocompleter_target: "createBtn", + action: "autocompleter#swapCreate:prevent" } + ) + end + + def autocompleter_modal_create_link(args) + return unless args[:create_text] && args[:create].present? && + args[:create_path].present? + + modal_link_to( + args[:create], args[:create_text], args[:create_path], + icon: :plus, show_text: true, icon_class: "text-primary", + name: "create_#{args[:type]}", class: "ml-3 create-link", + data: { autocompleter_target: "createBtn" } + ) + end + + def autocompleter_find_button(args) + return unless args[:find_text] + + icon_link_to( + args[:find_text], "#", + icon: :find_on_map, show_text: false, icon_class: "text-primary", + name: "find_#{args[:type]}", class: "ml-3 d-none", + data: { map_target: "showBoxBtn", + action: "map#showBox:prevent" } + ) + end + + def autocompleter_keep_button(args) + return unless args[:keep_text] + + icon_link_to( + args[:keep_text], "#", + icon: :apply, show_text: false, icon_class: "text-primary", + active_icon: :edit, active_content: args[:edit_text], + name: "keep_#{args[:type]}", class: "ml-3 d-none", + data: { autocompleter_target: "keepBtn", map_target: "lockBoxBtn", + action: "map#toggleBoxLock:prevent" } + ) + end + + # minimum args :form, :type. + # Send :hidden to fill the id, :hidden_data to merge with hidden field data + def autocompleter_hidden_field(**args) + return unless args[:form].present? && args[:type].present? + + model = autocompleter_type_to_model(args[:type]) + data = { autocompleter_target: "hidden" }.merge(args[:hidden_data] || {}) + args[:form].hidden_field(:"#{model}_id", value: args[:hidden_value], data:) + end + + def autocompleter_type_to_model(type) + case type + when :region + :location + when :clade + :name + else + type + end + end + + def autocompleter_dropdown + tag.div(class: "auto_complete dropdown-menu", + data: { autocompleter_target: "pulldown", + action: "scroll->autocompleter#scrollList:passive" }) do + tag.ul(class: "virtual_list", data: { autocompleter_target: "list" }) do + 10.times do |i| + concat(tag.li(class: "dropdown-item") do + link_to("", "#", data: { + row: i, action: "click->autocompleter#selectRow:prevent" + }) + end) + end + end + end + end +end +# rubocop:enable Metrics/AbcSize diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index da97bad609..6e912414df 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -7,7 +7,6 @@ # helpers for form tags # rubocop:disable Metrics/ModuleLength # rubocop:disable Metrics/AbcSize -# rubocop:disable Metrics/MethodLength # rubocop:disable Metrics/CyclomaticComplexity module FormsHelper # Bootstrap submit button @@ -225,149 +224,6 @@ def text_label_row(args, label_opts) end end - # MO's autocompleter_field is a text_field that fetches suggestions from the - # db for the requested model. (For a textarea, pass textarea: true.) The - # stimulus controller handles keyboard and mouse interactions, does the - # fetching, and draws the dropdown menu. `args` allow incoming data attributes - # to deep_merge with controller data. We attempt to disable browser - # autocomplete via `autocomplete="off"` — the W3C standard API, but it - # has never been honored by Chrome or Safari. Chrome seems to be in a race to - # defeat the evolving hacks by developers to disable inappropriate - # autocompletes, and Safari is not much better - you just can't turn their - # crap off. (documented on SO) - # - def autocompleter_field(**args) - ac_args = { - placeholder: :start_typing.l, autocomplete: "off", - data: { autocompleter_target: "input" } - }.deep_merge(args.except(:wrap_data, :type, :separator, :textarea, - :hidden_value, :hidden_data, :create_text, - :keep_text, :edit_text, :find_text, :create, - :create_path)) - ac_args[:class] = class_names("dropdown", args[:class]) - ac_args[:wrap_data] = { - controller: :autocompleter, type: args[:type], - separator: args[:separator], - autocompleter_map_outlet: ".map-outlet", - autocompleter_geocode_outlet: ".geocode-outlet", - autocompleter_target: "wrap" - }.deep_merge(args[:wrap_data] || {}) - ac_args[:label_after] = capture do - [ - autocompleter_has_id_indicator, - autocompleter_find_button(args), - autocompleter_keep_button(args), - autocompleter_hidden_field(**args) - ].safe_join - end - ac_args[:label_end] = capture do - concat(autocompleter_create_button(args)) - concat(autocompleter_modal_create_link(args)) - end - ac_args[:append] = capture do - concat(autocompleter_dropdown) - concat(args[:append]) - end - - if args[:textarea] == true - text_area_with_label(**ac_args) - else - text_field_with_label(**ac_args) - 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", - data: { autocompleter_target: "hasIdIndicator" }) - end - - def autocompleter_create_button(args) - return if !args[:create_text] || args[:create].present? - - icon_link_to( - args[:create_text], "#", - icon: :plus, show_text: true, icon_class: "text-primary", - name: "create_#{args[:type]}", class: "ml-3 create-button", - data: { autocompleter_target: "createBtn", - action: "autocompleter#swapCreate:prevent" } - ) - end - - def autocompleter_modal_create_link(args) - return unless args[:create_text] && args[:create].present? && - args[:create_path].present? - - modal_link_to( - args[:create], args[:create_text], args[:create_path], - icon: :plus, show_text: true, icon_class: "text-primary", - name: "create_#{args[:type]}", class: "ml-3 create-link", - data: { autocompleter_target: "createBtn" } - ) - end - - def autocompleter_find_button(args) - return unless args[:find_text] - - icon_link_to( - args[:find_text], "#", - icon: :find_on_map, show_text: false, icon_class: "text-primary", - name: "find_#{args[:type]}", class: "ml-3 d-none", - data: { map_target: "showBoxBtn", - action: "map#showBox:prevent" } - ) - end - - def autocompleter_keep_button(args) - return unless args[:keep_text] - - icon_link_to( - args[:keep_text], "#", - icon: :apply, show_text: false, icon_class: "text-primary", - active_icon: :edit, active_content: args[:edit_text], - name: "keep_#{args[:type]}", class: "ml-3 d-none", - data: { autocompleter_target: "keepBtn", map_target: "lockBoxBtn", - action: "map#toggleBoxLock:prevent" } - ) - end - - # minimum args :form, :type. - # Send :hidden to fill the id, :hidden_data to merge with hidden field data - def autocompleter_hidden_field(**args) - return unless args[:form].present? && args[:type].present? - - model = autocompleter_type_to_model(args[:type]) - data = { autocompleter_target: "hidden" }.merge(args[:hidden_data] || {}) - args[:form].hidden_field(:"#{model}_id", value: args[:hidden_value], data:) - end - - def autocompleter_type_to_model(type) - case type - when :region - :location - when :clade - :name - else - type - end - end - - def autocompleter_dropdown - tag.div(class: "auto_complete dropdown-menu", - data: { autocompleter_target: "pulldown", - action: "scroll->autocompleter#scrollList:passive" }) do - tag.ul(class: "virtual_list", data: { autocompleter_target: "list" }) do - 10.times do |i| - concat(tag.li(class: "dropdown-item") do - link_to("", "#", data: { - row: i, action: "click->autocompleter#selectRow:prevent" - }) - end) - end - end - end - end - # Bootstrap select. # Works for select_year but not date_select, which generates multiple selects def select_with_label(**args) @@ -694,5 +550,4 @@ def separate_field_options_from_args(args, extras = []) end # rubocop:enable Metrics/ModuleLength # rubocop:enable Metrics/AbcSize -# rubocop:enable Metrics/MethodLength # rubocop:enable Metrics/CyclomaticComplexity diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index da2b032e5b..906fa78ada 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -232,12 +232,12 @@ export default class extends Controller { this.matches = []; this.stored_data = { id: 0 }; this.last_fetch_params = ''; - this.prepareInputElement(); - this.prepareHiddenInput(); if (!this.hasKeepBtnTarget || !this.keepBtnTarget?.classList?.contains('active')) { this.clearHiddenId(); } + this.prepareInputElement(); + this.prepareHiddenInput(); this.constrainedSelectionUI(); } } @@ -245,11 +245,13 @@ export default class extends Controller { constrainedSelectionUI() { const outlet_class = this.appropriateOutletClass(); if (this.TYPE === "location_google") { + this.verbose("autocompleter: location_google swap"); this.inputTarget.closest("form").classList.add(outlet_class); this.element.classList.add('create'); this.element.classList.remove('offer-create'); this.element.classList.remove('constrained'); } else if (this.ACT_LIKE_SELECT) { + this.verbose("autocompleter: ACT_LIKE_SELECT swap"); this.inputTarget.closest("form").classList.remove(outlet_class); // primer is not based on input, so go ahead and request from server. this.focused = true; // so it will draw the pulldown immediately @@ -257,8 +259,8 @@ export default class extends Controller { this.element.classList.add('constrained'); this.element.classList.remove('create'); } else { - this.inputTarget.closest("form").classList.remove(outlet_class); this.verbose("autocompleter: regular swap"); + this.inputTarget.closest("form").classList.remove(outlet_class); this.scheduleRefresh(); this.element.classList.remove('constrained', 'create'); } diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index d38ce868b0..bd1223cfaa 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -558,6 +558,9 @@ export default class extends GeocodeController { // this.showBoxBtnTarget.disabled = false } this.dispatch("reenableBtns") + // FIXME: This is a problem when there are two maps on the page. + // It emits the event to both maps, but only one should respond. + // Button should have an action instead that only affects the map it's in. this.dispatchPointChanged({ lat: null, lng: null }) } diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index d401fd30a6..65b2b4e100 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -82,9 +82,13 @@ end append:, hidden_data: { map_target: "locationId" }, create_text: :form_observations_create_locality.l, + map_outlet: "herbarium_form_map", data: { map_target: "placeInput", - action: "map:googlePrimer@window->autocompleter#refreshGooglePrimer" + action: [ + "map:pointChanged@window->autocompleter#swap", + "map:googlePrimer@window->autocompleter#refreshGooglePrimer" + ] } ) %> diff --git a/app/views/controllers/locations/_form.erb b/app/views/controllers/locations/_form.erb index 78d32f7a29..f21a0672e7 100644 --- a/app/views/controllers/locations/_form.erb +++ b/app/views/controllers/locations/_form.erb @@ -22,7 +22,8 @@ when "edit", "update" end form_args = { - model: @location, url: url_params, id: "location_form" + model: @location, url: url_params, id: "location_form", + data: { controller: "map" } } if local_assigns[:local] == true @@ -43,7 +44,7 @@ map_args = { editable: true, map_type: "location" } <%# NOTE: All other Stimulus data is on the map div, but we need the fields inside the controller scope, so map has controller: nil %> - <%= tag.div(class: "row", data: { controller: "map" }) do %> + <%= tag.div(class: "row") do %> <%= tag.div(class: "col-md-8 col-lg-6") do %> <%= render(partial: "locations/form/fields", locals: { f:, button:, location: @location, diff --git a/app/views/controllers/observations/form/_details.html.erb b/app/views/controllers/observations/form/_details.html.erb index 855491a2de..5c8f545516 100644 --- a/app/views/controllers/observations/form/_details.html.erb +++ b/app/views/controllers/observations/form/_details.html.erb @@ -74,6 +74,7 @@ t_s = { create_text: :form_observations_create_locality.l, keep_text: :form_observations_use_locality.l, edit_text: :form_observations_edit_locality.l, + map_outlet: "#observation_form_map", # find_text: :form_locations_find_on_map.l, data: { map_target: "placeInput", From 87fa4d02b6f5f4885d7703749fa0cfac32fe25af Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 6 Aug 2024 22:30:18 -0700 Subject: [PATCH 54/89] Try to straighten out action events to outlet actions --- app/helpers/autocompleter_helper.rb | 1 + app/helpers/forms_helper.rb | 4 +-- .../controllers/autocompleter_controller.js | 1 + .../controllers/geocode_controller.js | 33 ++++++++++++++----- app/views/controllers/herbaria/_form.erb | 8 +++-- .../controllers/observations/_form.html.erb | 2 ++ .../observations/form/_details.html.erb | 8 +++-- .../controllers/shared/_form_location_map.erb | 5 +++ 8 files changed, 48 insertions(+), 14 deletions(-) diff --git a/app/helpers/autocompleter_helper.rb b/app/helpers/autocompleter_helper.rb index a12d9dd7ba..aeb7cddca1 100644 --- a/app/helpers/autocompleter_helper.rb +++ b/app/helpers/autocompleter_helper.rb @@ -33,6 +33,7 @@ def autocompleter_field(**args) 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, diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index 6e912414df..d0249db2bc 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -166,7 +166,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) do + tag.div(class: wrap_class, data: wrap_data, id: args[:wrap_id]) do concat(text_label_row(args, label_opts)) if args[:addon].present? # text addon, not interactive concat(tag.div(class: "input-group") do @@ -542,7 +542,7 @@ def separate_field_options_from_args(args, extras = []) exceptions = [ :form, :field, :label, :class, :width, :inline, :between, :label_after, :label_end, :append, :help, :addon, :optional, :required, :monospace, - :type, :wrap_data, :button, :button_data + :type, :wrap_data, :wrap_id, :button, :button_data ] + extras args.clone.except(*exceptions) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 906fa78ada..1974ee64c2 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -210,6 +210,7 @@ export default class extends Controller { // Callable internally if you pass a detail object with a type property. // swap({ detail }) { + debugger; let type; if (this.hasSelectTarget) { type = this.selectTarget.value; diff --git a/app/javascript/controllers/geocode_controller.js b/app/javascript/controllers/geocode_controller.js index a18f746516..f97a0c5877 100644 --- a/app/javascript/controllers/geocode_controller.js +++ b/app/javascript/controllers/geocode_controller.js @@ -10,6 +10,7 @@ export default class extends Controller { static targets = ["southInput", "westInput", "northInput", "eastInput", "highInput", "lowInput", "placeInput", "locationId", "latInput", "lngInput", "altInput", "getElevation"] + static outlets = ["autocompleter"] connect() { this.element.dataset.stimulus = "connected" @@ -122,6 +123,7 @@ export default class extends Controller { } // Build a primer for the autocompleter with bounding box data, but -1 id + // FIXME: rename this function dispatchPrimer(results) { let north, south, east, west, name, id = -1 // Prefer geometry.bounds, but bounds do not exist for point locations. @@ -139,7 +141,11 @@ export default class extends Controller { this.verbose("geocode:dispatchPrimer") this.verbose(primer) - this.dispatch("googlePrimer", { detail: { primer } }) + // FIXME: this should call autocompleter#refreshGooglePrimer directly + if (this.hasAutocompleterOutlet) { + this.autocompleterOutlet.refreshGooglePrimer({ primer }) + } + // this.dispatch("googlePrimer", { detail: { primer } }) } // Format the address components for MO style. @@ -360,17 +366,25 @@ export default class extends Controller { } // Call the swap event on the autocompleter and send the type we need + // FIXME: rename this function dispatchPointChanged({ lat, lng }) { this.clearAutocompleterSwapBuffer() if (lat && lng) { this.autocomplete_buffer = setTimeout(() => { - this.dispatch("pointChanged", { - detail: { - type: "location_containing", - request_params: { lat, lng }, - } - }) + // FIXME: Instead of dispatching a pointChanged event, we should + // call the swap method in the paired autocompleter controller. + // this.dispatch("pointChanged", { + // detail: { + // type: "location_containing", + // request_params: { lat, lng }, + // } + // }) + if (this.hasAutocompleterOutlet) { + this.autocompleterOutlet.swap( + { type: "location_containing", request_params: { lat, lng } } + ) + } // this.verbose("geocode:dispatchPointChanged") }, 1000) @@ -385,7 +399,10 @@ export default class extends Controller { // } } else { this.autocomplete_buffer = setTimeout(() => { - this.dispatch("pointChanged", { detail: { type: "location" } }) + // this.dispatch("pointChanged", { detail: { type: "location" } }) + if (this.hasAutocompleterOutlet) { + this.autocompleterOutlet.swap({ type: "location" }) + } }, 1000) } } diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 65b2b4e100..47a73fbf8a 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -26,6 +26,7 @@ end model: @herbarium, id: "herbarium_form", class: "map-outlet", data: { controller: "map", + map_autocompleter_outlet: "herbarium_location_autocompleter", action: "autocompleter:hiddenIdDataChanged@window->map#showBox" } ) do |f| %> @@ -78,15 +79,18 @@ end tag.span("#{:form_observations_create_locality.l}:", class: "create-label")].safe_join(" "), wrap_data: { map_target: "autocompleter" }, + wrap_id: "herbarium_location_autocompleter", between: :optional, append:, hidden_data: { map_target: "locationId" }, create_text: :form_observations_create_locality.l, - map_outlet: "herbarium_form_map", + map_outlet: "#herbarium_form_map", + # FIXME: there are two maps, and either map action could affect this + # autocompleter. Map needs to use its own autocompleter outlet data: { map_target: "placeInput", action: [ - "map:pointChanged@window->autocompleter#swap", + # "map:pointChanged@window->autocompleter#swap", "map:googlePrimer@window->autocompleter#refreshGooglePrimer" ] } diff --git a/app/views/controllers/observations/_form.html.erb b/app/views/controllers/observations/_form.html.erb index 2ee258a907..c9399128db 100644 --- a/app/views/controllers/observations/_form.html.erb +++ b/app/views/controllers/observations/_form.html.erb @@ -19,8 +19,10 @@ image_upload_localization = { show_on_map: :show_on_map.t, something_went_wrong: :form_observations_upload_error.t }.to_json +# Actions are for the way these three stimulus controllers communicate data = { controller: "form-images form-exif map", + map_autocompleter_outlet: "#observation_location_autocompleter", action: [ "map:reenableBtns@window->form-exif#reenableButtons", "form-exif:pointChanged@window->map#calculateMarker", diff --git a/app/views/controllers/observations/form/_details.html.erb b/app/views/controllers/observations/form/_details.html.erb index 5c8f545516..e135709d40 100644 --- a/app/views/controllers/observations/form/_details.html.erb +++ b/app/views/controllers/observations/form/_details.html.erb @@ -74,12 +74,16 @@ t_s = { create_text: :form_observations_create_locality.l, keep_text: :form_observations_use_locality.l, edit_text: :form_observations_edit_locality.l, - map_outlet: "#observation_form_map", # 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", + # FIXME: any map action could affect this autocompleter. + # Map needs to use its own autocompleter outlet data: { map_target: "placeInput", action: [ - "map:pointChanged@window->autocompleter#swap", + # "map:pointChanged@window->autocompleter#swap", "form-exif:pointChanged@window->autocompleter#swap", "map:googlePrimer@window->autocompleter#refreshGooglePrimer" ].join(" ") diff --git a/app/views/controllers/shared/_form_location_map.erb b/app/views/controllers/shared/_form_location_map.erb index b62552689c..b445fd500a 100644 --- a/app/views/controllers/shared/_form_location_map.erb +++ b/app/views/controllers/shared/_form_location_map.erb @@ -1,5 +1,10 @@ <%# locals: (id: "", map_type: "location") -%> +<%# +The stimulus controller for this map needs to be on an ancestor element +that also contains the inputs +%> + <%= tag.div( "", id:, class: "form-map collapse", From 6dd575ba3dd50dd3a53bff28e9abe90227d1ab4a Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 7 Aug 2024 11:20:48 -0700 Subject: [PATCH 55/89] Use .map-outlet class also with id --- app/javascript/controllers/autocompleter_controller.js | 3 ++- app/views/controllers/herbaria/_form.erb | 2 +- app/views/controllers/shared/_form_location_map.erb | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 1974ee64c2..77a32278a9 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -210,7 +210,6 @@ export default class extends Controller { // Callable internally if you pass a detail object with a type property. // swap({ detail }) { - debugger; let type; if (this.hasSelectTarget) { type = this.selectTarget.value; @@ -267,6 +266,8 @@ export default class extends Controller { } } + // The autocompleter is paired with map controller by id, but only if this + // class is added. This allows us to hook events on mapOutletConnected. appropriateOutletClass() { if (this.hasMap) { return 'map-outlet'; diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 47a73fbf8a..b069829d5c 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -84,7 +84,7 @@ end append:, hidden_data: { map_target: "locationId" }, create_text: :form_observations_create_locality.l, - map_outlet: "#herbarium_form_map", + map_outlet: "#herbarium_form_map.map-outlet", # FIXME: there are two maps, and either map action could affect this # autocompleter. Map needs to use its own autocompleter outlet data: { diff --git a/app/views/controllers/shared/_form_location_map.erb b/app/views/controllers/shared/_form_location_map.erb index b445fd500a..0fb5a0a0e4 100644 --- a/app/views/controllers/shared/_form_location_map.erb +++ b/app/views/controllers/shared/_form_location_map.erb @@ -1,8 +1,8 @@ <%# locals: (id: "", map_type: "location") -%> <%# -The stimulus controller for this map needs to be on an ancestor element -that also contains the inputs +The stimulus controller for this map should be +on an ancestor element that also contains the inputs %> <%= tag.div( From 19aff88c25d99bd8c738b6ffb42fa03c7e0fae43 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 7 Aug 2024 11:21:24 -0700 Subject: [PATCH 56/89] Use .map-outlet and fix field addons for obs form --- .../controllers/observations/form/_details.html.erb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/controllers/observations/form/_details.html.erb b/app/views/controllers/observations/form/_details.html.erb index e135709d40..b59f188df9 100644 --- a/app/views/controllers/observations/form/_details.html.erb +++ b/app/views/controllers/observations/form/_details.html.erb @@ -4,9 +4,9 @@ including location autocomplete, map, lat/long/alt %> <% t_s = { - lat: { abbr: :LAT.l, full: :LATITUDE.l }, - lng: { abbr: :LNG.l, full: :LONGITUDE.l }, - alt: { abbr: :ALT.l, full: :ALTITUDE.l } + lat: { abbr: :LAT.l, full: :LATITUDE.l, addon: "º" }, + lng: { abbr: :LNG.l, full: :LONGITUDE.l, addon: "º" }, + alt: { abbr: :ALT.l, full: :ALTITUDE.l, addon: "m" } } %> @@ -32,7 +32,7 @@ t_s = { <% [: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: "º", + 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") @@ -76,7 +76,7 @@ t_s = { edit_text: :form_observations_edit_locality.l, # find_text: :form_locations_find_on_map.l, # Be precise about which map controller to connect to: - map_outlet: "#observation_form", + map_outlet: "#observation_form.map-outlet", wrap_id: "observation_location_autocompleter", # FIXME: any map action could affect this autocompleter. # Map needs to use its own autocompleter outlet From 343ad9c34a75eef00f6ea0994c5d8f13bdd9b557 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 7 Aug 2024 16:07:02 -0700 Subject: [PATCH 57/89] Switch from outlet_class --- .../controllers/autocompleter_controller.js | 94 +++++++++++-------- .../controllers/form-exif_controller.js | 25 +++-- .../controllers/geocode_controller.js | 14 ++- app/views/controllers/herbaria/_form.erb | 14 ++- .../controllers/observations/_form.html.erb | 8 +- .../observations/form/_details.html.erb | 4 +- 6 files changed, 93 insertions(+), 66 deletions(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 77a32278a9..768e00d378 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -243,16 +243,23 @@ export default class extends Controller { } constrainedSelectionUI() { - const outlet_class = this.appropriateOutletClass(); + // const outlet_class = this.appropriateOutletClass(); if (this.TYPE === "location_google") { this.verbose("autocompleter: location_google swap"); - this.inputTarget.closest("form").classList.add(outlet_class); + // Instead of adding outlet class, call stuff in mapOutletConnected + this.activateMapOutlet(); + // this.inputTarget.closest("form").classList.add(outlet_class); this.element.classList.add('create'); this.element.classList.remove('offer-create'); this.element.classList.remove('constrained'); + if (this.hasMapWrapTarget) { + this.mapWrapTarget.classList.remove('d-none'); + } } else if (this.ACT_LIKE_SELECT) { this.verbose("autocompleter: ACT_LIKE_SELECT swap"); - this.inputTarget.closest("form").classList.remove(outlet_class); + // Instead of removing outlet class, call stuff in mapOutletDisconnected + this.deactivateMapOutlet(); + // this.inputTarget.closest("form").classList.remove(outlet_class); // primer is not based on input, so go ahead and request from server. this.focused = true; // so it will draw the pulldown immediately this.refreshPrimer(); // directly refresh the primer w/request_params @@ -260,7 +267,9 @@ export default class extends Controller { this.element.classList.remove('create'); } else { this.verbose("autocompleter: regular swap"); - this.inputTarget.closest("form").classList.remove(outlet_class); + // Instead of removing outlet class, call stuff in mapOutletDisconnected + this.deactivateMapOutlet(); + // this.inputTarget.closest("form").classList.remove(outlet_class); this.scheduleRefresh(); this.element.classList.remove('constrained', 'create'); } @@ -268,13 +277,13 @@ export default class extends Controller { // The autocompleter is paired with map controller by id, but only if this // class is added. This allows us to hook events on mapOutletConnected. - appropriateOutletClass() { - if (this.hasMap) { - return 'map-outlet'; - } else if (this.hasGeocode) { - return 'geocode-outlet'; - } - } + // appropriateOutletClass() { + // if (this.hasMap) { + // return 'map-outlet'; + // } else if (this.hasGeocode) { + // return 'geocode-outlet'; + // } + // } swapCreate() { // this.createBtnTarget.classList.add('d-none'); @@ -282,33 +291,37 @@ export default class extends Controller { } // Connects the location_google autocompleter to call map controller methods - mapOutletConnected(outlet, element) { - this.verbose("autocompleter:mapOutletConnected()"); + activateMapOutlet() { + if (!this.hasMapOutlet) return; + + this.verbose("autocompleter:activateMapOutlet()"); // open the map if not already open - if (!outlet.opened && !outlet.hasAutocompleterTarget) - outlet.toggleMapBtnTarget.click(); + if (!this.mapOutlet.opened && !this.mapOutlet.hasAutocompleterTarget) + this.mapOutlet.toggleMapBtnTarget.click(); // set the map type so box is editable - outlet.map_type = "hybrid"; // only if location_google + this.mapOutlet.map_type = "hybrid"; // only if location_google let location - if (location = outlet.validateLatLngInputs(false)) { - outlet.geocodeLatLng(location); - } else if (outlet.hasLockBoxBtnTarget) { - outlet.lockBoxBtnTarget.classList.remove("d-none"); + if (location = this.mapOutlet.validateLatLngInputs(false)) { + this.mapOutlet.geocodeLatLng(location); + } else if (this.mapOutlet.hasLockBoxBtnTarget) { + this.mapOutlet.lockBoxBtnTarget.classList.remove("d-none"); } } - mapOutletDisconnected(outlet, element) { - this.verbose("autocompleter: map outlet disconnected"); - outlet.map_type = "observation"; - if (outlet.rectangle) outlet.rectangle.setEditable(false); + deactivateMapOutlet() { + if (!this.hasMapOutlet) return; - outlet.northInputTarget.value = ''; - outlet.southInputTarget.value = ''; - outlet.eastInputTarget.value = ''; - outlet.westInputTarget.value = ''; - outlet.highInputTarget.value = ''; - outlet.lowInputTarget.value = ''; + this.verbose("autocompleter: deactivateMapOutlet()"); + this.mapOutlet.map_type = "observation"; + if (this.mapOutlet.rectangle) this.mapOutlet.rectangle.setEditable(false); + + this.mapOutlet.northInputTarget.value = ''; + this.mapOutlet.southInputTarget.value = ''; + this.mapOutlet.eastInputTarget.value = ''; + this.mapOutlet.westInputTarget.value = ''; + this.mapOutlet.highInputTarget.value = ''; + this.mapOutlet.lowInputTarget.value = ''; } // pulldownTargetConnected() { @@ -567,9 +580,10 @@ export default class extends Controller { this.verbose("autocompleter:scheduleGoogleRefresh()"); this.clearRefresh(); this.refresh_timer = setTimeout((() => { - this.verbose("autocompleter:doing_google_refresh()"); + this.verbose("autocompleter: doing google refresh"); this.verbose(this.inputTarget.value); this.old_value = this.inputTarget.value; + debugger; // async, anything after this executes immediately if (this.hasGeocodeOutlet) { this.geocodeOutlet.geolocatePlaceName(this.inputTarget.value); @@ -1022,6 +1036,7 @@ export default class extends Controller { } // called on assign and clear, also when mapOutlet is connected + // FIXME: rename this function dispatchHiddenIdEvents() { const hidden_id = parseInt(this.hiddenTarget.value || 0), // stored_id = parseInt(this.stored_id || 0), @@ -1031,19 +1046,22 @@ export default class extends Controller { this.verbose("autocompleter:hidden_data: " + JSON.stringify(hidden_data)); // comparing data, not just ids, because google locations have same -1 id if (JSON.stringify(hidden_data) == JSON.stringify(this.stored_data)) { - this.verbose("autocompleter: not dispatching hiddenIdDataChanged"); + this.verbose("autocompleter: hidden data did not change"); } else { clearTimeout(this.data_timer); this.data_timer = setTimeout(() => { - this.verbose("autocompleter: dispatching hiddenIdDataChanged"); + this.verbose("autocompleter: hidden data changed"); this.cssHasIdOrNo(hidden_id); if (this.hasKeepBtnTarget) { this.keepBtnTarget.classList.remove('active'); } this.inputTarget.focus(); - this.dispatch('hiddenIdDataChanged', { - detail: { id: this.hiddenTarget.value } - }); + if (this.hasMapOutlet) { + this.mapOutlet.showBox(); + } + // this.dispatch('hiddenIdDataChanged', { + // detail: { id: this.hiddenTarget.value } + // }); }, 750) } } @@ -1470,8 +1488,8 @@ export default class extends Controller { } // Map controller sends back a primer formatted for the autocompleter - refreshGooglePrimer({ detail }) { - this.processFetchResponse(detail.primer) + refreshGooglePrimer({ primer }) { + this.processFetchResponse(primer) } // Process response from server: diff --git a/app/javascript/controllers/form-exif_controller.js b/app/javascript/controllers/form-exif_controller.js index 960edfa59a..ade851fadf 100644 --- a/app/javascript/controllers/form-exif_controller.js +++ b/app/javascript/controllers/form-exif_controller.js @@ -14,6 +14,7 @@ const internalConfig = { // Connects to data-controller="form-exif" export default class extends Controller { static targets = ["carousel", "item", "useExifBtn"] + static outlets = ["autocompleter", "map"] connect() { this.element.dataset.stimulus = "connected"; @@ -166,13 +167,23 @@ export default class extends Controller { _obs_lng.value = lng == null ? lng : lng.toFixed(4); _obs_alt.value = alt == null ? alt : alt.toFixed(0); - // should trigger change to update the map - this.dispatch("pointChanged", { - detail: { - type: "location_containing", - request_params: { lat, lng } - } - }); + // should trigger change to update the autocompleter and the map + if (this.hasAutocompleterOutlet) { + this.autocompleterOutlet.swap({ + detail: { type: "location_containing", request_params: { lat, lng } } + }); + } + if (this.hasMapOutlet) { + this.mapOutlet.calculateMarker( + { detail: { request_params: { lat, lng } } } + ); + } + // this.dispatch("pointChanged", { + // detail: { + // type: "location_containing", + // request_params: { lat, lng } + // } + // }); } if (_exif_data.exif_date) { const _exifSimpleDate = JSON.parse(_exif_data.exif_date); diff --git a/app/javascript/controllers/geocode_controller.js b/app/javascript/controllers/geocode_controller.js index f97a0c5877..b08721fadd 100644 --- a/app/javascript/controllers/geocode_controller.js +++ b/app/javascript/controllers/geocode_controller.js @@ -65,7 +65,7 @@ export default class extends Controller { let { results } = result // destructure, results is part of the result results = this.siftResults(results) this.ignorePlaceInput = true - this.dispatchPrimer(results) + this.sendPrimer(results) this.respondToGeocode(results) }) .catch((e) => { @@ -94,7 +94,7 @@ export default class extends Controller { .geocode({ address: address }) .then((result) => { const { results } = result // destructure, results is part of the result - this.dispatchPrimer(results) // will be ignored by non-autocompleters + this.sendPrimer(results) // will be ignored by non-autocompleters this.respondToGeocode(results) }) .catch((e) => { @@ -104,7 +104,7 @@ export default class extends Controller { } // Remove certain types of results from the geocoder response: - // both too precise and too general, before dispatchPrimer + // both too precise and too general, before sendPrimer siftResults(results) { if (results.length == 0) return results @@ -123,8 +123,7 @@ export default class extends Controller { } // Build a primer for the autocompleter with bounding box data, but -1 id - // FIXME: rename this function - dispatchPrimer(results) { + sendPrimer(results) { let north, south, east, west, name, id = -1 // Prefer geometry.bounds, but bounds do not exist for point locations. // MO locations must be boxes, so use viewport if bounds null. @@ -138,14 +137,13 @@ export default class extends Controller { name = this.formatMOPlaceName(result) return { name, north, south, east, west, id } }) - this.verbose("geocode:dispatchPrimer") + this.verbose("geocode:sendPrimer") this.verbose(primer) - // FIXME: this should call autocompleter#refreshGooglePrimer directly + // Call autocompleter#refreshGooglePrimer directly if (this.hasAutocompleterOutlet) { this.autocompleterOutlet.refreshGooglePrimer({ primer }) } - // this.dispatch("googlePrimer", { detail: { primer } }) } // Format the address components for MO style. diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index b069829d5c..99932cb35f 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -23,11 +23,11 @@ end %> <%= form_with( - model: @herbarium, id: "herbarium_form", class: "map-outlet", + model: @herbarium, id: "herbarium_form", data: { controller: "map", map_autocompleter_outlet: "herbarium_location_autocompleter", - action: "autocompleter:hiddenIdDataChanged@window->map#showBox" + # action: "autocompleter:hiddenIdDataChanged@window->map#showBox" } ) do |f| %> @@ -84,15 +84,13 @@ end append:, hidden_data: { map_target: "locationId" }, create_text: :form_observations_create_locality.l, - map_outlet: "#herbarium_form_map.map-outlet", - # FIXME: there are two maps, and either map action could affect this - # autocompleter. Map needs to use its own autocompleter outlet + map_outlet: "#herbarium_form", data: { map_target: "placeInput", - action: [ + # action: [ # "map:pointChanged@window->autocompleter#swap", - "map:googlePrimer@window->autocompleter#refreshGooglePrimer" - ] + # "map:googlePrimer@window->autocompleter#refreshGooglePrimer" + # ] } ) %> diff --git a/app/views/controllers/observations/_form.html.erb b/app/views/controllers/observations/_form.html.erb index c9399128db..fc5c4d31fe 100644 --- a/app/views/controllers/observations/_form.html.erb +++ b/app/views/controllers/observations/_form.html.erb @@ -19,14 +19,16 @@ image_upload_localization = { show_on_map: :show_on_map.t, something_went_wrong: :form_observations_upload_error.t }.to_json -# Actions are for the way these three stimulus controllers communicate +# Outlets are how the stimulus controllers call each others' methods. data = { controller: "form-images form-exif map", map_autocompleter_outlet: "#observation_location_autocompleter", + form_exif_autocompleter_outlet: "#observation_location_autocompleter", + form_exif_map_outlet: "#observation_form", action: [ "map:reenableBtns@window->form-exif#reenableButtons", - "form-exif:pointChanged@window->map#calculateMarker", - "autocompleter:hiddenIdDataChanged@window->map#showBox", + # "form-exif:pointChanged@window->map#calculateMarker", + # "autocompleter:hiddenIdDataChanged@window->map#showBox", ].join(" "), upload_max_size: max_size, localization: image_upload_localization, diff --git a/app/views/controllers/observations/form/_details.html.erb b/app/views/controllers/observations/form/_details.html.erb index 5aa3e5ea03..b32c088215 100644 --- a/app/views/controllers/observations/form/_details.html.erb +++ b/app/views/controllers/observations/form/_details.html.erb @@ -75,7 +75,7 @@ t_s = { edit_text: :form_observations_edit_locality.l, # find_text: :form_locations_find_on_map.l, # Be precise about which map controller to connect to: - map_outlet: "#observation_form.map-outlet", + map_outlet: "#observation_form", wrap_id: "observation_location_autocompleter", # FIXME: any map action could affect this autocompleter. # Map needs to use its own autocompleter outlet @@ -84,7 +84,7 @@ t_s = { action: [ # "map:pointChanged@window->autocompleter#swap", "form-exif:pointChanged@window->autocompleter#swap", - "map:googlePrimer@window->autocompleter#refreshGooglePrimer" + # "map:googlePrimer@window->autocompleter#refreshGooglePrimer" ].join(" ") } ) %> From 5e29b9db6469967366b1ad3757daa1a6d2c0fc3b Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 7 Aug 2024 18:53:12 -0700 Subject: [PATCH 58/89] add map_open arg, debug map, autocompleter --- app/helpers/map_helper.rb | 1 + .../controllers/autocompleter_controller.js | 17 ++++++++++++----- app/javascript/controllers/map_controller.js | 7 ++----- app/views/controllers/herbaria/_form.erb | 2 +- app/views/controllers/locations/_form.erb | 2 +- .../controllers/observations/_form.html.erb | 1 + 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/app/helpers/map_helper.rb b/app/helpers/map_helper.rb index f96a851590..b2814975b9 100644 --- a/app/helpers/map_helper.rb +++ b/app/helpers/map_helper.rb @@ -17,6 +17,7 @@ def make_map(objects: [], **args) controller: "map", map_target: "mapDiv", map_type: "info", + map_open: true, editable: false, controls: [:large_map, :map_type].to_json, location_format: User.current_location_format # method has a default diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 768e00d378..2b78671a81 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -246,14 +246,16 @@ export default class extends Controller { // const outlet_class = this.appropriateOutletClass(); if (this.TYPE === "location_google") { this.verbose("autocompleter: location_google swap"); - // Instead of adding outlet class, call stuff in mapOutletConnected - this.activateMapOutlet(); - // this.inputTarget.closest("form").classList.add(outlet_class); this.element.classList.add('create'); this.element.classList.remove('offer-create'); this.element.classList.remove('constrained'); if (this.hasMapWrapTarget) { this.mapWrapTarget.classList.remove('d-none'); + // Instead of adding outlet class, call stuff in mapOutletConnected + this.activateMapOutlet(); + // this.inputTarget.closest("form").classList.add(outlet_class); + } else { + this.verbose("autocompleter: no map wrap"); } } else if (this.ACT_LIKE_SELECT) { this.verbose("autocompleter: ACT_LIKE_SELECT swap"); @@ -292,12 +294,17 @@ export default class extends Controller { // Connects the location_google autocompleter to call map controller methods activateMapOutlet() { - if (!this.hasMapOutlet) return; + if (!this.hasMapOutlet) { + this.verbose("autocompleter: no map outlet"); + return; + } this.verbose("autocompleter:activateMapOutlet()"); // open the map if not already open - if (!this.mapOutlet.opened && !this.mapOutlet.hasAutocompleterTarget) + if (!this.mapOutlet.opened && this.mapOutlet.hasToggleMapBtnTarget) { + this.verbose("autocompleter: open map"); this.mapOutlet.toggleMapBtnTarget.click(); + } // set the map type so box is editable this.mapOutlet.map_type = "hybrid"; // only if location_google diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index bd1223cfaa..db6b94ce7c 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -18,7 +18,7 @@ export default class extends GeocodeController { this.element.dataset.stimulus = "connected" this.map_type = this.mapDivTarget.dataset.mapType this.editable = (this.mapDivTarget.dataset.editable === "true") - this.opened = this.map_type !== "observation" + this.opened = this.element.dataset.mapOpen === "true" this.marker = null // Only gets set if we're in edit mode this.rectangle = null // Only gets set if we're in edit mode this.location_format = this.mapDivTarget.dataset.locationFormat @@ -511,7 +511,7 @@ export default class extends GeocodeController { if (this.map == undefined) { this.drawMap() this.makeMapClickable() - } else { + } else if (this.mapBounds) { this.map.fitBounds(this.mapBounds) } @@ -558,9 +558,6 @@ export default class extends GeocodeController { // this.showBoxBtnTarget.disabled = false } this.dispatch("reenableBtns") - // FIXME: This is a problem when there are two maps on the page. - // It emits the event to both maps, but only one should respond. - // Button should have an action instead that only affects the map it's in. this.dispatchPointChanged({ lat: null, lng: null }) } diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 99932cb35f..5ddfb829f1 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -25,7 +25,7 @@ end <%= form_with( model: @herbarium, id: "herbarium_form", data: { - controller: "map", + controller: "map", map_open: false, map_autocompleter_outlet: "herbarium_location_autocompleter", # action: "autocompleter:hiddenIdDataChanged@window->map#showBox" } diff --git a/app/views/controllers/locations/_form.erb b/app/views/controllers/locations/_form.erb index f21a0672e7..15ae513ab1 100644 --- a/app/views/controllers/locations/_form.erb +++ b/app/views/controllers/locations/_form.erb @@ -23,7 +23,7 @@ end form_args = { model: @location, url: url_params, id: "location_form", - data: { controller: "map" } + data: { controller: "map", map_open: true } } if local_assigns[:local] == true diff --git a/app/views/controllers/observations/_form.html.erb b/app/views/controllers/observations/_form.html.erb index fc5c4d31fe..49a0a0f2f9 100644 --- a/app/views/controllers/observations/_form.html.erb +++ b/app/views/controllers/observations/_form.html.erb @@ -23,6 +23,7 @@ image_upload_localization = { data = { controller: "form-images form-exif map", map_autocompleter_outlet: "#observation_location_autocompleter", + map_open: false, form_exif_autocompleter_outlet: "#observation_location_autocompleter", form_exif_map_outlet: "#observation_form", action: [ From 87d2866c83f2e392e603dd194831b2bd1814c7fb Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 7 Aug 2024 19:11:54 -0700 Subject: [PATCH 59/89] Update map_controller.js --- app/javascript/controllers/map_controller.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index db6b94ce7c..c95be4dc54 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -500,7 +500,6 @@ export default class extends GeocodeController { // open/close handled by BS collapse toggleMap() { // this.verbose("map:toggleMap") - if (this.opened) { this.opened = false this.controlWrapTarget.classList.remove("map-open") From 491ddee38f6cbbe760a616444e64dd71e7a3c933 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 7 Aug 2024 23:39:47 -0700 Subject: [PATCH 60/89] Update autocompleter_controller.js --- app/javascript/controllers/autocompleter_controller.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index b96af646aa..ab1476779e 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -229,12 +229,12 @@ export default class extends Controller { this.matches = []; this.stored_data = { id: 0 }; this.last_fetch_params = ''; + this.prepareInputElement(); + this.prepareHiddenInput(); if (!this.hasKeepBtnTarget || !this.keepBtnTarget?.classList?.contains('active')) { this.clearHiddenId(); } - this.prepareInputElement(); - this.prepareHiddenInput(); this.constrainedSelectionUI(); } } @@ -569,7 +569,6 @@ export default class extends Controller { this.verbose("autocompleter: doing google refresh"); this.verbose(this.inputTarget.value); this.old_value = this.inputTarget.value; - debugger; // async, anything after this executes immediately if (this.hasGeocodeOutlet) { this.geocodeOutlet.geolocatePlaceName(this.inputTarget.value); From e96a9b152322f54738dd12dd74169f3bc3fe47ba Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Fri, 9 Aug 2024 13:29:43 -0700 Subject: [PATCH 61/89] Use `Locationable` in HerbariaController --- app/controllers/herbaria_controller.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/controllers/herbaria_controller.rb b/app/controllers/herbaria_controller.rb index 91defee666..efdcddfc88 100644 --- a/app/controllers/herbaria_controller.rb +++ b/app/controllers/herbaria_controller.rb @@ -47,6 +47,8 @@ # View and modify Herbaria (displayed as "Fungaria") # rubocop:disable Metrics/ClassLength class HerbariaController < ApplicationController + include ::Locationable + before_action :login_required # only: [:create, :destroy, :edit, :new, :update] before_action :store_location, only: [:create, :edit, :new, :show, :update] @@ -160,8 +162,10 @@ def modal_form_action def create @herbarium = Herbarium.new(herbarium_params) normalize_parameters + create_location_object_if_new(@herbarium) return render(:new) unless validate_herbarium! + try_to_save_location_if_new(@herbarium) @herbarium.save @herbarium.add_curator(@user) if @herbarium.personal_user notify_admins_of_new_herbarium unless @herbarium.personal_user @@ -174,8 +178,10 @@ def update @herbarium.attributes = herbarium_params normalize_parameters + create_location_object_if_new(@herbarium) return unless validate_herbarium! + try_to_save_location_if_new(@herbarium) @herbarium.save redirect_to_create_location_or_referrer_or_show_location end From 63a03222d585bc4de4c2c726d9444547bdcede2e Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Fri, 9 Aug 2024 13:41:20 -0700 Subject: [PATCH 62/89] Update herbaria_controller.rb Redo sequence of location stuff --- app/controllers/herbaria_controller.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/herbaria_controller.rb b/app/controllers/herbaria_controller.rb index efdcddfc88..581acde769 100644 --- a/app/controllers/herbaria_controller.rb +++ b/app/controllers/herbaria_controller.rb @@ -163,9 +163,9 @@ def create @herbarium = Herbarium.new(herbarium_params) normalize_parameters create_location_object_if_new(@herbarium) - return render(:new) unless validate_herbarium! - try_to_save_location_if_new(@herbarium) + return render(:new) unless validate_herbarium! && !@any_errors + @herbarium.save @herbarium.add_curator(@user) if @herbarium.personal_user notify_admins_of_new_herbarium unless @herbarium.personal_user @@ -179,9 +179,9 @@ def update @herbarium.attributes = herbarium_params normalize_parameters create_location_object_if_new(@herbarium) - return unless validate_herbarium! - try_to_save_location_if_new(@herbarium) + return unless validate_herbarium! && !@any_errors + @herbarium.save redirect_to_create_location_or_referrer_or_show_location end From 7dc5d0ba80d7e0a3405b917bac46b3002dadd14b Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 20 Aug 2024 15:23:22 -0700 Subject: [PATCH 63/89] Create herbarium_form_system_test.rb --- test/system/herbarium_form_system_test.rb | 32 +++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 test/system/herbarium_form_system_test.rb diff --git a/test/system/herbarium_form_system_test.rb b/test/system/herbarium_form_system_test.rb new file mode 100644 index 0000000000..c9ea1097be --- /dev/null +++ b/test/system/herbarium_form_system_test.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require("application_system_test_case") + +class HerbariumFormSystemTest < ApplicationSystemTestCase + def test_format_new_location_name + # browser = page.driver.browser + rolf = users("rolf") + login!(rolf) + + visit("/locations/new") + assert_selector("body.locations__new") + + assert_selector("#location_display_name") + assert_button(:form_locations_find_on_map.l) + # be sure the map is loaded! + assert_selector("#map_div div div") + fill_in("location_display_name", with: "genohlac gard france") + click_button(:form_locations_find_on_map.l) + + assert_selector("#location_display_name.geocoded") + assert_field("location_display_name", + with: "Génolhac, Gard, Occitanie, France") + + assert_field("location_north", with: "44.3726") + assert_field("location_east", with: "3.985") + assert_field("location_south", with: "44.3055") + assert_field("location_west", with: "3.9113") + assert_field("location_high", with: "1388.2098") + assert_field("location_low", with: "287.8201") + end +end From 5d7c1dc293c772fca8cb30b76f86cf86ae12eb0f Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 20 Aug 2024 15:46:42 -0700 Subject: [PATCH 64/89] Form map: Remove d-none and wrap id --- app/views/controllers/herbaria/_form.erb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 5ddfb829f1..a86263d7ca 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -65,10 +65,10 @@ end <% append = capture do - tag.div(id: "herbarium_geolocation", class: "mb-5 d-none", + tag.div(class: "mb-5", data: { autocompleter_target: "mapWrap" }) do render(partial: "shared/form_location_map", - locals: { id: "herbarium_form_map" }) + locals: { id: "herbarium_form_map", map_type: "location" }) end end %> From c322b8e56371efe86f2ed29431c2e69df9d0e265 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 20 Aug 2024 15:46:56 -0700 Subject: [PATCH 65/89] Debugging, rephrasing stimulus --- .../controllers/autocompleter_controller.js | 2 +- app/javascript/controllers/map_controller.js | 63 ++++++++++++------- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 385a5abcdc..a63f1acfbc 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -1611,7 +1611,7 @@ export default class extends Controller { } verbose(str) { - // console.log(str); + console.log(str); // document.getElementById("log"). // insertAdjacentText("beforeend", str + "
"); } diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index b359df1823..86d7b899ad 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -116,6 +116,7 @@ export default class extends GeocodeController { // If we only have one marker, don't use fitBounds - it's too zoomed in. // Call setCenter, setZoom with marker position and desired zoom level. drawMap() { + this.verbose("map:drawMap") this.map = new google.maps.Map(this.mapDivTarget, this.mapOptions) if (this.mapBounds) { if (Object.keys(this.collection.sets).length == 1) { @@ -141,6 +142,7 @@ export default class extends GeocodeController { buildOverlays() { if (!this.collection) return + this.verbose("map:buildOverlays") for (const [_xywh, set] of Object.entries(this.collection.sets)) { // this.verbose({ set }) // NOTE: according to the MapSet class, location sets are always is_box. @@ -415,6 +417,7 @@ export default class extends GeocodeController { if (!this.hasLocationIdTarget || !this.locationIdTarget.dataset.north) return false + this.verbose("map:mapLocationIdData") const bounds = { north: parseFloat(this.locationIdTarget.dataset.north), south: parseFloat(this.locationIdTarget.dataset.south), @@ -436,22 +439,22 @@ export default class extends GeocodeController { const east = parseFloat(this.eastInputTarget.value) const west = parseFloat(this.westInputTarget.value) - if (!(isNaN(north) || isNaN(south) || isNaN(east) || isNaN(west))) { - this.verbose("map:calculateRectangle") - const bounds = { north: north, south: south, east: east, west: west } - if (this.rectangle) { - this.rectangle.setBounds(bounds) - } - this.map.fitBounds(bounds) + if (isNaN(north) || isNaN(south) || isNaN(east) || isNaN(west)) return false + + this.verbose("map:calculateRectangle") + const bounds = { north: north, south: south, east: east, west: west } + if (this.rectangle) { + this.rectangle.setBounds(bounds) } + this.map.fitBounds(bounds) } // Infers a rectangle from the google place, if found. (could be point/bounds) placeClosestRectangle(viewport, extents) { + this.verbose("map:placeClosestRectangle") // Prefer extents for rectangle, fallback to viewport let bounds = extents || viewport if (bounds != undefined && bounds?.north) { - this.verbose("map:placeClosestRectangle") this.placeRectangle(bounds) } // else if (center) { @@ -466,6 +469,7 @@ export default class extends GeocodeController { // called by toggleMap checkForMarker() { + this.verbose("map:checkForMarker") let center if (center = this.validateLatLngInputs(false)) { this.calculateMarker({ detail: { request_params: center } }) @@ -478,11 +482,11 @@ export default class extends GeocodeController { // so, drops a pin on that location and center. Otherwise, checks if place // input has been prepopulated and uses that to focus map and drop a marker. calculateMarker(event) { - this.verbose("map:calculateMarker") if (this.map == undefined || !this.hasLatInputTarget || this.latInputTarget.value === '' || this.lngInputTarget.value === '') return false + this.verbose("map:calculateMarker") let location if (event?.detail?.request_params) { location = event.detail.request_params @@ -501,27 +505,38 @@ export default class extends GeocodeController { toggleMap() { this.verbose("map:toggleMap") if (this.opened) { - this.opened = false - this.controlWrapTarget.classList.remove("map-open") + this.closeMap() } else { - this.opened = true - this.controlWrapTarget.classList.add("map-open") + this.openMap() + } + } - if (this.map == undefined) { - this.drawMap() - this.makeMapClickable() - } else if (this.mapBounds) { - this.map.fitBounds(this.mapBounds) - } + closeMap() { + this.verbose("map:closeMap") + this.opened = false + this.controlWrapTarget.classList.remove("map-open") + } - setTimeout(() => { - this.checkForMarker() - this.checkForBox() // regardless if point - }, 500) // wait for map to open + openMap() { + this.verbose("map:openMap") + this.opened = true + this.controlWrapTarget.classList.add("map-open") + + if (this.map == undefined) { + this.drawMap() + this.makeMapClickable() + } else if (this.mapBounds) { + this.map.fitBounds(this.mapBounds) } + + setTimeout(() => { + this.checkForMarker() + this.checkForBox() // regardless if point + }, 500) // wait for map to open } makeMapClickable() { + this.verbose("map:makeMapClickable") google.maps.event.addListener(this.map, 'click', (e) => { // this.map.addListener('click', (e) => { const location = e.latLng.toJSON() @@ -644,7 +659,7 @@ export default class extends GeocodeController { // } verbose(str) { - // console.log(str); + console.log(str); // document.getElementById("log"). // insertAdjacentText("beforeend", str + "
"); } From 5a34ac927881c984142526027a171a0f9e6c8817 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 20 Aug 2024 15:55:40 -0700 Subject: [PATCH 66/89] Autocompleter helper: Move hidden field after dropdown --- app/helpers/autocompleter_helper.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/helpers/autocompleter_helper.rb b/app/helpers/autocompleter_helper.rb index 309c480701..02fffa57cc 100644 --- a/app/helpers/autocompleter_helper.rb +++ b/app/helpers/autocompleter_helper.rb @@ -25,7 +25,7 @@ def autocompleter_field(**args) 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_dropdown + ac_args[:append] = autocompleter_append(args) tag.div(id: args[:controller_id], data: autocompleter_controller_data(args)) do @@ -61,8 +61,7 @@ def autocompleter_label_after(args) [ autocompleter_has_id_indicator, autocompleter_find_button(args), - autocompleter_keep_button(args), - autocompleter_hidden_field(**args) + autocompleter_keep_button(args) ].safe_join end end @@ -150,6 +149,11 @@ def autocompleter_type_to_model(type) end end + def autocompleter_append(args) + [autocompleter_dropdown, + autocompleter_hidden_field(**args)].safe_join + end + def autocompleter_dropdown tag.div(class: "auto_complete dropdown-menu", data: { autocompleter_target: "pulldown", From a7e98a8f10a836dab1310db256086f909039a2c6 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 20 Aug 2024 15:56:12 -0700 Subject: [PATCH 67/89] Update _form.erb --- app/views/controllers/herbaria/_form.erb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index a86263d7ca..0745967c53 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -65,8 +65,7 @@ end <% append = capture do - tag.div(class: "mb-5", - data: { autocompleter_target: "mapWrap" }) do + tag.div(class: "mb-5", data: { autocompleter_target: "mapWrap" }) do render(partial: "shared/form_location_map", locals: { id: "herbarium_form_map", map_type: "location" }) end From d24972bf8b62f77433bc82c394e9134cf47e8e22 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 20 Aug 2024 17:57:27 -0700 Subject: [PATCH 68/89] Bunch of stuff --- .../controllers/autocompleter_controller.js | 22 ++++++++++--------- .../controllers/geocode_controller.js | 6 ++++- app/javascript/controllers/map_controller.js | 10 ++++----- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index a63f1acfbc..153a4cfd76 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -299,15 +299,15 @@ export default class extends Controller { } this.verbose("autocompleter:activateMapOutlet()"); - // open the map if not already open - if (!this.mapOutlet.opened && this.mapOutlet.hasToggleMapBtnTarget) { - this.verbose("autocompleter: open map"); - this.mapOutlet.toggleMapBtnTarget.click(); - } // set the map type so box is editable this.mapOutlet.map_type = "hybrid"; // only if location_google // set the map to stop ignoring place input this.mapOutlet.ignorePlaceInput = false; + // open the map if not already open + if (!this.mapOutlet.opened && this.mapOutlet.hasToggleMapBtnTarget) { + this.verbose("autocompleter: open map"); + this.mapOutlet.openMap(); + } // Often, this swap to location_google is for geolocating place_names and // should pay attention to text only. But in some cases the swap (e.g., from @@ -600,10 +600,11 @@ export default class extends Controller { this.verbose(this.inputTarget.value); this.old_value = this.inputTarget.value; // async, anything after this executes immediately + // STORE AND COMPARE SEARCH STRING. Otherwise we're doing double lookups if (this.hasGeocodeOutlet) { - this.geocodeOutlet.geolocatePlaceName(this.inputTarget.value); + this.geocodeOutlet.tryToGeolocate(this.inputTarget.value); } else if (this.hasMapOutlet) { - this.mapOutlet.geolocatePlaceName(this.inputTarget.value); + this.mapOutlet.tryToGeolocate(this.inputTarget.value); } // still necessary if primer unchanged, as likely? // this.populateMatches(); @@ -1075,14 +1076,15 @@ export default class extends Controller { { north, south, east, west } = this.hiddenTarget.dataset, hidden_data = { id: hidden_id, north, south, east, west }; - this.verbose("autocompleter:hidden_data: " + JSON.stringify(hidden_data)); // comparing data, not just ids, because google locations have same -1 id if (JSON.stringify(hidden_data) == JSON.stringify(this.stored_data)) { - this.verbose("autocompleter: hidden data did not change"); + this.verbose("autocompleter: hidden_data did not change"); } else { clearTimeout(this.data_timer); this.data_timer = setTimeout(() => { - this.verbose("autocompleter: hidden data changed"); + this.verbose("autocompleter: hidden_data changed"); + this.verbose("autocompleter:hidden_data: ") + this.verbose(JSON.stringify(hidden_data)); this.cssHasIdOrNo(hidden_id); if (this.hasKeepBtnTarget) { this.keepBtnTarget.classList.remove('active'); diff --git a/app/javascript/controllers/geocode_controller.js b/app/javascript/controllers/geocode_controller.js index 892b06ee9c..3af085b268 100644 --- a/app/javascript/controllers/geocode_controller.js +++ b/app/javascript/controllers/geocode_controller.js @@ -45,6 +45,7 @@ export default class extends Controller { } tryToGeocode() { + this.verbose("geocode:tryToGeocode") const location = this.validateLatLngInputs(false) if (location && @@ -75,6 +76,7 @@ export default class extends Controller { } tryToGeolocate() { + this.verbose("geocode:tryToGeolocate") const address = this.placeInputTarget.value if (this.ignorePlaceInput === false && @@ -84,6 +86,8 @@ export default class extends Controller { } geolocatePlaceName(address) { + if (address == this.lastGeolocatedAddress) return false + this.lastGeolocatedAddress = address this.verbose("geocode:geolocatePlaceName") this.verbose(address) @@ -139,7 +143,7 @@ export default class extends Controller { }) this.verbose("geocode:sendPrimer") this.verbose(primer) - + debugger // Call autocompleter#refreshGooglePrimer directly if (this.hasAutocompleterOutlet) { this.autocompleterOutlet.refreshGooglePrimer({ primer }) diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index 86d7b899ad..2cb00d3717 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -403,6 +403,7 @@ export default class extends GeocodeController { } else if (["location", "hybrid"].includes(this.map_type)) { // Only geocode lat/lng if we have no location_id and not ignoring place // ...and only geolocate placeName if we have no lat/lng + // Note: is this the right logic ????????????? if (this.ignorePlaceInput !== false) { this.tryToGeocode() // multiple possible results } else { @@ -508,6 +509,10 @@ export default class extends GeocodeController { this.closeMap() } else { this.openMap() + setTimeout(() => { + this.checkForMarker() + this.checkForBox() // regardless if point + }, 500) // wait for map to open } } @@ -528,11 +533,6 @@ export default class extends GeocodeController { } else if (this.mapBounds) { this.map.fitBounds(this.mapBounds) } - - setTimeout(() => { - this.checkForMarker() - this.checkForBox() // regardless if point - }, 500) // wait for map to open } makeMapClickable() { From 4572bd4d699f7ece6c87fb6d1f2cb61a0a9c7308 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 20 Aug 2024 17:57:35 -0700 Subject: [PATCH 69/89] Fix form markup --- app/views/controllers/herbaria/_form.erb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 0745967c53..4a856b8364 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -26,7 +26,7 @@ end model: @herbarium, id: "herbarium_form", data: { controller: "map", map_open: false, - map_autocompleter_outlet: "herbarium_location_autocompleter", + map_autocompleter_outlet: "#herbarium_location_autocompleter", # action: "autocompleter:hiddenIdDataChanged@window->map#showBox" } ) do |f| %> @@ -77,8 +77,8 @@ end label: [tag.span("#{:LOCATION.l}:", class: "unconstrained-label"), tag.span("#{:form_observations_create_locality.l}:", class: "create-label")].safe_join(" "), - wrap_data: { map_target: "autocompleter" }, - wrap_id: "herbarium_location_autocompleter", + controller_data: { map_target: "autocompleter" }, + controller_id: "herbarium_location_autocompleter", between: :optional, append:, hidden_data: { map_target: "locationId" }, From 5a4aec0c82d217b34c67a88fb8266d609e820156 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 20 Aug 2024 21:28:30 -0700 Subject: [PATCH 70/89] More adjustments --- app/javascript/controllers/geocode_controller.js | 2 +- app/javascript/controllers/map_controller.js | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/javascript/controllers/geocode_controller.js b/app/javascript/controllers/geocode_controller.js index 3af085b268..ff00b4d4bc 100644 --- a/app/javascript/controllers/geocode_controller.js +++ b/app/javascript/controllers/geocode_controller.js @@ -143,7 +143,7 @@ export default class extends Controller { }) this.verbose("geocode:sendPrimer") this.verbose(primer) - debugger + // Call autocompleter#refreshGooglePrimer directly if (this.hasAutocompleterOutlet) { this.autocompleterOutlet.refreshGooglePrimer({ primer }) diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index 2cb00d3717..b50ca1f3c3 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -509,10 +509,6 @@ export default class extends GeocodeController { this.closeMap() } else { this.openMap() - setTimeout(() => { - this.checkForMarker() - this.checkForBox() // regardless if point - }, 500) // wait for map to open } } @@ -533,6 +529,11 @@ export default class extends GeocodeController { } else if (this.mapBounds) { this.map.fitBounds(this.mapBounds) } + + setTimeout(() => { + this.checkForMarker() + this.checkForBox() // regardless if point + }, 500) // wait for map to open } makeMapClickable() { From 5d48c4242a674b3066f80a5e1abe5e5ff9e4558b Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Tue, 20 Aug 2024 21:39:12 -0700 Subject: [PATCH 71/89] Revert to toggle click --- app/javascript/controllers/autocompleter_controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 153a4cfd76..f81db28410 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -306,7 +306,7 @@ export default class extends Controller { // open the map if not already open if (!this.mapOutlet.opened && this.mapOutlet.hasToggleMapBtnTarget) { this.verbose("autocompleter: open map"); - this.mapOutlet.openMap(); + this.mapOutlet.toggleMapBtnTarget.click(); } // Often, this swap to location_google is for geolocating place_names and @@ -1044,7 +1044,7 @@ export default class extends Controller { if (this.wrapTarget.classList.contains('create')) { this.mapWrapTarget.classList.remove('d-none'); } else { - this.mapWrapTarget.classList.add('d-none'); + // this.mapWrapTarget.classList.add('d-none'); } } } From b5ed293d1b2dca6de1ebb9d2a7a700fa870a1c75 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 21 Aug 2024 00:56:06 -0700 Subject: [PATCH 72/89] Make Form submit turbo when appropriate --- app/views/controllers/herbaria/_form.erb | 26 +++++++++++++------- app/views/controllers/herbaria/edit.html.erb | 3 ++- app/views/controllers/herbaria/new.html.erb | 3 ++- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 4a856b8364..83d3855cf4 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -1,4 +1,4 @@ -<%# locals: (action:) -%> +<%# locals: (action:, local:) -%> <% create = (action == :create) button_name = create ? :CREATE.l : :SAVE.l @@ -20,16 +20,24 @@ if in_admin_mode? && !create end end end -%> -<%= form_with( - model: @herbarium, id: "herbarium_form", +form_args = { + model: @herbarium, + id: "herbarium_form", data: { controller: "map", map_open: false, - map_autocompleter_outlet: "#herbarium_location_autocompleter", - # action: "autocompleter:hiddenIdDataChanged@window->map#showBox" + map_autocompleter_outlet: "#herbarium_location_autocompleter" } -) do |f| %> +} +if local + form_args = form_args.merge({ local: true }) +else + form_args = form_args.deep_merge({ data: { turbo: true } }) +end + +%> + +<%= form_with(**form_args) do |f| %> <%= f.hidden_field(:back, value: @back) %> <%= f.hidden_field(:q, value: get_query_param) %> @@ -65,9 +73,9 @@ end <% append = capture do - tag.div(class: "mb-5", data: { autocompleter_target: "mapWrap" }) do + tag.div(class: "mb-5 d-none", data: { autocompleter_target: "mapWrap" }) do render(partial: "shared/form_location_map", - locals: { id: "herbarium_form_map", map_type: "location" }) + locals: { id: "herbarium_form_map", map_type: "observation" }) end end %> diff --git a/app/views/controllers/herbaria/edit.html.erb b/app/views/controllers/herbaria/edit.html.erb index f3bad93861..9897b6d252 100644 --- a/app/views/controllers/herbaria/edit.html.erb +++ b/app/views/controllers/herbaria/edit.html.erb @@ -4,4 +4,5 @@ add_page_title(:edit_herbarium_title.l) add_tab_set(herbarium_form_edit_tabs(herbarium: @herbarium)) %> -<%= render(partial: "herbaria/form", locals: { action: :update }) %> +<%= render(partial: "herbaria/form", + locals: { action: :update, local: false }) %> diff --git a/app/views/controllers/herbaria/new.html.erb b/app/views/controllers/herbaria/new.html.erb index f90082aaa8..2ce06ccfb5 100644 --- a/app/views/controllers/herbaria/new.html.erb +++ b/app/views/controllers/herbaria/new.html.erb @@ -5,4 +5,5 @@ add_page_title(:create_herbarium_title.l) add_tab_set(herbarium_form_new_tabs) %> -<%= render(partial: "herbaria/form", locals: { action: :create }) %> +<%= render(partial: "herbaria/form", + locals: { action: :create, local: false }) %> From d4eb7537abbb9685990ee2c9519418eb97c67a3e Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 21 Aug 2024 00:56:27 -0700 Subject: [PATCH 73/89] Add turbo-stream action to update the observation --- app/controllers/herbaria_controller.rb | 25 ++++++++++++++++--- app/javascript/application.js | 6 +++++ .../herbaria/_update_observation.erb | 14 +++++++++++ config/initializers/turbo_stream_actions.rb | 4 +++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 app/views/controllers/herbaria/_update_observation.erb diff --git a/app/controllers/herbaria_controller.rb b/app/controllers/herbaria_controller.rb index 581acde769..b45fee660b 100644 --- a/app/controllers/herbaria_controller.rb +++ b/app/controllers/herbaria_controller.rb @@ -128,7 +128,7 @@ def set_up_herbarium_for_edit def render_modal_herbarium_form render(partial: "shared/modal_form", locals: { title: modal_title, action: modal_form_action, - identifier: modal_identifier, + identifier: modal_identifier, local: false, form: "herbaria/form" }) and return end @@ -380,7 +380,7 @@ def user_can_destroy_herbarium? def redirect_to_create_location_or_referrer_or_show_location redirect_to_create_location || redirect_to_referrer || - redirect_with_query(herbarium_path(@herbarium)) + show_modal_flash_or_show_herbarium end def redirect_to_create_location @@ -401,11 +401,30 @@ def reload_herbarium_modal_form_and_flash ) and return true end + # What to do if the save succeeds + def show_modal_flash_or_show_herbarium + respond_to do |format| + format.html do + redirect_with_query(herbarium_path(@herbarium)) and return + end + format.turbo_stream do + # Context here is the obs form. + flash_notice( + :runtime_created_name.t(type: :herbarium, value: @herbarium.name) + ) + flash_notice( + :runtime_added_to.t(type: :herbarium, name: :observation) + ) + render(partial: "herbaria/update_observation") and return + end + end + end + def herbarium_params return {} unless params[:herbarium] params.require(:herbarium). - permit(:name, :code, :email, :mailing_address, :description, + permit(:name, :code, :email, :mailing_address, :description, :location_id, :place_name, :personal, :personal_user_name) end end diff --git a/app/javascript/application.js b/app/javascript/application.js index 98776d8d9f..29c0f16183 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -18,6 +18,12 @@ Turbo.setFormMode("optin") Turbo.StreamActions.close_modal = function () { $("#" + this.templateContent.textContent).modal('hide') }; +// https://stackoverflow.com/a/76744968/3357635 +Turbo.StreamActions.update_input = function () { + this.targetElements.forEach((target) => { + target.value = this.templateContent.textContent + }); +}; import "@rails/request.js" diff --git a/app/views/controllers/herbaria/_update_observation.erb b/app/views/controllers/herbaria/_update_observation.erb new file mode 100644 index 0000000000..d0ce50aa3a --- /dev/null +++ b/app/views/controllers/herbaria/_update_observation.erb @@ -0,0 +1,14 @@ +<%# Close the modal, update the obs with the new herbarium, and flash %> +<%= turbo_stream.close_modal("modal_herbarium") %> +<%= turbo_stream.remove("modal_herbarium") %> + +<%= turbo_stream.update("page_flash") do + flash_notices_html +end %> + +<%= turbo_stream.update_input("herbarium_record_herbarium_name", + @herbarium.name) %> + +<%= turbo_stream.update_input("herbarium_record_herbarium_id", + @herbarium.id) %> + diff --git a/config/initializers/turbo_stream_actions.rb b/config/initializers/turbo_stream_actions.rb index fa3d929d6a..718efd866c 100644 --- a/config/initializers/turbo_stream_actions.rb +++ b/config/initializers/turbo_stream_actions.rb @@ -7,5 +7,9 @@ def close_modal(id) action(:close_modal, "#", id) end + def update_input(id, value) + action(:update_input, id, value) + end + ::Turbo::Streams::TagBuilder.include(self) end From 86ad158b8d425507b82f27780f6ed9d5b02e9787 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 21 Aug 2024 01:01:58 -0700 Subject: [PATCH 74/89] Clear hidden id when form cleared --- app/javascript/controllers/autocompleter_controller.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index f81db28410..328a79a583 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -491,6 +491,7 @@ export default class extends Controller { // this.debug("ourChange(" + this.inputTarget.value + ")"); if (new_val.length == 0) { this.cssCollapseFields(); + this.clearHiddenId(); this.leaveCreate(); } else { this.cssUncollapseFields(); From 9ba7ebe1f17853f853fb5cfcc59309ece909669a Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Wed, 21 Aug 2024 01:04:46 -0700 Subject: [PATCH 75/89] Clean up controllers for testing --- app/javascript/controllers/autocompleter_controller.js | 10 +++++----- app/javascript/controllers/map_controller.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 328a79a583..109e5f9dc7 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -299,15 +299,15 @@ export default class extends Controller { } this.verbose("autocompleter:activateMapOutlet()"); - // set the map type so box is editable - this.mapOutlet.map_type = "hybrid"; // only if location_google - // set the map to stop ignoring place input - this.mapOutlet.ignorePlaceInput = false; // open the map if not already open if (!this.mapOutlet.opened && this.mapOutlet.hasToggleMapBtnTarget) { this.verbose("autocompleter: open map"); this.mapOutlet.toggleMapBtnTarget.click(); } + // set the map type so box is editable + this.mapOutlet.map_type = "hybrid"; // only if location_google + // set the map to stop ignoring place input + this.mapOutlet.ignorePlaceInput = false; // Often, this swap to location_google is for geolocating place_names and // should pay attention to text only. But in some cases the swap (e.g., from @@ -1614,7 +1614,7 @@ export default class extends Controller { } verbose(str) { - console.log(str); + // console.log(str); // document.getElementById("log"). // insertAdjacentText("beforeend", str + "
"); } diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index b50ca1f3c3..72e5b35971 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -660,7 +660,7 @@ export default class extends GeocodeController { // } verbose(str) { - console.log(str); + // console.log(str); // document.getElementById("log"). // insertAdjacentText("beforeend", str + "
"); } From a956e027ded93433632d750e859f3f504468c857 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 24 Aug 2024 14:16:41 -0700 Subject: [PATCH 76/89] App - Give better created notices --- app/controllers/application_controller.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9c12d701d6..e1f6b95400 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -788,7 +788,12 @@ def flash_object_errors(obj) def save_with_log(obj) type_sym = obj.class.to_s.underscore.to_sym if obj.save - flash_notice(:runtime_created_at.t(type: type_sym)) + notice = if obj.respond_to?(:text_name) && (name = obj.text_name) + :runtime_created_name.t(type: type_sym, value: name) + else + :runtime_created_at.t(type: type_sym) + end + flash_notice(notice) true else flash_error(:runtime_no_save.t(type: type_sym)) From 7c8f5794bc6c964ccac77b42ac7d006c4562af07 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 24 Aug 2024 14:18:05 -0700 Subject: [PATCH 77/89] Remove "create fungarium" button when form committed OK Also add turbo custom actions for adding/removing classes --- app/javascript/application.js | 13 ++++++++++++- .../controllers/herbaria/_update_observation.erb | 1 + config/initializers/turbo_stream_actions.rb | 10 +++++++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/app/javascript/application.js b/app/javascript/application.js index 29c0f16183..e8e553e34a 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -13,7 +13,7 @@ import "@hotwired/turbo-rails" // form, or button like delete/patch: set data-turbo="true" to opt in // link_to with GET: set data-turbo-stream="true" to opt in Turbo.setFormMode("optin") -// https://stackoverflow.com/questions/77421369/turbo-response-to-render-javascript-alert/77434363#77434363 +// https://stackoverflow.com/a/77434363/3357635 // use: <%= turbo_stream.close_modal("modal_#{obs.id}_naming") %> Turbo.StreamActions.close_modal = function () { $("#" + this.templateContent.textContent).modal('hide') @@ -24,6 +24,17 @@ Turbo.StreamActions.update_input = function () { target.value = this.templateContent.textContent }); }; +// https://stackoverflow.com/a/77836101/3357635 +Turbo.StreamActions.add_class = function () { + this.targetElements.forEach((target) => { + target.classList.add(this.templateContent.textContent) + }); +} +Turbo.StreamActions.remove_class = function () { + this.targetElements.forEach((target) => { + target.classList.remove(this.templateContent.textContent) + }); +} import "@rails/request.js" diff --git a/app/views/controllers/herbaria/_update_observation.erb b/app/views/controllers/herbaria/_update_observation.erb index d0ce50aa3a..0df945654c 100644 --- a/app/views/controllers/herbaria/_update_observation.erb +++ b/app/views/controllers/herbaria/_update_observation.erb @@ -12,3 +12,4 @@ end %> <%= turbo_stream.update_input("herbarium_record_herbarium_id", @herbarium.id) %> +<%= turbo_stream.remove("create_herbarium_btn") %> diff --git a/config/initializers/turbo_stream_actions.rb b/config/initializers/turbo_stream_actions.rb index 718efd866c..0d06e8c33e 100644 --- a/config/initializers/turbo_stream_actions.rb +++ b/config/initializers/turbo_stream_actions.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# https://stackoverflow.com/questions/77421369/turbo-response-to-render-javascript-alert/77434363#77434363 +# https://stackoverflow.com/a/77434363/3357635 # this is optional but makes it much cleaner module CustomTurboStreamActions def close_modal(id) @@ -11,5 +11,13 @@ def update_input(id, value) action(:update_input, id, value) end + def add_class(id, class_name) + action(:add_class, id, class_name) + end + + def remove_class(id, class_name) + action(:remove_class, id, class_name) + end + ::Turbo::Streams::TagBuilder.include(self) end From e02e108e53b42ccd440f0918dda0adb000bd4abd Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 24 Aug 2024 14:18:57 -0700 Subject: [PATCH 78/89] Add classes for autocompleter UI buttons, and an ID for the create button --- app/assets/stylesheets/Admin.scss | 2 +- app/assets/stylesheets/Agaricus.scss | 2 +- app/assets/stylesheets/Amanita.scss | 2 +- app/assets/stylesheets/BlackOnWhite.scss | 2 +- app/assets/stylesheets/Cantharellaceae.scss | 2 +- app/assets/stylesheets/Hygrocybe.scss | 2 +- app/assets/stylesheets/Sudo.scss | 2 +- app/assets/stylesheets/mo/_autocomplete.scss | 9 ++++++ app/helpers/autocompleter_helper.rb | 9 +++--- test/system/herbarium_form_system_test.rb | 33 ++++++++++---------- 10 files changed, 38 insertions(+), 27 deletions(-) diff --git a/app/assets/stylesheets/Admin.scss b/app/assets/stylesheets/Admin.scss index aef9b29a8d..823dac7709 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: #535454; // gray +$LEFT_BAR_BORDER_COLOR: #535354; // 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 de32becc3c..8cc478c8e5 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: #BF6362; // #A06463 +$brasiliensis_gills_1: #BF6262; // #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 8439d52e28..199d8a63e1 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: #f9e9d3; // faebd4 +$velosa_light_veil: #f9e8d3; // 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 beb7ee2336..2809a5de38 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: #D9D9Da; +$TOP_BAR_BORDER_COLOR: #D9D9D9; $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 5fc8c120c1..22901b7443 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: #12120d; // image 465 #10110b +$cornucopioides_dark_hymenium: #13120d; // 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 6546aca668..7cbf4e55b7 100644 --- a/app/assets/stylesheets/Hygrocybe.scss +++ b/app/assets/stylesheets/Hygrocybe.scss @@ -1,6 +1,6 @@ @import "defaults"; -$conica_stain: #34342d; // #37372f +$conica_stain: #34342c; // #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 06ffc4e641..2687d767b8 100644 --- a/app/assets/stylesheets/Sudo.scss +++ b/app/assets/stylesheets/Sudo.scss @@ -1,6 +1,6 @@ @import "defaults"; -$BODY_BG_COLOR: #DE7200; // #DD7700 +$BODY_BG_COLOR: #DE7201; // #DD7700 $LOGO_BORDER_COLOR: black; $LOGO_BORDER_WIDTH: 2px; // vs 1px in default diff --git a/app/assets/stylesheets/mo/_autocomplete.scss b/app/assets/stylesheets/mo/_autocomplete.scss index e7e75d7ce3..af1909e111 100644 --- a/app/assets/stylesheets/mo/_autocomplete.scss +++ b/app/assets/stylesheets/mo/_autocomplete.scss @@ -12,6 +12,15 @@ } } +.keep-btn { + display: none; +} +.create { + .keep-btn { + display: inline-block; + } +} + // initially we may not have id, but we also don't offer create // until they've typed something .create-button { diff --git a/app/helpers/autocompleter_helper.rb b/app/helpers/autocompleter_helper.rb index 02fffa57cc..f58832707c 100644 --- a/app/helpers/autocompleter_helper.rb +++ b/app/helpers/autocompleter_helper.rb @@ -84,8 +84,9 @@ def autocompleter_create_button(args) icon_link_to( args[:create_text], "#", + id: "create_#{args[:type]}_btn", class: "ml-3 create-button", icon: :plus, show_text: true, icon_class: "text-primary", - name: "create_#{args[:type]}", class: "ml-3 create-button", + name: "create_#{args[:type]}", data: { autocompleter_target: "createBtn", action: "autocompleter#swapCreate:prevent" } ) @@ -109,7 +110,7 @@ def autocompleter_find_button(args) icon_link_to( args[:find_text], "#", icon: :find_on_map, show_text: false, icon_class: "text-primary", - name: "find_#{args[:type]}", class: "ml-3 d-none", + name: "find_#{args[:type]}", class: "ml-3 find-btn d-none", data: { map_target: "showBoxBtn", action: "map#showBox:prevent" } ) @@ -122,9 +123,9 @@ def autocompleter_keep_button(args) args[:keep_text], "#", icon: :apply, show_text: false, icon_class: "text-primary", active_icon: :edit, active_content: args[:edit_text], - name: "keep_#{args[:type]}", class: "ml-3 d-none", + name: "keep_#{args[:type]}", class: "ml-3 keep-btn d-none", data: { autocompleter_target: "keepBtn", map_target: "lockBoxBtn", - action: "map#toggleBoxLock:prevent" } + action: "map#toggleBoxLock:prevent form-exif#showFields" } ) end diff --git a/test/system/herbarium_form_system_test.rb b/test/system/herbarium_form_system_test.rb index c9ea1097be..a1bae9e630 100644 --- a/test/system/herbarium_form_system_test.rb +++ b/test/system/herbarium_form_system_test.rb @@ -3,30 +3,31 @@ require("application_system_test_case") class HerbariumFormSystemTest < ApplicationSystemTestCase - def test_format_new_location_name + def test_fungarium_new_location # browser = page.driver.browser rolf = users("rolf") login!(rolf) - visit("/locations/new") - assert_selector("body.locations__new") + visit("/herbaria/new") + assert_selector("body.herbaria__new") - assert_selector("#location_display_name") - assert_button(:form_locations_find_on_map.l) + assert_selector("#herbarium_place_name") + fill_in("herbarium_place_name", with: "genohlac gard france") + assert_link(:form_observations_create_locality.l) # be sure the map is loaded! - assert_selector("#map_div div div") - fill_in("location_display_name", with: "genohlac gard france") - click_button(:form_locations_find_on_map.l) + # assert_selector("#map_div div div") + click_link(:form_observations_create_locality.l) - assert_selector("#location_display_name.geocoded") - assert_field("location_display_name", + assert_selector("#herbarium_place_name.geocoded") + assert_field("herbarium_place_name", with: "Génolhac, Gard, Occitanie, France") - assert_field("location_north", with: "44.3726") - assert_field("location_east", with: "3.985") - assert_field("location_south", with: "44.3055") - assert_field("location_west", with: "3.9113") - assert_field("location_high", with: "1388.2098") - assert_field("location_low", with: "287.8201") + assert_field("herbarium_location_id", with: "-1", type: :hidden) + assert_field("location_north", with: "44.3726", type: :hidden) + assert_field("location_east", with: "3.985", type: :hidden) + assert_field("location_south", with: "44.3055", type: :hidden) + assert_field("location_west", with: "3.9113", type: :hidden) + assert_field("location_high", with: "1388.2098", type: :hidden) + assert_field("location_low", with: "287.8201", type: :hidden) end end From 424f77e86b494122aa572e0ece3684e1274f607d Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 24 Aug 2024 16:17:46 -0700 Subject: [PATCH 79/89] Update geocode_controller.js Fix location matcher with street address --- app/javascript/controllers/geocode_controller.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/javascript/controllers/geocode_controller.js b/app/javascript/controllers/geocode_controller.js index ff00b4d4bc..e69ca31f58 100644 --- a/app/javascript/controllers/geocode_controller.js +++ b/app/javascript/controllers/geocode_controller.js @@ -152,6 +152,8 @@ export default class extends Controller { // Format the address components for MO style. formatMOPlaceName(result) { + const ignore_types = ["postal_code", "street_number"] + let name_components = [], usa_location = false result.address_components.forEach((component) => { if (component.types.includes("country") && component.short_name == "US") { @@ -162,7 +164,7 @@ export default class extends Controller { component.long_name.includes("County")) { // MO uses "Co." for County name_components.push(component.long_name.replace("County", "Co.")) - } else if (component.types.includes("postal_code")) { + } else if (ignore_types.some((type) => component.types.includes(type))) { // skip it for all. non-US countries it's an important differentiator? } else { name_components.push(component.long_name) From 2372947e565bf1a10036f60afe7dd2a33eab7f17 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 24 Aug 2024 16:18:03 -0700 Subject: [PATCH 80/89] Fix turbo submit on herbarium form --- app/views/controllers/herbaria/_form.erb | 4 ++-- app/views/controllers/herbaria/_update_observation.erb | 4 +--- app/views/controllers/herbaria/edit.html.erb | 2 +- app/views/controllers/herbaria/new.html.erb | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/app/views/controllers/herbaria/_form.erb b/app/views/controllers/herbaria/_form.erb index 83d3855cf4..65527c4098 100644 --- a/app/views/controllers/herbaria/_form.erb +++ b/app/views/controllers/herbaria/_form.erb @@ -1,4 +1,4 @@ -<%# locals: (action:, local:) -%> +<%# locals: (action:, local: true) -%> <% create = (action == :create) button_name = create ? :CREATE.l : :SAVE.l @@ -29,7 +29,7 @@ form_args = { map_autocompleter_outlet: "#herbarium_location_autocompleter" } } -if local +if local == true form_args = form_args.merge({ local: true }) else form_args = form_args.deep_merge({ data: { turbo: true } }) diff --git a/app/views/controllers/herbaria/_update_observation.erb b/app/views/controllers/herbaria/_update_observation.erb index 0df945654c..3dbd03a484 100644 --- a/app/views/controllers/herbaria/_update_observation.erb +++ b/app/views/controllers/herbaria/_update_observation.erb @@ -2,9 +2,7 @@ <%= turbo_stream.close_modal("modal_herbarium") %> <%= turbo_stream.remove("modal_herbarium") %> -<%= turbo_stream.update("page_flash") do - flash_notices_html -end %> +<%= turbo_stream.update("page_flash") { flash_notices_html } %> <%= turbo_stream.update_input("herbarium_record_herbarium_name", @herbarium.name) %> diff --git a/app/views/controllers/herbaria/edit.html.erb b/app/views/controllers/herbaria/edit.html.erb index 9897b6d252..b498c0cd14 100644 --- a/app/views/controllers/herbaria/edit.html.erb +++ b/app/views/controllers/herbaria/edit.html.erb @@ -5,4 +5,4 @@ add_tab_set(herbarium_form_edit_tabs(herbarium: @herbarium)) %> <%= render(partial: "herbaria/form", - locals: { action: :update, local: false }) %> + locals: { action: :update, local: true }) %> diff --git a/app/views/controllers/herbaria/new.html.erb b/app/views/controllers/herbaria/new.html.erb index 2ce06ccfb5..8076abbbfb 100644 --- a/app/views/controllers/herbaria/new.html.erb +++ b/app/views/controllers/herbaria/new.html.erb @@ -6,4 +6,4 @@ add_tab_set(herbarium_form_new_tabs) %> <%= render(partial: "herbaria/form", - locals: { action: :create, local: false }) %> + locals: { action: :create, local: true }) %> From f4e358a678e61b5994ace08aebb329ce3f67f79b Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 24 Aug 2024 16:18:18 -0700 Subject: [PATCH 81/89] Add location.text_name to show herbarium --- app/views/controllers/herbaria/show.html.erb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/views/controllers/herbaria/show.html.erb b/app/views/controllers/herbaria/show.html.erb index c0e87289e8..88030fedaa 100644 --- a/app/views/controllers/herbaria/show.html.erb +++ b/app/views/controllers/herbaria/show.html.erb @@ -4,7 +4,7 @@ add_page_title(@herbarium.format_name.t) add_pager_for(@herbarium) add_tab_set(herbarium_show_tabs(herbarium: @herbarium, user: @user)) -map = @herbarium.location ? true : false +map = @herbarium.location @container = :wide %> @@ -20,8 +20,10 @@ map = @herbarium.location ? true : false
- <%= render(partial: "herbaria/curator_table", - locals: { herbarium: @herbarium }) %> + <% if @herbarium.curators.present? %> + <%= render(partial: "herbaria/curator_table", + locals: { herbarium: @herbarium }) %> + <% end %> <% if @herbarium.curator?(@user) || in_admin_mode? %> @@ -49,14 +51,14 @@ map = @herbarium.location ? true : false <% end %>
- <% if !@herbarium.description.blank? %> + <% if @herbarium.description.present? %>
<%= :NOTES.t %>:
<%= @herbarium.description.tpl %>
<% end %> - <% if @herbarium.mailing_address && !@herbarium.mailing_address.empty? %> + <% if @herbarium.mailing_address.present? %>
<%= :herbarium_mailing_address.t %>:
<%= @herbarium.mailing_address.tp %> @@ -66,7 +68,8 @@ map = @herbarium.location ? true : false <% if map %>
- <%= make_map(objects: [@herbarium.location]) %> + <%= tag.div(class: "mb-3") { make_map(objects: [@herbarium.location]) } %> + <%= tag.p("#{:LOCATION.l}: #{@herbarium.location.text_name}") %>
<% end %>
From 79494f23db7adbc7031b3a76bc08dd6d53a55f3f Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sat, 24 Aug 2024 16:22:22 -0700 Subject: [PATCH 82/89] Check location creation --- app/views/controllers/herbaria/show.html.erb | 4 +++- test/system/herbarium_form_system_test.rb | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/views/controllers/herbaria/show.html.erb b/app/views/controllers/herbaria/show.html.erb index 88030fedaa..3c22f59c9b 100644 --- a/app/views/controllers/herbaria/show.html.erb +++ b/app/views/controllers/herbaria/show.html.erb @@ -69,7 +69,9 @@ map = @herbarium.location <% if map %>
<%= tag.div(class: "mb-3") { make_map(objects: [@herbarium.location]) } %> - <%= tag.p("#{:LOCATION.l}: #{@herbarium.location.text_name}") %> + <%= tag.p(id: "herbarium_location") do + "#{:LOCATION.l}: #{@herbarium.location.text_name}" + end %>
<% end %> diff --git a/test/system/herbarium_form_system_test.rb b/test/system/herbarium_form_system_test.rb index a1bae9e630..796ed576af 100644 --- a/test/system/herbarium_form_system_test.rb +++ b/test/system/herbarium_form_system_test.rb @@ -14,8 +14,6 @@ def test_fungarium_new_location assert_selector("#herbarium_place_name") fill_in("herbarium_place_name", with: "genohlac gard france") assert_link(:form_observations_create_locality.l) - # be sure the map is loaded! - # assert_selector("#map_div div div") click_link(:form_observations_create_locality.l) assert_selector("#herbarium_place_name.geocoded") @@ -29,5 +27,17 @@ def test_fungarium_new_location assert_field("location_west", with: "3.9113", type: :hidden) assert_field("location_high", with: "1388.2098", type: :hidden) assert_field("location_low", with: "287.8201", type: :hidden) + + within("#herbarium_form") do + fill_in("herbarium_name", with: "Herbarium des Cévennes") + fill_in("herbarium_code", with: "CEV") + click_commit + end + + # assert_no_selector("#modal_herbarium") + assert_selector("body.herbaria__show") + assert_selector("h1", text: "Herbarium des Cévennes (CEV)") + assert_selector("#herbarium_location", + text: "Génolhac, Gard, Occitanie, France") end end From 057450edbd7f166364138813def0466e67ee3a62 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 25 Aug 2024 01:04:09 -0700 Subject: [PATCH 83/89] Update herbarium_form_system_test.rb --- test/system/herbarium_form_system_test.rb | 39 +++++++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/test/system/herbarium_form_system_test.rb b/test/system/herbarium_form_system_test.rb index 796ed576af..3f5dedd452 100644 --- a/test/system/herbarium_form_system_test.rb +++ b/test/system/herbarium_form_system_test.rb @@ -3,14 +3,45 @@ require("application_system_test_case") class HerbariumFormSystemTest < ApplicationSystemTestCase - def test_fungarium_new_location + def test_create_fungarium_new_location # browser = page.driver.browser rolf = users("rolf") login!(rolf) visit("/herbaria/new") assert_selector("body.herbaria__new") + create_herbarium_with_new_location + # assert_no_selector("#modal_herbarium") + assert_selector("body.herbaria__show") + assert_selector("h1", text: "Herbarium des Cévennes (CEV)") + assert_selector("#herbarium_location", + text: "Génolhac, Gard, Occitanie, France") + end + + def test_observation_form_create_fungarium_new_location + rolf = users("rolf") + login!(rolf) + + visit("/observations/new") + assert_selector("body.observations__new") + + assert_selector("#observation_naming_specimen") + scroll_to(find("#observation_naming_specimen"), align: :top) + check("observation_specimen") + assert_selector("#herbarium_record_herbarium_name") + assert_selector(".create-link", text: :create_herbarium.l) + click_link(:create_herbarium.l) + + assert_selector("#modal_herbarium") + create_herbarium_with_new_location + + assert_no_selector("#modal_herbarium") + assert_field("herbarium_record_herbarium_name", + with: "Herbarium des Cévennes") + end + + def create_herbarium_with_new_location assert_selector("#herbarium_place_name") fill_in("herbarium_place_name", with: "genohlac gard france") assert_link(:form_observations_create_locality.l) @@ -33,11 +64,5 @@ def test_fungarium_new_location fill_in("herbarium_code", with: "CEV") click_commit end - - # assert_no_selector("#modal_herbarium") - assert_selector("body.herbaria__show") - assert_selector("h1", text: "Herbarium des Cévennes (CEV)") - assert_selector("#herbarium_location", - text: "Génolhac, Gard, Occitanie, France") end end From 2bb35e7211f54ba9b1820db1b93d62aead8a6667 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 25 Aug 2024 01:29:13 -0700 Subject: [PATCH 84/89] Fix the keep/edit box situation --- app/helpers/autocompleter_helper.rb | 18 +++++++++++++++--- .../controllers/autocompleter_controller.js | 6 +++--- app/javascript/controllers/map_controller.js | 15 +++++++-------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/app/helpers/autocompleter_helper.rb b/app/helpers/autocompleter_helper.rb index f58832707c..b726e14c9a 100644 --- a/app/helpers/autocompleter_helper.rb +++ b/app/helpers/autocompleter_helper.rb @@ -61,7 +61,8 @@ def autocompleter_label_after(args) [ autocompleter_has_id_indicator, autocompleter_find_button(args), - autocompleter_keep_button(args) + autocompleter_keep_box_button(args), + autocompleter_edit_box_button(args) ].safe_join end end @@ -116,19 +117,30 @@ def autocompleter_find_button(args) ) end - def autocompleter_keep_button(args) + def autocompleter_keep_box_button(args) return unless args[:keep_text] icon_link_to( args[:keep_text], "#", icon: :apply, show_text: false, icon_class: "text-primary", - active_icon: :edit, active_content: args[:edit_text], name: "keep_#{args[:type]}", class: "ml-3 keep-btn d-none", data: { autocompleter_target: "keepBtn", map_target: "lockBoxBtn", action: "map#toggleBoxLock:prevent form-exif#showFields" } ) end + def autocompleter_edit_box_button(args) + return unless args[:keep_text] + + icon_link_to( + args[:edit_text], "#", + icon: :edit, show_text: false, icon_class: "text-primary", + name: "edit_#{args[:type]}", class: "ml-3 edit-btn d-none", + data: { autocompleter_target: "editBtn", map_target: "editBoxBtn", + action: "map#toggleBoxLock:prevent form-exif#showFields" } + ) + end + # minimum args :form, :type. # Send :hidden to fill the id, :hidden_data to merge with hidden field data def autocompleter_hidden_field(**args) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 109e5f9dc7..8bb7b980a4 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", "collapseFields"] + "createBtn", "hasIdIndicator", "keepBtn", "editBtn", "mapWrap", "collapseFields"] static outlets = ["map"] initialize() { @@ -238,8 +238,8 @@ export default class extends Controller { this.last_fetch_params = ''; this.prepareInputElement(); this.prepareHiddenInput(); - if (!this.hasKeepBtnTarget || - !this.keepBtnTarget?.classList?.contains('active')) { + if (!this.hasEditBtnTarget || + this.editBtnTarget?.classList?.contains('d-none')) { this.clearHiddenId(); } this.constrainedSelectionUI(location); diff --git a/app/javascript/controllers/map_controller.js b/app/javascript/controllers/map_controller.js index 72e5b35971..da6b8ca127 100644 --- a/app/javascript/controllers/map_controller.js +++ b/app/javascript/controllers/map_controller.js @@ -12,7 +12,7 @@ export default class extends GeocodeController { "eastInput", "highInput", "lowInput", "placeInput", "locationId", "getElevation", "mapClearBtn", "controlWrap", "toggleMapBtn", "latInput", "lngInput", "altInput", "showBoxBtn", "lockBoxBtn", - "autocompleter"] + "editBoxBtn", "autocompleter"] connect() { this.element.dataset.stimulus = "map-connected" @@ -95,19 +95,18 @@ export default class extends GeocodeController { // Lock rectangle so it's not editable, and show this state in the icon link toggleBoxLock(event) { - if (this.rectangle && this.hasLockBoxBtnTarget) { + if (this.rectangle && this.hasLockBoxBtnTarget && + this.hasEditBoxBtnTarget) { if (this.rectangle.getEditable() === true) { this.rectangle.setEditable(false) this.rectangle.setOptions({ clickable: false }) - this.lockBoxBtnTarget.classList.add("active") - const active_title = this.lockBoxBtnTarget.dataset?.activeTitle ?? '' - this.lockBoxBtnTarget.setAttribute("title", active_title) + this.lockBoxBtnTarget.classList.add("d-none") + this.editBoxBtnTarget.classList.remove("d-none") } else { this.rectangle.setEditable(true) this.rectangle.setOptions({ clickable: true }) - this.lockBoxBtnTarget.classList.remove("active") - const title = this.lockBoxBtnTarget.dataset?.title ?? '' - this.lockBoxBtnTarget.setAttribute("title", title) + this.lockBoxBtnTarget.classList.remove("d-none") + this.editBoxBtnTarget.classList.add("d-none") } } } From 002faf7200ee59b2c0231defcc8f7d0c1d2b26ab Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 25 Aug 2024 14:59:08 -0700 Subject: [PATCH 85/89] Fix notes help for plain "Other" notes text area --- app/extensions/string_extensions.rb | 8 ++++++++ app/helpers/forms_helper.rb | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/extensions/string_extensions.rb b/app/extensions/string_extensions.rb index c16983359f..f78cce1a70 100644 --- a/app/extensions/string_extensions.rb +++ b/app/extensions/string_extensions.rb @@ -23,6 +23,8 @@ # gsub_html_special_chars:: auxiliary to html_to_ascii # unescape_html:: Render special encoded characters as regular characters # as_displayed:: Render everything humanly legible, for integration tests +# id_of_nested_field:: Rails generates `observation_notes` for the ID of a +# nested field like `observation[notes]` # --- # break_name:: Break a taxon name at the author # small_author:: Wrap the author in a span @@ -546,6 +548,12 @@ def as_displayed strip_html.unescape_html.strip_squeeze end + # Rails generates an id for a nested field like "foo[bar]" that's snake_case + # - no brackets. This gets you that string. (used in forms_helper) + def id_of_nested_field + gsub(/[\[\]]+/, "_").chop + end + # Insert a line break between the scientific name and the author # (for styling taxonomic names legibly) def break_name diff --git a/app/helpers/forms_helper.rb b/app/helpers/forms_helper.rb index ee748fcf9e..4cc398a318 100644 --- a/app/helpers/forms_helper.rb +++ b/app/helpers/forms_helper.rb @@ -503,7 +503,11 @@ def check_for_help_block(args) return args end - id = "#{args[:form].object_name}_#{args[:field]}_help" + id = [ + args[:form].object_name.to_s.id_of_nested_field, + args[:field].to_s, + "help" + ].join("_") args[:between] = capture do concat(args[:between]) concat(collapse_info_trigger(id)) From af14f64ad3eb8082d6d28507433b49ce431a3dfd Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 25 Aug 2024 14:59:30 -0700 Subject: [PATCH 86/89] Update autocompleter_controller.js Comments about "keepBtn" --- app/javascript/controllers/autocompleter_controller.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/javascript/controllers/autocompleter_controller.js b/app/javascript/controllers/autocompleter_controller.js index 8bb7b980a4..f81d551679 100644 --- a/app/javascript/controllers/autocompleter_controller.js +++ b/app/javascript/controllers/autocompleter_controller.js @@ -1020,6 +1020,8 @@ export default class extends Controller { // Respond to the state of the hidden input. Initially we may not have id, but // we also don't offer create until they've typed something. + // The `keepBtn` is for freezing the current box so people can pick a point. + // Otherwise you can't click a point inside the box. cssHasIdOrNo(hidden_id) { this.verbose("autocompleter:cssHasIdOrNo()"); From 6b7cf3c181564499c5a84685df5cfdb85b2f96c6 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 25 Aug 2024 14:59:51 -0700 Subject: [PATCH 87/89] Update panel_helper.rb help_block: Less margin after --- app/helpers/panel_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/helpers/panel_helper.rb b/app/helpers/panel_helper.rb index 5f265b4bc2..c6ca7e4cc4 100644 --- a/app/helpers/panel_helper.rb +++ b/app/helpers/panel_helper.rb @@ -168,7 +168,7 @@ def help_block(element = :div, string = "", **args, &block) # 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 = "well well-sm mb-3 help-block position-relative" div_class += " mt-3" if direction == "up" tag.div(class: div_class, id: args[:id]) do @@ -182,7 +182,7 @@ def help_block_with_arrow(direction = nil, **args, &block) end def collapse_help_block(direction = nil, string = nil, **args, &block) - div_class = "well well-sm help-block position-relative" + div_class = "well well-sm mb-3 help-block position-relative" div_class += " mt-3" if direction == "up" content = block ? capture(&block) : string From 2ad98539c24ccb53180eb00a9791ec870e63f410 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 25 Aug 2024 15:00:07 -0700 Subject: [PATCH 88/89] Update some translations --- config/locales/en.txt | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/config/locales/en.txt b/config/locales/en.txt index 0fc83fa377..d71243de76 100644 --- a/config/locales/en.txt +++ b/config/locales/en.txt @@ -699,6 +699,8 @@ close: close CREATE: Create create: create + DEFINE: Define + define: define DELETE: Delete delete: delete # deprecate a name @@ -771,16 +773,16 @@ destroyed: destroyed FILTERED: Filtered filtered: filtered + IGNORING: Ignoring + ignoring: ignoring MODIFIED: Modified modified: modified + NEW: New + new: new OPTIONAL: Optional optional: optional REQUIRED: Required required: required - WATCHING: Watching - watching: watching - IGNORING: Ignoring - ignoring: ignoring TRACKING: Tracking tracking: tracking UPDATED: Updated @@ -789,6 +791,8 @@ updated_at: updated at VIEWED: Viewed viewed: viewed + WATCHING: Watching + watching: watching # Common adjectives describing species names. (Note: "approved" seems to be # interchangeable with "accepted" in our site -- both indicate that the @@ -1670,10 +1674,10 @@ form_observations_open_map: "[:SHOW] [:map]" form_observations_hide_map: "[:HIDE] [:map]" form_observations_clear_map: "[:CLEAR] [:location]" - form_observations_click_point: "Tip: select a locality to center the map, then click a point on the map to set a location." + form_observations_click_point: "Tip: select a locality to center the map, then click a point on the map to set a location. If you're defining a new locality, click \"Use these bounds\" so you can select a point within." form_observations_locality_contains: "[:LOCALITIES] containing this point" - form_observations_create_locality: "[:CREATE] [:locality]" - form_observations_use_locality: "[:USE] this [:locality]" + form_observations_create_locality: "[:NEW] [:locality]" + form_observations_use_locality: "Use these bounds and select a point within" form_observations_edit_locality: "[:EDIT] this [:locality]" form_observations_notes_help: Please include any additional information you can think of about this observation that isn't clear from the photographs, e.g., habitat, substrate or nearby trees; distinctive texture, scent, taste, staining or bruising; results of chemical or microscopic analyses, etc. form_observations_remove_image_confirm: Are you sure you want to remove this image? This will only remove this image from this observation. If it is attached to other observations, it will remain attached to them. @@ -2607,8 +2611,8 @@ show_herbarium_request_sent: Request has been sent to admins. We'll get back to you as soon as possible. # herbaria/create - create_herbarium: Create Fungarium - create_herbarium_title: Create New Fungarium + create_herbarium: New Fungarium + create_herbarium_title: New Fungarium create_herbarium_personal: Check this box if this is your personal fungarium create_herbarium_personal_help: Each user can have one personal fungarium that they have curator privileges for. By default it is called "[name]", but you can change that name to anything you like. create_herbarium_code: Standard Abbreviation @@ -3086,7 +3090,7 @@ # info/textile sandbox_enter: Enter Textile you wish to test here - sandbox_header: This page let's you play with the textile markup language. Click 'Test' to see what your markup looks like. You will need to copy the results from this page to where ever you want to use it. + sandbox_header: This page lets you play with the textile markup language. Click 'Test' to see what your markup looks like. You will need to copy the results from this page to wherever you want to use it. sandbox_link_hobix_textile_reference: hobix Textile Reference sandbox_link_hobix_textile_cheatsheet: hobix cheatsheet (Textile Quick Reference) sandbox_link_textile_language_website: Textile Language website From 67b7a5d017f8517df37c3fed1c30bdd8b2231961 Mon Sep 17 00:00:00 2001 From: andrew nimmo Date: Sun, 25 Aug 2024 16:04:24 -0700 Subject: [PATCH 89/89] Update geocode_controller.js Ignore "postal_code_suffix" also --- app/javascript/controllers/geocode_controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/controllers/geocode_controller.js b/app/javascript/controllers/geocode_controller.js index e69ca31f58..477d072046 100644 --- a/app/javascript/controllers/geocode_controller.js +++ b/app/javascript/controllers/geocode_controller.js @@ -152,7 +152,7 @@ export default class extends Controller { // Format the address components for MO style. formatMOPlaceName(result) { - const ignore_types = ["postal_code", "street_number"] + const ignore_types = ["postal_code", "postal_code_suffix", "street_number"] let name_components = [], usa_location = false result.address_components.forEach((component) => {