import ApplicationController from "satis/controllers/application_controller"
/*
Usage:
Usage with slim and checkbox:
.site-company-wrapper data-controller='toggle'
= address_form.input :company, input_html: { 'data-toggle-target': 'input' }
div data-toggle-target='insertion'
template data-toggle-target='toggleable' data-toggle-value='true'
= address_form.input :company_name
*/
export default class extends ApplicationController {
static targets = ["toggleable", "insertion", "input"]
connect() {
this.boundUpdate = this.update.bind(this)
this.inputTargets.forEach((input) => {
input.addEventListener("change", this.boundUpdate)
})
this.update()
}
disconnect() {
this.inputTargets.forEach((input) => {
input.removeEventListener("change", this.boundUpdate)
})
}
update(event) {
/* FIXME: There should be a more cleaner way of doing this?
* Make sure that the toggle happens after the event bubble so any listeners are able to
* process before we overwrite the template nodes that are possibly updated and reinsert new nodes.
*/
setTimeout(() => {
this.toggle(this.currentValue)
})
}
toggle(value) {
// Update template nodes before we swap
this.toggleableTargets.forEach((target) => {
target.content.childNodes.forEach(child => {
let targetNodeId = child.getAttribute("data-toggleable-node-id")
if (!targetNodeId) return true;
this.insertionTarget.childNodes.forEach(iNode => {
if (iNode.getAttribute("data-toggleable-node-id") == targetNodeId) {
if (child.parentElement) {
child.outerHTML = iNode.outerHTML
iNode.remove()
}
}
})
})
})
// Clear the insertion target
this.insertionTarget.innerHTML = ""
// Reinsert elements
this.toggleableTargets.forEach((element) => {
if (element.getAttribute("data-toggle-value") == value || (element.getAttribute("data-toggle-not-value") != null && element.getAttribute("data-toggle-not-value") != value)) {
element.content.childNodes.forEach(node => this.setUniqueId(node))
let toggleContent = document.importNode(element.content, true)
toggleContent.childNodes.forEach((child) => {
this.insertionTarget.insertAdjacentHTML("beforeend", child.outerHTML)
})
}
})
}
get currentValue() {
if (this.inputTargets.length >= 1 && this.inputTargets[0].type == "radio") {
return this.inputTargets.find((input) => input.checked)?.value
} else if (this.inputTarget.type == "checkbox") {
return this.inputTarget.checked ? "true" : "false"
} else if (this.inputTarget.tagName == "SELECT" && this.data.get("attr")) {
let option = this.inputTarget.options[this.inputTarget.selectedIndex]
return option?.getAttribute(this.data.get("attr"))
} else {
return this.inputTarget.value
}
}
setUniqueId(node) {
if (node.getAttribute("data-toggleable-node-id")) return;
const dateString = Date.now().toString(36);
const randomness = Math.random().toString(36).substring(2);
node.setAttribute("data-toggleable-node-id", dateString + randomness)
}
}