UNPKG

substance

Version:

Substance is a JavaScript library for web-based content editing. It provides building blocks for realizing custom text editors and web-based publishing system. It is developed to power our online editing platform [Substance](http://substance.io).

88 lines (85 loc) 3.26 kB
import isArray from '../util/isArray' import uuid from '../util/uuid' // We need to disambiguate ids if the target document // contains a node with the same id. // Unfortunately, this can be difficult in some cases, // e.g. other nodes that have a reference to the re-named node // We only fix annotations for now. export default function _transferWithDisambiguatedIds (sourceDoc, targetDoc, id, visited) { if (visited[id]) throw new Error('FIXME: dont call me twice') visited[id] = id const node = sourceDoc.get(id, 'strict') const nodeData = node.toJSON() const oldId = id let newId if (targetDoc.contains(id)) { // change the node id newId = uuid(node.type) nodeData.id = newId } const annotationIndex = sourceDoc.getIndex('annotations') const nodeSchema = node.getSchema() // collect annotations so that we can create them in the target doc afterwards const annos = [] // now we iterate all properties of the node schema, // to see if there are owned references, which need to be created recursively, // and if there are text properties, where annotations could be attached to for (const prop of nodeSchema) { const name = prop.name if (name === 'id' || name === 'type') continue // Look for references to owned children and create recursively if (prop.isReference() && prop.isOwned()) { // NOTE: we need to recurse directly here, so that we can // update renamed references if (prop.isArray()) { const ids = nodeData[name] nodeData[name] = _transferArrayOfReferences(sourceDoc, targetDoc, ids, visited) } else { const id = nodeData[name] if (!visited[id]) { nodeData[name] = _transferWithDisambiguatedIds(sourceDoc, targetDoc, id, visited) } } // Look for text properties and create annotations in the target doc accordingly } else if (prop.isText()) { // This is really difficult in general // as we don't know where to look for. // TODO: ATM we only look for annotations. // We should also consider anchors / container-annotations // Probably we need a different approach, may const _annos = annotationIndex.get([oldId, prop.name]) // TODO: avoid altering the original node directly for (let i = 0; i < _annos.length; i++) { const anno = _annos[i] if (anno.start.path[0] === oldId && newId) { anno.start.path[0] = newId } if (anno.end.path[0] === oldId && newId) { anno.end.path[0] = newId } annos.push(anno) } } } targetDoc.create(nodeData) for (let i = 0; i < annos.length; i++) { _transferWithDisambiguatedIds(sourceDoc, targetDoc, annos[i].id, visited) } return nodeData.id } function _transferArrayOfReferences (sourceDoc, targetDoc, arr, visited) { const result = arr.slice(0) for (let i = 0; i < arr.length; i++) { const val = arr[i] // multi-dimensional if (isArray(val)) { result[i] = _transferArrayOfReferences(sourceDoc, targetDoc, val, visited) } else { const id = val if (id && !visited[id]) { result[i] = _transferWithDisambiguatedIds(sourceDoc, targetDoc, id, visited) } } } return result }