Version Description
- Added ability to customize tab characters and size for all editors
- Added ability to set custom editor heights for all editors
- Updated CodeMirror library to 2.33
- Updated CSS to work with new version of CodeMirror
- Fixed issue with media button toolbar not inserting shortcodes/content when in visual mode
- Fixed issue with blockquote QuickTag inserting twice
Download this release
Release Info
| Developer | benjaminprojas |
| Plugin | |
| Version | 1.1.0.2 |
| Comparing to | |
| See all releases | |
Code changes from version 1.1.0.1 to 1.1.0.2
- classes/WPEditorPosts.php +4 -1
- extensions/codemirror/codemirror.css +30 -0
- extensions/codemirror/js/codemirror.js +1079 -603
- js/posts-jquery.js +29 -17
- js/wpeditor.js +1 -1
- readme.txt +14 -1
- views/plugin-editor.php +13 -0
- views/settings.php +144 -0
- views/theme-editor.php +13 -1
- wpeditor.php +2 -2
classes/WPEditorPosts.php
CHANGED
|
@@ -13,7 +13,10 @@ class WPEditorPosts {
|
|
| 13 |
'lineWrapping' => WPEditorSetting::getValue('enable_post_line_wrapping') == 1 ? true : false,
|
| 14 |
'enterImgUrl' => __('Enter the URL of the image:', 'wpeditor'),
|
| 15 |
'enterImgDescription' => __('Enter a description of the image:', 'wpeditor'),
|
| 16 |
-
'lookupWord' => __('Enter a word to look up:', 'wpeditor')
|
|
|
|
|
|
|
|
|
|
| 17 |
);
|
| 18 |
wp_enqueue_script('wp-editor-posts-jquery');
|
| 19 |
wp_localize_script('wp-editor-posts-jquery', 'WPEPosts', $post_editor_settings);
|
| 13 |
'lineWrapping' => WPEditorSetting::getValue('enable_post_line_wrapping') == 1 ? true : false,
|
| 14 |
'enterImgUrl' => __('Enter the URL of the image:', 'wpeditor'),
|
| 15 |
'enterImgDescription' => __('Enter a description of the image:', 'wpeditor'),
|
| 16 |
+
'lookupWord' => __('Enter a word to look up:', 'wpeditor'),
|
| 17 |
+
'tabSize' => WPEditorSetting::getValue('enable_post_tab_size') ? WPEditorSetting::getValue('enable_post_tab_size') : 4,
|
| 18 |
+
'indentWithTabs' => WPEditorSetting::getValue('enable_post_tab_size') == 'tabs' ? true : false,
|
| 19 |
+
'editorHeight' => WPEditorSetting::getValue('enable_post_editor_height') ? WPEditorSetting::getValue('enable_post_editor_height') : false
|
| 20 |
);
|
| 21 |
wp_enqueue_script('wp-editor-posts-jquery');
|
| 22 |
wp_localize_script('wp-editor-posts-jquery', 'WPEPosts', $post_editor_settings);
|
extensions/codemirror/codemirror.css
CHANGED
|
@@ -43,6 +43,36 @@ background-image: linear-gradient(bottom,#E3E3E3,white);
|
|
| 43 |
is visible outside of the scrolling box. */
|
| 44 |
position: relative;
|
| 45 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
.CodeMirror-fullscreen {
|
| 47 |
display:block;
|
| 48 |
position:fixed !important;
|
| 43 |
is visible outside of the scrolling box. */
|
| 44 |
position: relative;
|
| 45 |
}
|
| 46 |
+
|
| 47 |
+
/* Vertical scrollbar */
|
| 48 |
+
.CodeMirror-scrollbar {
|
| 49 |
+
position: absolute;
|
| 50 |
+
right: 0; top: 0;
|
| 51 |
+
overflow-x: hidden;
|
| 52 |
+
overflow-y: scroll;
|
| 53 |
+
z-index: 5;
|
| 54 |
+
}
|
| 55 |
+
.CodeMirror-scrollbar-inner {
|
| 56 |
+
/* This needs to have a nonzero width in order for the scrollbar to appear
|
| 57 |
+
in Firefox and IE9. */
|
| 58 |
+
width: 1px;
|
| 59 |
+
}
|
| 60 |
+
.CodeMirror-scrollbar.cm-sb-overlap {
|
| 61 |
+
/* Ensure that the scrollbar appears in Lion, and that it overlaps the content
|
| 62 |
+
rather than sitting to the right of it. */
|
| 63 |
+
position: absolute;
|
| 64 |
+
z-index: 1;
|
| 65 |
+
float: none;
|
| 66 |
+
right: 0;
|
| 67 |
+
min-width: 12px;
|
| 68 |
+
}
|
| 69 |
+
.CodeMirror-scrollbar.cm-sb-nonoverlap {
|
| 70 |
+
min-width: 12px;
|
| 71 |
+
}
|
| 72 |
+
.CodeMirror-scrollbar.cm-sb-ie7 {
|
| 73 |
+
min-width: 18px;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
.CodeMirror-fullscreen {
|
| 77 |
display:block;
|
| 78 |
position:fixed !important;
|
extensions/codemirror/js/codemirror.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
| 1 |
-
// CodeMirror version 2.
|
| 2 |
//
|
| 3 |
// All functions that need access to the editor's state live inside
|
| 4 |
// the CodeMirror function. Below that, at the bottom of the file,
|
| 5 |
// some utilities are defined.
|
| 6 |
|
| 7 |
// CodeMirror is the only global var we claim
|
| 8 |
-
|
| 9 |
-
|
|
|
|
| 10 |
// closure is used to store the editor state.
|
| 11 |
function CodeMirror(place, givenOptions) {
|
| 12 |
// Determine effective options based on given values and defaults.
|
|
@@ -15,42 +16,55 @@ var CodeMirror = (function() {
|
|
| 15 |
if (defaults.hasOwnProperty(opt))
|
| 16 |
options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
|
| 17 |
|
| 18 |
-
var
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
// The element in which the editor lives.
|
| 20 |
-
var wrapper =
|
| 21 |
-
wrapper.className = "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : "");
|
| 22 |
-
// This mess creates the base DOM structure for the editor.
|
| 23 |
-
wrapper.innerHTML =
|
| 24 |
-
'<div style="overflow: hidden; position: relative; width: 3px; height: 0px;">' + // Wraps and hides input textarea
|
| 25 |
-
'<textarea style="position: absolute; padding: 0; width: 1px;" wrap="off" ' +
|
| 26 |
-
'autocorrect="off" autocapitalize="off"></textarea></div>' +
|
| 27 |
-
'<div class="CodeMirror-scroll" tabindex="-1">' +
|
| 28 |
-
'<div style="position: relative">' + // Set to the height of the text, causes scrolling
|
| 29 |
-
'<div style="position: relative">' + // Moved around its parent to cover visible view
|
| 30 |
-
'<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
|
| 31 |
-
// Provides positioning relative to (visible) text origin
|
| 32 |
-
'<div class="CodeMirror-lines"><div style="position: relative">' +
|
| 33 |
-
'<div style="position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden"></div>' +
|
| 34 |
-
'<pre class="CodeMirror-cursor"> </pre>' + // Absolutely positioned blinky cursor
|
| 35 |
-
'<div></div>' + // This DIV contains the actual code
|
| 36 |
-
'</div></div></div></div></div>';
|
| 37 |
if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
scroller = wrapper.lastChild, code = scroller.firstChild,
|
| 41 |
-
mover = code.firstChild, gutter = mover.firstChild, gutterText = gutter.firstChild,
|
| 42 |
-
lineSpace = gutter.nextSibling.firstChild, measure = lineSpace.firstChild,
|
| 43 |
-
cursor = measure.nextSibling, lineDiv = cursor.nextSibling;
|
| 44 |
-
themeChanged();
|
| 45 |
// Needed to hide big blue blinking cursor on Mobile Safari
|
| 46 |
-
if (
|
| 47 |
-
if (!webkit)
|
|
|
|
| 48 |
if (options.tabindex != null) input.tabIndex = options.tabindex;
|
|
|
|
| 49 |
if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
// Check for problem with IE innerHTML not working when we have a
|
| 52 |
// P (or similar) parent node.
|
| 53 |
-
try {
|
| 54 |
catch (e) {
|
| 55 |
if (e.message.match(/runtime/i))
|
| 56 |
e = new Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)");
|
|
@@ -71,19 +85,23 @@ var CodeMirror = (function() {
|
|
| 71 |
var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
|
| 72 |
// Selection-related flags. shiftSelecting obviously tracks
|
| 73 |
// whether the user is holding shift.
|
| 74 |
-
var shiftSelecting, lastClick, lastDoubleClick,
|
|
|
|
| 75 |
// Variables used by startOperation/endOperation to track what
|
| 76 |
// happened during the operation.
|
| 77 |
var updateInput, userSelChange, changes, textChanged, selectionChanged, leaveInputAlone,
|
| 78 |
gutterDirty, callbacks;
|
| 79 |
// Current visible range (may be bigger than the view window).
|
| 80 |
var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0;
|
| 81 |
-
// bracketHighlighted is used to remember that a
|
| 82 |
// marked.
|
| 83 |
var bracketHighlighted;
|
| 84 |
// Tracks the maximum line length so that the horizontal scrollbar
|
| 85 |
// can be kept static when scrolling.
|
| 86 |
-
var maxLine =
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
// Initialize the content.
|
| 89 |
operation(function(){setValue(options.value || ""); updateInput = false;})();
|
|
@@ -92,18 +110,18 @@ var CodeMirror = (function() {
|
|
| 92 |
// Register our event handlers.
|
| 93 |
connect(scroller, "mousedown", operation(onMouseDown));
|
| 94 |
connect(scroller, "dblclick", operation(onDoubleClick));
|
| 95 |
-
connect(lineSpace, "dragstart", onDragStart);
|
| 96 |
connect(lineSpace, "selectstart", e_preventDefault);
|
| 97 |
// Gecko browsers fire contextmenu *after* opening the menu, at
|
| 98 |
// which point we can't mess with it anymore. Context menu is
|
| 99 |
// handled in onMouseDown for Gecko.
|
| 100 |
if (!gecko) connect(scroller, "contextmenu", onContextMenu);
|
| 101 |
-
connect(scroller, "scroll",
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
|
|
|
| 107 |
connect(input, "keyup", operation(onKeyUp));
|
| 108 |
connect(input, "input", fastPoll);
|
| 109 |
connect(input, "keydown", operation(onKeyDown));
|
|
@@ -111,17 +129,32 @@ var CodeMirror = (function() {
|
|
| 111 |
connect(input, "focus", onFocus);
|
| 112 |
connect(input, "blur", onBlur);
|
| 113 |
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
connect(scroller, "paste", function(){focusInput(); fastPoll();});
|
| 118 |
connect(input, "paste", fastPoll);
|
| 119 |
-
connect(input, "cut", operation(function(){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
|
| 121 |
// IE throws unspecified error in certain cases, when
|
| 122 |
// trying to access activeElement before onload
|
| 123 |
-
var hasFocus; try { hasFocus = (
|
| 124 |
-
if (hasFocus) setTimeout(onFocus, 20);
|
| 125 |
else onBlur();
|
| 126 |
|
| 127 |
function isLine(l) {return l >= 0 && l < doc.size;}
|
|
@@ -135,47 +168,71 @@ var CodeMirror = (function() {
|
|
| 135 |
setValue: operation(setValue),
|
| 136 |
getSelection: getSelection,
|
| 137 |
replaceSelection: operation(replaceSelection),
|
| 138 |
-
focus: function(){focusInput(); onFocus(); fastPoll();},
|
| 139 |
setOption: function(option, value) {
|
| 140 |
var oldVal = options[option];
|
| 141 |
options[option] = value;
|
| 142 |
if (option == "mode" || option == "indentUnit") loadMode();
|
| 143 |
-
else if (option == "readOnly" && value) {onBlur(); input.blur();}
|
|
|
|
| 144 |
else if (option == "theme") themeChanged();
|
| 145 |
else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
|
| 146 |
-
else if (option == "tabSize")
|
| 147 |
-
if (option == "
|
| 148 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
},
|
| 150 |
getOption: function(option) {return options[option];},
|
| 151 |
undo: operation(undo),
|
| 152 |
redo: operation(redo),
|
| 153 |
indentLine: operation(function(n, dir) {
|
| 154 |
-
if (
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
}),
|
| 156 |
indentSelection: operation(indentSelected),
|
| 157 |
historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
|
| 158 |
clearHistory: function() {history = new History();},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
matchBrackets: operation(function(){matchBrackets(true);}),
|
| 160 |
getTokenAt: operation(function(pos) {
|
| 161 |
pos = clipPos(pos);
|
| 162 |
-
return getLine(pos.line).getTokenAt(mode, getStateBefore(pos.line), pos.ch);
|
| 163 |
}),
|
| 164 |
getStateAfter: function(line) {
|
| 165 |
line = clipLine(line == null ? doc.size - 1: line);
|
| 166 |
return getStateBefore(line + 1);
|
| 167 |
},
|
| 168 |
-
cursorCoords: function(start){
|
| 169 |
if (start == null) start = sel.inverted;
|
| 170 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
},
|
| 172 |
-
charCoords: function(pos){return pageCoords(clipPos(pos));},
|
| 173 |
coordsChar: function(coords) {
|
| 174 |
var off = eltOffset(lineSpace);
|
| 175 |
return coordsChar(coords.x - off.left, coords.y - off.top);
|
| 176 |
},
|
| 177 |
markText: operation(markText),
|
| 178 |
setBookmark: setBookmark,
|
|
|
|
| 179 |
setMarker: operation(addGutterMarker),
|
| 180 |
clearMarker: operation(removeGutterMarker),
|
| 181 |
setLineClass: operation(setLineClass),
|
|
@@ -190,15 +247,16 @@ var CodeMirror = (function() {
|
|
| 190 |
return line;
|
| 191 |
},
|
| 192 |
lineInfo: lineInfo,
|
|
|
|
| 193 |
addWidget: function(pos, node, scroll, vert, horiz) {
|
| 194 |
pos = localCoords(clipPos(pos));
|
| 195 |
var top = pos.yBot, left = pos.x;
|
| 196 |
node.style.position = "absolute";
|
| 197 |
-
|
| 198 |
if (vert == "over") top = pos.y;
|
| 199 |
else if (vert == "near") {
|
| 200 |
var vspace = Math.max(scroller.offsetHeight, doc.height * textHeight()),
|
| 201 |
-
hspace = Math.max(
|
| 202 |
if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight)
|
| 203 |
top = pos.y - node.offsetHeight;
|
| 204 |
if (left + node.offsetWidth > hspace)
|
|
@@ -207,11 +265,11 @@ var CodeMirror = (function() {
|
|
| 207 |
node.style.top = (top + paddingTop()) + "px";
|
| 208 |
node.style.left = node.style.right = "";
|
| 209 |
if (horiz == "right") {
|
| 210 |
-
left =
|
| 211 |
node.style.right = "0px";
|
| 212 |
} else {
|
| 213 |
if (horiz == "left") left = 0;
|
| 214 |
-
else if (horiz == "middle") left = (
|
| 215 |
node.style.left = (left + paddingLeft()) + "px";
|
| 216 |
}
|
| 217 |
if (scroll)
|
|
@@ -241,14 +299,23 @@ var CodeMirror = (function() {
|
|
| 241 |
if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
|
| 242 |
}),
|
| 243 |
replaceRange: operation(replaceRange),
|
| 244 |
-
getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
|
| 245 |
|
|
|
|
| 246 |
execCommand: function(cmd) {return commands[cmd](instance);},
|
| 247 |
// Stuff used by commands, probably not much use to outside code.
|
| 248 |
moveH: operation(moveH),
|
| 249 |
deleteH: operation(deleteH),
|
| 250 |
moveV: operation(moveV),
|
| 251 |
-
toggleOverwrite: function() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 252 |
|
| 253 |
posFromIndex: function(off) {
|
| 254 |
var lineNo = 0, ch;
|
|
@@ -268,9 +335,32 @@ var CodeMirror = (function() {
|
|
| 268 |
});
|
| 269 |
return index;
|
| 270 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 271 |
|
| 272 |
operation: function(f){return operation(f)();},
|
| 273 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 274 |
getInputField: function(){return input;},
|
| 275 |
getWrapperElement: function(){return wrapper;},
|
| 276 |
getScrollerElement: function(){return scroller;},
|
|
@@ -290,17 +380,36 @@ var CodeMirror = (function() {
|
|
| 290 |
splitLines(code), top, top);
|
| 291 |
updateInput = true;
|
| 292 |
}
|
| 293 |
-
function getValue(
|
| 294 |
var text = [];
|
| 295 |
doc.iter(0, doc.size, function(line) { text.push(line.text); });
|
| 296 |
-
return text.join("\n");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 297 |
}
|
| 298 |
|
| 299 |
function onMouseDown(e) {
|
| 300 |
-
setShift(e
|
| 301 |
// Check whether this is a click in a widget
|
| 302 |
for (var n = e_target(e); n != wrapper; n = n.parentNode)
|
| 303 |
-
if (n.parentNode ==
|
| 304 |
|
| 305 |
// See if this is a click in the gutter
|
| 306 |
for (var n = e_target(e); n != wrapper; n = n.parentNode)
|
|
@@ -314,10 +423,12 @@ var CodeMirror = (function() {
|
|
| 314 |
|
| 315 |
switch (e_button(e)) {
|
| 316 |
case 3:
|
| 317 |
-
if (gecko
|
| 318 |
return;
|
| 319 |
case 2:
|
| 320 |
if (start) setCursor(start.line, start.ch, true);
|
|
|
|
|
|
|
| 321 |
return;
|
| 322 |
}
|
| 323 |
// For button 1, if it was clicked inside the editor
|
|
@@ -327,44 +438,66 @@ var CodeMirror = (function() {
|
|
| 327 |
|
| 328 |
if (!focused) onFocus();
|
| 329 |
|
| 330 |
-
var now = +new Date;
|
| 331 |
if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) {
|
|
|
|
| 332 |
e_preventDefault(e);
|
| 333 |
setTimeout(focusInput, 20);
|
| 334 |
-
|
| 335 |
} else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) {
|
|
|
|
| 336 |
lastDoubleClick = {time: now, pos: start};
|
| 337 |
e_preventDefault(e);
|
| 338 |
-
|
|
|
|
| 339 |
} else { lastClick = {time: now, pos: start}; }
|
| 340 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 341 |
var last = start, going;
|
| 342 |
-
if (dragAndDrop && !posEq(sel.from, sel.to) &&
|
| 343 |
-
!posLess(start, sel.from) && !posLess(sel.to, start)) {
|
| 344 |
// Let the drag handler handle this.
|
| 345 |
-
if (webkit)
|
| 346 |
-
var up = connect(
|
| 347 |
-
|
| 348 |
-
draggingText = false;
|
| 349 |
-
up();
|
| 350 |
-
if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
|
| 351 |
-
e_preventDefault(e2);
|
| 352 |
-
setCursor(start.line, start.ch, true);
|
| 353 |
-
focusInput();
|
| 354 |
-
}
|
| 355 |
-
}), true);
|
| 356 |
draggingText = true;
|
|
|
|
|
|
|
| 357 |
return;
|
| 358 |
}
|
| 359 |
e_preventDefault(e);
|
| 360 |
-
setCursor(start.line, start.ch, true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 361 |
|
| 362 |
function extend(e) {
|
| 363 |
var cur = posFromMouse(e, true);
|
| 364 |
if (cur && !posEq(cur, last)) {
|
| 365 |
if (!focused) onFocus();
|
| 366 |
last = cur;
|
| 367 |
-
|
| 368 |
updateInput = false;
|
| 369 |
var visible = visibleLines();
|
| 370 |
if (cur.line >= visible.to || cur.line < visible.from)
|
|
@@ -372,36 +505,36 @@ var CodeMirror = (function() {
|
|
| 372 |
}
|
| 373 |
}
|
| 374 |
|
| 375 |
-
|
| 376 |
-
clearTimeout(going);
|
| 377 |
-
e_preventDefault(e);
|
| 378 |
-
extend(e);
|
| 379 |
-
}), true);
|
| 380 |
-
var up = connect(targetDocument, "mouseup", operation(function(e) {
|
| 381 |
clearTimeout(going);
|
| 382 |
var cur = posFromMouse(e);
|
| 383 |
-
if (cur)
|
| 384 |
e_preventDefault(e);
|
| 385 |
focusInput();
|
| 386 |
updateInput = true;
|
| 387 |
move(); up();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 388 |
}), true);
|
|
|
|
| 389 |
}
|
| 390 |
function onDoubleClick(e) {
|
| 391 |
for (var n = e_target(e); n != wrapper; n = n.parentNode)
|
| 392 |
if (n.parentNode == gutterText) return e_preventDefault(e);
|
| 393 |
-
var start = posFromMouse(e);
|
| 394 |
-
if (!start) return;
|
| 395 |
-
lastDoubleClick = {time: +new Date, pos: start};
|
| 396 |
e_preventDefault(e);
|
| 397 |
-
selectWordAt(start);
|
| 398 |
}
|
| 399 |
function onDrop(e) {
|
| 400 |
-
|
|
|
|
| 401 |
var pos = posFromMouse(e, true), files = e.dataTransfer.files;
|
| 402 |
if (!pos || options.readOnly) return;
|
| 403 |
if (files && files.length && window.FileReader && window.File) {
|
| 404 |
-
|
|
|
|
| 405 |
var reader = new FileReader;
|
| 406 |
reader.onload = function() {
|
| 407 |
text[i] = reader.result;
|
|
@@ -414,19 +547,21 @@ var CodeMirror = (function() {
|
|
| 414 |
}
|
| 415 |
};
|
| 416 |
reader.readAsText(file);
|
| 417 |
-
}
|
| 418 |
-
var n = files.length, text = Array(n), read = 0;
|
| 419 |
for (var i = 0; i < n; ++i) loadFile(files[i], i);
|
| 420 |
-
}
|
| 421 |
-
|
|
|
|
| 422 |
try {
|
| 423 |
var text = e.dataTransfer.getData("Text");
|
| 424 |
if (text) {
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
|
|
|
|
|
|
| 430 |
}
|
| 431 |
}
|
| 432 |
catch(e){}
|
|
@@ -434,80 +569,126 @@ var CodeMirror = (function() {
|
|
| 434 |
}
|
| 435 |
function onDragStart(e) {
|
| 436 |
var txt = getSelection();
|
| 437 |
-
// This will reset escapeElement
|
| 438 |
-
htmlEscape(txt);
|
| 439 |
-
e.dataTransfer.setDragImage(escapeElement, 0, 0);
|
| 440 |
e.dataTransfer.setData("Text", txt);
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
}
|
| 448 |
-
if (e.altKey) name = "Alt-" + name;
|
| 449 |
-
if (e.ctrlKey) name = "Ctrl-" + name;
|
| 450 |
-
if (e.metaKey) name = "Cmd-" + name;
|
| 451 |
-
if (e.shiftKey && (bound = lookupKey("Shift-" + name, options.extraKeys, options.keyMap))) {
|
| 452 |
-
dropShift = true;
|
| 453 |
-
} else {
|
| 454 |
-
bound = lookupKey(name, options.extraKeys, options.keyMap);
|
| 455 |
}
|
|
|
|
|
|
|
|
|
|
| 456 |
if (typeof bound == "string") {
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
}
|
| 460 |
-
|
| 461 |
-
|
| 462 |
-
|
| 463 |
-
|
| 464 |
-
shiftSelecting = null;
|
| 465 |
bound(instance);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 466 |
shiftSelecting = prevShift;
|
| 467 |
-
|
| 468 |
-
|
| 469 |
return true;
|
| 470 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 471 |
var lastStoppedKey = null;
|
| 472 |
function onKeyDown(e) {
|
| 473 |
if (!focused) onFocus();
|
| 474 |
-
|
|
|
|
|
|
|
|
|
|
| 475 |
// IE does strange things with escape.
|
| 476 |
-
|
| 477 |
-
setShift(code == 16 || e.shiftKey);
|
| 478 |
// First give onKeyEvent option a chance to handle this.
|
| 479 |
-
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
| 480 |
var handled = handleKeyBinding(e);
|
| 481 |
-
if (
|
| 482 |
-
lastStoppedKey = handled ?
|
| 483 |
// Opera has no cut event... we try to at least catch the key combo
|
| 484 |
-
if (!handled && (mac ?
|
| 485 |
replaceSelection("");
|
| 486 |
}
|
| 487 |
}
|
| 488 |
function onKeyPress(e) {
|
| 489 |
-
if (
|
| 490 |
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
| 491 |
-
|
| 492 |
-
if (
|
| 493 |
-
|
|
|
|
|
|
|
| 494 |
if (mode.electricChars.indexOf(ch) > -1)
|
| 495 |
setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75);
|
| 496 |
}
|
|
|
|
| 497 |
fastPoll();
|
| 498 |
}
|
| 499 |
function onKeyUp(e) {
|
| 500 |
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
| 501 |
-
if (e
|
| 502 |
}
|
| 503 |
|
| 504 |
function onFocus() {
|
| 505 |
-
if (options.readOnly) return;
|
| 506 |
if (!focused) {
|
| 507 |
if (options.onFocus) options.onFocus(instance);
|
| 508 |
focused = true;
|
| 509 |
-
if (
|
| 510 |
-
|
| 511 |
if (!leaveInputAlone) resetInput(true);
|
| 512 |
}
|
| 513 |
slowPoll();
|
|
@@ -517,7 +698,11 @@ var CodeMirror = (function() {
|
|
| 517 |
if (focused) {
|
| 518 |
if (options.onBlur) options.onBlur(instance);
|
| 519 |
focused = false;
|
| 520 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 521 |
}
|
| 522 |
clearInterval(blinker);
|
| 523 |
setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
|
|
@@ -526,6 +711,7 @@ var CodeMirror = (function() {
|
|
| 526 |
// Replace the range from from to to by the strings in newText.
|
| 527 |
// Afterwards, set the selection to selFrom, selTo.
|
| 528 |
function updateLines(from, to, newText, selFrom, selTo) {
|
|
|
|
| 529 |
if (history) {
|
| 530 |
var old = [];
|
| 531 |
doc.iter(from.line, to.line + 1, function(line) { old.push(line.text); });
|
|
@@ -535,25 +721,29 @@ var CodeMirror = (function() {
|
|
| 535 |
updateLinesNoUndo(from, to, newText, selFrom, selTo);
|
| 536 |
}
|
| 537 |
function unredoHelper(from, to) {
|
| 538 |
-
|
| 539 |
-
|
|
|
|
|
|
|
| 540 |
var replaced = [], end = change.start + change.added;
|
| 541 |
doc.iter(change.start, end, function(line) { replaced.push(line.text); });
|
| 542 |
-
|
| 543 |
-
var pos =
|
| 544 |
-
|
| 545 |
updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos);
|
| 546 |
-
updateInput = true;
|
| 547 |
}
|
|
|
|
|
|
|
| 548 |
}
|
| 549 |
function undo() {unredoHelper(history.done, history.undone);}
|
| 550 |
function redo() {unredoHelper(history.undone, history.done);}
|
| 551 |
|
| 552 |
function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
|
| 553 |
-
|
|
|
|
| 554 |
if (!options.lineWrapping)
|
| 555 |
-
doc.iter(from.line, to.line, function(line) {
|
| 556 |
-
if (line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
|
| 557 |
});
|
| 558 |
if (from.line != to.line || newText.length > 1) gutterDirty = true;
|
| 559 |
|
|
@@ -600,29 +790,21 @@ var CodeMirror = (function() {
|
|
| 600 |
doc.insert(from.line + 1, added);
|
| 601 |
}
|
| 602 |
if (options.lineWrapping) {
|
| 603 |
-
var perLine = scroller.clientWidth / charWidth() - 3;
|
| 604 |
doc.iter(from.line, from.line + newText.length, function(line) {
|
| 605 |
if (line.hidden) return;
|
| 606 |
var guess = Math.ceil(line.text.length / perLine) || 1;
|
| 607 |
if (guess != line.height) updateLineHeight(line, guess);
|
| 608 |
});
|
| 609 |
} else {
|
| 610 |
-
doc.iter(from.line,
|
| 611 |
var l = line.text;
|
| 612 |
-
if (l.length > maxLineLength) {
|
| 613 |
-
maxLine =
|
| 614 |
recomputeMaxLength = false;
|
| 615 |
}
|
| 616 |
});
|
| 617 |
-
if (recomputeMaxLength)
|
| 618 |
-
maxLineLength = 0; maxLine = ""; maxWidth = null;
|
| 619 |
-
doc.iter(0, doc.size, function(line) {
|
| 620 |
-
var l = line.text;
|
| 621 |
-
if (l.length > maxLineLength) {
|
| 622 |
-
maxLineLength = l.length; maxLine = l;
|
| 623 |
-
}
|
| 624 |
-
});
|
| 625 |
-
}
|
| 626 |
}
|
| 627 |
|
| 628 |
// Add these lines to the work array, so that they will be
|
|
@@ -648,10 +830,52 @@ var CodeMirror = (function() {
|
|
| 648 |
|
| 649 |
// Update the selection
|
| 650 |
function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
|
| 651 |
-
setSelection(selFrom, selTo
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 652 |
|
| 653 |
-
|
| 654 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 655 |
}
|
| 656 |
|
| 657 |
function replaceRange(code, from, to) {
|
|
@@ -687,19 +911,18 @@ var CodeMirror = (function() {
|
|
| 687 |
updateLines(from, to, code, newSel.from, newSel.to);
|
| 688 |
}
|
| 689 |
|
| 690 |
-
function getRange(from, to) {
|
| 691 |
var l1 = from.line, l2 = to.line;
|
| 692 |
if (l1 == l2) return getLine(l1).text.slice(from.ch, to.ch);
|
| 693 |
var code = [getLine(l1).text.slice(from.ch)];
|
| 694 |
doc.iter(l1 + 1, l2, function(line) { code.push(line.text); });
|
| 695 |
code.push(getLine(l2).text.slice(0, to.ch));
|
| 696 |
-
return code.join("\n");
|
| 697 |
}
|
| 698 |
-
function getSelection() {
|
| 699 |
-
return getRange(sel.from, sel.to);
|
| 700 |
}
|
| 701 |
|
| 702 |
-
var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
|
| 703 |
function slowPoll() {
|
| 704 |
if (pollingFast) return;
|
| 705 |
poll.set(options.pollInterval, function() {
|
|
@@ -729,7 +952,7 @@ var CodeMirror = (function() {
|
|
| 729 |
// supported or compatible enough yet to rely on.)
|
| 730 |
var prevInput = "";
|
| 731 |
function readInput() {
|
| 732 |
-
if (leaveInputAlone || !focused || hasSelection(input)) return false;
|
| 733 |
var text = input.value;
|
| 734 |
if (text == prevInput) return false;
|
| 735 |
shiftSelecting = null;
|
|
@@ -740,76 +963,95 @@ var CodeMirror = (function() {
|
|
| 740 |
else if (overwrite && posEq(sel.from, sel.to))
|
| 741 |
sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))};
|
| 742 |
replaceSelection(text.slice(same), "end");
|
| 743 |
-
prevInput =
|
|
|
|
| 744 |
return true;
|
| 745 |
}
|
| 746 |
function resetInput(user) {
|
| 747 |
if (!posEq(sel.from, sel.to)) {
|
| 748 |
prevInput = "";
|
| 749 |
input.value = getSelection();
|
| 750 |
-
|
| 751 |
} else if (user) prevInput = input.value = "";
|
| 752 |
}
|
| 753 |
|
| 754 |
function focusInput() {
|
| 755 |
-
if (
|
| 756 |
}
|
| 757 |
|
| 758 |
-
function scrollEditorIntoView() {
|
| 759 |
-
if (!cursor.getBoundingClientRect) return;
|
| 760 |
-
var rect = cursor.getBoundingClientRect();
|
| 761 |
-
// IE returns bogus coordinates when the instance sits inside of an iframe and the cursor is hidden
|
| 762 |
-
if (ie && rect.top == rect.bottom) return;
|
| 763 |
-
var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
|
| 764 |
-
if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView();
|
| 765 |
-
}
|
| 766 |
function scrollCursorIntoView() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 767 |
var cursor = localCoords(sel.inverted ? sel.from : sel.to);
|
| 768 |
var x = options.lineWrapping ? Math.min(cursor.x, lineSpace.offsetWidth) : cursor.x;
|
| 769 |
-
return
|
| 770 |
}
|
| 771 |
function scrollIntoView(x1, y1, x2, y2) {
|
| 772 |
-
var
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 773 |
y1 += pt; y2 += pt; x1 += pl; x2 += pl;
|
| 774 |
-
var screen = scroller.clientHeight, screentop =
|
| 775 |
-
|
| 776 |
-
|
|
|
|
|
|
|
| 777 |
|
| 778 |
var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
|
| 779 |
var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
|
| 780 |
-
|
| 781 |
-
|
| 782 |
-
|
| 783 |
-
|
|
|
|
|
|
|
| 784 |
}
|
| 785 |
-
else if (x2 > screenw + screenleft - 3) {
|
| 786 |
-
scroller.scrollLeft = x2 + 10 - screenw;
|
| 787 |
-
scrolled = true;
|
| 788 |
-
if (x2 > code.clientWidth) result = false;
|
| 789 |
-
}
|
| 790 |
-
if (scrolled && options.onScroll) options.onScroll(instance);
|
| 791 |
return result;
|
| 792 |
}
|
| 793 |
|
| 794 |
-
function visibleLines() {
|
| 795 |
-
var lh = textHeight(), top =
|
| 796 |
-
var
|
| 797 |
-
var
|
| 798 |
-
return {from: lineAtHeight(doc,
|
| 799 |
-
to: lineAtHeight(doc,
|
| 800 |
}
|
| 801 |
// Uses a set of changes plus the current scroll position to
|
| 802 |
// determine which DOM updates have to be made, and makes the
|
| 803 |
// updates.
|
| 804 |
-
function updateDisplay(changes, suppressCallback) {
|
| 805 |
if (!scroller.clientWidth) {
|
| 806 |
showingFrom = showingTo = displayOffset = 0;
|
| 807 |
return;
|
| 808 |
}
|
| 809 |
// Compute the new visible window
|
| 810 |
-
|
|
|
|
|
|
|
| 811 |
// Bail out if the visible area is already rendered and nothing changed.
|
| 812 |
-
if (changes !== true && changes.length == 0 && visible.from
|
|
|
|
|
|
|
|
|
|
| 813 |
var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100);
|
| 814 |
if (showingFrom < from && from - showingFrom < 20) from = showingFrom;
|
| 815 |
if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo);
|
|
@@ -827,24 +1069,27 @@ var CodeMirror = (function() {
|
|
| 827 |
if (range.from >= range.to) intact.splice(i--, 1);
|
| 828 |
else intactLines += range.to - range.from;
|
| 829 |
}
|
| 830 |
-
if (intactLines == to - from)
|
|
|
|
|
|
|
|
|
|
| 831 |
intact.sort(function(a, b) {return a.domStart - b.domStart;});
|
| 832 |
|
| 833 |
var th = textHeight(), gutterDisplay = gutter.style.display;
|
| 834 |
-
lineDiv.style.display =
|
| 835 |
patchDisplay(from, to, intact);
|
| 836 |
-
lineDiv.style.display = "";
|
| 837 |
|
| 838 |
-
// Position the mover div to align with the lines it's supposed
|
| 839 |
-
// to be showing (which will cover the visible display)
|
| 840 |
var different = from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight + th;
|
| 841 |
// This is just a bogus formula that detects when the editor is
|
| 842 |
// resized or the font size changes.
|
| 843 |
if (different) lastSizeC = scroller.clientHeight + th;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 844 |
showingFrom = from; showingTo = to;
|
| 845 |
displayOffset = heightAtLine(doc, from);
|
| 846 |
-
mover.style.top = (displayOffset * th) + "px";
|
| 847 |
-
code.style.height = (doc.height * th + 2 * paddingTop()) + "px";
|
| 848 |
|
| 849 |
// Since this is all rather error prone, it is honoured with the
|
| 850 |
// only assertion in the whole file.
|
|
@@ -852,30 +1097,34 @@ var CodeMirror = (function() {
|
|
| 852 |
throw new Error("BAD PATCH! " + JSON.stringify(intact) + " size=" + (showingTo - showingFrom) +
|
| 853 |
" nodes=" + lineDiv.childNodes.length);
|
| 854 |
|
| 855 |
-
|
| 856 |
-
|
| 857 |
-
var curNode = lineDiv.firstChild;
|
| 858 |
doc.iter(showingFrom, showingTo, function(line) {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 859 |
if (!line.hidden) {
|
| 860 |
var height = Math.round(curNode.offsetHeight / th) || 1;
|
| 861 |
-
if (line.height != height) {
|
|
|
|
|
|
|
|
|
|
| 862 |
}
|
| 863 |
curNode = curNode.nextSibling;
|
| 864 |
});
|
| 865 |
-
|
| 866 |
-
if (maxWidth == null) maxWidth = stringWidth(maxLine);
|
| 867 |
-
if (maxWidth > scroller.clientWidth) {
|
| 868 |
-
lineSpace.style.width = maxWidth + "px";
|
| 869 |
-
// Needed to prevent odd wrapping/hiding of widgets placed in here.
|
| 870 |
-
code.style.width = "";
|
| 871 |
-
code.style.width = scroller.scrollWidth + "px";
|
| 872 |
-
} else {
|
| 873 |
-
lineSpace.style.width = code.style.width = "";
|
| 874 |
-
}
|
| 875 |
}
|
|
|
|
|
|
|
|
|
|
| 876 |
gutter.style.display = gutterDisplay;
|
| 877 |
-
if (different || gutterDirty)
|
| 878 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 879 |
if (!suppressCallback && options.onUpdate) options.onUpdate(instance);
|
| 880 |
return true;
|
| 881 |
}
|
|
@@ -904,14 +1153,14 @@ var CodeMirror = (function() {
|
|
| 904 |
}
|
| 905 |
|
| 906 |
function patchDisplay(from, to, intact) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 907 |
// The first pass removes the DOM nodes that aren't intact.
|
| 908 |
-
if (!intact.length) lineDiv
|
| 909 |
else {
|
| 910 |
-
function killNode(node) {
|
| 911 |
-
var tmp = node.nextSibling;
|
| 912 |
-
node.parentNode.removeChild(node);
|
| 913 |
-
return tmp;
|
| 914 |
-
}
|
| 915 |
var domPos = 0, curNode = lineDiv.firstChild, n;
|
| 916 |
for (var i = 0; i < intact.length; ++i) {
|
| 917 |
var cur = intact[i];
|
|
@@ -922,22 +1171,20 @@ var CodeMirror = (function() {
|
|
| 922 |
}
|
| 923 |
// This pass fills in the lines that actually changed.
|
| 924 |
var nextIntact = intact.shift(), curNode = lineDiv.firstChild, j = from;
|
| 925 |
-
var sfrom = sel.from.line, sto = sel.to.line, inSel = sfrom < from && sto >= from;
|
| 926 |
-
var scratch = targetDocument.createElement("div"), newElt;
|
| 927 |
doc.iter(from, to, function(line) {
|
| 928 |
-
var ch1 = null, ch2 = null;
|
| 929 |
-
if (inSel) {
|
| 930 |
-
ch1 = 0;
|
| 931 |
-
if (sto == j) {inSel = false; ch2 = sel.to.ch;}
|
| 932 |
-
} else if (sfrom == j) {
|
| 933 |
-
if (sto == j) {ch1 = sel.from.ch; ch2 = sel.to.ch;}
|
| 934 |
-
else {inSel = true; ch1 = sel.from.ch;}
|
| 935 |
-
}
|
| 936 |
if (nextIntact && nextIntact.to == j) nextIntact = intact.shift();
|
| 937 |
if (!nextIntact || nextIntact.from > j) {
|
| 938 |
-
if (line.hidden)
|
| 939 |
-
else
|
| 940 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 941 |
} else {
|
| 942 |
curNode = curNode.nextSibling;
|
| 943 |
}
|
|
@@ -949,44 +1196,79 @@ var CodeMirror = (function() {
|
|
| 949 |
if (!options.gutter && !options.lineNumbers) return;
|
| 950 |
var hText = mover.offsetHeight, hEditor = scroller.clientHeight;
|
| 951 |
gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px";
|
| 952 |
-
var
|
| 953 |
doc.iter(showingFrom, Math.max(showingTo, showingFrom + 1), function(line) {
|
| 954 |
if (line.hidden) {
|
| 955 |
-
|
| 956 |
} else {
|
| 957 |
var marker = line.gutterMarker;
|
| 958 |
-
var text = options.lineNumbers ? i + options.firstLineNumber : null;
|
| 959 |
if (marker && marker.text)
|
| 960 |
text = marker.text.replace("%N%", text != null ? text : "");
|
| 961 |
else if (text == null)
|
| 962 |
text = "\u00a0";
|
| 963 |
-
|
| 964 |
-
|
| 965 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 966 |
}
|
| 967 |
++i;
|
| 968 |
});
|
| 969 |
gutter.style.display = "none";
|
| 970 |
-
gutterText
|
| 971 |
-
|
| 972 |
-
|
| 973 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 974 |
gutter.style.display = "";
|
|
|
|
| 975 |
lineSpace.style.marginLeft = gutter.offsetWidth + "px";
|
| 976 |
gutterDirty = false;
|
|
|
|
| 977 |
}
|
| 978 |
-
function
|
| 979 |
-
var
|
| 980 |
-
var
|
|
|
|
|
|
|
| 981 |
var wrapOff = eltOffset(wrapper), lineOff = eltOffset(lineDiv);
|
| 982 |
-
inputDiv.style.top = (
|
| 983 |
-
inputDiv.style.left = (
|
| 984 |
-
if (
|
| 985 |
-
cursor.style.top =
|
| 986 |
-
cursor.style.left = (options.lineWrapping ? Math.min(
|
| 987 |
cursor.style.display = "";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 988 |
}
|
| 989 |
-
else cursor.style.display = "none";
|
| 990 |
}
|
| 991 |
|
| 992 |
function setShift(val) {
|
|
@@ -1012,37 +1294,32 @@ var CodeMirror = (function() {
|
|
| 1012 |
if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
|
| 1013 |
|
| 1014 |
// Skip over hidden lines.
|
| 1015 |
-
if (from.line != oldFrom)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1016 |
if (to.line != oldTo) to = skipHidden(to, oldTo, sel.to.ch);
|
| 1017 |
|
| 1018 |
if (posEq(from, to)) sel.inverted = false;
|
| 1019 |
else if (posEq(from, sel.to)) sel.inverted = false;
|
| 1020 |
else if (posEq(to, sel.from)) sel.inverted = true;
|
| 1021 |
|
| 1022 |
-
|
| 1023 |
-
|
| 1024 |
-
|
| 1025 |
-
|
| 1026 |
-
|
| 1027 |
-
|
| 1028 |
-
|
| 1029 |
-
|
| 1030 |
-
|
| 1031 |
-
|
| 1032 |
-
|
| 1033 |
-
if (!posEq(from, sel.from)) {
|
| 1034 |
-
if (from.line < oldFrom)
|
| 1035 |
-
changes.push({from: from.line, to: Math.min(to.line, oldFrom) + 1});
|
| 1036 |
-
else
|
| 1037 |
-
changes.push({from: oldFrom, to: Math.min(oldTo, from.line) + 1});
|
| 1038 |
-
}
|
| 1039 |
-
if (!posEq(to, sel.to)) {
|
| 1040 |
-
if (to.line < oldTo)
|
| 1041 |
-
changes.push({from: Math.max(oldFrom, from.line), to: oldTo + 1});
|
| 1042 |
-
else
|
| 1043 |
-
changes.push({from: Math.max(from.line, oldTo), to: to.line + 1});
|
| 1044 |
}
|
| 1045 |
}
|
|
|
|
| 1046 |
sel.from = from; sel.to = to;
|
| 1047 |
selectionChanged = true;
|
| 1048 |
}
|
|
@@ -1053,13 +1330,14 @@ var CodeMirror = (function() {
|
|
| 1053 |
var line = getLine(lNo);
|
| 1054 |
if (!line.hidden) {
|
| 1055 |
var ch = pos.ch;
|
| 1056 |
-
if (ch > oldCh || ch > line.text.length) ch = line.text.length;
|
| 1057 |
return {line: lNo, ch: ch};
|
| 1058 |
}
|
| 1059 |
lNo += dir;
|
| 1060 |
}
|
| 1061 |
}
|
| 1062 |
var line = getLine(pos.line);
|
|
|
|
| 1063 |
if (!line.hidden) return pos;
|
| 1064 |
if (pos.line >= oldLine) return getNonHidden(1) || getNonHidden(-1);
|
| 1065 |
else return getNonHidden(-1) || getNonHidden(1);
|
|
@@ -1119,26 +1397,37 @@ var CodeMirror = (function() {
|
|
| 1119 |
else replaceRange("", sel.from, findPosH(dir, unit));
|
| 1120 |
userSelChange = true;
|
| 1121 |
}
|
| 1122 |
-
var goalColumn = null;
|
| 1123 |
function moveV(dir, unit) {
|
| 1124 |
var dist = 0, pos = localCoords(sel.inverted ? sel.from : sel.to, true);
|
| 1125 |
if (goalColumn != null) pos.x = goalColumn;
|
| 1126 |
-
if (unit == "page")
|
| 1127 |
-
|
| 1128 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1129 |
setCursor(target.line, target.ch, true);
|
| 1130 |
goalColumn = pos.x;
|
| 1131 |
}
|
| 1132 |
|
| 1133 |
-
function
|
| 1134 |
var line = getLine(pos.line).text;
|
| 1135 |
var start = pos.ch, end = pos.ch;
|
| 1136 |
-
|
| 1137 |
-
|
| 1138 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1139 |
}
|
| 1140 |
function selectLine(line) {
|
| 1141 |
-
setSelectionUser({line: line, ch: 0}, {line: line, ch:
|
| 1142 |
}
|
| 1143 |
function indentSelected(mode) {
|
| 1144 |
if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
|
|
@@ -1155,28 +1444,26 @@ var CodeMirror = (function() {
|
|
| 1155 |
|
| 1156 |
var line = getLine(n), curSpace = line.indentation(options.tabSize),
|
| 1157 |
curSpaceString = line.text.match(/^\s*/)[0], indentation;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1158 |
if (how == "prev") {
|
| 1159 |
if (n) indentation = getLine(n-1).indentation(options.tabSize);
|
| 1160 |
else indentation = 0;
|
| 1161 |
}
|
| 1162 |
-
else if (how == "smart") indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
|
| 1163 |
else if (how == "add") indentation = curSpace + options.indentUnit;
|
| 1164 |
else if (how == "subtract") indentation = curSpace - options.indentUnit;
|
| 1165 |
indentation = Math.max(0, indentation);
|
| 1166 |
var diff = indentation - curSpace;
|
| 1167 |
|
| 1168 |
-
|
| 1169 |
-
|
| 1170 |
-
var
|
| 1171 |
-
}
|
| 1172 |
-
else {
|
| 1173 |
-
var indentString = "", pos = 0;
|
| 1174 |
-
if (options.indentWithTabs)
|
| 1175 |
-
for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
|
| 1176 |
-
while (pos < indentation) {++pos; indentString += " ";}
|
| 1177 |
-
}
|
| 1178 |
|
| 1179 |
-
|
|
|
|
| 1180 |
}
|
| 1181 |
|
| 1182 |
function loadMode() {
|
|
@@ -1200,29 +1487,32 @@ var CodeMirror = (function() {
|
|
| 1200 |
var guess = Math.ceil(line.text.length / perLine) || 1;
|
| 1201 |
if (guess != 1) updateLineHeight(line, guess);
|
| 1202 |
});
|
| 1203 |
-
lineSpace.style.
|
| 1204 |
} else {
|
| 1205 |
wrapper.className = wrapper.className.replace(" CodeMirror-wrap", "");
|
| 1206 |
-
|
| 1207 |
doc.iter(0, doc.size, function(line) {
|
| 1208 |
if (line.height != 1 && !line.hidden) updateLineHeight(line, 1);
|
| 1209 |
-
if (line.text.length > maxLine.length) maxLine = line.text;
|
| 1210 |
});
|
| 1211 |
}
|
| 1212 |
changes.push({from: 0, to: doc.size});
|
| 1213 |
}
|
| 1214 |
-
function
|
| 1215 |
-
|
| 1216 |
-
|
| 1217 |
-
|
| 1218 |
-
|
| 1219 |
-
|
| 1220 |
-
updateDisplay(true);
|
| 1221 |
}
|
| 1222 |
function themeChanged() {
|
| 1223 |
-
scroller.className = scroller.className.replace(/\s*cm-s-\
|
| 1224 |
options.theme.replace(/(^|\s)\s*/g, " cm-s-");
|
| 1225 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1226 |
|
| 1227 |
function TextMarker() { this.set = []; }
|
| 1228 |
TextMarker.prototype.clear = operation(function() {
|
|
@@ -1233,7 +1523,7 @@ var CodeMirror = (function() {
|
|
| 1233 |
var lineN = lineNo(line);
|
| 1234 |
min = Math.min(min, lineN); max = Math.max(max, lineN);
|
| 1235 |
for (var j = 0; j < mk.length; ++j)
|
| 1236 |
-
if (mk[j].
|
| 1237 |
}
|
| 1238 |
if (min != Infinity)
|
| 1239 |
changes.push({from: min, to: max + 1});
|
|
@@ -1244,7 +1534,7 @@ var CodeMirror = (function() {
|
|
| 1244 |
var line = this.set[i], mk = line.marked;
|
| 1245 |
for (var j = 0; j < mk.length; ++j) {
|
| 1246 |
var mark = mk[j];
|
| 1247 |
-
if (mark.
|
| 1248 |
if (mark.from != null || mark.to != null) {
|
| 1249 |
var found = lineNo(line);
|
| 1250 |
if (found != null) {
|
|
@@ -1261,8 +1551,9 @@ var CodeMirror = (function() {
|
|
| 1261 |
function markText(from, to, className) {
|
| 1262 |
from = clipPos(from); to = clipPos(to);
|
| 1263 |
var tm = new TextMarker();
|
|
|
|
| 1264 |
function add(line, from, to, className) {
|
| 1265 |
-
getLine(line).addMark(new MarkedText(from, to, className, tm
|
| 1266 |
}
|
| 1267 |
if (from.line == to.line) add(from.line, from.ch, to.ch, className);
|
| 1268 |
else {
|
|
@@ -1282,6 +1573,19 @@ var CodeMirror = (function() {
|
|
| 1282 |
return bm;
|
| 1283 |
}
|
| 1284 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1285 |
function addGutterMarker(line, text, className) {
|
| 1286 |
if (typeof line == "number") line = getLine(clipLine(line));
|
| 1287 |
line.gutterMarker = {text: text, style: className};
|
|
@@ -1303,10 +1607,11 @@ var CodeMirror = (function() {
|
|
| 1303 |
else return null;
|
| 1304 |
return line;
|
| 1305 |
}
|
| 1306 |
-
function setLineClass(handle, className) {
|
| 1307 |
return changeLine(handle, function(line) {
|
| 1308 |
-
if (line.className != className) {
|
| 1309 |
line.className = className;
|
|
|
|
| 1310 |
return true;
|
| 1311 |
}
|
| 1312 |
});
|
|
@@ -1315,10 +1620,22 @@ var CodeMirror = (function() {
|
|
| 1315 |
return changeLine(handle, function(line, no) {
|
| 1316 |
if (line.hidden != hidden) {
|
| 1317 |
line.hidden = hidden;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1318 |
updateLineHeight(line, hidden ? 0 : 1);
|
| 1319 |
-
|
| 1320 |
-
|
| 1321 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1322 |
return (gutterDirty = true);
|
| 1323 |
}
|
| 1324 |
});
|
|
@@ -1330,29 +1647,22 @@ var CodeMirror = (function() {
|
|
| 1330 |
var n = line;
|
| 1331 |
line = getLine(line);
|
| 1332 |
if (!line) return null;
|
| 1333 |
-
}
|
| 1334 |
-
else {
|
| 1335 |
var n = lineNo(line);
|
| 1336 |
if (n == null) return null;
|
| 1337 |
}
|
| 1338 |
var marker = line.gutterMarker;
|
| 1339 |
return {line: n, handle: line, text: line.text, markerText: marker && marker.text,
|
| 1340 |
-
markerClass: marker && marker.style, lineClass: line.className};
|
| 1341 |
}
|
| 1342 |
|
| 1343 |
-
function stringWidth(str) {
|
| 1344 |
-
measure.innerHTML = "<pre><span>x</span></pre>";
|
| 1345 |
-
measure.firstChild.firstChild.firstChild.nodeValue = str;
|
| 1346 |
-
return measure.firstChild.firstChild.offsetWidth || 10;
|
| 1347 |
-
}
|
| 1348 |
// These are used to go from pixel positions to character
|
| 1349 |
// positions, taking varying character widths into account.
|
| 1350 |
function charFromX(line, x) {
|
| 1351 |
if (x <= 0) return 0;
|
| 1352 |
var lineObj = getLine(line), text = lineObj.text;
|
| 1353 |
function getX(len) {
|
| 1354 |
-
|
| 1355 |
-
return measure.firstChild.firstChild.offsetWidth;
|
| 1356 |
}
|
| 1357 |
var from = 0, fromX = 0, to = text.length, toX;
|
| 1358 |
// Guess a suitable upper bound for our search.
|
|
@@ -1375,24 +1685,18 @@ var CodeMirror = (function() {
|
|
| 1375 |
}
|
| 1376 |
}
|
| 1377 |
|
| 1378 |
-
var tempId = Math.floor(Math.random() * 0xffffff).toString(16);
|
| 1379 |
function measureLine(line, ch) {
|
| 1380 |
-
|
| 1381 |
-
|
| 1382 |
-
|
| 1383 |
-
|
| 1384 |
-
|
| 1385 |
-
|
| 1386 |
-
|
| 1387 |
-
'<span id="CodeMirror-temp-' + tempId + '">' + htmlEscape(line.text.charAt(ch) || " ") + "</span>" +
|
| 1388 |
-
extra + "</pre>";
|
| 1389 |
-
var elt = document.getElementById("CodeMirror-temp-" + tempId);
|
| 1390 |
-
var top = elt.offsetTop, left = elt.offsetLeft;
|
| 1391 |
// Older IEs report zero offsets for spans directly after a wrap
|
| 1392 |
-
if (ie &&
|
| 1393 |
-
var backup =
|
| 1394 |
-
backup.
|
| 1395 |
-
elt.parentNode.insertBefore(backup, elt.nextSibling);
|
| 1396 |
top = backup.offsetTop;
|
| 1397 |
}
|
| 1398 |
return {top: top, left: left};
|
|
@@ -1409,17 +1713,19 @@ var CodeMirror = (function() {
|
|
| 1409 |
}
|
| 1410 |
// Coords must be lineSpace-local
|
| 1411 |
function coordsChar(x, y) {
|
| 1412 |
-
if (y < 0) y = 0;
|
| 1413 |
var th = textHeight(), cw = charWidth(), heightPos = displayOffset + Math.floor(y / th);
|
|
|
|
| 1414 |
var lineNo = lineAtHeight(doc, heightPos);
|
| 1415 |
if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc.size - 1).text.length};
|
| 1416 |
var lineObj = getLine(lineNo), text = lineObj.text;
|
| 1417 |
var tw = options.lineWrapping, innerOff = tw ? heightPos - heightAtLine(doc, lineNo) : 0;
|
| 1418 |
if (x <= 0 && innerOff == 0) return {line: lineNo, ch: 0};
|
|
|
|
| 1419 |
function getX(len) {
|
| 1420 |
var sp = measureLine(lineObj, len);
|
| 1421 |
if (tw) {
|
| 1422 |
var off = Math.round(sp.top / th);
|
|
|
|
| 1423 |
return Math.max(0, sp.left + (off - innerOff) * scroller.clientWidth);
|
| 1424 |
}
|
| 1425 |
return sp.left;
|
|
@@ -1438,9 +1744,12 @@ var CodeMirror = (function() {
|
|
| 1438 |
if (estX < x) {from = estimated; fromX = estX;}
|
| 1439 |
// Do a binary search between these bounds.
|
| 1440 |
for (;;) {
|
| 1441 |
-
if (to - from <= 1)
|
|
|
|
|
|
|
|
|
|
| 1442 |
var middle = Math.ceil((from + to) / 2), middleX = getX(middle);
|
| 1443 |
-
if (middleX > x) {to = middle; toX = middleX;}
|
| 1444 |
else {from = middle; fromX = middleX;}
|
| 1445 |
}
|
| 1446 |
}
|
|
@@ -1449,26 +1758,32 @@ var CodeMirror = (function() {
|
|
| 1449 |
return {x: off.left + local.x, y: off.top + local.y, yBot: off.top + local.yBot};
|
| 1450 |
}
|
| 1451 |
|
| 1452 |
-
var cachedHeight, cachedHeightFor,
|
| 1453 |
function textHeight() {
|
| 1454 |
-
if (
|
| 1455 |
-
|
| 1456 |
-
for (var i = 0; i < 49; ++i)
|
| 1457 |
-
|
|
|
|
|
|
|
|
|
|
| 1458 |
}
|
| 1459 |
var offsetHeight = lineDiv.clientHeight;
|
| 1460 |
if (offsetHeight == cachedHeightFor) return cachedHeight;
|
| 1461 |
cachedHeightFor = offsetHeight;
|
| 1462 |
-
measure.
|
| 1463 |
cachedHeight = measure.firstChild.offsetHeight / 50 || 1;
|
| 1464 |
-
measure
|
| 1465 |
return cachedHeight;
|
| 1466 |
}
|
| 1467 |
var cachedWidth, cachedWidthFor = 0;
|
| 1468 |
function charWidth() {
|
| 1469 |
if (scroller.clientWidth == cachedWidthFor) return cachedWidth;
|
| 1470 |
cachedWidthFor = scroller.clientWidth;
|
| 1471 |
-
|
|
|
|
|
|
|
|
|
|
| 1472 |
}
|
| 1473 |
function paddingTop() {return lineSpace.offsetTop;}
|
| 1474 |
function paddingLeft() {return lineSpace.offsetLeft;}
|
|
@@ -1486,8 +1801,8 @@ var CodeMirror = (function() {
|
|
| 1486 |
return coordsChar(x - offL.left, y - offL.top);
|
| 1487 |
}
|
| 1488 |
function onContextMenu(e) {
|
| 1489 |
-
var pos = posFromMouse(e);
|
| 1490 |
-
if (!pos ||
|
| 1491 |
if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
|
| 1492 |
operation(setCursor)(pos.line, pos.ch);
|
| 1493 |
|
|
@@ -1499,12 +1814,13 @@ var CodeMirror = (function() {
|
|
| 1499 |
leaveInputAlone = true;
|
| 1500 |
var val = input.value = getSelection();
|
| 1501 |
focusInput();
|
| 1502 |
-
input
|
| 1503 |
function rehide() {
|
| 1504 |
var newVal = splitLines(input.value).join("\n");
|
| 1505 |
-
if (newVal != val) operation(replaceSelection)(newVal, "end");
|
| 1506 |
inputDiv.style.position = "relative";
|
| 1507 |
input.style.cssText = oldCSS;
|
|
|
|
| 1508 |
leaveInputAlone = false;
|
| 1509 |
resetInput(true);
|
| 1510 |
slowPoll();
|
|
@@ -1516,8 +1832,7 @@ var CodeMirror = (function() {
|
|
| 1516 |
mouseup();
|
| 1517 |
setTimeout(rehide, 20);
|
| 1518 |
}, true);
|
| 1519 |
-
}
|
| 1520 |
-
else {
|
| 1521 |
setTimeout(rehide, 50);
|
| 1522 |
}
|
| 1523 |
}
|
|
@@ -1529,7 +1844,7 @@ var CodeMirror = (function() {
|
|
| 1529 |
cursor.style.visibility = "";
|
| 1530 |
blinker = setInterval(function() {
|
| 1531 |
cursor.style.visibility = (on = !on) ? "" : "hidden";
|
| 1532 |
-
},
|
| 1533 |
}
|
| 1534 |
|
| 1535 |
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
|
|
@@ -1547,7 +1862,7 @@ var CodeMirror = (function() {
|
|
| 1547 |
var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
|
| 1548 |
for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
|
| 1549 |
var text = st[i];
|
| 1550 |
-
if (st[i+1] !=
|
| 1551 |
for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
|
| 1552 |
if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
|
| 1553 |
var match = matching[cur];
|
|
@@ -1634,13 +1949,17 @@ var CodeMirror = (function() {
|
|
| 1634 |
var changed = line.highlight(mode, state, options.tabSize);
|
| 1635 |
if (changed) realChange = true;
|
| 1636 |
line.stateAfter = copyState(mode, state);
|
|
|
|
| 1637 |
if (compare) {
|
| 1638 |
-
|
| 1639 |
-
|
|
|
|
|
|
|
| 1640 |
if (changed !== false || !hadState) unchanged = 0;
|
| 1641 |
else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, "")))
|
| 1642 |
-
|
| 1643 |
}
|
|
|
|
| 1644 |
++i;
|
| 1645 |
});
|
| 1646 |
if (bail) return;
|
|
@@ -1663,15 +1982,28 @@ var CodeMirror = (function() {
|
|
| 1663 |
changes = []; selectionChanged = false; callbacks = [];
|
| 1664 |
}
|
| 1665 |
function endOperation() {
|
| 1666 |
-
|
| 1667 |
-
if (
|
| 1668 |
-
|
| 1669 |
-
|
| 1670 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1671 |
if (gutterDirty) updateGutter();
|
| 1672 |
}
|
| 1673 |
-
if (
|
| 1674 |
-
if (selectionChanged)
|
| 1675 |
|
| 1676 |
if (focused && !leaveInputAlone &&
|
| 1677 |
(updateInput === true || (updateInput !== false && selectionChanged)))
|
|
@@ -1682,11 +2014,11 @@ var CodeMirror = (function() {
|
|
| 1682 |
if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
|
| 1683 |
if (posEq(sel.from, sel.to)) matchBrackets(false);
|
| 1684 |
}), 20);
|
| 1685 |
-
var
|
| 1686 |
-
if (
|
|
|
|
|
|
|
| 1687 |
options.onCursorActivity(instance);
|
| 1688 |
-
if (tc && options.onChange && instance)
|
| 1689 |
-
options.onChange(instance, tc);
|
| 1690 |
for (var i = 0; i < cbs.length; ++i) cbs[i](instance);
|
| 1691 |
if (updated && options.onUpdate) options.onUpdate(instance);
|
| 1692 |
}
|
|
@@ -1700,6 +2032,11 @@ var CodeMirror = (function() {
|
|
| 1700 |
};
|
| 1701 |
}
|
| 1702 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1703 |
for (var ext in extensions)
|
| 1704 |
if (extensions.propertyIsEnumerable(ext) &&
|
| 1705 |
!instance.propertyIsEnumerable(ext))
|
|
@@ -1714,57 +2051,69 @@ var CodeMirror = (function() {
|
|
| 1714 |
theme: "default",
|
| 1715 |
indentUnit: 2,
|
| 1716 |
indentWithTabs: false,
|
|
|
|
| 1717 |
tabSize: 4,
|
| 1718 |
keyMap: "default",
|
| 1719 |
extraKeys: null,
|
| 1720 |
electricChars: true,
|
|
|
|
| 1721 |
onKeyEvent: null,
|
|
|
|
| 1722 |
lineWrapping: false,
|
| 1723 |
lineNumbers: false,
|
| 1724 |
gutter: false,
|
| 1725 |
fixedGutter: false,
|
| 1726 |
firstLineNumber: 1,
|
| 1727 |
readOnly: false,
|
|
|
|
| 1728 |
onChange: null,
|
| 1729 |
onCursorActivity: null,
|
|
|
|
| 1730 |
onGutterClick: null,
|
| 1731 |
onHighlightComplete: null,
|
| 1732 |
onUpdate: null,
|
| 1733 |
onFocus: null, onBlur: null, onScroll: null,
|
| 1734 |
matchBrackets: false,
|
|
|
|
| 1735 |
workTime: 100,
|
| 1736 |
workDelay: 200,
|
| 1737 |
pollInterval: 100,
|
| 1738 |
undoDepth: 40,
|
| 1739 |
tabindex: null,
|
| 1740 |
-
|
|
|
|
| 1741 |
};
|
| 1742 |
|
| 1743 |
-
var
|
|
|
|
| 1744 |
var win = /Win/.test(navigator.platform);
|
| 1745 |
|
| 1746 |
// Known modes, by name and by MIME
|
| 1747 |
-
var modes = {}, mimeModes = {};
|
| 1748 |
CodeMirror.defineMode = function(name, mode) {
|
| 1749 |
if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1750 |
modes[name] = mode;
|
| 1751 |
};
|
| 1752 |
CodeMirror.defineMIME = function(mime, spec) {
|
| 1753 |
mimeModes[mime] = spec;
|
| 1754 |
};
|
| 1755 |
-
CodeMirror.
|
| 1756 |
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
|
| 1757 |
spec = mimeModes[spec];
|
| 1758 |
-
if (typeof spec == "string")
|
| 1759 |
-
|
| 1760 |
-
|
| 1761 |
-
|
| 1762 |
-
|
| 1763 |
-
|
| 1764 |
-
|
| 1765 |
-
|
| 1766 |
-
|
| 1767 |
-
return mfactory(options,
|
| 1768 |
};
|
| 1769 |
CodeMirror.listModes = function() {
|
| 1770 |
var list = [];
|
|
@@ -1821,6 +2170,10 @@ var CodeMirror = (function() {
|
|
| 1821 |
indentMore: function(cm) {cm.indentSelection("add");},
|
| 1822 |
indentLess: function(cm) {cm.indentSelection("subtract");},
|
| 1823 |
insertTab: function(cm) {cm.replaceSelection("\t", "end");},
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1824 |
transposeChars: function(cm) {
|
| 1825 |
var cur = cm.getCursor(), line = cm.getLine(cur.line);
|
| 1826 |
if (cur.ch > 0 && cur.ch < line.length - 1)
|
|
@@ -1838,7 +2191,7 @@ var CodeMirror = (function() {
|
|
| 1838 |
keyMap.basic = {
|
| 1839 |
"Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
|
| 1840 |
"End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
|
| 1841 |
-
"Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "
|
| 1842 |
"Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
|
| 1843 |
};
|
| 1844 |
// Note that the save and find-related commands aren't defined by
|
|
@@ -1849,6 +2202,7 @@ var CodeMirror = (function() {
|
|
| 1849 |
"Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
|
| 1850 |
"Ctrl-Backspace": "delWordLeft", "Ctrl-Delete": "delWordRight", "Ctrl-S": "save", "Ctrl-F": "find",
|
| 1851 |
"Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
|
|
|
|
| 1852 |
fallthrough: "basic"
|
| 1853 |
};
|
| 1854 |
keyMap.macDefault = {
|
|
@@ -1857,6 +2211,7 @@ var CodeMirror = (function() {
|
|
| 1857 |
"Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordLeft",
|
| 1858 |
"Ctrl-Alt-Backspace": "delWordRight", "Alt-Delete": "delWordRight", "Cmd-S": "save", "Cmd-F": "find",
|
| 1859 |
"Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
|
|
|
|
| 1860 |
fallthrough: ["basic", "emacsy"]
|
| 1861 |
};
|
| 1862 |
keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
|
|
@@ -1867,23 +2222,37 @@ var CodeMirror = (function() {
|
|
| 1867 |
"Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
|
| 1868 |
};
|
| 1869 |
|
| 1870 |
-
function
|
| 1871 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1872 |
var found = map[name];
|
| 1873 |
-
if (found
|
| 1874 |
-
|
| 1875 |
-
|
| 1876 |
-
|
| 1877 |
-
|
| 1878 |
-
|
| 1879 |
-
if (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1880 |
}
|
| 1881 |
-
return
|
| 1882 |
}
|
| 1883 |
-
|
|
|
|
| 1884 |
}
|
| 1885 |
function isModifierKey(event) {
|
| 1886 |
-
var name = keyNames[event
|
| 1887 |
return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
|
| 1888 |
}
|
| 1889 |
|
|
@@ -1892,6 +2261,15 @@ var CodeMirror = (function() {
|
|
| 1892 |
options.value = textarea.value;
|
| 1893 |
if (!options.tabindex && textarea.tabindex)
|
| 1894 |
options.tabindex = textarea.tabindex;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1895 |
|
| 1896 |
function save() {textarea.value = instance.getValue();}
|
| 1897 |
if (textarea.form) {
|
|
@@ -1899,13 +2277,12 @@ var CodeMirror = (function() {
|
|
| 1899 |
var rmSubmit = connect(textarea.form, "submit", save, true);
|
| 1900 |
if (typeof textarea.form.submit == "function") {
|
| 1901 |
var realSubmit = textarea.form.submit;
|
| 1902 |
-
function wrappedSubmit() {
|
| 1903 |
save();
|
| 1904 |
textarea.form.submit = realSubmit;
|
| 1905 |
textarea.form.submit();
|
| 1906 |
textarea.form.submit = wrappedSubmit;
|
| 1907 |
-
}
|
| 1908 |
-
textarea.form.submit = wrappedSubmit;
|
| 1909 |
}
|
| 1910 |
}
|
| 1911 |
|
|
@@ -1928,6 +2305,18 @@ var CodeMirror = (function() {
|
|
| 1928 |
return instance;
|
| 1929 |
};
|
| 1930 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1931 |
// Utility functions for working with state. Exported because modes
|
| 1932 |
// sometimes need to do this.
|
| 1933 |
function copyState(mode, state) {
|
|
@@ -1956,7 +2345,7 @@ var CodeMirror = (function() {
|
|
| 1956 |
StringStream.prototype = {
|
| 1957 |
eol: function() {return this.pos >= this.string.length;},
|
| 1958 |
sol: function() {return this.pos == 0;},
|
| 1959 |
-
peek: function() {return this.string.charAt(this.pos);},
|
| 1960 |
next: function() {
|
| 1961 |
if (this.pos < this.string.length)
|
| 1962 |
return this.string.charAt(this.pos++);
|
|
@@ -1987,13 +2376,12 @@ var CodeMirror = (function() {
|
|
| 1987 |
indentation: function() {return countColumn(this.string, null, this.tabSize);},
|
| 1988 |
match: function(pattern, consume, caseInsensitive) {
|
| 1989 |
if (typeof pattern == "string") {
|
| 1990 |
-
|
| 1991 |
if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
|
| 1992 |
if (consume !== false) this.pos += pattern.length;
|
| 1993 |
return true;
|
| 1994 |
}
|
| 1995 |
-
}
|
| 1996 |
-
else {
|
| 1997 |
var match = this.string.slice(this.pos).match(pattern);
|
| 1998 |
if (match && consume !== false) this.pos += match[0].length;
|
| 1999 |
return match;
|
|
@@ -2003,34 +2391,34 @@ var CodeMirror = (function() {
|
|
| 2003 |
};
|
| 2004 |
CodeMirror.StringStream = StringStream;
|
| 2005 |
|
| 2006 |
-
function MarkedText(from, to, className,
|
| 2007 |
-
this.from = from; this.to = to; this.style = className; this.
|
| 2008 |
}
|
| 2009 |
MarkedText.prototype = {
|
| 2010 |
-
attach: function(line) { this.set.push(line); },
|
| 2011 |
detach: function(line) {
|
| 2012 |
-
var ix = indexOf(this.set, line);
|
| 2013 |
-
if (ix > -1) this.set.splice(ix, 1);
|
| 2014 |
},
|
| 2015 |
split: function(pos, lenBefore) {
|
| 2016 |
if (this.to <= pos && this.to != null) return null;
|
| 2017 |
var from = this.from < pos || this.from == null ? null : this.from - pos + lenBefore;
|
| 2018 |
var to = this.to == null ? null : this.to - pos + lenBefore;
|
| 2019 |
-
return new MarkedText(from, to, this.style, this.
|
| 2020 |
},
|
| 2021 |
-
dup: function() { return new MarkedText(null, null, this.style, this.
|
| 2022 |
clipTo: function(fromOpen, from, toOpen, to, diff) {
|
| 2023 |
-
if (this.from != null && this.from >= from)
|
| 2024 |
-
this.from = Math.max(to, this.from) + diff;
|
| 2025 |
-
if (this.to != null && this.to > from)
|
| 2026 |
-
this.to = to < this.to ? this.to + diff : from;
|
| 2027 |
if (fromOpen && to > this.from && (to < this.to || this.to == null))
|
| 2028 |
this.from = null;
|
|
|
|
|
|
|
| 2029 |
if (toOpen && (from < this.to || this.to == null) && (from > this.from || this.from == null))
|
| 2030 |
this.to = null;
|
|
|
|
|
|
|
| 2031 |
},
|
| 2032 |
isDead: function() { return this.from != null && this.to != null && this.from >= this.to; },
|
| 2033 |
-
sameSet: function(x) { return this.
|
| 2034 |
};
|
| 2035 |
|
| 2036 |
function Bookmark(pos) {
|
|
@@ -2067,14 +2455,22 @@ var CodeMirror = (function() {
|
|
| 2067 |
}
|
| 2068 |
};
|
| 2069 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2070 |
// Line objects. These hold state related to a line, including
|
| 2071 |
// highlighting info (the styles array).
|
| 2072 |
function Line(text, styles) {
|
| 2073 |
this.styles = styles || [text, null];
|
| 2074 |
this.text = text;
|
| 2075 |
this.height = 1;
|
| 2076 |
-
this.marked = this.gutterMarker = this.className = this.handlers = null;
|
| 2077 |
-
this.stateAfter = this.parent = this.hidden = null;
|
| 2078 |
}
|
| 2079 |
Line.inheritMarks = function(text, orig) {
|
| 2080 |
var ln = new Line(text), mk = orig && orig.marked;
|
|
@@ -2087,7 +2483,7 @@ var CodeMirror = (function() {
|
|
| 2087 |
}
|
| 2088 |
}
|
| 2089 |
return ln;
|
| 2090 |
-
}
|
| 2091 |
Line.prototype = {
|
| 2092 |
// Replace a piece of a line, keeping the styles around it intact.
|
| 2093 |
replace: function(from, to_, text) {
|
|
@@ -2100,7 +2496,8 @@ var CodeMirror = (function() {
|
|
| 2100 |
this.stateAfter = null;
|
| 2101 |
if (mk) {
|
| 2102 |
var diff = text.length - (to - from);
|
| 2103 |
-
for (var i = 0
|
|
|
|
| 2104 |
mark.clipTo(from == null, from || 0, to_ == null, to, diff);
|
| 2105 |
if (mark.isDead()) {mark.detach(this); mk.splice(i--, 1);}
|
| 2106 |
}
|
|
@@ -2118,6 +2515,7 @@ var CodeMirror = (function() {
|
|
| 2118 |
if (newmark) {
|
| 2119 |
if (!taken.marked) taken.marked = [];
|
| 2120 |
taken.marked.push(newmark); newmark.attach(taken);
|
|
|
|
| 2121 |
}
|
| 2122 |
}
|
| 2123 |
}
|
|
@@ -2158,11 +2556,20 @@ var CodeMirror = (function() {
|
|
| 2158 |
fixMarkEnds: function(other) {
|
| 2159 |
var mk = this.marked, omk = other.marked;
|
| 2160 |
if (!mk) return;
|
| 2161 |
-
for (var i = 0; i < mk.length; ++i) {
|
| 2162 |
var mark = mk[i], close = mark.to == null;
|
| 2163 |
if (close && omk) {
|
| 2164 |
-
for (var j = 0; j < omk.length; ++j)
|
| 2165 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2166 |
}
|
| 2167 |
if (close) mark.to = this.text.length;
|
| 2168 |
}
|
|
@@ -2212,8 +2619,8 @@ var CodeMirror = (function() {
|
|
| 2212 |
},
|
| 2213 |
// Fetch the parser token for a given character. Useful for hacks
|
| 2214 |
// that want to inspect the mode state (say, for completion).
|
| 2215 |
-
getTokenAt: function(mode, state, ch) {
|
| 2216 |
-
var txt = this.text, stream = new StringStream(txt);
|
| 2217 |
while (stream.pos < ch && !stream.eol()) {
|
| 2218 |
stream.start = stream.pos;
|
| 2219 |
var style = mode.token(stream, state);
|
|
@@ -2227,74 +2634,126 @@ var CodeMirror = (function() {
|
|
| 2227 |
indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
|
| 2228 |
// Produces an HTML fragment for the line, taking selection,
|
| 2229 |
// marking, and highlighting into account.
|
| 2230 |
-
|
| 2231 |
-
var
|
| 2232 |
-
|
| 2233 |
-
|
| 2234 |
-
function span(text, style) {
|
| 2235 |
if (!text) return;
|
| 2236 |
// Work around a bug where, in some compat modes, IE ignores leading spaces
|
| 2237 |
if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1);
|
| 2238 |
first = false;
|
| 2239 |
-
if (
|
| 2240 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2241 |
}
|
|
|
|
| 2242 |
var st = this.styles, allText = this.text, marked = this.marked;
|
| 2243 |
-
if (sfrom == sto) sfrom = null;
|
| 2244 |
var len = allText.length;
|
| 2245 |
-
|
| 2246 |
-
|
| 2247 |
-
|
| 2248 |
-
|
| 2249 |
-
|
|
|
|
|
|
|
| 2250 |
for (var i = 0, ch = 0; ch < len; i+=2) {
|
| 2251 |
var str = st[i], style = st[i+1], l = str.length;
|
| 2252 |
if (ch + l > len) str = str.slice(0, len - ch);
|
| 2253 |
ch += l;
|
| 2254 |
-
span(str, style
|
| 2255 |
}
|
| 2256 |
-
else {
|
| 2257 |
var pos = 0, i = 0, text = "", style, sg = 0;
|
| 2258 |
-
var
|
| 2259 |
-
function
|
| 2260 |
-
|
| 2261 |
-
|
| 2262 |
-
|
|
|
|
|
|
|
| 2263 |
}
|
| 2264 |
-
|
| 2265 |
-
|
| 2266 |
-
|
| 2267 |
-
|
| 2268 |
-
|
| 2269 |
-
|
| 2270 |
-
if (sfrom > pos) upto = sfrom;
|
| 2271 |
-
else if (sto == null || sto > pos) {
|
| 2272 |
-
extraStyle = " CodeMirror-selected";
|
| 2273 |
-
if (sto != null) upto = Math.min(upto, sto);
|
| 2274 |
-
}
|
| 2275 |
}
|
| 2276 |
-
|
| 2277 |
-
|
| 2278 |
-
|
| 2279 |
-
|
| 2280 |
-
|
| 2281 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2282 |
}
|
| 2283 |
-
|
| 2284 |
-
for (;;) {
|
| 2285 |
-
var end = pos + text.length;
|
| 2286 |
-
var appliedStyle = style;
|
| 2287 |
-
if (extraStyle) appliedStyle = style ? style + extraStyle : extraStyle;
|
| 2288 |
-
span(end > upto ? text.slice(0, upto - pos) : text, appliedStyle);
|
| 2289 |
-
if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
|
| 2290 |
-
pos = end;
|
| 2291 |
-
text = st[i++]; style = "cm-" + st[i++];
|
| 2292 |
}
|
| 2293 |
}
|
| 2294 |
-
if (sfrom != null && sto == null) span(" ", "CodeMirror-selected");
|
| 2295 |
}
|
| 2296 |
-
|
| 2297 |
-
return html.join("");
|
| 2298 |
},
|
| 2299 |
cleanUp: function() {
|
| 2300 |
this.parent = null;
|
|
@@ -2309,8 +2768,7 @@ var CodeMirror = (function() {
|
|
| 2309 |
if (state == 0) {
|
| 2310 |
if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
|
| 2311 |
if (end >= from) state = 1;
|
| 2312 |
-
}
|
| 2313 |
-
else if (state == 1) {
|
| 2314 |
if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
|
| 2315 |
else dest.push(part, source[i+1]);
|
| 2316 |
}
|
|
@@ -2345,7 +2803,7 @@ var CodeMirror = (function() {
|
|
| 2345 |
},
|
| 2346 |
insertHeight: function(at, lines, height) {
|
| 2347 |
this.height += height;
|
| 2348 |
-
this.lines.
|
| 2349 |
for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
|
| 2350 |
},
|
| 2351 |
iterN: function(at, n, op) {
|
|
@@ -2384,6 +2842,7 @@ var CodeMirror = (function() {
|
|
| 2384 |
var lines = [];
|
| 2385 |
this.collapse(lines);
|
| 2386 |
this.children = [new LeafChunk(lines)];
|
|
|
|
| 2387 |
}
|
| 2388 |
},
|
| 2389 |
collapse: function(lines) {
|
|
@@ -2510,31 +2969,36 @@ var CodeMirror = (function() {
|
|
| 2510 |
function History() {
|
| 2511 |
this.time = 0;
|
| 2512 |
this.done = []; this.undone = [];
|
|
|
|
|
|
|
| 2513 |
}
|
| 2514 |
History.prototype = {
|
| 2515 |
addChange: function(start, added, old) {
|
| 2516 |
this.undone.length = 0;
|
| 2517 |
-
var time = +new Date,
|
| 2518 |
-
|
| 2519 |
-
|
| 2520 |
-
|
| 2521 |
-
|
| 2522 |
-
|
| 2523 |
-
|
| 2524 |
-
|
| 2525 |
-
|
| 2526 |
-
|
| 2527 |
-
|
| 2528 |
-
|
| 2529 |
-
|
| 2530 |
-
|
| 2531 |
-
|
| 2532 |
-
|
| 2533 |
-
for (var i = last.added - oldoff, e = old.length; i < e; ++i)
|
| 2534 |
-
last.old.push(old[i]);
|
| 2535 |
-
if (last.added < added) last.added = added;
|
| 2536 |
}
|
| 2537 |
this.time = time;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2538 |
}
|
| 2539 |
};
|
| 2540 |
|
|
@@ -2560,10 +3024,21 @@ var CodeMirror = (function() {
|
|
| 2560 |
|
| 2561 |
function e_target(e) {return e.target || e.srcElement;}
|
| 2562 |
function e_button(e) {
|
| 2563 |
-
|
| 2564 |
-
|
| 2565 |
-
|
| 2566 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2567 |
}
|
| 2568 |
|
| 2569 |
// Event handler registration. If disconnect is true, it'll return a
|
|
@@ -2572,8 +3047,7 @@ var CodeMirror = (function() {
|
|
| 2572 |
if (typeof node.addEventListener == "function") {
|
| 2573 |
node.addEventListener(type, handler, false);
|
| 2574 |
if (disconnect) return function() {node.removeEventListener(type, handler, false);};
|
| 2575 |
-
}
|
| 2576 |
-
else {
|
| 2577 |
var wrapHandler = function(event) {handler(event || window.event);};
|
| 2578 |
node.attachEvent("on" + type, wrapHandler);
|
| 2579 |
if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
|
|
@@ -2584,26 +3058,36 @@ var CodeMirror = (function() {
|
|
| 2584 |
function Delayed() {this.id = null;}
|
| 2585 |
Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
|
| 2586 |
|
|
|
|
|
|
|
| 2587 |
// Detect drag-and-drop
|
| 2588 |
var dragAndDrop = function() {
|
| 2589 |
-
//
|
| 2590 |
-
//
|
| 2591 |
-
if (
|
| 2592 |
-
var div =
|
| 2593 |
-
return "draggable" in div;
|
| 2594 |
}();
|
| 2595 |
|
| 2596 |
-
var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
|
| 2597 |
-
var ie = /MSIE \d/.test(navigator.userAgent);
|
| 2598 |
-
var webkit = /WebKit\//.test(navigator.userAgent);
|
| 2599 |
-
|
| 2600 |
-
var lineSep = "\n";
|
| 2601 |
// Feature-detect whether newlines in textareas are converted to \r\n
|
| 2602 |
-
|
| 2603 |
-
var te =
|
| 2604 |
te.value = "foo\nbar";
|
| 2605 |
-
if (te.value.indexOf("\r") > -1)
|
| 2606 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2607 |
|
| 2608 |
// Counts the column offset in a string, taking tabs into account.
|
| 2609 |
// Used mostly to find indentation.
|
|
@@ -2619,31 +3103,7 @@ var CodeMirror = (function() {
|
|
| 2619 |
return n;
|
| 2620 |
}
|
| 2621 |
|
| 2622 |
-
function computedStyle(elt) {
|
| 2623 |
-
if (elt.currentStyle) return elt.currentStyle;
|
| 2624 |
-
return window.getComputedStyle(elt, null);
|
| 2625 |
-
}
|
| 2626 |
-
|
| 2627 |
-
// Find the position of an element by following the offsetParent chain.
|
| 2628 |
-
// If screen==true, it returns screen (rather than page) coordinates.
|
| 2629 |
function eltOffset(node, screen) {
|
| 2630 |
-
var bod = node.ownerDocument.body;
|
| 2631 |
-
var x = 0, y = 0, skipBody = false;
|
| 2632 |
-
for (var n = node; n; n = n.offsetParent) {
|
| 2633 |
-
var ol = n.offsetLeft, ot = n.offsetTop;
|
| 2634 |
-
// Firefox reports weird inverted offsets when the body has a border.
|
| 2635 |
-
if (n == bod) { x += Math.abs(ol); y += Math.abs(ot); }
|
| 2636 |
-
else { x += ol, y += ot; }
|
| 2637 |
-
if (screen && computedStyle(n).position == "fixed")
|
| 2638 |
-
skipBody = true;
|
| 2639 |
-
}
|
| 2640 |
-
var e = screen && !skipBody ? null : bod;
|
| 2641 |
-
for (var n = node.parentNode; n != e; n = n.parentNode)
|
| 2642 |
-
if (n.scrollLeft != null) { x -= n.scrollLeft; y -= n.scrollTop;}
|
| 2643 |
-
return {left: x, top: y};
|
| 2644 |
-
}
|
| 2645 |
-
// Use the faster and saner getBoundingClientRect method when possible.
|
| 2646 |
-
if (document.documentElement.getBoundingClientRect != null) eltOffset = function(node, screen) {
|
| 2647 |
// Take the parts of bounding client rect that we are interested in so we are able to edit if need be,
|
| 2648 |
// since the returned value cannot be changed externally (they are kept in sync as the element moves within the page)
|
| 2649 |
try { var box = node.getBoundingClientRect(); box = { top: box.top, left: box.left }; }
|
|
@@ -2659,43 +3119,51 @@ var CodeMirror = (function() {
|
|
| 2659 |
}
|
| 2660 |
}
|
| 2661 |
return box;
|
| 2662 |
-
}
|
| 2663 |
|
| 2664 |
// Get a node's text content.
|
| 2665 |
function eltText(node) {
|
| 2666 |
return node.textContent || node.innerText || node.nodeValue || "";
|
| 2667 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2668 |
|
| 2669 |
// Operations on {line, ch} objects.
|
| 2670 |
function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
|
| 2671 |
function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
|
| 2672 |
function copyPos(x) {return {line: x.line, ch: x.ch};}
|
| 2673 |
|
| 2674 |
-
|
| 2675 |
-
|
| 2676 |
-
|
| 2677 |
-
|
|
|
|
|
|
|
|
|
|
| 2678 |
}
|
| 2679 |
-
|
| 2680 |
-
|
| 2681 |
-
|
| 2682 |
-
|
| 2683 |
-
|
| 2684 |
-
|
| 2685 |
-
|
| 2686 |
-
|
| 2687 |
-
|
| 2688 |
-
|
| 2689 |
-
|
| 2690 |
-
|
| 2691 |
-
|
| 2692 |
-
|
| 2693 |
-
CodeMirror.htmlEscape = htmlEscape;
|
| 2694 |
|
| 2695 |
// Used to position the cursor after an undo/redo by finding the
|
| 2696 |
// last edited character.
|
| 2697 |
function editEnd(from, to) {
|
| 2698 |
-
if (!to) return
|
| 2699 |
if (!from) return to.length;
|
| 2700 |
for (var i = from.length, j = to.length; i >= 0 && j >= 0; --i, --j)
|
| 2701 |
if (from.charAt(i) != to.charAt(j)) break;
|
|
@@ -2715,14 +3183,22 @@ var CodeMirror = (function() {
|
|
| 2715 |
// See if "".split is the broken IE version, if so, provide an
|
| 2716 |
// alternative way to split lines.
|
| 2717 |
var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
|
| 2718 |
-
var pos = 0,
|
| 2719 |
-
while (
|
| 2720 |
-
|
| 2721 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2722 |
}
|
| 2723 |
-
result.push(string.slice(pos));
|
| 2724 |
return result;
|
| 2725 |
-
} : function(string){return string.split(/\r
|
| 2726 |
CodeMirror.splitLines = splitLines;
|
| 2727 |
|
| 2728 |
var hasSelection = window.getSelection ? function(te) {
|
|
@@ -2743,10 +3219,10 @@ var CodeMirror = (function() {
|
|
| 2743 |
var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
|
| 2744 |
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
|
| 2745 |
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
|
| 2746 |
-
46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod",
|
| 2747 |
-
|
| 2748 |
-
|
| 2749 |
-
63233: "Down", 63302: "Insert", 63272: "Delete"};
|
| 2750 |
CodeMirror.keyNames = keyNames;
|
| 2751 |
(function() {
|
| 2752 |
// Number keys
|
| 1 |
+
// CodeMirror version 2.33
|
| 2 |
//
|
| 3 |
// All functions that need access to the editor's state live inside
|
| 4 |
// the CodeMirror function. Below that, at the bottom of the file,
|
| 5 |
// some utilities are defined.
|
| 6 |
|
| 7 |
// CodeMirror is the only global var we claim
|
| 8 |
+
window.CodeMirror = (function() {
|
| 9 |
+
"use strict";
|
| 10 |
+
// This is the function that produces an editor instance. Its
|
| 11 |
// closure is used to store the editor state.
|
| 12 |
function CodeMirror(place, givenOptions) {
|
| 13 |
// Determine effective options based on given values and defaults.
|
| 16 |
if (defaults.hasOwnProperty(opt))
|
| 17 |
options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
|
| 18 |
|
| 19 |
+
var input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em");
|
| 20 |
+
input.setAttribute("wrap", "off"); input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off");
|
| 21 |
+
// Wraps and hides input textarea
|
| 22 |
+
var inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
|
| 23 |
+
// The empty scrollbar content, used solely for managing the scrollbar thumb.
|
| 24 |
+
var scrollbarInner = elt("div", null, "CodeMirror-scrollbar-inner");
|
| 25 |
+
// The vertical scrollbar. Horizontal scrolling is handled by the scroller itself.
|
| 26 |
+
var scrollbar = elt("div", [scrollbarInner], "CodeMirror-scrollbar");
|
| 27 |
+
// DIVs containing the selection and the actual code
|
| 28 |
+
var lineDiv = elt("div"), selectionDiv = elt("div", null, null, "position: relative; z-index: -1");
|
| 29 |
+
// Blinky cursor, and element used to ensure cursor fits at the end of a line
|
| 30 |
+
var cursor = elt("pre", "\u00a0", "CodeMirror-cursor"), widthForcer = elt("pre", "\u00a0", "CodeMirror-cursor", "visibility: hidden");
|
| 31 |
+
// Used to measure text size
|
| 32 |
+
var measure = elt("div", null, null, "position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden;");
|
| 33 |
+
var lineSpace = elt("div", [measure, cursor, widthForcer, selectionDiv, lineDiv], null, "position: relative; z-index: 0");
|
| 34 |
+
var gutterText = elt("div", null, "CodeMirror-gutter-text"), gutter = elt("div", [gutterText], "CodeMirror-gutter");
|
| 35 |
+
// Moved around its parent to cover visible view
|
| 36 |
+
var mover = elt("div", [gutter, elt("div", [lineSpace], "CodeMirror-lines")], null, "position: relative");
|
| 37 |
+
// Set to the height of the text, causes scrolling
|
| 38 |
+
var sizer = elt("div", [mover], null, "position: relative");
|
| 39 |
+
// Provides scrolling
|
| 40 |
+
var scroller = elt("div", [sizer], "CodeMirror-scroll");
|
| 41 |
+
scroller.setAttribute("tabIndex", "-1");
|
| 42 |
// The element in which the editor lives.
|
| 43 |
+
var wrapper = elt("div", [inputDiv, scrollbar, scroller], "CodeMirror" + (options.lineWrapping ? " CodeMirror-wrap" : ""));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
|
| 45 |
+
|
| 46 |
+
themeChanged(); keyMapChanged();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
// Needed to hide big blue blinking cursor on Mobile Safari
|
| 48 |
+
if (ios) input.style.width = "0px";
|
| 49 |
+
if (!webkit) scroller.draggable = true;
|
| 50 |
+
lineSpace.style.outline = "none";
|
| 51 |
if (options.tabindex != null) input.tabIndex = options.tabindex;
|
| 52 |
+
if (options.autofocus) focusInput();
|
| 53 |
if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
|
| 54 |
+
// Needed to handle Tab key in KHTML
|
| 55 |
+
if (khtml) inputDiv.style.height = "1px", inputDiv.style.position = "absolute";
|
| 56 |
+
|
| 57 |
+
// Check for OS X >= 10.7. This has transparent scrollbars, so the
|
| 58 |
+
// overlaying of one scrollbar with another won't work. This is a
|
| 59 |
+
// temporary hack to simply turn off the overlay scrollbar. See
|
| 60 |
+
// issue #727.
|
| 61 |
+
if (mac_geLion) { scrollbar.style.zIndex = -2; scrollbar.style.visibility = "hidden"; }
|
| 62 |
+
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
|
| 63 |
+
else if (ie_lt8) scrollbar.style.minWidth = "18px";
|
| 64 |
|
| 65 |
// Check for problem with IE innerHTML not working when we have a
|
| 66 |
// P (or similar) parent node.
|
| 67 |
+
try { charWidth(); }
|
| 68 |
catch (e) {
|
| 69 |
if (e.message.match(/runtime/i))
|
| 70 |
e = new Error("A CodeMirror inside a P-style element does not work in Internet Explorer. (innerHTML bug)");
|
| 85 |
var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
|
| 86 |
// Selection-related flags. shiftSelecting obviously tracks
|
| 87 |
// whether the user is holding shift.
|
| 88 |
+
var shiftSelecting, lastClick, lastDoubleClick, lastScrollTop = 0, draggingText,
|
| 89 |
+
overwrite = false, suppressEdits = false;
|
| 90 |
// Variables used by startOperation/endOperation to track what
|
| 91 |
// happened during the operation.
|
| 92 |
var updateInput, userSelChange, changes, textChanged, selectionChanged, leaveInputAlone,
|
| 93 |
gutterDirty, callbacks;
|
| 94 |
// Current visible range (may be bigger than the view window).
|
| 95 |
var displayOffset = 0, showingFrom = 0, showingTo = 0, lastSizeC = 0;
|
| 96 |
+
// bracketHighlighted is used to remember that a bracket has been
|
| 97 |
// marked.
|
| 98 |
var bracketHighlighted;
|
| 99 |
// Tracks the maximum line length so that the horizontal scrollbar
|
| 100 |
// can be kept static when scrolling.
|
| 101 |
+
var maxLine = getLine(0), updateMaxLine = false, maxLineChanged = true;
|
| 102 |
+
var tabCache = {};
|
| 103 |
+
var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
|
| 104 |
+
var goalColumn = null;
|
| 105 |
|
| 106 |
// Initialize the content.
|
| 107 |
operation(function(){setValue(options.value || ""); updateInput = false;})();
|
| 110 |
// Register our event handlers.
|
| 111 |
connect(scroller, "mousedown", operation(onMouseDown));
|
| 112 |
connect(scroller, "dblclick", operation(onDoubleClick));
|
|
|
|
| 113 |
connect(lineSpace, "selectstart", e_preventDefault);
|
| 114 |
// Gecko browsers fire contextmenu *after* opening the menu, at
|
| 115 |
// which point we can't mess with it anymore. Context menu is
|
| 116 |
// handled in onMouseDown for Gecko.
|
| 117 |
if (!gecko) connect(scroller, "contextmenu", onContextMenu);
|
| 118 |
+
connect(scroller, "scroll", onScrollMain);
|
| 119 |
+
connect(scrollbar, "scroll", onScrollBar);
|
| 120 |
+
connect(scrollbar, "mousedown", function() {if (focused) setTimeout(focusInput, 0);});
|
| 121 |
+
var resizeHandler = connect(window, "resize", function() {
|
| 122 |
+
if (wrapper.parentNode) updateDisplay(true);
|
| 123 |
+
else resizeHandler();
|
| 124 |
+
}, true);
|
| 125 |
connect(input, "keyup", operation(onKeyUp));
|
| 126 |
connect(input, "input", fastPoll);
|
| 127 |
connect(input, "keydown", operation(onKeyDown));
|
| 129 |
connect(input, "focus", onFocus);
|
| 130 |
connect(input, "blur", onBlur);
|
| 131 |
|
| 132 |
+
function drag_(e) {
|
| 133 |
+
if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
|
| 134 |
+
e_stop(e);
|
| 135 |
+
}
|
| 136 |
+
if (options.dragDrop) {
|
| 137 |
+
connect(scroller, "dragstart", onDragStart);
|
| 138 |
+
connect(scroller, "dragenter", drag_);
|
| 139 |
+
connect(scroller, "dragover", drag_);
|
| 140 |
+
connect(scroller, "drop", operation(onDrop));
|
| 141 |
+
}
|
| 142 |
connect(scroller, "paste", function(){focusInput(); fastPoll();});
|
| 143 |
connect(input, "paste", fastPoll);
|
| 144 |
+
connect(input, "cut", operation(function(){
|
| 145 |
+
if (!options.readOnly) replaceSelection("");
|
| 146 |
+
}));
|
| 147 |
+
|
| 148 |
+
// Needed to handle Tab key in KHTML
|
| 149 |
+
if (khtml) connect(sizer, "mouseup", function() {
|
| 150 |
+
if (document.activeElement == input) input.blur();
|
| 151 |
+
focusInput();
|
| 152 |
+
});
|
| 153 |
|
| 154 |
// IE throws unspecified error in certain cases, when
|
| 155 |
// trying to access activeElement before onload
|
| 156 |
+
var hasFocus; try { hasFocus = (document.activeElement == input); } catch(e) { }
|
| 157 |
+
if (hasFocus || options.autofocus) setTimeout(onFocus, 20);
|
| 158 |
else onBlur();
|
| 159 |
|
| 160 |
function isLine(l) {return l >= 0 && l < doc.size;}
|
| 168 |
setValue: operation(setValue),
|
| 169 |
getSelection: getSelection,
|
| 170 |
replaceSelection: operation(replaceSelection),
|
| 171 |
+
focus: function(){window.focus(); focusInput(); onFocus(); fastPoll();},
|
| 172 |
setOption: function(option, value) {
|
| 173 |
var oldVal = options[option];
|
| 174 |
options[option] = value;
|
| 175 |
if (option == "mode" || option == "indentUnit") loadMode();
|
| 176 |
+
else if (option == "readOnly" && value == "nocursor") {onBlur(); input.blur();}
|
| 177 |
+
else if (option == "readOnly" && !value) {resetInput(true);}
|
| 178 |
else if (option == "theme") themeChanged();
|
| 179 |
else if (option == "lineWrapping" && oldVal != value) operation(wrappingChanged)();
|
| 180 |
+
else if (option == "tabSize") updateDisplay(true);
|
| 181 |
+
else if (option == "keyMap") keyMapChanged();
|
| 182 |
+
if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber" ||
|
| 183 |
+
option == "theme" || option == "lineNumberFormatter") {
|
| 184 |
+
gutterChanged();
|
| 185 |
+
updateDisplay(true);
|
| 186 |
+
}
|
| 187 |
},
|
| 188 |
getOption: function(option) {return options[option];},
|
| 189 |
undo: operation(undo),
|
| 190 |
redo: operation(redo),
|
| 191 |
indentLine: operation(function(n, dir) {
|
| 192 |
+
if (typeof dir != "string") {
|
| 193 |
+
if (dir == null) dir = options.smartIndent ? "smart" : "prev";
|
| 194 |
+
else dir = dir ? "add" : "subtract";
|
| 195 |
+
}
|
| 196 |
+
if (isLine(n)) indentLine(n, dir);
|
| 197 |
}),
|
| 198 |
indentSelection: operation(indentSelected),
|
| 199 |
historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
|
| 200 |
clearHistory: function() {history = new History();},
|
| 201 |
+
setHistory: function(histData) {
|
| 202 |
+
history = new History();
|
| 203 |
+
history.done = histData.done;
|
| 204 |
+
history.undone = histData.undone;
|
| 205 |
+
},
|
| 206 |
+
getHistory: function() {
|
| 207 |
+
history.time = 0;
|
| 208 |
+
return {done: history.done.concat([]), undone: history.undone.concat([])};
|
| 209 |
+
},
|
| 210 |
matchBrackets: operation(function(){matchBrackets(true);}),
|
| 211 |
getTokenAt: operation(function(pos) {
|
| 212 |
pos = clipPos(pos);
|
| 213 |
+
return getLine(pos.line).getTokenAt(mode, getStateBefore(pos.line), options.tabSize, pos.ch);
|
| 214 |
}),
|
| 215 |
getStateAfter: function(line) {
|
| 216 |
line = clipLine(line == null ? doc.size - 1: line);
|
| 217 |
return getStateBefore(line + 1);
|
| 218 |
},
|
| 219 |
+
cursorCoords: function(start, mode) {
|
| 220 |
if (start == null) start = sel.inverted;
|
| 221 |
+
return this.charCoords(start ? sel.from : sel.to, mode);
|
| 222 |
+
},
|
| 223 |
+
charCoords: function(pos, mode) {
|
| 224 |
+
pos = clipPos(pos);
|
| 225 |
+
if (mode == "local") return localCoords(pos, false);
|
| 226 |
+
if (mode == "div") return localCoords(pos, true);
|
| 227 |
+
return pageCoords(pos);
|
| 228 |
},
|
|
|
|
| 229 |
coordsChar: function(coords) {
|
| 230 |
var off = eltOffset(lineSpace);
|
| 231 |
return coordsChar(coords.x - off.left, coords.y - off.top);
|
| 232 |
},
|
| 233 |
markText: operation(markText),
|
| 234 |
setBookmark: setBookmark,
|
| 235 |
+
findMarksAt: findMarksAt,
|
| 236 |
setMarker: operation(addGutterMarker),
|
| 237 |
clearMarker: operation(removeGutterMarker),
|
| 238 |
setLineClass: operation(setLineClass),
|
| 247 |
return line;
|
| 248 |
},
|
| 249 |
lineInfo: lineInfo,
|
| 250 |
+
getViewport: function() { return {from: showingFrom, to: showingTo};},
|
| 251 |
addWidget: function(pos, node, scroll, vert, horiz) {
|
| 252 |
pos = localCoords(clipPos(pos));
|
| 253 |
var top = pos.yBot, left = pos.x;
|
| 254 |
node.style.position = "absolute";
|
| 255 |
+
sizer.appendChild(node);
|
| 256 |
if (vert == "over") top = pos.y;
|
| 257 |
else if (vert == "near") {
|
| 258 |
var vspace = Math.max(scroller.offsetHeight, doc.height * textHeight()),
|
| 259 |
+
hspace = Math.max(sizer.clientWidth, lineSpace.clientWidth) - paddingLeft();
|
| 260 |
if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight)
|
| 261 |
top = pos.y - node.offsetHeight;
|
| 262 |
if (left + node.offsetWidth > hspace)
|
| 265 |
node.style.top = (top + paddingTop()) + "px";
|
| 266 |
node.style.left = node.style.right = "";
|
| 267 |
if (horiz == "right") {
|
| 268 |
+
left = sizer.clientWidth - node.offsetWidth;
|
| 269 |
node.style.right = "0px";
|
| 270 |
} else {
|
| 271 |
if (horiz == "left") left = 0;
|
| 272 |
+
else if (horiz == "middle") left = (sizer.clientWidth - node.offsetWidth) / 2;
|
| 273 |
node.style.left = (left + paddingLeft()) + "px";
|
| 274 |
}
|
| 275 |
if (scroll)
|
| 299 |
if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
|
| 300 |
}),
|
| 301 |
replaceRange: operation(replaceRange),
|
| 302 |
+
getRange: function(from, to, lineSep) {return getRange(clipPos(from), clipPos(to), lineSep);},
|
| 303 |
|
| 304 |
+
triggerOnKeyDown: operation(onKeyDown),
|
| 305 |
execCommand: function(cmd) {return commands[cmd](instance);},
|
| 306 |
// Stuff used by commands, probably not much use to outside code.
|
| 307 |
moveH: operation(moveH),
|
| 308 |
deleteH: operation(deleteH),
|
| 309 |
moveV: operation(moveV),
|
| 310 |
+
toggleOverwrite: function() {
|
| 311 |
+
if(overwrite){
|
| 312 |
+
overwrite = false;
|
| 313 |
+
cursor.className = cursor.className.replace(" CodeMirror-overwrite", "");
|
| 314 |
+
} else {
|
| 315 |
+
overwrite = true;
|
| 316 |
+
cursor.className += " CodeMirror-overwrite";
|
| 317 |
+
}
|
| 318 |
+
},
|
| 319 |
|
| 320 |
posFromIndex: function(off) {
|
| 321 |
var lineNo = 0, ch;
|
| 335 |
});
|
| 336 |
return index;
|
| 337 |
},
|
| 338 |
+
scrollTo: function(x, y) {
|
| 339 |
+
if (x != null) scroller.scrollLeft = x;
|
| 340 |
+
if (y != null) scrollbar.scrollTop = scroller.scrollTop = y;
|
| 341 |
+
updateDisplay([]);
|
| 342 |
+
},
|
| 343 |
+
getScrollInfo: function() {
|
| 344 |
+
return {x: scroller.scrollLeft, y: scrollbar.scrollTop,
|
| 345 |
+
height: scrollbar.scrollHeight, width: scroller.scrollWidth};
|
| 346 |
+
},
|
| 347 |
+
setSize: function(width, height) {
|
| 348 |
+
function interpret(val) {
|
| 349 |
+
val = String(val);
|
| 350 |
+
return /^\d+$/.test(val) ? val + "px" : val;
|
| 351 |
+
}
|
| 352 |
+
if (width != null) wrapper.style.width = interpret(width);
|
| 353 |
+
if (height != null) scroller.style.height = interpret(height);
|
| 354 |
+
instance.refresh();
|
| 355 |
+
},
|
| 356 |
|
| 357 |
operation: function(f){return operation(f)();},
|
| 358 |
+
compoundChange: function(f){return compoundChange(f);},
|
| 359 |
+
refresh: function(){
|
| 360 |
+
updateDisplay(true, null, lastScrollTop);
|
| 361 |
+
if (scrollbar.scrollHeight > lastScrollTop)
|
| 362 |
+
scrollbar.scrollTop = lastScrollTop;
|
| 363 |
+
},
|
| 364 |
getInputField: function(){return input;},
|
| 365 |
getWrapperElement: function(){return wrapper;},
|
| 366 |
getScrollerElement: function(){return scroller;},
|
| 380 |
splitLines(code), top, top);
|
| 381 |
updateInput = true;
|
| 382 |
}
|
| 383 |
+
function getValue(lineSep) {
|
| 384 |
var text = [];
|
| 385 |
doc.iter(0, doc.size, function(line) { text.push(line.text); });
|
| 386 |
+
return text.join(lineSep || "\n");
|
| 387 |
+
}
|
| 388 |
+
|
| 389 |
+
function onScrollBar(e) {
|
| 390 |
+
if (scrollbar.scrollTop != lastScrollTop) {
|
| 391 |
+
lastScrollTop = scroller.scrollTop = scrollbar.scrollTop;
|
| 392 |
+
updateDisplay([]);
|
| 393 |
+
}
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
function onScrollMain(e) {
|
| 397 |
+
if (options.fixedGutter && gutter.style.left != scroller.scrollLeft + "px")
|
| 398 |
+
gutter.style.left = scroller.scrollLeft + "px";
|
| 399 |
+
if (scroller.scrollTop != lastScrollTop) {
|
| 400 |
+
lastScrollTop = scroller.scrollTop;
|
| 401 |
+
if (scrollbar.scrollTop != lastScrollTop)
|
| 402 |
+
scrollbar.scrollTop = lastScrollTop;
|
| 403 |
+
updateDisplay([]);
|
| 404 |
+
}
|
| 405 |
+
if (options.onScroll) options.onScroll(instance);
|
| 406 |
}
|
| 407 |
|
| 408 |
function onMouseDown(e) {
|
| 409 |
+
setShift(e_prop(e, "shiftKey"));
|
| 410 |
// Check whether this is a click in a widget
|
| 411 |
for (var n = e_target(e); n != wrapper; n = n.parentNode)
|
| 412 |
+
if (n.parentNode == sizer && n != mover) return;
|
| 413 |
|
| 414 |
// See if this is a click in the gutter
|
| 415 |
for (var n = e_target(e); n != wrapper; n = n.parentNode)
|
| 423 |
|
| 424 |
switch (e_button(e)) {
|
| 425 |
case 3:
|
| 426 |
+
if (gecko) onContextMenu(e);
|
| 427 |
return;
|
| 428 |
case 2:
|
| 429 |
if (start) setCursor(start.line, start.ch, true);
|
| 430 |
+
setTimeout(focusInput, 20);
|
| 431 |
+
e_preventDefault(e);
|
| 432 |
return;
|
| 433 |
}
|
| 434 |
// For button 1, if it was clicked inside the editor
|
| 438 |
|
| 439 |
if (!focused) onFocus();
|
| 440 |
|
| 441 |
+
var now = +new Date, type = "single";
|
| 442 |
if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) {
|
| 443 |
+
type = "triple";
|
| 444 |
e_preventDefault(e);
|
| 445 |
setTimeout(focusInput, 20);
|
| 446 |
+
selectLine(start.line);
|
| 447 |
} else if (lastClick && lastClick.time > now - 400 && posEq(lastClick.pos, start)) {
|
| 448 |
+
type = "double";
|
| 449 |
lastDoubleClick = {time: now, pos: start};
|
| 450 |
e_preventDefault(e);
|
| 451 |
+
var word = findWordAt(start);
|
| 452 |
+
setSelectionUser(word.from, word.to);
|
| 453 |
} else { lastClick = {time: now, pos: start}; }
|
| 454 |
|
| 455 |
+
function dragEnd(e2) {
|
| 456 |
+
if (webkit) scroller.draggable = false;
|
| 457 |
+
draggingText = false;
|
| 458 |
+
up(); drop();
|
| 459 |
+
if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
|
| 460 |
+
e_preventDefault(e2);
|
| 461 |
+
setCursor(start.line, start.ch, true);
|
| 462 |
+
focusInput();
|
| 463 |
+
}
|
| 464 |
+
}
|
| 465 |
var last = start, going;
|
| 466 |
+
if (options.dragDrop && dragAndDrop && !options.readOnly && !posEq(sel.from, sel.to) &&
|
| 467 |
+
!posLess(start, sel.from) && !posLess(sel.to, start) && type == "single") {
|
| 468 |
// Let the drag handler handle this.
|
| 469 |
+
if (webkit) scroller.draggable = true;
|
| 470 |
+
var up = connect(document, "mouseup", operation(dragEnd), true);
|
| 471 |
+
var drop = connect(scroller, "drop", operation(dragEnd), true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 472 |
draggingText = true;
|
| 473 |
+
// IE's approach to draggable
|
| 474 |
+
if (scroller.dragDrop) scroller.dragDrop();
|
| 475 |
return;
|
| 476 |
}
|
| 477 |
e_preventDefault(e);
|
| 478 |
+
if (type == "single") setCursor(start.line, start.ch, true);
|
| 479 |
+
|
| 480 |
+
var startstart = sel.from, startend = sel.to;
|
| 481 |
+
|
| 482 |
+
function doSelect(cur) {
|
| 483 |
+
if (type == "single") {
|
| 484 |
+
setSelectionUser(start, cur);
|
| 485 |
+
} else if (type == "double") {
|
| 486 |
+
var word = findWordAt(cur);
|
| 487 |
+
if (posLess(cur, startstart)) setSelectionUser(word.from, startend);
|
| 488 |
+
else setSelectionUser(startstart, word.to);
|
| 489 |
+
} else if (type == "triple") {
|
| 490 |
+
if (posLess(cur, startstart)) setSelectionUser(startend, clipPos({line: cur.line, ch: 0}));
|
| 491 |
+
else setSelectionUser(startstart, clipPos({line: cur.line + 1, ch: 0}));
|
| 492 |
+
}
|
| 493 |
+
}
|
| 494 |
|
| 495 |
function extend(e) {
|
| 496 |
var cur = posFromMouse(e, true);
|
| 497 |
if (cur && !posEq(cur, last)) {
|
| 498 |
if (!focused) onFocus();
|
| 499 |
last = cur;
|
| 500 |
+
doSelect(cur);
|
| 501 |
updateInput = false;
|
| 502 |
var visible = visibleLines();
|
| 503 |
if (cur.line >= visible.to || cur.line < visible.from)
|
| 505 |
}
|
| 506 |
}
|
| 507 |
|
| 508 |
+
function done(e) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 509 |
clearTimeout(going);
|
| 510 |
var cur = posFromMouse(e);
|
| 511 |
+
if (cur) doSelect(cur);
|
| 512 |
e_preventDefault(e);
|
| 513 |
focusInput();
|
| 514 |
updateInput = true;
|
| 515 |
move(); up();
|
| 516 |
+
}
|
| 517 |
+
var move = connect(document, "mousemove", operation(function(e) {
|
| 518 |
+
clearTimeout(going);
|
| 519 |
+
e_preventDefault(e);
|
| 520 |
+
if (!ie && !e_button(e)) done(e);
|
| 521 |
+
else extend(e);
|
| 522 |
}), true);
|
| 523 |
+
var up = connect(document, "mouseup", operation(done), true);
|
| 524 |
}
|
| 525 |
function onDoubleClick(e) {
|
| 526 |
for (var n = e_target(e); n != wrapper; n = n.parentNode)
|
| 527 |
if (n.parentNode == gutterText) return e_preventDefault(e);
|
|
|
|
|
|
|
|
|
|
| 528 |
e_preventDefault(e);
|
|
|
|
| 529 |
}
|
| 530 |
function onDrop(e) {
|
| 531 |
+
if (options.onDragEvent && options.onDragEvent(instance, addStop(e))) return;
|
| 532 |
+
e_preventDefault(e);
|
| 533 |
var pos = posFromMouse(e, true), files = e.dataTransfer.files;
|
| 534 |
if (!pos || options.readOnly) return;
|
| 535 |
if (files && files.length && window.FileReader && window.File) {
|
| 536 |
+
var n = files.length, text = Array(n), read = 0;
|
| 537 |
+
var loadFile = function(file, i) {
|
| 538 |
var reader = new FileReader;
|
| 539 |
reader.onload = function() {
|
| 540 |
text[i] = reader.result;
|
| 547 |
}
|
| 548 |
};
|
| 549 |
reader.readAsText(file);
|
| 550 |
+
};
|
|
|
|
| 551 |
for (var i = 0; i < n; ++i) loadFile(files[i], i);
|
| 552 |
+
} else {
|
| 553 |
+
// Don't do a replace if the drop happened inside of the selected text.
|
| 554 |
+
if (draggingText && !(posLess(pos, sel.from) || posLess(sel.to, pos))) return;
|
| 555 |
try {
|
| 556 |
var text = e.dataTransfer.getData("Text");
|
| 557 |
if (text) {
|
| 558 |
+
compoundChange(function() {
|
| 559 |
+
var curFrom = sel.from, curTo = sel.to;
|
| 560 |
+
setSelectionUser(pos, pos);
|
| 561 |
+
if (draggingText) replaceRange("", curFrom, curTo);
|
| 562 |
+
replaceSelection(text);
|
| 563 |
+
focusInput();
|
| 564 |
+
});
|
| 565 |
}
|
| 566 |
}
|
| 567 |
catch(e){}
|
| 569 |
}
|
| 570 |
function onDragStart(e) {
|
| 571 |
var txt = getSelection();
|
|
|
|
|
|
|
|
|
|
| 572 |
e.dataTransfer.setData("Text", txt);
|
| 573 |
+
|
| 574 |
+
// Use dummy image instead of default browsers image.
|
| 575 |
+
if (gecko || chrome || opera) {
|
| 576 |
+
var img = elt('img');
|
| 577 |
+
img.scr = 'data:image/gif;base64,R0lGODdhAgACAIAAAAAAAP///ywAAAAAAgACAAACAoRRADs='; //1x1 image
|
| 578 |
+
e.dataTransfer.setDragImage(img, 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 579 |
}
|
| 580 |
+
}
|
| 581 |
+
|
| 582 |
+
function doHandleBinding(bound, dropShift) {
|
| 583 |
if (typeof bound == "string") {
|
| 584 |
+
bound = commands[bound];
|
| 585 |
+
if (!bound) return false;
|
| 586 |
+
}
|
| 587 |
+
var prevShift = shiftSelecting;
|
| 588 |
+
try {
|
| 589 |
+
if (options.readOnly) suppressEdits = true;
|
| 590 |
+
if (dropShift) shiftSelecting = null;
|
|
|
|
| 591 |
bound(instance);
|
| 592 |
+
} catch(e) {
|
| 593 |
+
if (e != Pass) throw e;
|
| 594 |
+
return false;
|
| 595 |
+
} finally {
|
| 596 |
shiftSelecting = prevShift;
|
| 597 |
+
suppressEdits = false;
|
| 598 |
+
}
|
| 599 |
return true;
|
| 600 |
}
|
| 601 |
+
var maybeTransition;
|
| 602 |
+
function handleKeyBinding(e) {
|
| 603 |
+
// Handle auto keymap transitions
|
| 604 |
+
var startMap = getKeyMap(options.keyMap), next = startMap.auto;
|
| 605 |
+
clearTimeout(maybeTransition);
|
| 606 |
+
if (next && !isModifierKey(e)) maybeTransition = setTimeout(function() {
|
| 607 |
+
if (getKeyMap(options.keyMap) == startMap) {
|
| 608 |
+
options.keyMap = (next.call ? next.call(null, instance) : next);
|
| 609 |
+
}
|
| 610 |
+
}, 50);
|
| 611 |
+
|
| 612 |
+
var name = keyNames[e_prop(e, "keyCode")], handled = false;
|
| 613 |
+
if (name == null || e.altGraphKey) return false;
|
| 614 |
+
if (e_prop(e, "altKey")) name = "Alt-" + name;
|
| 615 |
+
if (e_prop(e, "ctrlKey")) name = "Ctrl-" + name;
|
| 616 |
+
if (e_prop(e, "metaKey")) name = "Cmd-" + name;
|
| 617 |
+
|
| 618 |
+
var stopped = false;
|
| 619 |
+
function stop() { stopped = true; }
|
| 620 |
+
|
| 621 |
+
if (e_prop(e, "shiftKey")) {
|
| 622 |
+
handled = lookupKey("Shift-" + name, options.extraKeys, options.keyMap,
|
| 623 |
+
function(b) {return doHandleBinding(b, true);}, stop)
|
| 624 |
+
|| lookupKey(name, options.extraKeys, options.keyMap, function(b) {
|
| 625 |
+
if (typeof b == "string" && /^go[A-Z]/.test(b)) return doHandleBinding(b);
|
| 626 |
+
}, stop);
|
| 627 |
+
} else {
|
| 628 |
+
handled = lookupKey(name, options.extraKeys, options.keyMap, doHandleBinding, stop);
|
| 629 |
+
}
|
| 630 |
+
if (stopped) handled = false;
|
| 631 |
+
if (handled) {
|
| 632 |
+
e_preventDefault(e);
|
| 633 |
+
restartBlink();
|
| 634 |
+
if (ie) { e.oldKeyCode = e.keyCode; e.keyCode = 0; }
|
| 635 |
+
}
|
| 636 |
+
return handled;
|
| 637 |
+
}
|
| 638 |
+
function handleCharBinding(e, ch) {
|
| 639 |
+
var handled = lookupKey("'" + ch + "'", options.extraKeys,
|
| 640 |
+
options.keyMap, function(b) { return doHandleBinding(b, true); });
|
| 641 |
+
if (handled) {
|
| 642 |
+
e_preventDefault(e);
|
| 643 |
+
restartBlink();
|
| 644 |
+
}
|
| 645 |
+
return handled;
|
| 646 |
+
}
|
| 647 |
+
|
| 648 |
var lastStoppedKey = null;
|
| 649 |
function onKeyDown(e) {
|
| 650 |
if (!focused) onFocus();
|
| 651 |
+
if (ie && e.keyCode == 27) { e.returnValue = false; }
|
| 652 |
+
if (pollingFast) { if (readInput()) pollingFast = false; }
|
| 653 |
+
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
| 654 |
+
var code = e_prop(e, "keyCode");
|
| 655 |
// IE does strange things with escape.
|
| 656 |
+
setShift(code == 16 || e_prop(e, "shiftKey"));
|
|
|
|
| 657 |
// First give onKeyEvent option a chance to handle this.
|
|
|
|
| 658 |
var handled = handleKeyBinding(e);
|
| 659 |
+
if (opera) {
|
| 660 |
+
lastStoppedKey = handled ? code : null;
|
| 661 |
// Opera has no cut event... we try to at least catch the key combo
|
| 662 |
+
if (!handled && code == 88 && e_prop(e, mac ? "metaKey" : "ctrlKey"))
|
| 663 |
replaceSelection("");
|
| 664 |
}
|
| 665 |
}
|
| 666 |
function onKeyPress(e) {
|
| 667 |
+
if (pollingFast) readInput();
|
| 668 |
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
| 669 |
+
var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode");
|
| 670 |
+
if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
|
| 671 |
+
if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(e)) return;
|
| 672 |
+
var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
|
| 673 |
+
if (options.electricChars && mode.electricChars && options.smartIndent && !options.readOnly) {
|
| 674 |
if (mode.electricChars.indexOf(ch) > -1)
|
| 675 |
setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 75);
|
| 676 |
}
|
| 677 |
+
if (handleCharBinding(e, ch)) return;
|
| 678 |
fastPoll();
|
| 679 |
}
|
| 680 |
function onKeyUp(e) {
|
| 681 |
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
|
| 682 |
+
if (e_prop(e, "keyCode") == 16) shiftSelecting = null;
|
| 683 |
}
|
| 684 |
|
| 685 |
function onFocus() {
|
| 686 |
+
if (options.readOnly == "nocursor") return;
|
| 687 |
if (!focused) {
|
| 688 |
if (options.onFocus) options.onFocus(instance);
|
| 689 |
focused = true;
|
| 690 |
+
if (scroller.className.search(/\bCodeMirror-focused\b/) == -1)
|
| 691 |
+
scroller.className += " CodeMirror-focused";
|
| 692 |
if (!leaveInputAlone) resetInput(true);
|
| 693 |
}
|
| 694 |
slowPoll();
|
| 698 |
if (focused) {
|
| 699 |
if (options.onBlur) options.onBlur(instance);
|
| 700 |
focused = false;
|
| 701 |
+
if (bracketHighlighted)
|
| 702 |
+
operation(function(){
|
| 703 |
+
if (bracketHighlighted) { bracketHighlighted(); bracketHighlighted = null; }
|
| 704 |
+
})();
|
| 705 |
+
scroller.className = scroller.className.replace(" CodeMirror-focused", "");
|
| 706 |
}
|
| 707 |
clearInterval(blinker);
|
| 708 |
setTimeout(function() {if (!focused) shiftSelecting = null;}, 150);
|
| 711 |
// Replace the range from from to to by the strings in newText.
|
| 712 |
// Afterwards, set the selection to selFrom, selTo.
|
| 713 |
function updateLines(from, to, newText, selFrom, selTo) {
|
| 714 |
+
if (suppressEdits) return;
|
| 715 |
if (history) {
|
| 716 |
var old = [];
|
| 717 |
doc.iter(from.line, to.line + 1, function(line) { old.push(line.text); });
|
| 721 |
updateLinesNoUndo(from, to, newText, selFrom, selTo);
|
| 722 |
}
|
| 723 |
function unredoHelper(from, to) {
|
| 724 |
+
if (!from.length) return;
|
| 725 |
+
var set = from.pop(), out = [];
|
| 726 |
+
for (var i = set.length - 1; i >= 0; i -= 1) {
|
| 727 |
+
var change = set[i];
|
| 728 |
var replaced = [], end = change.start + change.added;
|
| 729 |
doc.iter(change.start, end, function(line) { replaced.push(line.text); });
|
| 730 |
+
out.push({start: change.start, added: change.old.length, old: replaced});
|
| 731 |
+
var pos = {line: change.start + change.old.length - 1,
|
| 732 |
+
ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])};
|
| 733 |
updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: getLine(end-1).text.length}, change.old, pos, pos);
|
|
|
|
| 734 |
}
|
| 735 |
+
updateInput = true;
|
| 736 |
+
to.push(out);
|
| 737 |
}
|
| 738 |
function undo() {unredoHelper(history.done, history.undone);}
|
| 739 |
function redo() {unredoHelper(history.undone, history.done);}
|
| 740 |
|
| 741 |
function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
|
| 742 |
+
if (suppressEdits) return;
|
| 743 |
+
var recomputeMaxLength = false, maxLineLength = maxLine.text.length;
|
| 744 |
if (!options.lineWrapping)
|
| 745 |
+
doc.iter(from.line, to.line + 1, function(line) {
|
| 746 |
+
if (!line.hidden && line.text.length == maxLineLength) {recomputeMaxLength = true; return true;}
|
| 747 |
});
|
| 748 |
if (from.line != to.line || newText.length > 1) gutterDirty = true;
|
| 749 |
|
| 790 |
doc.insert(from.line + 1, added);
|
| 791 |
}
|
| 792 |
if (options.lineWrapping) {
|
| 793 |
+
var perLine = Math.max(5, scroller.clientWidth / charWidth() - 3);
|
| 794 |
doc.iter(from.line, from.line + newText.length, function(line) {
|
| 795 |
if (line.hidden) return;
|
| 796 |
var guess = Math.ceil(line.text.length / perLine) || 1;
|
| 797 |
if (guess != line.height) updateLineHeight(line, guess);
|
| 798 |
});
|
| 799 |
} else {
|
| 800 |
+
doc.iter(from.line, from.line + newText.length, function(line) {
|
| 801 |
var l = line.text;
|
| 802 |
+
if (!line.hidden && l.length > maxLineLength) {
|
| 803 |
+
maxLine = line; maxLineLength = l.length; maxLineChanged = true;
|
| 804 |
recomputeMaxLength = false;
|
| 805 |
}
|
| 806 |
});
|
| 807 |
+
if (recomputeMaxLength) updateMaxLine = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 808 |
}
|
| 809 |
|
| 810 |
// Add these lines to the work array, so that they will be
|
| 830 |
|
| 831 |
// Update the selection
|
| 832 |
function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
|
| 833 |
+
setSelection(clipPos(selFrom), clipPos(selTo),
|
| 834 |
+
updateLine(sel.from.line), updateLine(sel.to.line));
|
| 835 |
+
}
|
| 836 |
+
|
| 837 |
+
function needsScrollbar() {
|
| 838 |
+
var realHeight = doc.height * textHeight() + 2 * paddingTop();
|
| 839 |
+
return realHeight * .99 > scroller.offsetHeight ? realHeight : false;
|
| 840 |
+
}
|
| 841 |
+
|
| 842 |
+
function updateVerticalScroll(scrollTop) {
|
| 843 |
+
var scrollHeight = needsScrollbar();
|
| 844 |
+
scrollbar.style.display = scrollHeight ? "block" : "none";
|
| 845 |
+
if (scrollHeight) {
|
| 846 |
+
scrollbarInner.style.height = sizer.style.minHeight = scrollHeight + "px";
|
| 847 |
+
scrollbar.style.height = scroller.clientHeight + "px";
|
| 848 |
+
if (scrollTop != null) {
|
| 849 |
+
scrollbar.scrollTop = scroller.scrollTop = scrollTop;
|
| 850 |
+
// 'Nudge' the scrollbar to work around a Webkit bug where,
|
| 851 |
+
// in some situations, we'd end up with a scrollbar that
|
| 852 |
+
// reported its scrollTop (and looked) as expected, but
|
| 853 |
+
// *behaved* as if it was still in a previous state (i.e.
|
| 854 |
+
// couldn't scroll up, even though it appeared to be at the
|
| 855 |
+
// bottom).
|
| 856 |
+
if (webkit) setTimeout(function() {
|
| 857 |
+
if (scrollbar.scrollTop != scrollTop) return;
|
| 858 |
+
scrollbar.scrollTop = scrollTop + (scrollTop ? -1 : 1);
|
| 859 |
+
scrollbar.scrollTop = scrollTop;
|
| 860 |
+
}, 0);
|
| 861 |
+
}
|
| 862 |
+
} else {
|
| 863 |
+
sizer.style.minHeight = "";
|
| 864 |
+
}
|
| 865 |
+
// Position the mover div to align with the current virtual scroll position
|
| 866 |
+
mover.style.top = displayOffset * textHeight() + "px";
|
| 867 |
+
}
|
| 868 |
|
| 869 |
+
function computeMaxLength() {
|
| 870 |
+
maxLine = getLine(0); maxLineChanged = true;
|
| 871 |
+
var maxLineLength = maxLine.text.length;
|
| 872 |
+
doc.iter(1, doc.size, function(line) {
|
| 873 |
+
var l = line.text;
|
| 874 |
+
if (!line.hidden && l.length > maxLineLength) {
|
| 875 |
+
maxLineLength = l.length; maxLine = line;
|
| 876 |
+
}
|
| 877 |
+
});
|
| 878 |
+
updateMaxLine = false;
|
| 879 |
}
|
| 880 |
|
| 881 |
function replaceRange(code, from, to) {
|
| 911 |
updateLines(from, to, code, newSel.from, newSel.to);
|
| 912 |
}
|
| 913 |
|
| 914 |
+
function getRange(from, to, lineSep) {
|
| 915 |
var l1 = from.line, l2 = to.line;
|
| 916 |
if (l1 == l2) return getLine(l1).text.slice(from.ch, to.ch);
|
| 917 |
var code = [getLine(l1).text.slice(from.ch)];
|
| 918 |
doc.iter(l1 + 1, l2, function(line) { code.push(line.text); });
|
| 919 |
code.push(getLine(l2).text.slice(0, to.ch));
|
| 920 |
+
return code.join(lineSep || "\n");
|
| 921 |
}
|
| 922 |
+
function getSelection(lineSep) {
|
| 923 |
+
return getRange(sel.from, sel.to, lineSep);
|
| 924 |
}
|
| 925 |
|
|
|
|
| 926 |
function slowPoll() {
|
| 927 |
if (pollingFast) return;
|
| 928 |
poll.set(options.pollInterval, function() {
|
| 952 |
// supported or compatible enough yet to rely on.)
|
| 953 |
var prevInput = "";
|
| 954 |
function readInput() {
|
| 955 |
+
if (leaveInputAlone || !focused || hasSelection(input) || options.readOnly) return false;
|
| 956 |
var text = input.value;
|
| 957 |
if (text == prevInput) return false;
|
| 958 |
shiftSelecting = null;
|
| 963 |
else if (overwrite && posEq(sel.from, sel.to))
|
| 964 |
sel.to = {line: sel.to.line, ch: Math.min(getLine(sel.to.line).text.length, sel.to.ch + (text.length - same))};
|
| 965 |
replaceSelection(text.slice(same), "end");
|
| 966 |
+
if (text.length > 1000) { input.value = prevInput = ""; }
|
| 967 |
+
else prevInput = text;
|
| 968 |
return true;
|
| 969 |
}
|
| 970 |
function resetInput(user) {
|
| 971 |
if (!posEq(sel.from, sel.to)) {
|
| 972 |
prevInput = "";
|
| 973 |
input.value = getSelection();
|
| 974 |
+
if (focused) selectInput(input);
|
| 975 |
} else if (user) prevInput = input.value = "";
|
| 976 |
}
|
| 977 |
|
| 978 |
function focusInput() {
|
| 979 |
+
if (options.readOnly != "nocursor") input.focus();
|
| 980 |
}
|
| 981 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 982 |
function scrollCursorIntoView() {
|
| 983 |
+
var coords = calculateCursorCoords();
|
| 984 |
+
scrollIntoView(coords.x, coords.y, coords.x, coords.yBot);
|
| 985 |
+
if (!focused) return;
|
| 986 |
+
var box = sizer.getBoundingClientRect(), doScroll = null;
|
| 987 |
+
if (coords.y + box.top < 0) doScroll = true;
|
| 988 |
+
else if (coords.y + box.top + textHeight() > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
|
| 989 |
+
if (doScroll != null) {
|
| 990 |
+
var hidden = cursor.style.display == "none";
|
| 991 |
+
if (hidden) {
|
| 992 |
+
cursor.style.display = "";
|
| 993 |
+
cursor.style.left = coords.x + "px";
|
| 994 |
+
cursor.style.top = (coords.y - displayOffset) + "px";
|
| 995 |
+
}
|
| 996 |
+
cursor.scrollIntoView(doScroll);
|
| 997 |
+
if (hidden) cursor.style.display = "none";
|
| 998 |
+
}
|
| 999 |
+
}
|
| 1000 |
+
function calculateCursorCoords() {
|
| 1001 |
var cursor = localCoords(sel.inverted ? sel.from : sel.to);
|
| 1002 |
var x = options.lineWrapping ? Math.min(cursor.x, lineSpace.offsetWidth) : cursor.x;
|
| 1003 |
+
return {x: x, y: cursor.y, yBot: cursor.yBot};
|
| 1004 |
}
|
| 1005 |
function scrollIntoView(x1, y1, x2, y2) {
|
| 1006 |
+
var scrollPos = calculateScrollPos(x1, y1, x2, y2);
|
| 1007 |
+
if (scrollPos.scrollLeft != null) {scroller.scrollLeft = scrollPos.scrollLeft;}
|
| 1008 |
+
if (scrollPos.scrollTop != null) {scrollbar.scrollTop = scroller.scrollTop = scrollPos.scrollTop;}
|
| 1009 |
+
}
|
| 1010 |
+
function calculateScrollPos(x1, y1, x2, y2) {
|
| 1011 |
+
var pl = paddingLeft(), pt = paddingTop();
|
| 1012 |
y1 += pt; y2 += pt; x1 += pl; x2 += pl;
|
| 1013 |
+
var screen = scroller.clientHeight, screentop = scrollbar.scrollTop, result = {};
|
| 1014 |
+
var docBottom = needsScrollbar() || Infinity;
|
| 1015 |
+
var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10;
|
| 1016 |
+
if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1);
|
| 1017 |
+
else if (y2 > screentop + screen) result.scrollTop = (atBottom ? docBottom : y2) - screen;
|
| 1018 |
|
| 1019 |
var screenw = scroller.clientWidth, screenleft = scroller.scrollLeft;
|
| 1020 |
var gutterw = options.fixedGutter ? gutter.clientWidth : 0;
|
| 1021 |
+
var atLeft = x1 < gutterw + pl + 10;
|
| 1022 |
+
if (x1 < screenleft + gutterw || atLeft) {
|
| 1023 |
+
if (atLeft) x1 = 0;
|
| 1024 |
+
result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
|
| 1025 |
+
} else if (x2 > screenw + screenleft - 3) {
|
| 1026 |
+
result.scrollLeft = x2 + 10 - screenw;
|
| 1027 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1028 |
return result;
|
| 1029 |
}
|
| 1030 |
|
| 1031 |
+
function visibleLines(scrollTop) {
|
| 1032 |
+
var lh = textHeight(), top = (scrollTop != null ? scrollTop : scrollbar.scrollTop) - paddingTop();
|
| 1033 |
+
var fromHeight = Math.max(0, Math.floor(top / lh));
|
| 1034 |
+
var toHeight = Math.ceil((top + scroller.clientHeight) / lh);
|
| 1035 |
+
return {from: lineAtHeight(doc, fromHeight),
|
| 1036 |
+
to: lineAtHeight(doc, toHeight)};
|
| 1037 |
}
|
| 1038 |
// Uses a set of changes plus the current scroll position to
|
| 1039 |
// determine which DOM updates have to be made, and makes the
|
| 1040 |
// updates.
|
| 1041 |
+
function updateDisplay(changes, suppressCallback, scrollTop) {
|
| 1042 |
if (!scroller.clientWidth) {
|
| 1043 |
showingFrom = showingTo = displayOffset = 0;
|
| 1044 |
return;
|
| 1045 |
}
|
| 1046 |
// Compute the new visible window
|
| 1047 |
+
// If scrollTop is specified, use that to determine which lines
|
| 1048 |
+
// to render instead of the current scrollbar position.
|
| 1049 |
+
var visible = visibleLines(scrollTop);
|
| 1050 |
// Bail out if the visible area is already rendered and nothing changed.
|
| 1051 |
+
if (changes !== true && changes.length == 0 && visible.from > showingFrom && visible.to < showingTo) {
|
| 1052 |
+
updateVerticalScroll(scrollTop);
|
| 1053 |
+
return;
|
| 1054 |
+
}
|
| 1055 |
var from = Math.max(visible.from - 100, 0), to = Math.min(doc.size, visible.to + 100);
|
| 1056 |
if (showingFrom < from && from - showingFrom < 20) from = showingFrom;
|
| 1057 |
if (showingTo > to && showingTo - to < 20) to = Math.min(doc.size, showingTo);
|
| 1069 |
if (range.from >= range.to) intact.splice(i--, 1);
|
| 1070 |
else intactLines += range.to - range.from;
|
| 1071 |
}
|
| 1072 |
+
if (intactLines == to - from && from == showingFrom && to == showingTo) {
|
| 1073 |
+
updateVerticalScroll(scrollTop);
|
| 1074 |
+
return;
|
| 1075 |
+
}
|
| 1076 |
intact.sort(function(a, b) {return a.domStart - b.domStart;});
|
| 1077 |
|
| 1078 |
var th = textHeight(), gutterDisplay = gutter.style.display;
|
| 1079 |
+
lineDiv.style.display = "none";
|
| 1080 |
patchDisplay(from, to, intact);
|
| 1081 |
+
lineDiv.style.display = gutter.style.display = "";
|
| 1082 |
|
|
|
|
|
|
|
| 1083 |
var different = from != showingFrom || to != showingTo || lastSizeC != scroller.clientHeight + th;
|
| 1084 |
// This is just a bogus formula that detects when the editor is
|
| 1085 |
// resized or the font size changes.
|
| 1086 |
if (different) lastSizeC = scroller.clientHeight + th;
|
| 1087 |
+
if (from != showingFrom || to != showingTo && options.onViewportChange)
|
| 1088 |
+
setTimeout(function(){
|
| 1089 |
+
if (options.onViewportChange) options.onViewportChange(instance, from, to);
|
| 1090 |
+
});
|
| 1091 |
showingFrom = from; showingTo = to;
|
| 1092 |
displayOffset = heightAtLine(doc, from);
|
|
|
|
|
|
|
| 1093 |
|
| 1094 |
// Since this is all rather error prone, it is honoured with the
|
| 1095 |
// only assertion in the whole file.
|
| 1097 |
throw new Error("BAD PATCH! " + JSON.stringify(intact) + " size=" + (showingTo - showingFrom) +
|
| 1098 |
" nodes=" + lineDiv.childNodes.length);
|
| 1099 |
|
| 1100 |
+
function checkHeights() {
|
| 1101 |
+
var curNode = lineDiv.firstChild, heightChanged = false;
|
|
|
|
| 1102 |
doc.iter(showingFrom, showingTo, function(line) {
|
| 1103 |
+
// Work around bizarro IE7 bug where, sometimes, our curNode
|
| 1104 |
+
// is magically replaced with a new node in the DOM, leaving
|
| 1105 |
+
// us with a reference to an orphan (nextSibling-less) node.
|
| 1106 |
+
if (!curNode) return;
|
| 1107 |
if (!line.hidden) {
|
| 1108 |
var height = Math.round(curNode.offsetHeight / th) || 1;
|
| 1109 |
+
if (line.height != height) {
|
| 1110 |
+
updateLineHeight(line, height);
|
| 1111 |
+
gutterDirty = heightChanged = true;
|
| 1112 |
+
}
|
| 1113 |
}
|
| 1114 |
curNode = curNode.nextSibling;
|
| 1115 |
});
|
| 1116 |
+
return heightChanged;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1117 |
}
|
| 1118 |
+
|
| 1119 |
+
if (options.lineWrapping) checkHeights();
|
| 1120 |
+
|
| 1121 |
gutter.style.display = gutterDisplay;
|
| 1122 |
+
if (different || gutterDirty) {
|
| 1123 |
+
// If the gutter grew in size, re-check heights. If those changed, re-draw gutter.
|
| 1124 |
+
updateGutter() && options.lineWrapping && checkHeights() && updateGutter();
|
| 1125 |
+
}
|
| 1126 |
+
updateVerticalScroll(scrollTop);
|
| 1127 |
+
updateSelection();
|
| 1128 |
if (!suppressCallback && options.onUpdate) options.onUpdate(instance);
|
| 1129 |
return true;
|
| 1130 |
}
|
| 1153 |
}
|
| 1154 |
|
| 1155 |
function patchDisplay(from, to, intact) {
|
| 1156 |
+
function killNode(node) {
|
| 1157 |
+
var tmp = node.nextSibling;
|
| 1158 |
+
node.parentNode.removeChild(node);
|
| 1159 |
+
return tmp;
|
| 1160 |
+
}
|
| 1161 |
// The first pass removes the DOM nodes that aren't intact.
|
| 1162 |
+
if (!intact.length) removeChildren(lineDiv);
|
| 1163 |
else {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1164 |
var domPos = 0, curNode = lineDiv.firstChild, n;
|
| 1165 |
for (var i = 0; i < intact.length; ++i) {
|
| 1166 |
var cur = intact[i];
|
| 1171 |
}
|
| 1172 |
// This pass fills in the lines that actually changed.
|
| 1173 |
var nextIntact = intact.shift(), curNode = lineDiv.firstChild, j = from;
|
|
|
|
|
|
|
| 1174 |
doc.iter(from, to, function(line) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1175 |
if (nextIntact && nextIntact.to == j) nextIntact = intact.shift();
|
| 1176 |
if (!nextIntact || nextIntact.from > j) {
|
| 1177 |
+
if (line.hidden) var lineElement = elt("pre");
|
| 1178 |
+
else {
|
| 1179 |
+
var lineElement = line.getElement(makeTab);
|
| 1180 |
+
if (line.className) lineElement.className = line.className;
|
| 1181 |
+
// Kludge to make sure the styled element lies behind the selection (by z-index)
|
| 1182 |
+
if (line.bgClassName) {
|
| 1183 |
+
var pre = elt("pre", "\u00a0", line.bgClassName, "position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: -2");
|
| 1184 |
+
lineElement = elt("div", [pre, lineElement], null, "position: relative");
|
| 1185 |
+
}
|
| 1186 |
+
}
|
| 1187 |
+
lineDiv.insertBefore(lineElement, curNode);
|
| 1188 |
} else {
|
| 1189 |
curNode = curNode.nextSibling;
|
| 1190 |
}
|
| 1196 |
if (!options.gutter && !options.lineNumbers) return;
|
| 1197 |
var hText = mover.offsetHeight, hEditor = scroller.clientHeight;
|
| 1198 |
gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px";
|
| 1199 |
+
var fragment = document.createDocumentFragment(), i = showingFrom, normalNode;
|
| 1200 |
doc.iter(showingFrom, Math.max(showingTo, showingFrom + 1), function(line) {
|
| 1201 |
if (line.hidden) {
|
| 1202 |
+
fragment.appendChild(elt("pre"));
|
| 1203 |
} else {
|
| 1204 |
var marker = line.gutterMarker;
|
| 1205 |
+
var text = options.lineNumbers ? options.lineNumberFormatter(i + options.firstLineNumber) : null;
|
| 1206 |
if (marker && marker.text)
|
| 1207 |
text = marker.text.replace("%N%", text != null ? text : "");
|
| 1208 |
else if (text == null)
|
| 1209 |
text = "\u00a0";
|
| 1210 |
+
var markerElement = fragment.appendChild(elt("pre", null, marker && marker.style));
|
| 1211 |
+
markerElement.innerHTML = text;
|
| 1212 |
+
for (var j = 1; j < line.height; ++j) {
|
| 1213 |
+
markerElement.appendChild(elt("br"));
|
| 1214 |
+
markerElement.appendChild(document.createTextNode("\u00a0"));
|
| 1215 |
+
}
|
| 1216 |
+
if (!marker) normalNode = i;
|
| 1217 |
}
|
| 1218 |
++i;
|
| 1219 |
});
|
| 1220 |
gutter.style.display = "none";
|
| 1221 |
+
removeChildrenAndAdd(gutterText, fragment);
|
| 1222 |
+
// Make sure scrolling doesn't cause number gutter size to pop
|
| 1223 |
+
if (normalNode != null && options.lineNumbers) {
|
| 1224 |
+
var node = gutterText.childNodes[normalNode - showingFrom];
|
| 1225 |
+
var minwidth = String(doc.size).length, val = eltText(node.firstChild), pad = "";
|
| 1226 |
+
while (val.length + pad.length < minwidth) pad += "\u00a0";
|
| 1227 |
+
if (pad) node.insertBefore(document.createTextNode(pad), node.firstChild);
|
| 1228 |
+
}
|
| 1229 |
gutter.style.display = "";
|
| 1230 |
+
var resized = Math.abs((parseInt(lineSpace.style.marginLeft) || 0) - gutter.offsetWidth) > 2;
|
| 1231 |
lineSpace.style.marginLeft = gutter.offsetWidth + "px";
|
| 1232 |
gutterDirty = false;
|
| 1233 |
+
return resized;
|
| 1234 |
}
|
| 1235 |
+
function updateSelection() {
|
| 1236 |
+
var collapsed = posEq(sel.from, sel.to);
|
| 1237 |
+
var fromPos = localCoords(sel.from, true);
|
| 1238 |
+
var toPos = collapsed ? fromPos : localCoords(sel.to, true);
|
| 1239 |
+
var headPos = sel.inverted ? fromPos : toPos, th = textHeight();
|
| 1240 |
var wrapOff = eltOffset(wrapper), lineOff = eltOffset(lineDiv);
|
| 1241 |
+
inputDiv.style.top = Math.max(0, Math.min(scroller.offsetHeight, headPos.y + lineOff.top - wrapOff.top)) + "px";
|
| 1242 |
+
inputDiv.style.left = Math.max(0, Math.min(scroller.offsetWidth, headPos.x + lineOff.left - wrapOff.left)) + "px";
|
| 1243 |
+
if (collapsed) {
|
| 1244 |
+
cursor.style.top = headPos.y + "px";
|
| 1245 |
+
cursor.style.left = (options.lineWrapping ? Math.min(headPos.x, lineSpace.offsetWidth) : headPos.x) + "px";
|
| 1246 |
cursor.style.display = "";
|
| 1247 |
+
selectionDiv.style.display = "none";
|
| 1248 |
+
} else {
|
| 1249 |
+
var sameLine = fromPos.y == toPos.y, fragment = document.createDocumentFragment();
|
| 1250 |
+
var clientWidth = lineSpace.clientWidth || lineSpace.offsetWidth;
|
| 1251 |
+
var clientHeight = lineSpace.clientHeight || lineSpace.offsetHeight;
|
| 1252 |
+
var add = function(left, top, right, height) {
|
| 1253 |
+
var rstyle = quirksMode ? "width: " + (!right ? clientWidth : clientWidth - right - left) + "px"
|
| 1254 |
+
: "right: " + right + "px";
|
| 1255 |
+
fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
|
| 1256 |
+
"px; top: " + top + "px; " + rstyle + "; height: " + height + "px"));
|
| 1257 |
+
};
|
| 1258 |
+
if (sel.from.ch && fromPos.y >= 0) {
|
| 1259 |
+
var right = sameLine ? clientWidth - toPos.x : 0;
|
| 1260 |
+
add(fromPos.x, fromPos.y, right, th);
|
| 1261 |
+
}
|
| 1262 |
+
var middleStart = Math.max(0, fromPos.y + (sel.from.ch ? th : 0));
|
| 1263 |
+
var middleHeight = Math.min(toPos.y, clientHeight) - middleStart;
|
| 1264 |
+
if (middleHeight > 0.2 * th)
|
| 1265 |
+
add(0, middleStart, 0, middleHeight);
|
| 1266 |
+
if ((!sameLine || !sel.from.ch) && toPos.y < clientHeight - .5 * th)
|
| 1267 |
+
add(0, toPos.y, clientWidth - toPos.x, th);
|
| 1268 |
+
removeChildrenAndAdd(selectionDiv, fragment);
|
| 1269 |
+
cursor.style.display = "none";
|
| 1270 |
+
selectionDiv.style.display = "";
|
| 1271 |
}
|
|
|
|
| 1272 |
}
|
| 1273 |
|
| 1274 |
function setShift(val) {
|
| 1294 |
if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
|
| 1295 |
|
| 1296 |
// Skip over hidden lines.
|
| 1297 |
+
if (from.line != oldFrom) {
|
| 1298 |
+
var from1 = skipHidden(from, oldFrom, sel.from.ch);
|
| 1299 |
+
// If there is no non-hidden line left, force visibility on current line
|
| 1300 |
+
if (!from1) setLineHidden(from.line, false);
|
| 1301 |
+
else from = from1;
|
| 1302 |
+
}
|
| 1303 |
if (to.line != oldTo) to = skipHidden(to, oldTo, sel.to.ch);
|
| 1304 |
|
| 1305 |
if (posEq(from, to)) sel.inverted = false;
|
| 1306 |
else if (posEq(from, sel.to)) sel.inverted = false;
|
| 1307 |
else if (posEq(to, sel.from)) sel.inverted = true;
|
| 1308 |
|
| 1309 |
+
if (options.autoClearEmptyLines && posEq(sel.from, sel.to)) {
|
| 1310 |
+
var head = sel.inverted ? from : to;
|
| 1311 |
+
if (head.line != sel.from.line && sel.from.line < doc.size) {
|
| 1312 |
+
var oldLine = getLine(sel.from.line);
|
| 1313 |
+
if (/^\s+$/.test(oldLine.text))
|
| 1314 |
+
setTimeout(operation(function() {
|
| 1315 |
+
if (oldLine.parent && /^\s+$/.test(oldLine.text)) {
|
| 1316 |
+
var no = lineNo(oldLine);
|
| 1317 |
+
replaceRange("", {line: no, ch: 0}, {line: no, ch: oldLine.text.length});
|
| 1318 |
+
}
|
| 1319 |
+
}, 10));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1320 |
}
|
| 1321 |
}
|
| 1322 |
+
|
| 1323 |
sel.from = from; sel.to = to;
|
| 1324 |
selectionChanged = true;
|
| 1325 |
}
|
| 1330 |
var line = getLine(lNo);
|
| 1331 |
if (!line.hidden) {
|
| 1332 |
var ch = pos.ch;
|
| 1333 |
+
if (toEnd || ch > oldCh || ch > line.text.length) ch = line.text.length;
|
| 1334 |
return {line: lNo, ch: ch};
|
| 1335 |
}
|
| 1336 |
lNo += dir;
|
| 1337 |
}
|
| 1338 |
}
|
| 1339 |
var line = getLine(pos.line);
|
| 1340 |
+
var toEnd = pos.ch == line.text.length && pos.ch != oldCh;
|
| 1341 |
if (!line.hidden) return pos;
|
| 1342 |
if (pos.line >= oldLine) return getNonHidden(1) || getNonHidden(-1);
|
| 1343 |
else return getNonHidden(-1) || getNonHidden(1);
|
| 1397 |
else replaceRange("", sel.from, findPosH(dir, unit));
|
| 1398 |
userSelChange = true;
|
| 1399 |
}
|
|
|
|
| 1400 |
function moveV(dir, unit) {
|
| 1401 |
var dist = 0, pos = localCoords(sel.inverted ? sel.from : sel.to, true);
|
| 1402 |
if (goalColumn != null) pos.x = goalColumn;
|
| 1403 |
+
if (unit == "page") {
|
| 1404 |
+
var screen = Math.min(scroller.clientHeight, window.innerHeight || document.documentElement.clientHeight);
|
| 1405 |
+
var target = coordsChar(pos.x, pos.y + screen * dir);
|
| 1406 |
+
} else if (unit == "line") {
|
| 1407 |
+
var th = textHeight();
|
| 1408 |
+
var target = coordsChar(pos.x, pos.y + .5 * th + dir * th);
|
| 1409 |
+
}
|
| 1410 |
+
if (unit == "page") scrollbar.scrollTop += localCoords(target, true).y - pos.y;
|
| 1411 |
setCursor(target.line, target.ch, true);
|
| 1412 |
goalColumn = pos.x;
|
| 1413 |
}
|
| 1414 |
|
| 1415 |
+
function findWordAt(pos) {
|
| 1416 |
var line = getLine(pos.line).text;
|
| 1417 |
var start = pos.ch, end = pos.ch;
|
| 1418 |
+
if (line) {
|
| 1419 |
+
if (pos.after === false || end == line.length) --start; else ++end;
|
| 1420 |
+
var startChar = line.charAt(start);
|
| 1421 |
+
var check = isWordChar(startChar) ? isWordChar :
|
| 1422 |
+
/\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} :
|
| 1423 |
+
function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
|
| 1424 |
+
while (start > 0 && check(line.charAt(start - 1))) --start;
|
| 1425 |
+
while (end < line.length && check(line.charAt(end))) ++end;
|
| 1426 |
+
}
|
| 1427 |
+
return {from: {line: pos.line, ch: start}, to: {line: pos.line, ch: end}};
|
| 1428 |
}
|
| 1429 |
function selectLine(line) {
|
| 1430 |
+
setSelectionUser({line: line, ch: 0}, clipPos({line: line + 1, ch: 0}));
|
| 1431 |
}
|
| 1432 |
function indentSelected(mode) {
|
| 1433 |
if (posEq(sel.from, sel.to)) return indentLine(sel.from.line, mode);
|
| 1444 |
|
| 1445 |
var line = getLine(n), curSpace = line.indentation(options.tabSize),
|
| 1446 |
curSpaceString = line.text.match(/^\s*/)[0], indentation;
|
| 1447 |
+
if (how == "smart") {
|
| 1448 |
+
indentation = mode.indent(state, line.text.slice(curSpaceString.length), line.text);
|
| 1449 |
+
if (indentation == Pass) how = "prev";
|
| 1450 |
+
}
|
| 1451 |
if (how == "prev") {
|
| 1452 |
if (n) indentation = getLine(n-1).indentation(options.tabSize);
|
| 1453 |
else indentation = 0;
|
| 1454 |
}
|
|
|
|
| 1455 |
else if (how == "add") indentation = curSpace + options.indentUnit;
|
| 1456 |
else if (how == "subtract") indentation = curSpace - options.indentUnit;
|
| 1457 |
indentation = Math.max(0, indentation);
|
| 1458 |
var diff = indentation - curSpace;
|
| 1459 |
|
| 1460 |
+
var indentString = "", pos = 0;
|
| 1461 |
+
if (options.indentWithTabs)
|
| 1462 |
+
for (var i = Math.floor(indentation / options.tabSize); i; --i) {pos += options.tabSize; indentString += "\t";}
|
| 1463 |
+
while (pos < indentation) {++pos; indentString += " ";}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1464 |
|
| 1465 |
+
if (indentString != curSpaceString)
|
| 1466 |
+
replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length});
|
| 1467 |
}
|
| 1468 |
|
| 1469 |
function loadMode() {
|
| 1487 |
var guess = Math.ceil(line.text.length / perLine) || 1;
|
| 1488 |
if (guess != 1) updateLineHeight(line, guess);
|
| 1489 |
});
|
| 1490 |
+
lineSpace.style.minWidth = widthForcer.style.left = "";
|
| 1491 |
} else {
|
| 1492 |
wrapper.className = wrapper.className.replace(" CodeMirror-wrap", "");
|
| 1493 |
+
computeMaxLength();
|
| 1494 |
doc.iter(0, doc.size, function(line) {
|
| 1495 |
if (line.height != 1 && !line.hidden) updateLineHeight(line, 1);
|
|
|
|
| 1496 |
});
|
| 1497 |
}
|
| 1498 |
changes.push({from: 0, to: doc.size});
|
| 1499 |
}
|
| 1500 |
+
function makeTab(col) {
|
| 1501 |
+
var w = options.tabSize - col % options.tabSize, cached = tabCache[w];
|
| 1502 |
+
if (cached) return cached;
|
| 1503 |
+
for (var str = "", i = 0; i < w; ++i) str += " ";
|
| 1504 |
+
var span = elt("span", str, "cm-tab");
|
| 1505 |
+
return (tabCache[w] = {element: span, width: w});
|
|
|
|
| 1506 |
}
|
| 1507 |
function themeChanged() {
|
| 1508 |
+
scroller.className = scroller.className.replace(/\s*cm-s-\S+/g, "") +
|
| 1509 |
options.theme.replace(/(^|\s)\s*/g, " cm-s-");
|
| 1510 |
}
|
| 1511 |
+
function keyMapChanged() {
|
| 1512 |
+
var style = keyMap[options.keyMap].style;
|
| 1513 |
+
wrapper.className = wrapper.className.replace(/\s*cm-keymap-\S+/g, "") +
|
| 1514 |
+
(style ? " cm-keymap-" + style : "");
|
| 1515 |
+
}
|
| 1516 |
|
| 1517 |
function TextMarker() { this.set = []; }
|
| 1518 |
TextMarker.prototype.clear = operation(function() {
|
| 1523 |
var lineN = lineNo(line);
|
| 1524 |
min = Math.min(min, lineN); max = Math.max(max, lineN);
|
| 1525 |
for (var j = 0; j < mk.length; ++j)
|
| 1526 |
+
if (mk[j].marker == this) mk.splice(j--, 1);
|
| 1527 |
}
|
| 1528 |
if (min != Infinity)
|
| 1529 |
changes.push({from: min, to: max + 1});
|
| 1534 |
var line = this.set[i], mk = line.marked;
|
| 1535 |
for (var j = 0; j < mk.length; ++j) {
|
| 1536 |
var mark = mk[j];
|
| 1537 |
+
if (mark.marker == this) {
|
| 1538 |
if (mark.from != null || mark.to != null) {
|
| 1539 |
var found = lineNo(line);
|
| 1540 |
if (found != null) {
|
| 1551 |
function markText(from, to, className) {
|
| 1552 |
from = clipPos(from); to = clipPos(to);
|
| 1553 |
var tm = new TextMarker();
|
| 1554 |
+
if (!posLess(from, to)) return tm;
|
| 1555 |
function add(line, from, to, className) {
|
| 1556 |
+
getLine(line).addMark(new MarkedText(from, to, className, tm));
|
| 1557 |
}
|
| 1558 |
if (from.line == to.line) add(from.line, from.ch, to.ch, className);
|
| 1559 |
else {
|
| 1573 |
return bm;
|
| 1574 |
}
|
| 1575 |
|
| 1576 |
+
function findMarksAt(pos) {
|
| 1577 |
+
pos = clipPos(pos);
|
| 1578 |
+
var markers = [], marked = getLine(pos.line).marked;
|
| 1579 |
+
if (!marked) return markers;
|
| 1580 |
+
for (var i = 0, e = marked.length; i < e; ++i) {
|
| 1581 |
+
var m = marked[i];
|
| 1582 |
+
if ((m.from == null || m.from <= pos.ch) &&
|
| 1583 |
+
(m.to == null || m.to >= pos.ch))
|
| 1584 |
+
markers.push(m.marker || m);
|
| 1585 |
+
}
|
| 1586 |
+
return markers;
|
| 1587 |
+
}
|
| 1588 |
+
|
| 1589 |
function addGutterMarker(line, text, className) {
|
| 1590 |
if (typeof line == "number") line = getLine(clipLine(line));
|
| 1591 |
line.gutterMarker = {text: text, style: className};
|
| 1607 |
else return null;
|
| 1608 |
return line;
|
| 1609 |
}
|
| 1610 |
+
function setLineClass(handle, className, bgClassName) {
|
| 1611 |
return changeLine(handle, function(line) {
|
| 1612 |
+
if (line.className != className || line.bgClassName != bgClassName) {
|
| 1613 |
line.className = className;
|
| 1614 |
+
line.bgClassName = bgClassName;
|
| 1615 |
return true;
|
| 1616 |
}
|
| 1617 |
});
|
| 1620 |
return changeLine(handle, function(line, no) {
|
| 1621 |
if (line.hidden != hidden) {
|
| 1622 |
line.hidden = hidden;
|
| 1623 |
+
if (!options.lineWrapping) {
|
| 1624 |
+
if (hidden && line.text.length == maxLine.text.length) {
|
| 1625 |
+
updateMaxLine = true;
|
| 1626 |
+
} else if (!hidden && line.text.length > maxLine.text.length) {
|
| 1627 |
+
maxLine = line; updateMaxLine = false;
|
| 1628 |
+
}
|
| 1629 |
+
}
|
| 1630 |
updateLineHeight(line, hidden ? 0 : 1);
|
| 1631 |
+
var fline = sel.from.line, tline = sel.to.line;
|
| 1632 |
+
if (hidden && (fline == no || tline == no)) {
|
| 1633 |
+
var from = fline == no ? skipHidden({line: fline, ch: 0}, fline, 0) : sel.from;
|
| 1634 |
+
var to = tline == no ? skipHidden({line: tline, ch: 0}, tline, 0) : sel.to;
|
| 1635 |
+
// Can't hide the last visible line, we'd have no place to put the cursor
|
| 1636 |
+
if (!to) return;
|
| 1637 |
+
setSelection(from, to);
|
| 1638 |
+
}
|
| 1639 |
return (gutterDirty = true);
|
| 1640 |
}
|
| 1641 |
});
|
| 1647 |
var n = line;
|
| 1648 |
line = getLine(line);
|
| 1649 |
if (!line) return null;
|
| 1650 |
+
} else {
|
|
|
|
| 1651 |
var n = lineNo(line);
|
| 1652 |
if (n == null) return null;
|
| 1653 |
}
|
| 1654 |
var marker = line.gutterMarker;
|
| 1655 |
return {line: n, handle: line, text: line.text, markerText: marker && marker.text,
|
| 1656 |
+
markerClass: marker && marker.style, lineClass: line.className, bgClass: line.bgClassName};
|
| 1657 |
}
|
| 1658 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1659 |
// These are used to go from pixel positions to character
|
| 1660 |
// positions, taking varying character widths into account.
|
| 1661 |
function charFromX(line, x) {
|
| 1662 |
if (x <= 0) return 0;
|
| 1663 |
var lineObj = getLine(line), text = lineObj.text;
|
| 1664 |
function getX(len) {
|
| 1665 |
+
return measureLine(lineObj, len).left;
|
|
|
|
| 1666 |
}
|
| 1667 |
var from = 0, fromX = 0, to = text.length, toX;
|
| 1668 |
// Guess a suitable upper bound for our search.
|
| 1685 |
}
|
| 1686 |
}
|
| 1687 |
|
|
|
|
| 1688 |
function measureLine(line, ch) {
|
| 1689 |
+
if (ch == 0) return {top: 0, left: 0};
|
| 1690 |
+
var wbr = options.lineWrapping && ch < line.text.length &&
|
| 1691 |
+
spanAffectsWrapping.test(line.text.slice(ch - 1, ch + 1));
|
| 1692 |
+
var pre = line.getElement(makeTab, ch, wbr);
|
| 1693 |
+
removeChildrenAndAdd(measure, pre);
|
| 1694 |
+
var anchor = pre.anchor;
|
| 1695 |
+
var top = anchor.offsetTop, left = anchor.offsetLeft;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1696 |
// Older IEs report zero offsets for spans directly after a wrap
|
| 1697 |
+
if (ie && top == 0 && left == 0) {
|
| 1698 |
+
var backup = elt("span", "x");
|
| 1699 |
+
anchor.parentNode.insertBefore(backup, anchor.nextSibling);
|
|
|
|
| 1700 |
top = backup.offsetTop;
|
| 1701 |
}
|
| 1702 |
return {top: top, left: left};
|
| 1713 |
}
|
| 1714 |
// Coords must be lineSpace-local
|
| 1715 |
function coordsChar(x, y) {
|
|
|
|
| 1716 |
var th = textHeight(), cw = charWidth(), heightPos = displayOffset + Math.floor(y / th);
|
| 1717 |
+
if (heightPos < 0) return {line: 0, ch: 0};
|
| 1718 |
var lineNo = lineAtHeight(doc, heightPos);
|
| 1719 |
if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc.size - 1).text.length};
|
| 1720 |
var lineObj = getLine(lineNo), text = lineObj.text;
|
| 1721 |
var tw = options.lineWrapping, innerOff = tw ? heightPos - heightAtLine(doc, lineNo) : 0;
|
| 1722 |
if (x <= 0 && innerOff == 0) return {line: lineNo, ch: 0};
|
| 1723 |
+
var wrongLine = false;
|
| 1724 |
function getX(len) {
|
| 1725 |
var sp = measureLine(lineObj, len);
|
| 1726 |
if (tw) {
|
| 1727 |
var off = Math.round(sp.top / th);
|
| 1728 |
+
wrongLine = off != innerOff;
|
| 1729 |
return Math.max(0, sp.left + (off - innerOff) * scroller.clientWidth);
|
| 1730 |
}
|
| 1731 |
return sp.left;
|
| 1744 |
if (estX < x) {from = estimated; fromX = estX;}
|
| 1745 |
// Do a binary search between these bounds.
|
| 1746 |
for (;;) {
|
| 1747 |
+
if (to - from <= 1) {
|
| 1748 |
+
var after = x - fromX < toX - x;
|
| 1749 |
+
return {line: lineNo, ch: after ? from : to, after: after};
|
| 1750 |
+
}
|
| 1751 |
var middle = Math.ceil((from + to) / 2), middleX = getX(middle);
|
| 1752 |
+
if (middleX > x) {to = middle; toX = middleX; if (wrongLine) toX += 1000; }
|
| 1753 |
else {from = middle; fromX = middleX;}
|
| 1754 |
}
|
| 1755 |
}
|
| 1758 |
return {x: off.left + local.x, y: off.top + local.y, yBot: off.top + local.yBot};
|
| 1759 |
}
|
| 1760 |
|
| 1761 |
+
var cachedHeight, cachedHeightFor, measurePre;
|
| 1762 |
function textHeight() {
|
| 1763 |
+
if (measurePre == null) {
|
| 1764 |
+
measurePre = elt("pre");
|
| 1765 |
+
for (var i = 0; i < 49; ++i) {
|
| 1766 |
+
measurePre.appendChild(document.createTextNode("x"));
|
| 1767 |
+
measurePre.appendChild(elt("br"));
|
| 1768 |
+
}
|
| 1769 |
+
measurePre.appendChild(document.createTextNode("x"));
|
| 1770 |
}
|
| 1771 |
var offsetHeight = lineDiv.clientHeight;
|
| 1772 |
if (offsetHeight == cachedHeightFor) return cachedHeight;
|
| 1773 |
cachedHeightFor = offsetHeight;
|
| 1774 |
+
removeChildrenAndAdd(measure, measurePre.cloneNode(true));
|
| 1775 |
cachedHeight = measure.firstChild.offsetHeight / 50 || 1;
|
| 1776 |
+
removeChildren(measure);
|
| 1777 |
return cachedHeight;
|
| 1778 |
}
|
| 1779 |
var cachedWidth, cachedWidthFor = 0;
|
| 1780 |
function charWidth() {
|
| 1781 |
if (scroller.clientWidth == cachedWidthFor) return cachedWidth;
|
| 1782 |
cachedWidthFor = scroller.clientWidth;
|
| 1783 |
+
var anchor = elt("span", "x");
|
| 1784 |
+
var pre = elt("pre", [anchor]);
|
| 1785 |
+
removeChildrenAndAdd(measure, pre);
|
| 1786 |
+
return (cachedWidth = anchor.offsetWidth || 10);
|
| 1787 |
}
|
| 1788 |
function paddingTop() {return lineSpace.offsetTop;}
|
| 1789 |
function paddingLeft() {return lineSpace.offsetLeft;}
|
| 1801 |
return coordsChar(x - offL.left, y - offL.top);
|
| 1802 |
}
|
| 1803 |
function onContextMenu(e) {
|
| 1804 |
+
var pos = posFromMouse(e), scrollPos = scrollbar.scrollTop;
|
| 1805 |
+
if (!pos || opera) return; // Opera is difficult.
|
| 1806 |
if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
|
| 1807 |
operation(setCursor)(pos.line, pos.ch);
|
| 1808 |
|
| 1814 |
leaveInputAlone = true;
|
| 1815 |
var val = input.value = getSelection();
|
| 1816 |
focusInput();
|
| 1817 |
+
selectInput(input);
|
| 1818 |
function rehide() {
|
| 1819 |
var newVal = splitLines(input.value).join("\n");
|
| 1820 |
+
if (newVal != val && !options.readOnly) operation(replaceSelection)(newVal, "end");
|
| 1821 |
inputDiv.style.position = "relative";
|
| 1822 |
input.style.cssText = oldCSS;
|
| 1823 |
+
if (ie_lt9) scrollbar.scrollTop = scrollPos;
|
| 1824 |
leaveInputAlone = false;
|
| 1825 |
resetInput(true);
|
| 1826 |
slowPoll();
|
| 1832 |
mouseup();
|
| 1833 |
setTimeout(rehide, 20);
|
| 1834 |
}, true);
|
| 1835 |
+
} else {
|
|
|
|
| 1836 |
setTimeout(rehide, 50);
|
| 1837 |
}
|
| 1838 |
}
|
| 1844 |
cursor.style.visibility = "";
|
| 1845 |
blinker = setInterval(function() {
|
| 1846 |
cursor.style.visibility = (on = !on) ? "" : "hidden";
|
| 1847 |
+
}, options.cursorBlinkRate);
|
| 1848 |
}
|
| 1849 |
|
| 1850 |
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
|
| 1862 |
var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
|
| 1863 |
for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
|
| 1864 |
var text = st[i];
|
| 1865 |
+
if (st[i+1] != style) {pos += d * text.length; continue;}
|
| 1866 |
for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
|
| 1867 |
if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
|
| 1868 |
var match = matching[cur];
|
| 1949 |
var changed = line.highlight(mode, state, options.tabSize);
|
| 1950 |
if (changed) realChange = true;
|
| 1951 |
line.stateAfter = copyState(mode, state);
|
| 1952 |
+
var done = null;
|
| 1953 |
if (compare) {
|
| 1954 |
+
var same = hadState && compare(hadState, state);
|
| 1955 |
+
if (same != Pass) done = !!same;
|
| 1956 |
+
}
|
| 1957 |
+
if (done == null) {
|
| 1958 |
if (changed !== false || !hadState) unchanged = 0;
|
| 1959 |
else if (++unchanged > 3 && (!mode.indent || mode.indent(hadState, "") == mode.indent(state, "")))
|
| 1960 |
+
done = true;
|
| 1961 |
}
|
| 1962 |
+
if (done) return true;
|
| 1963 |
++i;
|
| 1964 |
});
|
| 1965 |
if (bail) return;
|
| 1982 |
changes = []; selectionChanged = false; callbacks = [];
|
| 1983 |
}
|
| 1984 |
function endOperation() {
|
| 1985 |
+
if (updateMaxLine) computeMaxLength();
|
| 1986 |
+
if (maxLineChanged && !options.lineWrapping) {
|
| 1987 |
+
var cursorWidth = widthForcer.offsetWidth, left = measureLine(maxLine, maxLine.text.length).left;
|
| 1988 |
+
if (!ie_lt8) {
|
| 1989 |
+
widthForcer.style.left = left + "px";
|
| 1990 |
+
lineSpace.style.minWidth = (left + cursorWidth) + "px";
|
| 1991 |
+
}
|
| 1992 |
+
maxLineChanged = false;
|
| 1993 |
+
}
|
| 1994 |
+
var newScrollPos, updated;
|
| 1995 |
+
if (selectionChanged) {
|
| 1996 |
+
var coords = calculateCursorCoords();
|
| 1997 |
+
newScrollPos = calculateScrollPos(coords.x, coords.y, coords.x, coords.yBot);
|
| 1998 |
+
}
|
| 1999 |
+
if (changes.length || newScrollPos && newScrollPos.scrollTop != null)
|
| 2000 |
+
updated = updateDisplay(changes, true, newScrollPos && newScrollPos.scrollTop);
|
| 2001 |
+
if (!updated) {
|
| 2002 |
+
if (selectionChanged) updateSelection();
|
| 2003 |
if (gutterDirty) updateGutter();
|
| 2004 |
}
|
| 2005 |
+
if (newScrollPos) scrollCursorIntoView();
|
| 2006 |
+
if (selectionChanged) restartBlink();
|
| 2007 |
|
| 2008 |
if (focused && !leaveInputAlone &&
|
| 2009 |
(updateInput === true || (updateInput !== false && selectionChanged)))
|
| 2014 |
if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
|
| 2015 |
if (posEq(sel.from, sel.to)) matchBrackets(false);
|
| 2016 |
}), 20);
|
| 2017 |
+
var sc = selectionChanged, cbs = callbacks; // these can be reset by callbacks
|
| 2018 |
+
if (textChanged && options.onChange && instance)
|
| 2019 |
+
options.onChange(instance, textChanged);
|
| 2020 |
+
if (sc && options.onCursorActivity)
|
| 2021 |
options.onCursorActivity(instance);
|
|
|
|
|
|
|
| 2022 |
for (var i = 0; i < cbs.length; ++i) cbs[i](instance);
|
| 2023 |
if (updated && options.onUpdate) options.onUpdate(instance);
|
| 2024 |
}
|
| 2032 |
};
|
| 2033 |
}
|
| 2034 |
|
| 2035 |
+
function compoundChange(f) {
|
| 2036 |
+
history.startCompound();
|
| 2037 |
+
try { return f(); } finally { history.endCompound(); }
|
| 2038 |
+
}
|
| 2039 |
+
|
| 2040 |
for (var ext in extensions)
|
| 2041 |
if (extensions.propertyIsEnumerable(ext) &&
|
| 2042 |
!instance.propertyIsEnumerable(ext))
|
| 2051 |
theme: "default",
|
| 2052 |
indentUnit: 2,
|
| 2053 |
indentWithTabs: false,
|
| 2054 |
+
smartIndent: true,
|
| 2055 |
tabSize: 4,
|
| 2056 |
keyMap: "default",
|
| 2057 |
extraKeys: null,
|
| 2058 |
electricChars: true,
|
| 2059 |
+
autoClearEmptyLines: false,
|
| 2060 |
onKeyEvent: null,
|
| 2061 |
+
onDragEvent: null,
|
| 2062 |
lineWrapping: false,
|
| 2063 |
lineNumbers: false,
|
| 2064 |
gutter: false,
|
| 2065 |
fixedGutter: false,
|
| 2066 |
firstLineNumber: 1,
|
| 2067 |
readOnly: false,
|
| 2068 |
+
dragDrop: true,
|
| 2069 |
onChange: null,
|
| 2070 |
onCursorActivity: null,
|
| 2071 |
+
onViewportChange: null,
|
| 2072 |
onGutterClick: null,
|
| 2073 |
onHighlightComplete: null,
|
| 2074 |
onUpdate: null,
|
| 2075 |
onFocus: null, onBlur: null, onScroll: null,
|
| 2076 |
matchBrackets: false,
|
| 2077 |
+
cursorBlinkRate: 530,
|
| 2078 |
workTime: 100,
|
| 2079 |
workDelay: 200,
|
| 2080 |
pollInterval: 100,
|
| 2081 |
undoDepth: 40,
|
| 2082 |
tabindex: null,
|
| 2083 |
+
autofocus: null,
|
| 2084 |
+
lineNumberFormatter: function(integer) { return integer; }
|
| 2085 |
};
|
| 2086 |
|
| 2087 |
+
var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
|
| 2088 |
+
var mac = ios || /Mac/.test(navigator.platform);
|
| 2089 |
var win = /Win/.test(navigator.platform);
|
| 2090 |
|
| 2091 |
// Known modes, by name and by MIME
|
| 2092 |
+
var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
|
| 2093 |
CodeMirror.defineMode = function(name, mode) {
|
| 2094 |
if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
|
| 2095 |
+
if (arguments.length > 2) {
|
| 2096 |
+
mode.dependencies = [];
|
| 2097 |
+
for (var i = 2; i < arguments.length; ++i) mode.dependencies.push(arguments[i]);
|
| 2098 |
+
}
|
| 2099 |
modes[name] = mode;
|
| 2100 |
};
|
| 2101 |
CodeMirror.defineMIME = function(mime, spec) {
|
| 2102 |
mimeModes[mime] = spec;
|
| 2103 |
};
|
| 2104 |
+
CodeMirror.resolveMode = function(spec) {
|
| 2105 |
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
|
| 2106 |
spec = mimeModes[spec];
|
| 2107 |
+
else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec))
|
| 2108 |
+
return CodeMirror.resolveMode("application/xml");
|
| 2109 |
+
if (typeof spec == "string") return {name: spec};
|
| 2110 |
+
else return spec || {name: "null"};
|
| 2111 |
+
};
|
| 2112 |
+
CodeMirror.getMode = function(options, spec) {
|
| 2113 |
+
var spec = CodeMirror.resolveMode(spec);
|
| 2114 |
+
var mfactory = modes[spec.name];
|
| 2115 |
+
if (!mfactory) return CodeMirror.getMode(options, "text/plain");
|
| 2116 |
+
return mfactory(options, spec);
|
| 2117 |
};
|
| 2118 |
CodeMirror.listModes = function() {
|
| 2119 |
var list = [];
|
| 2170 |
indentMore: function(cm) {cm.indentSelection("add");},
|
| 2171 |
indentLess: function(cm) {cm.indentSelection("subtract");},
|
| 2172 |
insertTab: function(cm) {cm.replaceSelection("\t", "end");},
|
| 2173 |
+
defaultTab: function(cm) {
|
| 2174 |
+
if (cm.somethingSelected()) cm.indentSelection("add");
|
| 2175 |
+
else cm.replaceSelection("\t", "end");
|
| 2176 |
+
},
|
| 2177 |
transposeChars: function(cm) {
|
| 2178 |
var cur = cm.getCursor(), line = cm.getLine(cur.line);
|
| 2179 |
if (cur.ch > 0 && cur.ch < line.length - 1)
|
| 2191 |
keyMap.basic = {
|
| 2192 |
"Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
|
| 2193 |
"End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
|
| 2194 |
+
"Delete": "delCharRight", "Backspace": "delCharLeft", "Tab": "defaultTab", "Shift-Tab": "indentAuto",
|
| 2195 |
"Enter": "newlineAndIndent", "Insert": "toggleOverwrite"
|
| 2196 |
};
|
| 2197 |
// Note that the save and find-related commands aren't defined by
|
| 2202 |
"Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
|
| 2203 |
"Ctrl-Backspace": "delWordLeft", "Ctrl-Delete": "delWordRight", "Ctrl-S": "save", "Ctrl-F": "find",
|
| 2204 |
"Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
|
| 2205 |
+
"Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
|
| 2206 |
fallthrough: "basic"
|
| 2207 |
};
|
| 2208 |
keyMap.macDefault = {
|
| 2211 |
"Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordLeft",
|
| 2212 |
"Ctrl-Alt-Backspace": "delWordRight", "Alt-Delete": "delWordRight", "Cmd-S": "save", "Cmd-F": "find",
|
| 2213 |
"Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
|
| 2214 |
+
"Cmd-[": "indentLess", "Cmd-]": "indentMore",
|
| 2215 |
fallthrough: ["basic", "emacsy"]
|
| 2216 |
};
|
| 2217 |
keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
|
| 2222 |
"Alt-D": "delWordRight", "Alt-Backspace": "delWordLeft", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
|
| 2223 |
};
|
| 2224 |
|
| 2225 |
+
function getKeyMap(val) {
|
| 2226 |
+
if (typeof val == "string") return keyMap[val];
|
| 2227 |
+
else return val;
|
| 2228 |
+
}
|
| 2229 |
+
function lookupKey(name, extraMap, map, handle, stop) {
|
| 2230 |
+
function lookup(map) {
|
| 2231 |
+
map = getKeyMap(map);
|
| 2232 |
var found = map[name];
|
| 2233 |
+
if (found === false) {
|
| 2234 |
+
if (stop) stop();
|
| 2235 |
+
return true;
|
| 2236 |
+
}
|
| 2237 |
+
if (found != null && handle(found)) return true;
|
| 2238 |
+
if (map.nofallthrough) {
|
| 2239 |
+
if (stop) stop();
|
| 2240 |
+
return true;
|
| 2241 |
+
}
|
| 2242 |
+
var fallthrough = map.fallthrough;
|
| 2243 |
+
if (fallthrough == null) return false;
|
| 2244 |
+
if (Object.prototype.toString.call(fallthrough) != "[object Array]")
|
| 2245 |
+
return lookup(fallthrough);
|
| 2246 |
+
for (var i = 0, e = fallthrough.length; i < e; ++i) {
|
| 2247 |
+
if (lookup(fallthrough[i])) return true;
|
| 2248 |
}
|
| 2249 |
+
return false;
|
| 2250 |
}
|
| 2251 |
+
if (extraMap && lookup(extraMap)) return true;
|
| 2252 |
+
return lookup(map);
|
| 2253 |
}
|
| 2254 |
function isModifierKey(event) {
|
| 2255 |
+
var name = keyNames[e_prop(event, "keyCode")];
|
| 2256 |
return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
|
| 2257 |
}
|
| 2258 |
|
| 2261 |
options.value = textarea.value;
|
| 2262 |
if (!options.tabindex && textarea.tabindex)
|
| 2263 |
options.tabindex = textarea.tabindex;
|
| 2264 |
+
// Set autofocus to true if this textarea is focused, or if it has
|
| 2265 |
+
// autofocus and no other element is focused.
|
| 2266 |
+
if (options.autofocus == null) {
|
| 2267 |
+
var hasFocus = document.body;
|
| 2268 |
+
// doc.activeElement occasionally throws on IE
|
| 2269 |
+
try { hasFocus = document.activeElement; } catch(e) {}
|
| 2270 |
+
options.autofocus = hasFocus == textarea ||
|
| 2271 |
+
textarea.getAttribute("autofocus") != null && hasFocus == document.body;
|
| 2272 |
+
}
|
| 2273 |
|
| 2274 |
function save() {textarea.value = instance.getValue();}
|
| 2275 |
if (textarea.form) {
|
| 2277 |
var rmSubmit = connect(textarea.form, "submit", save, true);
|
| 2278 |
if (typeof textarea.form.submit == "function") {
|
| 2279 |
var realSubmit = textarea.form.submit;
|
| 2280 |
+
textarea.form.submit = function wrappedSubmit() {
|
| 2281 |
save();
|
| 2282 |
textarea.form.submit = realSubmit;
|
| 2283 |
textarea.form.submit();
|
| 2284 |
textarea.form.submit = wrappedSubmit;
|
| 2285 |
+
};
|
|
|
|
| 2286 |
}
|
| 2287 |
}
|
| 2288 |
|
| 2305 |
return instance;
|
| 2306 |
};
|
| 2307 |
|
| 2308 |
+
var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
|
| 2309 |
+
var ie = /MSIE \d/.test(navigator.userAgent);
|
| 2310 |
+
var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent);
|
| 2311 |
+
var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent);
|
| 2312 |
+
var quirksMode = ie && document.documentMode == 5;
|
| 2313 |
+
var webkit = /WebKit\//.test(navigator.userAgent);
|
| 2314 |
+
var chrome = /Chrome\//.test(navigator.userAgent);
|
| 2315 |
+
var opera = /Opera\//.test(navigator.userAgent);
|
| 2316 |
+
var safari = /Apple Computer/.test(navigator.vendor);
|
| 2317 |
+
var khtml = /KHTML\//.test(navigator.userAgent);
|
| 2318 |
+
var mac_geLion = /Mac OS X 10\D([7-9]|\d\d)\D/.test(navigator.userAgent);
|
| 2319 |
+
|
| 2320 |
// Utility functions for working with state. Exported because modes
|
| 2321 |
// sometimes need to do this.
|
| 2322 |
function copyState(mode, state) {
|
| 2345 |
StringStream.prototype = {
|
| 2346 |
eol: function() {return this.pos >= this.string.length;},
|
| 2347 |
sol: function() {return this.pos == 0;},
|
| 2348 |
+
peek: function() {return this.string.charAt(this.pos) || undefined;},
|
| 2349 |
next: function() {
|
| 2350 |
if (this.pos < this.string.length)
|
| 2351 |
return this.string.charAt(this.pos++);
|
| 2376 |
indentation: function() {return countColumn(this.string, null, this.tabSize);},
|
| 2377 |
match: function(pattern, consume, caseInsensitive) {
|
| 2378 |
if (typeof pattern == "string") {
|
| 2379 |
+
var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
|
| 2380 |
if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
|
| 2381 |
if (consume !== false) this.pos += pattern.length;
|
| 2382 |
return true;
|
| 2383 |
}
|
| 2384 |
+
} else {
|
|
|
|
| 2385 |
var match = this.string.slice(this.pos).match(pattern);
|
| 2386 |
if (match && consume !== false) this.pos += match[0].length;
|
| 2387 |
return match;
|
| 2391 |
};
|
| 2392 |
CodeMirror.StringStream = StringStream;
|
| 2393 |
|
| 2394 |
+
function MarkedText(from, to, className, marker) {
|
| 2395 |
+
this.from = from; this.to = to; this.style = className; this.marker = marker;
|
| 2396 |
}
|
| 2397 |
MarkedText.prototype = {
|
| 2398 |
+
attach: function(line) { this.marker.set.push(line); },
|
| 2399 |
detach: function(line) {
|
| 2400 |
+
var ix = indexOf(this.marker.set, line);
|
| 2401 |
+
if (ix > -1) this.marker.set.splice(ix, 1);
|
| 2402 |
},
|
| 2403 |
split: function(pos, lenBefore) {
|
| 2404 |
if (this.to <= pos && this.to != null) return null;
|
| 2405 |
var from = this.from < pos || this.from == null ? null : this.from - pos + lenBefore;
|
| 2406 |
var to = this.to == null ? null : this.to - pos + lenBefore;
|
| 2407 |
+
return new MarkedText(from, to, this.style, this.marker);
|
| 2408 |
},
|
| 2409 |
+
dup: function() { return new MarkedText(null, null, this.style, this.marker); },
|
| 2410 |
clipTo: function(fromOpen, from, toOpen, to, diff) {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2411 |
if (fromOpen && to > this.from && (to < this.to || this.to == null))
|
| 2412 |
this.from = null;
|
| 2413 |
+
else if (this.from != null && this.from >= from)
|
| 2414 |
+
this.from = Math.max(to, this.from) + diff;
|
| 2415 |
if (toOpen && (from < this.to || this.to == null) && (from > this.from || this.from == null))
|
| 2416 |
this.to = null;
|
| 2417 |
+
else if (this.to != null && this.to > from)
|
| 2418 |
+
this.to = to < this.to ? this.to + diff : from;
|
| 2419 |
},
|
| 2420 |
isDead: function() { return this.from != null && this.to != null && this.from >= this.to; },
|
| 2421 |
+
sameSet: function(x) { return this.marker == x.marker; }
|
| 2422 |
};
|
| 2423 |
|
| 2424 |
function Bookmark(pos) {
|
| 2455 |
}
|
| 2456 |
};
|
| 2457 |
|
| 2458 |
+
// When measuring the position of the end of a line, different
|
| 2459 |
+
// browsers require different approaches. If an empty span is added,
|
| 2460 |
+
// many browsers report bogus offsets. Of those, some (Webkit,
|
| 2461 |
+
// recent IE) will accept a space without moving the whole span to
|
| 2462 |
+
// the next line when wrapping it, others work with a zero-width
|
| 2463 |
+
// space.
|
| 2464 |
+
var eolSpanContent = " ";
|
| 2465 |
+
if (gecko || (ie && !ie_lt8)) eolSpanContent = "\u200b";
|
| 2466 |
+
else if (opera) eolSpanContent = "";
|
| 2467 |
+
|
| 2468 |
// Line objects. These hold state related to a line, including
|
| 2469 |
// highlighting info (the styles array).
|
| 2470 |
function Line(text, styles) {
|
| 2471 |
this.styles = styles || [text, null];
|
| 2472 |
this.text = text;
|
| 2473 |
this.height = 1;
|
|
|
|
|
|
|
| 2474 |
}
|
| 2475 |
Line.inheritMarks = function(text, orig) {
|
| 2476 |
var ln = new Line(text), mk = orig && orig.marked;
|
| 2483 |
}
|
| 2484 |
}
|
| 2485 |
return ln;
|
| 2486 |
+
};
|
| 2487 |
Line.prototype = {
|
| 2488 |
// Replace a piece of a line, keeping the styles around it intact.
|
| 2489 |
replace: function(from, to_, text) {
|
| 2496 |
this.stateAfter = null;
|
| 2497 |
if (mk) {
|
| 2498 |
var diff = text.length - (to - from);
|
| 2499 |
+
for (var i = 0; i < mk.length; ++i) {
|
| 2500 |
+
var mark = mk[i];
|
| 2501 |
mark.clipTo(from == null, from || 0, to_ == null, to, diff);
|
| 2502 |
if (mark.isDead()) {mark.detach(this); mk.splice(i--, 1);}
|
| 2503 |
}
|
| 2515 |
if (newmark) {
|
| 2516 |
if (!taken.marked) taken.marked = [];
|
| 2517 |
taken.marked.push(newmark); newmark.attach(taken);
|
| 2518 |
+
if (newmark == mark) mk.splice(i--, 1);
|
| 2519 |
}
|
| 2520 |
}
|
| 2521 |
}
|
| 2556 |
fixMarkEnds: function(other) {
|
| 2557 |
var mk = this.marked, omk = other.marked;
|
| 2558 |
if (!mk) return;
|
| 2559 |
+
outer: for (var i = 0; i < mk.length; ++i) {
|
| 2560 |
var mark = mk[i], close = mark.to == null;
|
| 2561 |
if (close && omk) {
|
| 2562 |
+
for (var j = 0; j < omk.length; ++j) {
|
| 2563 |
+
var om = omk[j];
|
| 2564 |
+
if (!om.sameSet(mark) || om.from != null) continue;
|
| 2565 |
+
if (mark.from == this.text.length && om.to == 0) {
|
| 2566 |
+
omk.splice(j, 1);
|
| 2567 |
+
mk.splice(i--, 1);
|
| 2568 |
+
continue outer;
|
| 2569 |
+
} else {
|
| 2570 |
+
close = false; break;
|
| 2571 |
+
}
|
| 2572 |
+
}
|
| 2573 |
}
|
| 2574 |
if (close) mark.to = this.text.length;
|
| 2575 |
}
|
| 2619 |
},
|
| 2620 |
// Fetch the parser token for a given character. Useful for hacks
|
| 2621 |
// that want to inspect the mode state (say, for completion).
|
| 2622 |
+
getTokenAt: function(mode, state, tabSize, ch) {
|
| 2623 |
+
var txt = this.text, stream = new StringStream(txt, tabSize);
|
| 2624 |
while (stream.pos < ch && !stream.eol()) {
|
| 2625 |
stream.start = stream.pos;
|
| 2626 |
var style = mode.token(stream, state);
|
| 2634 |
indentation: function(tabSize) {return countColumn(this.text, null, tabSize);},
|
| 2635 |
// Produces an HTML fragment for the line, taking selection,
|
| 2636 |
// marking, and highlighting into account.
|
| 2637 |
+
getElement: function(makeTab, wrapAt, wrapWBR) {
|
| 2638 |
+
var first = true, col = 0, specials = /[\t\u0000-\u0019\u200b\u2028\u2029\uFEFF]/g;
|
| 2639 |
+
var pre = elt("pre");
|
| 2640 |
+
function span_(html, text, style) {
|
|
|
|
| 2641 |
if (!text) return;
|
| 2642 |
// Work around a bug where, in some compat modes, IE ignores leading spaces
|
| 2643 |
if (first && ie && text.charAt(0) == " ") text = "\u00a0" + text.slice(1);
|
| 2644 |
first = false;
|
| 2645 |
+
if (!specials.test(text)) {
|
| 2646 |
+
col += text.length;
|
| 2647 |
+
var content = document.createTextNode(text);
|
| 2648 |
+
} else {
|
| 2649 |
+
var content = document.createDocumentFragment(), pos = 0;
|
| 2650 |
+
while (true) {
|
| 2651 |
+
specials.lastIndex = pos;
|
| 2652 |
+
var m = specials.exec(text);
|
| 2653 |
+
var skipped = m ? m.index - pos : text.length - pos;
|
| 2654 |
+
if (skipped) {
|
| 2655 |
+
content.appendChild(document.createTextNode(text.slice(pos, pos + skipped)));
|
| 2656 |
+
col += skipped;
|
| 2657 |
+
}
|
| 2658 |
+
if (!m) break;
|
| 2659 |
+
pos += skipped + 1;
|
| 2660 |
+
if (m[0] == "\t") {
|
| 2661 |
+
var tab = makeTab(col);
|
| 2662 |
+
content.appendChild(tab.element.cloneNode(true));
|
| 2663 |
+
col += tab.width;
|
| 2664 |
+
} else {
|
| 2665 |
+
var token = elt("span", "\u2022", "cm-invalidchar");
|
| 2666 |
+
token.title = "\\u" + m[0].charCodeAt(0).toString(16);
|
| 2667 |
+
content.appendChild(token);
|
| 2668 |
+
col += 1;
|
| 2669 |
+
}
|
| 2670 |
+
}
|
| 2671 |
+
}
|
| 2672 |
+
if (style) html.appendChild(elt("span", [content], style));
|
| 2673 |
+
else html.appendChild(content);
|
| 2674 |
+
}
|
| 2675 |
+
var span = span_;
|
| 2676 |
+
if (wrapAt != null) {
|
| 2677 |
+
var outPos = 0, anchor = pre.anchor = elt("span");
|
| 2678 |
+
span = function(html, text, style) {
|
| 2679 |
+
var l = text.length;
|
| 2680 |
+
if (wrapAt >= outPos && wrapAt < outPos + l) {
|
| 2681 |
+
if (wrapAt > outPos) {
|
| 2682 |
+
span_(html, text.slice(0, wrapAt - outPos), style);
|
| 2683 |
+
// See comment at the definition of spanAffectsWrapping
|
| 2684 |
+
if (wrapWBR) html.appendChild(elt("wbr"));
|
| 2685 |
+
}
|
| 2686 |
+
html.appendChild(anchor);
|
| 2687 |
+
var cut = wrapAt - outPos;
|
| 2688 |
+
span_(anchor, opera ? text.slice(cut, cut + 1) : text.slice(cut), style);
|
| 2689 |
+
if (opera) span_(html, text.slice(cut + 1), style);
|
| 2690 |
+
wrapAt--;
|
| 2691 |
+
outPos += l;
|
| 2692 |
+
} else {
|
| 2693 |
+
outPos += l;
|
| 2694 |
+
span_(html, text, style);
|
| 2695 |
+
if (outPos == wrapAt && outPos == len) {
|
| 2696 |
+
setTextContent(anchor, eolSpanContent);
|
| 2697 |
+
html.appendChild(anchor);
|
| 2698 |
+
}
|
| 2699 |
+
// Stop outputting HTML when gone sufficiently far beyond measure
|
| 2700 |
+
else if (outPos > wrapAt + 10 && /\s/.test(text)) span = function(){};
|
| 2701 |
+
}
|
| 2702 |
+
};
|
| 2703 |
}
|
| 2704 |
+
|
| 2705 |
var st = this.styles, allText = this.text, marked = this.marked;
|
|
|
|
| 2706 |
var len = allText.length;
|
| 2707 |
+
function styleToClass(style) {
|
| 2708 |
+
if (!style) return null;
|
| 2709 |
+
return "cm-" + style.replace(/ +/g, " cm-");
|
| 2710 |
+
}
|
| 2711 |
+
if (!allText && wrapAt == null) {
|
| 2712 |
+
span(pre, " ");
|
| 2713 |
+
} else if (!marked || !marked.length) {
|
| 2714 |
for (var i = 0, ch = 0; ch < len; i+=2) {
|
| 2715 |
var str = st[i], style = st[i+1], l = str.length;
|
| 2716 |
if (ch + l > len) str = str.slice(0, len - ch);
|
| 2717 |
ch += l;
|
| 2718 |
+
span(pre, str, styleToClass(style));
|
| 2719 |
}
|
| 2720 |
+
} else {
|
| 2721 |
var pos = 0, i = 0, text = "", style, sg = 0;
|
| 2722 |
+
var nextChange = marked[0].from || 0, marks = [], markpos = 0;
|
| 2723 |
+
var advanceMarks = function() {
|
| 2724 |
+
var m;
|
| 2725 |
+
while (markpos < marked.length &&
|
| 2726 |
+
((m = marked[markpos]).from == pos || m.from == null)) {
|
| 2727 |
+
if (m.style != null) marks.push(m);
|
| 2728 |
+
++markpos;
|
| 2729 |
}
|
| 2730 |
+
nextChange = markpos < marked.length ? marked[markpos].from : Infinity;
|
| 2731 |
+
for (var i = 0; i < marks.length; ++i) {
|
| 2732 |
+
var to = marks[i].to;
|
| 2733 |
+
if (to == null) to = Infinity;
|
| 2734 |
+
if (to == pos) marks.splice(i--, 1);
|
| 2735 |
+
else nextChange = Math.min(to, nextChange);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2736 |
}
|
| 2737 |
+
};
|
| 2738 |
+
var m = 0;
|
| 2739 |
+
while (pos < len) {
|
| 2740 |
+
if (nextChange == pos) advanceMarks();
|
| 2741 |
+
var upto = Math.min(len, nextChange);
|
| 2742 |
+
while (true) {
|
| 2743 |
+
if (text) {
|
| 2744 |
+
var end = pos + text.length;
|
| 2745 |
+
var appliedStyle = style;
|
| 2746 |
+
for (var j = 0; j < marks.length; ++j)
|
| 2747 |
+
appliedStyle = (appliedStyle ? appliedStyle + " " : "") + marks[j].style;
|
| 2748 |
+
span(pre, end > upto ? text.slice(0, upto - pos) : text, appliedStyle);
|
| 2749 |
+
if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
|
| 2750 |
+
pos = end;
|
| 2751 |
}
|
| 2752 |
+
text = st[i++]; style = styleToClass(st[i++]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2753 |
}
|
| 2754 |
}
|
|
|
|
| 2755 |
}
|
| 2756 |
+
return pre;
|
|
|
|
| 2757 |
},
|
| 2758 |
cleanUp: function() {
|
| 2759 |
this.parent = null;
|
| 2768 |
if (state == 0) {
|
| 2769 |
if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
|
| 2770 |
if (end >= from) state = 1;
|
| 2771 |
+
} else if (state == 1) {
|
|
|
|
| 2772 |
if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
|
| 2773 |
else dest.push(part, source[i+1]);
|
| 2774 |
}
|
| 2803 |
},
|
| 2804 |
insertHeight: function(at, lines, height) {
|
| 2805 |
this.height += height;
|
| 2806 |
+
this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
|
| 2807 |
for (var i = 0, e = lines.length; i < e; ++i) lines[i].parent = this;
|
| 2808 |
},
|
| 2809 |
iterN: function(at, n, op) {
|
| 2842 |
var lines = [];
|
| 2843 |
this.collapse(lines);
|
| 2844 |
this.children = [new LeafChunk(lines)];
|
| 2845 |
+
this.children[0].parent = this;
|
| 2846 |
}
|
| 2847 |
},
|
| 2848 |
collapse: function(lines) {
|
| 2969 |
function History() {
|
| 2970 |
this.time = 0;
|
| 2971 |
this.done = []; this.undone = [];
|
| 2972 |
+
this.compound = 0;
|
| 2973 |
+
this.closed = false;
|
| 2974 |
}
|
| 2975 |
History.prototype = {
|
| 2976 |
addChange: function(start, added, old) {
|
| 2977 |
this.undone.length = 0;
|
| 2978 |
+
var time = +new Date, cur = this.done[this.done.length - 1], last = cur && cur[cur.length - 1];
|
| 2979 |
+
var dtime = time - this.time;
|
| 2980 |
+
|
| 2981 |
+
if (this.compound && cur && !this.closed) {
|
| 2982 |
+
cur.push({start: start, added: added, old: old});
|
| 2983 |
+
} else if (dtime > 400 || !last || this.closed ||
|
| 2984 |
+
last.start > start + old.length || last.start + last.added < start) {
|
| 2985 |
+
this.done.push([{start: start, added: added, old: old}]);
|
| 2986 |
+
this.closed = false;
|
| 2987 |
+
} else {
|
| 2988 |
+
var startBefore = Math.max(0, last.start - start),
|
| 2989 |
+
endAfter = Math.max(0, (start + old.length) - (last.start + last.added));
|
| 2990 |
+
for (var i = startBefore; i > 0; --i) last.old.unshift(old[i - 1]);
|
| 2991 |
+
for (var i = endAfter; i > 0; --i) last.old.push(old[old.length - i]);
|
| 2992 |
+
if (startBefore) last.start = start;
|
| 2993 |
+
last.added += added - (old.length - startBefore - endAfter);
|
|
|
|
|
|
|
|
|
|
| 2994 |
}
|
| 2995 |
this.time = time;
|
| 2996 |
+
},
|
| 2997 |
+
startCompound: function() {
|
| 2998 |
+
if (!this.compound++) this.closed = true;
|
| 2999 |
+
},
|
| 3000 |
+
endCompound: function() {
|
| 3001 |
+
if (!--this.compound) this.closed = true;
|
| 3002 |
}
|
| 3003 |
};
|
| 3004 |
|
| 3024 |
|
| 3025 |
function e_target(e) {return e.target || e.srcElement;}
|
| 3026 |
function e_button(e) {
|
| 3027 |
+
var b = e.which;
|
| 3028 |
+
if (b == null) {
|
| 3029 |
+
if (e.button & 1) b = 1;
|
| 3030 |
+
else if (e.button & 2) b = 3;
|
| 3031 |
+
else if (e.button & 4) b = 2;
|
| 3032 |
+
}
|
| 3033 |
+
if (mac && e.ctrlKey && b == 1) b = 3;
|
| 3034 |
+
return b;
|
| 3035 |
+
}
|
| 3036 |
+
|
| 3037 |
+
// Allow 3rd-party code to override event properties by adding an override
|
| 3038 |
+
// object to an event object.
|
| 3039 |
+
function e_prop(e, prop) {
|
| 3040 |
+
var overridden = e.override && e.override.hasOwnProperty(prop);
|
| 3041 |
+
return overridden ? e.override[prop] : e[prop];
|
| 3042 |
}
|
| 3043 |
|
| 3044 |
// Event handler registration. If disconnect is true, it'll return a
|
| 3047 |
if (typeof node.addEventListener == "function") {
|
| 3048 |
node.addEventListener(type, handler, false);
|
| 3049 |
if (disconnect) return function() {node.removeEventListener(type, handler, false);};
|
| 3050 |
+
} else {
|
|
|
|
| 3051 |
var wrapHandler = function(event) {handler(event || window.event);};
|
| 3052 |
node.attachEvent("on" + type, wrapHandler);
|
| 3053 |
if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
|
| 3058 |
function Delayed() {this.id = null;}
|
| 3059 |
Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
|
| 3060 |
|
| 3061 |
+
var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
|
| 3062 |
+
|
| 3063 |
// Detect drag-and-drop
|
| 3064 |
var dragAndDrop = function() {
|
| 3065 |
+
// There is *some* kind of drag-and-drop support in IE6-8, but I
|
| 3066 |
+
// couldn't get it to work yet.
|
| 3067 |
+
if (ie_lt9) return false;
|
| 3068 |
+
var div = elt('div');
|
| 3069 |
+
return "draggable" in div || "dragDrop" in div;
|
| 3070 |
}();
|
| 3071 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3072 |
// Feature-detect whether newlines in textareas are converted to \r\n
|
| 3073 |
+
var lineSep = function () {
|
| 3074 |
+
var te = elt("textarea");
|
| 3075 |
te.value = "foo\nbar";
|
| 3076 |
+
if (te.value.indexOf("\r") > -1) return "\r\n";
|
| 3077 |
+
return "\n";
|
| 3078 |
+
}();
|
| 3079 |
+
|
| 3080 |
+
// For a reason I have yet to figure out, some browsers disallow
|
| 3081 |
+
// word wrapping between certain characters *only* if a new inline
|
| 3082 |
+
// element is started between them. This makes it hard to reliably
|
| 3083 |
+
// measure the position of things, since that requires inserting an
|
| 3084 |
+
// extra span. This terribly fragile set of regexps matches the
|
| 3085 |
+
// character combinations that suffer from this phenomenon on the
|
| 3086 |
+
// various browsers.
|
| 3087 |
+
var spanAffectsWrapping = /^$/; // Won't match any two-character string
|
| 3088 |
+
if (gecko) spanAffectsWrapping = /$'/;
|
| 3089 |
+
else if (safari) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
|
| 3090 |
+
else if (chrome) spanAffectsWrapping = /\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/;
|
| 3091 |
|
| 3092 |
// Counts the column offset in a string, taking tabs into account.
|
| 3093 |
// Used mostly to find indentation.
|
| 3103 |
return n;
|
| 3104 |
}
|
| 3105 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3106 |
function eltOffset(node, screen) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3107 |
// Take the parts of bounding client rect that we are interested in so we are able to edit if need be,
|
| 3108 |
// since the returned value cannot be changed externally (they are kept in sync as the element moves within the page)
|
| 3109 |
try { var box = node.getBoundingClientRect(); box = { top: box.top, left: box.left }; }
|
| 3119 |
}
|
| 3120 |
}
|
| 3121 |
return box;
|
| 3122 |
+
}
|
| 3123 |
|
| 3124 |
// Get a node's text content.
|
| 3125 |
function eltText(node) {
|
| 3126 |
return node.textContent || node.innerText || node.nodeValue || "";
|
| 3127 |
}
|
| 3128 |
+
function selectInput(node) {
|
| 3129 |
+
if (ios) { // Mobile Safari apparently has a bug where select() is broken.
|
| 3130 |
+
node.selectionStart = 0;
|
| 3131 |
+
node.selectionEnd = node.value.length;
|
| 3132 |
+
} else node.select();
|
| 3133 |
+
}
|
| 3134 |
|
| 3135 |
// Operations on {line, ch} objects.
|
| 3136 |
function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
|
| 3137 |
function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
|
| 3138 |
function copyPos(x) {return {line: x.line, ch: x.ch};}
|
| 3139 |
|
| 3140 |
+
function elt(tag, content, className, style) {
|
| 3141 |
+
var e = document.createElement(tag);
|
| 3142 |
+
if (className) e.className = className;
|
| 3143 |
+
if (style) e.style.cssText = style;
|
| 3144 |
+
if (typeof content == "string") setTextContent(e, content);
|
| 3145 |
+
else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
|
| 3146 |
+
return e;
|
| 3147 |
}
|
| 3148 |
+
function removeChildren(e) {
|
| 3149 |
+
e.innerHTML = "";
|
| 3150 |
+
return e;
|
| 3151 |
+
}
|
| 3152 |
+
function removeChildrenAndAdd(parent, e) {
|
| 3153 |
+
removeChildren(parent).appendChild(e);
|
| 3154 |
+
}
|
| 3155 |
+
function setTextContent(e, str) {
|
| 3156 |
+
if (ie_lt9) {
|
| 3157 |
+
e.innerHTML = "";
|
| 3158 |
+
e.appendChild(document.createTextNode(str));
|
| 3159 |
+
} else e.textContent = str;
|
| 3160 |
+
}
|
| 3161 |
+
CodeMirror.setTextContent = setTextContent;
|
|
|
|
| 3162 |
|
| 3163 |
// Used to position the cursor after an undo/redo by finding the
|
| 3164 |
// last edited character.
|
| 3165 |
function editEnd(from, to) {
|
| 3166 |
+
if (!to) return 0;
|
| 3167 |
if (!from) return to.length;
|
| 3168 |
for (var i = from.length, j = to.length; i >= 0 && j >= 0; --i, --j)
|
| 3169 |
if (from.charAt(i) != to.charAt(j)) break;
|
| 3183 |
// See if "".split is the broken IE version, if so, provide an
|
| 3184 |
// alternative way to split lines.
|
| 3185 |
var splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
|
| 3186 |
+
var pos = 0, result = [], l = string.length;
|
| 3187 |
+
while (pos <= l) {
|
| 3188 |
+
var nl = string.indexOf("\n", pos);
|
| 3189 |
+
if (nl == -1) nl = string.length;
|
| 3190 |
+
var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
|
| 3191 |
+
var rt = line.indexOf("\r");
|
| 3192 |
+
if (rt != -1) {
|
| 3193 |
+
result.push(line.slice(0, rt));
|
| 3194 |
+
pos += rt + 1;
|
| 3195 |
+
} else {
|
| 3196 |
+
result.push(line);
|
| 3197 |
+
pos = nl + 1;
|
| 3198 |
+
}
|
| 3199 |
}
|
|
|
|
| 3200 |
return result;
|
| 3201 |
+
} : function(string){return string.split(/\r\n?|\n/);};
|
| 3202 |
CodeMirror.splitLines = splitLines;
|
| 3203 |
|
| 3204 |
var hasSelection = window.getSelection ? function(te) {
|
| 3219 |
var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
|
| 3220 |
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
|
| 3221 |
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
|
| 3222 |
+
46: "Delete", 59: ";", 91: "Mod", 92: "Mod", 93: "Mod", 109: "-", 107: "=", 127: "Delete",
|
| 3223 |
+
186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
|
| 3224 |
+
221: "]", 222: "'", 63276: "PageUp", 63277: "PageDown", 63275: "End", 63273: "Home",
|
| 3225 |
+
63234: "Left", 63232: "Up", 63235: "Right", 63233: "Down", 63302: "Insert", 63272: "Delete"};
|
| 3226 |
CodeMirror.keyNames = keyNames;
|
| 3227 |
(function() {
|
| 3228 |
// Number keys
|
js/posts-jquery.js
CHANGED
|
@@ -116,9 +116,6 @@ tags = {};
|
|
| 116 |
$('#wpe_qt_content_block').live("click", function() {
|
| 117 |
insertOpenCloseTag('block', 'b-quote', '\n\n<blockquote>', '</blockquote>\n\n');
|
| 118 |
})
|
| 119 |
-
$('#wpe_qt_content_block').live("click", function() {
|
| 120 |
-
insertOpenCloseTag('block', 'b-quote', '\n\n<blockquote>', '</blockquote>\n\n');
|
| 121 |
-
})
|
| 122 |
$('#wpe_qt_content_del').live("click", function() {
|
| 123 |
insertOpenCloseTag('del', 'del', '<del datetime="' + _datetime() + '">', '</del>');
|
| 124 |
})
|
|
@@ -210,7 +207,7 @@ tags = {};
|
|
| 210 |
this.focus();
|
| 211 |
this.setSelectionRange(start, end);
|
| 212 |
}
|
| 213 |
-
else if
|
| 214 |
var range = this.createTextRange();
|
| 215 |
range.collapse(true);
|
| 216 |
range.moveEnd('character', end);
|
|
@@ -221,19 +218,26 @@ tags = {};
|
|
| 221 |
};
|
| 222 |
window.original_send_to_editor = window.send_to_editor;
|
| 223 |
window.send_to_editor = function(html){
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
};
|
| 238 |
function postCodeMirror(element) {
|
| 239 |
var activeLine = WPEPosts.activeLine;
|
|
@@ -242,6 +246,8 @@ tags = {};
|
|
| 242 |
theme: WPEPosts.theme,
|
| 243 |
lineNumbers: WPEPosts.lineNumbers,
|
| 244 |
lineWrapping: WPEPosts.lineWrapping,
|
|
|
|
|
|
|
| 245 |
onCursorActivity: function() {
|
| 246 |
editor.setLineClass(hlLine, null);
|
| 247 |
hlLine = editor.setLineClass(editor.getCursor().line, activeLine);
|
|
@@ -276,6 +282,11 @@ tags = {};
|
|
| 276 |
}
|
| 277 |
});
|
| 278 |
var hlLine = editor.setLineClass(0, activeLine);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 279 |
if(!$('.CodeMirror .quicktags-toolbar').length) {
|
| 280 |
$('.CodeMirror').prepend('<div class="quicktags-toolbar">' +
|
| 281 |
'<input type="button" id="wpe_qt_content_strong" class="wpe_ed_button" title="" value="b">' +
|
|
@@ -295,6 +306,7 @@ tags = {};
|
|
| 295 |
'<input type="button" id="wpe_qt_content_fullscreen" class="ed_button" title="" value="fullscreen">' +
|
| 296 |
'</div>'
|
| 297 |
).height($('.CodeMirror').height() + 33);
|
|
|
|
| 298 |
}
|
| 299 |
}
|
| 300 |
})(jQuery);
|
| 116 |
$('#wpe_qt_content_block').live("click", function() {
|
| 117 |
insertOpenCloseTag('block', 'b-quote', '\n\n<blockquote>', '</blockquote>\n\n');
|
| 118 |
})
|
|
|
|
|
|
|
|
|
|
| 119 |
$('#wpe_qt_content_del').live("click", function() {
|
| 120 |
insertOpenCloseTag('del', 'del', '<del datetime="' + _datetime() + '">', '</del>');
|
| 121 |
})
|
| 207 |
this.focus();
|
| 208 |
this.setSelectionRange(start, end);
|
| 209 |
}
|
| 210 |
+
else if(this.createTextRange) {
|
| 211 |
var range = this.createTextRange();
|
| 212 |
range.collapse(true);
|
| 213 |
range.moveEnd('character', end);
|
| 218 |
};
|
| 219 |
window.original_send_to_editor = window.send_to_editor;
|
| 220 |
window.send_to_editor = function(html){
|
| 221 |
+
if(editor_status == 'html') {
|
| 222 |
+
var cursor = editor.getCursor(true);
|
| 223 |
+
var lines = $('#content').val().substr(0, this.selectionStart).split("\n");
|
| 224 |
+
var newLength = 0, line = 1, lineArray = [];
|
| 225 |
+
lineArray[0] = 0;
|
| 226 |
+
$.each(lines, function(key, value) {
|
| 227 |
+
newLength = newLength + value.length + 1;
|
| 228 |
+
lineArray[line] = newLength;
|
| 229 |
+
line++;
|
| 230 |
+
});
|
| 231 |
+
editor.toTextArea();
|
| 232 |
+
$('#content').setContentCursor(lineArray[cursor.line] + cursor.ch, lineArray[cursor.line] + cursor.ch);
|
| 233 |
+
window.original_send_to_editor(html);
|
| 234 |
+
postCodeMirror('content');
|
| 235 |
+
editor.setCursor(cursor.line, cursor.ch + html.length)
|
| 236 |
+
editor.focus();
|
| 237 |
+
}
|
| 238 |
+
else {
|
| 239 |
+
window.original_send_to_editor(html);
|
| 240 |
+
}
|
| 241 |
};
|
| 242 |
function postCodeMirror(element) {
|
| 243 |
var activeLine = WPEPosts.activeLine;
|
| 246 |
theme: WPEPosts.theme,
|
| 247 |
lineNumbers: WPEPosts.lineNumbers,
|
| 248 |
lineWrapping: WPEPosts.lineWrapping,
|
| 249 |
+
indentWithTabs: WPEPosts.indentWithTabs,
|
| 250 |
+
tabSize: WPEPosts.tabSize,
|
| 251 |
onCursorActivity: function() {
|
| 252 |
editor.setLineClass(hlLine, null);
|
| 253 |
hlLine = editor.setLineClass(editor.getCursor().line, activeLine);
|
| 282 |
}
|
| 283 |
});
|
| 284 |
var hlLine = editor.setLineClass(0, activeLine);
|
| 285 |
+
if(WPEPosts.editorHeight) {
|
| 286 |
+
$('.CodeMirror-scroll, .CodeMirror, .CodeMirror-gutter').height(WPEPosts.editorHeight + 'px');
|
| 287 |
+
var scrollDivHeight = $('.CodeMirror-scroll div:first-child').height();
|
| 288 |
+
$('.CodeMirror-gutter').height(scrollDivHeight);
|
| 289 |
+
}
|
| 290 |
if(!$('.CodeMirror .quicktags-toolbar').length) {
|
| 291 |
$('.CodeMirror').prepend('<div class="quicktags-toolbar">' +
|
| 292 |
'<input type="button" id="wpe_qt_content_strong" class="wpe_ed_button" title="" value="b">' +
|
| 306 |
'<input type="button" id="wpe_qt_content_fullscreen" class="ed_button" title="" value="fullscreen">' +
|
| 307 |
'</div>'
|
| 308 |
).height($('.CodeMirror').height() + 33);
|
| 309 |
+
editor.focus();
|
| 310 |
}
|
| 311 |
}
|
| 312 |
})(jQuery);
|
js/wpeditor.js
CHANGED
|
@@ -53,7 +53,7 @@ function toggleFullscreenEditing() {
|
|
| 53 |
else {
|
| 54 |
editorDiv.removeClass('CodeMirror-fullscreen');
|
| 55 |
editorDiv.height(toggleFullscreenEditing.beforeFullscreen.height);
|
| 56 |
-
$jq('.CodeMirror-scroll').height(
|
| 57 |
editorDiv.width('97%');
|
| 58 |
editor.refresh();
|
| 59 |
}
|
| 53 |
else {
|
| 54 |
editorDiv.removeClass('CodeMirror-fullscreen');
|
| 55 |
editorDiv.height(toggleFullscreenEditing.beforeFullscreen.height);
|
| 56 |
+
$jq('.CodeMirror-scroll').height(toggleFullscreenEditing.beforeFullscreen.height);
|
| 57 |
editorDiv.width('97%');
|
| 58 |
editor.refresh();
|
| 59 |
}
|
readme.txt
CHANGED
|
@@ -4,7 +4,7 @@ Donate link: http://wpeditor.net/
|
|
| 4 |
Tags: plugin editor, theme editor, page editor, post editor, pages, posts, html, codemirror, plugins, themes, editor, fancybox, post.php, post-new.php, ajax, syntax highlighting, html syntax highlighting
|
| 5 |
Requires at least: 3.0
|
| 6 |
Tested up to: 3.4.1
|
| 7 |
-
Stable tag: 1.1.0.
|
| 8 |
License: GPLv2 or later
|
| 9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
| 10 |
|
|
@@ -69,6 +69,14 @@ Yes! While we don't have a need for further developers at this time, any financi
|
|
| 69 |
|
| 70 |
== Changelog ==
|
| 71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
= 1.1.0.1 =
|
| 73 |
* Fixed Upload/Insert media buttons not working in page/post editor
|
| 74 |
* Removed legacy CSS theme files
|
|
@@ -103,6 +111,11 @@ Yes! While we don't have a need for further developers at this time, any financi
|
|
| 103 |
|
| 104 |
== Upgrade Notice ==
|
| 105 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
= 1.1.0.1 =
|
| 107 |
Fixed media buttons not working in Page/Post editor
|
| 108 |
|
| 4 |
Tags: plugin editor, theme editor, page editor, post editor, pages, posts, html, codemirror, plugins, themes, editor, fancybox, post.php, post-new.php, ajax, syntax highlighting, html syntax highlighting
|
| 5 |
Requires at least: 3.0
|
| 6 |
Tested up to: 3.4.1
|
| 7 |
+
Stable tag: 1.1.0.2
|
| 8 |
License: GPLv2 or later
|
| 9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
| 10 |
|
| 69 |
|
| 70 |
== Changelog ==
|
| 71 |
|
| 72 |
+
= 1.1.0.2 =
|
| 73 |
+
* Added ability to customize tab characters and size for all editors
|
| 74 |
+
* Added ability to set custom editor heights for all editors
|
| 75 |
+
* Updated CodeMirror library to 2.33
|
| 76 |
+
* Updated CSS to work with new version of CodeMirror
|
| 77 |
+
* Fixed issue with media button toolbar not inserting shortcodes/content when in visual mode
|
| 78 |
+
* Fixed issue with blockquote QuickTag inserting twice
|
| 79 |
+
|
| 80 |
= 1.1.0.1 =
|
| 81 |
* Fixed Upload/Insert media buttons not working in page/post editor
|
| 82 |
* Removed legacy CSS theme files
|
| 111 |
|
| 112 |
== Upgrade Notice ==
|
| 113 |
|
| 114 |
+
= 1.1.0.2 =
|
| 115 |
+
CodeMirror 2.33
|
| 116 |
+
Fixed issue with media button toolbar not inserting shortcodes/content when in visual mode
|
| 117 |
+
Fixed issue with blockquote QuickTag inserting twice
|
| 118 |
+
|
| 119 |
= 1.1.0.1 =
|
| 120 |
Fixed media buttons not working in Page/Post editor
|
| 121 |
|
views/plugin-editor.php
CHANGED
|
@@ -168,6 +168,11 @@
|
|
| 168 |
});
|
| 169 |
return false;
|
| 170 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
})
|
| 172 |
})(jQuery);
|
| 173 |
function runCodeMirror(extension) {
|
|
@@ -205,6 +210,14 @@
|
|
| 205 |
<?php }
|
| 206 |
if(WPEditorSetting::getValue('enable_plugin_line_wrapping')) { ?>
|
| 207 |
lineWrapping: true,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
<?php } ?>
|
| 209 |
onCursorActivity: function() {
|
| 210 |
editor.setLineClass(hlLine, null);
|
| 168 |
});
|
| 169 |
return false;
|
| 170 |
});
|
| 171 |
+
<?php if(WPEditorSetting::getValue('enable_plugin_editor_height')) { ?>
|
| 172 |
+
$('.CodeMirror-scroll, .CodeMirror').height('<?php echo WPEditorSetting::getValue("enable_plugin_editor_height"); ?>px');
|
| 173 |
+
var scrollDivHeight = $('.CodeMirror-scroll div:first-child').height();
|
| 174 |
+
$('.CodeMirror-gutter').height(scrollDivHeight);
|
| 175 |
+
<?php } ?>
|
| 176 |
})
|
| 177 |
})(jQuery);
|
| 178 |
function runCodeMirror(extension) {
|
| 210 |
<?php }
|
| 211 |
if(WPEditorSetting::getValue('enable_plugin_line_wrapping')) { ?>
|
| 212 |
lineWrapping: true,
|
| 213 |
+
<?php }
|
| 214 |
+
if(WPEditorSetting::getValue('enable_plugin_tab_characters') && WPEditorSetting::getValue('enable_plugin_tab_characters') == 'tabs') { ?>
|
| 215 |
+
indentWithTabs: true,
|
| 216 |
+
<?php }
|
| 217 |
+
if(WPEditorSetting::getValue('enable_plugin_tab_size')) { ?>
|
| 218 |
+
tabSize: <?php echo WPEditorSetting::getValue('enable_plugin_tab_size'); ?>,
|
| 219 |
+
<?php } else { ?>
|
| 220 |
+
tabSize: 2,
|
| 221 |
<?php } ?>
|
| 222 |
onCursorActivity: function() {
|
| 223 |
editor.setLineClass(hlLine, null);
|
views/settings.php
CHANGED
|
@@ -256,6 +256,54 @@
|
|
| 256 |
</ul>
|
| 257 |
</div>
|
| 258 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 259 |
<div id="enable-theme-file-upload" class="section">
|
| 260 |
<div class="section-header">
|
| 261 |
<h3><?php _e('File Upload', 'wpeditor'); ?></h3>
|
|
@@ -429,6 +477,54 @@
|
|
| 429 |
</ul>
|
| 430 |
</div>
|
| 431 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 432 |
<div id="enable-plugin-file-upload" class="section">
|
| 433 |
<div class="section-header">
|
| 434 |
<h3><?php _e('File Upload', 'wpeditor'); ?></h3>
|
|
@@ -569,6 +665,54 @@
|
|
| 569 |
</ul>
|
| 570 |
</div>
|
| 571 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 572 |
<div id="save-settings">
|
| 573 |
<ul>
|
| 574 |
<li>
|
| 256 |
</ul>
|
| 257 |
</div>
|
| 258 |
</div>
|
| 259 |
+
<div id="enable-theme-tab-characters" class="section">
|
| 260 |
+
<div class="section-header">
|
| 261 |
+
<h3><?php _e('Tab Characters', 'wpeditor'); ?></h3>
|
| 262 |
+
</div>
|
| 263 |
+
<div class="section-body">
|
| 264 |
+
<ul>
|
| 265 |
+
<li>
|
| 266 |
+
<label for="enable_theme_tab_characters"><?php _e('Tab Characters:', 'wpeditor'); ?></label>
|
| 267 |
+
</li>
|
| 268 |
+
<li class="indent">
|
| 269 |
+
<select name="enable_theme_tab_characters">
|
| 270 |
+
<option value="spaces"<?php echo WPEditorSetting::getValue('enable_theme_tab_characters') == 'spaces' ? ' selected="selected"' : ''; ?>><?php _e('Spaces', 'wpeditor'); ?></option>
|
| 271 |
+
<option value="tabs"<?php echo WPEditorSetting::getValue('enable_theme_tab_characters') == 'tabs' ? ' selected="selected"' : ''; ?>><?php _e('Tabs', 'wpeditor'); ?></option>
|
| 272 |
+
</select>
|
| 273 |
+
</li>
|
| 274 |
+
<li class="indent description">
|
| 275 |
+
<p><?php _e("This will set the tab character for the theme editor.<br />Default: Spaces", 'wpeditor'); ?></p>
|
| 276 |
+
</li>
|
| 277 |
+
<li>
|
| 278 |
+
<label for="enable_theme_tab_size"><?php _e('Tab Size:', 'wpeditor'); ?></label>
|
| 279 |
+
</li>
|
| 280 |
+
<li class="indent">
|
| 281 |
+
<input class="small-text" name="enable_theme_tab_size" value="<?php echo WPEditorSetting::getValue('enable_theme_tab_size') ? WPEditorSetting::getValue('enable_theme_tab_size') : 2; ?>" />
|
| 282 |
+
</li>
|
| 283 |
+
<li class="indent description">
|
| 284 |
+
<p><?php _e("This will set the tab size for the theme editor.<br />Default: 2", 'wpeditor'); ?></p>
|
| 285 |
+
</li>
|
| 286 |
+
</ul>
|
| 287 |
+
</div>
|
| 288 |
+
</div>
|
| 289 |
+
<div id="enable-theme-editor-height" class="section">
|
| 290 |
+
<div class="section-header">
|
| 291 |
+
<h3><?php _e('Tab Characters', 'wpeditor'); ?></h3>
|
| 292 |
+
</div>
|
| 293 |
+
<div class="section-body">
|
| 294 |
+
<ul>
|
| 295 |
+
<li>
|
| 296 |
+
<label for="enable_theme_editor_height"><?php _e('Editor Height:', 'wpeditor'); ?></label>
|
| 297 |
+
</li>
|
| 298 |
+
<li class="indent">
|
| 299 |
+
<input class="small-text" name="enable_theme_editor_height" value="<?php echo WPEditorSetting::getValue('enable_theme_editor_height') ? WPEditorSetting::getValue('enable_theme_editor_height') : 450; ?>" />
|
| 300 |
+
</li>
|
| 301 |
+
<li class="indent description">
|
| 302 |
+
<p><?php _e("This will set the height in pixels for the theme editor.<br />Default: 450", 'wpeditor'); ?></p>
|
| 303 |
+
</li>
|
| 304 |
+
</ul>
|
| 305 |
+
</div>
|
| 306 |
+
</div>
|
| 307 |
<div id="enable-theme-file-upload" class="section">
|
| 308 |
<div class="section-header">
|
| 309 |
<h3><?php _e('File Upload', 'wpeditor'); ?></h3>
|
| 477 |
</ul>
|
| 478 |
</div>
|
| 479 |
</div>
|
| 480 |
+
<div id="enable-plugin-tab-characters" class="section">
|
| 481 |
+
<div class="section-header">
|
| 482 |
+
<h3><?php _e('Tab Characters', 'wpeditor'); ?></h3>
|
| 483 |
+
</div>
|
| 484 |
+
<div class="section-body">
|
| 485 |
+
<ul>
|
| 486 |
+
<li>
|
| 487 |
+
<label for="enable_plugin_tab_characters"><?php _e('Tab Characters:', 'wpeditor'); ?></label>
|
| 488 |
+
</li>
|
| 489 |
+
<li class="indent">
|
| 490 |
+
<select name="enable_plugin_tab_characters">
|
| 491 |
+
<option value="spaces"<?php echo WPEditorSetting::getValue('enable_plugin_tab_characters') == 'spaces' ? ' selected="selected"' : ''; ?>><?php _e('Spaces', 'wpeditor'); ?></option>
|
| 492 |
+
<option value="tabs"<?php echo WPEditorSetting::getValue('enable_plugin_tab_characters') == 'tabs' ? ' selected="selected"' : ''; ?>><?php _e('Tabs', 'wpeditor'); ?></option>
|
| 493 |
+
</select>
|
| 494 |
+
</li>
|
| 495 |
+
<li class="indent description">
|
| 496 |
+
<p><?php _e("This will set the tab character for the plugin editor.<br />Default: Spaces", 'wpeditor'); ?></p>
|
| 497 |
+
</li>
|
| 498 |
+
<li>
|
| 499 |
+
<label for="enable_plugin_tab_size"><?php _e('Tab Size:', 'wpeditor'); ?></label>
|
| 500 |
+
</li>
|
| 501 |
+
<li class="indent">
|
| 502 |
+
<input class="small-text" name="enable_plugin_tab_size" value="<?php echo WPEditorSetting::getValue('enable_plugin_tab_size') ? WPEditorSetting::getValue('enable_plugin_tab_size') : 2; ?>" />
|
| 503 |
+
</li>
|
| 504 |
+
<li class="indent description">
|
| 505 |
+
<p><?php _e("This will set the tab size for the plugin editor.<br />Default: 2", 'wpeditor'); ?></p>
|
| 506 |
+
</li>
|
| 507 |
+
</ul>
|
| 508 |
+
</div>
|
| 509 |
+
</div>
|
| 510 |
+
<div id="enable-plugin-editor-height" class="section">
|
| 511 |
+
<div class="section-header">
|
| 512 |
+
<h3><?php _e('Tab Characters', 'wpeditor'); ?></h3>
|
| 513 |
+
</div>
|
| 514 |
+
<div class="section-body">
|
| 515 |
+
<ul>
|
| 516 |
+
<li>
|
| 517 |
+
<label for="enable_plugin_editor_height"><?php _e('Editor Height:', 'wpeditor'); ?></label>
|
| 518 |
+
</li>
|
| 519 |
+
<li class="indent">
|
| 520 |
+
<input class="small-text" name="enable_plugin_editor_height" value="<?php echo WPEditorSetting::getValue('enable_plugin_editor_height') ? WPEditorSetting::getValue('enable_plugin_editor_height') : 450; ?>" />
|
| 521 |
+
</li>
|
| 522 |
+
<li class="indent description">
|
| 523 |
+
<p><?php _e("This will set the height in pixels for the plugin editor.<br />Default: 450", 'wpeditor'); ?></p>
|
| 524 |
+
</li>
|
| 525 |
+
</ul>
|
| 526 |
+
</div>
|
| 527 |
+
</div>
|
| 528 |
<div id="enable-plugin-file-upload" class="section">
|
| 529 |
<div class="section-header">
|
| 530 |
<h3><?php _e('File Upload', 'wpeditor'); ?></h3>
|
| 665 |
</ul>
|
| 666 |
</div>
|
| 667 |
</div>
|
| 668 |
+
<div id="enable-post-tab-characters" class="section">
|
| 669 |
+
<div class="section-header">
|
| 670 |
+
<h3><?php _e('Tab Characters', 'wpeditor'); ?></h3>
|
| 671 |
+
</div>
|
| 672 |
+
<div class="section-body">
|
| 673 |
+
<ul>
|
| 674 |
+
<li>
|
| 675 |
+
<label for="enable_post_tab_characters"><?php _e('Tab Characters:', 'wpeditor'); ?></label>
|
| 676 |
+
</li>
|
| 677 |
+
<li class="indent">
|
| 678 |
+
<select name="enable_post_tab_characters">
|
| 679 |
+
<option value="spaces"<?php echo WPEditorSetting::getValue('enable_post_tab_characters') == 'spaces' ? ' selected="selected"' : ''; ?>><?php _e('Spaces', 'wpeditor'); ?></option>
|
| 680 |
+
<option value="tabs"<?php echo WPEditorSetting::getValue('enable_post_tab_characters') == 'tabs' ? ' selected="selected"' : ''; ?>><?php _e('Tabs', 'wpeditor'); ?></option>
|
| 681 |
+
</select>
|
| 682 |
+
</li>
|
| 683 |
+
<li class="indent description">
|
| 684 |
+
<p><?php _e("This will set the tab character for the post editor.<br />Default: Spaces", 'wpeditor'); ?></p>
|
| 685 |
+
</li>
|
| 686 |
+
<li>
|
| 687 |
+
<label for="enable_post_tab_size"><?php _e('Tab Size:', 'wpeditor'); ?></label>
|
| 688 |
+
</li>
|
| 689 |
+
<li class="indent">
|
| 690 |
+
<input class="small-text" name="enable_post_tab_size" value="<?php echo WPEditorSetting::getValue('enable_post_tab_size') ? WPEditorSetting::getValue('enable_post_tab_size') : 2; ?>" />
|
| 691 |
+
</li>
|
| 692 |
+
<li class="indent description">
|
| 693 |
+
<p><?php _e("This will set the tab size for the post editor.<br />Default: 2", 'wpeditor'); ?></p>
|
| 694 |
+
</li>
|
| 695 |
+
</ul>
|
| 696 |
+
</div>
|
| 697 |
+
</div>
|
| 698 |
+
<div id="enable-post-editor-height" class="section">
|
| 699 |
+
<div class="section-header">
|
| 700 |
+
<h3><?php _e('Tab Characters', 'wpeditor'); ?></h3>
|
| 701 |
+
</div>
|
| 702 |
+
<div class="section-body">
|
| 703 |
+
<ul>
|
| 704 |
+
<li>
|
| 705 |
+
<label for="enable_post_editor_height"><?php _e('Editor Height:', 'wpeditor'); ?></label>
|
| 706 |
+
</li>
|
| 707 |
+
<li class="indent">
|
| 708 |
+
<input class="small-text" name="enable_post_editor_height" value="<?php echo WPEditorSetting::getValue('enable_post_editor_height') ? WPEditorSetting::getValue('enable_post_editor_height') : 450; ?>" />
|
| 709 |
+
</li>
|
| 710 |
+
<li class="indent description">
|
| 711 |
+
<p><?php _e("This will set the height in pixels for the post editor.<br />Default: 450", 'wpeditor'); ?></p>
|
| 712 |
+
</li>
|
| 713 |
+
</ul>
|
| 714 |
+
</div>
|
| 715 |
+
</div>
|
| 716 |
<div id="save-settings">
|
| 717 |
<ul>
|
| 718 |
<li>
|
views/theme-editor.php
CHANGED
|
@@ -175,7 +175,11 @@
|
|
| 175 |
});
|
| 176 |
return false;
|
| 177 |
});
|
| 178 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
})
|
| 180 |
})(jQuery);
|
| 181 |
function runCodeMirror(extension) {
|
|
@@ -213,6 +217,14 @@
|
|
| 213 |
<?php }
|
| 214 |
if(WPEditorSetting::getValue('enable_theme_line_wrapping')) { ?>
|
| 215 |
lineWrapping: true,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
<?php } ?>
|
| 217 |
onCursorActivity: function() {
|
| 218 |
editor.setLineClass(hlLine, null);
|
| 175 |
});
|
| 176 |
return false;
|
| 177 |
});
|
| 178 |
+
<?php if(WPEditorSetting::getValue('enable_theme_editor_height')) { ?>
|
| 179 |
+
$('.CodeMirror-scroll, .CodeMirror').height('<?php echo WPEditorSetting::getValue("enable_theme_editor_height"); ?>px');
|
| 180 |
+
var scrollDivHeight = $('.CodeMirror-scroll div:first-child').height();
|
| 181 |
+
$('.CodeMirror-gutter').height(scrollDivHeight);
|
| 182 |
+
<?php } ?>
|
| 183 |
})
|
| 184 |
})(jQuery);
|
| 185 |
function runCodeMirror(extension) {
|
| 217 |
<?php }
|
| 218 |
if(WPEditorSetting::getValue('enable_theme_line_wrapping')) { ?>
|
| 219 |
lineWrapping: true,
|
| 220 |
+
<?php }
|
| 221 |
+
if(WPEditorSetting::getValue('enable_theme_tab_characters') && WPEditorSetting::getValue('enable_theme_tab_characters') == 'tabs') { ?>
|
| 222 |
+
indentWithTabs: true,
|
| 223 |
+
<?php }
|
| 224 |
+
if(WPEditorSetting::getValue('enable_theme_tab_size')) { ?>
|
| 225 |
+
tabSize: <?php echo WPEditorSetting::getValue('enable_theme_tab_size'); ?>,
|
| 226 |
+
<?php } else { ?>
|
| 227 |
+
tabSize: 2,
|
| 228 |
<?php } ?>
|
| 229 |
onCursorActivity: function() {
|
| 230 |
editor.setLineClass(hlLine, null);
|
wpeditor.php
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
Plugin Name: WP Editor
|
| 4 |
Plugin URI: http://wpeditor.net
|
| 5 |
Description: This plugin modifies the default behavior of the WordPress plugin and theme editors.
|
| 6 |
-
Version: 1.1.0.
|
| 7 |
Author: Benjamin Rojas
|
| 8 |
Author URI: http://benjaminrojas.net
|
| 9 |
Text Domain: wpeditor
|
|
@@ -31,7 +31,7 @@ if(!class_exists('WPEditor')) {
|
|
| 31 |
ob_start();
|
| 32 |
|
| 33 |
// Define the WP Editor version number
|
| 34 |
-
define('WPEDITOR_VERSION_NUMBER', '1.1');
|
| 35 |
|
| 36 |
$wp_34 = false;
|
| 37 |
if(version_compare(get_bloginfo('version'), '3.4', '>=')) {
|
| 3 |
Plugin Name: WP Editor
|
| 4 |
Plugin URI: http://wpeditor.net
|
| 5 |
Description: This plugin modifies the default behavior of the WordPress plugin and theme editors.
|
| 6 |
+
Version: 1.1.0.2
|
| 7 |
Author: Benjamin Rojas
|
| 8 |
Author URI: http://benjaminrojas.net
|
| 9 |
Text Domain: wpeditor
|
| 31 |
ob_start();
|
| 32 |
|
| 33 |
// Define the WP Editor version number
|
| 34 |
+
define('WPEDITOR_VERSION_NUMBER', '1.1.0.2');
|
| 35 |
|
| 36 |
$wp_34 = false;
|
| 37 |
if(version_compare(get_bloginfo('version'), '3.4', '>=')) {
|
