openrat-cms

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

update_line.js (7819B)


      1 import { buildLineContent } from "../line/line_data.js"
      2 import { lineNumberFor } from "../line/utils_line.js"
      3 import { ie, ie_version } from "../util/browser.js"
      4 import { elt } from "../util/dom.js"
      5 import { signalLater } from "../util/operation_group.js"
      6 
      7 // When an aspect of a line changes, a string is added to
      8 // lineView.changes. This updates the relevant part of the line's
      9 // DOM structure.
     10 export function updateLineForChanges(cm, lineView, lineN, dims) {
     11   for (let j = 0; j < lineView.changes.length; j++) {
     12     let type = lineView.changes[j]
     13     if (type == "text") updateLineText(cm, lineView)
     14     else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims)
     15     else if (type == "class") updateLineClasses(cm, lineView)
     16     else if (type == "widget") updateLineWidgets(cm, lineView, dims)
     17   }
     18   lineView.changes = null
     19 }
     20 
     21 // Lines with gutter elements, widgets or a background class need to
     22 // be wrapped, and have the extra elements added to the wrapper div
     23 function ensureLineWrapped(lineView) {
     24   if (lineView.node == lineView.text) {
     25     lineView.node = elt("div", null, null, "position: relative")
     26     if (lineView.text.parentNode)
     27       lineView.text.parentNode.replaceChild(lineView.node, lineView.text)
     28     lineView.node.appendChild(lineView.text)
     29     if (ie && ie_version < 8) lineView.node.style.zIndex = 2
     30   }
     31   return lineView.node
     32 }
     33 
     34 function updateLineBackground(cm, lineView) {
     35   let cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass
     36   if (cls) cls += " CodeMirror-linebackground"
     37   if (lineView.background) {
     38     if (cls) lineView.background.className = cls
     39     else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null }
     40   } else if (cls) {
     41     let wrap = ensureLineWrapped(lineView)
     42     lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild)
     43     cm.display.input.setUneditable(lineView.background)
     44   }
     45 }
     46 
     47 // Wrapper around buildLineContent which will reuse the structure
     48 // in display.externalMeasured when possible.
     49 function getLineContent(cm, lineView) {
     50   let ext = cm.display.externalMeasured
     51   if (ext && ext.line == lineView.line) {
     52     cm.display.externalMeasured = null
     53     lineView.measure = ext.measure
     54     return ext.built
     55   }
     56   return buildLineContent(cm, lineView)
     57 }
     58 
     59 // Redraw the line's text. Interacts with the background and text
     60 // classes because the mode may output tokens that influence these
     61 // classes.
     62 function updateLineText(cm, lineView) {
     63   let cls = lineView.text.className
     64   let built = getLineContent(cm, lineView)
     65   if (lineView.text == lineView.node) lineView.node = built.pre
     66   lineView.text.parentNode.replaceChild(built.pre, lineView.text)
     67   lineView.text = built.pre
     68   if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
     69     lineView.bgClass = built.bgClass
     70     lineView.textClass = built.textClass
     71     updateLineClasses(cm, lineView)
     72   } else if (cls) {
     73     lineView.text.className = cls
     74   }
     75 }
     76 
     77 function updateLineClasses(cm, lineView) {
     78   updateLineBackground(cm, lineView)
     79   if (lineView.line.wrapClass)
     80     ensureLineWrapped(lineView).className = lineView.line.wrapClass
     81   else if (lineView.node != lineView.text)
     82     lineView.node.className = ""
     83   let textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass
     84   lineView.text.className = textClass || ""
     85 }
     86 
     87 function updateLineGutter(cm, lineView, lineN, dims) {
     88   if (lineView.gutter) {
     89     lineView.node.removeChild(lineView.gutter)
     90     lineView.gutter = null
     91   }
     92   if (lineView.gutterBackground) {
     93     lineView.node.removeChild(lineView.gutterBackground)
     94     lineView.gutterBackground = null
     95   }
     96   if (lineView.line.gutterClass) {
     97     let wrap = ensureLineWrapped(lineView)
     98     lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
     99                                     `left: ${cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth}px; width: ${dims.gutterTotalWidth}px`)
    100     cm.display.input.setUneditable(lineView.gutterBackground)
    101     wrap.insertBefore(lineView.gutterBackground, lineView.text)
    102   }
    103   let markers = lineView.line.gutterMarkers
    104   if (cm.options.lineNumbers || markers) {
    105     let wrap = ensureLineWrapped(lineView)
    106     let gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", `left: ${cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth}px`)
    107     cm.display.input.setUneditable(gutterWrap)
    108     wrap.insertBefore(gutterWrap, lineView.text)
    109     if (lineView.line.gutterClass)
    110       gutterWrap.className += " " + lineView.line.gutterClass
    111     if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
    112       lineView.lineNumber = gutterWrap.appendChild(
    113         elt("div", lineNumberFor(cm.options, lineN),
    114             "CodeMirror-linenumber CodeMirror-gutter-elt",
    115             `left: ${dims.gutterLeft["CodeMirror-linenumbers"]}px; width: ${cm.display.lineNumInnerWidth}px`))
    116     if (markers) for (let k = 0; k < cm.options.gutters.length; ++k) {
    117       let id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]
    118       if (found)
    119         gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
    120                                    `left: ${dims.gutterLeft[id]}px; width: ${dims.gutterWidth[id]}px`))
    121     }
    122   }
    123 }
    124 
    125 function updateLineWidgets(cm, lineView, dims) {
    126   if (lineView.alignable) lineView.alignable = null
    127   for (let node = lineView.node.firstChild, next; node; node = next) {
    128     next = node.nextSibling
    129     if (node.className == "CodeMirror-linewidget")
    130       lineView.node.removeChild(node)
    131   }
    132   insertLineWidgets(cm, lineView, dims)
    133 }
    134 
    135 // Build a line's DOM representation from scratch
    136 export function buildLineElement(cm, lineView, lineN, dims) {
    137   let built = getLineContent(cm, lineView)
    138   lineView.text = lineView.node = built.pre
    139   if (built.bgClass) lineView.bgClass = built.bgClass
    140   if (built.textClass) lineView.textClass = built.textClass
    141 
    142   updateLineClasses(cm, lineView)
    143   updateLineGutter(cm, lineView, lineN, dims)
    144   insertLineWidgets(cm, lineView, dims)
    145   return lineView.node
    146 }
    147 
    148 // A lineView may contain multiple logical lines (when merged by
    149 // collapsed spans). The widgets for all of them need to be drawn.
    150 function insertLineWidgets(cm, lineView, dims) {
    151   insertLineWidgetsFor(cm, lineView.line, lineView, dims, true)
    152   if (lineView.rest) for (let i = 0; i < lineView.rest.length; i++)
    153     insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false)
    154 }
    155 
    156 function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
    157   if (!line.widgets) return
    158   let wrap = ensureLineWrapped(lineView)
    159   for (let i = 0, ws = line.widgets; i < ws.length; ++i) {
    160     let widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget")
    161     if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true")
    162     positionLineWidget(widget, node, lineView, dims)
    163     cm.display.input.setUneditable(node)
    164     if (allowAbove && widget.above)
    165       wrap.insertBefore(node, lineView.gutter || lineView.text)
    166     else
    167       wrap.appendChild(node)
    168     signalLater(widget, "redraw")
    169   }
    170 }
    171 
    172 function positionLineWidget(widget, node, lineView, dims) {
    173   if (widget.noHScroll) {
    174     ;(lineView.alignable || (lineView.alignable = [])).push(node)
    175     let width = dims.wrapperWidth
    176     node.style.left = dims.fixedPos + "px"
    177     if (!widget.coverGutter) {
    178       width -= dims.gutterTotalWidth
    179       node.style.paddingLeft = dims.gutterTotalWidth + "px"
    180     }
    181     node.style.width = width + "px"
    182   }
    183   if (widget.coverGutter) {
    184     node.style.zIndex = 5
    185     node.style.position = "relative"
    186     if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"
    187   }
    188 }