openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

document_data.js (4226B)


      1 import { loadMode } from "../display/mode_state.js"
      2 import { runInOp } from "../display/operations.js"
      3 import { regChange } from "../display/view_tracking.js"
      4 import { Line, updateLine } from "../line/line_data.js"
      5 import { findMaxLine } from "../line/spans.js"
      6 import { getLine } from "../line/utils_line.js"
      7 import { estimateLineHeights } from "../measurement/position_measurement.js"
      8 import { addClass, rmClass } from "../util/dom.js"
      9 import { lst } from "../util/misc.js"
     10 import { signalLater } from "../util/operation_group.js"
     11 
     12 // DOCUMENT DATA STRUCTURE
     13 
     14 // By default, updates that start and end at the beginning of a line
     15 // are treated specially, in order to make the association of line
     16 // widgets and marker elements with the text behave more intuitive.
     17 export function isWholeLineUpdate(doc, change) {
     18   return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
     19     (!doc.cm || doc.cm.options.wholeLineUpdateBefore)
     20 }
     21 
     22 // Perform a change on the document data structure.
     23 export function updateDoc(doc, change, markedSpans, estimateHeight) {
     24   function spansFor(n) {return markedSpans ? markedSpans[n] : null}
     25   function update(line, text, spans) {
     26     updateLine(line, text, spans, estimateHeight)
     27     signalLater(line, "change", line, change)
     28   }
     29   function linesFor(start, end) {
     30     let result = []
     31     for (let i = start; i < end; ++i)
     32       result.push(new Line(text[i], spansFor(i), estimateHeight))
     33     return result
     34   }
     35 
     36   let from = change.from, to = change.to, text = change.text
     37   let firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line)
     38   let lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line
     39 
     40   // Adjust the line structure
     41   if (change.full) {
     42     doc.insert(0, linesFor(0, text.length))
     43     doc.remove(text.length, doc.size - text.length)
     44   } else if (isWholeLineUpdate(doc, change)) {
     45     // This is a whole-line replace. Treated specially to make
     46     // sure line objects move the way they are supposed to.
     47     let added = linesFor(0, text.length - 1)
     48     update(lastLine, lastLine.text, lastSpans)
     49     if (nlines) doc.remove(from.line, nlines)
     50     if (added.length) doc.insert(from.line, added)
     51   } else if (firstLine == lastLine) {
     52     if (text.length == 1) {
     53       update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans)
     54     } else {
     55       let added = linesFor(1, text.length - 1)
     56       added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight))
     57       update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0))
     58       doc.insert(from.line + 1, added)
     59     }
     60   } else if (text.length == 1) {
     61     update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0))
     62     doc.remove(from.line + 1, nlines)
     63   } else {
     64     update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0))
     65     update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans)
     66     let added = linesFor(1, text.length - 1)
     67     if (nlines > 1) doc.remove(from.line + 1, nlines - 1)
     68     doc.insert(from.line + 1, added)
     69   }
     70 
     71   signalLater(doc, "change", doc, change)
     72 }
     73 
     74 // Call f for all linked documents.
     75 export function linkedDocs(doc, f, sharedHistOnly) {
     76   function propagate(doc, skip, sharedHist) {
     77     if (doc.linked) for (let i = 0; i < doc.linked.length; ++i) {
     78       let rel = doc.linked[i]
     79       if (rel.doc == skip) continue
     80       let shared = sharedHist && rel.sharedHist
     81       if (sharedHistOnly && !shared) continue
     82       f(rel.doc, shared)
     83       propagate(rel.doc, doc, shared)
     84     }
     85   }
     86   propagate(doc, null, true)
     87 }
     88 
     89 // Attach a document to an editor.
     90 export function attachDoc(cm, doc) {
     91   if (doc.cm) throw new Error("This document is already in use.")
     92   cm.doc = doc
     93   doc.cm = cm
     94   estimateLineHeights(cm)
     95   loadMode(cm)
     96   setDirectionClass(cm)
     97   if (!cm.options.lineWrapping) findMaxLine(cm)
     98   cm.options.mode = doc.modeOption
     99   regChange(cm)
    100 }
    101 
    102 function setDirectionClass(cm) {
    103   ;(cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl")
    104 }
    105 
    106 export function directionChanged(cm) {
    107   runInOp(cm, () => {
    108     setDirectionClass(cm)
    109     regChange(cm)
    110   })
    111 }