Skip to content

Commit

Permalink
Merge pull request #5 from alexjoverm/master
Browse files Browse the repository at this point in the history
Several improvements
  • Loading branch information
alexjoverm authored Jan 30, 2017
2 parents ce34797 + 430926e commit d8778cb
Show file tree
Hide file tree
Showing 23 changed files with 821 additions and 414 deletions.
5 changes: 1 addition & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ language: node_js
branches:
only:
- master
cache:
directories:
- node_modules
notifications:
email: false
node_js:
- '7'
- '6'
before_script:
- npm prune && npm cache clean
script:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ShortcutJS
[![npm](https://img.shields.io/npm/v/shortcutjs.svg)](https://www.npmjs.com/package/shortcutjs)
[![Travis](https://img.shields.io/travis/coosto/ShortcutJS.svg)]()
[![Coveralls](https://img.shields.io/coveralls/coosto/ShortcutJS.svg)]()
[![Coverage Status](https://coveralls.io/repos/github/coosto/ShortcutJS/badge.svg?branch=master)](https://coveralls.io/github/coosto/ShortcutJS?branch=master)
[![npm](https://img.shields.io/npm/dt/shortcutjs.svg)](https://www.npmjs.com/package/shortcutjs)
[![David](https://img.shields.io/david/coosto/ShortcutJS.svg)]()
[![David](https://img.shields.io/david/dev/coosto/ShortcutJS.svg)]()
Expand Down
21 changes: 14 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
"lint": "tslint -e node_modules/** **/*.ts ",
"commit": "git-cz",
"test": "jest",
"test:prod": "npm run lint && npm run test -- --coverage --no-cache",
"report-coverage" : "npm run test -- --coverage --no-cache && cat ./coverage/lcov.info | coveralls",
"test:watch": "jest --watch",
"test:prod": "npm run lint && npm run test -- -i --coverage --no-cache",
"report-coverage": "npm run test -- --coverage --no-cache && cat ./coverage/lcov.info | coveralls",
"prebuild": "rimraf dist",
"build": "webpack",
"build": "cross-env NODE_ENV=production webpack",
"build:dev": "webpack",
"semantic-release": "semantic-release pre && npm publish && semantic-release post"
},
"files": [
Expand Down Expand Up @@ -52,6 +54,7 @@
"babel-preset-es2015": "^6.22.0",
"commitizen": "^2.9.5",
"coveralls": "^2.11.15",
"cross-env": "^3.1.4",
"cz-conventional-changelog": "^1.2.0",
"ghooks": "^2.0.0",
"jest": "^18.1.0",
Expand Down Expand Up @@ -80,12 +83,16 @@
"/^((?!src).)/"
],
"testResultsProcessor": "<rootDir>/node_modules/ts-jest/coverageprocessor.js",
"coveragePathIgnorePatterns": [
"/node_modules/",
"/test/"
],
"coverageThreshold": {
"global": {
"branches": 80,
"functions": 90,
"lines": 90,
"statements": 90
"branches": 90,
"functions": 95,
"lines": 95,
"statements": 95
}
}
}
Expand Down
88 changes: 88 additions & 0 deletions src/event-processor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { Action } from './action'
import { KeyCombo } from './key-combo'
import { logger, compareSets } from './utils'

export class EventProcessor {
public currentCombo: KeyCombo
public lastEvent: KeyboardEvent

constructor () {
this.currentCombo = new KeyCombo()
}

public reset () {
this.currentCombo = new KeyCombo()
}

public processEvent (ev: KeyboardEvent, actions: Map<string, Action>, debug: boolean) {
const wasAppended = this.currentCombo.addEvent(ev)

// Avoid repeated events
if (!wasAppended) {
return false
}

if (debug) {
this.printDebugKeyPressed(ev)
}

if (wasAppended) {
this.processActionCombos(ev, actions, debug)
}
}

public cleanCombo (debug) {
this.reset()

if (debug) {
logger.log('ShortcutJS: Cleaned keyMap')
}
}

/**
* Search for the right action, given a keyCombo, and execute its callbacks
*/
public processActionCombos (ev: KeyboardEvent, actions: Map<string, Action>, debug: boolean) {
for (let action of actions.values()) {
if (this.matchesComboAction(action)) {
if (debug) {
this.printDebugActionFound(action)
}

for (let cb of action.callbacks) {
cb(ev)
}
// Don't continue after finding it
return false
}
}
}

/**
* Checks whether the que matches a particular action
*/
private matchesComboAction (action: Action) {
return KeyCombo.isEqual(this.currentCombo, action.keyCombo)
}

private printDebugKeyPressed (ev: KeyboardEvent) {
logger.group('ShortcutJS: KeyPressed')
logger.log('Key: ', ev.keyCode)
logger.group('Current combo:')
logger.log('Keys: ', [...this.currentCombo.keys])
logger.log('State keys: ', this.currentCombo.stateKeys)
logger.groupEnd()
logger.groupEnd()
}

private printDebugActionFound (action: Action) {
logger.group('%cShortcutJS: Action Matched', 'color: green')
logger.log('Action: ', action.name)
logger.group('Current combo:')
logger.log('Keys: ', [...this.currentCombo.keys])
logger.log('State keys: ', this.currentCombo.stateKeys)
logger.groupEnd()
logger.log(`${action.callbacks.size} callbacks found`)
logger.groupEnd()
}
}
123 changes: 20 additions & 103 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,14 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
import { IOptions, Options } from './options'

import { keyContainer } from './key-container'
import { Action } from './action'
import { EventProcessor } from './event-processor'
import { JsonParser } from './json-parser'
import { KeyCombo } from './key-combo'
import { Action } from './action'

interface Logger extends Console {
group(title: string, options?: string)
}

const logger = console as Logger
import { keyContainer } from './key-container'

/**
* First Version of a ShortcutJS.
Expand All @@ -42,61 +39,50 @@ const logger = console as Logger
*/
export class ShortcutJS {
public actions: Map<string, Action>
public keyMap: Map<number, boolean>
public options: any
public options: Options
public eventProcessor: EventProcessor
private initialized: boolean

// ********* PRIVATE API (only internal use) **********
/**
* Private constructor
*
* @memberOf ShortcutJS
*/
constructor () {
// With Maps we avoid events duplication, achieve immutability and performance
this.actions = new Map()
this.keyMap = new Map()
this.initialized = false
this.options = {
debug: false
}
this.eventProcessor = new EventProcessor()
}

public init (options = {}) {
public init (options: IOptions = null) {
if (!this.initialized) {
// @todo do some checking here
this.options = Object.assign({}, this.options, options)
this.options = new Options(options)

window.addEventListener('keydown', this.processEvent.bind(this))
window.addEventListener('keyup', this.removeAllKeys.bind(this))
window.addEventListener('keyup', this.cleanCombo.bind(this))

this.initialized = true
}
}

public reset () {
this.keyMap = new Map()
this.actions = new Map()
this.eventProcessor.reset()
this.initialized = false

window.removeEventListener('keydown', this.processEvent)
window.removeEventListener('keyup', this.removeAllKeys)
window.removeEventListener('keyup', this.cleanCombo)
}

public loadFromJson(json, options = null) {
public loadFromJson(json, options: IOptions = null) {
this.init(options)
JsonParser.parse(this, json)
}

public addAction (action) {
public addAction (action: Action) {
if (!(action instanceof Action)) {
throw new Error('You must pass an Action instance object')
}

this.actions.set(action.name, action)
}

public subscribe (actionName, cb) {
public subscribe (actionName: string, cb: Function) {
if (this.actions.has(actionName)) {
const action = this.actions.get(actionName)
action.addCallback(cb)
Expand All @@ -105,7 +91,7 @@ export class ShortcutJS {
}
}

public unsubscribe (actionName, cb = null) {
public unsubscribe (actionName: string, cb: Function = null) {
if (this.actions.has(actionName)) {
const action = this.actions.get(actionName)
action.removeCallback(cb)
Expand All @@ -114,81 +100,12 @@ export class ShortcutJS {
}
}

public processEvent (ev) {
const wasAppended = this.addEventToMap(ev)

if (this.options.debug) {
this.printDebugKeyPressed(ev)
}

if (wasAppended) {
this.processActionCombos(ev)
}
}

/**
* Cleans the event Queue
*/
public removeAllKeys (ev) {
this.keyMap.clear()
if (this.options.debug) {
logger.log('ShortcutJS: Cleaned keyMap')
}
}

/**
* Search for the right action, given a keyCombo, and execute its callbacks
*/
public processActionCombos (ev) {
for (let action of this.actions.values()) {
if (this.isQueueInAction(action)) {
if (this.options.debug) {
this.printDebugActionFound(action)
}

for (let cb of action.callbacks) {
cb(ev)
}
// Don't continue after finding it
return false
}
}
}

private addEventToMap (ev) {
if (this.keyMap.has(ev.keyCode)) {
return false
} else {
this.keyMap.set(ev.keyCode, true)
return true
}
}

/**
* Checks whether the que matches a particular action
* @todo Performance improvement
* - Idea 1: Using binary operators for comparison
* - Idea 2: Generating uuid's per KeyCombo
* @param {any} action
*/
private isQueueInAction (action) {
const diff = new Set([...action.keyCombo.keys.keys()].filter(key => !this.keyMap.has(key)))
return !diff.size // return boolean from size
}

private printDebugKeyPressed (ev: KeyboardEvent) {
logger.group('ShortcutJS: KeyPressed')
logger.log('Key: ', ev.keyCode)
logger.log('Current keyMap: ', [...this.keyMap.keys()])
logger.groupEnd()
public processEvent (ev: KeyboardEvent) {
this.eventProcessor.processEvent(ev, this.actions, this.options.debug)
}

private printDebugActionFound (action: Action) {
logger.group('%cShortcutJS: Action Matched', 'color: green')
logger.log('Action: ', action.name)
logger.log('Current keyMap: ', [...this.keyMap.keys()])
logger.log(`${action.callbacks.size} callbacks found`)
logger.groupEnd()
public cleanCombo () {
this.eventProcessor.cleanCombo(this.options.debug)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/json-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export class JsonParser {

json.forEach(obj => {
const jsonActionCombo = new JsonActionCombo(obj)
const keyCombo = new KeyCombo(jsonActionCombo.combo)
const keyCombo = KeyCombo.fromString(jsonActionCombo.combo)
const action = new Action(jsonActionCombo.action, keyCombo)
shortcutJS.addAction(action)
})
Expand Down
Loading

0 comments on commit d8778cb

Please sign in to comment.