PageSourceSearch

https://app.youwindrenewables.com/assets/controllers/checkbox_group_controller-7524af37.js

js youwindrenewables.com collected 2026-09-29 10:40:44 UTC 3,915 bytes, 109 lines download raw bytes

1import { Controller } from "@hotwired/stimulus"
2import { patch } from "@rails/request.js"
3
4// Connects to data-controller="checkbox-group"
5// Reusable checkbox group: toggles visibility of elements matching
6// a configurable data attribute, and persists state via async PATCH.
7//
8// Values:
9//   url              — PATCH endpoint to persist hidden columns
10//   column-attribute — data attribute name used to find table cells, e.g. "data-pixel-table-column"
11//
12// Targets:
13//   checkbox     — the checkboxes controlling visibility
14//   counter      — optional span showing "visible/total" count on the trigger button
15//   modal        — Bootstrap modal containing the checkboxes
16//   sortableList — container for sortable checkboxes
17export default class extends Controller {
18  static targets = ["checkbox", "counter", "modal", "sortableList"]
19  static values = { url: String, columnAttribute: String, sortable: Boolean, refreshOnClose: Boolean }
20
21  connect() {
22    this.updateFirstVisibleAccordionBorder()
23    if (this.sortableValue) {
24      this._onModalShow = () => this._initSortable()
25      this.modalTarget.addEventListener("shown.bs.modal", this._onModalShow)
26    }
27    if (this.refreshOnCloseValue) {
28      this._onModalClose = () => { if (this._dirty) { this._dirty = false; window.location.reload() } }
29      this.modalTarget.addEventListener("hidden.bs.modal", this._onModalClose)
30    }
31  }
32
33  disconnect() {
34    if (this._onModalShow) this.modalTarget.removeEventListener("shown.bs.modal", this._onModalShow)
35    if (this._onModalClose) this.modalTarget.removeEventListener("hidden.bs.modal", this._onModalClose)
36    this.sortable?.destroy()
37  }
38
39  _initSortable() {
40    if (this.sortable) return
41    if (!this.hasSortableListTarget) return
42    this.sortable = Sortable.create(this.sortableListTarget, {
43      animation: 150,
44      handle: ".bi-grip-vertical",
45      onEnd: () => this.persist()
46    })
47  }
48
49  toggle(event) {
50    this.applyVisibility(event.target.value, event.target.checked)
51    this.updateCounter()
52    this.persist()
53  }
54
55  checkAll(event) {
56    event.preventDefault()
57    this.checkboxTargets.forEach(cb => {
58      cb.checked = true
59      this.applyVisibility(cb.value, true)
60    })
61    this.updateCounter()
62    this.persist()
63  }
64
65  uncheckAll(event) {
66    event.preventDefault()
67    this.checkboxTargets.forEach(cb => {
68      cb.checked = false
69      this.applyVisibility(cb.value, false)
70    })
71    this.updateCounter()
72    this.persist()
73  }
74
75  applyVisibility(key, visible) {
76    const attr = this.columnAttributeValue || "data-column"
77    document.querySelectorAll(`[${attr}="${key}"]`).forEach(el => {
78      el.classList.toggle("d-none", !visible)
79    })
80    this.updateFirstVisibleAccordionBorder()
81  }
82
83  updateFirstVisibleAccordionBorder() {
84    const attr = this.columnAttributeValue || "data-column"
85    const accordionItems = Array.from(document.querySelectorAll(`[${attr}]`))
86      .filter(el => el.classList.contains("accordion-item"))
87    accordionItems.forEach(el => el.classList.remove("border-top"))
88    accordionItems.find(el => !el.classList.contains("d-none"))?.classList.add("border-top")
89  }
90
91  updateCounter() {
92    if (!this.hasCounterTarget) return
93    const total = this.checkboxTargets.length
94    const visible = this.checkboxTargets.filter(cb => cb.checked).length
95    this.counterTarget.textContent = `(${visible}/${total})`
96  }
97
98  persist() {
99    this._dirty = true
100    const checkboxes = this.checkboxTargets
101    const hidden = checkboxes.filter(cb => !cb.checked).map(cb => cb.value)
102    const ordered = checkboxes.map(cb => cb.value)
103    const data = new FormData()
104    hidden.forEach(col => data.append("hidden_columns[]", col))
105    if (hidden.length === 0) data.append("hidden_columns[]", "")
106    ordered.forEach(col => data.append("ordered_columns[]", col))
107    patch(this.urlValue, { body: data, responseKind: "turbo-stream" })
108  }
109}

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.