1a78de6f71
This will make the system listen for changes via the filtered collections, when any, or via all the collections otherwise.
101 lines
2.5 KiB
JavaScript
101 lines
2.5 KiB
JavaScript
import { Controller } from "@hotwired/stimulus"
|
|
import { toSentence } from "helpers/text_helpers"
|
|
|
|
export default class extends Controller {
|
|
#hiddenField
|
|
|
|
static targets = [ "label", "item", "hiddenFieldTemplate" ]
|
|
static values = {
|
|
selectPropertyName: { type: String, default: "aria-checked" },
|
|
defaultValue: String,
|
|
noSelectionLabel: { type: String, default: "No selection" },
|
|
labelPrefix: String
|
|
}
|
|
|
|
connect() {
|
|
this.refresh()
|
|
}
|
|
|
|
change(event) {
|
|
const item = event.target.closest("[role='checkbox']")
|
|
if (item) {
|
|
this.#toggleSelection(item)
|
|
}
|
|
}
|
|
|
|
refresh() {
|
|
this.labelTarget.textContent = this.#selectedLabel
|
|
this.#updateHiddenFields()
|
|
}
|
|
|
|
clear(event) {
|
|
this.#deselectAll()
|
|
this.#updateHiddenFields()
|
|
this.labelTarget.textContent = this.#selectedLabel
|
|
}
|
|
|
|
get #selectedLabel() {
|
|
const selectedValues = this.#selectedValues()
|
|
if (selectedValues.length === 0) {
|
|
return this.noSelectionLabelValue
|
|
}
|
|
|
|
const labels = this.#selectedItems().map(item => item.dataset.multiSelectionComboboxLabel)
|
|
const sentence = toSentence(labels, {
|
|
two_words_connector: " or ",
|
|
last_word_connector: ", or "
|
|
})
|
|
|
|
return this.hasLabelPrefixValue ? `${this.labelPrefixValue} ${sentence}` : sentence
|
|
}
|
|
|
|
#toggleSelection(item) {
|
|
const isSelected = item.getAttribute(this.selectPropertyNameValue) === "true"
|
|
|
|
if (isSelected) {
|
|
item.setAttribute(this.selectPropertyNameValue, "false")
|
|
} else {
|
|
item.setAttribute(this.selectPropertyNameValue, "true")
|
|
}
|
|
|
|
this.#updateHiddenFields()
|
|
this.labelTarget.textContent = this.#selectedLabel
|
|
}
|
|
|
|
#updateHiddenFields() {
|
|
this.#clearHiddenFields()
|
|
this.#addHiddenFields()
|
|
}
|
|
|
|
#deselectAll() {
|
|
this.itemTargets.forEach(item => {
|
|
item.setAttribute(this.selectPropertyNameValue, "false")
|
|
})
|
|
}
|
|
|
|
#selectedItems() {
|
|
return this.itemTargets.filter(item =>
|
|
item.getAttribute(this.selectPropertyNameValue) === "true"
|
|
)
|
|
}
|
|
|
|
#selectedValues() {
|
|
return this.#selectedItems().map(item => item.dataset.multiSelectionComboboxValue)
|
|
}
|
|
|
|
#clearHiddenFields() {
|
|
this.element.querySelectorAll('input[type="hidden"]').forEach(field => {
|
|
field.remove()
|
|
})
|
|
}
|
|
|
|
#addHiddenFields() {
|
|
this.#selectedValues().forEach(value => {
|
|
const [ field ] = this.hiddenFieldTemplateTarget.content.cloneNode(true).children
|
|
field.removeAttribute("id")
|
|
field.value = value
|
|
this.element.appendChild(field)
|
|
})
|
|
}
|
|
}
|