annotate .cms/lib/codemirror/src/model/mark_text.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 { eltP } from "../util/dom.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
2 import { eventMixin, hasHandler, on } from "../util/event.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
3 import { endOperation, operation, runInOp, startOperation } from "../display/operations.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
4 import { clipPos, cmp, Pos } from "../line/pos.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
5 import { lineNo, updateLineHeight } from "../line/utils_line.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
6 import { clearLineMeasurementCacheFor, findViewForLine, textHeight } from "../measurement/position_measurement.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
7 import { seeReadOnlySpans, seeCollapsedSpans } from "../line/saw_special_spans.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
8 import { addMarkedSpan, conflictingCollapsedRange, getMarkedSpanFor, lineIsHidden, lineLength, MarkedSpan, removeMarkedSpan, visualLine } from "../line/spans.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
9 import { copyObj, indexOf, lst } from "../util/misc.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
10 import { signalLater } from "../util/operation_group.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
11 import { widgetHeight } from "../measurement/widgets.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
12 import { regChange, regLineChange } from "../display/view_tracking.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
13
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
14 import { linkedDocs } from "./document_data.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
15 import { addChangeToHistory } from "./history.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
16 import { reCheckSelection } from "./selection_updates.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
17
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
18 // TEXTMARKERS
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
19
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
20 // Created with markText and setBookmark methods. A TextMarker is a
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
21 // handle that can be used to clear or find a marked position in the
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
22 // document. Line objects hold arrays (markedSpans) containing
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
23 // {from, to, marker} object pointing to such marker objects, and
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
24 // indicating that such a marker is present on that line. Multiple
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
25 // lines may point to the same marker when it spans across lines.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
26 // The spans will have null for their from/to properties when the
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
27 // marker continues beyond the start/end of the line. Markers have
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
28 // links back to the lines they currently touch.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
29
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
30 // Collapsed markers have unique ids, in order to be able to order
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
31 // them, which is needed for uniquely determining an outer marker
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
32 // when they overlap (they may nest, but not partially overlap).
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
33 let nextMarkerId = 0
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
34
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
35 export class TextMarker {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
36 constructor(doc, type) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
37 this.lines = []
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
38 this.type = type
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
39 this.doc = doc
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
40 this.id = ++nextMarkerId
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
41 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
42
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
43 // Clear the marker.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
44 clear() {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
45 if (this.explicitlyCleared) return
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
46 let cm = this.doc.cm, withOp = cm && !cm.curOp
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
47 if (withOp) startOperation(cm)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
48 if (hasHandler(this, "clear")) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
49 let found = this.find()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
50 if (found) signalLater(this, "clear", found.from, found.to)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
51 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
52 let min = null, max = null
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
53 for (let i = 0; i < this.lines.length; ++i) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
54 let line = this.lines[i]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
55 let span = getMarkedSpanFor(line.markedSpans, this)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
56 if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
57 else if (cm) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
58 if (span.to != null) max = lineNo(line)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
59 if (span.from != null) min = lineNo(line)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
60 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
61 line.markedSpans = removeMarkedSpan(line.markedSpans, span)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
62 if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
63 updateLineHeight(line, textHeight(cm.display))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
64 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
65 if (cm && this.collapsed && !cm.options.lineWrapping) for (let i = 0; i < this.lines.length; ++i) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
66 let visual = visualLine(this.lines[i]), len = lineLength(visual)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
67 if (len > cm.display.maxLineLength) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
68 cm.display.maxLine = visual
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
69 cm.display.maxLineLength = len
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
70 cm.display.maxLineChanged = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
71 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
72 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
73
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
74 if (min != null && cm && this.collapsed) regChange(cm, min, max + 1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
75 this.lines.length = 0
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
76 this.explicitlyCleared = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
77 if (this.atomic && this.doc.cantEdit) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
78 this.doc.cantEdit = false
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
79 if (cm) reCheckSelection(cm.doc)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
80 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
81 if (cm) signalLater(cm, "markerCleared", cm, this, min, max)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
82 if (withOp) endOperation(cm)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
83 if (this.parent) this.parent.clear()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
84 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
85
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
86 // Find the position of the marker in the document. Returns a {from,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
87 // to} object by default. Side can be passed to get a specific side
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
88 // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
89 // Pos objects returned contain a line object, rather than a line
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
90 // number (used to prevent looking up the same line twice).
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
91 find(side, lineObj) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
92 if (side == null && this.type == "bookmark") side = 1
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
93 let from, to
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
94 for (let i = 0; i < this.lines.length; ++i) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
95 let line = this.lines[i]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
96 let span = getMarkedSpanFor(line.markedSpans, this)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
97 if (span.from != null) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
98 from = Pos(lineObj ? line : lineNo(line), span.from)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
99 if (side == -1) return from
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
100 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
101 if (span.to != null) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
102 to = Pos(lineObj ? line : lineNo(line), span.to)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
103 if (side == 1) return to
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
104 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
105 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
106 return from && {from: from, to: to}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
107 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
108
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
109 // Signals that the marker's widget changed, and surrounding layout
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
110 // should be recomputed.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
111 changed() {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
112 let pos = this.find(-1, true), widget = this, cm = this.doc.cm
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
113 if (!pos || !cm) return
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
114 runInOp(cm, () => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
115 let line = pos.line, lineN = lineNo(pos.line)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
116 let view = findViewForLine(cm, lineN)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
117 if (view) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
118 clearLineMeasurementCacheFor(view)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
119 cm.curOp.selectionChanged = cm.curOp.forceUpdate = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
120 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
121 cm.curOp.updateMaxLine = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
122 if (!lineIsHidden(widget.doc, line) && widget.height != null) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
123 let oldHeight = widget.height
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
124 widget.height = null
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
125 let dHeight = widgetHeight(widget) - oldHeight
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
126 if (dHeight)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
127 updateLineHeight(line, line.height + dHeight)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
128 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
129 signalLater(cm, "markerChanged", cm, this)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
130 })
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
131 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
132
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
133 attachLine(line) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
134 if (!this.lines.length && this.doc.cm) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
135 let op = this.doc.cm.curOp
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
136 if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
137 (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
138 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
139 this.lines.push(line)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
140 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
141
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
142 detachLine(line) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
143 this.lines.splice(indexOf(this.lines, line), 1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
144 if (!this.lines.length && this.doc.cm) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
145 let op = this.doc.cm.curOp
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
146 ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this)
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 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
150 eventMixin(TextMarker)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
151
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
152 // Create a marker, wire it up to the right lines, and
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
153 export function markText(doc, from, to, options, type) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
154 // Shared markers (across linked documents) are handled separately
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
155 // (markTextShared will call out to this again, once per
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
156 // document).
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
157 if (options && options.shared) return markTextShared(doc, from, to, options, type)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
158 // Ensure we are in an operation.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
159 if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
160
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
161 let marker = new TextMarker(doc, type), diff = cmp(from, to)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
162 if (options) copyObj(options, marker, false)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
163 // Don't connect empty markers unless clearWhenEmpty is false
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
164 if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
165 return marker
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
166 if (marker.replacedWith) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
167 // Showing up as a widget implies collapsed (widget replaces text)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
168 marker.collapsed = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
169 marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
170 if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
171 if (options.insertLeft) marker.widgetNode.insertLeft = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
172 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
173 if (marker.collapsed) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
174 if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
175 from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
176 throw new Error("Inserting collapsed marker partially overlapping an existing one")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
177 seeCollapsedSpans()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
178 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
179
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
180 if (marker.addToHistory)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
181 addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
182
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
183 let curLine = from.line, cm = doc.cm, updateMaxLine
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
184 doc.iter(curLine, to.line + 1, line => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
185 if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
186 updateMaxLine = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
187 if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
188 addMarkedSpan(line, new MarkedSpan(marker,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
189 curLine == from.line ? from.ch : null,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
190 curLine == to.line ? to.ch : null), doc.cm && doc.cm.curOp)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
191 ++curLine
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
192 })
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
193 // lineIsHidden depends on the presence of the spans, so needs a second pass
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
194 if (marker.collapsed) doc.iter(from.line, to.line + 1, line => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
195 if (lineIsHidden(doc, line)) updateLineHeight(line, 0)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
196 })
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
197
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
198 if (marker.clearOnEnter) on(marker, "beforeCursorEnter", () => marker.clear())
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
199
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
200 if (marker.readOnly) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
201 seeReadOnlySpans()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
202 if (doc.history.done.length || doc.history.undone.length)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
203 doc.clearHistory()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
204 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
205 if (marker.collapsed) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
206 marker.id = ++nextMarkerId
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
207 marker.atomic = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
208 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
209 if (cm) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
210 // Sync editor state
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
211 if (updateMaxLine) cm.curOp.updateMaxLine = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
212 if (marker.collapsed)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
213 regChange(cm, from.line, to.line + 1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
214 else if (marker.className || marker.startStyle || marker.endStyle || marker.css ||
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
215 marker.attributes || marker.title)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
216 for (let i = from.line; i <= to.line; i++) regLineChange(cm, i, "text")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
217 if (marker.atomic) reCheckSelection(cm.doc)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
218 signalLater(cm, "markerAdded", cm, marker)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
219 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
220 return marker
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
221 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
222
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
223 // SHARED TEXTMARKERS
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
224
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
225 // A shared marker spans multiple linked documents. It is
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
226 // implemented as a meta-marker-object controlling multiple normal
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
227 // markers.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
228 export class SharedTextMarker {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
229 constructor(markers, primary) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
230 this.markers = markers
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
231 this.primary = primary
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
232 for (let i = 0; i < markers.length; ++i)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
233 markers[i].parent = this
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
234 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
235
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
236 clear() {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
237 if (this.explicitlyCleared) return
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
238 this.explicitlyCleared = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
239 for (let i = 0; i < this.markers.length; ++i)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
240 this.markers[i].clear()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
241 signalLater(this, "clear")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
242 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
243
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
244 find(side, lineObj) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
245 return this.primary.find(side, lineObj)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
246 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
247 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
248 eventMixin(SharedTextMarker)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
249
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
250 function markTextShared(doc, from, to, options, type) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
251 options = copyObj(options)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
252 options.shared = false
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
253 let markers = [markText(doc, from, to, options, type)], primary = markers[0]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
254 let widget = options.widgetNode
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
255 linkedDocs(doc, doc => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
256 if (widget) options.widgetNode = widget.cloneNode(true)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
257 markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
258 for (let i = 0; i < doc.linked.length; ++i)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
259 if (doc.linked[i].isParent) return
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
260 primary = lst(markers)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
261 })
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
262 return new SharedTextMarker(markers, primary)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
263 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
264
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
265 export function findSharedMarkers(doc) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
266 return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), m => m.parent)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
267 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
268
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
269 export function copySharedMarkers(doc, markers) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
270 for (let i = 0; i < markers.length; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
271 let marker = markers[i], pos = marker.find()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
272 let mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
273 if (cmp(mFrom, mTo)) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
274 let subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
275 marker.markers.push(subMark)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
276 subMark.parent = marker
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
277 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
278 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
279 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
280
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
281 export function detachSharedMarkers(markers) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
282 for (let i = 0; i < markers.length; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
283 let marker = markers[i], linked = [marker.primary.doc]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
284 linkedDocs(marker.primary.doc, d => linked.push(d))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
285 for (let j = 0; j < marker.markers.length; j++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
286 let subMarker = marker.markers[j]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
287 if (indexOf(linked, subMarker.doc) == -1) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
288 subMarker.parent = null
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
289 marker.markers.splice(j--, 1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
290 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
291 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
292 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
293 }