Compare commits

..

1 Commits

Author SHA1 Message Date
67f519052a Extract disableElement/enableElement to shared module
Stimulus controllers were reaching into Turbo.StreamElement.prototype
to call disableElement/enableElement — tight coupling to Turbo internals.

Extract both functions to app/javascript/element_helpers.js and import
from there in application.js (which still assigns them to the Turbo
prototype for server-driven Turbo Stream actions), details_controller,
and readout_unit_controller.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 14:19:49 +00:00
5 changed files with 23 additions and 18 deletions

View File

@@ -2,6 +2,7 @@
// https://github.com/rails/importmap-rails // https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails" import "@hotwired/turbo-rails"
import "controllers" import "controllers"
import { disableElement, enableElement } from "element_helpers"
/* Hide page before loaded for testing purposes */ /* Hide page before loaded for testing purposes */
@@ -12,23 +13,13 @@ document.addEventListener('turbo:load', showPage)
/* Turbo stream actions */ /* Turbo stream actions */
Turbo.StreamElement.prototype.disableElement = function(element) { Turbo.StreamElement.prototype.disableElement = disableElement
element.setAttribute("disabled", "disabled") Turbo.StreamElement.prototype.enableElement = enableElement
element.setAttribute("aria-disabled", "true")
element.setAttribute("tabindex", "-1")
}
Turbo.StreamActions.disable = function() { Turbo.StreamActions.disable = function() {
this.targetElements.forEach((e) => { this.disableElement(e) }) this.targetElements.forEach(disableElement)
}
Turbo.StreamElement.prototype.enableElement = function(element) {
element.removeAttribute("disabled")
element.removeAttribute("aria-disabled")
// Assume 'tabindex' is not used explicitly, so removing it is safe
element.removeAttribute("tabindex")
} }
Turbo.StreamActions.enable = function() { Turbo.StreamActions.enable = function() {
this.targetElements.forEach((e) => { this.enableElement(e) }) this.targetElements.forEach(enableElement)
} }
/* TODO: change to visibility = collapse to avoid width change? */ /* TODO: change to visibility = collapse to avoid width change? */

View File

@@ -1,4 +1,5 @@
import { Controller } from "@hotwired/stimulus" import { Controller } from "@hotwired/stimulus"
import { disableElement, enableElement } from "element_helpers"
export default class extends Controller { export default class extends Controller {
static targets = ["countLabel", "submitButton", "list"] static targets = ["countLabel", "submitButton", "list"]
@@ -18,10 +19,10 @@ export default class extends Controller {
const count = this.element.querySelectorAll('input:checked:not([disabled])').length const count = this.element.querySelectorAll('input:checked:not([disabled])').length
if (count > 0) { if (count > 0) {
this.countLabelTarget.textContent = count + ' selected' this.countLabelTarget.textContent = count + ' selected'
Turbo.StreamElement.prototype.enableElement(this.submitButtonTarget) enableElement(this.submitButtonTarget)
} else { } else {
this.countLabelTarget.textContent = this.countLabelTarget.dataset.prompt this.countLabelTarget.textContent = this.countLabelTarget.dataset.prompt
Turbo.StreamElement.prototype.disableElement(this.submitButtonTarget) disableElement(this.submitButtonTarget)
} }
} }

View File

@@ -1,13 +1,14 @@
import { Controller } from "@hotwired/stimulus" import { Controller } from "@hotwired/stimulus"
import { disableElement, enableElement } from "element_helpers"
export default class extends Controller { export default class extends Controller {
static targets = ["select", "button"] static targets = ["select", "button"]
unitChanged() { unitChanged() {
if (this.selectTarget.value && this.selectTarget.value !== this.selectTarget.dataset.defaultUnitId) { if (this.selectTarget.value && this.selectTarget.value !== this.selectTarget.dataset.defaultUnitId) {
Turbo.StreamElement.prototype.enableElement(this.buttonTarget) enableElement(this.buttonTarget)
} else { } else {
Turbo.StreamElement.prototype.disableElement(this.buttonTarget) disableElement(this.buttonTarget)
} }
} }

View File

@@ -0,0 +1,11 @@
export function disableElement(element) {
element.setAttribute("disabled", "disabled")
element.setAttribute("aria-disabled", "true")
element.setAttribute("tabindex", "-1")
}
export function enableElement(element) {
element.removeAttribute("disabled")
element.removeAttribute("aria-disabled")
element.removeAttribute("tabindex")
}

View File

@@ -1,6 +1,7 @@
# Pin npm packages by running ./bin/importmap # Pin npm packages by running ./bin/importmap
pin "application", preload: true pin "application", preload: true
pin "element_helpers"
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true