Skip to content

Commit

Permalink
WIP start implementing the on-key helper
Browse files Browse the repository at this point in the history
  • Loading branch information
lukemelia committed May 20, 2020
1 parent 4feeece commit d16ef3e
Show file tree
Hide file tree
Showing 9 changed files with 451 additions and 28 deletions.
44 changes: 22 additions & 22 deletions API-DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,33 @@ Replaces the `keyboard-press` component in 6.0.0-beta.0. Since nothing is output
helper is more appropriate than a component.

```hbs
<!-- Fires DoThing on keydown of the key that generates "c" on their computer
<!-- Fires `doThing` on keydown of the key that generates "c" on their computer
while Alt is pressed -->
{{on-key "alt+c" this.DoThing}}
<!-- Fires DoThing on KEYUP of the key that generates "c" on their computer
{{on-key "alt+c" this.doThing}}
<!-- Fires `doThing` on KEYUP of the key that generates "c" on their computer
while Alt is pressed -->
{{on-key "alt+c" this.DoThing event="keyup"}}
<!-- Fires DoThing on keydown of the key that generates "c" on their computer
{{on-key "alt+c" this.doThing event="keyup"}}
<!-- Fires `doThing` on keydown of the key that generates "c" on their computer
while Alt is pressed, or on keydown of the key that generates "t" while
Ctrl and Shift are pressed (i.e. no API support for binding multiple keys,
just include on-key twice) -->
{{on-key "alt+c" this.DoThing}}
{{on-key "ctrl+shift+t" this.DoThing}}
<!-- Fires DoThing on keydown of the key at the standard position of the C key
{{on-key "alt+c" this.doThing}}
{{on-key "ctrl+shift+t" this.doThing}}
<!-- Fires `doThing` on keydown of the key at the standard position of the C key
while Alt is pressed. This is inferred from the use of "KeyC" rather than "c" -->
{{on-key "alt+KeyC" this.DoThing}}
<!-- Fires DoThing on keyup of the key at the standard position of the C key
{{on-key "alt+KeyC" this.doThing}}
<!-- Fires `doThing` on keyup of the key at the standard position of the C key
while Alt is pressed -->
{{on-key "alt+KeyC" this.DoThing event="keyup"}}
{{on-key "alt+KeyC" this.doThing event="keyup"}}
```

#### on-key element modifier
Expand All @@ -79,10 +79,10 @@ Uses the same signature as the `on-key` helper.
<!-- When used with a form element input, textarea, or select, the action fires only
when element has focus: -->
<input type='text' {{on-key "alt+c" this.DoThing}}> <!-- `key` mode -->
<input type='text' {{on-key "alt+c" this.DoThing event="keyup"}}> <!-- `key` mode -->
<input type='text' {{on-key "alt+KeyC" this.DoThing}}> <!-- `code` mode -->
<input type='text' {{on-key "alt+KeyC" this.DoThing event="keyup"}}> <!-- `code` mode -->
<input type='text' {{on-key "alt+c" this.doThing}}> <!-- `key` mode -->
<input type='text' {{on-key "alt+c" this.doThing event="keyup"}}> <!-- `key` mode -->
<input type='text' {{on-key "alt+KeyC" this.doThing}}> <!-- `code` mode -->
<input type='text' {{on-key "alt+KeyC" this.doThing event="keyup"}}> <!-- `code` mode -->
<!-- When used with another element type and leaving off the action, it will trigger a
`click` on the element if no action is passed. This allows for easy declaration of
Expand All @@ -104,8 +104,8 @@ import { onKey } from 'ember-keyboard';

