Skip to content

Commit db1b282

Browse files
committed
Make line widget handles objects with methods. Handle widget height better
Closes #1147 Widget handles now have .clear() and .changed() methods. The second informs CodeMirror that the widget changed, and causes it to recompute the line height for the widget's line. Fixes some sloppiness in the tracking of widget heights.
1 parent ee07146 commit db1b282

File tree

2 files changed

+70
-25
lines changed

2 files changed

+70
-25
lines changed

doc/manual.html

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -978,12 +978,15 @@

Programming API

978978
CodeMirror-specific CSS classes, and those classes might in some
979979
cases affect it. This method returns an object that represents
980980
the widget placement. It'll have a <code>linecode> property
981-
pointing at the line handle that it is associated with, and it
982-
can be passed to <code>removeLineWidgetcode> to remove the
983-
widget.dd>
984-
985-
<dt id="removeLineWidget"><code>removeLineWidget(widget)code>dt>
986-
<dd>Removes the given line widget.dd>
981+
pointing at the line handle that it is associated with, and the following methods:
982+
<dl>
983+
<dt id="widget_clear"><code>clear()code>dt><dd>Removes the widget.dd>
984+
<dt id="widget_changed"><code>changed()code>dt><dd>Call
985+
this if you made some change to the widget's DOM node that
986+
might affect its height. It'll force CodeMirror to update
987+
the height of the line that contains the widget.dd>
988+
dl>
989+
dd>
987990

988991
<dt id="posFromIndex"><code>posFromIndex(index) → objectcode>dt>
989992
<dd>Calculates and returns a <code>{line, ch}code> object for a

lib/codemirror.js

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -497,8 +497,12 @@ window.CodeMirror = (function() {
497497
}
498498
var diff = node.lineObj.height - height;
499499
if (height < 2) height = textHeight(display);
500-
if (diff > .001 || diff < -.001)
500+
if (diff > .001 || diff < -.001) {
501501
updateLineHeight(node.lineObj, height);
502+
var widgets = node.lineObj.widgets;
503+
if (widgets) for (var i = 0; i < widgets.length; ++i)
504+
widgets[i].height = widgets[i].node.offsetHeight;
505+
}
502506
}
503507
display.viewOffset = heightAtLine(cm, getLine(doc, from));
504508
// Position the mover div to align with the current virtual scroll position
@@ -978,7 +982,7 @@ window.CodeMirror = (function() {
978982
// Context is one of "line", "div" (display.lineDiv), "local"/null (editor), or "page"
979983
function intoCoordSystem(cm, lineObj, rect, context) {
980984
if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
981-
var size = lineObj.widgets[i].node.offsetHeight;
985+
var size = widgetHeight(lineObj.widgets[i]);
982986
rect.top += size; rect.bottom += size;
983987
}
984988
if (context == "line") return rect;
@@ -2597,25 +2601,10 @@ window.CodeMirror = (function() {
25972601
}),
25982602

25992603
addLineWidget: operation(null, function(handle, node, options) {
2600-
var widget = options || {};
2601-
widget.node = node;
2602-
if (widget.noHScroll) this.display.alignWidgets = true;
2603-
changeLine(this, handle, function(line) {
2604-
(line.widgets || (line.widgets = [])).push(widget);
2605-
widget.line = line;
2606-
return true;
2607-
});
2608-
return widget;
2604+
return addLineWidget(this, handle, node, options);
26092605
}),
26102606

2611-
removeLineWidget: operation(null, function(widget) {
2612-
var ws = widget.line.widgets, no = lineNo(widget.line);
2613-
if (no == null || !ws) return;
2614-
for (var i = 0; i < ws.length; ++i) if (ws[i] == widget) ws.splice(i--, 1);
2615-
var newHeight = widget.node.offsetHeight ? widget.line.height - widget.node.offsetHeight : textHeight(this.display);
2616-
updateLineHeight(widget.line, newHeight);
2617-
regChange(this, no, no + 1);
2618-
}),
2607+
removeLineWidget: function(widget) { widget.remove(); },
26192608

26202609
lineInfo: function(line) {
26212610
if (typeof line == "number") {
@@ -3587,6 +3576,59 @@ window.CodeMirror = (function() {
35873576
line.markedSpans = spans;
35883577
}
35893578

3579+
// LINE WIDGETS
3580+
3581+
var LineWidget = CodeMirror.LineWidget = function(cm, node, options) {
3582+
for (var opt in options) if (options.hasOwnProperty(opt))
3583+
this[opt] = options[opt];
3584+
this.cm = cm;
3585+
this.node = node;
3586+
};
3587+
function widgetOperation(f) {
3588+
return function() {
3589+
startOperation(this.cm);
3590+
try {var result = f.apply(this, arguments);}
3591+
finally {endOperation(this.cm);}
3592+
return result;
3593+
};
3594+
}
3595+
LineWidget.prototype.clear = widgetOperation(function() {
3596+
var ws = this.line.widgets, no = lineNo(this.line);
3597+
if (no == null || !ws) return;
3598+
for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
3599+
updateLineHeight(this.line, Math.max(0, this.line.height - widgetHeight(this)));
3600+
regChange(this.cm, no, no + 1);
3601+
});
3602+
LineWidget.prototype.changed = widgetOperation(function() {
3603+
var oldH = this.height;
3604+
this.height = null;
3605+
var diff = widgetHeight(this) - oldH;
3606+
if (!diff) return;
3607+
updateLineHeight(this.line, this.line.height + diff);
3608+
var no = lineNo(this.line);
3609+
regChange(this.cm, no, no + 1);
3610+
});
3611+
3612+
function widgetHeight(widget) {
3613+
if (widget.height != null) return widget.height;
3614+
if (!widget.node.parentNode)
3615+
removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, "position: relative"));
3616+
return widget.height = widget.node.offsetHeight;
3617+
}
3618+
3619+
function addLineWidget(cm, handle, node, options) {
3620+
var widget = new LineWidget(cm, node, options);
3621+
if (widget.noHScroll) cm.display.alignWidgets = true;
3622+
changeLine(cm, handle, function(line) {
3623+
(line.widgets || (line.widgets = [])).push(widget);
3624+
widget.line = line;
3625+
if (!lineIsHidden(line) || widget.showIfHidden)
3626+
updateLineHeight(line, line.height + widgetHeight(widget));
3627+
return true;
3628+
});
3629+
return widget;
3630+
}
3631+
35903632
// LINE DATA STRUCTURE
35913633

35923634
// Line objects. These hold state related to a line, including

0 commit comments

Comments
 (0)