You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
2.3 KiB
84 lines
2.3 KiB
"use strict"
|
|
|
|
const months = document.getElementById('months')
|
|
let selecting = null // { origin, className, range }
|
|
let is_select = false
|
|
|
|
months.addEventListener("pointerdown", event => {
|
|
selecting = null
|
|
is_select = false
|
|
for (const elem of document.querySelectorAll(".selecting, .unselecting")) {
|
|
elem.className = ""
|
|
}
|
|
|
|
if (event.buttons !== 1) return
|
|
let target = event.target
|
|
if (target.nodeType == 3) target = target.parentNode
|
|
if (target.tagName !== "LABEL") return
|
|
|
|
event.preventDefault()
|
|
|
|
const className = target.className = document.getElementById(target.htmlFor).checked ? "unselecting" : "selecting"
|
|
selecting = {
|
|
origin: target,
|
|
className,
|
|
range: [ target ]
|
|
}
|
|
})
|
|
|
|
months.addEventListener('pointermove', event => {
|
|
if (selecting === null) return
|
|
event.preventDefault()
|
|
is_select = true
|
|
|
|
const range = document.createRange()
|
|
range.selectNode(selecting.origin)
|
|
if (range.comparePoint(event.target, 0) > 0) range.setEndAfter(event.target)
|
|
else range.setStartBefore(event.target)
|
|
|
|
const treeWalker = document.createTreeWalker(
|
|
range.commonAncestorContainer,
|
|
NodeFilter.SHOW_ELEMENT,
|
|
{ acceptNode: (node) => node.nodeName.toLowerCase() === 'label' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP }
|
|
)
|
|
|
|
const new_range = []
|
|
let currentNode
|
|
while (currentNode = treeWalker.nextNode()) {
|
|
if (range.intersectsNode(currentNode)) {
|
|
new_range.push(currentNode)
|
|
const idx = selecting.range.indexOf(currentNode)
|
|
if (idx !== -1) selecting.range.splice(idx, 1)
|
|
else currentNode.className = selecting.className
|
|
}
|
|
}
|
|
for (const elem of selecting.range) {
|
|
elem.className = ""
|
|
}
|
|
selecting.range = new_range
|
|
})
|
|
|
|
document.addEventListener('pointercancel', event => {
|
|
if (selecting === null) return
|
|
for (const elem of selecting.range) {
|
|
elem.className = ""
|
|
}
|
|
selecting = null
|
|
is_select = false
|
|
})
|
|
|
|
document.addEventListener('pointerup', event => {
|
|
if (selecting === null) return
|
|
event.preventDefault()
|
|
for (const elem of selecting.range) {
|
|
if (is_select) document.getElementById(elem.htmlFor).checked = selecting.className == "selecting"
|
|
elem.className = ""
|
|
}
|
|
selecting = null
|
|
})
|
|
months.addEventListener('click', event => {
|
|
if (is_select) {
|
|
event.preventDefault()
|
|
is_select = false
|
|
}
|
|
})
|