From fee3ce8627f2188844c533b7b54746798675abcb Mon Sep 17 00:00:00 2001 From: barbie-bot Date: Sat, 4 Apr 2026 13:44:44 +0000 Subject: [PATCH] Migrate all inline JS to Stimulus controllers Add stimulus-rails gem and wire up 7 controllers: - measurements_view_controller: view toggle (compact/wide) via localStorage - measurements_controller: grouped rows MutationObserver - charts_controller: Plotly chart rendering - form_controller: keyboard shortcuts (Escape/Enter) and submit validation - details_controller: quantity picker state, focusout close, MutationObserver - readout_unit_controller: default unit button enable/disable + PATCH submission - drag_controller: drag-and-drop for quantity reparenting and unit rebasing Remove all inline onclick/onkeydown/ondrag*/onsubmit handlers from templates. Remove all window.* global exports from application.js. Remove bare +
+
+ +
diff --git a/app/views/measurements/_edit_form.html.erb b/app/views/measurements/_edit_form.html.erb index 845ef41..a4770f0 100644 --- a/app/views/measurements/_edit_form.html.erb +++ b/app/views/measurements/_edit_form.html.erb @@ -1,6 +1,7 @@ <%= tabular_fields_for @readout, form: form_tag do |form| %> - <%- tag.tr id: row, class: "form", onkeydown: "formProcessKey(event)", - data: {form: form_tag, hidden_row: hidden_row, link: link} do %> + <%- tag.tr id: row, class: "form", + data: {controller: 'form', action: 'keydown->form#processKey', + form: form_tag, hidden_row: hidden_row, link: link} do %> <%= @readout.quantity %> <%= form.number_field :value, required: true, autofocus: true %> diff --git a/app/views/measurements/_edit_panel.html.erb b/app/views/measurements/_edit_panel.html.erb index 20f59b2..dd08eb9 100644 --- a/app/views/measurements/_edit_panel.html.erb +++ b/app/views/measurements/_edit_panel.html.erb @@ -6,8 +6,9 @@ id: form_tag do |form| %> - <%= tag.tr id: row, class: "form", onkeydown: "formProcessKey(event)", - data: {form: form_tag, hidden_row: hidden_row} do %> + <%= tag.tr id: row, class: "form", + data: {controller: 'form', action: 'keydown->form#processKey', + form: form_tag, hidden_row: hidden_row} do %> <%= tag.tr id: "quantity_", hidden: true, - ondragover: "dragOver(event)", ondrop: "drop(event)", - ondragenter: "dragEnter(event)", ondragleave: "dragLeave(event)", - data: {drop_id: "quantity_", drop_id_param: "quantity[parent_id]"} do %> + data: {controller: 'drag', + action: 'dragover->drag#over drop->drag#drop dragenter->drag#enter dragleave->drag#leave', + drag_drop_id_value: 'quantity_', + drag_drop_id_param_value: 'quantity[parent_id]'} do %> <% end %> diff --git a/app/views/readouts/_form.html.erb b/app/views/readouts/_form.html.erb index 0f2dfd8..e6d067f 100644 --- a/app/views/readouts/_form.html.erb +++ b/app/views/readouts/_form.html.erb @@ -1,6 +1,6 @@ -<%# TODO: add readout reordering by dragging %> <%= tabular_fields_for 'readouts[]', readout do |form| %> - <%- tag.tr id: dom_id(readout.quantity, :new, :readout) do %> + <%- tag.tr id: dom_id(readout.quantity, :new, :readout), + data: {controller: 'readout-unit'} do %> <%= tag.tr id: "unit_", hidden: true, - ondragover: "dragOver(event)", ondrop: "drop(event)", - ondragenter: "dragEnter(event)", ondragleave: "dragLeave(event)", - data: {drop_id: "unit_", drop_id_param: "unit[base_id]"} do %> + data: {controller: 'drag', + action: 'dragover->drag#over drop->drag#drop dragenter->drag#enter dragleave->drag#leave', + drag_drop_id_value: 'unit_', + drag_drop_id_param_value: 'unit[base_id]'} do %> <% end %> diff --git a/app/views/users/profiles/new.html.erb b/app/views/users/profiles/new.html.erb index bb0ebe7..b5965af 100644 --- a/app/views/users/profiles/new.html.erb +++ b/app/views/users/profiles/new.html.erb @@ -1,5 +1,5 @@ <%= labeled_form_for resource, url: user_registration_path, - html: {class: 'main-area', onsubmit: 'formValidate(event)'} do |f| %> + html: {class: 'main-area', data: {controller: 'form', action: 'submit->form#validate'}} do |f| %> <%= f.email_field :email, required: true, size: 30, autofocus: true, autocomplete: 'email' %> diff --git a/app/views/users/sessions/new.html.erb b/app/views/users/sessions/new.html.erb index 0678d95..5faa038 100644 --- a/app/views/users/sessions/new.html.erb +++ b/app/views/users/sessions/new.html.erb @@ -1,5 +1,5 @@ <%= labeled_form_for resource, url: user_session_path, - html: {class: 'main-area', onsubmit: 'formValidate(event)'} do |f| %> + html: {class: 'main-area', data: {controller: 'form', action: 'submit->form#validate'}} do |f| %> <%= f.email_field :email, required: true, size: 30, autofocus: true, autocomplete: 'email' %> diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc index 53df955..b019bfb 100644 --- a/config/credentials.yml.enc +++ b/config/credentials.yml.enc @@ -1 +1 @@ -3nm9KZNtyLhPgZBVzOOkN2FXHD0uEMuzgb5Sl1MrAMmi6+iEFSzyTHfZFW2mz18VyNz5DDYvTODZqBDQKK+FQh70uEQkmGqaY5XsTOzUFzk56quaPNtZvFEGux1nX2avSbYQBs3HeyYyWyTAFhez5j8tVb6sZD2xZ8twa9KAB42j86NIHT9w/ZMFqZbGbdBoR1Mrqoy9/IWv2QgxMTpGR6JBpTUwauXm6wS/bTt8SCXF57JSVgvdw/BxFzoA3Xj6N5E89LbMfh54W2ruMhybka5E7zXN9z0v4oXt8GiYZFIODEYZwqzEVaUK1WXS5qb5OrDJFAzs29Uf/gDrIDx71Lot+jejCS+xFfI9454EnHcVH66wKuwF6ylKupJDffM0hQHplcEfVSq5UiDfbPXm46Vr0g1A--2RrmuzCBuHvYpPNA--ugbuRe7ivfDqeUCt6ahciA== \ No newline at end of file +yQ/e5AEwReoZ6yiIqCZjBbl2Tp41JNcuwfWF3FeSSk2K0XBtE+VQXHlAHMBPRwbBdkutB8jls+YKou3JX58j88BEH3Ft/8h7GIepYF+nOhdb79y05lqEhARA4IZYnHe1Do72MdmseE0ectfDpfk6Q1qnfiTFe3X1KyfLR0hiSEM5+1ZYfk2loUBWSIfgYuqtK7bEOZiL6imU46n4+58g3VZd0cK7getT7rwNlVt1s6ME9PTwT/RqE736fLEIyDeaEg8hBxTrPVeYyii2o4IWM02/0HsuRPxXLLQAgXyzHhlT9wo18X5FaaecgGloBie0UMrPS3j6oBlVn61WQbkuEe/yQKnzyiw0v5HSmzME4PiDTaSW2em/BtGiMAhJpyukipQa4/leR3OTJxv3TAMha1bnk/OC--QU+gjSEvBsZpr3XT--osCoTfqZ4ENeas+nFdXefA== \ No newline at end of file diff --git a/config/importmap.rb b/config/importmap.rb index 26c5560..8dce42d 100644 --- a/config/importmap.rb +++ b/config/importmap.rb @@ -2,3 +2,6 @@ pin "application", preload: true pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true +pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true +pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true +pin_all_from "app/javascript/controllers", under: "controllers"
<%= @readout.quantity %> <%= form.number_field :value, required: true, autofocus: true %> diff --git a/app/views/measurements/_form.html.erb b/app/views/measurements/_form.html.erb index f8db9f9..732c5ca 100644 --- a/app/views/measurements/_form.html.erb +++ b/app/views/measurements/_form.html.erb @@ -1,6 +1,6 @@ <%= tabular_form_with model: Measurement.new, id: :measurement_form, class: 'topside-area flex vertical center', - html: {onkeydown: 'formProcessKey(event)'} do |form| %> + html: {data: {controller: 'form', action: 'keydown->form#processKey'}} do |form| %> @@ -17,17 +17,18 @@ <%# TODO: right-click selection; unnecessary with hierarchical tags? %>
+ data-controller="details" + data-action="focusout->details#close change->details#change keydown->details#processKey"> - + <%= t('.select_quantity') %> <%= image_button_tag t(:apply), "update", name: nil, disabled: true, formaction: new_readout_path, formmethod: :get, formnovalidate: true, - data: {turbo_stream: true} %> + data: {turbo_stream: true, details_target: 'submitButton'} %> -
    <%= quantities_check_boxes(@quantities) %>
