./vendor/assets/javascripts/codemirror.js in codemirror-rails-0.2.1 vs ./vendor/assets/javascripts/codemirror.js in codemirror-rails-0.2.2
- old
+ new
@@ -117,19 +117,21 @@
getSelection: getSelection,
replaceSelection: operation(replaceSelection),
focus: function(){focusInput(); onFocus(); fastPoll();},
setOption: function(option, value) {
options[option] = value;
- if (option == "lineNumbers" || option == "gutter") gutterChanged();
+ if (option == "lineNumbers" || option == "gutter" || option == "firstLineNumber") gutterChanged();
else if (option == "mode" || option == "indentUnit") loadMode();
else if (option == "readOnly" && value == "nocursor") input.blur();
else if (option == "theme") scroller.className = scroller.className.replace(/cm-s-\w+/, "cm-s-" + value);
},
getOption: function(option) {return options[option];},
undo: operation(undo),
redo: operation(redo),
- indentLine: operation(function(n) {if (isLine(n)) indentLine(n, "smart");}),
+ indentLine: operation(function(n, dir) {
+ if (isLine(n)) indentLine(n, dir == null ? "smart" : dir ? "add" : "subtract");
+ }),
historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
matchBrackets: operation(function(){matchBrackets(true);}),
getTokenAt: function(pos) {
pos = clipPos(pos);
return lines[pos.line].getTokenAt(mode, getStateBefore(pos.line), pos.ch);
@@ -198,11 +200,12 @@
operation: function(f){return operation(f)();},
refresh: function(){updateDisplay(true);},
getInputField: function(){return input;},
getWrapperElement: function(){return wrapper;},
- getScrollerElement: function(){return scroller;}
+ getScrollerElement: function(){return scroller;},
+ getGutterElement: function(){return gutter;}
};
function setValue(code) {
history = null;
var top = {line: 0, ch: 0};
@@ -338,25 +341,28 @@
if (!anyMod && code == 13) {return;} // enter
if (!anyMod && code == 9 && handleTab(e.shiftKey)) return e_preventDefault(e); // tab
if (mod && code == 90) {undo(); return e_preventDefault(e);} // ctrl-z
if (mod && ((e.shiftKey && code == 90) || code == 89)) {redo(); return e_preventDefault(e);} // ctrl-shift-z, ctrl-y
}
+ if (code == 36) { if (options.smartHome) { smartHome(); return e_preventDefault(e); } }
// Key id to use in the movementKeys map. We also pass it to
// fastPoll in order to 'self learn'. We need this because
// reducedSelection, the hack where we collapse the selection to
// its start when it is inverted and a movement key is pressed
// (and later restore it again), shouldn't be used for
// non-movement keys.
- curKeyId = (mod ? "c" : "") + code;
- if (sel.inverted && movementKeys.hasOwnProperty(curKeyId)) {
+ curKeyId = (mod ? "c" : "") + (e.altKey ? "a" : "") + code;
+ if (sel.inverted && movementKeys[curKeyId] === true) {
var range = selRange(input);
if (range) {
reducedSelection = {anchor: range.start};
setSelRange(input, range.start, range.start);
}
}
+ // Don't save the key as a movementkey unless it had a modifier
+ if (!mod && !e.altKey) curKeyId = null;
fastPoll(curKeyId);
}
function onKeyUp(e) {
if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e))) return;
if (reducedSelection) {
@@ -564,11 +570,14 @@
var missed = false;
pollingFast = true;
function p() {
startOperation();
var changed = readInput();
- if (changed == "moved" && keyId) movementKeys[keyId] = true;
+ if (changed && keyId) {
+ if (changed == "moved" && movementKeys[keyId] == null) movementKeys[keyId] = true;
+ if (changed == "changed") movementKeys[keyId] = false;
+ }
if (!changed && !missed) {missed = true; poll.set(80, p);}
else {pollingFast = false; slowPoll();}
endOperation();
}
poll.set(20, p);
@@ -661,10 +670,16 @@
}
function focusInput() {
if (options.readOnly != "nocursor") input.focus();
}
+ function scrollEditorIntoView() {
+ if (!cursor.getBoundingClientRect) return;
+ var rect = cursor.getBoundingClientRect();
+ var winH = window.innerHeight || document.body.offsetHeight || document.documentElement.offsetHeight;
+ if (rect.top < 0 || rect.bottom > winH) cursor.scrollIntoView();
+ }
function scrollCursorIntoView() {
var cursor = localCoords(sel.inverted ? sel.from : sel.to);
return scrollIntoView(cursor.x, cursor.y, cursor.x, cursor.yBot);
}
function scrollIntoView(x1, y1, x2, y2) {
@@ -764,12 +779,12 @@
showingFrom = from; showingTo = to;
mover.style.top = (from * lineHeight()) + "px";
if (different) {
lastHeight = scroller.clientHeight;
code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
- updateGutter();
}
+ if (different || updates.length) updateGutter();
if (maxWidth == null) maxWidth = stringWidth(maxLine);
if (maxWidth > scroller.clientWidth) {
lineSpace.style.width = maxWidth + "px";
// Needed to prevent odd wrapping/hiding of widgets placed in here.
@@ -869,14 +884,16 @@
gutter.style.display = "";
lineSpace.style.marginLeft = gutter.offsetWidth + "px";
}
function updateCursor() {
var head = sel.inverted ? sel.from : sel.to, lh = lineHeight();
- var x = charX(head.line, head.ch) + "px", y = (head.line - showingFrom) * lh + "px";
+ var x = charX(head.line, head.ch);
inputDiv.style.top = (head.line * lh - scroller.scrollTop) + "px";
+ inputDiv.style.left = (x - scroller.scrollLeft) + "px";
if (posEq(sel.from, sel.to)) {
- cursor.style.top = y; cursor.style.left = x;
+ cursor.style.top = (head.line - showingFrom) * lh + "px";
+ cursor.style.left = x + "px";
cursor.style.display = "";
}
else cursor.style.display = "none";
}
@@ -992,10 +1009,14 @@
indentSelected(shift ? "subtract" : "add");
break;
}
return true;
}
+ function smartHome() {
+ var firstNonWS = Math.max(0, lines[sel.from.line].text.search(/\S/));
+ setCursor(sel.from.line, sel.from.ch <= firstNonWS && sel.from.ch ? 0 : firstNonWS, true);
+ }
function indentLine(n, how) {
if (how == "smart") {
if (!mode.indent) how = "prev";
else var state = getStateBefore(n);
@@ -1188,12 +1209,12 @@
if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
operation(setCursor)(pos.line, pos.ch);
var oldCSS = input.style.cssText;
inputDiv.style.position = "absolute";
- input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e_pageY(e) - 1) +
- "px; left: " + (e_pageX(e) - 1) + "px; z-index: 1000; background: white; " +
+ input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
+ "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; " +
"border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
leaveInputAlone = true;
var val = input.value = getSelection();
focusInput();
setSelRange(input, 0, input.value.length);
@@ -1282,11 +1303,11 @@
if (search == 0) return 0;
var line = lines[search-1];
if (line.stateAfter) return search;
var indented = line.indentation();
if (minline == null || minindent > indented) {
- minline = search;
+ minline = search - 1;
minindent = indented;
}
}
return minline;
}
@@ -1319,29 +1340,30 @@
if (task >= lines.length) continue;
var start = findStartLine(task), state = start && lines[start-1].stateAfter;
if (state) state = copyState(mode, state);
else state = startState(mode);
- var unchanged = 0, compare = mode.compareStates;
+ var unchanged = 0, compare = mode.compareStates, realChange = false;
for (var i = start, l = lines.length; i < l; ++i) {
var line = lines[i], hadState = line.stateAfter;
if (+new Date > end) {
work.push(i);
startWorker(options.workDelay);
- changes.push({from: task, to: i + 1});
+ if (realChange) changes.push({from: task, to: i + 1});
return;
}
var changed = line.highlight(mode, state);
+ if (changed) realChange = true;
line.stateAfter = copyState(mode, state);
if (compare) {
if (hadState && compare(hadState, state)) break;
} else {
- if (changed || !hadState) unchanged = 0;
+ if (changed !== false || !hadState) unchanged = 0;
else if (++unchanged > 3) break;
}
}
- changes.push({from: task, to: i + 1});
+ if (realChange) changes.push({from: task, to: i + 1});
}
if (foundWork && options.onHighlightComplete)
options.onHighlightComplete(instance);
}
function startWorker(time) {
@@ -1360,11 +1382,11 @@
var reScroll = false;
if (selectionChanged) reScroll = !scrollCursorIntoView();
if (changes.length) updateDisplay(changes);
else if (selectionChanged) updateCursor();
if (reScroll) scrollCursorIntoView();
- if (selectionChanged) restartBlink();
+ if (selectionChanged) {scrollEditorIntoView(); restartBlink();}
// updateInput can be set to a boolean value to force/prevent an
// update.
if (focused && !leaveInputAlone &&
(updateInput === true || (updateInput !== false && selectionChanged)))
@@ -1525,10 +1547,11 @@
onKeyEvent: null,
lineNumbers: false,
gutter: false,
firstLineNumber: 1,
readOnly: false,
+ smartHome: true,
onChange: null,
onCursorActivity: null,
onGutterClick: null,
onHighlightComplete: null,
onFocus: null, onBlur: null, onScroll: null,
@@ -1658,11 +1681,11 @@
if (typeof match == "string") var ok = ch == match;
else var ok = ch && (match.test ? match.test(ch) : match(ch));
if (ok) {++this.pos; return ch;}
},
eatWhile: function(match) {
- var start = this.start;
+ var start = this.pos;
while (this.eat(match)){}
return this.pos > start;
},
eatSpace: function() {
var start = this.pos;
@@ -1767,14 +1790,14 @@
break;
}
}
if (st.length != pos) {st.length = pos; changed = true;}
if (pos && st[pos-2] != prevWord) changed = true;
- // Short lines with simple highlights always count as changed,
- // because they are likely to highlight the same way in various
- // contexts.
- return changed || (st.length < 5 && this.text.length < 10);
+ // Short lines with simple highlights return null, and are
+ // counted as changed by the driver because they are likely to
+ // highlight the same way in various contexts.
+ return changed || (st.length < 5 && this.text.length < 10 ? null : false);
},
// Fetch the parser token for a given character. Useful for hacks
// that want to inspect the mode state (say, for completion).
getTokenAt: function(mode, state, ch) {
var txt = this.text, stream = new StringStream(txt);
@@ -1927,19 +1950,9 @@
function e_button(e) {
if (e.which) return e.which;
else if (e.button & 1) return 1;
else if (e.button & 2) return 3;
else if (e.button & 4) return 2;
- }
- function e_pageX(e) {
- if (e.pageX != null) return e.pageX;
- var doc = e_target(e).ownerDocument;
- return e.clientX + doc.body.scrollLeft + doc.documentElement.scrollLeft;
- }
- function e_pageY(e) {
- if (e.pageY != null) return e.pageY;
- var doc = e_target(e).ownerDocument;
- return e.clientY + doc.body.scrollTop + doc.documentElement.scrollTop;
}
// Event handler registration. If disconnect is true, it'll return a
// function that unregisters the handler.
function connect(node, type, handler, disconnect) {
\ No newline at end of file