diff --git a/src/lib/codemirror/README.md b/src/lib/codemirror/README.md index a3a351b..8bc6c93 100644 --- a/src/lib/codemirror/README.md +++ b/src/lib/codemirror/README.md @@ -1,4 +1,5 @@ # CodeMirror + [![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) @@ -15,8 +16,8 @@ customizing CodeMirror to fit your application, and extending it with new functionality. You can find more information (and the -[manual](http://codemirror.net/doc/manual.html)) on the [project -page](http://codemirror.net). For questions and discussion, use the +[manual](https://codemirror.net/doc/manual.html)) on the [project +page](https://codemirror.net). For questions and discussion, use the [discussion forum](https://discuss.codemirror.net/). See @@ -28,6 +29,19 @@ The CodeMirror community aims to be welcoming to everybody. We use the (1.1)](http://contributor-covenant.org/version/1/1/0/) as our code of conduct. +### Installation + +Either get the [zip file](https://codemirror.net/codemirror.zip) with +the latest version, or make sure you have [Node](https://nodejs.org/) +installed and run: + + npm install codemirror + +**NOTE**: This is the source repository for the library, and not the +distribution channel. Cloning it is not the recommended way to install +the library, and will in fact not work unless you also run the build +step. + ### Quickstart To build the project, make sure you have Node.js installed (at least version 6) diff --git a/src/lib/codemirror/addon/merge/merge.js b/src/lib/codemirror/addon/merge/merge.js index 5b87b5e..63373f7 100644 --- a/src/lib/codemirror/addon/merge/merge.js +++ b/src/lib/codemirror/addon/merge/merge.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/LICENSE // declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL @@ -43,6 +43,7 @@ if (!this.edit.state.trackAlignable) this.edit.state.trackAlignable = new TrackAlignable(this.edit) this.orig.state.trackAlignable = new TrackAlignable(this.orig) } + this.lockButton.title = this.edit.phrase("Toggle locked scrolling"); this.orig.state.diffViews = [this]; var classLocation = options.chunkClassLocation || "background"; @@ -500,7 +501,7 @@ var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc", "CodeMirror-merge-copy")); var editOriginals = dv.mv.options.allowEditingOriginals; - copy.title = editOriginals ? "Push to left" : "Revert chunk"; + copy.title = dv.edit.phrase(editOriginals ? "Push to left" : "Revert chunk"); copy.chunk = chunk; copy.style.top = (chunk.origTo > chunk.origFrom ? top : dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit) + "px"; @@ -594,7 +595,6 @@ function buildGap(dv) { var lock = dv.lockButton = elt("div", null, "CodeMirror-merge-scrolllock"); - lock.title = "Toggle locked scrolling"; var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap"); CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); }); var gapElts = [lockWrap]; @@ -728,7 +728,7 @@ cm.addLineClass(from, "wrap", "CodeMirror-merge-collapsed-line"); var widget = document.createElement("span"); widget.className = "CodeMirror-merge-collapsed-widget"; - widget.title = "Identical text collapsed. Click to expand."; + widget.title = cm.phrase("Identical text collapsed. Click to expand."); var mark = cm.markText(Pos(from, 0), Pos(to - 1), { inclusiveLeft: true, inclusiveRight: true, diff --git a/src/lib/codemirror/addon/selection/active-line.js b/src/lib/codemirror/addon/selection/active-line.js index aa295d0..c7b14ce 100644 --- a/src/lib/codemirror/addon/selection/active-line.js +++ b/src/lib/codemirror/addon/selection/active-line.js @@ -1,5 +1,5 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/LICENSE (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS diff --git a/src/lib/codemirror/lib/codemirror.js b/src/lib/codemirror/lib/codemirror.js index e942fe6..e178478 100644 --- a/src/lib/codemirror/lib/codemirror.js +++ b/src/lib/codemirror/lib/codemirror.js @@ -1,7 +1,7 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE +// Distributed under an MIT license: https://codemirror.net/LICENSE -// This is CodeMirror (http://codemirror.net), a code editor +// This is CodeMirror (https://codemirror.net), a code editor // implemented in JavaScript on top of the browser's DOM. // // You can find some technical background for some of the code below @@ -746,6 +746,16 @@ function collapsedSpanAtSide(line, start) { function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) } function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) } +function collapsedSpanAround(line, ch) { + var sps = sawCollapsedSpans && line.markedSpans, found + if (sps) { for (var i = 0; i < sps.length; ++i) { + var sp = sps[i] + if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker } + } } + return found +} + // 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. @@ -1810,7 +1820,7 @@ function buildLineContent(cm, lineView) { var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content, col: 0, pos: 0, cm: cm, trailingSpace: false, - splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")} + splitSpaces: cm.getOption("lineWrapping")} lineView.measure = {} // Iterate over the logical lines that make up this visual line. @@ -1931,6 +1941,8 @@ function buildToken(builder, text, style, startStyle, endStyle, title, css) { builder.content.appendChild(content) } +// Change some spaces to NBSP to prevent the browser from collapsing +// trailing spaces at the end of a line when rendering text (issue #1362). function splitSpaces(text, trailingBefore) { if (text.length > 1 && !/ /.test(text)) { return text } var spaceBefore = trailingBefore, result = "" @@ -2778,12 +2790,11 @@ function coordsChar(cm, x, y) { var lineObj = getLine(doc, lineN) for (;;) { var found = coordsCharInner(cm, lineObj, lineN, x, y) - var merged = collapsedSpanAtEnd(lineObj) - var mergedPos = merged && merged.find(0, true) - if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) - { lineN = lineNo(lineObj = mergedPos.to.line) } - else - { return found } + var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 ? 1 : 0)) + if (!collapsed) { return found } + var rangeEnd = collapsed.find(1) + if (rangeEnd.line == lineN) { return rangeEnd } + lineObj = getLine(doc, lineN = rangeEnd.line) } } @@ -3543,6 +3554,7 @@ var NativeScrollbars = function(place, scroll, cm) { this.cm = cm var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar") var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar") + vert.tabIndex = horiz.tabIndex = -1 place(vert); place(horiz) on(vert, "scroll", function () { @@ -4783,7 +4795,7 @@ function addChangeToHistory(doc, change, selAfter, opId) { if ((hist.lastOp == opId || hist.lastOrigin == change.origin && change.origin && - ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || + ((change.origin.charAt(0) == "+" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) || change.origin.charAt(0) == "*")) && (cur = lastChangeEvent(hist, hist.lastOp == opId))) { // Merge this change into the last event @@ -5684,7 +5696,7 @@ LineWidget.prototype.changed = function () { this.height = null var diff = widgetHeight(this) - oldH if (!diff) { return } - updateLineHeight(line, line.height + diff) + if (!lineIsHidden(this.doc, line)) { updateLineHeight(line, line.height + diff) } if (cm) { runInOp(cm, function () { cm.curOp.forceUpdate = true @@ -6567,8 +6579,6 @@ function registerGlobalHandlers() { // Called when the window resizes function onResize(cm) { var d = cm.display - if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) - { return } // Might be a text scaling operation, clear size caches. d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null d.scrollbarsClipped = false @@ -6614,7 +6624,7 @@ keyMap.pcDefault = { "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", - fallthrough: "basic" + "fallthrough": "basic" } // Very basic readline/emacs-style bindings, which are standard on Mac. keyMap.emacsy = { @@ -6632,7 +6642,7 @@ keyMap.macDefault = { "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", - fallthrough: ["basic", "emacsy"] + "fallthrough": ["basic", "emacsy"] } keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault @@ -7234,8 +7244,9 @@ function onMouseDown(e) { } return } - if (clickInGutter(cm, e)) { return } - var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single" + var button = e_button(e) + if (button == 3 && captureRightClick ? contextMenuInGutter(cm, e) : clickInGutter(cm, e)) { return } + var pos = posFromMouse(cm, e), repeat = pos ? clickRepeat(pos, button) : "single" window.focus() // #3261: make sure, that we're not starting a second selection @@ -7312,8 +7323,8 @@ function leftButtonStartDrag(cm, event, pos, behavior) { var dragEnd = operation(cm, function (e) { if (webkit) { display.scroller.draggable = false } cm.state.draggingText = false - off(document, "mouseup", dragEnd) - off(document, "mousemove", mouseMove) + off(display.wrapper.ownerDocument, "mouseup", dragEnd) + off(display.wrapper.ownerDocument, "mousemove", mouseMove) off(display.scroller, "dragstart", dragStart) off(display.scroller, "drop", dragEnd) if (!moved) { @@ -7322,7 +7333,7 @@ function leftButtonStartDrag(cm, event, pos, behavior) { { 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 () {document.body.focus(); display.input.focus()}, 20) } + { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus()}, 20) } else { display.input.focus() } } @@ -7337,8 +7348,8 @@ function leftButtonStartDrag(cm, event, pos, behavior) { dragEnd.copy = !behavior.moveOnDrag // IE's approach to draggable if (display.scroller.dragDrop) { display.scroller.dragDrop() } - on(document, "mouseup", dragEnd) - on(document, "mousemove", mouseMove) + on(display.wrapper.ownerDocument, "mouseup", dragEnd) + on(display.wrapper.ownerDocument, "mousemove", mouseMove) on(display.scroller, "dragstart", dragStart) on(display.scroller, "drop", dragEnd) @@ -7470,19 +7481,19 @@ function leftButtonSelect(cm, event, start, behavior) { counter = Infinity e_preventDefault(e) display.input.focus() - off(document, "mousemove", move) - off(document, "mouseup", up) + off(display.wrapper.ownerDocument, "mousemove", move) + off(display.wrapper.ownerDocument, "mouseup", up) doc.history.lastSelOrigin = null } var move = operation(cm, function (e) { - if (!e_button(e)) { done(e) } + if (e.buttons === 0 || !e_button(e)) { done(e) } else { extend(e) } }) var up = operation(cm, done) cm.state.selectingText = up - on(document, "mousemove", move) - on(document, "mouseup", up) + on(display.wrapper.ownerDocument, "mousemove", move) + on(display.wrapper.ownerDocument, "mouseup", up) } // Used when mouse-selecting to adjust the anchor to the proper side @@ -7714,6 +7725,7 @@ function defineOptions(CodeMirror) { option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; }) option("autofocus", null) option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true) + option("phrases", null) } function guttersChanged(cm) { @@ -7765,6 +7777,7 @@ function CodeMirror(place, options) { var doc = options.value if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction) } + else if (options.mode) { doc.modeOption = options.mode } this.doc = doc var input = new CodeMirror.inputStyles[options.inputStyle](this) @@ -8551,6 +8564,11 @@ function addEditorMethods(CodeMirror) { return old }), + phrase: function(phraseText) { + var phrases = this.options.phrases + return phrases && Object.prototype.hasOwnProperty.call(phrases, phraseText) ? phrases[phraseText] : phraseText + }, + getInputField: function(){return this.display.input.getField()}, getWrapperElement: function(){return this.display.wrapper}, getScrollerElement: function(){return this.display.scroller}, @@ -8755,8 +8773,12 @@ ContentEditableInput.prototype.showSelection = function (info, takeFocus) { this.showMultipleSelections(info) }; +ContentEditableInput.prototype.getSelection = function () { + return this.cm.display.wrapper.ownerDocument.getSelection() +}; + ContentEditableInput.prototype.showPrimarySelection = function () { - var sel = window.getSelection(), cm = this.cm, prim = cm.doc.sel.primary() + var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary() var from = prim.from(), to = prim.to() if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) { @@ -8823,13 +8845,13 @@ ContentEditableInput.prototype.showMultipleSelections = function (info) { }; ContentEditableInput.prototype.rememberSelection = function () { - var sel = window.getSelection() + var sel = this.getSelection() this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset }; ContentEditableInput.prototype.selectionInEditor = function () { - var sel = window.getSelection() + var sel = this.getSelection() if (!sel.rangeCount) { return false } var node = sel.getRangeAt(0).commonAncestorContainer return contains(this.div, node) @@ -8864,14 +8886,14 @@ ContentEditableInput.prototype.receivedFocus = function () { }; ContentEditableInput.prototype.selectionChanged = function () { - var sel = window.getSelection() + var sel = this.getSelection() return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset }; ContentEditableInput.prototype.pollSelection = function () { if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return } - var sel = window.getSelection(), cm = this.cm + var sel = this.getSelection(), cm = this.cm // On Android Chrome (version 56, at least), backspacing into an // uneditable block element will put the cursor in that element, // and then, because it's not editable, hide the virtual keyboard. @@ -9005,7 +9027,7 @@ ContentEditableInput.prototype.setUneditable = function (node) { }; ContentEditableInput.prototype.onKeyPress = function (e) { - if (e.charCode == 0) { return } + if (e.charCode == 0 || this.composing) { return } e.preventDefault() if (!this.cm.isReadOnly()) { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0) } @@ -9045,12 +9067,13 @@ function isInGutter(node) { function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos } function domTextBetween(cm, from, to, fromLine, toLine) { - var text = "", closing = false, lineSep = cm.doc.lineSeparator() + var text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false function recognizeMarker(id) { return function (marker) { return marker.id == id; } } function close() { if (closing) { text += lineSep - closing = false + if (extraLinebreak) { text += lineSep } + closing = extraLinebreak = false } } function addText(str) { @@ -9062,8 +9085,8 @@ function domTextBetween(cm, from, to, fromLine, toLine) { function walk(node) { if (node.nodeType == 1) { var cmText = node.getAttribute("cm-text") - if (cmText != null) { - addText(cmText || node.textContent.replace(/\u200b/g, "")) + if (cmText) { + addText(cmText) return } var markerID = node.getAttribute("cm-marker"), range @@ -9074,19 +9097,24 @@ function domTextBetween(cm, from, to, fromLine, toLine) { return } if (node.getAttribute("contenteditable") == "false") { return } - var isBlock = /^(pre|div|p)$/i.test(node.nodeName) + var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName) + if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return } + if (isBlock) { close() } for (var i = 0; i < node.childNodes.length; i++) { walk(node.childNodes[i]) } + + if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true } if (isBlock) { closing = true } } else if (node.nodeType == 3) { - addText(node.nodeValue) + addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " ")) } } for (;;) { walk(from) if (from == to) { break } from = from.nextSibling + extraLinebreak = false } return text } @@ -9187,13 +9215,10 @@ TextareaInput.prototype.init = function (display) { var this$1 = this; var input = this, cm = this.cm + this.createField(display) + var te = this.textarea - // Wraps and hides input textarea - var div = this.wrapper = hiddenTextarea() - // The semihidden textarea that is focused when the editor is - // focused, and receives input. - var te = this.textarea = div.firstChild - display.wrapper.insertBefore(div, display.wrapper.firstChild) + display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild) // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) if (ios) { te.style.width = "0px" } @@ -9260,6 +9285,14 @@ TextareaInput.prototype.init = function (display) { }) }; +TextareaInput.prototype.createField = function (_display) { + // Wraps and hides input textarea + this.wrapper = hiddenTextarea() + // The semihidden textarea that is focused when the editor is + // focused, and receives input. + this.textarea = this.wrapper.firstChild +}; + TextareaInput.prototype.prepareSelection = function () { // Redraw the selection and/or cursor var cm = this.cm, display = cm.display, doc = cm.doc @@ -9653,7 +9686,7 @@ CodeMirror.fromTextArea = fromTextArea addLegacyProps(CodeMirror) -CodeMirror.version = "5.35.0" +CodeMirror.version = "5.40.2" return CodeMirror;