- Get the current version:
5.7.
+ Get the current version:
5.13.
You can see the
code or
read the
release notes.
There is a
minification helper.
@@ -162,7 +162,7 @@
license that CodeMirror uses.
Discussion around the project is done on
- a discussion forum.
+ a discussion forum.
There is also
the codemirror-announce
list, which is only used for major announcements (such as new
diff --git a/www/code/codemirror-5.7/keymap/emacs.js b/www/code/codemirror-5.13.2/keymap/emacs.js
similarity index 100%
rename from www/code/codemirror-5.7/keymap/emacs.js
rename to www/code/codemirror-5.13.2/keymap/emacs.js
diff --git a/www/code/codemirror-5.7/keymap/sublime.js b/www/code/codemirror-5.13.2/keymap/sublime.js
similarity index 98%
rename from www/code/codemirror-5.7/keymap/sublime.js
rename to www/code/codemirror-5.13.2/keymap/sublime.js
index 44e812a24..49db3b871 100644
--- a/www/code/codemirror-5.7/keymap/sublime.js
+++ b/www/code/codemirror-5.13.2/keymap/sublime.js
@@ -105,9 +105,10 @@
cm.setSelections(extended);
};
- map["Shift-" + ctrl + "K"] = "deleteLine";
+ map["Shift-Ctrl-K"] = "deleteLine";
function insertLine(cm, above) {
+ if (cm.isReadOnly()) return CodeMirror.Pass
cm.operation(function() {
var len = cm.listSelections().length, newSelection = [], last = -1;
for (var i = 0; i < len; i++) {
@@ -123,9 +124,9 @@
});
}
- cmds[map[ctrl + "Enter"] = "insertLineAfter"] = function(cm) { insertLine(cm, false); };
+ cmds[map[ctrl + "Enter"] = "insertLineAfter"] = function(cm) { return insertLine(cm, false); };
- cmds[map["Shift-" + ctrl + "Enter"] = "insertLineBefore"] = function(cm) { insertLine(cm, true); };
+ cmds[map["Shift-" + ctrl + "Enter"] = "insertLineBefore"] = function(cm) { return insertLine(cm, true); };
function wordAt(cm, pos) {
var start = pos.ch, end = start, line = cm.getLine(pos.line);
@@ -192,6 +193,7 @@
var swapLineCombo = mac ? "Cmd-Ctrl-" : "Shift-Ctrl-";
cmds[map[swapLineCombo + "Up"] = "swapLineUp"] = function(cm) {
+ if (cm.isReadOnly()) return CodeMirror.Pass
var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1, newSels = [];
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i], from = range.from().line - 1, to = range.to().line;
@@ -218,6 +220,7 @@
};
cmds[map[swapLineCombo + "Down"] = "swapLineDown"] = function(cm) {
+ if (cm.isReadOnly()) return CodeMirror.Pass
var ranges = cm.listSelections(), linesToMove = [], at = cm.lastLine() + 1;
for (var i = ranges.length - 1; i >= 0; i--) {
var range = ranges[i], from = range.to().line + 1, to = range.from().line;
@@ -240,7 +243,9 @@
});
};
- map[ctrl + "/"] = "toggleComment";
+ cmds[map[ctrl + "/"] = "toggleCommentIndented"] = function(cm) {
+ cm.toggleComment({ indent: true });
+ }
cmds[map[ctrl + "J"] = "joinLines"] = function(cm) {
var ranges = cm.listSelections(), joined = [];
@@ -287,6 +292,7 @@
map[ctrl + "T"] = "transposeChars";
function sortLines(cm, caseSensitive) {
+ if (cm.isReadOnly()) return CodeMirror.Pass
var ranges = cm.listSelections(), toSort = [], selected;
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i];
diff --git a/www/code/codemirror-5.7/keymap/vim.js b/www/code/codemirror-5.13.2/keymap/vim.js
similarity index 99%
rename from www/code/codemirror-5.7/keymap/vim.js
rename to www/code/codemirror-5.13.2/keymap/vim.js
index 14897a84d..5ed2d9bf7 100644
--- a/www/code/codemirror-5.7/keymap/vim.js
+++ b/www/code/codemirror-5.13.2/keymap/vim.js
@@ -64,9 +64,9 @@
{ keys: '', type: 'keyToKey', toKeys: '', context: 'insert' },
{ keys: '', type: 'keyToKey', toKeys: '', context: 'insert' },
{ keys: 's', type: 'keyToKey', toKeys: 'cl', context: 'normal' },
- { keys: 's', type: 'keyToKey', toKeys: 'xi', context: 'visual'},
+ { keys: 's', type: 'keyToKey', toKeys: 'c', context: 'visual'},
{ keys: 'S', type: 'keyToKey', toKeys: 'cc', context: 'normal' },
- { keys: 'S', type: 'keyToKey', toKeys: 'dcc', context: 'visual' },
+ { keys: 'S', type: 'keyToKey', toKeys: 'VdO', context: 'visual' },
{ keys: '', type: 'keyToKey', toKeys: '0' },
{ keys: '', type: 'keyToKey', toKeys: '$' },
{ keys: '', type: 'keyToKey', toKeys: '' },
@@ -164,6 +164,7 @@
{ keys: 'v', type: 'action', action: 'toggleVisualMode' },
{ keys: 'V', type: 'action', action: 'toggleVisualMode', actionArgs: { linewise: true }},
{ keys: '', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }},
+ { keys: '', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }},
{ keys: 'gv', type: 'action', action: 'reselectLastSelection' },
{ keys: 'J', type: 'action', action: 'joinLines', isEdit: true },
{ keys: 'p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true }},
@@ -292,12 +293,7 @@
// Keypress character binding of format "'a'"
return key.charAt(1);
}
- var pieces = key.split('-');
- if (/-$/.test(key)) {
- // If the - key was typed, split will result in 2 extra empty strings
- // in the array. Replace them with 1 '-'.
- pieces.splice(-2, 2, '-');
- }
+ var pieces = key.split(/-(?!$)/);
var lastPiece = pieces[pieces.length - 1];
if (pieces.length == 1 && pieces[0].length == 1) {
// No-modifier bindings use literal character bindings above. Skip.
@@ -686,6 +682,9 @@
// Add user defined key bindings.
exCommandDispatcher.map(lhs, rhs, ctx);
},
+ unmap: function(lhs, ctx) {
+ exCommandDispatcher.unmap(lhs, ctx);
+ },
// TODO: Expose setOption and getOption as instance methods. Need to decide how to namespace
// them, or somehow make them work with the existing CodeMirror setOption/getOption API.
setOption: setOption,
@@ -1697,11 +1696,12 @@
var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat;
var first = cm.firstLine();
var last = cm.lastLine();
- // Vim cancels linewise motions that start on an edge and move beyond
- // that edge. It does not cancel motions that do not start on an edge.
- if ((line < first && cur.line == first) ||
- (line > last && cur.line == last)) {
- return;
+ // Vim go to line begin or line end when cursor at first/last line and
+ // move to previous/next line is triggered.
+ if (line < first && cur.line == first){
+ return this.moveToStartOfLine(cm, head, motionArgs, vim);
+ }else if (line > last && cur.line == last){
+ return this.moveToEol(cm, head, motionArgs, vim);
}
if (motionArgs.toFirstChar){
endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line));
@@ -1959,13 +1959,21 @@
text = text.slice(0, - match[0].length);
}
}
- var wasLastLine = head.line - 1 == cm.lastLine();
- cm.replaceRange('', anchor, head);
- if (args.linewise && !wasLastLine) {
+ var prevLineEnd = new Pos(anchor.line - 1, Number.MAX_VALUE);
+ var wasLastLine = cm.firstLine() == cm.lastLine();
+ if (head.line > cm.lastLine() && args.linewise && !wasLastLine) {
+ cm.replaceRange('', prevLineEnd, head);
+ } else {
+ cm.replaceRange('', anchor, head);
+ }
+ if (args.linewise) {
// Push the next line back down, if there is a next line.
- CodeMirror.commands.newlineAndIndent(cm);
- // null ch so setCursor moves to end of line.
- anchor.ch = null;
+ if (!wasLastLine) {
+ cm.setCursor(prevLineEnd);
+ CodeMirror.commands.newlineAndIndent(cm);
+ }
+ // make sure cursor ends up at the end of the line.
+ anchor.ch = Number.MAX_VALUE;
}
finalHead = anchor;
} else {
@@ -2144,9 +2152,7 @@
switch (actionArgs.position) {
case 'center': y = y - (height / 2) + lineHeight;
break;
- case 'bottom': y = y - height + lineHeight*1.4;
- break;
- case 'top': y = y + lineHeight*0.4;
+ case 'bottom': y = y - height + lineHeight;
break;
}
cm.scrollTo(null, y);
@@ -3208,7 +3214,7 @@
return cur;
}
- /*
+ /**
* Returns the boundaries of the next word. If the cursor in the middle of
* the word, then returns the boundaries of the current word, starting at
* the cursor. If the cursor is at the start/end of a word, and we are going
diff --git a/www/code/codemirror.css b/www/code/codemirror-5.13.2/lib/codemirror.css
similarity index 97%
rename from www/code/codemirror.css
rename to www/code/codemirror-5.13.2/lib/codemirror.css
index 3543523e6..1cf66a9fa 100644
--- a/www/code/codemirror.css
+++ b/www/code/codemirror-5.13.2/lib/codemirror.css
@@ -165,7 +165,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
}
/* The fake, visible scrollbars. Used to force redraw during scrolling
- before actuall scrolling happens, thus preventing shaking and
+ before actual scrolling happens, thus preventing shaking and
flickering artifacts. */
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
position: absolute;
@@ -191,12 +191,14 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
+ min-height: 100%;
z-index: 3;
}
.CodeMirror-gutter {
white-space: normal;
height: 100%;
display: inline-block;
+ vertical-align: top;
margin-bottom: -30px;
/* Hack to make IE7 behave */
*zoom:1;
@@ -244,6 +246,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
position: relative;
overflow: visible;
-webkit-tap-highlight-color: transparent;
+ -webkit-font-variant-ligatures: none;
+ font-variant-ligatures: none;
}
.CodeMirror-wrap pre {
word-wrap: break-word;
diff --git a/www/code/codemirror-5.7/lib/codemirror.js b/www/code/codemirror-5.13.2/lib/codemirror.js
similarity index 97%
rename from www/code/codemirror-5.7/lib/codemirror.js
rename to www/code/codemirror-5.13.2/lib/codemirror.js
index c6f9af859..ec49e3a33 100644
--- a/www/code/codemirror-5.7/lib/codemirror.js
+++ b/www/code/codemirror-5.13.2/lib/codemirror.js
@@ -13,7 +13,7 @@
else if (typeof define == "function" && define.amd) // AMD
return define([], mod);
else // Plain browser env
- this.CodeMirror = mod();
+ (this || window).CodeMirror = mod();
})(function() {
"use strict";
@@ -21,27 +21,29 @@
// Kludges for bugs and behavior differences that can't be feature
// detected are enabled based on userAgent etc sniffing.
+ var userAgent = navigator.userAgent;
+ var platform = navigator.platform;
- var gecko = /gecko\/\d/i.test(navigator.userAgent);
- var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
- var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
+ var gecko = /gecko\/\d/i.test(userAgent);
+ var ie_upto10 = /MSIE \d/.test(userAgent);
+ var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
var ie = ie_upto10 || ie_11up;
var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
- var webkit = /WebKit\//.test(navigator.userAgent);
- var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
- var chrome = /Chrome\//.test(navigator.userAgent);
- var presto = /Opera\//.test(navigator.userAgent);
+ var webkit = /WebKit\//.test(userAgent);
+ var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
+ var chrome = /Chrome\//.test(userAgent);
+ var presto = /Opera\//.test(userAgent);
var safari = /Apple Computer/.test(navigator.vendor);
- var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
- var phantom = /PhantomJS/.test(navigator.userAgent);
+ var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
+ var phantom = /PhantomJS/.test(userAgent);
- var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
+ var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
// This is woefully incomplete. Suggestions for alternative methods welcome.
- var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
- var mac = ios || /Mac/.test(navigator.platform);
- var windows = /win/i.test(navigator.platform);
+ var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
+ var mac = ios || /Mac/.test(platform);
+ var windows = /win/i.test(platform);
- var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
+ var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
if (presto_version) presto_version = Number(presto_version[1]);
if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
@@ -408,7 +410,7 @@
if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
});
- this.checkedOverlay = false;
+ this.checkedZeroWidth = false;
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
}
@@ -443,29 +445,43 @@
this.horiz.firstChild.style.width = "0";
}
- if (!this.checkedOverlay && measure.clientHeight > 0) {
- if (sWidth == 0) this.overlayHack();
- this.checkedOverlay = true;
+ if (!this.checkedZeroWidth && measure.clientHeight > 0) {
+ if (sWidth == 0) this.zeroWidthHack();
+ this.checkedZeroWidth = true;
}
return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
},
setScrollLeft: function(pos) {
if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
+ if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz);
},
setScrollTop: function(pos) {
if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
+ if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert);
},
- overlayHack: function() {
+ zeroWidthHack: function() {
var w = mac && !mac_geMountainLion ? "12px" : "18px";
- this.horiz.style.minHeight = this.vert.style.minWidth = w;
- var self = this;
- var barMouseDown = function(e) {
- if (e_target(e) != self.vert && e_target(e) != self.horiz)
- operation(self.cm, onMouseDown)(e);
- };
- on(this.vert, "mousedown", barMouseDown);
- on(this.horiz, "mousedown", barMouseDown);
+ this.horiz.style.height = this.vert.style.width = w;
+ this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
+ this.disableHoriz = new Delayed;
+ this.disableVert = new Delayed;
+ },
+ enableZeroWidthBar: function(bar, delay) {
+ bar.style.pointerEvents = "auto";
+ function maybeDisable() {
+ // To find out whether the scrollbar is still visible, we
+ // check whether the element under the pixel in the bottom
+ // left corner of the scrollbar box is the scrollbar box
+ // itself (when the bar is still visible) or its filler child
+ // (when the bar is hidden). If it is still visible, we keep
+ // it enabled, if it's hidden, we disable pointer events.
+ var box = bar.getBoundingClientRect();
+ var elt = document.elementFromPoint(box.left + 1, box.bottom - 1);
+ if (elt != bar) bar.style.pointerEvents = "none";
+ else delay.set(1000, maybeDisable);
+ }
+ delay.set(1000, maybeDisable);
},
clear: function() {
var parent = this.horiz.parentNode;
@@ -527,6 +543,7 @@
d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
+ d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"
if (sizes.right && sizes.bottom) {
d.scrollbarFiller.style.display = "block";
@@ -730,6 +747,7 @@
function postUpdateDisplay(cm, update) {
var viewport = update.viewport;
+
for (var first = true;; first = false) {
if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
// Clip forced viewport to actual scrollable area.
@@ -745,8 +763,8 @@
updateHeightsInViewport(cm);
var barMeasure = measureForScrollbars(cm);
updateSelection(cm);
- setDocumentHeight(cm, barMeasure);
updateScrollbars(cm, barMeasure);
+ setDocumentHeight(cm, barMeasure);
}
update.signal(cm, "update", cm);
@@ -763,17 +781,16 @@
postUpdateDisplay(cm, update);
var barMeasure = measureForScrollbars(cm);
updateSelection(cm);
- setDocumentHeight(cm, barMeasure);
updateScrollbars(cm, barMeasure);
+ setDocumentHeight(cm, barMeasure);
update.finish();
}
}
function setDocumentHeight(cm, measure) {
cm.display.sizer.style.minHeight = measure.docHeight + "px";
- var total = measure.docHeight + cm.display.barHeight;
- cm.display.heightForcer.style.top = total + "px";
- cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px";
+ cm.display.heightForcer.style.top = measure.docHeight + "px";
+ cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
}
// Read the actual heights of the rendered lines, and update their
@@ -807,7 +824,7 @@
// given line.
function updateWidgetHeight(line) {
if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
- line.widgets[i].height = line.widgets[i].node.offsetHeight;
+ line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight;
}
// Do a bulk-read of the DOM positions and sizes needed to draw the
@@ -1078,10 +1095,6 @@
if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
}
- function isReadOnly(cm) {
- return cm.options.readOnly || cm.doc.cantEdit;
- }
-
// This will be set to an array of strings when copying, so that,
// when pasting, we know what kind of selections the copied text
// was made out of.
@@ -1136,7 +1149,7 @@
var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
if (pasted) {
e.preventDefault();
- if (!isReadOnly(cm) && !cm.options.disableInput)
+ if (!cm.isReadOnly() && !cm.options.disableInput)
runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); });
return true;
}
@@ -1239,13 +1252,14 @@
});
on(te, "paste", function(e) {
- if (handlePaste(e, cm)) return true;
+ if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return
cm.state.pasteIncoming = true;
input.fastPoll();
});
function prepareCopyCut(e) {
+ if (signalDOMEvent(cm, e)) return
if (cm.somethingSelected()) {
lastCopied = cm.getSelections();
if (input.inaccurateSelection) {
@@ -1273,7 +1287,7 @@
on(te, "copy", prepareCopyCut);
on(display.scroller, "paste", function(e) {
- if (eventInWidget(display, e)) return;
+ if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return;
cm.state.pasteIncoming = true;
input.focus();
});
@@ -1407,7 +1421,7 @@
// in which case reading its value would be expensive.
if (this.contextMenuPending || !cm.state.focused ||
(hasSelection(input) && !prevInput && !this.composing) ||
- isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
+ cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
return false;
var text = input.value;
@@ -1469,10 +1483,11 @@
if (reset && cm.doc.sel.contains(pos) == -1)
operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
- var oldCSS = te.style.cssText;
- input.wrapper.style.position = "absolute";
- te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
- "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
+ var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
+ input.wrapper.style.cssText = "position: absolute"
+ var wrapperBox = input.wrapper.getBoundingClientRect()
+ te.style.cssText = "position: absolute; width: 30px; height: 30px; top: " + (e.clientY - wrapperBox.top - 5) +
+ "px; left: " + (e.clientX - wrapperBox.left - 5) + "px; z-index: 1000; background: " +
(ie ? "rgba(255, 255, 255, .05)" : "transparent") +
"; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
@@ -1503,7 +1518,7 @@
}
function rehide() {
input.contextMenuPending = false;
- input.wrapper.style.position = "relative";
+ input.wrapper.style.cssText = oldWrapperCSS
te.style.cssText = oldCSS;
if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
@@ -1558,7 +1573,9 @@
var div = input.div = display.lineDiv;
disableBrowserMagic(div);
- on(div, "paste", function(e) { handlePaste(e, cm); })
+ on(div, "paste", function(e) {
+ if (!signalDOMEvent(cm, e)) handlePaste(e, cm);
+ })
on(div, "compositionstart", function(e) {
var data = e.data;
@@ -1596,11 +1613,12 @@
on(div, "input", function() {
if (input.composing) return;
- if (isReadOnly(cm) || !input.pollContent())
+ if (cm.isReadOnly() || !input.pollContent())
runInOp(input.cm, function() {regChange(cm);});
});
function onCopyCut(e) {
+ if (signalDOMEvent(cm, e)) return
if (cm.somethingSelected()) {
lastCopied = cm.getSelections();
if (e.type == "cut") cm.replaceSelection("", null, "cut");
@@ -1676,8 +1694,13 @@
try { var rng = range(start.node, start.offset, end.offset, end.node); }
catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
if (rng) {
- sel.removeAllRanges();
- sel.addRange(rng);
+ if (!gecko && this.cm.state.focused) {
+ sel.collapse(start.node, start.offset);
+ if (!rng.collapsed) sel.addRange(rng);
+ } else {
+ sel.removeAllRanges();
+ sel.addRange(rng);
+ }
if (old && sel.anchorNode == null) sel.addRange(old);
else if (gecko) this.startGracePeriod();
}
@@ -1821,7 +1844,7 @@
this.div.focus();
},
applyComposition: function(composing) {
- if (isReadOnly(this.cm))
+ if (this.cm.isReadOnly())
operation(this.cm, regChange)(this.cm)
else if (composing.data && composing.data != composing.startData)
operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
@@ -1833,7 +1856,7 @@
onKeyPress: function(e) {
e.preventDefault();
- if (!isReadOnly(this.cm))
+ if (!this.cm.isReadOnly())
operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
},
@@ -2138,7 +2161,7 @@
// Give beforeSelectionChange handlers a change to influence a
// selection update.
- function filterSelectionChange(doc, sel) {
+ function filterSelectionChange(doc, sel, options) {
var obj = {
ranges: sel.ranges,
update: function(ranges) {
@@ -2146,7 +2169,8 @@
for (var i = 0; i < ranges.length; i++)
this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
clipPos(doc, ranges[i].head));
- }
+ },
+ origin: options && options.origin
};
signal(doc, "beforeSelectionChange", doc, obj);
if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
@@ -2172,7 +2196,7 @@
function setSelectionNoUndo(doc, sel, options) {
if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
- sel = filterSelectionChange(doc, sel);
+ sel = filterSelectionChange(doc, sel, options);
var bias = options && options.bias ||
(cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
@@ -2206,8 +2230,9 @@
var out;
for (var i = 0; i < sel.ranges.length; i++) {
var range = sel.ranges[i];
- var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);
- var newHead = skipAtomic(doc, range.head, bias, mayClear);
+ var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
+ var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
+ var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
if (out || newAnchor != range.anchor || newHead != range.head) {
if (!out) out = sel.ranges.slice(0, i);
out[i] = new Range(newAnchor, newHead);
@@ -2216,54 +2241,61 @@
return out ? normalizeSelection(out, sel.primIndex) : sel;
}
- // Ensure a given position is not inside an atomic range.
- function skipAtomic(doc, pos, bias, mayClear) {
- var flipped = false, curPos = pos;
- var dir = bias || 1;
- doc.cantEdit = false;
- search: for (;;) {
- var line = getLine(doc, curPos.line);
- if (line.markedSpans) {
- for (var i = 0; i < line.markedSpans.length; ++i) {
- var sp = line.markedSpans[i], m = sp.marker;
- if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
- (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
- if (mayClear) {
- signal(m, "beforeCursorEnter");
- if (m.explicitlyCleared) {
- if (!line.markedSpans) break;
- else {--i; continue;}
- }
- }
- if (!m.atomic) continue;
- var newPos = m.find(dir < 0 ? -1 : 1);
- if (cmp(newPos, curPos) == 0) {
- newPos.ch += dir;
- if (newPos.ch < 0) {
- if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
- else newPos = null;
- } else if (newPos.ch > line.text.length) {
- if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
- else newPos = null;
- }
- if (!newPos) {
- if (flipped) {
- // Driven in a corner -- no valid cursor position found at all
- // -- try again *with* clearing, if we didn't already
- if (!mayClear) return skipAtomic(doc, pos, bias, true);
- // Otherwise, turn off editing until further notice, and return the start of the doc
- doc.cantEdit = true;
- return Pos(doc.first, 0);
- }
- flipped = true; newPos = pos; dir = -dir;
- }
- }
- curPos = newPos;
- continue search;
+ function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
+ var line = getLine(doc, pos.line);
+ if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
+ var sp = line.markedSpans[i], m = sp.marker;
+ if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
+ (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
+ if (mayClear) {
+ signal(m, "beforeCursorEnter");
+ if (m.explicitlyCleared) {
+ if (!line.markedSpans) break;
+ else {--i; continue;}
}
}
+ if (!m.atomic) continue;
+
+ if (oldPos) {
+ var near = m.find(dir < 0 ? 1 : -1), diff;
+ if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
+ near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null);
+ if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
+ return skipAtomicInner(doc, near, pos, dir, mayClear);
+ }
+
+ var far = m.find(dir < 0 ? -1 : 1);
+ if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
+ far = movePos(doc, far, dir, far.line == pos.line ? line : null);
+ return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null;
}
- return curPos;
+ }
+ return pos;
+ }
+
+ // Ensure a given position is not inside an atomic range.
+ function skipAtomic(doc, pos, oldPos, bias, mayClear) {
+ var dir = bias || 1;
+ var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
+ (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
+ skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
+ (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
+ if (!found) {
+ doc.cantEdit = true;
+ return Pos(doc.first, 0);
+ }
+ return found;
+ }
+
+ function movePos(doc, pos, dir, line) {
+ if (dir < 0 && pos.ch == 0) {
+ if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1));
+ else return null;
+ } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
+ if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0);
+ else return null;
+ } else {
+ return new Pos(pos.line, pos.ch + dir);
}
}
@@ -2281,6 +2313,7 @@
for (var i = 0; i < doc.sel.ranges.length; i++) {
if (primary === false && i == doc.sel.primIndex) continue;
var range = doc.sel.ranges[i];
+ if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue;
var collapsed = range.empty();
if (collapsed || cm.options.showCursorWhenSelecting)
drawSelectionCursor(cm, range.head, curFragment);
@@ -3082,16 +3115,17 @@
if (op.preparedSelection)
cm.display.input.showSelection(op.preparedSelection);
- if (op.updatedDisplay)
- setDocumentHeight(cm, op.barMeasure);
if (op.updatedDisplay || op.startHeight != cm.doc.height)
updateScrollbars(cm, op.barMeasure);
+ if (op.updatedDisplay)
+ setDocumentHeight(cm, op.barMeasure);
if (op.selectionChanged) restartBlink(cm);
if (cm.state.focused && op.updateInput)
cm.display.input.reset(op.typing);
- if (op.focus && op.focus == activeElt()) ensureFocus(op.cm);
+ if (op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus()))
+ ensureFocus(op.cm);
}
function endOperation_finish(op) {
@@ -3110,7 +3144,7 @@
display.scroller.scrollTop = doc.scrollTop;
}
if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
- doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));
+ doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft));
display.scrollbars.setScrollLeft(doc.scrollLeft);
display.scroller.scrollLeft = doc.scrollLeft;
alignHorizontally(cm);
@@ -3406,7 +3440,7 @@
return dx * dx + dy * dy > 20 * 20;
}
on(d.scroller, "touchstart", function(e) {
- if (!isMouseLikeTouchEvent(e)) {
+ if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {
clearTimeout(touchFinished);
var now = +new Date;
d.activeTouch = {start: now, moved: false,
@@ -3461,7 +3495,7 @@
over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
start: function(e){onDragStart(cm, e);},
drop: operation(cm, onDrop),
- leave: function() {clearDragCursor(cm);}
+ leave: function(e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
};
var inp = d.input.getField();
@@ -3535,7 +3569,7 @@
// not interfere with, such as a scrollbar or widget.
function onMouseDown(e) {
var cm = this, display = cm.display;
- if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return;
+ if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return;
display.shift = e.shiftKey;
if (eventInWidget(display, e)) {
@@ -3591,7 +3625,7 @@
}
var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
- if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
+ if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
type == "single" && (contained = sel.contains(start)) > -1 &&
(cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) &&
(cmp(contained.to(), start) > 0 || start.xRel < 0))
@@ -3776,7 +3810,7 @@
// Determines whether an event happened in the gutter, and fires the
// handlers for the corresponding event.
- function gutterEvent(cm, e, type, prevent, signalfn) {
+ function gutterEvent(cm, e, type, prevent) {
try { var mX = e.clientX, mY = e.clientY; }
catch(e) { return false; }
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
@@ -3793,14 +3827,14 @@
if (g && g.getBoundingClientRect().right >= mX) {
var line = lineAtHeight(cm.doc, mY);
var gutter = cm.options.gutters[i];
- signalfn(cm, type, cm, line, gutter, e);
+ signal(cm, type, cm, line, gutter, e);
return e_defaultPrevented(e);
}
}
}
function clickInGutter(cm, e) {
- return gutterEvent(cm, e, "gutterClick", true, signalLater);
+ return gutterEvent(cm, e, "gutterClick", true);
}
// Kludge to work around strange IE behavior where it'll sometimes
@@ -3815,15 +3849,21 @@
e_preventDefault(e);
if (ie) lastDrop = +new Date;
var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
- if (!pos || isReadOnly(cm)) return;
+ if (!pos || cm.isReadOnly()) return;
// Might be a file drop, in which case we simply extract the text
// and insert it.
if (files && files.length && window.FileReader && window.File) {
var n = files.length, text = Array(n), read = 0;
var loadFile = function(file, i) {
+ if (cm.options.allowDropFileTypes &&
+ indexOf(cm.options.allowDropFileTypes, file.type) == -1)
+ return;
+
var reader = new FileReader;
reader.onload = operation(cm, function() {
- text[i] = reader.result;
+ var content = reader.result;
+ if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "";
+ text[i] = content;
if (++read == n) {
pos = clipPos(cm.doc, pos);
var change = {from: pos, to: pos,
@@ -3965,8 +4005,9 @@
var display = cm.display, scroll = display.scroller;
// Quit if there's nothing to scroll here
- if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
- dy && scroll.scrollHeight > scroll.clientHeight)) return;
+ var canScrollX = scroll.scrollWidth > scroll.clientWidth;
+ var canScrollY = scroll.scrollHeight > scroll.clientHeight;
+ if (!(dx && canScrollX || dy && canScrollY)) return;
// Webkit browsers on OS X abort momentum scrolls when the target
// of the scroll event is removed from the scrollable element.
@@ -3990,10 +4031,15 @@
// scrolling entirely here. It'll be slightly off from native, but
// better than glitching out.
if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
- if (dy)
+ if (dy && canScrollY)
setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
- e_preventDefault(e);
+ // Only prevent default scrolling if vertical scrolling is
+ // actually possible. Otherwise, it causes vertical scroll
+ // jitter on OSX trackpads when deltaX is small and deltaY
+ // is large (issue #3579)
+ if (!dy || (dy && canScrollY))
+ e_preventDefault(e);
display.wheelStartX = null; // Abort measurement, if in progress
return;
}
@@ -4042,7 +4088,7 @@
cm.display.input.ensurePolled();
var prevShift = cm.display.shift, done = false;
try {
- if (isReadOnly(cm)) cm.state.suppressEdits = true;
+ if (cm.isReadOnly()) cm.state.suppressEdits = true;
if (dropShift) cm.display.shift = false;
done = bound(cm) != Pass;
} finally {
@@ -4221,12 +4267,13 @@
// right-click take effect on it.
function onContextMenu(cm, e) {
if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
+ if (signalDOMEvent(cm, e, "contextmenu")) return;
cm.display.input.onContextMenu(e);
}
function contextMenuInGutter(cm, e) {
if (!hasHandler(cm, "gutterContextMenu")) return false;
- return gutterEvent(cm, e, "gutterContextMenu", false, signal);
+ return gutterEvent(cm, e, "gutterContextMenu", false);
}
// UPDATING
@@ -4774,10 +4821,9 @@
function findPosH(doc, pos, dir, unit, visually) {
var line = pos.line, ch = pos.ch, origDir = dir;
var lineObj = getLine(doc, line);
- var possible = true;
function findNextLine() {
var l = line + dir;
- if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
+ if (l < doc.first || l >= doc.first + doc.size) return false
line = l;
return lineObj = getLine(doc, l);
}
@@ -4787,14 +4833,16 @@
if (!boundToLine && findNextLine()) {
if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
else ch = dir < 0 ? lineObj.text.length : 0;
- } else return (possible = false);
+ } else return false
} else ch = next;
return true;
}
- if (unit == "char") moveOnce();
- else if (unit == "column") moveOnce(true);
- else if (unit == "word" || unit == "group") {
+ if (unit == "char") {
+ moveOnce()
+ } else if (unit == "column") {
+ moveOnce(true)
+ } else if (unit == "word" || unit == "group") {
var sawType = null, group = unit == "group";
var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
for (var first = true;; first = false) {
@@ -4814,8 +4862,8 @@
if (dir > 0 && !moveOnce(!first)) break;
}
}
- var result = skipAtomic(doc, Pos(line, ch), origDir, true);
- if (!possible) result.hitSide = true;
+ var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true);
+ if (!cmp(pos, result)) result.hitSide = true;
return result;
}
@@ -5202,6 +5250,7 @@
signal(this, "overwriteToggle", this, this.state.overwrite);
},
hasFocus: function() { return this.display.input.getField() == activeElt(); },
+ isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit); },
scrollTo: methodOp(function(x, y) {
if (x != null || y != null) resolveScrollToPos(this);
@@ -5404,6 +5453,7 @@
});
option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
option("dragDrop", true, dragDropChanged);
+ option("allowDropFileTypes", null);
option("cursorBlinkRate", 530);
option("cursorScrollMargin", 0);
@@ -5708,8 +5758,8 @@
var range = cm.listSelections()[i];
cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input");
cm.indentLine(range.from().line + 1, null, true);
- ensureCursorVisible(cm);
}
+ ensureCursorVisible(cm);
});
},
toggleOverwrite: function(cm) {cm.toggleOverwrite();}
@@ -6637,7 +6687,7 @@
parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;";
removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
}
- return widget.height = widget.node.offsetHeight;
+ return widget.height = widget.node.parentNode.offsetHeight;
}
function addLineWidget(doc, handle, node, options) {
@@ -7047,7 +7097,7 @@
if (nextChange == pos) { // Update current marker set
spanStyle = spanEndStyle = spanStartStyle = title = css = "";
collapsed = null; nextChange = Infinity;
- var foundBookmarks = [];
+ var foundBookmarks = [], endStyles
for (var j = 0; j < spans.length; ++j) {
var sp = spans[j], m = sp.marker;
if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
@@ -7058,9 +7108,9 @@
spanEndStyle = "";
}
if (m.className) spanStyle += " " + m.className;
- if (m.css) css = m.css;
+ if (m.css) css = (css ? css + ";" : "") + m.css;
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
- if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
+ if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to)
if (m.title && !title) title = m.title;
if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
collapsed = sp;
@@ -7068,14 +7118,17 @@
nextChange = sp.from;
}
}
+ if (endStyles) for (var j = 0; j < endStyles.length; j += 2)
+ if (endStyles[j + 1] == nextChange) spanEndStyle += " " + endStyles[j]
+
+ if (!collapsed || collapsed.from == pos) for (var j = 0; j < foundBookmarks.length; ++j)
+ buildCollapsedSpan(builder, 0, foundBookmarks[j]);
if (collapsed && (collapsed.from || 0) == pos) {
buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
collapsed.marker, collapsed.from == null);
if (collapsed.to == null) return;
if (collapsed.to == pos) collapsed = false;
}
- if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
- buildCollapsedSpan(builder, 0, foundBookmarks[j]);
}
if (pos >= len) break;
@@ -7327,6 +7380,7 @@
this.id = ++nextDocId;
this.modeOption = mode;
this.lineSep = lineSep;
+ this.extend = false;
if (typeof text == "string") text = this.splitLines(text);
updateDoc(this, {from: start, to: start, text: text});
@@ -7414,10 +7468,11 @@
extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
}),
extendSelections: docMethodOp(function(heads, options) {
- extendSelections(this, clipPosArray(this, heads, options));
+ extendSelections(this, clipPosArray(this, heads), options);
}),
extendSelectionsBy: docMethodOp(function(f, options) {
- extendSelections(this, map(this.sel.ranges, f), options);
+ var heads = map(this.sel.ranges, f);
+ extendSelections(this, clipPosArray(this, heads), options);
}),
setSelections: docMethodOp(function(ranges, primary, options) {
if (!ranges.length) return;
@@ -7542,7 +7597,7 @@
removeLineWidget: function(widget) { widget.clear(); },
markText: function(from, to, options) {
- return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
+ return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range");
},
setBookmark: function(pos, options) {
var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
@@ -7570,9 +7625,9 @@
var spans = line.markedSpans;
if (spans) for (var i = 0; i < spans.length; i++) {
var span = spans[i];
- if (!(lineNo == from.line && from.ch > span.to ||
- span.from == null && lineNo != from.line||
- lineNo == to.line && span.from > to.ch) &&
+ if (!(span.to != null && lineNo == from.line && from.ch > span.to ||
+ span.from == null && lineNo != from.line ||
+ span.from != null && lineNo == to.line && span.from > to.ch) &&
(!filter || filter(span.marker)))
found.push(span.marker.parent || span.marker);
}
@@ -8103,24 +8158,30 @@
}
};
+ var noHandlers = []
+ function getHandlers(emitter, type, copy) {
+ var arr = emitter._handlers && emitter._handlers[type]
+ if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers
+ else return arr || noHandlers
+ }
+
var off = CodeMirror.off = function(emitter, type, f) {
if (emitter.removeEventListener)
emitter.removeEventListener(type, f, false);
else if (emitter.detachEvent)
emitter.detachEvent("on" + type, f);
else {
- var arr = emitter._handlers && emitter._handlers[type];
- if (!arr) return;
- for (var i = 0; i < arr.length; ++i)
- if (arr[i] == f) { arr.splice(i, 1); break; }
+ var handlers = getHandlers(emitter, type, false)
+ for (var i = 0; i < handlers.length; ++i)
+ if (handlers[i] == f) { handlers.splice(i, 1); break; }
}
};
var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
- var arr = emitter._handlers && emitter._handlers[type];
- if (!arr) return;
+ var handlers = getHandlers(emitter, type, true)
+ if (!handlers.length) return;
var args = Array.prototype.slice.call(arguments, 2);
- for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args);
+ for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args);
};
var orphanDelayedCallbacks = null;
@@ -8133,8 +8194,8 @@
// them to be executed when the last operation ends, or, if no
// operation is active, when a timeout fires.
function signalLater(emitter, type /*, values...*/) {
- var arr = emitter._handlers && emitter._handlers[type];
- if (!arr) return;
+ var arr = getHandlers(emitter, type, false)
+ if (!arr.length) return;
var args = Array.prototype.slice.call(arguments, 2), list;
if (operationGroup) {
list = operationGroup.delayedCallbacks;
@@ -8174,8 +8235,7 @@
}
function hasHandler(emitter, type) {
- var arr = emitter._handlers && emitter._handlers[type];
- return arr && arr.length > 0;
+ return getHandlers(emitter, type).length > 0
}
// Add on and off methods to a constructor's prototype, to make
@@ -8829,7 +8889,7 @@
// THE END
- CodeMirror.version = "5.7.0";
+ CodeMirror.version = "5.13.2";
return CodeMirror;
});
diff --git a/www/code/codemirror-5.7/mode/apl/apl.js b/www/code/codemirror-5.13.2/mode/apl/apl.js
similarity index 100%
rename from www/code/codemirror-5.7/mode/apl/apl.js
rename to www/code/codemirror-5.13.2/mode/apl/apl.js
diff --git a/www/code/codemirror-5.7/mode/apl/index.html b/www/code/codemirror-5.13.2/mode/apl/index.html
similarity index 100%
rename from www/code/codemirror-5.7/mode/apl/index.html
rename to www/code/codemirror-5.13.2/mode/apl/index.html
diff --git a/www/code/codemirror-5.7/mode/asciiarmor/asciiarmor.js b/www/code/codemirror-5.13.2/mode/asciiarmor/asciiarmor.js
similarity index 100%
rename from www/code/codemirror-5.7/mode/asciiarmor/asciiarmor.js
rename to www/code/codemirror-5.13.2/mode/asciiarmor/asciiarmor.js
diff --git a/www/code/codemirror-5.7/mode/asciiarmor/index.html b/www/code/codemirror-5.13.2/mode/asciiarmor/index.html
similarity index 100%
rename from www/code/codemirror-5.7/mode/asciiarmor/index.html
rename to www/code/codemirror-5.13.2/mode/asciiarmor/index.html
diff --git a/www/code/codemirror-5.7/mode/asn.1/asn.1.js b/www/code/codemirror-5.13.2/mode/asn.1/asn.1.js
similarity index 100%
rename from www/code/codemirror-5.7/mode/asn.1/asn.1.js
rename to www/code/codemirror-5.13.2/mode/asn.1/asn.1.js
diff --git a/www/code/mode/asn.1/index.html b/www/code/codemirror-5.13.2/mode/asn.1/index.html
similarity index 98%
rename from www/code/mode/asn.1/index.html
rename to www/code/codemirror-5.13.2/mode/asn.1/index.html
index 8346f8e50..699fd4473 100644
--- a/www/code/mode/asn.1/index.html
+++ b/www/code/codemirror-5.13.2/mode/asn.1/index.html
@@ -1,4 +1,4 @@
-
+
CodeMirror: ASN.1 mode
@@ -73,6 +73,5 @@
The development of this mode has been sponsored by Ericsson
.
Coded by Asmelash Tsegay Gebretsadkan
-
diff --git a/www/code/codemirror-5.7/mode/asterisk/asterisk.js b/www/code/codemirror-5.13.2/mode/asterisk/asterisk.js
similarity index 100%
rename from www/code/codemirror-5.7/mode/asterisk/asterisk.js
rename to www/code/codemirror-5.13.2/mode/asterisk/asterisk.js
diff --git a/www/code/codemirror-5.7/mode/asterisk/index.html b/www/code/codemirror-5.13.2/mode/asterisk/index.html
similarity index 100%
rename from www/code/codemirror-5.7/mode/asterisk/index.html
rename to www/code/codemirror-5.13.2/mode/asterisk/index.html
diff --git a/www/code/codemirror-5.7/mode/brainfuck/brainfuck.js b/www/code/codemirror-5.13.2/mode/brainfuck/brainfuck.js
similarity index 100%
rename from www/code/codemirror-5.7/mode/brainfuck/brainfuck.js
rename to www/code/codemirror-5.13.2/mode/brainfuck/brainfuck.js
diff --git a/www/code/codemirror-5.7/mode/brainfuck/index.html b/www/code/codemirror-5.13.2/mode/brainfuck/index.html
similarity index 100%
rename from www/code/codemirror-5.7/mode/brainfuck/index.html
rename to www/code/codemirror-5.13.2/mode/brainfuck/index.html
diff --git a/www/code/codemirror-5.7/mode/clike/clike.js b/www/code/codemirror-5.13.2/mode/clike/clike.js
similarity index 70%
rename from www/code/codemirror-5.7/mode/clike/clike.js
rename to www/code/codemirror-5.13.2/mode/clike/clike.js
index 50f1ea734..34d3a5afd 100644
--- a/www/code/codemirror-5.7/mode/clike/clike.js
+++ b/www/code/codemirror-5.13.2/mode/clike/clike.js
@@ -11,6 +11,42 @@
})(function(CodeMirror) {
"use strict";
+function Context(indented, column, type, align, prev) {
+ this.indented = indented;
+ this.column = column;
+ this.type = type;
+ this.align = align;
+ this.prev = prev;
+}
+function isStatement(type) {
+ return type == "statement" || type == "switchstatement" || type == "namespace";
+}
+function pushContext(state, col, type) {
+ var indent = state.indented;
+ if (state.context && isStatement(state.context.type) && !isStatement(type))
+ indent = state.context.indented;
+ return state.context = new Context(indent, col, type, null, state.context);
+}
+function popContext(state) {
+ var t = state.context.type;
+ if (t == ")" || t == "]" || t == "}")
+ state.indented = state.context.indented;
+ return state.context = state.context.prev;
+}
+
+function typeBefore(stream, state) {
+ if (state.prevToken == "variable" || state.prevToken == "variable-3") return true;
+ if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, stream.start))) return true;
+}
+
+function isTopScope(context) {
+ for (;;) {
+ if (!context || context.type == "top") return true;
+ if (context.type == "}" && context.prev.type != "namespace") return false;
+ context = context.prev;
+ }
+}
+
CodeMirror.defineMode("clike", function(config, parserConfig) {
var indentUnit = config.indentUnit,
statementIndentUnit = parserConfig.statementIndentUnit || indentUnit,
@@ -25,8 +61,12 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
multiLineStrings = parserConfig.multiLineStrings,
indentStatements = parserConfig.indentStatements !== false,
indentSwitch = parserConfig.indentSwitch !== false,
- namespaceSeparator = parserConfig.namespaceSeparator;
- var isOperatorChar = /[+\-*&%=<>!?|\/]/;
+ namespaceSeparator = parserConfig.namespaceSeparator,
+ isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/,
+ numberStart = parserConfig.numberStart || /[\d\.]/,
+ number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i,
+ isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/,
+ endStatement = parserConfig.endStatement || /^[;:,]$/;
var curPunc, isDefKeyword;
@@ -40,13 +80,14 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
}
- if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
+ if (isPunctuationChar.test(ch)) {
curPunc = ch;
return null;
}
- if (/\d/.test(ch)) {
- stream.eatWhile(/[\w\.]/);
- return "number";
+ if (numberStart.test(ch)) {
+ stream.backUp(1)
+ if (stream.match(number)) return "number"
+ stream.next()
}
if (ch == "/") {
if (stream.eat("*")) {
@@ -59,7 +100,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
}
}
if (isOperatorChar.test(ch)) {
- stream.eatWhile(isOperatorChar);
+ while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {}
return "operator";
}
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
@@ -67,17 +108,17 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
var cur = stream.current();
- if (keywords.propertyIsEnumerable(cur)) {
- if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
- if (defKeywords.propertyIsEnumerable(cur)) isDefKeyword = true;
+ if (contains(keywords, cur)) {
+ if (contains(blockKeywords, cur)) curPunc = "newstatement";
+ if (contains(defKeywords, cur)) isDefKeyword = true;
return "keyword";
}
- if (types.propertyIsEnumerable(cur)) return "variable-3";
- if (builtin.propertyIsEnumerable(cur)) {
- if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
+ if (contains(types, cur)) return "variable-3";
+ if (contains(builtin, cur)) {
+ if (contains(blockKeywords, cur)) curPunc = "newstatement";
return "builtin";
}
- if (atoms.propertyIsEnumerable(cur)) return "atom";
+ if (contains(atoms, cur)) return "atom";
return "variable";
}
@@ -106,42 +147,6 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
return "comment";
}
- function Context(indented, column, type, align, prev) {
- this.indented = indented;
- this.column = column;
- this.type = type;
- this.align = align;
- this.prev = prev;
- }
- function isStatement(type) {
- return type == "statement" || type == "switchstatement" || type == "namespace";
- }
- function pushContext(state, col, type) {
- var indent = state.indented;
- if (state.context && isStatement(state.context.type) && !isStatement(type))
- indent = state.context.indented;
- return state.context = new Context(indent, col, type, null, state.context);
- }
- function popContext(state) {
- var t = state.context.type;
- if (t == ")" || t == "]" || t == "}")
- state.indented = state.context.indented;
- return state.context = state.context.prev;
- }
-
- function typeBefore(stream, state) {
- if (state.prevToken == "variable" || state.prevToken == "variable-3") return true;
- if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, stream.start))) return true;
- }
-
- function isTopScope(context) {
- for (;;) {
- if (!context || context.type == "top") return true;
- if (context.type == "}" && context.prev.type != "namespace") return false;
- context = context.prev;
- }
- }
-
// Interface
return {
@@ -168,8 +173,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
if (style == "comment" || style == "meta") return style;
if (ctx.align == null) ctx.align = true;
- if ((curPunc == ";" || curPunc == ":" || curPunc == ","))
- while (isStatement(state.context.type)) popContext(state);
+ if (endStatement.test(curPunc)) while (isStatement(state.context.type)) popContext(state);
else if (curPunc == "{") pushContext(state, stream.column(), "}");
else if (curPunc == "[") pushContext(state, stream.column(), "]");
else if (curPunc == "(") pushContext(state, stream.column(), ")");
@@ -212,8 +216,16 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass;
var ctx = state.context, firstChar = textAfter && textAfter.charAt(0);
if (isStatement(ctx.type) && firstChar == "}") ctx = ctx.prev;
+ if (hooks.indent) {
+ var hook = hooks.indent(state, ctx, textAfter);
+ if (typeof hook == "number") return hook
+ }
var closing = firstChar == ctx.type;
var switchBlock = ctx.prev && ctx.prev.type == "switchstatement";
+ if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) {
+ while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev
+ return ctx.indented
+ }
if (isStatement(ctx.type))
return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit);
if (ctx.align && (!dontAlignCalls || ctx.type != ")"))
@@ -238,27 +250,30 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
return obj;
}
+ function contains(words, word) {
+ if (typeof words === "function") {
+ return words(word);
+ } else {
+ return words.propertyIsEnumerable(word);
+ }
+ }
var cKeywords = "auto if break case register continue return default do sizeof " +
- "static else struct switch extern typedef float union for " +
- "goto while enum const volatile";
+ "static else struct switch extern typedef union for goto while enum const volatile";
var cTypes = "int long char short double float unsigned signed void size_t ptrdiff_t";
function cppHook(stream, state) {
- if (!state.startOfLine) return false;
- for (;;) {
- if (stream.skipTo("\\")) {
- stream.next();
- if (stream.eol()) {
- state.tokenize = cppHook;
- break;
- }
- } else {
- stream.skipToEnd();
- state.tokenize = null;
- break;
+ if (!state.startOfLine) return false
+ for (var ch, next = null; ch = stream.peek();) {
+ if (ch == "\\" && stream.match(/^.$/)) {
+ next = cppHook
+ break
+ } else if (ch == "/" && stream.match(/^\/[\/\*]/, false)) {
+ break
}
+ stream.next()
}
- return "meta";
+ state.tokenize = next
+ return "meta"
}
function pointerHook(_stream, state) {
@@ -413,6 +428,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
defKeywords: words("class interface package enum"),
typeFirstDefinitions: true,
atoms: words("true false null"),
+ endStatement: /^[;:]$/,
hooks: {
"@": function(stream) {
stream.eatWhile(/[\w\$_]/);
@@ -468,7 +484,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
keywords: words(
/* scala */
- "abstract case catch class def do else extends false final finally for forSome if " +
+ "abstract case catch class def do else extends final finally for forSome if " +
"implicit import lazy match new null object override package private protected return " +
"sealed super this throw trait try type val var while with yield _ : = => <- <: " +
"<% >: # @ " +
@@ -481,7 +497,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
),
types: words(
"AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " +
- "Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " +
+ "Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable " +
"Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " +
"Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " +
"StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " +
@@ -511,6 +527,68 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
"'": function(stream) {
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
return "atom";
+ },
+ "=": function(stream, state) {
+ var cx = state.context
+ if (cx.type == "}" && cx.align && stream.eat(">")) {
+ state.context = new Context(cx.indented, cx.column, cx.type, null, cx.prev)
+ return "operator"
+ } else {
+ return false
+ }
+ }
+ },
+ modeProps: {closeBrackets: {triples: '"'}}
+ });
+
+ function tokenKotlinString(tripleString){
+ return function (stream, state) {
+ var escaped = false, next, end = false;
+ while (!stream.eol()) {
+ if (!tripleString && !escaped && stream.match('"') ) {end = true; break;}
+ if (tripleString && stream.match('"""')) {end = true; break;}
+ next = stream.next();
+ if(!escaped && next == "$" && stream.match('{'))
+ stream.skipTo("}");
+ escaped = !escaped && next == "\\" && !tripleString;
+ }
+ if (end || !tripleString)
+ state.tokenize = null;
+ return "string";
+ }
+ }
+
+ def("text/x-kotlin", {
+ name: "clike",
+ keywords: words(
+ /*keywords*/
+ "package as typealias class interface this super val " +
+ "var fun for is in This throw return " +
+ "break continue object if else while do try when !in !is as? " +
+
+ /*soft keywords*/
+ "file import where by get set abstract enum open inner override private public internal " +
+ "protected catch finally out final vararg reified dynamic companion constructor init " +
+ "sealed field property receiver param sparam lateinit data inline noinline tailrec " +
+ "external annotation crossinline const operator infix"
+ ),
+ types: words(
+ /* package java.lang */
+ "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " +
+ "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " +
+ "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " +
+ "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void"
+ ),
+ intendSwitch: false,
+ indentStatements: false,
+ multiLineStrings: true,
+ blockKeywords: words("catch class do else finally for if where try while enum"),
+ defKeywords: words("class val var object package interface fun"),
+ atoms: words("true false null this"),
+ hooks: {
+ '"': function(stream, state) {
+ state.tokenize = tokenKotlinString(stream.match('""'));
+ return state.tokenize(stream, state);
}
},
modeProps: {closeBrackets: {triples: '"'}}
@@ -598,7 +676,10 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
stream.eatWhile(/[\w\$]/);
return "keyword";
},
- "#": cppHook
+ "#": cppHook,
+ indent: function(_state, ctx, textAfter) {
+ if (ctx.type == "statement" && /^@\w/.test(textAfter)) return ctx.indented
+ }
},
modeProps: {fold: "brace"}
});
@@ -616,4 +697,85 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
modeProps: {fold: ["brace", "include"]}
});
+ // Ceylon Strings need to deal with interpolation
+ var stringTokenizer = null;
+ function tokenCeylonString(type) {
+ return function(stream, state) {
+ var escaped = false, next, end = false;
+ while (!stream.eol()) {
+ if (!escaped && stream.match('"') &&
+ (type == "single" || stream.match('""'))) {
+ end = true;
+ break;
+ }
+ if (!escaped && stream.match('``')) {
+ stringTokenizer = tokenCeylonString(type);
+ end = true;
+ break;
+ }
+ next = stream.next();
+ escaped = type == "single" && !escaped && next == "\\";
+ }
+ if (end)
+ state.tokenize = null;
+ return "string";
+ }
+ }
+
+ def("text/x-ceylon", {
+ name: "clike",
+ keywords: words("abstracts alias assembly assert assign break case catch class continue dynamic else" +
+ " exists extends finally for function given if import in interface is let module new" +
+ " nonempty object of out outer package return satisfies super switch then this throw" +
+ " try value void while"),
+ types: function(word) {
+ // In Ceylon all identifiers that start with an uppercase are types
+ var first = word.charAt(0);
+ return (first === first.toUpperCase() && first !== first.toLowerCase());
+ },
+ blockKeywords: words("case catch class dynamic else finally for function if interface module new object switch try while"),
+ defKeywords: words("class dynamic function interface module object package value"),
+ builtin: words("abstract actual aliased annotation by default deprecated doc final formal late license" +
+ " native optional sealed see serializable shared suppressWarnings tagged throws variable"),
+ isPunctuationChar: /[\[\]{}\(\),;\:\.`]/,
+ isOperatorChar: /[+\-*&%=<>!?|^~:\/]/,
+ numberStart: /[\d#$]/,
+ number: /^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i,
+ multiLineStrings: true,
+ typeFirstDefinitions: true,
+ atoms: words("true false null larger smaller equal empty finished"),
+ indentSwitch: false,
+ styleDefs: false,
+ hooks: {
+ "@": function(stream) {
+ stream.eatWhile(/[\w\$_]/);
+ return "meta";
+ },
+ '"': function(stream, state) {
+ state.tokenize = tokenCeylonString(stream.match('""') ? "triple" : "single");
+ return state.tokenize(stream, state);
+ },
+ '`': function(stream, state) {
+ if (!stringTokenizer || !stream.match('`')) return false;
+ state.tokenize = stringTokenizer;
+ stringTokenizer = null;
+ return state.tokenize(stream, state);
+ },
+ "'": function(stream) {
+ stream.eatWhile(/[\w\$_\xa1-\uffff]/);
+ return "atom";
+ },
+ token: function(_stream, state, style) {
+ if ((style == "variable" || style == "variable-3") &&
+ state.prevToken == ".") {
+ return "variable-2";
+ }
+ }
+ },
+ modeProps: {
+ fold: ["brace", "import"],
+ closeBrackets: {triples: '"'}
+ }
+ });
+
});
diff --git a/www/code/mode/clike/index.html b/www/code/codemirror-5.13.2/mode/clike/index.html
similarity index 65%
rename from www/code/mode/clike/index.html
rename to www/code/codemirror-5.13.2/mode/clike/index.html
index 226c6ce84..45c670ae5 100644
--- a/www/code/mode/clike/index.html
+++ b/www/code/codemirror-5.13.2/mode/clike/index.html
@@ -206,6 +206,103 @@ object FilterTest extends App {
}
+