./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