Files
procat2/cateditor/src/components/CatalogContents.vue

442 lines
13 KiB
Vue

<template>
<v-container fluid>
<v-row class="fill-height">
<v-btn @click="showAddProductDialog = true">Add products</v-btn>
</v-row>
<v-row class="fill-height">
<v-col cols="4">
<v-card>
<DragListHeading title="Sections">
<v-btn icon class="ma-0 pa-0" @click="showAddSectionDialog = true">
<v-icon>add</v-icon>
</v-btn>
</DragListHeading>
<div id="sections" class="list-group">
<div v-for="item in catalog.sections" :key="item.id">
<v-hover :key="item.id">
<v-list-item
slot-scope="{ hover }"
:class="sectionListItemClasses(item.id, hover)"
@click="selectSection(item.id)"
>
<!-- TODO try move sectionparent into v-list-title
and so section-drop can cover all interior
-->
<v-list-item-content class="section-parent">
<v-list-item-title v-html="item.name"/>
<v-list-item-subtitle
class="caption font-weight-light"
color="grey lighten-2"
>
{{ sectionModelCount(item.id) }} {{ sectionModelCount(item.id) | pluralize('model') }}
</v-list-item-subtitle>
<v-list-item-subtitle class="section-drop" :section-id="item.id"/>
</v-list-item-content>
<v-list-item-action>
<span class="group">
<v-btn icon @click.stop="popSectionInfo(item.id)">
<v-icon small color="grey lighten-1">info</v-icon>
</v-btn>
<v-btn icon @click.stop="popSectionDelete(item.id)">
<v-icon small color="grey lighten-1">delete</v-icon>
</v-btn>
</span>
</v-list-item-action>
</v-list-item>
</v-hover>
</div>
</div>
</v-card>
</v-col>
<v-col cols="4">
<v-card>
<DragListHeading title="Models" />
<div id="models" class="list-group">
<div v-for="item in selectedModels" :key="item.model">
<v-hover :key="item.model">
<v-list-item
slot-scope="{ hover }"
:class="modelListItemClasses(item.model, hover)"
@click="selectModel(item.model)"
>
<v-list-item-content>
<v-list-item-title v-html="item.name"/>
<v-list-item-subtitle
class="caption font-weight-light"
color="grey lighten-2">
{{ item.ids.length }} {{ item.ids.length | pluralize('material') }}
</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action>
<span class="group">
<v-btn icon @click.stop="popModelInfo(item.model)">
<v-icon small color="grey lighten-1">info</v-icon>
</v-btn>
<v-btn icon @click.stop="popModelDelete(item.model)">
<v-icon small color="grey lighten-1">delete</v-icon>
</v-btn>
</span>
</v-list-item-action>
</v-list-item>
</v-hover>
</div>
</div>
</v-card>
</v-col>
<v-col cols="4">
<v-card>
<DragListHeading title="Materials" />
<div id="materials" class="list-group">
<div v-for="item in selectedMaterials" :key="item.id">
<v-hover :key="item.id">
<v-list-item
slot-scope="{ hover }"
:class="materialListItemClasses(item.id, hover)"
@click="selectMaterial(item.id)"
>
<v-list-item-content>
<v-list-item-title><b>{{ item.id }}</b> {{ item.name }}</v-list-item-title>
<v-list-item-subtitle v-html="item.color"/>
</v-list-item-content>
<v-list-item-action>
<span class="group">
<v-btn icon @click="popMaterialDelete(item.id)">
<v-icon small color="grey lighten-1">delete</v-icon>
</v-btn>
</span>
</v-list-item-action>
</v-list-item>
</v-hover>
</div>
</div>
</v-card>
</v-col>
</v-row>
<AddProductDialog v-model="showAddProductDialog"/>
<AddSectionDialog v-model="showAddSectionDialog"/>
<SectionInfoDialog v-model="showSectionInfoDialog"/>
<SectionDeleteDialog v-model="showSectionDeleteDialog"/>
<ModelInfoDialog v-model="showModelInfoDialog"/>
<ModelDeleteDialog v-model="showModelDeleteDialog"/>
<MaterialDeleteDialog v-model="showMaterialDeleteDialog"/>
</v-container>
</template>
<script>
import Sortable from 'sortablejs'
import { mapState, mapGetters, mapActions } from 'vuex'
//import RawDisplayer from './RawDisplayer'
import DragListHeading from './DragListHeading'
import AddProductDialog from './AddProductDialog'
import AddSectionDialog from './AddSectionDialog'
import SectionInfoDialog from './SectionInfoDialog'
import SectionDeleteDialog from './SectionDeleteDialog'
import ModelInfoDialog from './ModelInfoDialog'
import ModelDeleteDialog from './ModelDeleteDialog'
import MaterialDeleteDialog from './MaterialDeleteDialog'
export default {
components: {
DragListHeading,
AddProductDialog,
AddSectionDialog,
SectionInfoDialog,
SectionDeleteDialog,
ModelInfoDialog,
ModelDeleteDialog,
MaterialDeleteDialog,
//RawDisplayer,
},
data: () => ({
showAddProductDialog: false,
showAddSectionDialog: false,
showSectionInfoDialog: false,
showSectionDeleteDialog: false,
showModelInfoDialog: false,
showModelDeleteDialog: false,
//showMaterialInfoDialog: false,
showMaterialDeleteDialog: false,
}),
computed: {
...mapState([
'catalog',
'materials',
'selectedSectionID',
'selectedModelID',
'selectedMaterialID',
]),
...mapGetters([
'section',
'selectedSection',
'selectedModel',
'selectedMaterial',
'sectionModels',
'modelMaterials',
'material',
]),
selectedModels() {
let section = this.selectedSection
return this.sectionModels(section)
},
selectedMaterials() {
let model = this.selectedModel
return this.modelMaterials(model)
},
},
mounted: function() {
let me = this
// reordering of sections
Sortable.create(document.getElementById('sections'), {
group: {
name: 'sections',
},
animation: 150,
onEnd: function(evt) {
me.reorderSection({ from: evt.oldIndex, to: evt.newIndex })
},
})
// reordering of models
Sortable.create(document.getElementById('models'), {
group: {
name: 'models',
},
animation: 150,
onStart: function(evt) {
addSectionDrops(me)
},
onEnd: function(evt) {
if (evt.from === evt.to) {
me.reorderModel({ section: me.selectedSection,
fromIndex: evt.oldIndex,
toIndex: evt.newIndex })
} else {
// dropped on a section.
let models = me.selectedModels
let model = models[evt.oldIndex]
let sectionID = Number(evt.to.getAttribute('section-id'))
let newSection = me.section(sectionID)
if (me.selectedSection.id !== newSection.id) {
me.moveModelToSection({ model: model,
oldSection: me.selectedSection,
newSection: newSection })
} else {
console.log('not moving to same section')
}
}
},
})
// reordering of materials
Sortable.create(document.getElementById('materials'), {
group: {
name: 'materials',
},
animation: 150,
onStart: function(evt) {
addSectionDrops(me)
},
onEnd: function(evt) {
if (evt.from === evt.to) {
me.reorderMaterial({ section: me.selectedSection,
model: me.selectedModel,
fromIndex: evt.oldIndex,
toIndex: evt.newIndex })
} else {
// dropped on a section.
let mats = me.selectedMaterials
let mat = mats[evt.oldIndex]
let sectionID = Number(evt.to.getAttribute('section-id'))
let newSection = me.section(sectionID)
if (me.selectedSection.id !== newSection.id) {
me.moveMaterialToSection({ material: mat,
oldSection: me.selectedSection,
oldModel: me.selectedModel,
newSection: newSection })
} else {
console.log('not moving to same section')
}
}
},
})
},
methods: {
sectionModelCount(sectionID) {
let section = this.section(sectionID)
if (section) {
let models = this.sectionModels(section) || []
return models.length
} else {
return 0
}
},
sectionListItemClasses(id, hovering) {
if (id === this.selectedSectionID) {
return 'list-item primary'
} else if (hovering) {
return 'list-item list-hover'
} else {
return 'list-item'
}
},
modelListItemClasses(id, hovering) {
if (id === this.selectedModelID) {
return 'list-item primary'
} else if (hovering) {
return 'list-item list-hover'
} else {
return 'list-item'
}
},
materialListItemClasses(id, hovering) {
if (id === this.selectedMaterialID) {
return 'list-item primary'
} else if (hovering) {
return 'list-item list-hover'
} else {
return 'list-item'
}
},
popSectionInfo(id) {
this.selectSection(id)
this.showSectionInfoDialog = true
},
popSectionDelete(id) {
this.selectSection(id)
this.showSectionDeleteDialog = true
},
popModelInfo(id) {
this.selectModel(id)
this.showModelInfoDialog = true
},
popModelDelete(id) {
this.selectModel(id)
this.showModelDeleteDialog = true
},
popMaterialDelete(id) {
this.selectMaterial(id)
this.showMaterialDeleteDialog = true
},
...mapActions([
'selectSection',
'selectModel',
'selectMaterial',
'reorderSection',
'reorderModel',
'reorderMaterial',
'moveModelToSection',
'moveMaterialToSection',
]),
}
}
function addSectionDrops(myvue) {
// make sure our section drop targets are set up
// after catalog load or section add
// drop model or material into a section
var drops = document.getElementsByClassName('section-drop')
for (var i = 0; i < drops.length; ++i) {
if (!drops[i].getAttribute('drop-ready')) {
drops[i].setAttribute('drop-ready', true)
Sortable.create(drops[i], {
group: {
name: 'section-drops',
pull: false,
put: function(to, from) {
// don't allow drop on section where it already lives
let oldSectionID = myvue.selectedSection.id
let newSectionID = to.el.getAttribute('section-id')
if (Number(oldSectionID) === Number(newSectionID)) {
return false
}
// allow drop from anything but another section
return from.options.group.name !== 'sections'
},
},
animation: 150,
// (actual drop is handled in the originating list)
})
}
}
}
</script>
<style>
.selected {
background-color: purple;
}
.sortable-chosen {
color: black;
background-color: #fddd04;
}
.sortable-ghost {
background-color: #bababa;
}
.section-parent {
position: relative;
}
.section-drop {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 100%;
}
.list-item {
background-color: white;
border-bottom: 1px solid #ddd;
}
.list-hover {
background-color: #eee;
border-bottom: 1px solid #ccc;
}
.list-group {
background-color: #ccc;
min-height: 200px;
max-height: 400px;
overflow-y: auto;
}
</style>