PageSourceSearch

https://bikeindex.org/assets/controllers/org/impound_update_multi_…629dca0f6dd86e9cf716a58b176b91ea631057b5.js

js bikeindex.org collected 2026-09-24 08:54:12 UTC 3,716 bytes, 113 lines download raw bytes

1import { Controller } from '@hotwired/stimulus'
2import { CollapseUtils, collapse } from 'utils/collapse_utils'
3
4// Connects to data-controller='org--impound-update-multi'
5// The impound records index multi-update extras: reveals the update panel and
6// the checkbox column, enables only the checkboxes whose row supports the
7// selected update kind, and blocks submitting with nothing checked. The
8// kind-specific fields are handled by the separate org--impound-update controller.
9export default class extends Controller {
10  static targets = ['toggle', 'panel', 'kindSelect', 'error']
11  static values = { openLabel: String, closedLabel: String, disabledTitle: String }
12
13  connect () {
14    // The panel may be rendered already-open (multi_update=true) — in that
15    // case sync the checkbox enabled state, since toggle() never runs.
16    if (this.panelOpen) {
17      this.refreshChecks()
18    }
19  }
20
21  toggle () {
22    this.panelOpen ? this.closePanel() : this.openPanel()
23  }
24
25  openPanel () {
26    collapse('show', this.panelTarget)
27    this.cells.forEach(cell => cell.classList.remove('tw:hidden'))
28    this.refreshChecks()
29    this.toggleTarget.textContent = this.openLabelValue
30    this.refreshTableEdges()
31    this.setUrlParam(true)
32  }
33
34  closePanel () {
35    collapse('hide', this.panelTarget)
36    this.cells.forEach(cell => cell.classList.add('tw:hidden'))
37    this.toggleTarget.textContent = this.closedLabelValue
38    this.refreshTableEdges()
39    this.setUrlParam(false)
40  }
41
42  // Showing/hiding the column changes which cell is last-visible — let the
43  // ui--table controller re-apply edge rounding/borders.
44  refreshTableEdges () {
45    window.dispatchEvent(new Event('ui-table:refresh'))
46  }
47
48  // Reflect the opened state in the URL without adding a history entry
49  setUrlParam (open) {
50    const url = new URL(window.location)
51    if (open) {
52      url.searchParams.set('multi_update', 'true')
53    } else {
54      url.searchParams.delete('multi_update')
55    }
56    window.history.replaceState(window.history.state, '', url)
57  }
58
59  get panelOpen () {
60    return CollapseUtils.isVisible(this.panelTarget)
61  }
62
63  // Block submitting the form with no rows checked, showing the error alert
64  validate (event) {
65    if (this.anyChecked) {
66      collapse('hide', this.errorTarget)
67    } else {
68      collapse('show', this.errorTarget)
69      event.preventDefault()
70      // stopImmediatePropagation keeps the event from reaching rails-ujs (which
71      // would disable the data-disable-with button and leave it stuck) and from
72      // reaching form-persist#clear (which would wipe the draft on a blocked submit).
73      event.stopImmediatePropagation()
74    }
75  }
76
77  // Once a row is checked, the "select a record" error no longer applies
78  hideErrorIfChecked () {
79    if (this.anyChecked) collapse('hide', this.errorTarget)
80  }
81
82  get anyChecked () {
83    return [...this.cells].some(cell =>
84      cell.querySelector('input[type=checkbox]')?.checked
85    )
86  }
87
88  // Enable only the checkboxes whose row supports the selected kind
89  refreshChecks () {
90    const kind = this.kindSelectTarget.value
91    this.cells.forEach(cell => {
92      const checkbox = cell.querySelector('input[type=checkbox]')
93      if (!checkbox) return
94
95      const allowed = checkbox.dataset.updateKinds.split(' ').includes(kind)
96      checkbox.disabled = !allowed
97      if (allowed) {
98        cell.removeAttribute('title')
99      } else {
100        checkbox.checked = false
101        cell.title = this.disabledTitleValue.replace('{kind}', this.kindLabel)
102      }
103    })
104  }
105
106  get cells () {
107    return this.element.querySelectorAll('.multi-update-cell')
108  }
109
110  get kindLabel () {
111    return this.kindSelectTarget.selectedOptions[0]?.text
112  }
113};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.