From 5d617484e5025dc32165c30b530127c45db31703 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Tue, 22 Dec 2020 09:06:26 -0500 Subject: [PATCH] Upgrade CodeMirror library to 5.59.0 (from 5.46.0) --- src/lib/codemirror/README.md | 1 - src/lib/codemirror/addon/comment/comment.js | 4 +- src/lib/codemirror/addon/display/panel.js | 54 +- .../codemirror/addon/edit/matchbrackets.js | 16 +- src/lib/codemirror/addon/fold/foldcode.js | 9 +- src/lib/codemirror/addon/fold/foldgutter.js | 33 +- src/lib/codemirror/addon/hint/show-hint.js | 105 ++- src/lib/codemirror/addon/merge/merge.js | 18 +- .../addon/scroll/annotatescrollbar.js | 14 +- .../codemirror/addon/search/searchcursor.js | 35 +- src/lib/codemirror/lib/codemirror.css | 24 +- src/lib/codemirror/lib/codemirror.js | 772 +++++++++--------- 12 files changed, 618 insertions(+), 467 deletions(-) diff --git a/src/lib/codemirror/README.md b/src/lib/codemirror/README.md index 2a7b1f5eb..92debf448 100644 --- a/src/lib/codemirror/README.md +++ b/src/lib/codemirror/README.md @@ -2,7 +2,6 @@ [![Build Status](https://travis-ci.org/codemirror/CodeMirror.svg)](https://travis-ci.org/codemirror/CodeMirror) [![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror) -[![Join the chat at https://gitter.im/codemirror/CodeMirror](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/codemirror/CodeMirror) CodeMirror is a versatile text editor implemented in JavaScript for the browser. It is specialized for editing code, and comes with over diff --git a/src/lib/codemirror/addon/comment/comment.js b/src/lib/codemirror/addon/comment/comment.js index 8394e85a4..dac48d038 100644 --- a/src/lib/codemirror/addon/comment/comment.js +++ b/src/lib/codemirror/addon/comment/comment.js @@ -13,7 +13,7 @@ var noOptions = {}; var nonWS = /[^\s\u00a0]/; - var Pos = CodeMirror.Pos; + var Pos = CodeMirror.Pos, cmp = CodeMirror.cmpPos; function firstNonWS(str) { var found = str.search(nonWS); @@ -126,7 +126,9 @@ if (i != end || lastLineHasText) self.replaceRange(lead + pad, Pos(i, 0)); } else { + var atCursor = cmp(self.getCursor("to"), to) == 0, empty = !self.somethingSelected() self.replaceRange(endString, to); + if (atCursor) self.setSelection(empty ? to : self.getCursor("from"), to) self.replaceRange(startString, from); } }); diff --git a/src/lib/codemirror/addon/display/panel.js b/src/lib/codemirror/addon/display/panel.js index 5faf1d560..4c9f2c0fc 100644 --- a/src/lib/codemirror/addon/display/panel.js +++ b/src/lib/codemirror/addon/display/panel.js @@ -1,15 +1,15 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/LICENSE -(function(mod) { +(function (mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); else if (typeof define == "function" && define.amd) // AMD define(["../../lib/codemirror"], mod); else // Plain browser env mod(CodeMirror); -})(function(CodeMirror) { - CodeMirror.defineExtension("addPanel", function(node, options) { +})(function (CodeMirror) { + CodeMirror.defineExtension("addPanel", function (node, options) { options = options || {}; if (!this.state.panels) initPanels(this); @@ -25,8 +25,7 @@ wrapper.insertBefore(node, options.before.node); } else if (replace) { wrapper.insertBefore(node, options.replace.node); - info.panels++; - options.replace.clear(); + options.replace.clear(true); } else if (options.position == "bottom") { wrapper.appendChild(node); } else if (options.position == "before-bottom") { @@ -38,14 +37,15 @@ } var height = (options && options.height) || node.offsetHeight; - this._setSize(null, info.heightLeft -= height); - if (!replace) { - info.panels++; - } - if (options.stable && isAtTop(this, node)) - this.scrollTo(null, this.getScrollInfo().top + height) - return new Panel(this, node, options, height); + var panel = new Panel(this, node, options, height); + info.panels.push(panel); + + this.setSize(); + if (options.stable && isAtTop(this, node)) + this.scrollTo(null, this.getScrollInfo().top + height); + + return panel; }); function Panel(cm, node, options, height) { @@ -56,22 +56,23 @@ this.cleared = false; } - Panel.prototype.clear = function() { + /* when skipRemove is true, clear() was called from addPanel(). + * Thus removePanels() should not be called (issue 5518) */ + Panel.prototype.clear = function (skipRemove) { if (this.cleared) return; this.cleared = true; var info = this.cm.state.panels; - this.cm._setSize(null, info.heightLeft += this.height); + info.panels.splice(info.panels.indexOf(this), 1); + this.cm.setSize(); if (this.options.stable && isAtTop(this.cm, this.node)) this.cm.scrollTo(null, this.cm.getScrollInfo().top - this.height) info.wrapper.removeChild(this.node); - if (--info.panels == 0) removePanels(this.cm); + if (info.panels.length == 0 && !skipRemove) removePanels(this.cm); }; - Panel.prototype.changed = function(height) { - var newHeight = height == null ? this.node.offsetHeight : height; - var info = this.cm.state.panels; - this.cm._setSize(null, info.heightLeft -= (newHeight - this.height)); - this.height = newHeight; + Panel.prototype.changed = function () { + this.height = this.node.getBoundingClientRect().height; + this.cm.setSize(); }; function initPanels(cm) { @@ -80,8 +81,7 @@ var height = parseInt(style.height); var info = cm.state.panels = { setHeight: wrap.style.height, - heightLeft: height, - panels: 0, + panels: [], wrapper: document.createElement("div") }; wrap.parentNode.insertBefore(info.wrapper, wrap); @@ -90,8 +90,8 @@ if (hasFocus) cm.focus(); cm._setSize = cm.setSize; - if (height != null) cm.setSize = function(width, newHeight) { - if (newHeight == null) return this._setSize(width, newHeight); + if (height != null) cm.setSize = function (width, newHeight) { + if (!newHeight) newHeight = info.wrapper.offsetHeight; info.setHeight = newHeight; if (typeof newHeight != "number") { var px = /^(\d+\.?\d*)px$/.exec(newHeight); @@ -100,10 +100,12 @@ } else { info.wrapper.style.height = newHeight; newHeight = info.wrapper.offsetHeight; - info.wrapper.style.height = ""; } } - cm._setSize(width, info.heightLeft += (newHeight - height)); + var editorheight = newHeight - info.panels + .map(function (p) { return p.node.getBoundingClientRect().height; }) + .reduce(function (a, b) { return a + b; }, 0); + cm._setSize(width, editorheight); height = newHeight; }; } diff --git a/src/lib/codemirror/addon/edit/matchbrackets.js b/src/lib/codemirror/addon/edit/matchbrackets.js index 2a147282c..037740880 100644 --- a/src/lib/codemirror/addon/edit/matchbrackets.js +++ b/src/lib/codemirror/addon/edit/matchbrackets.js @@ -117,17 +117,25 @@ }); } + function clearHighlighted(cm) { + if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) { + cm.state.matchBrackets.currentlyHighlighted(); + cm.state.matchBrackets.currentlyHighlighted = null; + } + } + CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { if (old && old != CodeMirror.Init) { cm.off("cursorActivity", doMatchBrackets); - if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) { - cm.state.matchBrackets.currentlyHighlighted(); - cm.state.matchBrackets.currentlyHighlighted = null; - } + cm.off("focus", doMatchBrackets) + cm.off("blur", clearHighlighted) + clearHighlighted(cm); } if (val) { cm.state.matchBrackets = typeof val == "object" ? val : {}; cm.on("cursorActivity", doMatchBrackets); + cm.on("focus", doMatchBrackets) + cm.on("blur", clearHighlighted) } }); diff --git a/src/lib/codemirror/addon/fold/foldcode.js b/src/lib/codemirror/addon/fold/foldcode.js index e146fb9f3..887df3fe0 100644 --- a/src/lib/codemirror/addon/fold/foldcode.js +++ b/src/lib/codemirror/addon/fold/foldcode.js @@ -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"); diff --git a/src/lib/codemirror/addon/fold/foldgutter.js b/src/lib/codemirror/addon/fold/foldgutter.js index 988c67c45..7d46a609b 100644 --- a/src/lib/codemirror/addon/fold/foldgutter.js +++ b/src/lib/codemirror/addon/fold/foldgutter.js @@ -16,7 +16,7 @@ cm.clearGutter(cm.state.foldGutter.options.gutter); cm.state.foldGutter = null; cm.off("gutterClick", onGutterClick); - cm.off("change", onChange); + cm.off("changes", onChange); cm.off("viewportChange", onViewportChange); cm.off("fold", onFold); cm.off("unfold", onFold); @@ -26,7 +26,7 @@ cm.state.foldGutter = new State(parseOptions(val)); updateInViewport(cm); cm.on("gutterClick", onGutterClick); - cm.on("change", onChange); + cm.on("changes", onChange); cm.on("viewportChange", onViewportChange); cm.on("fold", onFold); cm.on("unfold", onFold); @@ -51,8 +51,13 @@ function isFolded(cm, line) { var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0)); - for (var i = 0; i < marks.length; ++i) - if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i]; + for (var i = 0; i < marks.length; ++i) { + if (marks[i].__isFold) { + var fromPos = marks[i].find(-1); + if (fromPos && fromPos.line === line) + return marks[i]; + } + } } function marker(spec) { @@ -66,24 +71,36 @@ } function updateFoldInfo(cm, from, to) { - var opts = cm.state.foldGutter.options, cur = from; + var opts = cm.state.foldGutter.options, cur = from - 1; var minSize = cm.foldOption(opts, "minFoldSize"); var func = cm.foldOption(opts, "rangeFinder"); + // we can reuse the built-in indicator element if its className matches the new state + var clsFolded = typeof opts.indicatorFolded == "string" && classTest(opts.indicatorFolded); + var clsOpen = typeof opts.indicatorOpen == "string" && classTest(opts.indicatorOpen); cm.eachLine(from, to, function(line) { + ++cur; var mark = null; + var old = line.gutterMarkers; + if (old) old = old[opts.gutter]; if (isFolded(cm, cur)) { + if (clsFolded && old && clsFolded.test(old.className)) return; mark = marker(opts.indicatorFolded); } else { var pos = Pos(cur, 0); var range = func && func(cm, pos); - if (range && range.to.line - range.from.line >= minSize) + if (range && range.to.line - range.from.line >= minSize) { + if (clsOpen && old && clsOpen.test(old.className)) return; mark = marker(opts.indicatorOpen); + } } + if (!mark && !old) return; cm.setGutterMarker(line, opts.gutter, mark); - ++cur; }); } + // copied from CodeMirror/src/util/dom.js + function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") } + function updateInViewport(cm) { var vp = cm.getViewport(), state = cm.state.foldGutter; if (!state) return; @@ -100,7 +117,7 @@ if (gutter != opts.gutter) return; var folded = isFolded(cm, line); if (folded) folded.clear(); - else cm.foldCode(Pos(line, 0), opts.rangeFinder); + else cm.foldCode(Pos(line, 0), opts); } function onChange(cm) { diff --git a/src/lib/codemirror/addon/hint/show-hint.js b/src/lib/codemirror/addon/hint/show-hint.js index e3cd209d7..5ef1bba64 100644 --- a/src/lib/codemirror/addon/hint/show-hint.js +++ b/src/lib/codemirror/addon/hint/show-hint.js @@ -1,6 +1,8 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/LICENSE +// declare global: DOMRect + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); @@ -85,12 +87,19 @@ }, pick: function(data, i) { - var completion = data.list[i]; - if (completion.hint) completion.hint(this.cm, data, completion); - else this.cm.replaceRange(getText(completion), completion.from || data.from, - completion.to || data.to, "complete"); - CodeMirror.signal(data, "pick", completion); - this.close(); + var completion = data.list[i], self = this; + this.cm.operation(function() { + if (completion.hint) + completion.hint(self.cm, data, completion); + else + self.cm.replaceRange(getText(completion), completion.from || data.from, + completion.to || data.to, "complete"); + CodeMirror.signal(data, "pick", completion); + self.cm.scrollIntoView(); + }); + if (this.options.closeOnPick) { + this.close(); + } }, cursorActivity: function() { @@ -99,11 +108,18 @@ this.debounce = 0; } + var identStart = this.startPos; + if(this.data) { + identStart = this.data.from; + } + var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || - pos.ch < this.startPos.ch || this.cm.somethingSelected() || + pos.ch < identStart.ch || this.cm.somethingSelected() || (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { - this.close(); + if (this.options.closeOnCursorActivity) { + this.close(); + } } else { var self = this; this.debounce = requestAnimationFrame(function() {self.update();}); @@ -229,30 +245,47 @@ elt.hintId = i; } + var container = completion.options.container || ownerDocument.body; var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); var left = pos.left, top = pos.bottom, below = true; - hints.style.left = left + "px"; - hints.style.top = top + "px"; + var offsetLeft = 0, offsetTop = 0; + if (container !== ownerDocument.body) { + // We offset the cursor position because left and top are relative to the offsetParent's top left corner. + var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1; + var offsetParent = isContainerPositioned ? container : container.offsetParent; + var offsetParentPosition = offsetParent.getBoundingClientRect(); + var bodyPosition = ownerDocument.body.getBoundingClientRect(); + offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft); + offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop); + } + hints.style.left = (left - offsetLeft) + "px"; + hints.style.top = (top - offsetTop) + "px"; + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth); var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight); - (completion.options.container || ownerDocument.body).appendChild(hints); - var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; - var scrolls = hints.scrollHeight > hints.clientHeight + 1 - var startScroll = cm.getScrollInfo(); + container.appendChild(hints); + var box = completion.options.moveOnOverlap ? hints.getBoundingClientRect() : new DOMRect(); + var scrolls = completion.options.paddingForScrollbar ? hints.scrollHeight > hints.clientHeight + 1 : false; + + // Compute in the timeout to avoid reflow on init + var startScroll; + setTimeout(function() { startScroll = cm.getScrollInfo(); }); + + var overlapY = box.bottom - winH; if (overlapY > 0) { var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); if (curTop - height > 0) { // Fits above cursor - hints.style.top = (top = pos.top - height) + "px"; + hints.style.top = (top = pos.top - height - offsetTop) + "px"; below = false; } else if (height > winH) { hints.style.height = (winH - 5) + "px"; - hints.style.top = (top = pos.bottom - box.top) + "px"; + hints.style.top = (top = pos.bottom - box.top - offsetTop) + "px"; var cursor = cm.getCursor(); if (data.from.ch != cursor.ch) { pos = cm.cursorCoords(cursor); - hints.style.left = (left = pos.left) + "px"; + hints.style.left = (left = pos.left - offsetLeft) + "px"; box = hints.getBoundingClientRect(); } } @@ -263,7 +296,7 @@ hints.style.width = (winW - 5) + "px"; overlapX -= (box.right - box.left) - winW; } - hints.style.left = (left = pos.left - overlapX) + "px"; + hints.style.left = (left = pos.left - overlapX - offsetLeft) + "px"; } if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling) node.style.paddingRight = cm.display.nativeBarWidth + "px" @@ -311,6 +344,12 @@ setTimeout(function(){cm.focus();}, 20); }); + // The first hint doesn't need to be scrolled to on init + var selectedHintRange = this.getSelectedHintRange(); + if (selectedHintRange.from !== 0 || selectedHintRange.to !== 0) { + this.scrollToActive(); + } + CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]); return true; } @@ -351,15 +390,31 @@ if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); node = this.hints.childNodes[this.selectedHint = i]; node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; - if (node.offsetTop < this.hints.scrollTop) - this.hints.scrollTop = node.offsetTop - 3; - else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) - this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; + this.scrollToActive() CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); }, + scrollToActive: function() { + var selectedHintRange = this.getSelectedHintRange(); + var node1 = this.hints.childNodes[selectedHintRange.from]; + var node2 = this.hints.childNodes[selectedHintRange.to]; + var firstNode = this.hints.firstChild; + if (node1.offsetTop < this.hints.scrollTop) + this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop; + else if (node2.offsetTop + node2.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) + this.hints.scrollTop = node2.offsetTop + node2.offsetHeight - this.hints.clientHeight + firstNode.offsetTop; + }, + screenAmount: function() { return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; + }, + + getSelectedHintRange: function() { + var margin = this.completion.options.scrollMargin || 0; + return { + from: Math.max(0, this.selectedHint - margin), + to: Math.min(this.data.list.length - 1, this.selectedHint + margin), + }; } }; @@ -437,11 +492,15 @@ completeSingle: true, alignWithWord: true, closeCharacters: /[\s()\[\]{};:>,]/, + closeOnCursorActivity: true, + closeOnPick: true, closeOnUnfocus: true, completeOnSingleClick: true, container: null, customKeys: null, - extraKeys: null + extraKeys: null, + paddingForScrollbar: true, + moveOnOverlap: true, }; CodeMirror.defineOption("hintOptions", null); diff --git a/src/lib/codemirror/addon/merge/merge.js b/src/lib/codemirror/addon/merge/merge.js index 63373f75e..827edb713 100644 --- a/src/lib/codemirror/addon/merge/merge.js +++ b/src/lib/codemirror/addon/merge/merge.js @@ -443,22 +443,26 @@ aligners[i].clear(); aligners.length = 0; - var cm = [dv.edit, dv.orig], scroll = []; + var cm = [dv.edit, dv.orig], scroll = [], offset = [] if (other) cm.push(other.orig); - for (var i = 0; i < cm.length; i++) + for (var i = 0; i < cm.length; i++) { scroll.push(cm[i].getScrollInfo().top); + offset.push(-cm[i].getScrollerElement().getBoundingClientRect().top) + } + if (offset[0] != offset[1] || cm.length == 3 && offset[1] != offset[2]) + alignLines(cm, offset, [0, 0, 0], aligners) for (var ln = 0; ln < linesToAlign.length; ln++) - alignLines(cm, linesToAlign[ln], aligners); + alignLines(cm, offset, linesToAlign[ln], aligners); for (var i = 0; i < cm.length; i++) cm[i].scrollTo(null, scroll[i]); } - function alignLines(cm, lines, aligners) { - var maxOffset = 0, offset = []; + function alignLines(cm, cmOffset, lines, aligners) { + var maxOffset = -1e8, offset = []; for (var i = 0; i < cm.length; i++) if (lines[i] != null) { - var off = cm[i].heightAtLine(lines[i], "local"); + var off = cm[i].heightAtLine(lines[i], "local") - cmOffset[i]; offset[i] = off; maxOffset = Math.max(maxOffset, off); } @@ -918,7 +922,7 @@ hasMarker: function(n) { var handle = this.cm.getLineHandle(n) if (handle.markedSpans) for (var i = 0; i < handle.markedSpans.length; i++) - if (handle.markedSpans[i].mark.collapsed && handle.markedSpans[i].to != null) + if (handle.markedSpans[i].marker.collapsed && handle.markedSpans[i].to != null) return true return false }, diff --git a/src/lib/codemirror/addon/scroll/annotatescrollbar.js b/src/lib/codemirror/addon/scroll/annotatescrollbar.js index 356625811..c12e44cda 100644 --- a/src/lib/codemirror/addon/scroll/annotatescrollbar.js +++ b/src/lib/codemirror/addon/scroll/annotatescrollbar.js @@ -43,7 +43,7 @@ cm.on("markerAdded", this.resizeHandler); cm.on("markerCleared", this.resizeHandler); if (options.listenForChanges !== false) - cm.on("change", this.changeHandler = function() { + cm.on("changes", this.changeHandler = function() { scheduleRedraw(250); }); } @@ -72,10 +72,16 @@ var wrapping = cm.getOption("lineWrapping"); var singleLineH = wrapping && cm.defaultTextHeight() * 1.5; var curLine = null, curLineObj = null; + function getY(pos, top) { if (curLine != pos.line) { - curLine = pos.line; - curLineObj = cm.getLineHandle(curLine); + curLine = pos.line + curLineObj = cm.getLineHandle(pos.line) + var visual = cm.getLineHandleVisualStart(curLineObj) + if (visual != curLineObj) { + curLine = cm.getLineNumber(visual) + curLineObj = visual + } } if ((curLineObj.widgets && curLineObj.widgets.length) || (wrapping && curLineObj.height > singleLineH)) @@ -116,7 +122,7 @@ this.cm.off("refresh", this.resizeHandler); this.cm.off("markerAdded", this.resizeHandler); this.cm.off("markerCleared", this.resizeHandler); - if (this.changeHandler) this.cm.off("change", this.changeHandler); + if (this.changeHandler) this.cm.off("changes", this.changeHandler); this.div.parentNode.removeChild(this.div); }; }); diff --git a/src/lib/codemirror/addon/search/searchcursor.js b/src/lib/codemirror/addon/search/searchcursor.js index aae36dfe5..d58695788 100644 --- a/src/lib/codemirror/addon/search/searchcursor.js +++ b/src/lib/codemirror/addon/search/searchcursor.js @@ -72,24 +72,26 @@ } } - function lastMatchIn(string, regexp) { - var cutOff = 0, match - for (;;) { - regexp.lastIndex = cutOff + function lastMatchIn(string, regexp, endMargin) { + var match, from = 0 + while (from <= string.length) { + regexp.lastIndex = from var newMatch = regexp.exec(string) - if (!newMatch) return match - match = newMatch - cutOff = match.index + (match[0].length || 1) - if (cutOff == string.length) return match + if (!newMatch) break + var end = newMatch.index + newMatch[0].length + if (end > string.length - endMargin) break + if (!match || end > match.index + match[0].length) + match = newMatch + from = newMatch.index + 1 } + return match } function searchRegexpBackward(doc, regexp, start) { regexp = ensureFlags(regexp, "g") for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) { var string = doc.getLine(line) - if (ch > -1) string = string.slice(0, ch) - var match = lastMatchIn(string, regexp) + var match = lastMatchIn(string, regexp, ch < 0 ? 0 : string.length - ch) if (match) return {from: Pos(line, match.index), to: Pos(line, match.index + match[0].length), @@ -98,16 +100,17 @@ } function searchRegexpBackwardMultiline(doc, regexp, start) { + if (!maybeMultiline(regexp)) return searchRegexpBackward(doc, regexp, start) regexp = ensureFlags(regexp, "gm") - var string, chunk = 1 + var string, chunkSize = 1, endMargin = doc.getLine(start.line).length - start.ch for (var line = start.line, first = doc.firstLine(); line >= first;) { - for (var i = 0; i < chunk; i++) { + for (var i = 0; i < chunkSize && line >= first; i++) { var curLine = doc.getLine(line--) - string = string == null ? curLine.slice(0, start.ch) : curLine + "\n" + string + string = string == null ? curLine : curLine + "\n" + string } - chunk *= 2 + chunkSize *= 2 - var match = lastMatchIn(string, regexp) + var match = lastMatchIn(string, regexp, endMargin) if (match) { var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n") var startLine = line + before.length, startCh = before[before.length - 1].length @@ -237,7 +240,7 @@ var result = this.matches(reverse, this.doc.clipPos(reverse ? this.pos.from : this.pos.to)) // Implements weird auto-growing behavior on null-matches for - // backwards-compatiblity with the vim code (unfortunately) + // backwards-compatibility with the vim code (unfortunately) while (result && CodeMirror.cmpPos(result.from, result.to) == 0) { if (reverse) { if (result.from.ch) result.from = Pos(result.from.line, result.from.ch - 1) diff --git a/src/lib/codemirror/lib/codemirror.css b/src/lib/codemirror/lib/codemirror.css index c7a8ae704..5ea2d2be2 100644 --- a/src/lib/codemirror/lib/codemirror.css +++ b/src/lib/codemirror/lib/codemirror.css @@ -13,12 +13,13 @@ .CodeMirror-lines { padding: 4px 0; /* Vertical padding around content */ } -.CodeMirror pre { +.CodeMirror pre.CodeMirror-line, +.CodeMirror pre.CodeMirror-line-like { padding: 0 4px; /* Horizontal padding of content */ } .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { - background-color: white; /* The little square between H and V scrollbars */ + background-color: transparent; /* The little square between H and V scrollbars */ } /* GUTTER */ @@ -96,7 +97,7 @@ .CodeMirror-rulers { position: absolute; - left: 0; right: 0; top: -50px; bottom: -20px; + left: 0; right: 0; top: -50px; bottom: 0; overflow: hidden; } .CodeMirror-ruler { @@ -163,17 +164,17 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} .CodeMirror-scroll { overflow: scroll !important; /* Things will break if this is overridden */ - /* 30px is the magic margin used to hide the element's real scrollbars */ + /* 50px is the magic margin used to hide the element's real scrollbars */ /* See overflow: hidden in .CodeMirror */ - margin-bottom: -30px; margin-right: -30px; - padding-bottom: 30px; + margin-bottom: -50px; margin-right: -50px; + padding-bottom: 50px; height: 100%; outline: none; /* Prevent dragging from highlighting the element */ position: relative; } .CodeMirror-sizer { position: relative; - border-right: 30px solid transparent; + border-right: 50px solid transparent; } /* The fake, visible scrollbars. Used to force redraw during scrolling @@ -183,6 +184,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} position: absolute; z-index: 6; display: none; + outline: none; } .CodeMirror-vscrollbar { right: 0; top: 0; @@ -211,7 +213,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} height: 100%; display: inline-block; vertical-align: top; - margin-bottom: -30px; + margin-bottom: -50px; } .CodeMirror-gutter-wrapper { position: absolute; @@ -236,7 +238,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} cursor: text; min-height: 1px; /* prevents collapsing before first draw */ } -.CodeMirror pre { +.CodeMirror pre.CodeMirror-line, +.CodeMirror pre.CodeMirror-line-like { /* Reset some styles that the rest of the page might have set */ -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; border-width: 0; @@ -255,7 +258,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} -webkit-font-variant-ligatures: contextual; font-variant-ligatures: contextual; } -.CodeMirror-wrap pre { +.CodeMirror-wrap pre.CodeMirror-line, +.CodeMirror-wrap pre.CodeMirror-line-like { word-wrap: break-word; white-space: pre-wrap; word-break: normal; diff --git a/src/lib/codemirror/lib/codemirror.js b/src/lib/codemirror/lib/codemirror.js index 6d8bd9f28..cb2186789 100644 --- a/src/lib/codemirror/lib/codemirror.js +++ b/src/lib/codemirror/lib/codemirror.js @@ -10,7 +10,7 @@ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : - (global.CodeMirror = factory()); + (global = global || self, global.CodeMirror = factory()); }(this, (function () { 'use strict'; // Kludges for bugs and behavior differences that can't be feature @@ -32,7 +32,7 @@ var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent); var phantom = /PhantomJS/.test(userAgent); - var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent); + var ios = !edge && /AppleWebKit/.test(userAgent) && (/Mobile\/\w+/.test(userAgent) || navigator.maxTouchPoints > 2); var android = /Android/.test(userAgent); // This is woefully incomplete. Suggestions for alternative methods welcome. var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent); @@ -173,10 +173,28 @@ } } - var Delayed = function() {this.id = null;}; + var Delayed = function() { + this.id = null; + this.f = null; + this.time = 0; + this.handler = bind(this.onTimeout, this); + }; + Delayed.prototype.onTimeout = function (self) { + self.id = 0; + if (self.time <= +new Date) { + self.f(); + } else { + setTimeout(self.handler, self.time - +new Date); + } + }; Delayed.prototype.set = function (ms, f) { - clearTimeout(this.id); - this.id = setTimeout(f, ms); + this.f = f; + var time = +new Date + ms; + if (!this.id || time < this.time) { + clearTimeout(this.id); + this.id = setTimeout(this.handler, ms); + this.time = time; + } }; function indexOf(array, elt) { @@ -186,7 +204,7 @@ } // Number of pixels added to scroller and sizer to hide scrollbar - var scrollerGap = 30; + var scrollerGap = 50; // Returned or thrown by various protocols to signal 'I'm not // handling this'. @@ -467,14 +485,15 @@ for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {} order.push(new BidiSpan(0, start, i$7)); } else { - var pos = i$7, at = order.length; + var pos = i$7, at = order.length, isRTL = direction == "rtl" ? 1 : 0; for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {} for (var j$2 = pos; j$2 < i$7;) { if (countsAsNum.test(types[j$2])) { - if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); } + if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); at += isRTL; } var nstart = j$2; for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {} order.splice(at, 0, new BidiSpan(2, nstart, j$2)); + at += isRTL; pos = j$2; } else { ++j$2; } } @@ -518,8 +537,8 @@ } else if (emitter.attachEvent) { emitter.attachEvent("on" + type, f); } else { - var map$$1 = emitter._handlers || (emitter._handlers = {}); - map$$1[type] = (map$$1[type] || noHandlers).concat(f); + var map = emitter._handlers || (emitter._handlers = {}); + map[type] = (map[type] || noHandlers).concat(f); } }; @@ -533,11 +552,11 @@ } else if (emitter.detachEvent) { emitter.detachEvent("on" + type, f); } else { - var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type]; + var map = emitter._handlers, arr = map && map[type]; if (arr) { var index = indexOf(arr, f); if (index > -1) - { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); } + { map[type] = arr.slice(0, index).concat(arr.slice(index + 1)); } } } } @@ -665,11 +684,11 @@ try { return te.selectionStart != te.selectionEnd } catch(e) { return false } } : function (te) { - var range$$1; - try {range$$1 = te.ownerDocument.selection.createRange();} + var range; + try {range = te.ownerDocument.selection.createRange();} catch(e) {} - if (!range$$1 || range$$1.parentElement() != te) { return false } - return range$$1.compareEndPoints("StartToEnd", range$$1) != 0 + if (!range || range.parentElement() != te) { return false } + return range.compareEndPoints("StartToEnd", range) != 0 }; var hasCopyEvent = (function () { @@ -817,10 +836,8 @@ return this.pos > start }; StringStream.prototype.eatSpace = function () { - var this$1 = this; - var start = this.pos; - while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; } + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; } return this.pos > start }; StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;}; @@ -1016,11 +1033,9 @@ }; Context.prototype.baseToken = function (n) { - var this$1 = this; - if (!this.baseTokens) { return null } while (this.baseTokens[this.baseTokenPos] <= n) - { this$1.baseTokenPos += 2; } + { this.baseTokenPos += 2; } var type = this.baseTokens[this.baseTokenPos + 1]; return {type: type && type.replace(/( |^)overlay .*/, ""), size: this.baseTokens[this.baseTokenPos] - n} @@ -1186,7 +1201,7 @@ var prop = lineClass[1] ? "bgClass" : "textClass"; if (output[prop] == null) { output[prop] = lineClass[2]; } - else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) + else if (!(new RegExp("(?:^|\\s)" + lineClass[2] + "(?:$|\\s)")).test(output[prop])) { output[prop] += " " + lineClass[2]; } } } return type @@ -1509,8 +1524,8 @@ // Test whether there exists a collapsed span that partially // overlaps (covers the start or end, but not both) of a new span. // Such overlap is not allowed. - function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) { - var line = getLine(doc, lineNo$$1); + function conflictingCollapsedRange(doc, lineNo, from, to, marker) { + var line = getLine(doc, lineNo); var sps = sawCollapsedSpans && line.markedSpans; if (sps) { for (var i = 0; i < sps.length; ++i) { var sp = sps[i]; @@ -1826,7 +1841,7 @@ } } builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32; - if (style || startStyle || endStyle || mustWrap || css) { + if (style || startStyle || endStyle || mustWrap || css || attributes) { var fullStyle = style || ""; if (startStyle) { fullStyle += startStyle; } if (endStyle) { fullStyle += endStyle; } @@ -2191,10 +2206,10 @@ function updateLineWidgets(cm, lineView, dims) { if (lineView.alignable) { lineView.alignable = null; } + var isWidget = classTest("CodeMirror-linewidget"); for (var node = lineView.node.firstChild, next = (void 0); node; node = next) { next = node.nextSibling; - if (node.className == "CodeMirror-linewidget") - { lineView.node.removeChild(node); } + if (isWidget.test(node.className)) { lineView.node.removeChild(node); } } insertLineWidgets(cm, lineView, dims); } @@ -2224,7 +2239,7 @@ if (!line.widgets) { return } var wrap = ensureLineWrapped(lineView); for (var i = 0, ws = line.widgets; i < ws.length; ++i) { - var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget" + (widget.className ? " " + widget.className : "")); if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); } positionLineWidget(widget, node, lineView, dims); cm.display.input.setUneditable(node); @@ -2284,7 +2299,7 @@ function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight} function paddingH(display) { if (display.cachedPaddingH) { return display.cachedPaddingH } - var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); + var e = removeChildrenAndAdd(display.measure, elt("pre", "x", "CodeMirror-line-like")); var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; } @@ -2412,36 +2427,36 @@ var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; - function nodeAndOffsetInLineMap(map$$1, ch, bias) { + function nodeAndOffsetInLineMap(map, ch, bias) { var node, start, end, collapse, mStart, mEnd; // First, search the line map for the text node corresponding to, // or closest to, the target character. - for (var i = 0; i < map$$1.length; i += 3) { - mStart = map$$1[i]; - mEnd = map$$1[i + 1]; + for (var i = 0; i < map.length; i += 3) { + mStart = map[i]; + mEnd = map[i + 1]; if (ch < mStart) { start = 0; end = 1; collapse = "left"; } else if (ch < mEnd) { start = ch - mStart; end = start + 1; - } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) { + } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { end = mEnd - mStart; start = end - 1; if (ch >= mEnd) { collapse = "right"; } } if (start != null) { - node = map$$1[i + 2]; + node = map[i + 2]; if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) { collapse = bias; } if (bias == "left" && start == 0) - { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) { - node = map$$1[(i -= 3) + 2]; + { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { + node = map[(i -= 3) + 2]; collapse = "left"; } } if (bias == "right" && start == mEnd - mStart) - { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) { - node = map$$1[(i += 3) + 2]; + { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { + node = map[(i += 3) + 2]; collapse = "right"; } } break @@ -2678,7 +2693,7 @@ function PosWithInfo(line, ch, sticky, outside, xRel) { var pos = Pos(line, ch, sticky); pos.xRel = xRel; - if (outside) { pos.outside = true; } + if (outside) { pos.outside = outside; } return pos } @@ -2687,16 +2702,16 @@ function coordsChar(cm, x, y) { var doc = cm.doc; y += cm.display.viewOffset; - if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) } + if (y < 0) { return PosWithInfo(doc.first, 0, null, -1, -1) } var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; if (lineN > last) - { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) } + { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, 1, 1) } if (x < 0) { x = 0; } var lineObj = getLine(doc, lineN); for (;;) { var found = coordsCharInner(cm, lineObj, lineN, x, y); - var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 ? 1 : 0)); + var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 || found.outside > 0 ? 1 : 0)); if (!collapsed) { return found } var rangeEnd = collapsed.find(1); if (rangeEnd.line == lineN) { return rangeEnd } @@ -2724,13 +2739,13 @@ return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x } - function coordsCharInner(cm, lineObj, lineNo$$1, x, y) { + function coordsCharInner(cm, lineObj, lineNo, x, y) { // Move y into line-local coordinate space y -= heightAtLine(lineObj); var preparedMeasure = prepareMeasureForLine(cm, lineObj); // When directly calling `measureCharPrepared`, we have to adjust // for the widgets at this line. - var widgetHeight$$1 = widgetTopHeight(lineObj); + var widgetHeight = widgetTopHeight(lineObj); var begin = 0, end = lineObj.text.length, ltr = true; var order = getOrder(lineObj, cm.doc.direction); @@ -2738,7 +2753,7 @@ // which bidi section the coordinates fall into. if (order) { var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart) - (cm, lineObj, lineNo$$1, preparedMeasure, order, x, y); + (cm, lineObj, lineNo, preparedMeasure, order, x, y); ltr = part.level != 1; // The awkward -1 offsets are needed because findFirst (called // on these below) will treat its first bound as inclusive, @@ -2754,7 +2769,7 @@ var chAround = null, boxAround = null; var ch = findFirst(function (ch) { var box = measureCharPrepared(cm, preparedMeasure, ch); - box.top += widgetHeight$$1; box.bottom += widgetHeight$$1; + box.top += widgetHeight; box.bottom += widgetHeight; if (!boxIsAfter(box, x, y, false)) { return false } if (box.top <= y && box.left <= x) { chAround = ch; @@ -2778,27 +2793,27 @@ // left of the character and compare it's vertical position to the // coordinates sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" : - (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ? + (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight <= y) == ltr ? "after" : "before"; // Now get accurate coordinates for this place, in order to get a // base X position - var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), "line", lineObj, preparedMeasure); + var coords = cursorCoords(cm, Pos(lineNo, ch, sticky), "line", lineObj, preparedMeasure); baseX = coords.left; - outside = y < coords.top || y >= coords.bottom; + outside = y < coords.top ? -1 : y >= coords.bottom ? 1 : 0; } ch = skipExtendingChars(lineObj.text, ch, 1); - return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX) + return PosWithInfo(lineNo, ch, sticky, outside, x - baseX) } - function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) { + function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) { // Bidi parts are sorted left-to-right, and in a non-line-wrapping // situation, we can take this ordering to correspond to the visual // ordering. This finds the first part whose end is after the given // coordinates. var index = findFirst(function (i) { var part = order[i], ltr = part.level != 1; - return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? "before" : "after"), + return boxIsAfter(cursorCoords(cm, Pos(lineNo, ltr ? part.to : part.from, ltr ? "before" : "after"), "line", lineObj, preparedMeasure), x, y, true) }, 0, order.length - 1); var part = order[index]; @@ -2807,7 +2822,7 @@ // that start, move one part back. if (index > 0) { var ltr = part.level != 1; - var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? "after" : "before"), + var start = cursorCoords(cm, Pos(lineNo, ltr ? part.from : part.to, ltr ? "after" : "before"), "line", lineObj, preparedMeasure); if (boxIsAfter(start, x, y, true) && start.top > y) { part = order[index - 1]; } @@ -2853,7 +2868,7 @@ function textHeight(display) { if (display.cachedTextHeight != null) { return display.cachedTextHeight } if (measureText == null) { - measureText = elt("pre"); + measureText = elt("pre", null, "CodeMirror-line-like"); // Measure a bunch of lines, for browsers that compute // fractional heights. for (var i = 0; i < 49; ++i) { @@ -2873,7 +2888,7 @@ function charWidth(display) { if (display.cachedCharWidth != null) { return display.cachedCharWidth } var anchor = elt("span", "xxxxxxxxxx"); - var pre = elt("pre", [anchor]); + var pre = elt("pre", [anchor], "CodeMirror-line-like"); removeChildrenAndAdd(display.measure, pre); var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; if (width > 2) { display.cachedCharWidth = width; } @@ -2945,9 +2960,9 @@ var x, y, space = display.lineSpace.getBoundingClientRect(); // Fails unpredictably on IE[67] when mouse is dragged around quickly. try { x = e.clientX - space.left; y = e.clientY - space.top; } - catch (e) { return null } + catch (e$1) { return null } var coords = coordsChar(cm, x, y), line; - if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { + if (forRect && coords.xRel > 0 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); } @@ -3128,13 +3143,13 @@ for (var i = 0; i < doc.sel.ranges.length; i++) { if (!primary && i == doc.sel.primIndex) { continue } - var range$$1 = doc.sel.ranges[i]; - if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue } - var collapsed = range$$1.empty(); + 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$$1.head, curFragment); } + { drawSelectionCursor(cm, range.head, curFragment); } if (!collapsed) - { drawSelectionRange(cm, range$$1, selFragment); } + { drawSelectionRange(cm, range, selFragment); } } return result } @@ -3161,7 +3176,7 @@ function cmpCoords(a, b) { return a.top - b.top || a.left - b.left } // Draws the given range as a highlighted selection - function drawSelectionRange(cm, range$$1, output) { + function drawSelectionRange(cm, range, output) { var display = cm.display, doc = cm.doc; var fragment = document.createDocumentFragment(); var padding = paddingH(cm.display), leftSide = padding.left; @@ -3230,7 +3245,7 @@ return {start: start, end: end} } - var sFrom = range$$1.from(), sTo = range$$1.to(); + var sFrom = range.from(), sTo = range.to(); if (sFrom.line == sTo.line) { drawForLine(sFrom.line, sFrom.ch, sTo.ch); } else { @@ -3261,26 +3276,31 @@ var on = true; display.cursorDiv.style.visibility = ""; if (cm.options.cursorBlinkRate > 0) - { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; }, - cm.options.cursorBlinkRate); } + { display.blinker = setInterval(function () { + if (!cm.hasFocus()) { onBlur(cm); } + display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; + }, cm.options.cursorBlinkRate); } else if (cm.options.cursorBlinkRate < 0) { display.cursorDiv.style.visibility = "hidden"; } } function ensureFocus(cm) { - if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } + if (!cm.hasFocus()) { + cm.display.input.focus(); + if (!cm.state.focused) { onFocus(cm); } + } } function delayBlurEvent(cm) { cm.state.delayingBlurEvent = true; setTimeout(function () { if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; - onBlur(cm); + if (cm.state.focused) { onBlur(cm); } } }, 100); } function onFocus(cm, e) { - if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; } + if (cm.state.delayingBlurEvent && !cm.state.draggingText) { cm.state.delayingBlurEvent = false; } if (cm.options.readOnly == "nocursor") { return } if (!cm.state.focused) { @@ -3462,14 +3482,15 @@ if (newTop != screentop) { result.scrollTop = newTop; } } - var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; - var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); + var gutterSpace = cm.options.fixedGutter ? 0 : display.gutters.offsetWidth; + var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft - gutterSpace; + var screenw = displayWidth(cm) - display.gutters.offsetWidth; var tooWide = rect.right - rect.left > screenw; if (tooWide) { rect.right = rect.left + screenw; } if (rect.left < 10) { result.scrollLeft = 0; } else if (rect.left < screenleft) - { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); } + { result.scrollLeft = Math.max(0, rect.left + gutterSpace - (tooWide ? 0 : 10)); } else if (rect.right > screenw + screenleft - 3) { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; } return result @@ -3497,9 +3518,9 @@ if (y != null) { cm.curOp.scrollTop = y; } } - function scrollToRange(cm, range$$1) { + function scrollToRange(cm, range) { resolveScrollToPos(cm); - cm.curOp.scrollToPos = range$$1; + cm.curOp.scrollToPos = range; } // When an operation has its scrollToPos property set, and another @@ -3507,11 +3528,11 @@ // 'simulates' scrolling that position into view in a cheap way, so // that the effect of intermediate scroll commands is not ignored. function resolveScrollToPos(cm) { - var range$$1 = cm.curOp.scrollToPos; - if (range$$1) { + var range = cm.curOp.scrollToPos; + if (range) { cm.curOp.scrollToPos = null; - var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to); - scrollToCoordsRange(cm, from, to, range$$1.margin); + var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); + scrollToCoordsRange(cm, from, to, range.margin); } } @@ -3536,7 +3557,7 @@ } function setScrollTop(cm, val, forceScroll) { - val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val); + val = Math.max(0, Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val)); if (cm.display.scroller.scrollTop == val && !forceScroll) { return } cm.doc.scrollTop = val; cm.display.scrollbars.setScrollTop(val); @@ -3546,7 +3567,7 @@ // Sync scroller and scrollbar, ensure the gutter elements are // aligned. function setScrollLeft(cm, val, isScroller, forceScroll) { - val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); + val = Math.max(0, Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth)); if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return } cm.doc.scrollLeft = val; alignHorizontally(cm); @@ -3658,9 +3679,9 @@ // (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$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2) + var elt = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2) : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1); - if (elt$$1 != bar) { bar.style.pointerEvents = "none"; } + if (elt != bar) { bar.style.pointerEvents = "none"; } else { delay.set(1000, maybeDisable); } } delay.set(1000, maybeDisable); @@ -4000,10 +4021,8 @@ { this.events.push(arguments); } }; DisplayUpdate.prototype.finish = function () { - var this$1 = this; - for (var i = 0; i < this.events.length; i++) - { signal.apply(null, this$1.events[i]); } + { signal.apply(null, this.events[i]); } }; function maybeClipScrollbars(cm) { @@ -4037,12 +4056,13 @@ function restoreSelection(snapshot) { if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return } snapshot.activeElt.focus(); - if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) { - var sel = window.getSelection(), range$$1 = document.createRange(); - range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset); - range$$1.collapse(false); + if (!/^(INPUT|TEXTAREA)$/.test(snapshot.activeElt.nodeName) && + snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) { + var sel = window.getSelection(), range = document.createRange(); + range.setEnd(snapshot.anchorNode, snapshot.anchorOffset); + range.collapse(false); sel.removeAllRanges(); - sel.addRange(range$$1); + sel.addRange(range); sel.extend(snapshot.focusNode, snapshot.focusOffset); } } @@ -4135,6 +4155,8 @@ update.visible = visibleLines(cm.display, cm.doc, viewport); if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) { break } + } else if (first) { + update.visible = visibleLines(cm.display, cm.doc, viewport); } if (!updateDisplayIfNeeded(cm, update)) { break } updateHeightsInViewport(cm); @@ -4535,40 +4557,32 @@ Selection.prototype.primary = function () { return this.ranges[this.primIndex] }; Selection.prototype.equals = function (other) { - var this$1 = this; - if (other == this) { return true } if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false } for (var i = 0; i < this.ranges.length; i++) { - var here = this$1.ranges[i], there = other.ranges[i]; + var here = this.ranges[i], there = other.ranges[i]; if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false } } return true }; Selection.prototype.deepCopy = function () { - var this$1 = this; - var out = []; for (var i = 0; i < this.ranges.length; i++) - { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); } + { out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); } return new Selection(out, this.primIndex) }; Selection.prototype.somethingSelected = function () { - var this$1 = this; - for (var i = 0; i < this.ranges.length; i++) - { if (!this$1.ranges[i].empty()) { return true } } + { if (!this.ranges[i].empty()) { return true } } return false }; Selection.prototype.contains = function (pos, end) { - var this$1 = this; - if (!end) { end = pos; } for (var i = 0; i < this.ranges.length; i++) { - var range = this$1.ranges[i]; + var range = this.ranges[i]; if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) { return i } } @@ -4694,16 +4708,16 @@ } // Perform a change on the document data structure. - function updateDoc(doc, change, markedSpans, estimateHeight$$1) { + function updateDoc(doc, change, markedSpans, estimateHeight) { function spansFor(n) {return markedSpans ? markedSpans[n] : null} function update(line, text, spans) { - updateLine(line, text, spans, estimateHeight$$1); + updateLine(line, text, spans, estimateHeight); signalLater(line, "change", line, change); } function linesFor(start, end) { var result = []; for (var i = start; i < end; ++i) - { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); } + { result.push(new Line(text[i], spansFor(i), estimateHeight)); } return result } @@ -4727,7 +4741,7 @@ update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); } else { var added$1 = linesFor(1, text.length - 1); - added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1)); + added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); doc.insert(from.line + 1, added$1); } @@ -5064,11 +5078,9 @@ var obj = { ranges: sel.ranges, update: function(ranges) { - var this$1 = this; - this.ranges = []; for (var i = 0; i < ranges.length; i++) - { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), + { this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), clipPos(doc, ranges[i].head)); } }, origin: options && options.origin @@ -5147,8 +5159,15 @@ 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))) { + + // Determine if we should prevent the cursor being placed to the left/right of an atomic marker + // Historically this was determined using the inclusiveLeft/Right option, but the new way to control it + // is with selectLeft/Right + var preventCursorLeft = ("selectLeft" in m) ? !m.selectLeft : m.inclusiveLeft; + var preventCursorRight = ("selectRight" in m) ? !m.selectRight : m.inclusiveRight; + + if ((sp.from == null || (preventCursorLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && + (sp.to == null || (preventCursorRight ? sp.to >= pos.ch : sp.to > pos.ch))) { if (mayClear) { signal(m, "beforeCursorEnter"); if (m.explicitlyCleared) { @@ -5160,14 +5179,14 @@ if (oldPos) { var near = m.find(dir < 0 ? 1 : -1), diff = (void 0); - if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) + if (dir < 0 ? preventCursorRight : preventCursorLeft) { 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) + if (dir < 0 ? preventCursorLeft : preventCursorRight) { far = movePos(doc, far, dir, far.line == pos.line ? line : null); } return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null } @@ -5396,6 +5415,9 @@ if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); } else { updateDoc(doc, change, spans); } setSelectionNoUndo(doc, selAfter, sel_dontScroll); + + if (doc.cantEdit && skipAtomic(doc, Pos(doc.firstLine(), 0))) + { doc.cantEdit = false; } } // Handle the interaction of a change to a document with the editor @@ -5545,13 +5567,11 @@ // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html function LeafChunk(lines) { - var this$1 = this; - this.lines = lines; this.parent = null; var height = 0; for (var i = 0; i < lines.length; ++i) { - lines[i].parent = this$1; + lines[i].parent = this; height += lines[i].height; } this.height = height; @@ -5562,11 +5582,9 @@ // Remove the n lines at offset 'at'. removeInner: function(at, n) { - var this$1 = this; - for (var i = at, e = at + n; i < e; ++i) { - var line = this$1.lines[i]; - this$1.height -= line.height; + var line = this.lines[i]; + this.height -= line.height; cleanUpLine(line); signalLater(line, "delete"); } @@ -5581,31 +5599,25 @@ // Insert the given array of lines at offset 'at', count them as // having the given height. insertInner: function(at, lines, height) { - var this$1 = this; - this.height += height; this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); - for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; } + for (var i = 0; i < lines.length; ++i) { lines[i].parent = this; } }, // Used to iterate over a part of the tree. iterN: function(at, n, op) { - var this$1 = this; - for (var e = at + n; at < e; ++at) - { if (op(this$1.lines[at])) { return true } } + { if (op(this.lines[at])) { return true } } } }; function BranchChunk(children) { - var this$1 = this; - this.children = children; var size = 0, height = 0; for (var i = 0; i < children.length; ++i) { var ch = children[i]; size += ch.chunkSize(); height += ch.height; - ch.parent = this$1; + ch.parent = this; } this.size = size; this.height = height; @@ -5616,16 +5628,14 @@ chunkSize: function() { return this.size }, removeInner: function(at, n) { - var this$1 = this; - this.size -= n; for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize(); + var child = this.children[i], sz = child.chunkSize(); if (at < sz) { var rm = Math.min(n, sz - at), oldHeight = child.height; child.removeInner(at, rm); - this$1.height -= oldHeight - child.height; - if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; } + this.height -= oldHeight - child.height; + if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } if ((n -= rm) == 0) { break } at = 0; } else { at -= sz; } @@ -5642,18 +5652,14 @@ }, collapse: function(lines) { - var this$1 = this; - - for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); } + for (var i = 0; i < this.children.length; ++i) { this.children[i].collapse(lines); } }, insertInner: function(at, lines, height) { - var this$1 = this; - this.size += lines.length; this.height += height; for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize(); + var child = this.children[i], sz = child.chunkSize(); if (at <= sz) { child.insertInner(at, lines, height); if (child.lines && child.lines.length > 50) { @@ -5663,11 +5669,11 @@ for (var pos = remaining; pos < child.lines.length;) { var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)); child.height -= leaf.height; - this$1.children.splice(++i, 0, leaf); - leaf.parent = this$1; + this.children.splice(++i, 0, leaf); + leaf.parent = this; } child.lines = child.lines.slice(0, remaining); - this$1.maybeSpill(); + this.maybeSpill(); } break } @@ -5699,10 +5705,8 @@ }, iterN: function(at, n, op) { - var this$1 = this; - for (var i = 0; i < this.children.length; ++i) { - var child = this$1.children[i], sz = child.chunkSize(); + var child = this.children[i], sz = child.chunkSize(); if (at < sz) { var used = Math.min(n, sz - at); if (child.iterN(at, used, op)) { return true } @@ -5716,20 +5720,16 @@ // Line widgets are block elements displayed above or below a line. var LineWidget = function(doc, node, options) { - var this$1 = this; - if (options) { for (var opt in options) { if (options.hasOwnProperty(opt)) - { this$1[opt] = options[opt]; } } } + { this[opt] = options[opt]; } } } this.doc = doc; this.node = node; }; LineWidget.prototype.clear = function () { - var this$1 = this; - var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); if (no == null || !ws) { return } - for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } } + for (var i = 0; i < ws.length; ++i) { if (ws[i] == this) { ws.splice(i--, 1); } } if (!ws.length) { line.widgets = null; } var height = widgetHeight(this); updateLineHeight(line, Math.max(0, line.height - height)); @@ -5772,7 +5772,7 @@ changeLine(doc, handle, "widget", function (line) { var widgets = line.widgets || (line.widgets = []); if (widget.insertAt == null) { widgets.push(widget); } - else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); } + else { widgets.splice(Math.min(widgets.length, Math.max(0, widget.insertAt)), 0, widget); } widget.line = line; if (cm && !lineIsHidden(doc, line)) { var aboveVisible = heightAtLine(line) < doc.scrollTop; @@ -5812,8 +5812,6 @@ // Clear the marker. TextMarker.prototype.clear = function () { - var this$1 = this; - if (this.explicitlyCleared) { return } var cm = this.doc.cm, withOp = cm && !cm.curOp; if (withOp) { startOperation(cm); } @@ -5823,19 +5821,19 @@ } var min = null, max = null; for (var i = 0; i < this.lines.length; ++i) { - var line = this$1.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this$1); - if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text"); } + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (cm && !this.collapsed) { regLineChange(cm, lineNo(line), "text"); } else if (cm) { if (span.to != null) { max = lineNo(line); } if (span.from != null) { min = lineNo(line); } } line.markedSpans = removeMarkedSpan(line.markedSpans, span); - if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm) + if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) { updateLineHeight(line, textHeight(cm.display)); } } if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) { - var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual); + var visual = visualLine(this.lines[i$1]), len = lineLength(visual); if (len > cm.display.maxLineLength) { cm.display.maxLine = visual; cm.display.maxLineLength = len; @@ -5861,13 +5859,11 @@ // Pos objects returned contain a line object, rather than a line // number (used to prevent looking up the same line twice). TextMarker.prototype.find = function (side, lineObj) { - var this$1 = this; - if (side == null && this.type == "bookmark") { side = 1; } var from, to; for (var i = 0; i < this.lines.length; ++i) { - var line = this$1.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this$1); + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); if (span.from != null) { from = Pos(lineObj ? line : lineNo(line), span.from); if (side == -1) { return from } @@ -6001,21 +5997,17 @@ // implemented as a meta-marker-object controlling multiple normal // markers. var SharedTextMarker = function(markers, primary) { - var this$1 = this; - this.markers = markers; this.primary = primary; for (var i = 0; i < markers.length; ++i) - { markers[i].parent = this$1; } + { markers[i].parent = this; } }; SharedTextMarker.prototype.clear = function () { - var this$1 = this; - if (this.explicitlyCleared) { return } this.explicitlyCleared = true; for (var i = 0; i < this.markers.length; ++i) - { this$1.markers[i].clear(); } + { this.markers[i].clear(); } signalLater(this, "clear"); }; @@ -6158,11 +6150,11 @@ clipPos: function(pos) {return clipPos(this, pos)}, getCursor: function(start) { - var range$$1 = this.sel.primary(), pos; - if (start == null || start == "head") { pos = range$$1.head; } - else if (start == "anchor") { pos = range$$1.anchor; } - else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); } - else { pos = range$$1.from(); } + var range = this.sel.primary(), pos; + if (start == null || start == "head") { pos = range.head; } + else if (start == "anchor") { pos = range.anchor; } + else if (start == "end" || start == "to" || start === false) { pos = range.to(); } + else { pos = range.from(); } return pos }, listSelections: function() { return this.sel.ranges }, @@ -6185,13 +6177,11 @@ extendSelections(this, clipPosArray(this, heads), options); }), setSelections: docMethodOp(function(ranges, primary, options) { - var this$1 = this; - if (!ranges.length) { return } var out = []; for (var i = 0; i < ranges.length; i++) - { out[i] = new Range(clipPos(this$1, ranges[i].anchor), - clipPos(this$1, ranges[i].head)); } + { out[i] = new Range(clipPos(this, ranges[i].anchor), + clipPos(this, ranges[i].head)); } if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); } setSelection(this, normalizeSelection(this.cm, out, primary), options); }), @@ -6202,23 +6192,19 @@ }), getSelection: function(lineSep) { - var this$1 = this; - var ranges = this.sel.ranges, lines; for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()); + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); lines = lines ? lines.concat(sel) : sel; } if (lineSep === false) { return lines } else { return lines.join(lineSep || this.lineSeparator()) } }, getSelections: function(lineSep) { - var this$1 = this; - var parts = [], ranges = this.sel.ranges; for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()); - if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); } + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + if (lineSep !== false) { sel = sel.join(lineSep || this.lineSeparator()); } parts[i] = sel; } return parts @@ -6230,16 +6216,14 @@ this.replaceSelections(dup, collapse, origin || "+input"); }, replaceSelections: docMethodOp(function(code, collapse, origin) { - var this$1 = this; - var changes = [], sel = this.sel; for (var i = 0; i < sel.ranges.length; i++) { - var range$$1 = sel.ranges[i]; - changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin}; + var range = sel.ranges[i]; + 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$1 = changes.length - 1; i$1 >= 0; i$1--) - { makeChange(this$1, changes[i$1]); } + { makeChange(this, changes[i$1]); } if (newSel) { setSelectionReplaceHistory(this, newSel); } else if (this.cm) { ensureCursorVisible(this.cm); } }), @@ -6257,7 +6241,12 @@ for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } } return {undo: done, redo: undone} }, - clearHistory: function() {this.history = new History(this.history.maxGeneration);}, + clearHistory: function() { + var this$1 = this; + + this.history = new History(this.history.maxGeneration); + linkedDocs(this, function (doc) { return doc.history = this$1.history; }, true); + }, markClean: function() { this.cleanGeneration = this.changeGeneration(true); @@ -6378,18 +6367,18 @@ }, findMarks: function(from, to, filter) { from = clipPos(this, from); to = clipPos(this, to); - var found = [], lineNo$$1 = from.line; + var found = [], lineNo = from.line; this.iter(from.line, to.line + 1, function (line) { var spans = line.markedSpans; if (spans) { for (var i = 0; i < spans.length; i++) { var span = spans[i]; - if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to || - span.from == null && lineNo$$1 != from.line || - span.from != null && lineNo$$1 == 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); } } } - ++lineNo$$1; + ++lineNo; }); return found }, @@ -6404,14 +6393,14 @@ }, posFromIndex: function(off) { - var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length; + var ch, lineNo = this.first, sepSize = this.lineSeparator().length; this.iter(function (line) { var sz = line.text.length + sepSize; if (sz > off) { ch = off; return true } off -= sz; - ++lineNo$$1; + ++lineNo; }); - return clipPos(this, Pos(lineNo$$1, ch)) + return clipPos(this, Pos(lineNo, ch)) }, indexFromPos: function (coords) { coords = clipPos(this, coords); @@ -6450,15 +6439,13 @@ return copy }, unlinkDoc: function(other) { - var this$1 = this; - if (other instanceof CodeMirror) { other = other.doc; } if (this.linked) { for (var i = 0; i < this.linked.length; ++i) { - var link = this$1.linked[i]; + var link = this.linked[i]; if (link.doc != other) { continue } - this$1.linked.splice(i, 1); - other.unlinkDoc(this$1); - detachSharedMarkers(findSharedMarkers(this$1)); + this.linked.splice(i, 1); + other.unlinkDoc(this); + detachSharedMarkers(findSharedMarkers(this)); break } } // If the histories were shared, split them again @@ -6510,28 +6497,39 @@ // 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 () { - var content = reader.result; - if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = ""; } - text[i] = content; - if (++read == n) { + var markAsReadAndPasteIfAllFilesAreRead = function () { + if (++read == n) { + operation(cm, function () { pos = clipPos(cm.doc, pos); var change = {from: pos, to: pos, - text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), + text: cm.doc.splitLines( + text.filter(function (t) { return t != null; }).join(cm.doc.lineSeparator())), origin: "paste"}; makeChange(cm.doc, change); - setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); + setSelectionReplaceHistory(cm.doc, simpleSelection(clipPos(cm.doc, pos), clipPos(cm.doc, changeEnd(change)))); + })(); + } + }; + var readTextFromFile = function (file, i) { + if (cm.options.allowDropFileTypes && + indexOf(cm.options.allowDropFileTypes, file.type) == -1) { + markAsReadAndPasteIfAllFilesAreRead(); + return + } + var reader = new FileReader; + reader.onerror = function () { return markAsReadAndPasteIfAllFilesAreRead(); }; + reader.onload = function () { + var content = reader.result; + if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { + markAsReadAndPasteIfAllFilesAreRead(); + return } - }); + text[i] = content; + markAsReadAndPasteIfAllFilesAreRead(); + }; reader.readAsText(file); }; - for (var i = 0; i < n; ++i) { loadFile(files[i], i); } + for (var i = 0; i < files.length; i++) { readTextFromFile(files[i], i); } } else { // Normal drop // Don't do a replace if the drop happened inside of the selected text. if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { @@ -6553,7 +6551,7 @@ cm.display.input.focus(); } } - catch(e){} + catch(e$1){} } } @@ -6649,7 +6647,7 @@ 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 145: "ScrollLock", 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", - 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 221: "]", 222: "'", 224: "Mod", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" }; @@ -6756,18 +6754,18 @@ return keymap } - function lookupKey(key, map$$1, handle, context) { - map$$1 = getKeyMap(map$$1); - var found = map$$1.call ? map$$1.call(key, context) : map$$1[key]; + function lookupKey(key, map, handle, context) { + map = getKeyMap(map); + var found = map.call ? map.call(key, context) : map[key]; if (found === false) { return "nothing" } if (found === "...") { return "multi" } if (found != null && handle(found)) { return "handled" } - if (map$$1.fallthrough) { - if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]") - { return lookupKey(key, map$$1.fallthrough, handle, context) } - for (var i = 0; i < map$$1.fallthrough.length; i++) { - var result = lookupKey(key, map$$1.fallthrough[i], handle, context); + if (map.fallthrough) { + if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") + { return lookupKey(key, map.fallthrough, handle, context) } + for (var i = 0; i < map.fallthrough.length; i++) { + var result = lookupKey(key, map.fallthrough[i], handle, context); if (result) { return result } } } @@ -6784,7 +6782,7 @@ var base = name; if (event.altKey && base != "Alt") { name = "Alt-" + name; } if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; } - if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; } + if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Mod") { name = "Cmd-" + name; } if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; } return name } @@ -6841,6 +6839,7 @@ function endOfLine(visually, cm, lineObj, lineNo, dir) { if (visually) { + if (cm.doc.direction == "rtl") { dir = -dir; } var order = getOrder(lineObj, cm.doc.direction); if (order) { var part = dir < 0 ? lst(order) : order[0]; @@ -7009,7 +7008,7 @@ goGroupRight: function (cm) { return cm.moveH(1, "group"); }, goGroupLeft: function (cm) { return cm.moveH(-1, "group"); }, goWordRight: function (cm) { return cm.moveH(1, "word"); }, - delCharBefore: function (cm) { return cm.deleteH(-1, "char"); }, + delCharBefore: function (cm) { return cm.deleteH(-1, "codepoint"); }, delCharAfter: function (cm) { return cm.deleteH(1, "char"); }, delWordBefore: function (cm) { return cm.deleteH(-1, "word"); }, delWordAfter: function (cm) { return cm.deleteH(1, "word"); }, @@ -7095,7 +7094,7 @@ var line = getLine(cm.doc, start.line); var order = getOrder(line, cm.doc.direction); if (!order || order[0].level == 0) { - var firstNonWS = Math.max(0, line.text.search(/\S/)); + var firstNonWS = Math.max(start.ch, line.text.search(/\S/)); var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky) } @@ -7198,6 +7197,7 @@ var lastStoppedKey = null; function onKeyDown(e) { var cm = this; + if (e.target && e.target != cm.display.input.getField()) { return } cm.curOp.focus = activeElt(); if (signalDOMEvent(cm, e)) { return } // IE does strange things with escape. @@ -7211,6 +7211,8 @@ if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) { cm.replaceSelection("", null, "cut"); } } + if (gecko && !mac && !handled && code == 46 && e.shiftKey && !e.ctrlKey && document.execCommand) + { document.execCommand("cut"); } // Turn mouse into crosshair when Alt is held on Mac. if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) @@ -7239,6 +7241,7 @@ function onKeyPress(e) { var cm = this; + if (e.target && e.target != cm.display.input.getField()) { return } if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return } var keyCode = e.keyCode, charCode = e.charCode; if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return} @@ -7378,6 +7381,10 @@ var dragEnd = operation(cm, function (e) { if (webkit) { display.scroller.draggable = false; } cm.state.draggingText = false; + if (cm.state.delayingBlurEvent) { + if (cm.hasFocus()) { cm.state.delayingBlurEvent = false; } + else { delayBlurEvent(cm); } + } off(display.wrapper.ownerDocument, "mouseup", dragEnd); off(display.wrapper.ownerDocument, "mousemove", mouseMove); off(display.scroller, "dragstart", dragStart); @@ -7387,8 +7394,8 @@ if (!behavior.addNew) { extendSelection(cm.doc, pos, null, null, behavior.extend); } // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) - if (webkit || ie && ie_version == 9) - { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus();}, 20); } + if ((webkit && !safari) || ie && ie_version == 9) + { setTimeout(function () {display.wrapper.ownerDocument.body.focus({preventScroll: true}); display.input.focus();}, 20); } else { display.input.focus(); } } @@ -7401,15 +7408,15 @@ if (webkit) { display.scroller.draggable = true; } cm.state.draggingText = dragEnd; dragEnd.copy = !behavior.moveOnDrag; - // IE's approach to draggable - if (display.scroller.dragDrop) { display.scroller.dragDrop(); } on(display.wrapper.ownerDocument, "mouseup", dragEnd); on(display.wrapper.ownerDocument, "mousemove", mouseMove); on(display.scroller, "dragstart", dragStart); on(display.scroller, "drop", dragEnd); - delayBlurEvent(cm); + cm.state.delayingBlurEvent = true; setTimeout(function () { return display.input.focus(); }, 20); + // IE's approach to draggable + if (display.scroller.dragDrop) { display.scroller.dragDrop(); } } function rangeForUnit(cm, pos, unit) { @@ -7422,6 +7429,7 @@ // Normal selection, as opposed to text dragging. function leftButtonSelect(cm, event, start, behavior) { + if (ie) { delayBlurEvent(cm); } var display = cm.display, doc = cm.doc; e_preventDefault(event); @@ -7442,11 +7450,11 @@ start = posFromMouse(cm, event, true, true); ourIndex = -1; } else { - var range$$1 = rangeForUnit(cm, start, behavior.unit); + var range = rangeForUnit(cm, start, behavior.unit); if (behavior.extend) - { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); } + { ourRange = extendRange(ourRange, range.anchor, range.head, behavior.extend); } else - { ourRange = range$$1; } + { ourRange = range; } } if (!behavior.addNew) { @@ -7489,14 +7497,14 @@ cm.scrollIntoView(pos); } else { var oldRange = ourRange; - var range$$1 = rangeForUnit(cm, pos, behavior.unit); + var range = rangeForUnit(cm, pos, behavior.unit); var anchor = oldRange.anchor, head; - if (cmp(range$$1.anchor, anchor) > 0) { - head = range$$1.head; - anchor = minPos(oldRange.from(), range$$1.anchor); + if (cmp(range.anchor, anchor) > 0) { + head = range.head; + anchor = minPos(oldRange.from(), range.anchor); } else { - head = range$$1.anchor; - anchor = maxPos(oldRange.to(), range$$1.head); + head = range.anchor; + anchor = maxPos(oldRange.to(), range.head); } var ranges$1 = startSel.ranges.slice(0); ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head)); @@ -7558,17 +7566,17 @@ // Used when mouse-selecting to adjust the anchor to the proper side // of a bidi jump depending on the visual position of the head. - function bidiSimplify(cm, range$$1) { - var anchor = range$$1.anchor; - var head = range$$1.head; + function bidiSimplify(cm, range) { + var anchor = range.anchor; + var head = range.head; var anchorLine = getLine(cm.doc, anchor.line); - if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 } + if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range } var order = getOrder(anchorLine); - if (!order) { return range$$1 } + if (!order) { return range } var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index]; - if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 } + if (part.from != anchor.ch && part.to != anchor.ch) { return range } var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1); - if (boundary == 0 || boundary == order.length) { return range$$1 } + if (boundary == 0 || boundary == order.length) { return range } // Compute the relative visual position of the head compared to the // anchor (<0 is to the left, >0 to the right) @@ -7587,7 +7595,7 @@ var usePart = order[boundary + (leftSide ? -1 : 0)]; var from = leftSide == (usePart.level == 1); var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before"; - return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head) + return anchor.ch == ch && anchor.sticky == sticky ? range : new Range(new Pos(anchor.line, ch, sticky), head) } @@ -7600,7 +7608,7 @@ mY = e.touches[0].clientY; } else { try { mX = e.clientX; mY = e.clientY; } - catch(e) { return false } + catch(e$1) { return false } } if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false } if (prevent) { e_preventDefault(e); } @@ -7700,7 +7708,7 @@ 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", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) { + option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200c\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, function (cm, val, old) { cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); if (old != Init) { cm.refresh(); } }); @@ -7764,6 +7772,12 @@ } cm.display.input.readOnlyChanged(val); }); + + option("screenReaderLabel", null, function (cm, val) { + val = (val === '') ? null : val; + cm.display.input.screenReaderLabelChanged(val); + }); + option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true); option("dragDrop", true, dragDropChanged); option("allowDropFileTypes", null); @@ -7874,15 +7888,17 @@ attachDoc(this, doc); if ((options.autofocus && !mobile) || this.hasFocus()) - { setTimeout(bind(onFocus, this), 20); } + { setTimeout(function () { + if (this$1.hasFocus() && !this$1.state.focused) { onFocus(this$1); } + }, 20); } else { onBlur(this); } for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt)) - { optionHandlers[opt](this$1, options[opt], Init); } } + { optionHandlers[opt](this, options[opt], Init); } } maybeUpdateLineNumberWidth(this); if (options.finishInit) { options.finishInit(this); } - for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); } + for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this); } endOperation(this); // Suppress optimizelegibility in Webkit, since it breaks text // measuring on line wrapping boundaries. @@ -7916,6 +7932,9 @@ // which point we can't mess with it anymore. Context menu is // handled in onMouseDown for these browsers. on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }); + on(d.input.getField(), "contextmenu", function (e) { + if (!d.scroller.contains(e.target)) { onContextMenu(cm, e); } + }); // Used to suppress mouse event handling when a touch happens var touchFinished, prevTouch = {end: 0}; @@ -8104,14 +8123,14 @@ var updateInput = cm.curOp.updateInput; // Normal behavior is to insert the new text into every selection for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) { - var range$$1 = sel.ranges[i$1]; - var from = range$$1.from(), to = range$$1.to(); - if (range$$1.empty()) { + var range = sel.ranges[i$1]; + var from = range.from(), to = range.to(); + if (range.empty()) { if (deleted && deleted > 0) // Handle deletion { from = Pos(from.line, from.ch - deleted); } else if (cm.state.overwrite && !paste) // Handle overwrite { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); } - else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted) + else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == textLines.join("\n")) { from = to = Pos(from.line, 0); } } var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines, @@ -8144,21 +8163,21 @@ var sel = cm.doc.sel; for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range$$1 = sel.ranges[i]; - if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue } - var mode = cm.getModeAt(range$$1.head); + var range = sel.ranges[i]; + if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) { continue } + var mode = cm.getModeAt(range.head); var indented = false; if (mode.electricChars) { for (var j = 0; j < mode.electricChars.length; j++) { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { - indented = indentLine(cm, range$$1.head.line, "smart"); + indented = indentLine(cm, range.head.line, "smart"); break } } } else if (mode.electricInput) { - if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch))) - { indented = indentLine(cm, range$$1.head.line, "smart"); } + if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) + { indented = indentLine(cm, range.head.line, "smart"); } } - if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); } + if (indented) { signalLater(cm, "electricInput", cm, range.head.line); } } } @@ -8223,13 +8242,13 @@ getOption: function(option) {return this.options[option]}, getDoc: function() {return this.doc}, - addKeyMap: function(map$$1, bottom) { - this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1)); + addKeyMap: function(map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); }, - removeKeyMap: function(map$$1) { + removeKeyMap: function(map) { var maps = this.state.keyMaps; for (var i = 0; i < maps.length; ++i) - { if (maps[i] == map$$1 || maps[i].name == map$$1) { + { if (maps[i] == map || maps[i].name == map) { maps.splice(i, 1); return true } } @@ -8246,15 +8265,13 @@ regChange(this); }), removeOverlay: methodOp(function(spec) { - var this$1 = this; - var overlays = this.state.overlays; for (var i = 0; i < overlays.length; ++i) { var cur = overlays[i].modeSpec; if (cur == spec || typeof spec == "string" && cur.name == spec) { overlays.splice(i, 1); - this$1.state.modeGen++; - regChange(this$1); + this.state.modeGen++; + regChange(this); return } } @@ -8268,24 +8285,22 @@ if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); } }), indentSelection: methodOp(function(how) { - var this$1 = this; - var ranges = this.doc.sel.ranges, end = -1; for (var i = 0; i < ranges.length; i++) { - var range$$1 = ranges[i]; - if (!range$$1.empty()) { - var from = range$$1.from(), to = range$$1.to(); + var range = ranges[i]; + if (!range.empty()) { + var from = range.from(), to = range.to(); var start = Math.max(end, from.line); - end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; + end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; for (var j = start; j < end; ++j) - { indentLine(this$1, j, how); } - var newRanges = this$1.doc.sel.ranges; + { indentLine(this, j, how); } + var newRanges = this.doc.sel.ranges; if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) - { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); } - } else if (range$$1.head.line > end) { - indentLine(this$1, range$$1.head.line, how, true); - end = range$$1.head.line; - if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); } + { replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); } + } else if (range.head.line > end) { + indentLine(this, range.head.line, how, true); + end = range.head.line; + if (i == this.doc.sel.primIndex) { ensureCursorVisible(this); } } } }), @@ -8327,8 +8342,6 @@ }, getHelpers: function(pos, type) { - var this$1 = this; - var found = []; if (!helpers.hasOwnProperty(type)) { return found } var help = helpers[type], mode = this.getModeAt(pos); @@ -8346,7 +8359,7 @@ } for (var i$1 = 0; i$1 < help._global.length; i$1++) { var cur = help._global[i$1]; - if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1) + if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) { found.push(cur.val); } } return found @@ -8359,10 +8372,10 @@ }, cursorCoords: function(start, mode) { - var pos, range$$1 = this.doc.sel.primary(); - if (start == null) { pos = range$$1.head; } + var pos, range = this.doc.sel.primary(); + if (start == null) { pos = range.head; } else if (typeof start == "object") { pos = clipPos(this.doc, start); } - else { pos = start ? range$$1.from() : range$$1.to(); } + else { pos = start ? range.from() : range.to(); } return cursorCoords(this, pos, mode || "page") }, @@ -8446,13 +8459,11 @@ triggerElectric: methodOp(function(text) { triggerElectric(this, text); }), findPosH: function(from, amount, unit, visually) { - var this$1 = this; - var dir = 1; if (amount < 0) { dir = -1; amount = -amount; } var cur = clipPos(this.doc, from); for (var i = 0; i < amount; ++i) { - cur = findPosH(this$1.doc, cur, dir, unit, visually); + cur = findPosH(this.doc, cur, dir, unit, visually); if (cur.hitSide) { break } } return cur @@ -8461,11 +8472,11 @@ moveH: methodOp(function(dir, unit) { var this$1 = this; - this.extendSelectionsBy(function (range$$1) { - if (this$1.display.shift || this$1.doc.extend || range$$1.empty()) - { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) } + this.extendSelectionsBy(function (range) { + if (this$1.display.shift || this$1.doc.extend || range.empty()) + { return findPosH(this$1.doc, range.head, dir, unit, this$1.options.rtlMoveVisually) } else - { return dir < 0 ? range$$1.from() : range$$1.to() } + { return dir < 0 ? range.from() : range.to() } }, sel_move); }), @@ -8474,23 +8485,21 @@ if (sel.somethingSelected()) { doc.replaceSelection("", null, "+delete"); } else - { deleteNearSelection(this, function (range$$1) { - var other = findPosH(doc, range$$1.head, dir, unit, false); - return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other} + { deleteNearSelection(this, function (range) { + var other = findPosH(doc, range.head, dir, unit, false); + return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other} }); } }), findPosV: function(from, amount, unit, goalColumn) { - var this$1 = this; - var dir = 1, x = goalColumn; if (amount < 0) { dir = -1; amount = -amount; } var cur = clipPos(this.doc, from); for (var i = 0; i < amount; ++i) { - var coords = cursorCoords(this$1, cur, "div"); + var coords = cursorCoords(this, cur, "div"); if (x == null) { x = coords.left; } else { coords.left = x; } - cur = findPosV(this$1, coords, dir, unit); + cur = findPosV(this, coords, dir, unit); if (cur.hitSide) { break } } return cur @@ -8501,14 +8510,14 @@ var doc = this.doc, goals = []; var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected(); - doc.extendSelectionsBy(function (range$$1) { + doc.extendSelectionsBy(function (range) { if (collapse) - { return dir < 0 ? range$$1.from() : range$$1.to() } - var headPos = cursorCoords(this$1, range$$1.head, "div"); - if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; } + { return dir < 0 ? range.from() : range.to() } + var headPos = cursorCoords(this$1, range.head, "div"); + if (range.goalColumn != null) { headPos.left = range.goalColumn; } goals.push(headPos.left); var pos = findPosV(this$1, headPos, dir, unit); - if (unit == "page" && range$$1 == doc.sel.primary()) + if (unit == "page" && range == doc.sel.primary()) { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); } return pos }, sel_move); @@ -8555,22 +8564,22 @@ clientHeight: displayHeight(this), clientWidth: displayWidth(this)} }, - scrollIntoView: methodOp(function(range$$1, margin) { - if (range$$1 == null) { - range$$1 = {from: this.doc.sel.primary().head, to: null}; + scrollIntoView: methodOp(function(range, margin) { + if (range == null) { + range = {from: this.doc.sel.primary().head, to: null}; if (margin == null) { margin = this.options.cursorScrollMargin; } - } else if (typeof range$$1 == "number") { - range$$1 = {from: Pos(range$$1, 0), to: null}; - } else if (range$$1.from == null) { - range$$1 = {from: range$$1, to: null}; + } else if (typeof range == "number") { + range = {from: Pos(range, 0), to: null}; + } else if (range.from == null) { + range = {from: range, to: null}; } - if (!range$$1.to) { range$$1.to = range$$1.from; } - range$$1.margin = margin || 0; + if (!range.to) { range.to = range.from; } + range.margin = margin || 0; - if (range$$1.from.line != null) { - scrollToRange(this, range$$1); + if (range.from.line != null) { + scrollToRange(this, range); } else { - scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin); + scrollToCoordsRange(this, range.from, range.to, range.margin); } }), @@ -8581,11 +8590,11 @@ if (width != null) { this.display.wrapper.style.width = interpret(width); } if (height != null) { this.display.wrapper.style.height = interpret(height); } if (this.options.lineWrapping) { clearLineMeasurementCache(this); } - var lineNo$$1 = this.display.viewFrom; - this.doc.iter(lineNo$$1, this.display.viewTo, function (line) { + var lineNo = this.display.viewFrom; + this.doc.iter(lineNo, this.display.viewTo, function (line) { if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) - { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } } - ++lineNo$$1; + { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo, "widget"); break } } } + ++lineNo; }); this.curOp.forceUpdate = true; signal(this, "refresh", this); @@ -8602,7 +8611,7 @@ clearCaches(this); scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop); updateGutterSpace(this.display); - if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5 || this.options.lineWrapping) { estimateLineHeights(this); } signal(this, "refresh", this); }), @@ -8644,34 +8653,40 @@ } // Used for horizontal relative motion. Dir is -1 or 1 (left or - // right), unit can be "char", "column" (like char, but doesn't - // cross line boundaries), "word" (across next word), or "group" (to - // the start of next group of word or non-word-non-whitespace - // chars). The visually param controls whether, in right-to-left - // text, direction 1 means to move towards the next index in the - // string, or towards the character to the right of the current - // position. The resulting position will have a hitSide=true - // property if it reached the end of the document. + // right), unit can be "codepoint", "char", "column" (like char, but + // doesn't cross line boundaries), "word" (across next word), or + // "group" (to the start of next group of word or + // non-word-non-whitespace chars). The visually param controls + // whether, in right-to-left text, direction 1 means to move towards + // the next index in the string, or towards the character to the right + // of the current position. The resulting position will have a + // hitSide=true property if it reached the end of the document. function findPosH(doc, pos, dir, unit, visually) { var oldPos = pos; var origDir = dir; var lineObj = getLine(doc, pos.line); + var lineDir = visually && doc.direction == "rtl" ? -dir : dir; function findNextLine() { - var l = pos.line + dir; + var l = pos.line + lineDir; if (l < doc.first || l >= doc.first + doc.size) { return false } pos = new Pos(l, pos.ch, pos.sticky); return lineObj = getLine(doc, l) } function moveOnce(boundToLine) { var next; - if (visually) { + if (unit == "codepoint") { + var ch = lineObj.text.charCodeAt(pos.ch + (unit > 0 ? 0 : -1)); + if (isNaN(ch)) { next = null; } + else { next = new Pos(pos.line, Math.max(0, Math.min(lineObj.text.length, pos.ch + dir * (ch >= 0xD800 && ch < 0xDC00 ? 2 : 1))), + -dir); } + } else if (visually) { next = moveVisually(doc.cm, lineObj, pos, dir); } else { next = moveLogically(lineObj, pos, dir); } if (next == null) { if (!boundToLine && findNextLine()) - { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); } + { pos = endOfLine(visually, doc.cm, lineObj, pos.line, lineDir); } else { return false } } else { @@ -8680,7 +8695,7 @@ return true } - if (unit == "char") { + if (unit == "char" || unit == "codepoint") { moveOnce(); } else if (unit == "column") { moveOnce(true); @@ -8750,8 +8765,16 @@ var div = input.div = display.lineDiv; disableBrowserMagic(div, cm.options.spellcheck, cm.options.autocorrect, cm.options.autocapitalize); + function belongsToInput(e) { + for (var t = e.target; t; t = t.parentNode) { + if (t == div) { return true } + if (/\bCodeMirror-(?:line)?widget\b/.test(t.className)) { break } + } + return false + } + on(div, "paste", function (e) { - if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } + if (!belongsToInput(e) || signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } // IE doesn't fire input events, so we schedule a read for the pasted content in this way if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); } }); @@ -8776,7 +8799,7 @@ }); function onCopyCut(e) { - if (signalDOMEvent(cm, e)) { return } + if (!belongsToInput(e) || signalDOMEvent(cm, e)) { return } if (cm.somethingSelected()) { setLastCopied({lineWise: false, text: cm.getSelections()}); if (e.type == "cut") { cm.replaceSelection("", null, "cut"); } @@ -8818,9 +8841,18 @@ on(div, "cut", onCopyCut); }; + ContentEditableInput.prototype.screenReaderLabelChanged = function (label) { + // Label for screenreaders, accessibility + if(label) { + this.div.setAttribute('aria-label', label); + } else { + this.div.removeAttribute('aria-label'); + } + }; + ContentEditableInput.prototype.prepareSelection = function () { var result = prepareSelection(this.cm, false); - result.focus = this.cm.state.focused; + result.focus = document.activeElement == this.div; return result }; @@ -8856,8 +8888,8 @@ var end = to.line < cm.display.viewTo && posToDOM(cm, to); if (!end) { var measure = view[view.length - 1].measure; - var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; - end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]}; + var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; + end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}; } if (!start || !end) { @@ -8916,7 +8948,7 @@ ContentEditableInput.prototype.focus = function () { if (this.cm.options.readOnly != "nocursor") { - if (!this.selectionInEditor()) + if (!this.selectionInEditor() || document.activeElement != this.div) { this.showSelection(this.prepareSelection(), true); } this.div.focus(); } @@ -9146,11 +9178,11 @@ addText(cmText); return } - var markerID = node.getAttribute("cm-marker"), range$$1; + var markerID = node.getAttribute("cm-marker"), range; if (markerID) { var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); - if (found.length && (range$$1 = found[0].find(0))) - { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); } + if (found.length && (range = found[0].find(0))) + { addText(getBetween(cm.doc, range.from, range.to).join(lineSep)); } return } if (node.getAttribute("contenteditable") == "false") { return } @@ -9218,13 +9250,13 @@ function find(textNode, topNode, offset) { for (var i = -1; i < (maps ? maps.length : 0); i++) { - var map$$1 = i < 0 ? measure.map : maps[i]; - for (var j = 0; j < map$$1.length; j += 3) { - var curNode = map$$1[j + 2]; + var map = i < 0 ? measure.map : maps[i]; + for (var j = 0; j < map.length; j += 3) { + var curNode = map[j + 2]; if (curNode == textNode || curNode == topNode) { var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); - var ch = map$$1[j] + offset; - if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; } + var ch = map[j] + offset; + if (offset < 0 || curNode != textNode) { ch = map[j + (offset ? 1 : 0)]; } return Pos(line, ch) } } @@ -9358,6 +9390,15 @@ this.textarea = this.wrapper.firstChild; }; + TextareaInput.prototype.screenReaderLabelChanged = function (label) { + // Label for screenreaders, accessibility + if(label) { + this.textarea.setAttribute('aria-label', label); + } else { + this.textarea.removeAttribute('aria-label'); + } + }; + TextareaInput.prototype.prepareSelection = function () { // Redraw the selection and/or cursor var cm = this.cm, display = cm.display, doc = cm.doc; @@ -9598,6 +9639,7 @@ TextareaInput.prototype.readOnlyChanged = function (val) { if (!val) { this.reset(); } this.textarea.disabled = val == "nocursor"; + this.textarea.readOnly = !!val; }; TextareaInput.prototype.setUneditable = function () {}; @@ -9649,7 +9691,7 @@ textarea.style.display = ""; if (textarea.form) { off(textarea.form, "submit", save); - if (typeof textarea.form.submit == "function") + if (!options.leaveSubmitMethodAlone && typeof textarea.form.submit == "function") { textarea.form.submit = realSubmit; } } }; @@ -9748,7 +9790,7 @@ addLegacyProps(CodeMirror); - CodeMirror.version = "5.46.0"; + CodeMirror.version = "5.59.0"; return CodeMirror;