| 1 |
// CodeMirror, copyright (c) by Marijn Haverbeke and others |
| 2 |
// Distributed under an MIT license: http://codemirror.net/LICENSE |
| 3 |
|
| 4 |
(function(mod) { |
| 5 |
if (typeof exports == "object" && typeof module == "object") // CommonJS |
| 6 |
mod(require("../../lib/codemirror")); |
| 7 |
else if (typeof define == "function" && define.amd) // AMD |
| 8 |
define(["../../lib/codemirror"], mod); |
| 9 |
else // Plain browser env |
| 10 |
mod(CodeMirror); |
| 11 |
})(function(CodeMirror) { |
| 12 |
"use strict"; |
| 13 |
|
| 14 |
function doFold(cm, pos, options, force) { |
| 15 |
if (options && options.call) { |
| 16 |
var finder = options; |
| 17 |
options = null; |
| 18 |
} else { |
| 19 |
var finder = getOption(cm, options, "rangeFinder"); |
| 20 |
} |
| 21 |
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0); |
| 22 |
var minSize = getOption(cm, options, "minFoldSize"); |
| 23 |
|
| 24 |
function getRange(allowFolded) { |
| 25 |
var range = finder(cm, pos); |
| 26 |
if (!range || range.to.line - range.from.line < minSize) return null; |
| 27 |
var marks = cm.findMarksAt(range.from); |
| 28 |
for (var i = 0; i < marks.length; ++i) { |
| 29 |
if (marks[i].__isFold && force !== "fold") { |
| 30 |
if (!allowFolded) return null; |
| 31 |
range.cleared = true; |
| 32 |
marks[i].clear(); |
| 33 |
} |
| 34 |
} |
| 35 |
return range; |
| 36 |
} |
| 37 |
|
| 38 |
var range = getRange(true); |
| 39 |
if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) { |
| 40 |
pos = CodeMirror.Pos(pos.line - 1, 0); |
| 41 |
range = getRange(false); |
| 42 |
} |
| 43 |
if (!range || range.cleared || force === "unfold") return; |
| 44 |
|
| 45 |
var myWidget = makeWidget(cm, options); |
| 46 |
CodeMirror.on(myWidget, "mousedown", function(e) { |
| 47 |
myRange.clear(); |
| 48 |
CodeMirror.e_preventDefault(e); |
| 49 |
}); |
| 50 |
var myRange = cm.markText(range.from, range.to, { |
| 51 |
replacedWith: myWidget, |
| 52 |
clearOnEnter: getOption(cm, options, "clearOnEnter"), |
| 53 |
__isFold: true |
| 54 |
}); |
| 55 |
myRange.on("clear", function(from, to) { |
| 56 |
CodeMirror.signal(cm, "unfold", cm, from, to); |
| 57 |
}); |
| 58 |
CodeMirror.signal(cm, "fold", cm, range.from, range.to); |
| 59 |
} |
| 60 |
|
| 61 |
function makeWidget(cm, options) { |
| 62 |
var widget = getOption(cm, options, "widget"); |
| 63 |
if (typeof widget == "string") { |
| 64 |
var text = document.createTextNode(widget); |
| 65 |
widget = document.createElement("span"); |
| 66 |
widget.appendChild(text); |
| 67 |
widget.className = "CodeMirror-foldmarker"; |
| 68 |
} else if (widget) { |
| 69 |
widget = widget.cloneNode(true) |
| 70 |
} |
| 71 |
return widget; |
| 72 |
} |
| 73 |
|
| 74 |
// Clumsy backwards-compatible interface |
| 75 |
CodeMirror.newFoldFunction = function(rangeFinder, widget) { |
| 76 |
return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); }; |
| 77 |
}; |
| 78 |
|
| 79 |
// New-style interface |
| 80 |
CodeMirror.defineExtension("foldCode", function(pos, options, force) { |
| 81 |
doFold(this, pos, options, force); |
| 82 |
}); |
| 83 |
|
| 84 |
CodeMirror.defineExtension("isFolded", function(pos) { |
| 85 |
var marks = this.findMarksAt(pos); |
| 86 |
for (var i = 0; i < marks.length; ++i) |
| 87 |
if (marks[i].__isFold) return true; |
| 88 |
}); |
| 89 |
|
| 90 |
CodeMirror.commands.toggleFold = function(cm) { |
| 91 |
cm.foldCode(cm.getCursor()); |
| 92 |
}; |
| 93 |
CodeMirror.commands.fold = function(cm) { |
| 94 |
cm.foldCode(cm.getCursor(), null, "fold"); |
| 95 |
}; |
| 96 |
CodeMirror.commands.unfold = function(cm) { |
| 97 |
cm.foldCode(cm.getCursor(), null, "unfold"); |
| 98 |
}; |
| 99 |
CodeMirror.commands.foldAll = function(cm) { |
| 100 |
cm.operation(function() { |
| 101 |
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) |
| 102 |
cm.foldCode(CodeMirror.Pos(i, 0), null, "fold"); |
| 103 |
}); |
| 104 |
}; |
| 105 |
CodeMirror.commands.unfoldAll = function(cm) { |
| 106 |
cm.operation(function() { |
| 107 |
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) |
| 108 |
cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold"); |
| 109 |
}); |
| 110 |
}; |
| 111 |
|
| 112 |
CodeMirror.registerHelper("fold", "combine", function() { |
| 113 |
var funcs = Array.prototype.slice.call(arguments, 0); |
| 114 |
return function(cm, start) { |
| 115 |
for (var i = 0; i < funcs.length; ++i) { |
| 116 |
var found = funcs[i](cm, start); |
| 117 |
if (found) return found; |
| 118 |
} |
| 119 |
}; |
| 120 |
}); |
| 121 |
|
| 122 |
CodeMirror.registerHelper("fold", "auto", function(cm, start) { |
| 123 |
var helpers = cm.getHelpers(start, "fold"); |
| 124 |
for (var i = 0; i < helpers.length; i++) { |
| 125 |
var cur = helpers[i](cm, start); |
| 126 |
if (cur) return cur; |
| 127 |
} |
| 128 |
}); |
| 129 |
|
| 130 |
var defaultOptions = { |
| 131 |
rangeFinder: CodeMirror.fold.auto, |
| 132 |
widget: "\u2194", |
| 133 |
minFoldSize: 0, |
| 134 |
scanUp: false, |
| 135 |
clearOnEnter: true |
| 136 |
}; |
| 137 |
|
| 138 |
CodeMirror.defineOption("foldOptions", null); |
| 139 |
|
| 140 |
function getOption(cm, options, name) { |
| 141 |
if (options && options[name] !== undefined) |
| 142 |
return options[name]; |
| 143 |
var editorOptions = cm.options.foldOptions; |
| 144 |
if (editorOptions && editorOptions[name] !== undefined) |
| 145 |
return editorOptions[name]; |
| 146 |
return defaultOptions[name]; |
| 147 |
} |
| 148 |
|
| 149 |
CodeMirror.defineExtension("foldOption", function(options, name) { |
| 150 |
return getOption(this, options, name); |
| 151 |
}); |
| 152 |
}); |
| 153 |
|