+
    <%= quantities_check_boxes(@quantities) %>
@@ -36,10 +37,3 @@ class: 'dangerous', onclick: render_turbo_stream('form_close') %>
<% end %> - - diff --git a/app/views/measurements/index.html.erb b/app/views/measurements/index.html.erb index 8d5c5b2..7f24cf2 100644 --- a/app/views/measurements/index.html.erb +++ b/app/views/measurements/index.html.erb @@ -1,5 +1,5 @@ <%# TODO: show hint when no quantities/units defined %> -
+
<% if current_user.at_least(:active) %> <%= image_link_to t('.new_measurement'), 'plus-outline', new_measurement_path, id: :new_measurement_link, onclick: 'this.blur();', @@ -7,16 +7,17 @@ <% end %> <%= image_button_tag '', 'view-rows', name: nil, type: 'button', class: 'view-toggle', title: t('.view_compact'), - data: {view: 'compact'}, onclick: "setMeasurementsView('compact')" %> + data: {view: 'compact', action: 'click->measurements-view#set', + 'measurements-view-name-param': 'compact'} %> <%= image_button_tag '', 'view-columns', name: nil, type: 'button', class: 'view-toggle', title: t('.view_wide'), - data: {view: 'wide'}, onclick: "setMeasurementsView('wide')" %> - + data: {view: 'wide', action: 'click->measurements-view#set', + 'measurements-view-name-param': 'wide'} %>
<%= tag.div id: :measurement_edit_form %> -
+
@@ -29,7 +30,7 @@ <% end %> - + <%= render(partial: 'readout', collection: @measurements, as: :readout) || render_no_items %>
<%= Quantity.model_name.human %>
@@ -38,4 +39,3 @@ <%= render 'wide_table', wide_groups: @wide_groups, wide_quantities: @wide_quantities %> - diff --git a/app/views/quantities/_form.html.erb b/app/views/quantities/_form.html.erb index 99c58e2..684cfd4 100644 --- a/app/views/quantities/_form.html.erb +++ b/app/views/quantities/_form.html.erb @@ -1,6 +1,7 @@ <%= tabular_fields_for @quantity, form: form_tag do |form| %> - <%- tag.tr id: row, class: "form", onkeydown: "formProcessKey(event)", - data: {link: link, form: form_tag, hidden_row: hidden_row} do %> + <%- tag.tr id: row, class: "form", + data: {controller: 'form', action: 'keydown->form#processKey', + link: link, form: form_tag, hidden_row: hidden_row} do %>
<%= form.text_field :name, required: true, autofocus: true, size: 20 %> diff --git a/app/views/quantities/_quantity.html.erb b/app/views/quantities/_quantity.html.erb index edec53e..a21996c 100644 --- a/app/views/quantities/_quantity.html.erb +++ b/app/views/quantities/_quantity.html.erb @@ -1,9 +1,10 @@ <%= tag.tr id: dom_id(quantity), - ondragstart: "dragStart(event)", ondragend: "dragEnd(event)", - ondragover: "dragOver(event)", ondrop: "drop(event)", - ondragenter: "dragEnter(event)", ondragleave: "dragLeave(event)", - data: {drag_path: reparent_quantity_path(quantity), drop_id: dom_id(quantity), - drop_id_param: "quantity[parent_id]"} do %> + draggable: true, + data: {controller: 'drag', + action: 'dragstart->drag#start dragend->drag#end dragover->drag#over drop->drag#drop dragenter->drag#enter dragleave->drag#leave', + drag_drag_path_value: reparent_quantity_path(quantity), + drag_drop_id_value: dom_id(quantity), + drag_drop_id_param_value: 'quantity[parent_id]'} do %> <%= link_to quantity, edit_quantity_path(quantity), class: 'link', diff --git a/app/views/quantities/index.html.erb b/app/views/quantities/index.html.erb index f82b49a..c52c6fe 100644 --- a/app/views/quantities/index.html.erb +++ b/app/views/quantities/index.html.erb @@ -23,9 +23,10 @@ <% end %>
<%= t '.top_level_drop' %> <%# TODO: add grayed readout index (in separate column?) %> <%= readout.quantity.relative_pathname(@superquantity) %> @@ -13,16 +13,18 @@ <%= form.collection_select :unit_id, @user_units, :id, ->(u){ sanitize(' ' * (u.base_id ? 1 : 0) + u.symbol) }, {prompt: '', disabled: '', selected: readout.quantity.default_unit_id || ''}, required: true, - data: {default_unit_id: readout.quantity.default_unit_id || ''}, - onchange: "readoutUnitChanged(this)" %> + data: {default_unit_id: readout.quantity.default_unit_id || '', + readout_unit_target: 'select', + action: 'change->readout-unit#unitChanged'} %> <%# TODO: change to _link_ after giving up displaying relative paths %> <%= image_button_tag '', 'check-circle-outline', class: 'set-default-unit', name: nil, type: 'button', disabled: true, title: t('readouts.form.set_default_unit'), - data: {path: quantity_path(readout.quantity)}, - onclick: 'setDefaultUnit(this)' %> + data: {path: quantity_path(readout.quantity), + readout_unit_target: 'button', + action: 'click->readout-unit#setDefault'} %> <%= image_button_tag '', 'delete-outline', class: 'dangerous', name: nil, formaction: discard_readouts_path(readout.quantity), formmethod: :get, formnovalidate: true, data: {turbo_stream: true} %> diff --git a/app/views/units/_form.html.erb b/app/views/units/_form.html.erb index a5b1a3e..15485c6 100644 --- a/app/views/units/_form.html.erb +++ b/app/views/units/_form.html.erb @@ -1,6 +1,7 @@ <%= tabular_fields_for @unit, form: form_tag do |form| %> - <%- tag.tr id: row, class: "form", onkeydown: "formProcessKey(event)", - data: {link: link, form: form_tag, hidden_row: hidden_row} do %> + <%- tag.tr id: row, class: "form", + data: {controller: 'form', action: 'keydown->form#processKey', + link: link, form: form_tag, hidden_row: hidden_row} do %> <%= form.text_field :symbol, required: true, autofocus: true, size: 12 %> diff --git a/app/views/units/_unit.html.erb b/app/views/units/_unit.html.erb index d5e726e..1608d4d 100644 --- a/app/views/units/_unit.html.erb +++ b/app/views/units/_unit.html.erb @@ -1,10 +1,10 @@ <%= tag.tr id: dom_id(unit), - ondragstart: "dragStart(event)", ondragend: "dragEnd(event)", - ondragover: "dragOver(event)", ondrop: "drop(event)", - ondragenter: "dragEnter(event)", ondragleave: "dragLeave(event)", - data: {drag_path: rebase_unit_path(unit), - drop_id: dom_id(unit.base || unit), - drop_id_param: "unit[base_id]"} do %> + draggable: true, + data: {controller: 'drag', + action: 'dragstart->drag#start dragend->drag#end dragover->drag#over drop->drag#drop dragenter->drag#enter dragleave->drag#leave', + drag_drag_path_value: rebase_unit_path(unit), + drag_drop_id_value: dom_id(unit.base || unit), + drag_drop_id_param_value: 'unit[base_id]'} do %> <%= link_to unit, edit_unit_path(unit), class: 'link', onclick: 'this.blur();', diff --git a/app/views/units/index.html.erb b/app/views/units/index.html.erb index 775fef8..42652c3 100644 --- a/app/views/units/index.html.erb +++ b/app/views/units/index.html.erb @@ -22,9 +22,10 @@ <% end %>
<%= t '.top_level_drop' %>