diff --git a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js index 39d410c0..1cb44914 100644 --- a/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js +++ b/app/imports/api/creature/creatureProperties/methods/insertPropertyFromLibraryNode.js @@ -116,7 +116,7 @@ function insertPropertyFromNode(nodeId, ancestors, order){ nodes = [node, ...nodes]; // set libraryNodeIds - storeLibraryNodeReferences(nodes, nodeId); + storeLibraryNodeReferences(nodes); // re-map all the ancestors setLineageOfDocs({ @@ -149,6 +149,7 @@ function insertPropertyFromNode(nodeId, ancestors, order){ function storeLibraryNodeReferences(nodes){ nodes.forEach(node => { + if (node.libraryNodeId) return; node.libraryNodeId = node._id; }); } @@ -162,20 +163,11 @@ function reifyNodeReferences(nodes, visitedRefs = new Set(), depth = 0){ // Filter out the reference nodes we replace let resultingNodes = nodes.filter(node => { - - // We have already visited this ref and replaced it - if (visitedRefs.has(node._id)) return false; - - // Already replaced an ancestor node - for (let i; i < node.ancestors.length; i++){ - if (visitedRefs.has(node.ancestors[i].id)) return false; - } - // This isn't a reference node, continue as normal if (node.type !== 'reference') return true; // We have gone too deep, keep the reference node as an error - if (depth > 10){ + if (depth >= 10){ if (Meteor.isClient) console.warn('Reference depth limit exceeded'); node.cache = {error: 'Reference depth limit exceeded'}; return true; @@ -211,26 +203,31 @@ function reifyNodeReferences(nodes, visitedRefs = new Set(), depth = 0){ oldParent: referencedNode.parent, }); - // Remove all the looped references and descendents from the new nodes - // We can't rely on the reify recursion to do this, since the IDs are - // getting renewed before it is called - addedNodes = addedNodes.filter(node => { - // Exclude removed referenced - if (visitedRefs.has(node._id)) return false; - - // Exclude descendants of removed references - for (let i; i < node.ancestors.length; i++){ - if (visitedRefs.has(node.ancestors[i].id)) return false; + // Filter all the looped references + addedNodes = addedNodes.filter(addedNode => { + // Add all non-reference nodes + if (addedNode.type !== 'reference'){ + return true; + } + // If this exact reference has already been resolved before, filter it out + if (visitedRefs.has(addedNode._id)){ + return false; + } else { + // Otherwise mark it as visited, and keep it + visitedRefs.add(addedNode._id); + return true; } - return true; }); - // TODO: Force the referencedNode to take the old id of the reference - // such that the reference's children can be kept + // Before renewing Ids make sure the library node reference is stored + storeLibraryNodeReferences(addedNodes); // Give the new referenced sub-tree new ids + // The referenced node must get the id of the ref node so that the + // descendants of the ref node keep their ancestry intact renewDocIds({ docArray: addedNodes, + idMap: { [referencedNode._id]: node._id }, }); // Reify the subtree as well with recursion diff --git a/app/imports/api/parenting/parenting.js b/app/imports/api/parenting/parenting.js index 70e7747d..e5a8cc62 100644 --- a/app/imports/api/parenting/parenting.js +++ b/app/imports/api/parenting/parenting.js @@ -101,7 +101,6 @@ export function getAncestry({parentRef, inheritedFields = {}}){ } 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){ @@ -109,6 +108,7 @@ export function setLineageOfDocs({docArray, oldParent, newAncestry}){ } let oldAncestors = doc.ancestors; let oldParentIndex = oldAncestors.findIndex(a => a.id === oldParent.id); + if (oldParentIndex === -1) return; doc.ancestors = [...newAncestry, ...oldAncestors.slice(oldParentIndex + 1)]; }); } @@ -117,17 +117,15 @@ export function setLineageOfDocs({docArray, oldParent, newAncestry}){ * 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 = {}; - +export function renewDocIds({docArray, collectionMap, idMap = {}}){ + // idMap is a map of {oldId: newId} // Get a random generator that's consistent on client and server let randomSrc = DDP.randomStream('renewDocIds'); // Give new ids and map the changes as {oldId: newId} docArray.forEach(doc => { let oldId = doc._id; - let newId = randomSrc.id(); + let newId = idMap[oldId] || randomSrc.id(); doc._id = newId; idMap[oldId] = newId; }); diff --git a/app/imports/server/publications/searchLibraryNodes.js b/app/imports/server/publications/searchLibraryNodes.js index 88d7e678..ddbbf4ba 100644 --- a/app/imports/server/publications/searchLibraryNodes.js +++ b/app/imports/server/publications/searchLibraryNodes.js @@ -4,7 +4,6 @@ import LibraryNodes from '/imports/api/library/LibraryNodes.js'; import { assertViewPermission } from '/imports/api/sharing/sharingPermissions.js'; Meteor.publish('selectedLibraryNodes', function(selectedNodeIds){ - console.log('attempting selectedLibraryNodes') check(selectedNodeIds, Array); // Limit to 20 selected nodes if (selectedNodeIds.length > 20){