Support functions as fold widget argument

So that the widgets can be dynamic with regards to their content.

Expand the fold demo with a JSON editor that shows the number of
elements in folded regions.
This commit is contained in:
Opender Singh 2019-11-24 15:49:19 +13:00 committed by Marijn Haverbeke
parent 00281786f0
commit 3ace5da283
3 changed files with 65 additions and 5 deletions

View File

@ -42,7 +42,7 @@
}
if (!range || range.cleared || force === "unfold") return;
var myWidget = makeWidget(cm, options);
var myWidget = makeWidget(cm, options, range);
CodeMirror.on(myWidget, "mousedown", function(e) {
myRange.clear();
CodeMirror.e_preventDefault(e);
@ -58,8 +58,13 @@
CodeMirror.signal(cm, "fold", cm, range.from, range.to);
}
function makeWidget(cm, options) {
function makeWidget(cm, options, range) {
var widget = getOption(cm, options, "widget");
if (typeof widget == "function") {
widget = widget(range.from, range.to);
}
if (typeof widget == "string") {
var text = document.createTextNode(widget);
widget = document.createElement("span");

View File

@ -53,7 +53,23 @@
<div style="max-width: 50em; margin-bottom: 1em">JavaScript:<br>
<textarea id="code" name="code"></textarea></div>
<div style="max-width: 50em; margin-bottom: 1em">HTML:<br>
<textarea id="code-html" name="code-html"></textarea></div>
<textarea id="code-html" name="code-html"></textarea></div>
<div style="max-width: 50em; margin-bottom: 1em">JSON with custom widget:<br>
<textarea id="code-json" name="code-json">
{
"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}
}
</textarea></div>
<div style="max-width: 50em">Python:<br>
<textarea id="code-python" name="code">
def foo():
@ -89,6 +105,7 @@ window.onload = function() {
var te_python = document.getElementById("code-python");
var te_markdown = document.getElementById("code-markdown");
te_markdown.value = "# Foo\n## Bar\n\nblah blah\n\n## Baz\n\nblah blah\n\n# Quux\n\nblah blah\n"
var te_json = document.getElementById("code-json");
window.editor = CodeMirror.fromTextArea(te, {
mode: "javascript",
@ -100,6 +117,40 @@ window.onload = function() {
});
editor.foldCode(CodeMirror.Pos(13, 0));
window.editor_json = CodeMirror.fromTextArea(te_json, {
mode: {name: "javascript", json: true},
lineNumbers: true,
lineWrapping: true,
extraKeys: {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }},
foldGutter: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
foldOptions: {
widget: (from, to) => {
var count = undefined;
// Get open / close token
var startToken = '{', endToken = '}';
var prevLine = window.editor_json.getLine(from.line);
if (prevLine.lastIndexOf('[') > prevLine.lastIndexOf('{')) {
startToken = '[', endToken = ']';
}
// Get json content
var internal = window.editor_json.getRange(from, to);
var toParse = startToken + internal + endToken;
// Get key count
try {
var parsed = JSON.parse(toParse);
count = Object.keys(parsed).length;
} catch(e) { }
return count ? `\u21A4${count}\u21A6` : '\u2194';
}
}
});
editor_json.foldCode(CodeMirror.Pos(5, 0));
window.editor_html = CodeMirror.fromTextArea(te_html, {
mode: "text/html",
lineNumbers: true,

View File

@ -2564,10 +2564,14 @@ editor.setOption("extraKeys", {
and <code>CodeMirror.fold.xml</code>, for XML-style languages,
and <code>CodeMirror.fold.comment</code>, for folding comment
blocks.</dd>
<dt><code><strong>widget</strong>: string|Element</code></dt>
<dt><code><strong>widget</strong>: string | Element | fn(from: Pos, to: Pos) → string|Element</code></dt>
<dd>The widget to show for folded ranges. Can be either a
string, in which case it'll become a span with
class <code>CodeMirror-foldmarker</code>, or a DOM node.</dd>
class <code>CodeMirror-foldmarker</code>, or a DOM node.
To dynamically generate the widget, this can be a function
that returns a string or DOM node, which will then render
as described. The function will be invoked with parameters
identifying the range to be folded.</dd>
<dt><code><strong>scanUp</strong>: boolean</code></dt>
<dd>When true (default is false), the addon will try to find
foldable ranges on the lines above the current one if there