diff .cms/lib/codemirror/src/model/line_widget.js @ 0:78edf6b517a0 draft

24.10
author Coffee CMS <info@coffee-cms.ru>
date Fri, 11 Oct 2024 22:40:23 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.cms/lib/codemirror/src/model/line_widget.js	Fri Oct 11 22:40:23 2024 +0000
@@ -0,0 +1,78 @@
+import { runInOp } from "../display/operations.js"
+import { addToScrollTop } from "../display/scrolling.js"
+import { regLineChange } from "../display/view_tracking.js"
+import { heightAtLine, lineIsHidden } from "../line/spans.js"
+import { lineNo, updateLineHeight } from "../line/utils_line.js"
+import { widgetHeight } from "../measurement/widgets.js"
+import { changeLine } from "./changes.js"
+import { eventMixin } from "../util/event.js"
+import { signalLater } from "../util/operation_group.js"
+
+// Line widgets are block elements displayed above or below a line.
+
+export class LineWidget {
+  constructor(doc, node, options) {
+    if (options) for (let opt in options) if (options.hasOwnProperty(opt))
+      this[opt] = options[opt]
+    this.doc = doc
+    this.node = node
+  }
+
+  clear() {
+    let cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line)
+    if (no == null || !ws) return
+    for (let i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1)
+    if (!ws.length) line.widgets = null
+    let height = widgetHeight(this)
+    updateLineHeight(line, Math.max(0, line.height - height))
+    if (cm) {
+      runInOp(cm, () => {
+        adjustScrollWhenAboveVisible(cm, line, -height)
+        regLineChange(cm, no, "widget")
+      })
+      signalLater(cm, "lineWidgetCleared", cm, this, no)
+    }
+  }
+
+  changed() {
+    let oldH = this.height, cm = this.doc.cm, line = this.line
+    this.height = null
+    let diff = widgetHeight(this) - oldH
+    if (!diff) return
+    if (!lineIsHidden(this.doc, line)) updateLineHeight(line, line.height + diff)
+    if (cm) {
+      runInOp(cm, () => {
+        cm.curOp.forceUpdate = true
+        adjustScrollWhenAboveVisible(cm, line, diff)
+        signalLater(cm, "lineWidgetChanged", cm, this, lineNo(line))
+      })
+    }
+  }
+}
+eventMixin(LineWidget)
+
+function adjustScrollWhenAboveVisible(cm, line, diff) {
+  if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
+    addToScrollTop(cm, diff)
+}
+
+export function addLineWidget(doc, handle, node, options) {
+  let widget = new LineWidget(doc, node, options)
+  let cm = doc.cm
+  if (cm && widget.noHScroll) cm.display.alignWidgets = true
+  changeLine(doc, handle, "widget", line => {
+    let widgets = line.widgets || (line.widgets = [])
+    if (widget.insertAt == null) widgets.push(widget)
+    else widgets.splice(Math.min(widgets.length, Math.max(0, widget.insertAt)), 0, widget)
+    widget.line = line
+    if (cm && !lineIsHidden(doc, line)) {
+      let aboveVisible = heightAtLine(line) < doc.scrollTop
+      updateLineHeight(line, line.height + widgetHeight(widget))
+      if (aboveVisible) addToScrollTop(cm, widget.height)
+      cm.curOp.forceUpdate = true
+    }
+    return true
+  })
+  if (cm) signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle))
+  return widget
+}