all files / model/ copySelection.js

91.03% Statements 71/78
69.44% Branches 25/36
100% Functions 5/5
93.42% Lines 71/76
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132                        18× 18× 18×   18×   12× 10×             18×                               10× 10×   10× 10× 10×   10× 10×   10× 10×     10× 10× 22× 22×   22×       22×       22× 22× 31× 31×   22×     10×   10× 10×     10×   10× 10×     10×          
import { cloneDeep, forEach } from '../util'
import Document from './Document'
import documentHelpers from './documentHelpers'
import { isFirst, isLast } from './selectionHelpers'
 
/**
  Creates a new document instance containing only the selected content
 
  @param {Object} args object with `selection`
  @return {Object} with a `doc` property that has a fresh doc with the copied content
*/
 
export default function copySelection(doc, selection) {
  Iif (!selection) throw new Error("'selection' is mandatory.")
  let copy = null
  Eif (!selection.isNull() && !selection.isCollapsed()) {
    // return a simplified version if only a piece of text is selected
    if (selection.isPropertySelection()) {
      copy = _copyPropertySelection(doc, selection)
    }
    else if (selection.isContainerSelection()) {
      copy = _copyContainerSelection(doc, selection)
    }
    else Eif (selection.isNodeSelection()) {
      copy = _copyNodeSelection(doc, selection)
    }
    else {
      console.error('Copy is not yet supported for selection type.')
    }
  }
  return copy
}
 
function _copyPropertySelection(doc, selection) {
  let path = selection.start.path
  let offset = selection.start.offset
  let endOffset = selection.end.offset
  let text = doc.get(path)
  let snippet = doc.createSnippet()
  let containerNode = snippet.getContainer()
  snippet.create({
    type: doc.schema.getDefaultTextType(),
    id: Document.TEXT_SNIPPET_ID,
    content: text.substring(offset, endOffset)
  })
  containerNode.show(Document.TEXT_SNIPPET_ID)
  let annotations = doc.getIndex('annotations').get(path, offset, endOffset)
  forEach(annotations, function(anno) {
    let data = cloneDeep(anno.toJSON())
    let path = [Document.TEXT_SNIPPET_ID, 'content']
    data.start = {
      path: path,
      offset: Math.max(offset, anno.start.offset)-offset
    }
    data.end = {
      path: path,
      offset: Math.min(endOffset, anno.end.offset)-offset
    }
    snippet.create(data)
  })
  return snippet
}
 
function _copyContainerSelection(tx, sel) {
  let snippet = tx.createSnippet()
  let container = snippet.getContainer()
 
  let nodeIds = sel.getNodeIds()
  let L = nodeIds.length
  Iif (L === 0) return snippet
 
  let start = sel.start
  let end = sel.end
 
  let skippedFirst = false
  let skippedLast = false
 
  // First copy the whole covered nodes
  let created = {}
  for(let i = 0; i<L; i++) {
    let id = nodeIds[i]
    let node = tx.get(id)
    // skip NIL selections, such as cursor at the end of first node or cursor at the start of last node.
    Iif (i===0 && isLast(tx, start)) {
      skippedFirst = true
      continue
    }
    Iif (i===L-1 && isFirst(tx, end)) {
      skippedLast = true
      continue
    }
    Eif (!created[id]) {
      documentHelpers.copyNode(node).forEach((nodeData) => {
        let copy = snippet.create(nodeData)
        created[copy.id] = true
      })
      container.show(id)
    }
  }
  Eif (!skippedFirst) {
    // ATTENTION: we need the root node here, e.g. the list, not the list items
    let startNode = snippet.get(start.getNodeId()).getRoot()
    if (startNode.isText()) {
      documentHelpers.deleteTextRange(snippet, null, start)
    } else Eif (startNode.isList()) {
      documentHelpers.deleteListRange(snippet, startNode, null, start)
    }
  }
  Eif (!skippedLast) {
    // ATTENTION: we need the root node here, e.g. the list, not the list items
    let endNode = snippet.get(end.getNodeId()).getRoot()
    if (endNode.isText()) {
      documentHelpers.deleteTextRange(snippet, end, null)
    } else Eif (endNode.isList()) {
      documentHelpers.deleteListRange(snippet, endNode, end, null)
    }
  }
  return snippet
}
 
function _copyNodeSelection(doc, selection) {
  let snippet = doc.createSnippet()
  let containerNode = snippet.getContainer()
  let nodeId = selection.getNodeId()
  let node = doc.get(nodeId)
  documentHelpers.copyNode(node).forEach((nodeData) => {
    snippet.create(nodeData)
  })
  containerNode.show(node.id)
  return snippet
}