mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-28 12:11:08 -04:00
242 lines
6.6 KiB
JavaScript
242 lines
6.6 KiB
JavaScript
import { toRefs, watch, nextTick, computed } from 'vue'
|
|
|
|
export default function usePointer(props, context, dep) {
|
|
const {
|
|
valueProp, showOptions, searchable, groupLabel,
|
|
groups: groupped, mode, groupSelect,
|
|
} = toRefs(props)
|
|
|
|
// ============ DEPENDENCIES ============
|
|
|
|
const fo = dep.fo
|
|
const fg = dep.fg
|
|
const handleOptionClick = dep.handleOptionClick
|
|
const handleGroupClick = dep.handleGroupClick
|
|
const search = dep.search
|
|
const pointer = dep.pointer
|
|
const setPointer = dep.setPointer
|
|
const clearPointer = dep.clearPointer
|
|
const multiselect = dep.multiselect
|
|
|
|
// ============== COMPUTED ==============
|
|
|
|
// no export
|
|
const options = computed(() => {
|
|
return fo.value.filter(o => !o.disabled)
|
|
})
|
|
|
|
const groups = computed(() => {
|
|
return fg.value.filter(o => !o.disabled)
|
|
})
|
|
|
|
const canPointGroups = computed(() => {
|
|
return mode.value !== 'single' && groupSelect.value
|
|
})
|
|
|
|
const isPointerGroup = computed(() => {
|
|
return pointer.value && pointer.value.group
|
|
})
|
|
|
|
const currentGroup = computed(() => {
|
|
return getParentGroup(pointer.value)
|
|
})
|
|
|
|
const prevGroup = computed(() => {
|
|
const group = isPointerGroup.value ? pointer.value : /* istanbul ignore next */ getParentGroup(pointer.value)
|
|
const groupIndex = groups.value.map(g => g[groupLabel.value]).indexOf(group[groupLabel.value])
|
|
let prevGroup = groups.value[groupIndex - 1]
|
|
|
|
if (prevGroup === undefined) {
|
|
prevGroup = lastGroup.value
|
|
}
|
|
|
|
return prevGroup
|
|
})
|
|
|
|
const nextGroup = computed(() => {
|
|
let nextIndex = groups.value.map(g => g.label).indexOf(isPointerGroup.value
|
|
? pointer.value[groupLabel.value]
|
|
: getParentGroup(pointer.value)[groupLabel.value]) + 1
|
|
|
|
if (groups.value.length <= nextIndex) {
|
|
nextIndex = 0
|
|
}
|
|
|
|
return groups.value[nextIndex]
|
|
})
|
|
|
|
const lastGroup = computed(() => {
|
|
return [...groups.value].slice(-1)[0]
|
|
})
|
|
|
|
const currentGroupFirstEnabledOption = computed(() => {
|
|
return pointer.value.__VISIBLE__.filter(o => !o.disabled)[0]
|
|
})
|
|
|
|
const currentGroupPrevEnabledOption = computed(() => {
|
|
const options = currentGroup.value.__VISIBLE__.filter(o => !o.disabled)
|
|
return options[options.map(o => o[valueProp.value]).indexOf(pointer.value[valueProp.value]) - 1]
|
|
})
|
|
|
|
const currentGroupNextEnabledOption = computed(() => {
|
|
const options = getParentGroup(pointer.value).__VISIBLE__.filter(o => !o.disabled)
|
|
return options[options.map(o => o[valueProp.value]).indexOf(pointer.value[valueProp.value]) + 1]
|
|
})
|
|
|
|
const prevGroupLastEnabledOption = computed(() => {
|
|
return [...prevGroup.value.__VISIBLE__.filter(o => !o.disabled)].slice(-1)[0]
|
|
})
|
|
|
|
const lastGroupLastEnabledOption = computed(() => {
|
|
return [...lastGroup.value.__VISIBLE__.filter(o => !o.disabled)].slice(-1)[0]
|
|
})
|
|
|
|
// =============== METHODS ==============
|
|
|
|
const isPointed = (option) => {
|
|
if (!pointer.value) {
|
|
return
|
|
}
|
|
|
|
if (option.group) {
|
|
return pointer.value[groupLabel.value] == option[groupLabel.value]
|
|
} else {
|
|
return pointer.value[valueProp.value] == option[valueProp.value]
|
|
}
|
|
}
|
|
|
|
const setPointerFirst = () => {
|
|
setPointer(options.value[0] || null)
|
|
}
|
|
|
|
const selectPointer = () => {
|
|
if (!pointer.value || pointer.value.disabled === true) {
|
|
return
|
|
}
|
|
|
|
if (isPointerGroup.value) {
|
|
handleGroupClick(pointer.value)
|
|
} else {
|
|
handleOptionClick(pointer.value)
|
|
}
|
|
}
|
|
|
|
const forwardPointer = () => {
|
|
if (pointer.value === null) {
|
|
setPointer((groupped.value && canPointGroups.value ? groups.value[0] : options.value[0]) || null)
|
|
}
|
|
else if (groupped.value && canPointGroups.value) {
|
|
let nextPointer = isPointerGroup.value ? currentGroupFirstEnabledOption.value : currentGroupNextEnabledOption.value
|
|
|
|
if (nextPointer === undefined) {
|
|
nextPointer = nextGroup.value
|
|
}
|
|
|
|
setPointer(nextPointer || /* istanbul ignore next */ null)
|
|
} else {
|
|
let next = options.value.map(o => o[valueProp.value]).indexOf(pointer.value[valueProp.value]) + 1
|
|
|
|
if (options.value.length <= next) {
|
|
next = 0
|
|
}
|
|
|
|
setPointer(options.value[next] || null)
|
|
}
|
|
|
|
nextTick(() => {
|
|
adjustWrapperScrollToPointer()
|
|
})
|
|
}
|
|
|
|
const backwardPointer = () => {
|
|
if (pointer.value === null) {
|
|
let prevPointer = options.value[options.value.length - 1]
|
|
|
|
if (groupped.value && canPointGroups.value) {
|
|
prevPointer = lastGroupLastEnabledOption.value
|
|
|
|
if (prevPointer === undefined) {
|
|
prevPointer = lastGroup.value
|
|
}
|
|
}
|
|
|
|
setPointer(prevPointer || null)
|
|
}
|
|
else if (groupped.value && canPointGroups.value) {
|
|
let prevPointer = isPointerGroup.value ? prevGroupLastEnabledOption.value : currentGroupPrevEnabledOption.value
|
|
|
|
if (prevPointer === undefined) {
|
|
prevPointer = isPointerGroup.value ? prevGroup.value : currentGroup.value
|
|
}
|
|
|
|
setPointer(prevPointer || /* istanbul ignore next */ null)
|
|
} else {
|
|
let prevIndex = options.value.map(o => o[valueProp.value]).indexOf(pointer.value[valueProp.value]) - 1
|
|
|
|
if (prevIndex < 0) {
|
|
prevIndex = options.value.length - 1
|
|
}
|
|
|
|
setPointer(options.value[prevIndex] || null)
|
|
}
|
|
|
|
nextTick(() => {
|
|
adjustWrapperScrollToPointer()
|
|
})
|
|
}
|
|
|
|
const getParentGroup = (option) => {
|
|
return groups.value.find((group) => {
|
|
return group.__VISIBLE__.map(o => o[valueProp.value]).indexOf(option[valueProp.value]) !== -1
|
|
})
|
|
}
|
|
|
|
// no export
|
|
/* istanbul ignore next */
|
|
const adjustWrapperScrollToPointer = () => {
|
|
let pointedOption = multiselect.value.querySelector(`[data-pointed]`)
|
|
|
|
if (!pointedOption) {
|
|
return
|
|
}
|
|
|
|
let wrapper = pointedOption.parentElement.parentElement
|
|
|
|
if (groupped.value) {
|
|
wrapper = isPointerGroup.value
|
|
? pointedOption.parentElement.parentElement.parentElement
|
|
: pointedOption.parentElement.parentElement.parentElement.parentElement
|
|
}
|
|
|
|
if (pointedOption.offsetTop + pointedOption.offsetHeight > wrapper.clientHeight + wrapper.scrollTop) {
|
|
wrapper.scrollTop = pointedOption.offsetTop + pointedOption.offsetHeight - wrapper.clientHeight
|
|
}
|
|
|
|
if (pointedOption.offsetTop < wrapper.scrollTop) {
|
|
wrapper.scrollTop = pointedOption.offsetTop
|
|
}
|
|
}
|
|
|
|
// ============== WATCHERS ==============
|
|
|
|
watch(search, (val) => {
|
|
if (searchable.value) {
|
|
if (val.length && showOptions.value) {
|
|
setPointerFirst()
|
|
} else {
|
|
clearPointer()
|
|
}
|
|
}
|
|
})
|
|
|
|
return {
|
|
pointer,
|
|
canPointGroups,
|
|
isPointed,
|
|
setPointerFirst,
|
|
selectPointer,
|
|
forwardPointer,
|
|
backwardPointer,
|
|
}
|
|
}
|