Inventory now uses filtered tree views to display items in containers

This commit is contained in:
Stefan Zermatten
2020-03-13 11:23:19 +02:00
parent adfe1dc613
commit 2381769ea2
7 changed files with 103 additions and 30 deletions

View File

@@ -1,6 +1,6 @@
import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js';
import getCollectionByName from '/imports/api/parenting/getCollectionByName.js';
import { flatten } from 'lodash';
import { flatten, findLast } from 'lodash';
const generalParents = [
'attribute',
@@ -32,6 +32,9 @@ export function getAllowedParents({childType}){
}
export function isParentAllowed({parentType = 'root', childType}){
return true;
//TODO until there is a good reason to disallow certain parenting options,
// this should just let the user do whatever
if (!childType) throw 'childType is required';
let allowedParents = getAllowedParents({childType});
return allowedParents.includes(parentType);
@@ -205,13 +208,14 @@ export function getName(doc){
}
}
export function nodesToTree({collection, ancestorId}){
export function nodesToTree({collection, ancestorId, filter}){
// Store a dict of all the nodes
let nodeIndex = {};
let nodeList = [];
collection.find({
'ancestors.id': ancestorId,
removed: {$ne: true},
...filter,
}, {
sort: {order: 1}
}).forEach( node => {
@@ -224,12 +228,16 @@ export function nodesToTree({collection, ancestorId}){
});
// Create a forest of trees
let forest = [];
// Either the node is a child of another node, or in the forest as a root
nodeList.forEach(node => {
if (nodeIndex[node.node.parent.id]){
nodeIndex[node.node.parent.id].children.push(node);
// Either the node is a child of its nearest found ancestor, or in the forest as a root
nodeList.forEach(treeNode => {
let ancestorInForest = findLast(
treeNode.node.ancestors,
ancestor => !!nodeIndex[ancestor.id]
);
if (ancestorInForest){
nodeIndex[ancestorInForest.id].children.push(treeNode);
} else {
forest.push(node);
forest.push(treeNode);
}
});
return forest;

View File

@@ -52,6 +52,11 @@ ItemSchema = new SimpleSchema({
type: Boolean,
optional: true,
},
// Unequipped items shouldn't affect creature stats
equipped: {
type: Boolean,
optional: true,
},
});
export { ItemSchema };

View File

@@ -127,7 +127,7 @@
<style lang="css" scoped>
.rotate-90 {
transform: rotate(90deg);
transform: rotate(90deg) translateZ(0);
}
.drag-area {
box-shadow: -2px 0px 0px 0px #808080;

View File

@@ -1,9 +1,40 @@
<template lang="html">
<div class="inventory">
<column-layout>
<v-card>
<v-card-actions>
<v-switch v-model="organize" label="Organize"/>
</v-card-actions>
<!-- Equipping things isn't implemented yet
<creature-properties-tree
:root="{collection: 'creatures', id: creatureId}"
:filter="{
equipped: true,
type: {$in: ['item']},
'ancestors.id': {$nin: containerIds}
}"
@selected="e => clickProperty(e)"
:organize="organize"
group="inventory"
/>
<v-divider/>
-->
<creature-properties-tree
:root="{collection: 'creatures', id: creatureId}"
:filter="{
equipped: {$ne: true},
type: {$in: ['item']},
'ancestors.id': {$nin: containerIds}
}"
@selected="e => clickProperty(e)"
:organize="organize"
group="inventory"
/>
</v-card>
<div v-for="container in containers" :key="container._id">
<container-card
:model="container"
:organize="organize"
/>
</div>
</column-layout>
@@ -13,14 +44,19 @@
<script>
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import CreaturePropertiesTree from '/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue';
import ContainerCard from '/imports/ui/properties/components/inventory/ContainerCard.vue';
export default {
props: {
creatureId: String,
},
data(){ return {
organize: false,
}},
components: {
ColumnLayout,
CreaturePropertiesTree,
ContainerCard,
},
meteor: {
@@ -31,14 +67,20 @@ export default {
removed: {$ne: true},
}, {
sort: {order: 1},
}).map(container => {
container.items = CreatureProperties.find({
'parent.id': container._id,
removed: {$ne: true},
}, {
sort: {order: 1},
}).fetch();
return container;
});
},
},
computed: {
containerIds(){
return this.containers.map(container => container._id);
},
},
methods: {
clickProperty(_id){
this.$store.commit('pushDialogStack', {
component: 'creature-property-dialog',
elementId: `tree-node-${_id}`,
data: {_id},
});
},
},

View File

@@ -16,6 +16,7 @@
:organize="organize"
@selected="e => selected = e"
:selected-node-id="selected"
style="min-width: 320px;"
/>
</div>
<v-divider vertical/>

View File

@@ -1,9 +1,9 @@
<template lang="html">
<v-card-text style="width: initial; max-width: 100%; min-width: 320px;">
<v-card-text style="width: initial; max-width: 100%;">
<tree-node-list
v-if="root"
:children="children"
:group="root.id"
:group="group"
:organize="organize"
:selected-node-id="selectedNodeId"
@selected="e => $emit('selected', e)"
@@ -27,10 +27,19 @@
root: Object,
organize: Boolean,
selectedNodeId: String,
filter: Object,
group: {
type: String,
default: 'creatureProperties'
}
},
meteor: {
children(){
return nodesToTree({collection: CreatureProperties, ancestorId: this.root.id});
return nodesToTree({
collection: CreatureProperties,
ancestorId: this.root.id,
filter: this.filter,
});
},
},
methods: {

View File

@@ -1,20 +1,18 @@
<template lang="html">
<toolbar-card :color="model.color" @toolbarclick="clickProperty(model._id)" :data-id="model._id">
<toolbar-card :color="model.color" @toolbarclick="clickContainer(model._id)" :data-id="model._id">
<template slot="toolbar">
<span>
{{model.name}}
</span>
<v-spacer/>
</template>
<v-list>
<item-list-tile
v-for="item in model.items"
:model="item"
:key="item._id"
:data-id="item._id"
@click="clickProperty(item._id)"
/>
</v-list>
<creature-properties-tree
:root="{collection: 'creatureProperties', id: model._id}"
:filter="{type: {$in: ['container', 'item', 'folder']}}"
@selected="e => clickProperty(e)"
:organize="organize"
group="inventory"
/>
</toolbar-card>
</template>
@@ -22,23 +20,33 @@
import CreatureProperties from '/imports/api/creature/CreatureProperties.js';
import ToolbarCard from '/imports/ui/components/ToolbarCard.vue';
import ItemListTile from '/imports/ui/properties/components/inventory/ItemListTile.vue';
import CreaturePropertiesTree from '/imports/ui/creature/creatureProperties/CreaturePropertiesTree.vue';
export default {
props: {
model: Object,
organize: Boolean,
},
components: {
ToolbarCard,
ItemListTile,
CreaturePropertiesTree,
},
methods: {
clickProperty(_id){
clickContainer(_id){
this.$store.commit('pushDialogStack', {
component: 'creature-property-dialog',
elementId: `${_id}`,
data: {_id},
});
},
clickProperty(_id){
this.$store.commit('pushDialogStack', {
component: 'creature-property-dialog',
elementId: `tree-node-${_id}`,
data: {_id},
});
},
}
};
</script>