Skip to content

Commit ce1f0cd

Browse files
AlexanderPrendotamarijnh
authored andcommitted
Support adding attributes when marking text
1 parent 3619ae2 commit ce1f0cd

File tree

4 files changed

+35
-15
lines changed

4 files changed

+35
-15
lines changed

doc/manual.html

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1716,10 +1716,9 @@ <h3 id="api_marker">Text-marking methods</h3>
17161716
to <code>startStyle</code>, but for the rightmost span.</dd>
17171717
<dt id="mark_css"><code><strong>css</strong>: string</code></dt>
17181718
<dd>A string of CSS to be applied to the covered text. For example <code>"color: #fe3"</code>.</dd>
1719-
<dt id="mark_title"><code><strong>title</strong>:
1720-
string</code></dt><dd>When given, will give the nodes created
1721-
for this span a HTML <code>title</code> attribute with the
1722-
given value.</dd>
1719+
<dt id="mark_attributes"><code><strong>attributes</strong>:
1720+
object</code></dt><dd>When given, will give the nodes created
1721+
for this span a HTML <code>attributes</code> with the given value.</dd>
17231722
<dt id="mark_shared"><code><strong>shared</strong>: boolean</code></dt><dd>When the
17241723
target document is <a href="#linkedDoc">linked</a> to other
17251724
documents, you can set <code>shared</code> to true to make the

src/line/line_data.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export function defaultSpecialCharPlaceholder(ch) {
127127

128128
// Build up the DOM representation for a single token, and add it to
129129
// the line map. Takes care to render special characters separately.
130-
function buildToken(builder, text, style, startStyle, endStyle, title, css) {
130+
function buildToken(builder, text, style, startStyle, endStyle, css, attributes) {
131131
if (!text) return
132132
let displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text
133133
let special = builder.cm.state.specialChars, mustWrap = false
@@ -183,7 +183,13 @@ function buildToken(builder, text, style, startStyle, endStyle, title, css) {
183183
if (startStyle) fullStyle += startStyle
184184
if (endStyle) fullStyle += endStyle
185185
let token = elt("span", [content], fullStyle, css)
186-
if (title) token.title = title
186+
if (attributes) {
187+
for (let attr in attributes){
188+
if (attributes.hasOwnProperty(attr) && attr !== "style" && attr !== "class") {
189+
token.setAttribute(attr, attributes[attr])
190+
}
191+
}
192+
}
187193
return builder.content.appendChild(token)
188194
}
189195
builder.content.appendChild(content)
@@ -207,7 +213,7 @@ function splitSpaces(text, trailingBefore) {
207213
// Work around nonsense dimensions being reported for stretches of
208214
// right-to-left text.
209215
function buildTokenBadBidi(inner, order) {
210-
return (builder, text, style, startStyle, endStyle, title, css) => {
216+
return (builder, text, style, startStyle, endStyle, css, attributes) => {
211217
style = style ? style + " cm-force-border" : "cm-force-border"
212218
let start = builder.pos, end = start + text.length
213219
for (;;) {
@@ -217,8 +223,8 @@ function buildTokenBadBidi(inner, order) {
217223
part = order[i]
218224
if (part.to > start && part.from <= start) break
219225
}
220-
if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css)
221-
inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css)
226+
if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, css, attributes)
227+
inner(builder, text.slice(0, part.to - start), style, startStyle, null, css, attributes)
222228
startStyle = null
223229
text = text.slice(part.to - start)
224230
start = part.to
@@ -253,10 +259,11 @@ function insertLineContent(line, builder, styles) {
253259
}
254260

255261
let len = allText.length, pos = 0, i = 1, text = "", style, css
256-
let nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed
262+
let nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed, attributes
257263
for (;;) {
258264
if (nextChange == pos) { // Update current marker set
259-
spanStyle = spanEndStyle = spanStartStyle = title = css = ""
265+
spanStyle = spanEndStyle = spanStartStyle = css = ""
266+
attributes = {}
260267
collapsed = null; nextChange = Infinity
261268
let foundBookmarks = [], endStyles
262269
for (let j = 0; j < spans.length; ++j) {
@@ -272,7 +279,10 @@ function insertLineContent(line, builder, styles) {
272279
if (m.css) css = (css ? css + ";" : "") + m.css
273280
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle
274281
if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to)
275-
if (m.title && !title) title = m.title
282+
// support for the old title property
283+
// https://github.com/codemirror/CodeMirror/pull/5673
284+
if (m.title) {attributes.title = m.title}
285+
if (m.attributes) { attributes = m.attributes }
276286
if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
277287
collapsed = sp
278288
} else if (sp.from > pos && nextChange > sp.from) {
@@ -300,7 +310,7 @@ function insertLineContent(line, builder, styles) {
300310
if (!collapsed) {
301311
let tokenText = end > upto ? text.slice(0, upto - pos) : text
302312
builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
303-
spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css)
313+
spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", css, attributes)
304314
}
305315
if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
306316
pos = end

src/model/mark_text.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ export function markText(doc, from, to, options, type) {
211211
if (updateMaxLine) cm.curOp.updateMaxLine = true
212212
if (marker.collapsed)
213213
regChange(cm, from.line, to.line + 1)
214-
else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
214+
else if (marker.className || marker.startStyle || marker.endStyle || marker.css || marker.attributes )
215215
for (let i = from.line; i <= to.line; i++) regLineChange(cm, i, "text")
216216
if (marker.atomic) reCheckSelection(cm.doc)
217217
signalLater(cm, "markerAdded", cm, marker)

test/test.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,13 +549,24 @@ testCM("markTextCSS", function(cm) {
549549
function present() {
550550
var spans = cm.display.lineDiv.getElementsByTagName("span");
551551
for (var i = 0; i < spans.length; i++)
552-
if (spans[i].style.color == "cyan" && span[i].textContent == "cdefg") return true;
552+
if (spans[i].style.color == "cyan" && spans[i].textContent == "cdefg") return true;
553553
}
554554
var m = cm.markText(Pos(0, 2), Pos(0, 6), {css: "color: cyan"});
555555
m.clear();
556556
is(!present());
557557
}, {value: "abcdefgh"});
558558

559+
testCM("markTextWithAttributes", function(cm) {
560+
function present() {
561+
var spans = cm.display.lineDiv.getElementsByTagName("span");
562+
for (var i = 0; i < spans.length; i++)
563+
if (spans[i].getAttribute('label') == "label" && span[i].textContent == "cdefg") return true;
564+
}
565+
var m = cm.markText(Pos(0, 2), Pos(0, 6), {attributes: {label: "label"}});
566+
m.clear();
567+
is(!present());
568+
}, {value: "abcdefgh"});
569+
559570
testCM("bookmark", function(cm) {
560571
function p(v) { return v && Pos(v[0], v[1]); }
561572
forEach([{a: [1, 0], b: [1, 1], c: "", d: [1, 4]},

0 commit comments

Comments
 (0)