Fixed item drag drop re-ordering
This commit is contained in:
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@@ -26,6 +26,7 @@
|
||||
"thumbhash",
|
||||
"uncomputed",
|
||||
"untarget",
|
||||
"vuedraggable",
|
||||
"vuetify",
|
||||
"Vuex",
|
||||
"walkdown"
|
||||
|
||||
@@ -5,7 +5,7 @@ import { assertEditPermission } from '/imports/api/sharing/sharingPermissions';
|
||||
import { organizeDoc } from '/imports/api/parenting/organizeMethods';
|
||||
import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/getRootCreatureAncestor';
|
||||
import BUILT_IN_TAGS from '/imports/constants/BUILT_IN_TAGS';
|
||||
import getParentRefByTag from '/imports/api/creature/creatureProperties/methods/getParentRefByTag';
|
||||
import getParentRefByTag from './getParentByTag';
|
||||
|
||||
// Equipping or unequipping an item will also change its parent
|
||||
const equipItem = new ValidatedMethod({
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties';
|
||||
import { getFilter } from '/imports/api/parenting/parentingFunctions';
|
||||
|
||||
export default function getParentRefByTag(creatureId, tag) {
|
||||
let prop = CreatureProperties.findOne({
|
||||
export default function getParentByTag(creatureId, tag) {
|
||||
return CreatureProperties.findOne({
|
||||
...getFilter.descendantsOfRoot(creatureId),
|
||||
removed: { $ne: true },
|
||||
inactive: { $ne: true },
|
||||
@@ -10,5 +10,4 @@ export default function getParentRefByTag(creatureId, tag) {
|
||||
}, {
|
||||
sort: { left: 1 },
|
||||
});
|
||||
return prop && { id: prop._id, collection: 'creatureProperties' };
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import getRootCreatureAncestor from '/imports/api/creature/creatureProperties/ge
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import { assertEditPermission } from '/imports/api/sharing/sharingPermissions';
|
||||
import { fetchDocByRef, rebuildNestedSets } from '/imports/api/parenting/parentingFunctions';
|
||||
import getParentRefByTag from '/imports/api/creature/creatureProperties/methods/getParentRefByTag';
|
||||
import getParentRefByTag from './getParentByTag';
|
||||
import { RefSchema } from '/imports/api/parenting/ChildSchema';
|
||||
|
||||
const insertProperty = new ValidatedMethod({
|
||||
|
||||
@@ -68,8 +68,8 @@
|
||||
<v-card-text class="px-0">
|
||||
<item-list
|
||||
equipment
|
||||
:items="equippedItems"
|
||||
:parent-ref="equipmentParentRef"
|
||||
:item-ids="equippedItemIds"
|
||||
:parent="equipmentParent"
|
||||
/>
|
||||
</v-card-text>
|
||||
</toolbar-card>
|
||||
@@ -81,8 +81,8 @@
|
||||
</v-toolbar-title>
|
||||
<v-card-text class="px-0">
|
||||
<item-list
|
||||
:items="carriedItems"
|
||||
:parent-ref="carriedParentRef"
|
||||
:item-ids="carriedItemIds"
|
||||
:parent="carriedParent"
|
||||
/>
|
||||
</v-card-text>
|
||||
</toolbar-card>
|
||||
@@ -112,7 +112,7 @@ import ColumnLayout from '/imports/client/ui/components/ColumnLayout.vue';
|
||||
import ContainerCard from '/imports/client/ui/properties/components/inventory/ContainerCard.vue';
|
||||
import ToolbarCard from '/imports/client/ui/components/ToolbarCard.vue';
|
||||
import ItemList from '/imports/client/ui/properties/components/inventory/ItemList.vue';
|
||||
import getParentRefByTag from '/imports/api/creature/creatureProperties/methods/getParentRefByTag';
|
||||
import getParentByTag from '/imports/api/creature/creatureProperties/methods/getParentByTag';
|
||||
import BUILT_IN_TAGS from '/imports/constants/BUILT_IN_TAGS';
|
||||
import CoinValue from '/imports/client/ui/components/CoinValue.vue';
|
||||
import stripFloatingPointOddities from '/imports/api/engine/computation/utility/stripFloatingPointOddities';
|
||||
@@ -141,7 +141,6 @@ export default {
|
||||
tabName: 'inventory',
|
||||
};
|
||||
},
|
||||
// @ts-ignore Meteor isn't defined on vue
|
||||
meteor: {
|
||||
folderIds() {
|
||||
return CreatureProperties.find({
|
||||
@@ -191,7 +190,7 @@ export default {
|
||||
sort: { left: 1 },
|
||||
});
|
||||
},
|
||||
carriedItems() {
|
||||
carriedItemIds() {
|
||||
return CreatureProperties.find({
|
||||
...getFilter.descendantsOfRoot(this.creatureId),
|
||||
$nor: [getFilter.descendantsOfAll(this.containers)],
|
||||
@@ -205,9 +204,10 @@ export default {
|
||||
deactivatedByToggle: { $ne: true },
|
||||
}, {
|
||||
sort: { left: 1 },
|
||||
});
|
||||
fields: { _id: 1 },
|
||||
}).map(prop => prop._id);
|
||||
},
|
||||
equippedItems() {
|
||||
equippedItemIds() {
|
||||
return CreatureProperties.find({
|
||||
...getFilter.descendantsOfRoot(this.creatureId),
|
||||
type: 'item',
|
||||
@@ -216,27 +216,22 @@ export default {
|
||||
inactive: { $ne: true },
|
||||
}, {
|
||||
sort: { left: 1 },
|
||||
});
|
||||
fields: { _id: 1 },
|
||||
}).map(prop => prop._id);
|
||||
},
|
||||
equipmentParentRef() {
|
||||
return getParentRefByTag(
|
||||
equipmentParent() {
|
||||
return getParentByTag(
|
||||
this.creatureId, BUILT_IN_TAGS.equipment
|
||||
) || getParentRefByTag(
|
||||
) || getParentByTag(
|
||||
this.creatureId, BUILT_IN_TAGS.inventory
|
||||
) || {
|
||||
id: this.creatureId,
|
||||
collection: 'creatures'
|
||||
};
|
||||
);
|
||||
},
|
||||
carriedParentRef() {
|
||||
return getParentRefByTag(
|
||||
carriedParent() {
|
||||
return getParentByTag(
|
||||
this.creatureId, BUILT_IN_TAGS.carried
|
||||
) || getParentRefByTag(
|
||||
) || getParentByTag(
|
||||
this.creatureId, BUILT_IN_TAGS.inventory
|
||||
) || {
|
||||
id: this.creatureId,
|
||||
collection: 'creatures'
|
||||
};
|
||||
);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties';
|
||||
import Creatures from '/imports/api/creature/creatures/Creatures';
|
||||
import ColumnLayout from '/imports/client/ui/components/ColumnLayout.vue';
|
||||
import getParentRefByTag from '/imports/api/creature/creatureProperties/methods/getParentRefByTag';
|
||||
import getParentRefByTag from '../../../../../api/creature/creatureProperties/methods/getParentByTag';
|
||||
import BUILT_IN_TAGS from '/imports/constants/BUILT_IN_TAGS';
|
||||
import CoinValue from '/imports/client/ui/components/CoinValue.vue';
|
||||
import stripFloatingPointOddities from '/imports/api/engine/computation/utility/stripFloatingPointOddities';
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
ghost-class="ghost"
|
||||
draggable=".creature"
|
||||
handle=".handle"
|
||||
:animation="200"
|
||||
@change="draggableChange"
|
||||
>
|
||||
<creature-list-tile
|
||||
@@ -71,19 +70,6 @@
|
||||
draggableChange({added, moved}){
|
||||
let event = added || moved;
|
||||
if (event){
|
||||
/*
|
||||
// If this item is now adjacent to another, set the order accordingly
|
||||
let order;
|
||||
let before = this.dataCreatures[event.newIndex - 1];
|
||||
let after = this.dataCreatures[event.newIndex + 1];
|
||||
if (before && before._id){
|
||||
order = before.order + 0.5;
|
||||
} else if (after && after._id) {
|
||||
order = after.order - 0.5;
|
||||
} else {
|
||||
order = -0.5;
|
||||
}
|
||||
*/
|
||||
let doc = event.element;
|
||||
moveCreatureToFolder.call({
|
||||
creatureId: doc._id,
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<draggable
|
||||
v-model="dataItems"
|
||||
:group="'item-list'"
|
||||
:animation="200"
|
||||
:sort="false"
|
||||
ghost-class="item-to-creature-ghost"
|
||||
draggable=".no-real-items"
|
||||
@@ -67,7 +66,7 @@
|
||||
<script lang="js">
|
||||
import SharedIcon from '/imports/client/ui/components/SharedIcon.vue';
|
||||
import draggable from 'vuedraggable';
|
||||
import { organizeDoc } from '/imports/api/parenting/organizeMethods';
|
||||
import { moveBetweenRoots } from '/imports/api/parenting/organizeMethods';
|
||||
import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue';
|
||||
|
||||
export default {
|
||||
@@ -91,44 +90,44 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
dropItem({ added }) {
|
||||
async dropItem({ added }) {
|
||||
const item = added?.element;
|
||||
if (!item?._id) return;
|
||||
const docRef = { collection: 'creatureProperties', id: item._id };
|
||||
|
||||
// Create the undo function
|
||||
const oldOrder = item.order;
|
||||
const oldParent = item.parent;
|
||||
// TODO organize doc needs to be replaced with organize between roots
|
||||
const undo = () => organizeDoc.callAsync({
|
||||
const oldRoot = item.root;
|
||||
const oldOrder = item.left;
|
||||
const undo = async () => {
|
||||
try {
|
||||
await moveBetweenRoots.callAsync({
|
||||
docRef,
|
||||
parentRef: oldParent,
|
||||
order: (oldOrder || 0) - 0.5,
|
||||
skipClient: true, // The client no longer has the doc subscribed, so we can't simulate
|
||||
}, (error) => {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
snackbar({ text: error.reason || error.message || error.toString() });
|
||||
}
|
||||
newRootRef: oldRoot,
|
||||
newPosition: (oldOrder || 1) - 0.5,
|
||||
skipClient: true, // The client will no longer have the doc subscribed, so we can't simulate
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
snackbar({ text: e.reason || e.message || e.toString() });
|
||||
}
|
||||
}
|
||||
|
||||
// TODO organize doc needs to be replaced with organize between roots
|
||||
organizeDoc.callAsync({
|
||||
try {
|
||||
await moveBetweenRoots.callAsync({
|
||||
docRef,
|
||||
parentRef: { collection: 'creatures', id: this.model._id },
|
||||
order: -0.5,
|
||||
}, (error) => {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
snackbar({ text: error.reason || error.message || error.toString() });
|
||||
} else {
|
||||
newRootRef: { collection: 'creatures', id: this.model._id },
|
||||
newPosition: 0.5,
|
||||
});
|
||||
snackbar({
|
||||
text: `Moved ${item.name || 'item'} to ${this.model.name || 'another character'}`,
|
||||
callbackName: 'undo',
|
||||
callback: undo,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
snackbar({ text: e.reason || e.message || e.toString() });
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@
|
||||
</template>
|
||||
<v-card-text class="px-0">
|
||||
<item-list
|
||||
:items="items"
|
||||
:parent-ref="{id: model._id, collection: 'creatureProperties'}"
|
||||
:item-ids="itemIds"
|
||||
:parent="model"
|
||||
/>
|
||||
</v-card-text>
|
||||
</toolbar-card>
|
||||
@@ -92,7 +92,7 @@ export default {
|
||||
},
|
||||
},
|
||||
meteor: {
|
||||
items() {
|
||||
itemIds() {
|
||||
return CreatureProperties.find({
|
||||
'parentId': this.model._id,
|
||||
type: { $in: ['item', 'container'] },
|
||||
@@ -102,7 +102,8 @@ export default {
|
||||
deactivatedByToggle: { $ne: true },
|
||||
}, {
|
||||
sort: { left: 1 },
|
||||
});
|
||||
fields: { _id: 1 }
|
||||
}).map(prop => prop._id);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -11,16 +11,16 @@
|
||||
ghost-class="ghost"
|
||||
draggable=".item"
|
||||
handle=".handle"
|
||||
:animation="200"
|
||||
:revert-on-spill="true"
|
||||
@change="change"
|
||||
>
|
||||
<item-list-tile
|
||||
v-for="item in dataItems"
|
||||
:key="item._id"
|
||||
v-for="itemId in dataItems"
|
||||
:key="itemId"
|
||||
class="item"
|
||||
:data-id="item._id"
|
||||
:model="item"
|
||||
@click="clickProperty(item._id)"
|
||||
:data-id="itemId"
|
||||
:item-id="itemId"
|
||||
@click="clickProperty(itemId)"
|
||||
/>
|
||||
</draggable>
|
||||
</v-list>
|
||||
@@ -29,8 +29,10 @@
|
||||
<script lang="js">
|
||||
import draggable from 'vuedraggable';
|
||||
import ItemListTile from '/imports/client/ui/properties/components/inventory/ItemListTile.vue';
|
||||
import { organizeDoc } from '/imports/api/parenting/organizeMethods';
|
||||
import { moveWithinRoot } from '/imports/api/parenting/organizeMethods';
|
||||
import updateCreatureProperty from '/imports/api/creature/creatureProperties/methods/updateCreatureProperty';
|
||||
import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -41,13 +43,13 @@ export default {
|
||||
context: { default: {} }
|
||||
},
|
||||
props: {
|
||||
items: {
|
||||
itemIds: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
parentRef: {
|
||||
parent: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => undefined,
|
||||
},
|
||||
preparingSpells: Boolean,
|
||||
equipment: Boolean,
|
||||
@@ -57,20 +59,13 @@ export default {
|
||||
dataItems: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
levels() {
|
||||
let levels = new Set();
|
||||
this.items.forEach(item => levels.add(item.level));
|
||||
return levels;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
items(value) {
|
||||
itemIds(value) {
|
||||
this.dataItems = value;
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.dataItems = this.items;
|
||||
this.dataItems = this.itemIds;
|
||||
},
|
||||
methods: {
|
||||
clickProperty(_id) {
|
||||
@@ -82,37 +77,58 @@ export default {
|
||||
},
|
||||
change({ added, moved }) {
|
||||
let event = added || moved;
|
||||
if (event) {
|
||||
if (! event) return;
|
||||
// If this item is now adjacent to another, set the order accordingly
|
||||
let order;
|
||||
let before = this.dataItems[event.newIndex - 1];
|
||||
let after = this.dataItems[event.newIndex + 1];
|
||||
if (before && before._id) {
|
||||
order = before.order + 0.5;
|
||||
} else if (after && after._id) {
|
||||
order = after.order - 0.5;
|
||||
const beforeId = this.dataItems[event.newIndex - 1]
|
||||
const afterId = this.dataItems[event.newIndex + 1]
|
||||
const before = beforeId && CreatureProperties.findOne(beforeId);
|
||||
const after = afterId && CreatureProperties.findOne(afterId);
|
||||
if (before) {
|
||||
order = before.right + 0.5;
|
||||
} else if (after) {
|
||||
order = after.left - 0.5;
|
||||
} else if (this.parent) {
|
||||
order = this.parent.left + 0.5;
|
||||
} else {
|
||||
order = -0.5;
|
||||
order = 0.5;
|
||||
}
|
||||
let doc = event.element;
|
||||
organizeDoc.callAsync({
|
||||
let docId = event.element;
|
||||
const doc = CreatureProperties.findOne(docId);
|
||||
if (!doc) return;
|
||||
moveWithinRoot.callAsync({
|
||||
docRef: {
|
||||
id: doc._id,
|
||||
id: docId,
|
||||
collection: 'creatureProperties',
|
||||
},
|
||||
parentRef: this.parentRef,
|
||||
order,
|
||||
newPosition: order,
|
||||
}, (e) => {
|
||||
if (e) {
|
||||
console.error(e);
|
||||
snackbar({ text: e.reason || e.message || e.toString() });
|
||||
}
|
||||
});
|
||||
if (doc.type === 'item' && doc.equipped != this.equipment) {
|
||||
if (doc.type === 'item' && doc.equipped !== this.equipment) {
|
||||
updateCreatureProperty.call({
|
||||
_id: doc._id,
|
||||
_id: docId,
|
||||
path: ['equipped'],
|
||||
value: !!this.equipment,
|
||||
}, (e) => {
|
||||
if (e) {
|
||||
this.dataItems = this.itemIds
|
||||
console.error(e);
|
||||
snackbar({ text: e.reason || e.message || e.toString() });
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
setTimeout(() => this.dataItems = this.items, 0);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.ghost {
|
||||
opacity: 0.1;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -42,21 +42,28 @@
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import treeNodeViewMixin from '/imports/client/ui/properties/treeNodeViews/treeNodeViewMixin';
|
||||
import PROPERTIES from '/imports/constants/PROPERTIES';
|
||||
import adjustQuantity from '/imports/api/creature/creatureProperties/methods/adjustQuantity';
|
||||
import IncrementButton from '/imports/client/ui/components/IncrementButton.vue';
|
||||
import { snackbar } from '/imports/client/ui/components/snackbars/SnackbarQueue';
|
||||
import PropertyIcon from '/imports/client/ui/properties/shared/PropertyIcon.vue';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
IncrementButton,
|
||||
PropertyIcon,
|
||||
},
|
||||
mixins: [treeNodeViewMixin],
|
||||
inject: {
|
||||
context: { default: {} }
|
||||
},
|
||||
props: {
|
||||
itemId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
selected: Boolean,
|
||||
hideIcon: Boolean,
|
||||
preparingSpells: Boolean,
|
||||
},
|
||||
data() {
|
||||
@@ -103,6 +110,11 @@ export default {
|
||||
});
|
||||
}
|
||||
},
|
||||
meteor: {
|
||||
model() {
|
||||
return CreatureProperties.findOne(this.itemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user