Skip to content

Commit

Permalink
Allow duplicate key commands to be registered
Browse files Browse the repository at this point in the history
* Last registered command wins
* Returning false from a command continues to the next matching command
  • Loading branch information
rlivsey committed Oct 14, 2015
1 parent 1364fb3 commit 0140bd9
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 9 deletions.
28 changes: 22 additions & 6 deletions src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
DEFAULT_TEXT_EXPANSIONS, findExpansion, validateExpansion
} from './text-expansions';
import {
DEFAULT_KEY_COMMANDS, findKeyCommand, validateKeyCommand
DEFAULT_KEY_COMMANDS, findKeyCommands, validateKeyCommand
} from './key-commands';
import { capitalize } from '../utils/string-utils';
import LifecycleCallbacksMixin from '../utils/lifecycle-callbacks';
Expand Down Expand Up @@ -196,7 +196,7 @@ class Editor {
if (!validateKeyCommand(keyCommand)) {
throw new Error('Key Command is not valid');
}
this.keyCommands.push(keyCommand);
this.keyCommands.unshift(keyCommand);
}

handleExpansion(event) {
Expand Down Expand Up @@ -602,11 +602,27 @@ class Editor {
this.handleKeyCommand(event);
}

/**
* Finds and runs the first matching key command for the event
*
* If multiple commands are bound to a key combination, the
* first matching one is run.
*
* If a command returns `false` then the next matching command
* is run instead.
*
* @method handleKeyCommand
* @param {Event} event The keyboard event triggered by the user
* @private
*/
handleKeyCommand(event) {
const keyCommand = findKeyCommand(this.keyCommands, event);
if (keyCommand) {
event.preventDefault();
keyCommand.run(this);
const keyCommands = findKeyCommands(this.keyCommands, event);
for (let i=0; i<keyCommands.length; i++) {
let keyCommand = keyCommands[i];
if (keyCommand.run(this) !== false) {
event.preventDefault();
return;
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/js/editor/key-commands.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Key from '../utils/key';
import { MODIFIERS } from '../utils/key';
import { detect } from '../utils/array-utils';
import { filter } from '../utils/array-utils';
import LinkCommand from '../commands/link';

export const DEFAULT_KEY_COMMANDS = [{
Expand Down Expand Up @@ -50,10 +50,10 @@ export function validateKeyCommand(keyCommand) {
return !!keyCommand.modifier && !!keyCommand.str && !!keyCommand.run;
}

export function findKeyCommand(keyCommands, keyEvent) {
export function findKeyCommands(keyCommands, keyEvent) {
const key = Key.fromEvent(keyEvent);

return detect(keyCommands, ({modifier, str}) => {
return filter(keyCommands, ({modifier, str}) => {
return key.hasModifier(modifier) && key.isChar(str);
});
}
56 changes: 56 additions & 0 deletions tests/acceptance/editor-key-commands-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,59 @@ test('new key commands can be registered', (assert) => {

assert.ok(!!passedEditor && passedEditor === editor, 'run method is called');
});

test('duplicate key commands can be registered with the last registered winning', (assert) => {
const mobiledoc = Helpers.mobiledoc.build(
({post, markupSection, marker}) => post([
markupSection('p', [marker('something')])
]));

let firstCommandRan, secondCommandRan;
editor = new Editor({mobiledoc});
editor.registerKeyCommand({
modifier: MODIFIERS.CTRL,
str: 'X',
run() { firstCommandRan = true; }
});
editor.registerKeyCommand({
modifier: MODIFIERS.CTRL,
str: 'X',
run() { secondCommandRan = true; }
});
editor.render(editorElement);

Helpers.dom.triggerKeyCommand(editor, 'X', MODIFIERS.CTRL);

assert.ok(!firstCommandRan, 'first registered method not called');
assert.ok(!!secondCommandRan, 'last registered method is called');
});

test('returning false from key command causes next match to run', (assert) => {
const mobiledoc = Helpers.mobiledoc.build(
({post, markupSection, marker}) => post([
markupSection('p', [marker('something')])
]));

let firstCommandRan, secondCommandRan;
editor = new Editor({mobiledoc});
editor.registerKeyCommand({
modifier: MODIFIERS.CTRL,
str: 'X',
run() { firstCommandRan = true; }
});
editor.registerKeyCommand({
modifier: MODIFIERS.CTRL,
str: 'X',
run() {
secondCommandRan = true;
return false;
}
});
editor.render(editorElement);

Helpers.dom.triggerKeyCommand(editor, 'X', MODIFIERS.CTRL);

assert.ok(!!secondCommandRan, 'last registered method is called');
assert.ok(!!firstCommandRan, 'first registered method is called');
});

0 comments on commit 0140bd9

Please sign in to comment.