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 | WP Editor |
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', '>=')) {
|