From 874349515f534b92654b5b84149ad69dda9de722 Mon Sep 17 00:00:00 2001 From: Julian Viereck Date: Wed, 15 Jun 2011 21:07:18 +0200 Subject: [PATCH] Make keyboard infrastructure route keys like []^$ the right way. --- demo/demo.js | 6 +++++- lib/ace/editor.js | 37 +++++++++++++++++++++++++--------- lib/ace/keyboard/keybinding.js | 17 ++++++++++------ lib/ace/keyboard/textinput.js | 14 +++++++++---- 4 files changed, 54 insertions(+), 20 deletions(-) diff --git a/demo/demo.js b/demo/demo.js index 29068cd5..d18dc4a0 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -80,7 +80,11 @@ exports.launch = function(env) { emacs: emacs, // This is a way to define simple keyboard remappings custom: new HashHandler({ - "gotoright": "Tab" + "gotoright": "Tab", + "indent": "]", + "outdent": "[", + "gotolinestart": "^", + "gotolineend": "$" }) } diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 01256ee3..3b52c0d1 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -421,14 +421,14 @@ var Editor =function(renderer, session) { var mode = session.getMode(); var cursor = this.getCursorPosition(); - + if (this.getBehavioursEnabled()) { // Get a transform if the current mode wants one. var transform = mode.transformAction(session.getState(cursor.row), 'insertion', this, session, text); if (transform) text = transform.text; } - + text = text.replace("\t", this.session.getTabString()); // remove selected text @@ -450,7 +450,7 @@ var Editor =function(renderer, session) { var line = session.getLine(cursor.row); var lineIndent = mode.getNextLineIndent(lineState, line.slice(0, cursor.column), session.getTabString()); var end = session.insert(cursor, text); - + if (transform && transform.selection) { if (transform.selection.length == 2) { // Transform relative to the current column this.selection.setSelectionRange( @@ -464,7 +464,7 @@ var Editor =function(renderer, session) { transform.selection[3])); } } - + var lineState = session.getState(cursor.row); // TODO disabled multiline auto indent @@ -510,8 +510,27 @@ var Editor =function(renderer, session) { } }; - this.onTextInput = function(text) { - this.keyBinding.onTextInput(text); + this.onTextInput = function(text, notPasted) { + // In case the text was not pasted and we got only one character, then + // handel it as a command key stroke. + if (notPasted && text.length == 1) { + // Note: The `null` as `keyCode` is important here, as there are + // some checks in the code for `keyCode == 0` meaning the text comes + // from the keyBinding.onTextInput code path. + var handled = this.keyBinding.onCommandKey({}, 0, null, text); + + // Check if the text was handled. If not, then handled it as "normal" + // text and insert it to the editor directly. This shouldn't be done + // using the this.keyBinding.onTextInput(text) function, as it would + // make the `text` get sent to the keyboardHandler twice, which might + // turn out to be a bad thing in case there is a custome keyboard + // handler like the StateHandler. + if (!handled) { + this.insert(text); + } + } else { + this.keyBinding.onTextInput(text); + } }; this.onCommandKey = function(e, hashId, keyCode) { @@ -614,12 +633,12 @@ var Editor =function(renderer, session) { this.getReadOnly = function() { return this.$readOnly; }; - + this.$modeBehaviours = false; this.setBehavioursEnabled = function (enabled) { this.$modeBehaviours = enabled; } - + this.getBehavioursEnabled = function () { return this.$modeBehaviours; } @@ -641,7 +660,7 @@ var Editor =function(renderer, session) { if (this.selection.isEmpty()) this.selection.selectLeft(); - + var range = this.getSelectionRange(); if (this.getBehavioursEnabled()) { var session = this.session; diff --git a/lib/ace/keyboard/keybinding.js b/lib/ace/keyboard/keybinding.js index 93fc3fa8..a342a4a1 100644 --- a/lib/ace/keyboard/keybinding.js +++ b/lib/ace/keyboard/keybinding.js @@ -88,22 +88,27 @@ var KeyBinding = function(editor) { } } + var success = false; if (toExecute) { - var success = canon.exec(toExecute.command, + success = canon.exec(toExecute.command, env, "editor", toExecute.args); if (success) { - return event.stopEvent(e); + event.stopEvent(e); } } + return success; }; - this.onCommandKey = function(e, hashId, keyCode) { - var keyString = keyUtil.keyCodeToString(keyCode); - this.$callKeyboardHandler(e, hashId, keyString, keyCode); + this.onCommandKey = function(e, hashId, keyCode, keyString) { + // In case there is no keyString, try to interprete the keyCode. + if (!keyString) { + keyString = keyUtil.keyCodeToString(keyCode); + } + return this.$callKeyboardHandler(e, hashId, keyString, keyCode); }; this.onTextInput = function(text) { - this.$callKeyboardHandler({}, 0, text, 0); + return this.$callKeyboardHandler({}, 0, text, 0); } }).call(KeyBinding.prototype); diff --git a/lib/ace/keyboard/textinput.js b/lib/ace/keyboard/textinput.js index ecd9a9e6..aa517cc2 100644 --- a/lib/ace/keyboard/textinput.js +++ b/lib/ace/keyboard/textinput.js @@ -54,6 +54,7 @@ var TextInput = function(parentNode, host) { var inCompostion = false; var copied = false; + var pasted = false; var tempStyle = ''; function sendText(valueToSend) { @@ -63,12 +64,15 @@ var TextInput = function(parentNode, host) { if (value.charCodeAt(value.length-1) == PLACEHOLDER.charCodeAt(0)) { value = value.slice(0, -1); if (value) - host.onTextInput(value); - } else - host.onTextInput(value); + host.onTextInput(value, !pasted); + } else { + host.onTextInput(value, !pasted); + } } } + copied = false; + pasted = false; // Safari doesn't fire copy events if no text is selected text.value = PLACEHOLDER; @@ -153,6 +157,8 @@ var TextInput = function(parentNode, host) { }; event.addListener(text, "textInput", onTextInput); event.addListener(text, "paste", function(e) { + // Mark that the next input text comes from past. + pasted = true; // Some browsers support the event.clipboardData API. Use this to get // the pasted content which increases speed if pasting a lot of lines. if (e.clipboardData && e.clipboardData.getData) { @@ -170,7 +176,7 @@ var TextInput = function(parentNode, host) { }; if (useragent.isIE) { - event.addListener(text, "beforecopy", function(e) { + event.addListener(text, "beforecopy", function(e) { var copyText = host.getCopyText(); if(copyText) clipboardData.setData("Text", copyText);