Trees can now be freely re-arranged :D
This commit is contained in:
@@ -51,7 +51,7 @@ export function getHighestOrder({collection, parentId}){
|
|||||||
fields: {order: 1},
|
fields: {order: 1},
|
||||||
sort: {order: -1},
|
sort: {order: -1},
|
||||||
});
|
});
|
||||||
return (highestOrderedDoc && highestOrderedDoc.order) || 0;
|
return highestOrderedDoc ? highestOrderedDoc.order : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setDocToLastOrder({collection, doc}){
|
export function setDocToLastOrder({collection, doc}){
|
||||||
@@ -61,7 +61,7 @@ export function setDocToLastOrder({collection, doc}){
|
|||||||
}) + 1;
|
}) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateOrder({docRef, order}){
|
export function updateDocOrder({docRef, order}){
|
||||||
let doc = fetchDocByRef(docRef, {fields: {
|
let doc = fetchDocByRef(docRef, {fields: {
|
||||||
order: 1,
|
order: 1,
|
||||||
parent: 1,
|
parent: 1,
|
||||||
@@ -71,8 +71,7 @@ export function updateOrder({docRef, order}){
|
|||||||
if (currentOrder === order){
|
if (currentOrder === order){
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Move the document to its new order
|
// First move the documents that are in the way
|
||||||
collection.update(doc._id, {$set: {order}}, {selector: {type: 'any'}});
|
|
||||||
let inBetweenSelector, increment;
|
let inBetweenSelector, increment;
|
||||||
if (order > currentOrder){
|
if (order > currentOrder){
|
||||||
// Move in-between docs backward
|
// Move in-between docs backward
|
||||||
@@ -98,9 +97,37 @@ export function updateOrder({docRef, order}){
|
|||||||
multi: true,
|
multi: true,
|
||||||
selector: {type: 'any'},
|
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}){
|
export function reorderDocs({collection, parentId}){
|
||||||
let bulkWrite = [];
|
let bulkWrite = [];
|
||||||
collection.find({
|
collection.find({
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import SimpleSchema from 'simpl-schema';
|
import SimpleSchema from 'simpl-schema';
|
||||||
import { updateParent } from '/imports/api/parenting/parenting.js';
|
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 { RefSchema } from '/imports/api/parenting/ChildSchema.js';
|
||||||
import { assertDocEditPermission } from '/imports/api/sharing/sharingPermissions.js';
|
import { assertDocEditPermission } from '/imports/api/sharing/sharingPermissions.js';
|
||||||
import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js';
|
import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js';
|
||||||
|
import getCollectionByName from '/imports/api/parenting/getCollectionByName.js';
|
||||||
|
|
||||||
const organizeDoc = new ValidatedMethod({
|
const organizeDoc = new ValidatedMethod({
|
||||||
name: 'organize.methods.organizeDoc',
|
name: 'organize.methods.organizeDoc',
|
||||||
@@ -17,14 +18,21 @@ const organizeDoc = new ValidatedMethod({
|
|||||||
}).validator(),
|
}).validator(),
|
||||||
run({docRef, parentRef, order}) {
|
run({docRef, parentRef, order}) {
|
||||||
let doc = fetchDocByRef(docRef);
|
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
|
// The user must be able to edit both the doc and its parent to move it
|
||||||
// successfully
|
// successfully
|
||||||
assertDocEditPermission(doc, this.userId);
|
assertDocEditPermission(doc, this.userId);
|
||||||
let parent = fetchDocByRef(parentRef);
|
let parent = fetchDocByRef(parentRef);
|
||||||
assertDocEditPermission(parent, this.userId);
|
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});
|
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}) {
|
run({docRef, order}) {
|
||||||
let doc = fetchDocByRef(docRef);
|
let doc = fetchDocByRef(docRef);
|
||||||
assertDocEditPermission(doc, this.userId);
|
assertDocEditPermission(doc, this.userId);
|
||||||
updateOrder({docRef, order})
|
updateDocOrder({docRef, order})
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -42,9 +42,6 @@ export function forEachDescendant({collection, ancestorId, filter = {}, options}
|
|||||||
|
|
||||||
// 1 database read
|
// 1 database read
|
||||||
export function getAncestry({parentRef, inheritedFields = {}}){
|
export function getAncestry({parentRef, inheritedFields = {}}){
|
||||||
// Ancestry must include ancestors
|
|
||||||
inheritedFields.ancestors = 1;
|
|
||||||
|
|
||||||
let parentDoc = fetchDocByRef(parentRef, {fields: inheritedFields});
|
let parentDoc = fetchDocByRef(parentRef, {fields: inheritedFields});
|
||||||
let parent = { ...parentRef};
|
let parent = { ...parentRef};
|
||||||
for (let field in inheritedFields){
|
for (let field in inheritedFields){
|
||||||
@@ -66,24 +63,30 @@ export function updateParent({docRef, parentRef}){
|
|||||||
parent: 1,
|
parent: 1,
|
||||||
ancestors: 1,
|
ancestors: 1,
|
||||||
}});
|
}});
|
||||||
|
let updateOptions = { selector: {type: 'any'} };
|
||||||
|
|
||||||
// Skip if we aren't changing the parent id
|
// Skip if we aren't changing the parent id
|
||||||
if (oldDoc.parent.id === parentRef.id) return;
|
if (oldDoc.parent.id === parentRef.id) return;
|
||||||
|
|
||||||
// update the document's parenting
|
// update the document's parenting
|
||||||
let {parent, ancestors} = getAncestry({parentRef});
|
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
|
// Remove the old ancestors from the descendants
|
||||||
updateDescendants({
|
updateDescendants({
|
||||||
|
collection,
|
||||||
ancestorId: docRef.id,
|
ancestorId: docRef.id,
|
||||||
modifier: {$pullAll: {
|
modifier: {$pullAll: {
|
||||||
ancestors: oldDoc.ancestors,
|
ancestors: oldDoc.ancestors,
|
||||||
}},
|
}},
|
||||||
|
options: updateOptions,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add the new ancestors to the descendants
|
// Add the new ancestors to the descendants
|
||||||
updateDescendants({
|
updateDescendants({
|
||||||
|
collection,
|
||||||
ancestorId: docRef.id,
|
ancestorId: docRef.id,
|
||||||
modifier: {$push: {
|
modifier: {$push: {
|
||||||
ancestors: {
|
ancestors: {
|
||||||
@@ -91,6 +94,7 @@ export function updateParent({docRef, parentRef}){
|
|||||||
$position: 0,
|
$position: 0,
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
|
options: updateOptions,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ let AttributeSchema = new SimpleSchema({
|
|||||||
defaultValue: 'newAttribute',
|
defaultValue: 'newAttribute',
|
||||||
},
|
},
|
||||||
// How it is displayed and computed is determined by type
|
// How it is displayed and computed is determined by type
|
||||||
type: {
|
attributeType: {
|
||||||
type: String,
|
type: String,
|
||||||
allowedValues: [
|
allowedValues: [
|
||||||
'ability', //Strength, Dex, Con, etc.
|
'ability', //Strength, Dex, Con, etc.
|
||||||
|
|||||||
@@ -45,7 +45,11 @@ export function assertEditPermission(doc, userId) {
|
|||||||
|
|
||||||
function getRoot(doc){
|
function getRoot(doc){
|
||||||
assertdocExists(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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<div :class="!hasChildren ? 'empty' : null">
|
<div :class="!hasChildren ? 'empty' : null" :data-id="node._id">
|
||||||
<div class="layout row align-center">
|
<div class="layout row align-center">
|
||||||
<v-btn
|
<v-btn
|
||||||
small icon
|
small icon
|
||||||
@@ -9,9 +9,10 @@
|
|||||||
>
|
>
|
||||||
<v-icon v-if="hasChildren || organize">chevron_right</v-icon>
|
<v-icon v-if="hasChildren || organize">chevron_right</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-icon class="handle mr-2" v-if="organize">reorder</v-icon>
|
<v-icon class="handle mr-2" v-if="organize" :disabled="expanded">reorder</v-icon>
|
||||||
<div>
|
<div>
|
||||||
<span class="mr-2 subheading">{{node && node.order}}</span>
|
<span class="mr-2 caption">{{node && node.order}}</span>
|
||||||
|
<span class="mr-2 caption">({{node && node.type}})</span>
|
||||||
{{node && node.name}}
|
{{node && node.name}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -21,7 +22,7 @@
|
|||||||
:node="node"
|
:node="node"
|
||||||
:children="computedChildren"
|
:children="computedChildren"
|
||||||
:group="group"
|
:group="group"
|
||||||
:show-empty="organize"
|
:organize="organize"
|
||||||
@reordered="e => $emit('reordered', e)"
|
@reordered="e => $emit('reordered', e)"
|
||||||
@reorganized="e => $emit('reorganized', e)"
|
@reorganized="e => $emit('reorganized', e)"
|
||||||
/>
|
/>
|
||||||
@@ -95,4 +96,7 @@
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
background: #c8ebfb;
|
background: #c8ebfb;
|
||||||
}
|
}
|
||||||
|
.v-icon--disabled {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
:value="children"
|
:value="children"
|
||||||
class="drag-area layout column"
|
class="drag-area layout column"
|
||||||
@change="change"
|
@change="change"
|
||||||
|
@start="start"
|
||||||
:group="group"
|
:group="group"
|
||||||
:animation="200"
|
:animation="200"
|
||||||
ghost-class="ghost"
|
ghost-class="ghost"
|
||||||
@@ -67,6 +68,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
start(){
|
||||||
|
console.log({start: arguments})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -33,11 +33,11 @@
|
|||||||
<smart-select
|
<smart-select
|
||||||
label="Type"
|
label="Type"
|
||||||
:items="attributeTypes"
|
:items="attributeTypes"
|
||||||
:value="model.type"
|
:value="model.attributeType"
|
||||||
:error-messages="errors.type"
|
:error-messages="errors.attributeType"
|
||||||
:menu-props="{auto: true, lazy: true}"
|
:menu-props="{auto: true, lazy: true}"
|
||||||
@change="(value, ack) => $emit('change', {path: ['type'], value, ack})"
|
@change="(value, ack) => $emit('change', {path: ['attributeType'], value, ack})"
|
||||||
:hint="attributeTypeHints[model.type]"
|
:hint="attributeTypeHints[model.attributeType]"
|
||||||
:debounce-time="debounceTime"
|
:debounce-time="debounceTime"
|
||||||
/>
|
/>
|
||||||
<form-section name="Advanced" standalone>
|
<form-section name="Advanced" standalone>
|
||||||
|
|||||||
@@ -51,13 +51,13 @@
|
|||||||
let parentRef;
|
let parentRef;
|
||||||
if (parent){
|
if (parent){
|
||||||
parentRef = {
|
parentRef = {
|
||||||
id: this.libraryId,
|
id: parent._id,
|
||||||
collection: 'libraries',
|
collection: 'libraryNodes',
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
parentRef = {
|
parentRef = {
|
||||||
id: parent._id,
|
id: this.libraryId,
|
||||||
collection: 'libraryNodes',
|
collection: 'libraries',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
organizeDoc.call({
|
organizeDoc.call({
|
||||||
|
|||||||
Reference in New Issue
Block a user