Added inserting library subtrees as character property subtrees

This commit is contained in:
Stefan Zermatten
2019-11-05 10:56:04 +02:00
parent 79a4488a28
commit ae0b060f01
6 changed files with 144 additions and 21 deletions

View File

@@ -1,8 +1,15 @@
import SimpleSchema from 'simpl-schema';
import ChildSchema from '/imports/api/parenting/ChildSchema.js';
import ChildSchema, { RefSchema } from '/imports/api/parenting/ChildSchema.js';
import Creature from '/imports/api/creature/Creatures.js';
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js';
import propertySchemasIndex from '/imports/api/properties/propertySchemasIndex.js';
import {
setLineageOfDocs,
getAncestry,
renewDocIds
} from '/imports/api/parenting/parenting.js';
import {setDocToLastOrder} from '/imports/api/parenting/order.js';
let CreatureProperties = new Mongo.Collection('creatureProperties');
@@ -11,12 +18,6 @@ let CreaturePropertySchema = new SimpleSchema({
type: String,
allowedValues: Object.keys(propertySchemasIndex),
},
charId: {
type: String,
regEx: SimpleSchema.RegEx.Id,
index: 1,
optional: true,
},
});
for (let key in propertySchemasIndex){
@@ -44,12 +45,85 @@ function assertPropertyEditPermission(property, userId){
const insertProperty = new ValidatedMethod({
name: 'CreatureProperties.methods.insert',
validate: null,
run(creatureProperty) {
assertPropertyEditPermission(creatureProperty, this.userId);
return CreatureProperties.insert(creatureProperty);
run({creatureProperty, parentRef}) {
// TODO insert a property with the correct ancestry and order
//assertPropertyEditPermission(creatureProperty, this.userId);
//return CreatureProperties.insert(creatureProperty);
// TODO trigger a recalculation of the creature
},
});
const insertPropertyFromLibraryNode = new ValidatedMethod({
name: 'CreatureProperties.methods.insertPropertyFromLibraryNode',
validate: new SimpleSchema({
nodeId: {
type: String,
regEx: SimpleSchema.RegEx.Id,
},
parentRef: {
type: RefSchema,
},
}).validator(),
run({nodeId, parentRef}) {
// get the new ancestry for the properties
let {parentDoc, ancestors} = getAncestry({parentRef});
// Check permission to edit
if (parentRef.collection === 'creatures'){
assertEditPermission(parentDoc, this.userId);
} else if (parentRef.collection === 'creatureProperties'){
assertPropertyEditPermission(parentDoc, this.userId);
} else {
throw `${parentRef.collection} is not a valid parent collection`
}
// Fetch the library node and its decendents, provided they have not been
// removed
let node = LibraryNodes.findOne({
_id: nodeId,
removed: {$ne: true},
});
if (!node) throw `Node not found for nodeId: ${nodeId}`;
let oldParent = node.parent;
let nodes = LibraryNodes.find({
'ancestors.id': nodeId,
removed: {$ne: true},
}).fetch();
// The root node is last in the array of nodes
nodes.push(node);
// re-map all the ancestors
setLineageOfDocs({
docArray: nodes,
newAncestry: ancestors,
oldParent,
});
// Give the docs new IDs without breaking internal references
renewDocIds({
docArray: nodes,
collectionMap: {'libraryNodes': 'creatureProperties'}
});
// Order the root node
setDocToLastOrder({
collection: CreatureProperties,
doc: node,
});
// Insert the creature properties
let docId;
nodes.forEach(doc => {
docId = CreatureProperties.insert(doc);
});
// TODO trigger a recalculation of the creature
// Return the docId of the last property, the inserted root property
return docId;
},
})
/*
const adjustAttribute = new ValidatedMethod({
name: 'Attributes.methods.adjust',
@@ -97,4 +171,4 @@ const adjustAttribute = new ValidatedMethod({
*/
export default CreatureProperties;
export { CreaturePropertySchema, insertProperty };
export { CreaturePropertySchema, insertProperty, insertPropertyFromLibraryNode };

View File

@@ -26,6 +26,7 @@ export function compareOrder(docA, docB){
// Go through their ancestors after the root, and find the first order
// difference
// TODO ancestors don't store order yet
let i, difference;
const length = Math.min(docA.ancestors.length, docB.ancestors.length);
for (i = 1; i < length; i++){

View File

@@ -94,6 +94,46 @@ export function getAncestry({parentRef, inheritedFields = {}}){
return {parentDoc, parent, ancestors};
}
export function setLineageOfDocs({docArray, oldParent, newAncestry}){
//const oldParent = oldAncestry[oldAncestry.length - 1];
const newParent = newAncestry[newAncestry.length - 1];
docArray.forEach(doc => {
if(doc.parent.id === oldParent.id){
doc.parent = newParent;
}
let oldAncestors = doc.ancestors;
let oldParentIndex = oldAncestors.findIndex(a => a.id === oldParent.id);
doc.ancestors = [...newAncestry, ...oldAncestors.slice(oldParentIndex + 1)];
});
}
/**
* Give documents new random ids and transform their references.
* Transform collections of re-IDed docs according to the collection map
*/
export function renewDocIds({docArray, collectionMap}){
// map of {oldId: newId}
let idMap = {};
// Give new ids and map the changes
docArray.forEach(doc => {
let oldId = doc._id;
let newId = Random.id();
doc._id = newId;
idMap[oldId] = newId;
});
const remapReference = ref => {
if (idMap[ref.id]){
ref.id = idMap[ref.id];
ref.collection = collectionMap[ref.collection] || ref.collection;
}
}
docArray.forEach(doc => {
remapReference(doc.parent);
doc.ancestors.forEach(remapReference);
});
}
export function updateParent({docRef, parentRef}){
let collection = getCollectionByName(docRef.collection);
let oldDoc = fetchDocByRef(docRef, {fields: {

View File

@@ -14,7 +14,7 @@
small icon
:class="showExpanded ? 'rotate-90' : null"
@click.stop="expanded = !expanded"
:disabled="!hasChildren && !organize"
:disabled="!hasChildren && !organize || !canExpand"
>
<v-icon v-if="canExpand && (hasChildren || organize)">chevron_right</v-icon>
</v-btn>

View File

@@ -80,7 +80,10 @@
<script>
import CreatureTreeContainer from '/imports/ui/creature/CreatureTreeContainer.vue';
import CreatureProperties, { insertProperty } from '/imports/api/creature/CreatureProperties.js';
import CreatureProperties, {
insertProperty,
insertPropertyFromLibraryNode
} from '/imports/api/creature/CreatureProperties.js';
import PropertyViewer from '/imports/ui/properties/PropertyViewer.vue';
import { setDocToLastOrder } from '/imports/api/parenting/order.js';
import PropertyIcon from '/imports/ui/properties/PropertyIcon.vue';
@@ -123,8 +126,13 @@
this.$store.commit('pushDialogStack', {
component: 'creature-property-from-library-dialog',
elementId: 'insert-creature-property-fab',
callback(creatureProperty){
console.log(creatureProperty);
callback(libraryNode){
console.log({libraryNode});
let propertyId = insertPropertyFromLibraryNode.call({
nodeId: libraryNode._id,
parentRef: {collection: 'creatures', id: that.creatureId},
});
console.log({propertyId});
return;
}
});

View File

@@ -29,19 +29,19 @@ RouterFactory.configure(factory => {
component: Home,
},{
path: '/characterList',
//component: CharacterList,
component: NotImplemented,
component: CharacterList,
//component: NotImplemented,
},{
path: '/library',
component: Library,
},{
path: '/character/:id/:urlName',
//component: CharacterSheetPage,
component: NotImplemented,
component: CharacterSheetPage,
//component: NotImplemented,
},{
path: '/character/:id',
//component: CharacterSheetPage,
component: NotImplemented,
component: CharacterSheetPage,
//component: NotImplemented,
},{
path: '/sign-in',