aircox/assets/src/components/AList.vue
bkfox 180cc8bc02 - various __all__
- serializer: track search, reorder module files
- autocomplete: allow simple string value selection
- playlist editor:
    - ui & flow improve
    - init data
    - save user settings
    - autocomplete
    - fix bugs
    - discard changes
2022-12-12 00:25:57 +01:00

101 lines
3.2 KiB
Vue

<template>
<div>
<!-- FIXME: header and footer should be inside list tags -->
<slot name="header"></slot>
<component :is="listTag" :class="listClass">
<template v-for="(item,index) in items" :key="index">
<component :is="itemTag" :class="itemClass" @click="select(index)"
:draggable="orderable" :data-index="index"
@dragstart="onDragStart" @dragover="onDragOver" @drop="onDrop">
<slot name="item" :selected="index == selectedIndex" :set="set" :index="index" :item="item"></slot>
</component>
</template>
</component>
<slot name="footer"></slot>
</div>
</template>
<script>
export default {
emits: ['select', 'unselect', 'move'],
data() {
return {
selectedIndex: this.defaultIndex,
}
},
props: {
listClass: String,
itemClass: String,
defaultIndex: { type: Number, default: -1},
set: Object,
orderable: { type: Boolean, default: false },
itemTag: { default: 'li' },
listTag: { default: 'ul' },
},
computed: {
model() { return this.set.model },
items() { return this.set.items },
length() { return this.set.length },
selected() {
return this.selectedIndex > -1 && this.items.length > this.selectedIndex > -1
? this.items[this.selectedIndex] : null;
},
},
methods: {
get(index) { return this.set.get(index) },
find(pred) { return this.set.find(pred) },
findIndex(pred) { return this.set.findIndex(pred) },
remove(index, select=false) {
this.set.remove(index);
if(index < this.selectedIndex)
this.selectedIndex--;
if(select && this.selectedIndex == index)
this.select(index)
},
select(index) {
this.selectedIndex = index > -1 && this.items.length ? index % this.items.length : -1;
this.$emit('select', { item: this.selected, index: this.selectedIndex });
return this.selectedIndex;
},
unselect() {
this.$emit('unselect', { item: this.selected, index: this.selectedIndex});
this.selectedIndex = -1;
},
onDragStart(ev) {
const dataset = ev.target.dataset;
const data = `row:${dataset.index}`
ev.dataTransfer.setData("text/cell", data)
ev.dataTransfer.dropEffect = 'move'
},
onDragOver(ev) {
ev.preventDefault()
ev.dataTransfer.dropEffect = 'move'
},
onDrop(ev) {
const data = ev.dataTransfer.getData("text/cell")
if(!data || !data.startsWith('row:'))
return
ev.preventDefault()
const from = Number(data.slice(4))
const target = ev.target.tagName == this.itemTag ? ev.target
: ev.target.closest(this.itemTag)
this.$emit('move', {
from, target,
to: Number(target.dataset.index),
set: this.set,
})
},
},
}
</script>