|
|
@@ -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";
|
|
|
|
|
|
@@ -41,6 +41,7 @@
|
|
|
// This is woefully incomplete. Suggestions for alternative methods welcome.
|
|
|
var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
|
|
|
var mac = ios || /Mac/.test(platform);
|
|
|
+ var chromeOS = /\bCrOS\b/.test(userAgent);
|
|
|
var windows = /win/i.test(platform);
|
|
|
|
|
|
var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
|
|
|
@@ -543,6 +544,7 @@
|
|
|
|
|
|
d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
|
|
|
d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
|
|
|
+ d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"
|
|
|
|
|
|
if (sizes.right && sizes.bottom) {
|
|
|
d.scrollbarFiller.style.display = "block";
|
|
|
@@ -746,6 +748,7 @@
|
|
|
|
|
|
function postUpdateDisplay(cm, update) {
|
|
|
var viewport = update.viewport;
|
|
|
+
|
|
|
for (var first = true;; first = false) {
|
|
|
if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
|
|
|
// Clip forced viewport to actual scrollable area.
|
|
|
@@ -761,8 +764,8 @@
|
|
|
updateHeightsInViewport(cm);
|
|
|
var barMeasure = measureForScrollbars(cm);
|
|
|
updateSelection(cm);
|
|
|
- setDocumentHeight(cm, barMeasure);
|
|
|
updateScrollbars(cm, barMeasure);
|
|
|
+ setDocumentHeight(cm, barMeasure);
|
|
|
}
|
|
|
|
|
|
update.signal(cm, "update", cm);
|
|
|
@@ -779,17 +782,16 @@
|
|
|
postUpdateDisplay(cm, update);
|
|
|
var barMeasure = measureForScrollbars(cm);
|
|
|
updateSelection(cm);
|
|
|
- setDocumentHeight(cm, barMeasure);
|
|
|
updateScrollbars(cm, barMeasure);
|
|
|
+ setDocumentHeight(cm, barMeasure);
|
|
|
update.finish();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function setDocumentHeight(cm, measure) {
|
|
|
cm.display.sizer.style.minHeight = measure.docHeight + "px";
|
|
|
- var total = measure.docHeight + cm.display.barHeight;
|
|
|
- cm.display.heightForcer.style.top = total + "px";
|
|
|
- cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px";
|
|
|
+ cm.display.heightForcer.style.top = measure.docHeight + "px";
|
|
|
+ cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
|
|
|
}
|
|
|
|
|
|
// Read the actual heights of the rendered lines, and update their
|
|
|
@@ -823,7 +825,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
|
|
|
@@ -1094,10 +1096,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.
|
|
|
@@ -1152,7 +1150,7 @@
|
|
|
var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
|
|
|
if (pasted) {
|
|
|
e.preventDefault();
|
|
|
- if (!isReadOnly(cm) && !cm.options.disableInput)
|
|
|
+ if (!cm.isReadOnly() && !cm.options.disableInput)
|
|
|
runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); });
|
|
|
return true;
|
|
|
}
|
|
|
@@ -1255,13 +1253,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) {
|
|
|
@@ -1289,7 +1288,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();
|
|
|
});
|
|
|
@@ -1423,7 +1422,7 @@
|
|
|
// in which case reading its value would be expensive.
|
|
|
if (this.contextMenuPending || !cm.state.focused ||
|
|
|
(hasSelection(input) && !prevInput && !this.composing) ||
|
|
|
- isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
|
|
|
+ cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
|
|
|
return false;
|
|
|
|
|
|
var text = input.value;
|
|
|
@@ -1485,10 +1484,11 @@
|
|
|
if (reset && cm.doc.sel.contains(pos) == -1)
|
|
|
operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
|
|
|
|
|
|
- var oldCSS = te.style.cssText;
|
|
|
- input.wrapper.style.position = "absolute";
|
|
|
- te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
|
|
|
- "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
|
|
|
+ var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
|
|
|
+ input.wrapper.style.cssText = "position: absolute"
|
|
|
+ var wrapperBox = input.wrapper.getBoundingClientRect()
|
|
|
+ te.style.cssText = "position: absolute; width: 30px; height: 30px; top: " + (e.clientY - wrapperBox.top - 5) +
|
|
|
+ "px; left: " + (e.clientX - wrapperBox.left - 5) + "px; z-index: 1000; background: " +
|
|
|
(ie ? "rgba(255, 255, 255, .05)" : "transparent") +
|
|
|
"; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
|
|
|
if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
|
|
|
@@ -1519,7 +1519,7 @@
|
|
|
}
|
|
|
function rehide() {
|
|
|
input.contextMenuPending = false;
|
|
|
- input.wrapper.style.position = "relative";
|
|
|
+ input.wrapper.style.cssText = oldWrapperCSS
|
|
|
te.style.cssText = oldCSS;
|
|
|
if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
|
|
|
|
|
|
@@ -1574,7 +1574,9 @@
|
|
|
var div = input.div = display.lineDiv;
|
|
|
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;
|
|
|
@@ -1612,11 +1614,12 @@
|
|
|
|
|
|
on(div, "input", function() {
|
|
|
if (input.composing) return;
|
|
|
- if (isReadOnly(cm) || !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");
|
|
|
@@ -1692,8 +1695,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();
|
|
|
}
|
|
|
@@ -1837,7 +1845,7 @@
|
|
|
this.div.focus();
|
|
|
},
|
|
|
applyComposition: function(composing) {
|
|
|
- if (isReadOnly(this.cm))
|
|
|
+ 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);
|
|
|
@@ -1849,7 +1857,7 @@
|
|
|
|
|
|
onKeyPress: function(e) {
|
|
|
e.preventDefault();
|
|
|
- if (!isReadOnly(this.cm))
|
|
|
+ if (!this.cm.isReadOnly())
|
|
|
operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
|
|
|
},
|
|
|
|
|
|
@@ -2154,7 +2162,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) {
|
|
|
@@ -2162,7 +2170,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);
|
|
|
@@ -2188,7 +2197,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);
|
|
|
@@ -2222,8 +2231,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);
|
|
|
@@ -2232,54 +2242,61 @@
|
|
|
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, near && near.line == pos.line ? line : null);
|
|
|
+ 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, far.line == pos.line ? line : null);
|
|
|
+ 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);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -2297,6 +2314,7 @@
|
|
|
for (var i = 0; i < doc.sel.ranges.length; i++) {
|
|
|
if (primary === false && i == doc.sel.primIndex) continue;
|
|
|
var range = doc.sel.ranges[i];
|
|
|
+ if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue;
|
|
|
var collapsed = range.empty();
|
|
|
if (collapsed || cm.options.showCursorWhenSelecting)
|
|
|
drawSelectionCursor(cm, range.head, curFragment);
|
|
|
@@ -3098,10 +3116,10 @@
|
|
|
|
|
|
if (op.preparedSelection)
|
|
|
cm.display.input.showSelection(op.preparedSelection);
|
|
|
- if (op.updatedDisplay)
|
|
|
- setDocumentHeight(cm, op.barMeasure);
|
|
|
if (op.updatedDisplay || op.startHeight != cm.doc.height)
|
|
|
updateScrollbars(cm, op.barMeasure);
|
|
|
+ if (op.updatedDisplay)
|
|
|
+ setDocumentHeight(cm, op.barMeasure);
|
|
|
|
|
|
if (op.selectionChanged) restartBlink(cm);
|
|
|
|
|
|
@@ -3127,7 +3145,7 @@
|
|
|
display.scroller.scrollTop = doc.scrollTop;
|
|
|
}
|
|
|
if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
|
|
|
- doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));
|
|
|
+ doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft));
|
|
|
display.scrollbars.setScrollLeft(doc.scrollLeft);
|
|
|
display.scroller.scrollLeft = doc.scrollLeft;
|
|
|
alignHorizontally(cm);
|
|
|
@@ -3423,7 +3441,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,
|
|
|
@@ -3478,7 +3496,7 @@
|
|
|
over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
|
|
|
start: function(e){onDragStart(cm, e);},
|
|
|
drop: operation(cm, onDrop),
|
|
|
- leave: function() {clearDragCursor(cm);}
|
|
|
+ leave: function(e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
|
|
|
};
|
|
|
|
|
|
var inp = d.input.getField();
|
|
|
@@ -3552,7 +3570,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)) {
|
|
|
@@ -3608,7 +3626,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))
|
|
|
@@ -3663,7 +3681,7 @@
|
|
|
ourIndex = doc.sel.primIndex;
|
|
|
}
|
|
|
|
|
|
- if (e.altKey) {
|
|
|
+ if (chromeOS ? e.shiftKey && e.metaKey : e.altKey) {
|
|
|
type = "rect";
|
|
|
if (!addNew) ourRange = new Range(start, start);
|
|
|
start = posFromMouse(cm, e, true, true);
|
|
|
@@ -3832,7 +3850,7 @@
|
|
|
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) {
|
|
|
@@ -3888,6 +3906,7 @@
|
|
|
if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
|
|
|
|
|
|
e.dataTransfer.setData("Text", cm.getSelection());
|
|
|
+ e.dataTransfer.effectAllowed = "copyMove"
|
|
|
|
|
|
// Use dummy image instead of default browsers image.
|
|
|
// Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
|
|
|
@@ -4071,7 +4090,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 {
|
|
|
@@ -4804,10 +4823,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);
|
|
|
}
|
|
|
@@ -4817,14 +4835,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) {
|
|
|
@@ -4844,8 +4864,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;
|
|
|
}
|
|
|
|
|
|
@@ -5232,6 +5252,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);
|
|
|
@@ -6668,7 +6689,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) {
|
|
|
@@ -7078,7 +7099,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) {
|
|
|
@@ -7091,7 +7112,7 @@
|
|
|
if (m.className) spanStyle += " " + m.className;
|
|
|
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;
|
|
|
@@ -7099,14 +7120,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;
|
|
|
|
|
|
@@ -7446,10 +7470,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;
|
|
|
@@ -7602,9 +7627,9 @@
|
|
|
var spans = line.markedSpans;
|
|
|
if (spans) for (var i = 0; i < spans.length; i++) {
|
|
|
var span = spans[i];
|
|
|
- if (!(lineNo == from.line && from.ch > span.to ||
|
|
|
- span.from == null && lineNo != from.line||
|
|
|
- lineNo == to.line && span.from > to.ch) &&
|
|
|
+ if (!(span.to != null && lineNo == from.line && from.ch >= span.to ||
|
|
|
+ span.from == null && lineNo != from.line ||
|
|
|
+ span.from != null && lineNo == to.line && span.from >= to.ch) &&
|
|
|
(!filter || filter(span.marker)))
|
|
|
found.push(span.marker.parent || span.marker);
|
|
|
}
|
|
|
@@ -7623,9 +7648,9 @@
|
|
|
},
|
|
|
|
|
|
posFromIndex: function(off) {
|
|
|
- var ch, lineNo = this.first;
|
|
|
+ var ch, lineNo = this.first, sepSize = this.lineSeparator().length;
|
|
|
this.iter(function(line) {
|
|
|
- var sz = line.text.length + 1;
|
|
|
+ var sz = line.text.length + sepSize;
|
|
|
if (sz > off) { ch = off; return true; }
|
|
|
off -= sz;
|
|
|
++lineNo;
|
|
|
@@ -7636,8 +7661,9 @@
|
|
|
coords = clipPos(this, coords);
|
|
|
var index = coords.ch;
|
|
|
if (coords.line < this.first || coords.ch < 0) return 0;
|
|
|
+ var sepSize = this.lineSeparator().length;
|
|
|
this.iter(this.first, coords.line, function (line) {
|
|
|
- index += line.text.length + 1;
|
|
|
+ index += line.text.length + sepSize;
|
|
|
});
|
|
|
return index;
|
|
|
},
|
|
|
@@ -8866,7 +8892,7 @@
|
|
|
|
|
|
// THE END
|
|
|
|
|
|
- CodeMirror.version = "5.9.0";
|
|
|
+ CodeMirror.version = "5.14.2";
|
|
|
|
|
|
return CodeMirror;
|
|
|
});
|