UNPKG

vue-three-shortkey

Version:

A plugin for VueJS 3.x accepts shortcuts globally and in a single listener.

470 lines (370 loc) 15.4 kB
import './Pollyfills' import find from 'array.prototype.find' import {expect} from 'chai' import {createApp, nextTick} from 'vue' import Shortkey from '../src/index.js' find.shim() const VM = template => createApp({ template, data() { return { called: false, calledBubble: false } }, methods: { foo() { this.called = true }, bar() { this.calledBubble = true } } }).use(Shortkey, { prevent: ['.disableshortkey', '.disableshortkey textarea'] }) function createEvent(name='keydown') { const event = document.createEvent('HTMLEvents') event.initEvent(name, false, true) return event } describe('Index.js', () => { describe('fn.decodeKey', () => { it('Return single key', () => { expect(Shortkey.decodeKey({key: 'Shift'})).to.equal('shift') expect(Shortkey.decodeKey({key: 'Control'})).to.equal('ctrl') expect(Shortkey.decodeKey({key: 'Meta'})).to.equal('meta') expect(Shortkey.decodeKey({key: 'Alt'})).to.equal('alt') expect(Shortkey.decodeKey({key: 'ArrowUp'})).to.equal('arrowup') expect(Shortkey.decodeKey({key: 'ArrowLeft'})).to.equal('arrowleft') expect(Shortkey.decodeKey({key: 'ArrowRight'})).to.equal('arrowright') expect(Shortkey.decodeKey({key: 'ArrowDown'})).to.equal('arrowdown') expect(Shortkey.decodeKey({key: 'AltGraph'})).to.equal('altgraph') expect(Shortkey.decodeKey({key: 'Escape'})).to.equal('esc') expect(Shortkey.decodeKey({key: 'Enter'})).to.equal('enter') expect(Shortkey.decodeKey({key: 'Tab'})).to.equal('tab') expect(Shortkey.decodeKey({key: ' '})).to.equal('space') expect(Shortkey.decodeKey({key: 'PageUp'})).to.equal('pageup') expect(Shortkey.decodeKey({key: 'PageDown'})).to.equal('pagedown') expect(Shortkey.decodeKey({key: 'Home'})).to.equal('home') expect(Shortkey.decodeKey({key: 'End'})).to.equal('end') expect(Shortkey.decodeKey({key: 'Delete'})).to.equal('del') expect(Shortkey.decodeKey({key: 'Backspace'})).to.equal('backspace') expect(Shortkey.decodeKey({key: 'Insert'})).to.equal('insert') expect(Shortkey.decodeKey({key: 'NumLock'})).to.equal('numlock') expect(Shortkey.decodeKey({key: 'CapsLock'})).to.equal('capslock') expect(Shortkey.decodeKey({key: 'Pause'})).to.equal('pause') expect(Shortkey.decodeKey({key: 'ContextMenu'})).to.equal('contextmenu') expect(Shortkey.decodeKey({key: 'ScrollLock'})).to.equal('scrolllock') expect(Shortkey.decodeKey({key: 'BrowserHome'})).to.equal('browserhome') expect(Shortkey.decodeKey({key: 'MediaSelect'})).to.equal('mediaselect') }) it('Return a combined key', () => { expect(Shortkey.decodeKey({altKey: true, key: 'a'})).to.equal('alta') expect(Shortkey.decodeKey({altKey: true, ctrlKey: true, key: 'a'})).to.equal('ctrlalta') }) }) }) describe('functionnal tests', () => { const createDiv = () => { const div = document.createElement('div') document.body.appendChild(div) return div } describe('Dispatch triggered event', () => { it('listen for keydown and dispatch simple event', () => { const vm = new VM('<div @shortkey="foo" v-shortkey="[\'q\']"></div>') const root = vm.mount(createDiv()) const keydown = createEvent('keydown') keydown.key = 'q' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'q' document.dispatchEvent(keyup) expect(root.called).to.be.true vm.unmount() }) it('unbind simple events', () => { const vm = new VM('<div @shortkey="foo" v-shortkey="[\'q\']"></div>') const root = vm.mount(createDiv()) vm.unmount() const keydown = createEvent('keydown') keydown.key = 'q' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'q' document.dispatchEvent(keyup) expect(root.called).to.be.false }); it('listen for keydown and dispatch event with object key', (done) => { const vm = new VM('<div @shortkey="foo" v-shortkey="{option1: [\'q\'], option2: [\'a\']}"></div>') const stubFoo = sinon.stub(vm._component.methods, 'foo').callsFake(fn => { expect(fn.srcKey).to.equal('option1') stubFoo.restore() vm.unmount() done() }) const root = vm.mount(createDiv()) const keydown = createEvent('keydown') keydown.key = 'q' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'q' document.dispatchEvent(keyup) expect(root.called).to.be.true }) it('unbind event with object key', () => { const vm = new VM('<div @shortkey="foo" v-shortkey="{option1: [\'q\'], option2: [\'a\']}"></div>') const root = vm.mount(createDiv()) vm.unmount() const keydown = createEvent('keydown') keydown.key = 'q' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'q' document.dispatchEvent(keyup) expect(root.called).to.be.false }) }) describe('Don`t dispatch triggered event', () => { it('dont trigger listen for keydown and dispatch event', () => { const vm = new VM('<div @shortkey="foo" v-shortkey="[\'b\']"><textarea v-shortkey.avoid></textarea></div>') const root = vm.mount(createDiv()) const textarea = root.$el.querySelector('textarea') textarea.focus() expect(document.activeElement == textarea).to.be.true const keydown = createEvent('keydown') keydown.key = 'b' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'b' document.dispatchEvent(keyup) expect(root.called).to.be.false vm.unmount() }) it('does not trigger events when its class is in the prevent list', () => { const vm = new VM('<div @shortkey="foo" v-shortkey="[\'b\']"><textarea class="disableshortkey"></textarea></div>') const root = vm.mount(createDiv()) const textarea = root.$el.querySelector('textarea') textarea.focus() expect(document.activeElement == textarea).to.be.true const keydown = createEvent('keydown') keydown.key = 'b' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'b' document.dispatchEvent(keyup) expect(root.called).to.be.false vm.unmount() }) it('does not trigger events when one of its classes is in the prevent list', () => { const vm = new VM('<div @shortkey="foo" v-shortkey="[\'b\']"><textarea class="disableshortkey stylingclass"></textarea></div>') const root = vm.mount(createDiv()) const textarea = root.$el.querySelector('textarea') textarea.focus() expect(document.activeElement == textarea).to.be.true const keydown = createEvent('keydown') keydown.key = 'b' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'b' document.dispatchEvent(keyup) expect(root.called).to.be.false vm.unmount() }) it('does not trigger events when it gets matched by one item in the prevent list', () => { const vm = new VM('<div @shortkey="foo" v-shortkey="[\'b\']" class="disableshortkey"><textarea class="stylingclass"></textarea></div>') const root = vm.mount(createDiv()) const textarea = root.$el.querySelector('textarea') textarea.focus() expect(document.activeElement == textarea).to.be.true const keydown = createEvent('keydown') keydown.key = 'b' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'b' document.dispatchEvent(keyup) expect(root.called).to.be.false vm.unmount() }) it('does trigger events when only the parent element gets matched by one item in the prevent list', () => { const vm = new VM('<div @shortkey="foo" v-shortkey="[\'b\']" class="disableshortkey"><input type="text" /></div>') const root = vm.mount(createDiv()) const input = root.$el.querySelector('input') input.focus() expect(document.activeElement == input).to.be.true const keydown = createEvent('keydown') keydown.key = 'b' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'b' document.dispatchEvent(keyup) expect(root.called).to.be.true vm.unmount() }) it('listen for keydown and dispatch event with object key', () => { const vm = new VM('<div @shortkey="foo" v-shortkey="{option1: [\'q\'], option2: [\'a\']}"><textarea v-shortkey.avoid></textarea></div>') const root = vm.mount(createDiv()) const textarea = root.$el.querySelector('textarea') textarea.focus() expect(document.activeElement == textarea).to.be.true const keydown = createEvent('keydown') keydown.key = 'q' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'q' document.dispatchEvent(keyup) expect(root.called).to.be.false vm.unmount() }) }) describe('Dispatch triggered event', () => { it('trigger listen for keydown and propagte event to all listeners when modifier is present', () => { const vm = new VM(`<div> <button type="button" class="foo" @shortkey="foo" v-shortkey.propagte="[\'c\']">FOO</button> <button type="button" class="bar" @shortkey="bar" v-shortkey.propagte="[\'c\']">BAR</button> </div>`) const root = vm.mount(createDiv()) const buttonFoo = root.$el.querySelector('button.foo') buttonFoo.focus() expect(document.activeElement == buttonFoo).to.be.true const keydown = createEvent('keydown') keydown.key = 'c' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'c' document.dispatchEvent(keyup) expect(root.called).to.be.true //expect(root.calledBubble).to.be.true vm.unmount() }) it('trigger listen for keydown and propagte event to all listeners when modifier is present on the first element', () => { const vm = new VM(`<div> <button type="button" class="foo" @shortkey="foo" v-shortkey.propagte="[\'c\']">FOO</button> <button type="button" class="bar" @shortkey="bar" v-shortkey="[\'c\']">BAR</button> </div>`) const root = vm.mount(createDiv()) const buttonFoo = root.$el.querySelector('button.foo') buttonFoo.focus() expect(document.activeElement == buttonFoo).to.be.true const keydown = createEvent('keydown') keydown.key = 'c' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'c' document.dispatchEvent(keyup) expect(root.called).to.be.true //expect(root.calledBubble).to.be.true vm.unmount() }) it('trigger listen for keydown and propagte event to all listeners when modifier is present on the last element', () => { const vm = new VM(`<div> <button type="button" class="foo" @shortkey="foo" v-shortkey="[\'c\']">FOO</button> <button type="button" class="bar" @shortkey="bar" v-shortkey.propagte="[\'c\']">BAR</button> </div>`) const root = vm.mount(createDiv()) const buttonFoo = root.$el.querySelector('button.foo') buttonFoo.focus() expect(document.activeElement == buttonFoo).to.be.true const keydown = createEvent('keydown') keydown.key = 'c' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'c' document.dispatchEvent(keyup) expect(root.called).to.be.true //expect(root.calledBubble).to.be.true vm.unmount() }) }) it('Setting focus with .focus modifier', () => { const vm = new VM(`<div><input type="text" /> <button type="button" v-shortkey.focus="['f']">BUTTON</button></div>`) const root = vm.mount(createDiv()) const inputText = root.$el.querySelector('input') inputText.focus() expect(document.activeElement == inputText).to.be.true const keydown = createEvent('keydown') keydown.key = 'f' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'f' document.dispatchEvent(keyup) const buttonInput = root.$el.querySelector('button') expect(document.activeElement == buttonInput).to.be.true vm.unmount() }) it('Bring push button with .push modifier', () => { const vm = new VM(`<div><button type="button" v-shortkey.push="['p']" @shortkey="foo()">BUTTON</button></div>`) const root = vm.mount(createDiv()) const spyFoo = sinon.spy(root, 'foo') const keydown = createEvent('keydown') keydown.key = 'p' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'p' document.dispatchEvent(keyup) expect(spyFoo.callCount).to.equal(2) spyFoo.restore() vm.unmount() }) it('Testing delete key', () => { const vm = new VM(`<button @shortkey="foo" v-shortkey="['del']"></button>`) const root = vm.mount(createDiv()) const keydown = createEvent('keydown') keydown.key = 'Delete' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keyup.key = 'Delete' document.dispatchEvent(keyup) expect(root.called).to.be.true vm.unmount() }) it('Testing ? key', () => { const vm = new VM(`<button @shortkey="foo" v-shortkey="['shift', '?']"></button>`) const root = vm.mount(createDiv()) const keydown = createEvent('keydown') keydown.shiftKey = true keydown.key = '?' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keydown.shiftKey = true keydown.key = '?' document.dispatchEvent(keyup) expect(root.called).to.be.true vm.unmount() }) it("Update the binding", (done) => { const vm = VM(`<div> <div v-if="!called" class="first" @shortkey="foo" v-shortkey="[\'q\']">foo</div> <div v-else class="test" @shortkey="bar" v-shortkey="[\'g\']">bar</div> </div>`) const root = vm.mount(createDiv()) const keydown = createEvent('keydown') keydown.key = 'q' document.dispatchEvent(keydown) const keyup = createEvent('keyup') keydown.key = 'q' document.dispatchEvent(keyup) expect(root.called).to.be.true nextTick(() => { const keydown2 = createEvent('keydown') keydown2.key = 'g' document.dispatchEvent(keydown2) const keyup2 = createEvent('keyup') keydown2.key = 'g' document.dispatchEvent(keyup2) expect(root.calledBubble).to.be.true vm.unmount() done() }) }) it('Prevent bubble event', () => { const vm = new VM('<div @shortkey="bar" v-shortkey="[\'a\']"><button type="button" @shortkey="foo" v-shortkey="[\'b\']">TEST</button></div>') const root = vm.mount(createDiv()) const textarea = root.$el.querySelector('button') const keydown = createEvent('keydown') keydown.key = 'b' document.dispatchEvent(keydown) expect(root.called).to.be.true expect(root.calledBubble).to.be.false vm.unmount() }) })