224 lines
5.2 KiB
Vue
224 lines
5.2 KiB
Vue
<template lang="html">
|
|
<v-sheet
|
|
class="tree-node"
|
|
:class="{
|
|
'empty': !hasChildren,
|
|
'found': node._matchedDocumentFilter,
|
|
}"
|
|
:data-id="`tree-node-${node._id}`"
|
|
>
|
|
<div
|
|
class="layout align-center justify-start tree-node-title"
|
|
style="cursor: pointer;"
|
|
:class="selected && 'primary--text'"
|
|
@click.stop="$emit('selected', node._id)"
|
|
>
|
|
<v-btn
|
|
v-if="!startExpanded"
|
|
small
|
|
icon
|
|
:class="showExpanded ? 'rotate-90' : null"
|
|
:disabled="!hasChildren && !organize || !canExpand"
|
|
@click.stop="expanded = !expanded"
|
|
>
|
|
<v-icon v-if="canExpand && (hasChildren || organize)">
|
|
mdi-chevron-right
|
|
</v-icon>
|
|
</v-btn>
|
|
<div
|
|
class="layout align-center justify-start pr-1"
|
|
:class="{'ml-4': startExpanded}"
|
|
style="flex-grow: 0;"
|
|
>
|
|
<drag-handle
|
|
v-if="organize"
|
|
class="mr-2"
|
|
:class="selected && 'primary--text'"
|
|
:disabled="expanded"
|
|
/>
|
|
<!--{{node && node.order}}-->
|
|
<tree-node-view
|
|
:model="node"
|
|
:selected="selected"
|
|
:show-external-details="showExternalDetails"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<v-expand-transition>
|
|
<div
|
|
v-show="showExpanded"
|
|
class="pl-3"
|
|
>
|
|
<v-fade-transition hide-on-leave>
|
|
<tree-node-list
|
|
v-if="showExpanded"
|
|
:node="node"
|
|
:children="computedChildren"
|
|
:group="group"
|
|
:organize="organize"
|
|
:selected-node="selectedNode"
|
|
:start-expanded="startExpanded"
|
|
:show-external-details="showExternalDetails"
|
|
@reordered="e => $emit('reordered', e)"
|
|
@reorganized="e => $emit('reorganized', e)"
|
|
@selected="e => $emit('selected', e)"
|
|
/>
|
|
<div v-else>
|
|
<div
|
|
v-for="i in children.length"
|
|
:key="i"
|
|
class="dummy-node"
|
|
/>
|
|
</div>
|
|
</v-fade-transition>
|
|
</div>
|
|
</v-expand-transition>
|
|
</v-sheet>
|
|
</template>
|
|
|
|
<script lang="js">
|
|
/**
|
|
* TreeNode's are list item views of character properties. Every property which
|
|
* can belong to the character is shown in the tree view of the character
|
|
* the tree view shows off the full character structure, and where each part of
|
|
* character comes from.
|
|
**/
|
|
import { canBeParent } from '/imports/api/parenting/parentingFunctions';
|
|
import { getPropertyIcon } from '/imports/constants/PROPERTIES';
|
|
import TreeNodeView from '/imports/client/ui/properties/treeNodeViews/TreeNodeView.vue';
|
|
import { isAncestor } from '/imports/api/parenting/parentingFunctions';
|
|
import { some } from 'lodash';
|
|
|
|
export default {
|
|
name: 'TreeNode',
|
|
components: {
|
|
TreeNodeView,
|
|
},
|
|
props: {
|
|
node: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
group: {
|
|
type: String,
|
|
default: undefined,
|
|
},
|
|
organize: Boolean,
|
|
children: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
getChildren: {
|
|
type: Function,
|
|
default: undefined,
|
|
},
|
|
selectedNode: {
|
|
type: Object,
|
|
default: undefined,
|
|
},
|
|
selected: Boolean,
|
|
startExpanded: Boolean,
|
|
showExternalDetails: Boolean,
|
|
},
|
|
data() {
|
|
return {
|
|
expanded: this.startExpanded ||
|
|
this.node._ancestorOfMatchedDocument ||
|
|
isAncestor(this.node, this.selectedNode),
|
|
}
|
|
},
|
|
computed: {
|
|
hasChildren() {
|
|
return this.children && !!this.children.length || this.lazy && !this.expanded;
|
|
},
|
|
showExpanded() {
|
|
return this.expanded && (this.organize || this.hasChildren)
|
|
},
|
|
computedChildren() {
|
|
let children = [];
|
|
if (this.children) {
|
|
children.push(...this.children)
|
|
}
|
|
if (this.getChildren) {
|
|
children.push(...this.getChildren())
|
|
}
|
|
return children;
|
|
},
|
|
canExpand() {
|
|
return canBeParent(this.node.type);
|
|
},
|
|
},
|
|
watch: {
|
|
'node._ancestorOfMatchedDocument'(value) {
|
|
this.expanded = !!value ||
|
|
some(this.selectedNode?.ancestors, ref => ref.id === this.node._id);
|
|
},
|
|
'selectedNode.parentId'() {
|
|
this.expanded = isAncestor(this.node, this.selectedNode) || this.expanded;
|
|
},
|
|
},
|
|
beforeCreate() {
|
|
this.$options.components.TreeNodeList = require('./TreeNodeList.vue').default
|
|
},
|
|
methods: {
|
|
icon(type) {
|
|
return getPropertyIcon(type);
|
|
},
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="css" scoped>
|
|
.rotate-90 {
|
|
transform: rotate(90deg) translateZ(0);
|
|
}
|
|
|
|
.drag-area {
|
|
box-shadow: -2px 0px 0px 0px #808080;
|
|
margin-left: 0;
|
|
min-height: 32px;
|
|
}
|
|
|
|
.empty .drag-area {
|
|
box-shadow: -2px 0px 0px 0px rgb(128, 128, 128, 0.4);
|
|
}
|
|
|
|
.empty .v-btn {
|
|
opacity: 0.4;
|
|
}
|
|
|
|
.found {
|
|
background: rgba(200, 0, 0, 0.1) !important;
|
|
}
|
|
|
|
.ghost {
|
|
opacity: 0.5;
|
|
background: rgba(251, 0, 0, 0.3);
|
|
}
|
|
|
|
.v-icon.v-icon--disabled {
|
|
opacity: 0;
|
|
}
|
|
|
|
.v-icon {
|
|
transition: none !important;
|
|
}
|
|
|
|
.theme--light .tree-node-title:hover {
|
|
background-color: rgba(0, 0, 0, .04);
|
|
}
|
|
|
|
.theme--dark .tree-node-title:hover {
|
|
background-color: rgba(255, 255, 255, .04);
|
|
}
|
|
|
|
.tree-node-title {
|
|
transition: background ease 0.3s, color ease 0.15s;
|
|
}
|
|
|
|
.tree-node-title,
|
|
.dummy-node {
|
|
min-height: 40px;
|
|
}
|
|
</style>
|