diff --git a/app/imports/api/creature/CreatureProperties.js b/app/imports/api/creature/CreatureProperties.js
index 39c8361a..3105f367 100644
--- a/app/imports/api/creature/CreatureProperties.js
+++ b/app/imports/api/creature/CreatureProperties.js
@@ -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 };
diff --git a/app/imports/api/parenting/order.js b/app/imports/api/parenting/order.js
index cab63b09..1a43258b 100644
--- a/app/imports/api/parenting/order.js
+++ b/app/imports/api/parenting/order.js
@@ -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++){
diff --git a/app/imports/api/parenting/parenting.js b/app/imports/api/parenting/parenting.js
index a622394a..33ea860d 100644
--- a/app/imports/api/parenting/parenting.js
+++ b/app/imports/api/parenting/parenting.js
@@ -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: {
diff --git a/app/imports/ui/components/tree/TreeNode.vue b/app/imports/ui/components/tree/TreeNode.vue
index 529f0389..909ea221 100644
--- a/app/imports/ui/components/tree/TreeNode.vue
+++ b/app/imports/ui/components/tree/TreeNode.vue
@@ -14,7 +14,7 @@
small icon
:class="showExpanded ? 'rotate-90' : null"
@click.stop="expanded = !expanded"
- :disabled="!hasChildren && !organize"
+ :disabled="!hasChildren && !organize || !canExpand"
>
chevron_right
diff --git a/app/imports/ui/creature/character/TreeTab.vue b/app/imports/ui/creature/character/TreeTab.vue
index 462f6659..002a3b97 100644
--- a/app/imports/ui/creature/character/TreeTab.vue
+++ b/app/imports/ui/creature/character/TreeTab.vue
@@ -80,7 +80,10 @@