openrat-cms

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

line_widget.min.js (2831B)


      1 import { runInOp } from "../display/operations.js"
      2 import { addToScrollTop } from "../display/scrolling.js"
      3 import { regLineChange } from "../display/view_tracking.js"
      4 import { heightAtLine, lineIsHidden } from "../line/spans.js"
      5 import { lineNo, updateLineHeight } from "../line/utils_line.js"
      6 import { widgetHeight } from "../measurement/widgets.js"
      7 import { changeLine } from "./changes.js"
      8 import { eventMixin } from "../util/event.js"
      9 import { signalLater } from "../util/operation_group.js"
     10 
     11 // Line widgets are block elements displayed above or below a line.
     12 
     13 export class LineWidget {
     14   constructor(doc, node, options) {
     15     if (options) for (let opt in options) if (options.hasOwnProperty(opt))
     16       this[opt] = options[opt]
     17     this.doc = doc
     18     this.node = node
     19   }
     20 
     21   clear() {
     22     let cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line)
     23     if (no == null || !ws) return
     24     for (let i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1)
     25     if (!ws.length) line.widgets = null
     26     let height = widgetHeight(this)
     27     updateLineHeight(line, Math.max(0, line.height - height))
     28     if (cm) {
     29       runInOp(cm, () => {
     30         adjustScrollWhenAboveVisible(cm, line, -height)
     31         regLineChange(cm, no, "widget")
     32       })
     33       signalLater(cm, "lineWidgetCleared", cm, this, no)
     34     }
     35   }
     36 
     37   changed() {
     38     let oldH = this.height, cm = this.doc.cm, line = this.line
     39     this.height = null
     40     let diff = widgetHeight(this) - oldH
     41     if (!diff) return
     42     updateLineHeight(line, line.height + diff)
     43     if (cm) {
     44       runInOp(cm, () => {
     45         cm.curOp.forceUpdate = true
     46         adjustScrollWhenAboveVisible(cm, line, diff)
     47         signalLater(cm, "lineWidgetChanged", cm, this, lineNo(line))
     48       })
     49     }
     50   }
     51 }
     52 eventMixin(LineWidget)
     53 
     54 function adjustScrollWhenAboveVisible(cm, line, diff) {
     55   if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
     56     addToScrollTop(cm, diff)
     57 }
     58 
     59 export function addLineWidget(doc, handle, node, options) {
     60   let widget = new LineWidget(doc, node, options)
     61   let cm = doc.cm
     62   if (cm && widget.noHScroll) cm.display.alignWidgets = true
     63   changeLine(doc, handle, "widget", line => {
     64     let widgets = line.widgets || (line.widgets = [])
     65     if (widget.insertAt == null) widgets.push(widget)
     66     else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget)
     67     widget.line = line
     68     if (cm && !lineIsHidden(doc, line)) {
     69       let aboveVisible = heightAtLine(line) < doc.scrollTop
     70       updateLineHeight(line, line.height + widgetHeight(widget))
     71       if (aboveVisible) addToScrollTop(cm, widget.height)
     72       cm.curOp.forceUpdate = true
     73     }
     74     return true
     75   })
     76   signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle))
     77   return widget
     78 }