annotate .cms/lib/codemirror/src/display/update_line.js @ 1:1d486627aa1e draft default tip

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