export default class Foo extends Component {
//...
@onKey('alt+c') // `key` mode

@onKey('alt+c') // `key` mode
doSomethingA() { ... }

@onKey('alt+c', { event: 'keyup' }) // `key` mode
Expand Down
40 changes: 40 additions & 0 deletions addon/helpers/on-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import listenerName from 'ember-keyboard/utils/listener-name';

export default class extends Helper {
@service keyboard;
keyCombo;
callback;
keyboardActivated = true;
keyboardPriority = 0;
eventName = 'keydown';
listenerName;

compute([keyCombo, callback], { event = 'keydown', activated = true, priority = 0 }) {
this.keyCombo = keyCombo;
this.callback = callback;
this.eventName = event;
this.keyboardActivated = activated;
this.keyboardPriority = priority;
this.listenerName = listenerName(this.eventName, this.keyCombo.split('+'));
this.keyboard.register(this);
}

destroy() {
this.keyboard.unregister(this);
super.destroy(...arguments);
}

has(triggerName) {
return triggerName === this.listenerName;
}

trigger(triggerName) {
if (triggerName === this.listenerName) {
if (this.callback) {
this.callback();
}
}
}
}
1 change: 1 addition & 0 deletions app/helpers/on-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from 'ember-keyboard/helpers/on-key';
72 changes: 72 additions & 0 deletions tests/acceptance/on-key-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { visit, currentURL, triggerEvent } from '@ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
import { module, test } from 'qunit';

import { keyDown } from 'ember-keyboard/test-support/test-helpers';

import { textChanged } from '../helpers/text-changed';

module('Acceptance | on-key helper ', function(hooks) {
setupApplicationTest(hooks);

hooks.beforeEach(async function(assert) {
await visit('/test-scenario/on-key-examples');
assert.equal(currentURL(), '/test-scenario/on-key-examples');
});

test('KeyS, no modifiers', async function(assert) {
assert.expect(3);

await textChanged(
assert,
() => keyDown('KeyS'), {
selectorName: 's',
beforeValue: 'S not pressed',
afterValue: 'S pressed'
});
});

test('Ctrl+KeyK', async function(assert) {
assert.expect(3);

await textChanged(
assert,
() => keyDown('ctrl+KeyK'), {
selectorName: 'ctrl-k',
beforeValue: 'Ctrl+K not pressed',
afterValue: 'Ctrl+K pressed'
});
});

test('keydown: Ctrl+k on a Dvorak Keyboard', async function(assert) {
assert.expect(3);

const ctrlKDownProperties = {
code: 'KeyV',
key: 'k',
keyCode: 75,
which: 75,
ctrlKey: true
};

await textChanged(
assert,
() => triggerEvent(document.body, 'keydown', ctrlKDownProperties), {
selectorName: 'ctrl-k',
beforeValue: 'Ctrl+K not pressed',
afterValue: 'Ctrl+K pressed'
});
});

test('shift+Slash', async function(assert) {
assert.expect(3);

await textChanged(
assert,
() => keyDown('shift+Slash'), {
selectorName: 'question-mark',
beforeValue: 'question mark not pressed',
afterValue: 'question mark pressed'
});
});
});
9 changes: 9 additions & 0 deletions tests/dummy/app/controllers/on-key-examples.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';

export default class extends Controller {
@tracked wasCtrlKPressed = false;
@tracked wasSPressed = false;
@tracked wasSlashPressed = false;
@tracked wasQuestionMarkPressed = false;
}
1 change: 1 addition & 0 deletions tests/dummy/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Router.map(function() {
this.route('touch');
this.route('keyboard');
this.route('deprecated/keyboard-combo');
this.route('on-key-examples');
this.route('element-modifiers');
});

Expand Down
32 changes: 32 additions & 0 deletions tests/dummy/app/templates/test-scenario/on-key-examples.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<span data-test-ctrl-k>
{{if this.wasCtrlKPressed 'Ctrl+K pressed' 'Ctrl+K not pressed'}}
</span>

{{on-key 'ctrl+KeyK' (fn (mut this.wasCtrlKPressed) true)}}

<hr />


<span data-test-s>
{{if this.wasSPressed 'S pressed' 'S not pressed'}}
</span>

{{on-key 'KeyS' (fn (mut this.wasSPressed) true)}}

<hr />


<span data-test-slash>
{{if this.wasSlashPressed 'slash pressed' 'slash not pressed'}}
</span>

{{on-key 'Slash' (fn (mut this.wasSlashPressed) true)}}

<hr />


<span data-test-question-mark>
{{if this.wasQuestionMarkPressed 'question mark pressed' 'question mark not pressed'}}
</span>

{{on-key 'shift+Slash' (fn (mut this.wasQuestionMarkPressed) true)}}
48 changes: 42 additions & 6 deletions tests/dummy/app/templates/usage.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,52 @@
### Using ember-keyboard in templates
To declaratively attach an action to a keyboard event while a particular template is rendered, use the `keyboard-press` component. In this example, when a user presses the '/' key, the onSlash action is triggered.
To declaratively attach an action to a keyboard event while a particular template
is rendered, use the `on-key` helper. In this example, when a user presses the '/'
key, the onSlash action is triggered.
```hbs
{{keyboard-press
key='Slash'
onPress=(action 'onSlash')
}}
{{on-key '/' this.onSlash}}
```
Note that the listener is active for the lifecycle of the template. When the template is unrendered, the listener is removed.
Note that the listener is active for the lifecycle of the helper. When the helper is unrendered, the listener is removed.
Modifiers are supported, too:
```hbs
{{on-key 'alt+c' this.doThing}}
```
By default, actions will be triggered on the `keydown` event. To fire it on
`keyup` or (the deprecated) `keypress`, specify the `event`:
```hbs
{{on-key 'alt+c' this.doThing event='keyup'}}
```
To bind multiple key combos, including to the same action, include the helper multiple times:
```hbs
{{on-key 'alt+c' this.doThing}}
{{on-key 'ctrl+shift+t' this.doThing}}
```
In the examples above, 'c', 't', and '/' are interpreted to mean “the key that
was pressed produces the specified character under normal circumstances.” In
the W3C's specifications for DOM keyboard events, this is known as the `key`
property. There is another property, called `code`, which is based on the
”standard position“ of a key regardless of what remapping may be in place.
Values for `code` look like `KeyC`, `Digit1`, `Backspace`, etc. [You can find a
full list here.](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values)
Values for `code` and `key` don't overlap, so if `ember-keyboard` will
automatically infer which property you care about based on how you specify your
key combo. For example,
```hbs
<!-- Fires DoThing on keydown of the key at the standard position of the C key
while Alt is pressed. This is inferred from the use of `KeyC` rather than `c` -->
{{on-key 'alt+KeyC' this.doThing}}
```
Another option (supported in Ember 3.12+) for templates is the `on-keyboard` element modifier. This allows a keydown event to trigger an action. In the following example, we trigger an action when the input field is focused and the user presses enter:
Expand Down
Loading

0 comments on commit d16ef3e

Please sign in to comment.