From 4f93ad3e9b728b14d4ae5315fa33fb85701bc24b Mon Sep 17 00:00:00 2001 From: Stefan Zermatten Date: Wed, 31 Jul 2019 11:52:11 +0200 Subject: [PATCH] Trees can now be freely re-arranged :D --- app/imports/api/parenting/order.js | 35 ++++++++++++++++--- app/imports/api/parenting/organizeMethods.js | 16 ++++++--- app/imports/api/parenting/parenting.js | 12 ++++--- app/imports/api/properties/Attributes.js | 2 +- app/imports/api/sharing/sharingPermissions.js | 6 +++- app/imports/ui/components/tree/TreeNode.vue | 12 ++++--- .../ui/components/tree/TreeNodeList.vue | 4 +++ app/imports/ui/forms/AttributeForm.vue | 8 ++--- .../ui/library/LibraryContentsContainer.vue | 8 ++--- 9 files changed, 77 insertions(+), 26 deletions(-) diff --git a/app/imports/api/parenting/order.js b/app/imports/api/parenting/order.js index 6bb58e43..32172c59 100644 --- a/app/imports/api/parenting/order.js +++ b/app/imports/api/parenting/order.js @@ -51,7 +51,7 @@ export function getHighestOrder({collection, parentId}){ fields: {order: 1}, sort: {order: -1}, }); - return (highestOrderedDoc && highestOrderedDoc.order) || 0; + return highestOrderedDoc ? highestOrderedDoc.order : -1; } export function setDocToLastOrder({collection, doc}){ @@ -61,7 +61,7 @@ export function setDocToLastOrder({collection, doc}){ }) + 1; } -export function updateOrder({docRef, order}){ +export function updateDocOrder({docRef, order}){ let doc = fetchDocByRef(docRef, {fields: { order: 1, parent: 1, @@ -71,8 +71,7 @@ export function updateOrder({docRef, order}){ if (currentOrder === order){ return; } else { - // Move the document to its new order - collection.update(doc._id, {$set: {order}}, {selector: {type: 'any'}}); + // First move the documents that are in the way let inBetweenSelector, increment; if (order > currentOrder){ // Move in-between docs backward @@ -98,9 +97,37 @@ export function updateOrder({docRef, order}){ multi: true, selector: {type: 'any'}, }); + // Then move the document itself + collection.update(doc._id, {$set: {order}}, {selector: {type: 'any'}}); } } +export function removedDocAtOrder({collection, doc}){ + // Decrement the order of all docs after the removed doc + collection.update({ + 'parent.id': doc.parent.id, + order: {$gt: doc.order}, + }, { + $inc: {order: -1}, + }, { + multi: true, + selector: {type: 'any'}, + }); +} + +export function insertedDocAtOrder({collection, parentId, order}){ + // Decrement the order of all docs after the removed doc + collection.update({ + 'parent.id': parentId, + order: {$gte: order}, + }, { + $inc: {order: 1}, + }, { + multi: true, + selector: {type: 'any'}, + }); +} + export function reorderDocs({collection, parentId}){ let bulkWrite = []; collection.find({ diff --git a/app/imports/api/parenting/organizeMethods.js b/app/imports/api/parenting/organizeMethods.js index 7bc233c7..3f9120e2 100644 --- a/app/imports/api/parenting/organizeMethods.js +++ b/app/imports/api/parenting/organizeMethods.js @@ -1,9 +1,10 @@ import SimpleSchema from 'simpl-schema'; import { updateParent } from '/imports/api/parenting/parenting.js'; -import { updateOrder } from '/imports/api/parenting/order.js'; +import { insertedDocAtOrder, removedDocAtOrder, updateDocOrder } from '/imports/api/parenting/order.js'; import { RefSchema } from '/imports/api/parenting/ChildSchema.js'; import { assertDocEditPermission } from '/imports/api/sharing/sharingPermissions.js'; import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js'; +import getCollectionByName from '/imports/api/parenting/getCollectionByName.js'; const organizeDoc = new ValidatedMethod({ name: 'organize.methods.organizeDoc', @@ -17,14 +18,21 @@ const organizeDoc = new ValidatedMethod({ }).validator(), run({docRef, parentRef, order}) { let doc = fetchDocByRef(docRef); - + let collection = getCollectionByName(docRef.collection); // The user must be able to edit both the doc and its parent to move it // successfully assertDocEditPermission(doc, this.userId); let parent = fetchDocByRef(parentRef); assertDocEditPermission(parent, this.userId); + + // Reorder the documents in the doc's old parent + removedDocAtOrder({collection, doc}); + // Reorder the docs in the destination parent + insertedDocAtOrder({collection, parentId: parentRef.id, order}); + // Change the doc's parent updateParent({docRef, parentRef}); - updateOrder({docRef, order}) + // Change the doc's order + collection.update(doc._id, {$set: {order}}, {selector: {type: 'any'}}); }, }); @@ -40,7 +48,7 @@ const reorderDoc = new ValidatedMethod({ run({docRef, order}) { let doc = fetchDocByRef(docRef); assertDocEditPermission(doc, this.userId); - updateOrder({docRef, order}) + updateDocOrder({docRef, order}) }, }); diff --git a/app/imports/api/parenting/parenting.js b/app/imports/api/parenting/parenting.js index 4f17df34..58b9784e 100644 --- a/app/imports/api/parenting/parenting.js +++ b/app/imports/api/parenting/parenting.js @@ -42,9 +42,6 @@ export function forEachDescendant({collection, ancestorId, filter = {}, options} // 1 database read export function getAncestry({parentRef, inheritedFields = {}}){ - // Ancestry must include ancestors - inheritedFields.ancestors = 1; - let parentDoc = fetchDocByRef(parentRef, {fields: inheritedFields}); let parent = { ...parentRef}; for (let field in inheritedFields){ @@ -66,24 +63,30 @@ export function updateParent({docRef, parentRef}){ parent: 1, ancestors: 1, }}); + let updateOptions = { selector: {type: 'any'} }; // Skip if we aren't changing the parent id if (oldDoc.parent.id === parentRef.id) return; // update the document's parenting let {parent, ancestors} = getAncestry({parentRef}); - collection.update(docRef.id, {$set: {parent, ancestors}}); + collection.update(docRef.id, { + $set: {parent, ancestors} + }, updateOptions); // Remove the old ancestors from the descendants updateDescendants({ + collection, ancestorId: docRef.id, modifier: {$pullAll: { ancestors: oldDoc.ancestors, }}, + options: updateOptions, }); // Add the new ancestors to the descendants updateDescendants({ + collection, ancestorId: docRef.id, modifier: {$push: { ancestors: { @@ -91,6 +94,7 @@ export function updateParent({docRef, parentRef}){ $position: 0, }, }}, + options: updateOptions, }); } diff --git a/app/imports/api/properties/Attributes.js b/app/imports/api/properties/Attributes.js index d7c52560..b191c2dd 100644 --- a/app/imports/api/properties/Attributes.js +++ b/app/imports/api/properties/Attributes.js @@ -17,7 +17,7 @@ let AttributeSchema = new SimpleSchema({ defaultValue: 'newAttribute', }, // How it is displayed and computed is determined by type - type: { + attributeType: { type: String, allowedValues: [ 'ability', //Strength, Dex, Con, etc. diff --git a/app/imports/api/sharing/sharingPermissions.js b/app/imports/api/sharing/sharingPermissions.js index aa5560ea..91a47f56 100644 --- a/app/imports/api/sharing/sharingPermissions.js +++ b/app/imports/api/sharing/sharingPermissions.js @@ -45,7 +45,11 @@ export function assertEditPermission(doc, userId) { function getRoot(doc){ assertdocExists(doc); - return fetchDocByRef(doc.ancestors && doc.ancestors.length && doc.ancestors[0] || doc); + if (doc.ancestors && doc.ancestors.length && doc.ancestors[0]){ + return fetchDocByRef(doc.ancestors[0]); + } else { + return doc; + } } /** diff --git a/app/imports/ui/components/tree/TreeNode.vue b/app/imports/ui/components/tree/TreeNode.vue index 531f88fc..d4f7c463 100644 --- a/app/imports/ui/components/tree/TreeNode.vue +++ b/app/imports/ui/components/tree/TreeNode.vue @@ -1,5 +1,5 @@