Began making generic tree re-arranging methods, still buggy
This commit is contained in:
@@ -8,7 +8,7 @@ import getModifierFields from '/imports/api/getModifierFields.js';
|
||||
let CreatureProperties = new Mongo.Collection('creatureProperties');
|
||||
|
||||
let CreaturePropertySchema = new SimpleSchema({
|
||||
creaturePropertyType: {
|
||||
type: {
|
||||
type: String,
|
||||
allowedValues: Object.keys(propertySchemas),
|
||||
},
|
||||
@@ -26,7 +26,7 @@ for (let key in propertySchemas){
|
||||
schema.extend(CreaturePropertySchema);
|
||||
schema.extend(ChildSchema);
|
||||
CreatureProperties.attachSchema(schema, {
|
||||
selector: {creaturePropertyType: key}
|
||||
selector: {type: key}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
updateChildren,
|
||||
updateDecendents,
|
||||
updateDescendants,
|
||||
} from '/imports/api/parenting/parenting.js';
|
||||
import { inheritedFields } from '/imports/api/parenting/ChildSchema.js';
|
||||
import MONGO_OPERATORS from '/imports/constants/MONGO_OPERATORS.js';
|
||||
@@ -11,7 +11,7 @@ import MONGO_OPERATORS from '/imports/constants/MONGO_OPERATORS.js';
|
||||
// It should have neglible performance impact for updates that aren't inherited
|
||||
function propagateInheritanceUpdate({_id, update}){
|
||||
let childModifier = {};
|
||||
let decendentModifier = {};
|
||||
let descendantModifier = {};
|
||||
// For each operator
|
||||
for (let operator of MONGO_OPERATORS){
|
||||
// If the operator is in the update, for each field
|
||||
@@ -26,11 +26,11 @@ function propagateInheritanceUpdate({_id, update}){
|
||||
}
|
||||
// If that field is updated and inherited
|
||||
if (inheritedFields.has(modifiedField)){
|
||||
// Perform the same update on the decendents
|
||||
// Perform the same update on the descendants
|
||||
if (!childModifier[operator]) childModifier[operator] = {};
|
||||
if (!decendentModifier[operator]) decendentModifier[operator] = {};
|
||||
if (!descendantModifier[operator]) descendantModifier[operator] = {};
|
||||
childModifier[operator][`parent.${field}`] = update[operator][field];
|
||||
decendentModifier[operator][`ancestors.$.${field}`] = update[operator][field];
|
||||
descendantModifier[operator][`ancestors.$.${field}`] = update[operator][field];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,10 +41,10 @@ function propagateInheritanceUpdate({_id, update}){
|
||||
modifier: childModifier,
|
||||
});
|
||||
|
||||
// Update the ancestors object of its decendents
|
||||
updateDecendents({
|
||||
// Update the ancestors object of its descendants
|
||||
updateDescendants({
|
||||
ancestorId: _id,
|
||||
modifier: decendentModifier,
|
||||
modifier: descendantModifier,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import getModifierFields from '/imports/api/getModifierFields.js';
|
||||
let LibraryNodes = new Mongo.Collection('libraryNodes');
|
||||
|
||||
let LibraryNodeSchema = new SimpleSchema({
|
||||
libraryNodeType: {
|
||||
type: {
|
||||
type: String,
|
||||
allowedValues: Object.keys(librarySchemas),
|
||||
},
|
||||
@@ -20,7 +20,7 @@ for (let key in librarySchemas){
|
||||
schema.extend(LibraryNodeSchema);
|
||||
schema.extend(ChildSchema);
|
||||
LibraryNodes.attachSchema(schema, {
|
||||
selector: {libraryNodeType: key}
|
||||
selector: {type: key}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ const updateNode = new ValidatedMethod({
|
||||
validate({_id, update}){
|
||||
let fields = getModifierFields(update);
|
||||
return !fields.hasAny([
|
||||
'libraryNodeType',
|
||||
'type',
|
||||
'order',
|
||||
'parent',
|
||||
'ancestors',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CreatureSchema } from '/imports/api/creature/Creatures.js';
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import { ActionSchema } from '/imports/api/properties/Actions.js';
|
||||
import { AttributeSchema } from '/imports/api/properties/Attributes.js';
|
||||
import { StoredBuffSchema } from '/imports/api/properties/Buffs.js';
|
||||
@@ -20,7 +20,6 @@ import { ItemSchema } from '/imports/api/properties/Items.js';
|
||||
|
||||
|
||||
const librarySchemas = {
|
||||
creature: CreatureSchema,
|
||||
action: ActionSchema,
|
||||
attribute: AttributeSchema,
|
||||
buff: StoredBuffSchema,
|
||||
@@ -39,6 +38,7 @@ const librarySchemas = {
|
||||
spell: SpellSchema,
|
||||
container: ContainerSchema,
|
||||
item: ItemSchema,
|
||||
any: new SimpleSchema({}),
|
||||
};
|
||||
|
||||
export default librarySchemas;
|
||||
|
||||
@@ -30,3 +30,4 @@ let ChildSchema = new SimpleSchema({
|
||||
});
|
||||
|
||||
export default ChildSchema;
|
||||
export { RefSchema };
|
||||
|
||||
@@ -72,30 +72,31 @@ export function updateOrder({docRef, order}){
|
||||
return;
|
||||
} else {
|
||||
// Move the document to its new order
|
||||
docRef.collection.update(doc._id, {$set: {order}});
|
||||
collection.update(doc._id, {$set: {order}}, {selector: {type: 'any'}});
|
||||
let inBetweenSelector, increment;
|
||||
if (order > currentOrder){
|
||||
// Move in-between docs backward
|
||||
inBetweenSelector = [
|
||||
{$gt: currentOrder},
|
||||
{$lte: order},
|
||||
];
|
||||
inBetweenSelector = {
|
||||
$gt: currentOrder,
|
||||
$lte: order
|
||||
};
|
||||
increment = -1;
|
||||
} else if (order < currentOrder){
|
||||
// Move in-between docs forward
|
||||
inBetweenSelector = [
|
||||
{$lt: currentOrder},
|
||||
{$gte: order},
|
||||
];
|
||||
inBetweenSelector = {
|
||||
$lt: currentOrder,
|
||||
$gte: order
|
||||
};
|
||||
increment = 1;
|
||||
}
|
||||
collection.update({
|
||||
'parent.id': doc.parent.id,
|
||||
order: {$and: inBetweenSelector},
|
||||
order: inBetweenSelector,
|
||||
}, {
|
||||
$inc: {order: increment},
|
||||
}, {
|
||||
multi: true,
|
||||
selector: {type: 'any'},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import { updateParent } from '/imports/api/parenting/parenting.js';
|
||||
|
||||
export default function organizeDoc({docRef, parentRef, order}){
|
||||
updateParent({docRef, parentRef});
|
||||
updateOrder({docRef, order})
|
||||
};
|
||||
47
app/imports/api/parenting/organizeMethods.js
Normal file
47
app/imports/api/parenting/organizeMethods.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import { updateParent } from '/imports/api/parenting/parenting.js';
|
||||
import { updateOrder } 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';
|
||||
|
||||
const organizeDoc = new ValidatedMethod({
|
||||
name: 'organize.methods.organizeDoc',
|
||||
validate: new SimpleSchema({
|
||||
docRef: RefSchema,
|
||||
parentRef: RefSchema,
|
||||
order: {
|
||||
type: Number,
|
||||
min: 0,
|
||||
},
|
||||
}).validator(),
|
||||
run({docRef, parentRef, order}) {
|
||||
let doc = fetchDocByRef(docRef);
|
||||
|
||||
// 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);
|
||||
updateParent({docRef, parentRef});
|
||||
updateOrder({docRef, order})
|
||||
},
|
||||
});
|
||||
|
||||
const reorderDoc = new ValidatedMethod({
|
||||
name: 'organize.methods.reorderDoc',
|
||||
validate: new SimpleSchema({
|
||||
docRef: RefSchema,
|
||||
order: {
|
||||
type: Number,
|
||||
min: 0,
|
||||
},
|
||||
}).validator(),
|
||||
run({docRef, order}) {
|
||||
let doc = fetchDocByRef(docRef);
|
||||
assertDocEditPermission(doc, this.userId);
|
||||
updateOrder({docRef, order})
|
||||
},
|
||||
});
|
||||
|
||||
export { organizeDoc, reorderDoc };
|
||||
@@ -1,6 +1,5 @@
|
||||
import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js';
|
||||
import getCollectionByName from '/imports/api/parenting/getCollectionByName.js';
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
|
||||
export function fetchParent({id, collection}){
|
||||
return fetchDocByRef({id, collection});
|
||||
@@ -23,20 +22,20 @@ export function updateChildren({collection, parentId, filter = {}, modifier, opt
|
||||
collection.update(filter, modifier, options);
|
||||
}
|
||||
|
||||
export function fetchDecendents({ collection, ancestorId, filter = {}, options}){
|
||||
export function fetchDescendants({ collection, ancestorId, filter = {}, options}){
|
||||
filter["ancestors.id"] = ancestorId;
|
||||
let decendents = [];
|
||||
decendents.push(...collection.find(filter, options).fetch());
|
||||
return decendents;
|
||||
let descendants = [];
|
||||
descendants.push(...collection.find(filter, options).fetch());
|
||||
return descendants;
|
||||
}
|
||||
|
||||
export function updateDecendents({collection, ancestorId, filter = {}, modifier, options={}}){
|
||||
export function updateDescendants({collection, ancestorId, filter = {}, modifier, options={}}){
|
||||
filter["ancestors.id"] = ancestorId;
|
||||
options.multi = true;
|
||||
collection.update(filter, modifier, options);
|
||||
}
|
||||
|
||||
export function forEachDecendent({collection, ancestorId, filter = {}, options}, callback){
|
||||
export function forEachDescendant({collection, ancestorId, filter = {}, options}, callback){
|
||||
filter["ancestors.id"] = ancestorId;
|
||||
collection.find(filter, options).forEach(callback);
|
||||
}
|
||||
@@ -75,16 +74,16 @@ export function updateParent({docRef, parentRef}){
|
||||
let {parent, ancestors} = getAncestry({parentRef});
|
||||
collection.update(docRef.id, {$set: {parent, ancestors}});
|
||||
|
||||
// Remove the old ancestors from the decendents
|
||||
updateDecendents({
|
||||
// Remove the old ancestors from the descendants
|
||||
updateDescendants({
|
||||
ancestorId: docRef.id,
|
||||
modifier: {$pullAll: {
|
||||
ancestors: oldDoc.ancestors,
|
||||
}},
|
||||
});
|
||||
|
||||
// Add the new ancestors to the decendents
|
||||
updateDecendents({
|
||||
// Add the new ancestors to the descendants
|
||||
updateDescendants({
|
||||
ancestorId: docRef.id,
|
||||
modifier: {$push: {
|
||||
ancestors: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import getCollectionByName from '/imports/api/parenting/getCollectionByName.js';
|
||||
import updateDecendents from '/imports/api/parenting/parenting.js';
|
||||
import updateDescendants from '/imports/api/parenting/parenting.js';
|
||||
|
||||
// 1 + n database hits
|
||||
export function softRemove({_id, collection}){
|
||||
@@ -12,9 +12,9 @@ export function softRemove({_id, collection}){
|
||||
}, $unset: {
|
||||
removedWith: 1,
|
||||
}});
|
||||
// Remove all the decendents that have not yet been removed, and set them to be
|
||||
// Remove all the descendants that have not yet been removed, and set them to be
|
||||
// removed with this document
|
||||
updateDecendents({
|
||||
updateDescendants({
|
||||
ancestorId: _id,
|
||||
filter: {removed: {$ne: true}},
|
||||
modifier: {$set: {
|
||||
@@ -41,7 +41,7 @@ export function restore({_id, collection}){
|
||||
removedAt: 1,
|
||||
}});
|
||||
if (numUpdated === 0) restoreError();
|
||||
updateDecendents({
|
||||
updateDescendants({
|
||||
ancestorId: _id,
|
||||
filter: {
|
||||
removedWith: _id,
|
||||
|
||||
@@ -80,4 +80,4 @@ let ActionSchema = new SimpleSchema({
|
||||
},
|
||||
});
|
||||
|
||||
export default { ActionSchema };
|
||||
export { ActionSchema };
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { _ } from 'meteor/underscore';
|
||||
import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js';
|
||||
|
||||
function assertIdValid(userId){
|
||||
if (!userId || typeof userId !== 'string'){
|
||||
@@ -25,6 +26,12 @@ export function assertOwnership(doc, userId){
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the user can edit the root document which manages its own sharing
|
||||
* permissions.
|
||||
*
|
||||
* Warning: the doc and userId must be set by a trusted source
|
||||
*/
|
||||
export function assertEditPermission(doc, userId) {
|
||||
assertIdValid(userId);
|
||||
assertdocExists(doc);
|
||||
@@ -36,6 +43,22 @@ export function assertEditPermission(doc, userId) {
|
||||
}
|
||||
}
|
||||
|
||||
function getRoot(doc){
|
||||
assertdocExists(doc);
|
||||
return fetchDocByRef(doc.ancestors && doc.ancestors.length && doc.ancestors[0] || doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the user can edit a descendant document whose root ancestor
|
||||
* implements sharing permissions.
|
||||
*
|
||||
* Warning: the doc and userId must be set by a trusted source
|
||||
*/
|
||||
export function assertDocEditPermission(doc, userId){
|
||||
let root = getRoot(doc);
|
||||
assertEditPermission(root, userId);
|
||||
}
|
||||
|
||||
export function assertViewPermission(doc, userId) {
|
||||
assertIdValid(userId);
|
||||
assertdocExists(doc);
|
||||
@@ -51,3 +74,14 @@ export function assertViewPermission(doc, userId) {
|
||||
`You do not have permission to view this character`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the user can view a descendant document whose root ancestor
|
||||
* implements sharing permissions.
|
||||
*
|
||||
* Warning: the doc and userId must be set by a trusted source
|
||||
*/
|
||||
export function assertDocViewPermission(doc, userId){
|
||||
let root = getRoot(doc);
|
||||
assertViewPermission(root, userId);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
:children="computedChildren"
|
||||
:group="group"
|
||||
:show-empty="organize"
|
||||
@moved="e => $emit('moved', e)"
|
||||
@reordered="e => $emit('reordered', e)"
|
||||
@reorganized="e => $emit('reorganized', e)"
|
||||
/>
|
||||
</div>
|
||||
</v-expand-transition>
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
:organize="organize"
|
||||
:lazy="lazy"
|
||||
class="item"
|
||||
@moved="e => $emit('moved', e)"
|
||||
@reordered="e => $emit('reordered', e)"
|
||||
@reorganized="e => $emit('reorganized', e)"
|
||||
@dragstart.native="e => e.dataTransfer.setData('cow', child.node && child.node.name)"
|
||||
/>
|
||||
</draggable>
|
||||
@@ -54,10 +55,17 @@
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
change({added, removed, moved}){
|
||||
if (removed) return;
|
||||
let newIndex = (added || moved).newIndex;
|
||||
this.$emit('moved', {parent: this.node, newIndex});
|
||||
change({added, moved}){
|
||||
let event = moved || added;
|
||||
if (event){
|
||||
let newIndex = event.newIndex;
|
||||
let doc = event.element.node;
|
||||
if (moved){
|
||||
this.$emit('reordered', {doc, newIndex});
|
||||
} else if (added){
|
||||
this.$emit('reorganized', {doc, parent: this.node, newIndex});
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
:children="libraryChildren"
|
||||
:group="library && library._id"
|
||||
:organize="organize"
|
||||
@moved="moved"
|
||||
@reordered="reordered"
|
||||
@reorganized="reorganized"
|
||||
/>
|
||||
</v-card-text>
|
||||
</template>
|
||||
@@ -14,6 +15,7 @@
|
||||
import Libraries from '/imports/api/library/Libraries.js';
|
||||
import LibraryNodes, { libraryNodesToTree } from '/imports/api/library/LibraryNodes.js';
|
||||
import TreeNodeList from '/imports/ui/components/tree/TreeNodeList.vue';
|
||||
import { organizeDoc, reorderDoc } from '/imports/api/parenting/organizeMethods.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -36,8 +38,36 @@
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
moved(e){
|
||||
console.log(e)
|
||||
reordered({doc, newIndex}){
|
||||
reorderDoc.call({
|
||||
docRef: {
|
||||
id: doc._id,
|
||||
collection: 'libraryNodes',
|
||||
},
|
||||
order: newIndex,
|
||||
});
|
||||
},
|
||||
reorganized({doc, parent, newIndex}){
|
||||
let parentRef;
|
||||
if (parent){
|
||||
parentRef = {
|
||||
id: this.libraryId,
|
||||
collection: 'libraries',
|
||||
};
|
||||
} else {
|
||||
parentRef = {
|
||||
id: parent._id,
|
||||
collection: 'libraryNodes',
|
||||
};
|
||||
}
|
||||
organizeDoc.call({
|
||||
docRef: {
|
||||
id: doc._id,
|
||||
collection: 'libraryNodes',
|
||||
},
|
||||
parentRef,
|
||||
order: newIndex,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -38,7 +38,7 @@ export default {
|
||||
mixins: [schemaFormMixin],
|
||||
data(){return {
|
||||
model: {
|
||||
libraryNodeType: this.type,
|
||||
type: this.type,
|
||||
},
|
||||
schema: undefined,
|
||||
validationContext: undefined,
|
||||
@@ -52,7 +52,7 @@ export default {
|
||||
this.schema = librarySchemas[newType];
|
||||
this.validationContext = this.schema.newContext();
|
||||
let model = this.schema.clean({});
|
||||
model.libraryNodeType = newType;
|
||||
model.type = newType;
|
||||
this.model = model;
|
||||
},
|
||||
model(newModel){
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
elementId: 'insert-library-node-fab',
|
||||
callback(libraryNode){
|
||||
if (!libraryNode) return;
|
||||
libraryNode.parent = {collection: "library", id: that.library._id};
|
||||
libraryNode.ancestors = [ {collection: "library", id: that.library._id}];
|
||||
libraryNode.parent = {collection: "libraries", id: that.library._id};
|
||||
libraryNode.ancestors = [ {collection: "libraries", id: that.library._id}];
|
||||
setDocToLastOrder({collection: LibraryNodes, doc: libraryNode});
|
||||
console.log(libraryNode);
|
||||
let libraryNodeId = insertNode.call(libraryNode);
|
||||
|
||||
@@ -3,3 +3,4 @@ import "/imports/api/creature/creatureComputation.js";
|
||||
import "/imports/api/parenting/deleteRemovedDocuments.js";
|
||||
import "/imports/server/config/accountsMeldConfig.js";
|
||||
import "/imports/server/config/simpleSchemaDebug.js";
|
||||
import "/imports/api/parenting/organizeMethods.js";
|
||||
|
||||
Reference in New Issue
Block a user