summaryrefslogtreecommitdiff
path: root/public/vendor/codemirror/lib/codemirror.js
diff options
context:
space:
mode:
authorWu Cheng-Han2016-01-17 14:28:04 -0600
committerWu Cheng-Han2016-01-17 14:28:04 -0600
commiteaa8ccaccb1091820d0a8d1223996a6dd057347d (patch)
tree6b4aaa3b3d1a2fed68147510142663222533775a /public/vendor/codemirror/lib/codemirror.js
parentce65e58096d57ace02723d11a125673f9d48c293 (diff)
Upgrade CodeMirror to 5.10.1 and now support fullscreen, jump-to-line in editor
Diffstat (limited to 'public/vendor/codemirror/lib/codemirror.js')
-rw-r--r--[-rwxr-xr-x]public/vendor/codemirror/lib/codemirror.js559
1 files changed, 357 insertions, 202 deletions
diff --git a/public/vendor/codemirror/lib/codemirror.js b/public/vendor/codemirror/lib/codemirror.js
index 92cacf0f..95a7dc74 100755..100644
--- a/public/vendor/codemirror/lib/codemirror.js
+++ b/public/vendor/codemirror/lib/codemirror.js
@@ -13,7 +13,7 @@
else if (typeof define == "function" && define.amd) // AMD
return define([], mod);
else // Plain browser env
- this.CodeMirror = mod();
+ (this || window).CodeMirror = mod();
})(function() {
"use strict";
@@ -21,27 +21,29 @@
// Kludges for bugs and behavior differences that can't be feature
// detected are enabled based on userAgent etc sniffing.
+ var userAgent = navigator.userAgent;
+ var platform = navigator.platform;
- var gecko = /gecko\/\d/i.test(navigator.userAgent);
- var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
- var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
+ var gecko = /gecko\/\d/i.test(userAgent);
+ var ie_upto10 = /MSIE \d/.test(userAgent);
+ var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
var ie = ie_upto10 || ie_11up;
var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
- var webkit = /WebKit\//.test(navigator.userAgent);
- var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
- var chrome = /Chrome\//.test(navigator.userAgent);
- var presto = /Opera\//.test(navigator.userAgent);
+ var webkit = /WebKit\//.test(userAgent);
+ var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
+ var chrome = /Chrome\//.test(userAgent);
+ var presto = /Opera\//.test(userAgent);
var safari = /Apple Computer/.test(navigator.vendor);
- var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
- var phantom = /PhantomJS/.test(navigator.userAgent);
+ var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
+ var phantom = /PhantomJS/.test(userAgent);
- var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
+ var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
// This is woefully incomplete. Suggestions for alternative methods welcome.
- var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
- var mac = ios || /Mac/.test(navigator.platform);
- var windows = /win/i.test(navigator.platform);
+ var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
+ var mac = ios || /Mac/.test(platform);
+ var windows = /win/i.test(platform);
- var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
+ var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
if (presto_version) presto_version = Number(presto_version[1]);
if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
@@ -65,7 +67,7 @@
setGuttersForLineNumbers(options);
var doc = options.value;
- if (typeof doc == "string") doc = new Doc(doc, options.mode);
+ if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator);
this.doc = doc;
var input = new CodeMirror.inputStyles[options.inputStyle](this);
@@ -87,6 +89,7 @@
focused: false,
suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
+ selectingText: false,
draggingText: false,
highlight: new Delayed(), // stores highlight worker timeout
keySeq: null, // Unfinished key sequence
@@ -407,7 +410,7 @@
if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
});
- this.checkedOverlay = false;
+ this.checkedZeroWidth = false;
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
}
@@ -442,29 +445,43 @@
this.horiz.firstChild.style.width = "0";
}
- if (!this.checkedOverlay && measure.clientHeight > 0) {
- if (sWidth == 0) this.overlayHack();
- this.checkedOverlay = true;
+ if (!this.checkedZeroWidth && measure.clientHeight > 0) {
+ if (sWidth == 0) this.zeroWidthHack();
+ this.checkedZeroWidth = true;
}
return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
},
setScrollLeft: function(pos) {
if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
+ if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz);
},
setScrollTop: function(pos) {
if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
+ if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert);
},
- overlayHack: function() {
+ zeroWidthHack: function() {
var w = mac && !mac_geMountainLion ? "12px" : "18px";
- this.horiz.style.minHeight = this.vert.style.minWidth = w;
- var self = this;
- var barMouseDown = function(e) {
- if (e_target(e) != self.vert && e_target(e) != self.horiz)
- operation(self.cm, onMouseDown)(e);
- };
- on(this.vert, "mousedown", barMouseDown);
- on(this.horiz, "mousedown", barMouseDown);
+ this.horiz.style.height = this.vert.style.width = w;
+ this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
+ this.disableHoriz = new Delayed;
+ this.disableVert = new Delayed;
+ },
+ enableZeroWidthBar: function(bar, delay) {
+ bar.style.pointerEvents = "auto";
+ function maybeDisable() {
+ // To find out whether the scrollbar is still visible, we
+ // check whether the element under the pixel in the bottom
+ // left corner of the scrollbar box is the scrollbar box
+ // itself (when the bar is still visible) or its filler child
+ // (when the bar is hidden). If it is still visible, we keep
+ // it enabled, if it's hidden, we disable pointer events.
+ var box = bar.getBoundingClientRect();
+ var elt = document.elementFromPoint(box.left + 1, box.bottom - 1);
+ if (elt != bar) bar.style.pointerEvents = "none";
+ else delay.set(1000, maybeDisable);
+ }
+ delay.set(1000, maybeDisable);
},
clear: function() {
var parent = this.horiz.parentNode;
@@ -714,7 +731,7 @@
// width and height.
removeChildren(display.cursorDiv);
removeChildren(display.selectionDiv);
- display.gutters.style.height = 0;
+ display.gutters.style.height = display.sizer.style.minHeight = 0;
if (different) {
display.lastWrapHeight = update.wrapperHeight;
@@ -806,7 +823,7 @@
// given line.
function updateWidgetHeight(line) {
if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
- line.widgets[i].height = line.widgets[i].node.offsetHeight;
+ line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight;
}
// Do a bulk-read of the DOM positions and sizes needed to draw the
@@ -955,12 +972,22 @@
lineView.node.removeChild(lineView.gutter);
lineView.gutter = null;
}
+ if (lineView.gutterBackground) {
+ lineView.node.removeChild(lineView.gutterBackground);
+ lineView.gutterBackground = null;
+ }
+ if (lineView.line.gutterClass) {
+ var wrap = ensureLineWrapped(lineView);
+ lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
+ "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +
+ "px; width: " + dims.gutterTotalWidth + "px");
+ wrap.insertBefore(lineView.gutterBackground, lineView.text);
+ }
var markers = lineView.line.gutterMarkers;
if (cm.options.lineNumbers || markers) {
var wrap = ensureLineWrapped(lineView);
var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " +
- (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +
- "px; width: " + dims.gutterTotalWidth + "px");
+ (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px");
cm.display.input.setUneditable(gutterWrap);
wrap.insertBefore(gutterWrap, lineView.text);
if (lineView.line.gutterClass)
@@ -1067,10 +1094,6 @@
if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
}
- function isReadOnly(cm) {
- return cm.options.readOnly || cm.doc.cantEdit;
- }
-
// This will be set to an array of strings when copying, so that,
// when pasting, we know what kind of selections the copied text
// was made out of.
@@ -1082,13 +1105,18 @@
if (!sel) sel = doc.sel;
var paste = cm.state.pasteIncoming || origin == "paste";
- var textLines = splitLines(inserted), multiPaste = null;
+ var textLines = doc.splitLines(inserted), multiPaste = null;
// When pasing N lines into N selections, insert one line per selection
if (paste && sel.ranges.length > 1) {
- if (lastCopied && lastCopied.join("\n") == inserted)
- multiPaste = sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines);
- else if (textLines.length == sel.ranges.length)
+ if (lastCopied && lastCopied.join("\n") == inserted) {
+ if (sel.ranges.length % lastCopied.length == 0) {
+ multiPaste = [];
+ for (var i = 0; i < lastCopied.length; i++)
+ multiPaste.push(doc.splitLines(lastCopied[i]));
+ }
+ } else if (textLines.length == sel.ranges.length) {
multiPaste = map(textLines, function(l) { return [l]; });
+ }
}
// Normal behavior is to insert the new text into every selection
@@ -1120,7 +1148,8 @@
var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
if (pasted) {
e.preventDefault();
- runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); });
+ if (!cm.isReadOnly() && !cm.options.disableInput)
+ runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); });
return true;
}
}
@@ -1222,13 +1251,14 @@
});
on(te, "paste", function(e) {
- if (handlePaste(e, cm)) return true;
+ if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return
cm.state.pasteIncoming = true;
input.fastPoll();
});
function prepareCopyCut(e) {
+ if (signalDOMEvent(cm, e)) return
if (cm.somethingSelected()) {
lastCopied = cm.getSelections();
if (input.inaccurateSelection) {
@@ -1256,7 +1286,7 @@
on(te, "copy", prepareCopyCut);
on(display.scroller, "paste", function(e) {
- if (eventInWidget(display, e)) return;
+ if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return;
cm.state.pasteIncoming = true;
input.focus();
});
@@ -1268,6 +1298,7 @@
on(te, "compositionstart", function() {
var start = cm.getCursor("from");
+ if (input.composing) input.composing.range.clear()
input.composing = {
start: start,
range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
@@ -1390,8 +1421,8 @@
// will be the case when there is a lot of text in the textarea,
// in which case reading its value would be expensive.
if (this.contextMenuPending || !cm.state.focused ||
- (hasSelection(input) && !prevInput) ||
- isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
+ (hasSelection(input) && !prevInput && !this.composing) ||
+ cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
return false;
var text = input.value;
@@ -1518,6 +1549,10 @@
}
},
+ readOnlyChanged: function(val) {
+ if (!val) this.reset();
+ },
+
setUneditable: nothing,
needsContentAttribute: false
@@ -1536,10 +1571,11 @@
init: function(display) {
var input = this, cm = input.cm;
var div = input.div = display.lineDiv;
- div.contentEditable = "true";
disableBrowserMagic(div);
- on(div, "paste", function(e) { handlePaste(e, cm); })
+ on(div, "paste", function(e) {
+ if (!signalDOMEvent(cm, e)) handlePaste(e, cm);
+ })
on(div, "compositionstart", function(e) {
var data = e.data;
@@ -1577,11 +1613,12 @@
on(div, "input", function() {
if (input.composing) return;
- if (!input.pollContent())
+ if (cm.isReadOnly() || !input.pollContent())
runInOp(input.cm, function() {regChange(cm);});
});
function onCopyCut(e) {
+ if (signalDOMEvent(cm, e)) return
if (cm.somethingSelected()) {
lastCopied = cm.getSelections();
if (e.type == "cut") cm.replaceSelection("", null, "cut");
@@ -1657,8 +1694,13 @@
try { var rng = range(start.node, start.offset, end.offset, end.node); }
catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
if (rng) {
- sel.removeAllRanges();
- sel.addRange(rng);
+ if (!gecko && this.cm.state.focused) {
+ sel.collapse(start.node, start.offset);
+ if (!rng.collapsed) sel.addRange(rng);
+ } else {
+ sel.removeAllRanges();
+ sel.addRange(rng);
+ }
if (old && sel.anchorNode == null) sel.addRange(old);
else if (gecko) this.startGracePeriod();
}
@@ -1758,7 +1800,7 @@
var toNode = display.view[toIndex + 1].node.previousSibling;
}
- var newText = splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
+ var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
while (newText.length > 1 && oldText.length > 1) {
if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
@@ -1802,17 +1844,24 @@
this.div.focus();
},
applyComposition: function(composing) {
- if (composing.data && composing.data != composing.startData)
+ if (this.cm.isReadOnly())
+ operation(this.cm, regChange)(this.cm)
+ else if (composing.data && composing.data != composing.startData)
operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
},
setUneditable: function(node) {
- node.setAttribute("contenteditable", "false");
+ node.contentEditable = "false"
},
onKeyPress: function(e) {
e.preventDefault();
- operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
+ if (!this.cm.isReadOnly())
+ operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
+ },
+
+ readOnlyChanged: function(val) {
+ this.div.contentEditable = String(val != "nocursor")
},
onContextMenu: nothing,
@@ -1914,7 +1963,7 @@
}
function domTextBetween(cm, from, to, fromLine, toLine) {
- var text = "", closing = false;
+ var text = "", closing = false, lineSep = cm.doc.lineSeparator();
function recognizeMarker(id) { return function(marker) { return marker.id == id; }; }
function walk(node) {
if (node.nodeType == 1) {
@@ -1928,7 +1977,7 @@
if (markerID) {
var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
if (found.length && (range = found[0].find()))
- text += getBetween(cm.doc, range.from, range.to).join("\n");
+ text += getBetween(cm.doc, range.from, range.to).join(lineSep);
return;
}
if (node.getAttribute("contenteditable") == "false") return;
@@ -1940,7 +1989,7 @@
var val = node.nodeValue;
if (!val) return;
if (closing) {
- text += "\n";
+ text += lineSep;
closing = false;
}
text += val;
@@ -2112,7 +2161,7 @@
// Give beforeSelectionChange handlers a change to influence a
// selection update.
- function filterSelectionChange(doc, sel) {
+ function filterSelectionChange(doc, sel, options) {
var obj = {
ranges: sel.ranges,
update: function(ranges) {
@@ -2120,7 +2169,8 @@
for (var i = 0; i < ranges.length; i++)
this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
clipPos(doc, ranges[i].head));
- }
+ },
+ origin: options && options.origin
};
signal(doc, "beforeSelectionChange", doc, obj);
if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
@@ -2146,7 +2196,7 @@
function setSelectionNoUndo(doc, sel, options) {
if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
- sel = filterSelectionChange(doc, sel);
+ sel = filterSelectionChange(doc, sel, options);
var bias = options && options.bias ||
(cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
@@ -2180,8 +2230,9 @@
var out;
for (var i = 0; i < sel.ranges.length; i++) {
var range = sel.ranges[i];
- var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);
- var newHead = skipAtomic(doc, range.head, bias, mayClear);
+ var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
+ var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
+ var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
if (out || newAnchor != range.anchor || newHead != range.head) {
if (!out) out = sel.ranges.slice(0, i);
out[i] = new Range(newAnchor, newHead);
@@ -2190,54 +2241,59 @@
return out ? normalizeSelection(out, sel.primIndex) : sel;
}
- // Ensure a given position is not inside an atomic range.
- function skipAtomic(doc, pos, bias, mayClear) {
- var flipped = false, curPos = pos;
- var dir = bias || 1;
- doc.cantEdit = false;
- search: for (;;) {
- var line = getLine(doc, curPos.line);
- if (line.markedSpans) {
- for (var i = 0; i < line.markedSpans.length; ++i) {
- var sp = line.markedSpans[i], m = sp.marker;
- if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
- (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
- if (mayClear) {
- signal(m, "beforeCursorEnter");
- if (m.explicitlyCleared) {
- if (!line.markedSpans) break;
- else {--i; continue;}
- }
- }
- if (!m.atomic) continue;
- var newPos = m.find(dir < 0 ? -1 : 1);
- if (cmp(newPos, curPos) == 0) {
- newPos.ch += dir;
- if (newPos.ch < 0) {
- if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
- else newPos = null;
- } else if (newPos.ch > line.text.length) {
- if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
- else newPos = null;
- }
- if (!newPos) {
- if (flipped) {
- // Driven in a corner -- no valid cursor position found at all
- // -- try again *with* clearing, if we didn't already
- if (!mayClear) return skipAtomic(doc, pos, bias, true);
- // Otherwise, turn off editing until further notice, and return the start of the doc
- doc.cantEdit = true;
- return Pos(doc.first, 0);
- }
- flipped = true; newPos = pos; dir = -dir;
- }
- }
- curPos = newPos;
- continue search;
+ function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
+ var line = getLine(doc, pos.line);
+ if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
+ var sp = line.markedSpans[i], m = sp.marker;
+ if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
+ (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
+ if (mayClear) {
+ signal(m, "beforeCursorEnter");
+ if (m.explicitlyCleared) {
+ if (!line.markedSpans) break;
+ else {--i; continue;}
}
}
+ if (!m.atomic) continue;
+
+ if (oldPos) {
+ var near = m.find(dir < 0 ? 1 : -1), diff;
+ if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) near = movePos(doc, near, -dir, line);
+ if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
+ return skipAtomicInner(doc, near, pos, dir, mayClear);
+ }
+
+ var far = m.find(dir < 0 ? -1 : 1);
+ if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) far = movePos(doc, far, dir, line);
+ return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null;
}
- return curPos;
+ }
+ return pos;
+ }
+
+ // Ensure a given position is not inside an atomic range.
+ function skipAtomic(doc, pos, oldPos, bias, mayClear) {
+ var dir = bias || 1;
+ var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
+ (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
+ skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
+ (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
+ if (!found) {
+ doc.cantEdit = true;
+ return Pos(doc.first, 0);
+ }
+ return found;
+ }
+
+ function movePos(doc, pos, dir, line) {
+ if (dir < 0 && pos.ch == 0) {
+ if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1));
+ else return null;
+ } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
+ if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0);
+ else return null;
+ } else {
+ return new Pos(pos.line, pos.ch + dir);
}
}
@@ -2257,7 +2313,7 @@
var range = doc.sel.ranges[i];
var collapsed = range.empty();
if (collapsed || cm.options.showCursorWhenSelecting)
- drawSelectionCursor(cm, range, curFragment);
+ drawSelectionCursor(cm, range.head, curFragment);
if (!collapsed)
drawSelectionRange(cm, range, selFragment);
}
@@ -2265,8 +2321,8 @@
}
// Draws a cursor for the given range
- function drawSelectionCursor(cm, range, output) {
- var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine);
+ function drawSelectionCursor(cm, head, output) {
+ var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
cursor.style.left = pos.left + "px";
@@ -2400,8 +2456,8 @@
doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
if (doc.frontier >= cm.display.viewFrom) { // Visible
- var oldStyles = line.styles;
- var highlighted = highlightLine(cm, line, state, true);
+ var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength;
+ var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true);
line.styles = highlighted.styles;
var oldCls = line.styleClasses, newCls = highlighted.classes;
if (newCls) line.styleClasses = newCls;
@@ -2410,9 +2466,10 @@
oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
if (ischange) changedLines.push(doc.frontier);
- line.stateAfter = copyState(doc.mode, state);
+ line.stateAfter = tooLong ? state : copyState(doc.mode, state);
} else {
- processLine(cm, line.text, state);
+ if (line.text.length <= cm.options.maxHighlightLength)
+ processLine(cm, line.text, state);
line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
}
++doc.frontier;
@@ -2557,10 +2614,12 @@
function prepareMeasureForLine(cm, line) {
var lineN = lineNo(line);
var view = findViewForLine(cm, lineN);
- if (view && !view.text)
+ if (view && !view.text) {
view = null;
- else if (view && view.changes)
+ } else if (view && view.changes) {
updateLineForChanges(cm, view, lineN, getDimensions(cm));
+ cm.curOp.forceUpdate = true;
+ }
if (!view)
view = updateExternalMeasurement(cm, line);
@@ -2973,12 +3032,12 @@
var callbacks = group.delayedCallbacks, i = 0;
do {
for (; i < callbacks.length; i++)
- callbacks[i]();
+ callbacks[i].call(null);
for (var j = 0; j < group.ops.length; j++) {
var op = group.ops[j];
if (op.cursorActivityHandlers)
while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
- op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm);
+ op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm);
}
} while (i < callbacks.length);
}
@@ -3072,7 +3131,8 @@
if (cm.state.focused && op.updateInput)
cm.display.input.reset(op.typing);
- if (op.focus && op.focus == activeElt()) ensureFocus(op.cm);
+ if (op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus()))
+ ensureFocus(op.cm);
}
function endOperation_finish(op) {
@@ -3387,7 +3447,7 @@
return dx * dx + dy * dy > 20 * 20;
}
on(d.scroller, "touchstart", function(e) {
- if (!isMouseLikeTouchEvent(e)) {
+ if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {
clearTimeout(touchFinished);
var now = +new Date;
d.activeTouch = {start: now, moved: false,
@@ -3438,9 +3498,11 @@
on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
d.dragFunctions = {
- simple: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},
+ enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},
+ over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
start: function(e){onDragStart(cm, e);},
- drop: operation(cm, onDrop)
+ drop: operation(cm, onDrop),
+ leave: function() {clearDragCursor(cm);}
};
var inp = d.input.getField();
@@ -3457,8 +3519,9 @@
var funcs = cm.display.dragFunctions;
var toggle = value ? on : off;
toggle(cm.display.scroller, "dragstart", funcs.start);
- toggle(cm.display.scroller, "dragenter", funcs.simple);
- toggle(cm.display.scroller, "dragover", funcs.simple);
+ toggle(cm.display.scroller, "dragenter", funcs.enter);
+ toggle(cm.display.scroller, "dragover", funcs.over);
+ toggle(cm.display.scroller, "dragleave", funcs.leave);
toggle(cm.display.scroller, "drop", funcs.drop);
}
}
@@ -3513,7 +3576,7 @@
// not interfere with, such as a scrollbar or widget.
function onMouseDown(e) {
var cm = this, display = cm.display;
- if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return;
+ if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return;
display.shift = e.shiftKey;
if (eventInWidget(display, e)) {
@@ -3531,7 +3594,10 @@
switch (e_button(e)) {
case 1:
- if (start)
+ // #3261: make sure, that we're not starting a second selection
+ if (cm.state.selectingText)
+ cm.state.selectingText(e);
+ else if (start)
leftButtonDown(cm, e, start);
else if (e_target(e) == display.scroller)
e_preventDefault(e);
@@ -3566,7 +3632,7 @@
}
var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
- if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
+ if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
type == "single" && (contained = sel.contains(start)) > -1 &&
(cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) &&
(cmp(contained.to(), start) > 0 || start.xRel < 0))
@@ -3651,7 +3717,8 @@
setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
{scroll: false, origin: "*mouse"});
} else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) {
- setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0));
+ setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
+ {scroll: false, origin: "*mouse"});
startSel = doc.sel;
} else {
replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
@@ -3729,6 +3796,7 @@
}
function done(e) {
+ cm.state.selectingText = false;
counter = Infinity;
e_preventDefault(e);
display.input.focus();
@@ -3742,13 +3810,14 @@
else extend(e);
});
var up = operation(cm, done);
+ cm.state.selectingText = up;
on(document, "mousemove", move);
on(document, "mouseup", up);
}
// Determines whether an event happened in the gutter, and fires the
// handlers for the corresponding event.
- function gutterEvent(cm, e, type, prevent, signalfn) {
+ function gutterEvent(cm, e, type, prevent) {
try { var mX = e.clientX, mY = e.clientY; }
catch(e) { return false; }
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
@@ -3765,14 +3834,14 @@
if (g && g.getBoundingClientRect().right >= mX) {
var line = lineAtHeight(cm.doc, mY);
var gutter = cm.options.gutters[i];
- signalfn(cm, type, cm, line, gutter, e);
+ signal(cm, type, cm, line, gutter, e);
return e_defaultPrevented(e);
}
}
}
function clickInGutter(cm, e) {
- return gutterEvent(cm, e, "gutterClick", true, signalLater);
+ return gutterEvent(cm, e, "gutterClick", true);
}
// Kludge to work around strange IE behavior where it'll sometimes
@@ -3781,23 +3850,32 @@
function onDrop(e) {
var cm = this;
+ clearDragCursor(cm);
if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
return;
e_preventDefault(e);
if (ie) lastDrop = +new Date;
var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
- if (!pos || isReadOnly(cm)) return;
+ if (!pos || cm.isReadOnly()) return;
// Might be a file drop, in which case we simply extract the text
// and insert it.
if (files && files.length && window.FileReader && window.File) {
var n = files.length, text = Array(n), read = 0;
var loadFile = function(file, i) {
+ if (cm.options.allowDropFileTypes &&
+ indexOf(cm.options.allowDropFileTypes, file.type) == -1)
+ return;
+
var reader = new FileReader;
reader.onload = operation(cm, function() {
- text[i] = reader.result;
+ var content = reader.result;
+ if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "";
+ text[i] = content;
if (++read == n) {
pos = clipPos(cm.doc, pos);
- var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"};
+ var change = {from: pos, to: pos,
+ text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
+ origin: "paste"};
makeChange(cm.doc, change);
setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
}
@@ -3851,6 +3929,25 @@
}
}
+ function onDragOver(cm, e) {
+ var pos = posFromMouse(cm, e);
+ if (!pos) return;
+ var frag = document.createDocumentFragment();
+ drawSelectionCursor(cm, pos, frag);
+ if (!cm.display.dragCursor) {
+ cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
+ cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
+ }
+ removeChildrenAndAdd(cm.display.dragCursor, frag);
+ }
+
+ function clearDragCursor(cm) {
+ if (cm.display.dragCursor) {
+ cm.display.lineSpace.removeChild(cm.display.dragCursor);
+ cm.display.dragCursor = null;
+ }
+ }
+
// SCROLL EVENTS
// Sync the scrollable area and scrollbars, ensure the viewport
@@ -3915,8 +4012,9 @@
var display = cm.display, scroll = display.scroller;
// Quit if there's nothing to scroll here
- if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
- dy && scroll.scrollHeight > scroll.clientHeight)) return;
+ var canScrollX = scroll.scrollWidth > scroll.clientWidth;
+ var canScrollY = scroll.scrollHeight > scroll.clientHeight;
+ if (!(dx && canScrollX || dy && canScrollY)) return;
// Webkit browsers on OS X abort momentum scrolls when the target
// of the scroll event is removed from the scrollable element.
@@ -3940,10 +4038,15 @@
// scrolling entirely here. It'll be slightly off from native, but
// better than glitching out.
if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
- if (dy)
+ if (dy && canScrollY)
setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
- e_preventDefault(e);
+ // Only prevent default scrolling if vertical scrolling is
+ // actually possible. Otherwise, it causes vertical scroll
+ // jitter on OSX trackpads when deltaX is small and deltaY
+ // is large (issue #3579)
+ if (!dy || (dy && canScrollY))
+ e_preventDefault(e);
display.wheelStartX = null; // Abort measurement, if in progress
return;
}
@@ -3992,7 +4095,7 @@
cm.display.input.ensurePolled();
var prevShift = cm.display.shift, done = false;
try {
- if (isReadOnly(cm)) cm.state.suppressEdits = true;
+ if (cm.isReadOnly()) cm.state.suppressEdits = true;
if (dropShift) cm.display.shift = false;
done = bound(cm) != Pass;
} finally {
@@ -4171,12 +4274,13 @@
// right-click take effect on it.
function onContextMenu(cm, e) {
if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
+ if (signalDOMEvent(cm, e, "contextmenu")) return;
cm.display.input.onContextMenu(e);
}
function contextMenuInGutter(cm, e) {
if (!hasHandler(cm, "gutterContextMenu")) return false;
- return gutterEvent(cm, e, "gutterContextMenu", false, signal);
+ return gutterEvent(cm, e, "gutterContextMenu", false);
}
// UPDATING
@@ -4480,7 +4584,7 @@
function replaceRange(doc, code, from, to, origin) {
if (!to) to = from;
if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
- if (typeof code == "string") code = splitLines(code);
+ if (typeof code == "string") code = doc.splitLines(code);
makeChange(doc, {from: from, to: to, text: code, origin: origin});
}
@@ -4724,10 +4828,9 @@
function findPosH(doc, pos, dir, unit, visually) {
var line = pos.line, ch = pos.ch, origDir = dir;
var lineObj = getLine(doc, line);
- var possible = true;
function findNextLine() {
var l = line + dir;
- if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
+ if (l < doc.first || l >= doc.first + doc.size) return false
line = l;
return lineObj = getLine(doc, l);
}
@@ -4737,14 +4840,16 @@
if (!boundToLine && findNextLine()) {
if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
else ch = dir < 0 ? lineObj.text.length : 0;
- } else return (possible = false);
+ } else return false
} else ch = next;
return true;
}
- if (unit == "char") moveOnce();
- else if (unit == "column") moveOnce(true);
- else if (unit == "word" || unit == "group") {
+ if (unit == "char") {
+ moveOnce()
+ } else if (unit == "column") {
+ moveOnce(true)
+ } else if (unit == "word" || unit == "group") {
var sawType = null, group = unit == "group";
var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
for (var first = true;; first = false) {
@@ -4764,8 +4869,8 @@
if (dir > 0 && !moveOnce(!first)) break;
}
}
- var result = skipAtomic(doc, Pos(line, ch), origDir, true);
- if (!possible) result.hitSide = true;
+ var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true);
+ if (!cmp(pos, result)) result.hitSide = true;
return result;
}
@@ -5057,7 +5162,7 @@
execCommand: function(cmd) {
if (commands.hasOwnProperty(cmd))
- return commands[cmd](this);
+ return commands[cmd].call(null, this);
},
triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
@@ -5152,6 +5257,7 @@
signal(this, "overwriteToggle", this, this.state.overwrite);
},
hasFocus: function() { return this.display.input.getField() == activeElt(); },
+ isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit); },
scrollTo: methodOp(function(x, y) {
if (x != null || y != null) resolveScrollToPos(this);
@@ -5275,6 +5381,22 @@
clearCaches(cm);
regChange(cm);
}, true);
+ option("lineSeparator", null, function(cm, val) {
+ cm.doc.lineSep = val;
+ if (!val) return;
+ var newBreaks = [], lineNo = cm.doc.first;
+ cm.doc.iter(function(line) {
+ for (var pos = 0;;) {
+ var found = line.text.indexOf(val, pos);
+ if (found == -1) break;
+ pos = found + val.length;
+ newBreaks.push(Pos(lineNo, found));
+ }
+ lineNo++;
+ });
+ for (var i = newBreaks.length - 1; i >= 0; i--)
+ replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length))
+ });
option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) {
cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
if (old != CodeMirror.Init) cm.refresh();
@@ -5333,11 +5455,12 @@
cm.display.disabled = true;
} else {
cm.display.disabled = false;
- if (!val) cm.display.input.reset();
}
+ cm.display.input.readOnlyChanged(val)
});
option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
option("dragDrop", true, dragDropChanged);
+ option("allowDropFileTypes", null);
option("cursorBlinkRate", 530);
option("cursorScrollMargin", 0);
@@ -5625,7 +5748,8 @@
} else if (cur.line > cm.doc.first) {
var prev = getLine(cm.doc, cur.line - 1).text;
if (prev)
- cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1),
+ cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
+ prev.charAt(prev.length - 1),
Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose");
}
}
@@ -5639,10 +5763,10 @@
var len = cm.listSelections().length;
for (var i = 0; i < len; i++) {
var range = cm.listSelections()[i];
- cm.replaceRange("\n", range.anchor, range.head, "+input");
+ cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input");
cm.indentLine(range.from().line + 1, null, true);
- ensureCursorVisible(cm);
}
+ ensureCursorVisible(cm);
});
},
toggleOverwrite: function(cm) {cm.toggleOverwrite();}
@@ -6570,7 +6694,7 @@
parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;";
removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
}
- return widget.height = widget.node.offsetHeight;
+ return widget.height = widget.node.parentNode.offsetHeight;
}
function addLineWidget(doc, handle, node, options) {
@@ -6759,7 +6883,9 @@
function getLineStyles(cm, line, updateFrontier) {
if (!line.styles || line.styles[0] != cm.state.modeGen) {
- var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line)));
+ var state = getStateBefore(cm, lineNo(line));
+ var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state);
+ line.stateAfter = state;
line.styles = result.styles;
if (result.classes) line.styleClasses = result.classes;
else if (line.styleClasses) line.styleClasses = null;
@@ -6776,7 +6902,7 @@
var stream = new StringStream(text, cm.options.tabSize);
stream.start = stream.pos = startAt || 0;
if (text == "") callBlankLine(mode, state);
- while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) {
+ while (!stream.eol()) {
readToken(mode, stream, state);
stream.start = stream.pos;
}
@@ -6803,7 +6929,7 @@
// is needed on Webkit to be able to get line-level bounding
// rectangles for it (in measureChar).
var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
- var builder = {pre: elt("pre", [content]), content: content,
+ var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content,
col: 0, pos: 0, cm: cm,
splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
lineView.measure = {};
@@ -6893,6 +7019,10 @@
txt.setAttribute("role", "presentation");
txt.setAttribute("cm-text", "\t");
builder.col += tabWidth;
+ } else if (m[0] == "\r" || m[0] == "\n") {
+ var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
+ txt.setAttribute("cm-text", m[0]);
+ builder.col += 1;
} else {
var txt = builder.cm.options.specialCharPlaceholder(m[0]);
txt.setAttribute("cm-text", m[0]);
@@ -6974,7 +7104,7 @@
if (nextChange == pos) { // Update current marker set
spanStyle = spanEndStyle = spanStartStyle = title = css = "";
collapsed = null; nextChange = Infinity;
- var foundBookmarks = [];
+ var foundBookmarks = [], endStyles
for (var j = 0; j < spans.length; ++j) {
var sp = spans[j], m = sp.marker;
if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
@@ -6985,9 +7115,9 @@
spanEndStyle = "";
}
if (m.className) spanStyle += " " + m.className;
- if (m.css) css = m.css;
+ if (m.css) css = (css ? css + ";" : "") + m.css;
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
- if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
+ if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to)
if (m.title && !title) title = m.title;
if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
collapsed = sp;
@@ -6995,14 +7125,17 @@
nextChange = sp.from;
}
}
+ if (endStyles) for (var j = 0; j < endStyles.length; j += 2)
+ if (endStyles[j + 1] == nextChange) spanEndStyle += " " + endStyles[j]
+
+ if (!collapsed || collapsed.from == pos) for (var j = 0; j < foundBookmarks.length; ++j)
+ buildCollapsedSpan(builder, 0, foundBookmarks[j]);
if (collapsed && (collapsed.from || 0) == pos) {
buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
collapsed.marker, collapsed.from == null);
if (collapsed.to == null) return;
if (collapsed.to == pos) collapsed = false;
}
- if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
- buildCollapsedSpan(builder, 0, foundBookmarks[j]);
}
if (pos >= len) break;
@@ -7238,8 +7371,8 @@
};
var nextDocId = 0;
- var Doc = CodeMirror.Doc = function(text, mode, firstLine) {
- if (!(this instanceof Doc)) return new Doc(text, mode, firstLine);
+ var Doc = CodeMirror.Doc = function(text, mode, firstLine, lineSep) {
+ if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep);
if (firstLine == null) firstLine = 0;
BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
@@ -7253,8 +7386,10 @@
this.history = new History(null);
this.id = ++nextDocId;
this.modeOption = mode;
+ this.lineSep = lineSep;
+ this.extend = false;
- if (typeof text == "string") text = splitLines(text);
+ if (typeof text == "string") text = this.splitLines(text);
updateDoc(this, {from: start, to: start, text: text});
setSelection(this, simpleSelection(start), sel_dontScroll);
};
@@ -7284,12 +7419,12 @@
getValue: function(lineSep) {
var lines = getLines(this, this.first, this.first + this.size);
if (lineSep === false) return lines;
- return lines.join(lineSep || "\n");
+ return lines.join(lineSep || this.lineSeparator());
},
setValue: docMethodOp(function(code) {
var top = Pos(this.first, 0), last = this.first + this.size - 1;
makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
- text: splitLines(code), origin: "setValue", full: true}, true);
+ text: this.splitLines(code), origin: "setValue", full: true}, true);
setSelection(this, simpleSelection(top));
}),
replaceRange: function(code, from, to, origin) {
@@ -7300,7 +7435,7 @@
getRange: function(from, to, lineSep) {
var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
if (lineSep === false) return lines;
- return lines.join(lineSep || "\n");
+ return lines.join(lineSep || this.lineSeparator());
},
getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
@@ -7340,10 +7475,11 @@
extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
}),
extendSelections: docMethodOp(function(heads, options) {
- extendSelections(this, clipPosArray(this, heads, options));
+ extendSelections(this, clipPosArray(this, heads), options);
}),
extendSelectionsBy: docMethodOp(function(f, options) {
- extendSelections(this, map(this.sel.ranges, f), options);
+ var heads = map(this.sel.ranges, f);
+ extendSelections(this, clipPosArray(this, heads), options);
}),
setSelections: docMethodOp(function(ranges, primary, options) {
if (!ranges.length) return;
@@ -7366,13 +7502,13 @@
lines = lines ? lines.concat(sel) : sel;
}
if (lineSep === false) return lines;
- else return lines.join(lineSep || "\n");
+ else return lines.join(lineSep || this.lineSeparator());
},
getSelections: function(lineSep) {
var parts = [], ranges = this.sel.ranges;
for (var i = 0; i < ranges.length; i++) {
var sel = getBetween(this, ranges[i].from(), ranges[i].to());
- if (lineSep !== false) sel = sel.join(lineSep || "\n");
+ if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator());
parts[i] = sel;
}
return parts;
@@ -7387,7 +7523,7 @@
var changes = [], sel = this.sel;
for (var i = 0; i < sel.ranges.length; i++) {
var range = sel.ranges[i];
- changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin};
+ changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin};
}
var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
for (var i = changes.length - 1; i >= 0; i--)
@@ -7468,7 +7604,7 @@
removeLineWidget: function(widget) { widget.clear(); },
markText: function(from, to, options) {
- return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
+ return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range");
},
setBookmark: function(pos, options) {
var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
@@ -7537,7 +7673,8 @@
},
copy: function(copyHistory) {
- var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first);
+ var doc = new Doc(getLines(this, this.first, this.first + this.size),
+ this.modeOption, this.first, this.lineSep);
doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
doc.sel = this.sel;
doc.extend = false;
@@ -7553,7 +7690,7 @@
var from = this.first, to = this.first + this.size;
if (options.from != null && options.from > from) from = options.from;
if (options.to != null && options.to < to) to = options.to;
- var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from);
+ var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep);
if (options.sharedHist) copy.history = this.history;
(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
@@ -7582,7 +7719,13 @@
iterLinkedDocs: function(f) {linkedDocs(this, f);},
getMode: function() {return this.mode;},
- getEditor: function() {return this.cm;}
+ getEditor: function() {return this.cm;},
+
+ splitLines: function(str) {
+ if (this.lineSep) return str.split(this.lineSep);
+ return splitLinesAuto(str);
+ },
+ lineSeparator: function() { return this.lineSep || "\n"; }
});
// Public alias.
@@ -8023,24 +8166,30 @@
}
};
+ var noHandlers = []
+ function getHandlers(emitter, type, copy) {
+ var arr = emitter._handlers && emitter._handlers[type]
+ if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers
+ else return arr || noHandlers
+ }
+
var off = CodeMirror.off = function(emitter, type, f) {
if (emitter.removeEventListener)
emitter.removeEventListener(type, f, false);
else if (emitter.detachEvent)
emitter.detachEvent("on" + type, f);
else {
- var arr = emitter._handlers && emitter._handlers[type];
- if (!arr) return;
- for (var i = 0; i < arr.length; ++i)
- if (arr[i] == f) { arr.splice(i, 1); break; }
+ var handlers = getHandlers(emitter, type, false)
+ for (var i = 0; i < handlers.length; ++i)
+ if (handlers[i] == f) { handlers.splice(i, 1); break; }
}
};
var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
- var arr = emitter._handlers && emitter._handlers[type];
- if (!arr) return;
+ var handlers = getHandlers(emitter, type, true)
+ if (!handlers.length) return;
var args = Array.prototype.slice.call(arguments, 2);
- for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
+ for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args);
};
var orphanDelayedCallbacks = null;
@@ -8053,8 +8202,8 @@
// them to be executed when the last operation ends, or, if no
// operation is active, when a timeout fires.
function signalLater(emitter, type /*, values...*/) {
- var arr = emitter._handlers && emitter._handlers[type];
- if (!arr) return;
+ var arr = getHandlers(emitter, type, false)
+ if (!arr.length) return;
var args = Array.prototype.slice.call(arguments, 2), list;
if (operationGroup) {
list = operationGroup.delayedCallbacks;
@@ -8094,8 +8243,7 @@
}
function hasHandler(emitter, type) {
- var arr = emitter._handlers && emitter._handlers[type];
- return arr && arr.length > 0;
+ return getHandlers(emitter, type).length > 0
}
// Add on and off methods to a constructor's prototype, to make
@@ -8142,7 +8290,7 @@
// The inverse of countColumn -- find the offset that corresponds to
// a particular column.
- function findColumn(string, goal, tabSize) {
+ var findColumn = CodeMirror.findColumn = function(string, goal, tabSize) {
for (var pos = 0, col = 0;;) {
var nextTab = string.indexOf("\t", pos);
if (nextTab == -1) nextTab = string.length;
@@ -8282,7 +8430,12 @@
} while (child = child.parentNode);
};
- function activeElt() { return document.activeElement; }
+ function activeElt() {
+ var activeElement = document.activeElement;
+ while (activeElement && activeElement.root && activeElement.root.activeElement)
+ activeElement = activeElement.root.activeElement;
+ return activeElement;
+ }
// Older versions of IE throws unspecified error when touching
// document.activeElement in some cases (during loading, in iframe)
if (ie && ie_version < 11) activeElt = function() {
@@ -8384,7 +8537,7 @@
// See if "".split is the broken IE version, if so, provide an
// alternative way to split lines.
- var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
+ var splitLinesAuto = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
var pos = 0, result = [], l = string.length;
while (pos <= l) {
var nl = string.indexOf("\n", pos);
@@ -8430,14 +8583,16 @@
// KEY NAMES
- var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
- 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
- 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
- 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete",
- 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
- 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
- 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"};
- CodeMirror.keyNames = keyNames;
+ var keyNames = CodeMirror.keyNames = {
+ 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
+ 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
+ 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
+ 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
+ 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
+ 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
+ 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
+ 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
+ };
(function() {
// Number keys
for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
@@ -8742,7 +8897,7 @@
// THE END
- CodeMirror.version = "5.4.0";
+ CodeMirror.version = "5.10.1";
return CodeMirror;
});