New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

phosphor-keymap

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

phosphor-keymap - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

lib/manager.d.ts

130

lib/index.d.ts

@@ -1,128 +0,2 @@

import { IDisposable } from 'phosphor-disposable';
/**
* An object which represents a key binding.
*/
export interface IKeyBinding {
/**
* The key sequence for the key binding.
*
* Each keystroke must adhere to the following format:
*
* `[<modifier-1>+[<modifier-2>+[<modifier-n>+]]]<key>`
*
* - Supported modifiers are `'ctrl'`, `'alt'`, `'shift'`, `'cmd'`.
* - The `'cmd'` modifier only works on OSX (browser limitation).
* - The modifiers may appear in any order.
* - The modifiers cannot appear in duplicate.
* - The primary key must be a valid key character.
* - The keystroke is case insensitive.
* - Mutliple keystrokes are separated by whitespace.
*
* #### Example
* **Valid Key Sequences**
* ``` typescript
* 'a'
* 'b'
* 'd d'
* 'ctrl+-'
* 'ctrl+='
* 'ctrl+alt+5'
* 'shift+f11'
* 'ctrl+k ctrl+t'
* 'alt+cmd+y ctrl+4 alt+]'
* ```
*
* **Invalid Key Sequences**
* ```typescript
* '%'
* '$'
* 'ctrl-a'
* '+ctrl+a'
* 'shift++o'
* 'ctrl+a shift'
* ```
*/
sequence: string;
/**
* The handler function to invoke when the key sequence is matched.
*
* The handler should return `true` to prevent the default and stop
* propagation of the key event. It should return `false` to allow
* the continued processing of the event.
*/
handler: () => boolean;
}
/**
* A class which manages a collection of key bindings.
*/
export declare class KeymapManager {
/**
* Construct a new key map.
*/
contstructor(): void;
/**
* Add key bindings to the key map.
*
* @param selector - The CSS selector for the key bindings.
*
* @param bindings - The key bindings to add to the key map.
*
* @returns A disposable which will remove the key bindings.
*
* #### Notes
* If the selector is an invalid CSS selector, a warning will
* be logged to the console and `undefined` will be returned.
*
* If the key sequence for a binding is invalid, or if a binding
* has a null handler, a warning will be logged to the console
* and that binding will be ignored.
*/
add(selector: string, bindings: IKeyBinding[]): IDisposable;
/**
* Process a `'keydown'` event and invoke the matching key bindings.
*
* @param event - The event object for a `'keydown'` event.
*
* #### Notes
* This should be called by user code in response to a `'keydown'`
* event. The keymap **does not** install its own event listeners,
* which allows user code full control over the nodes for which
* the keymap processes events.
*/
processKeydownEvent(event: KeyboardEvent): void;
/**
* Remove an array of ex key bindings from the key map.
*/
private _removeBindings(arr);
/**
* Start or restart the pending timer for the key map.
*/
private _startTimer();
/**
* Clear the pending timer for the key map.
*/
private _clearTimer();
/**
* Clear the pending state for the keymap.
*/
private _clearPendingState();
/**
* Set the pending exact match data.
*/
private _setExactData(exact, event);
/**
* Handle the partial timer timeout.
*
* This will reset the pending state and dispatch the exact matches.
*/
private _onPendingTimeout();
private _timer;
private _partialTimeout;
private _keystrokes;
private _bindings;
private _exactData;
}
/**
* Test whether an element matches a CSS selector.
*/
export declare function matchesSelector(elem: Element, selector: string): boolean;
export * from './keycodes';
export * from './manager';

@@ -9,335 +9,7 @@ /*-----------------------------------------------------------------------------

'use strict';
var clear_cut_1 = require('clear-cut');
var phosphor_disposable_1 = require('phosphor-disposable');
var keycodes_1 = require('./keycodes');
/**
* A class which manages a collection of key bindings.
*/
var KeymapManager = (function () {
function KeymapManager() {
this._timer = 0;
this._partialTimeout = 1000;
this._keystrokes = [];
this._bindings = [];
this._exactData = null;
}
/**
* Construct a new key map.
*/
KeymapManager.prototype.contstructor = function () { };
/**
* Add key bindings to the key map.
*
* @param selector - The CSS selector for the key bindings.
*
* @param bindings - The key bindings to add to the key map.
*
* @returns A disposable which will remove the key bindings.
*
* #### Notes
* If the selector is an invalid CSS selector, a warning will
* be logged to the console and `undefined` will be returned.
*
* If the key sequence for a binding is invalid, or if a binding
* has a null handler, a warning will be logged to the console
* and that binding will be ignored.
*/
KeymapManager.prototype.add = function (selector, bindings) {
var _this = this;
// Log a warning and bail if the selector is invalid.
if (!clear_cut_1.isSelectorValid(selector)) {
console.warn("Invalid key binding selector: " + selector);
return void 0;
}
// The newly created ex bindings for the valid key bindings.
var newBindings = [];
// Iterate over the bindings and covert them into ex bindings.
for (var i = 0, n = bindings.length; i < n; ++i) {
var binding = bindings[i];
// If the binding does not have a handler, warn and continue.
if (!binding.handler) {
console.warn("null handler for key binding: " + binding.sequence);
continue;
}
// Trim the key sequence and split into individual keystrokes.
var keystrokes = binding.sequence.trim().split(/\s+/);
// Normalize each keystroke and re-join into a canoncial form.
// If any of the keystrokes are invalid, warn and continue.
try {
var sequence = keystrokes.map(keycodes_1.normalizeKeystroke).join(' ');
}
catch (e) {
console.warn("invalid key binding sequence: " + binding.sequence);
continue;
}
// Create a new extended binding and add it to the arrays.
var exb = new ExBinding(selector, sequence, binding.handler);
this._bindings.push(exb);
newBindings.push(exb);
}
// Return a disposable which will remove the new bindings.
return new phosphor_disposable_1.DisposableDelegate(function () { return _this._removeBindings(newBindings); });
};
/**
* Process a `'keydown'` event and invoke the matching key bindings.
*
* @param event - The event object for a `'keydown'` event.
*
* #### Notes
* This should be called by user code in response to a `'keydown'`
* event. The keymap **does not** install its own event listeners,
* which allows user code full control over the nodes for which
* the keymap processes events.
*/
KeymapManager.prototype.processKeydownEvent = function (event) {
// If the actual pressed key is a modifier key, prevent the default
// and return. No bindings can be matched for *just* modifier keys.
if (keycodes_1.isModifierKeyCode(event.keyCode)) {
event.preventDefault();
return;
}
// Get the normalized keystroke and store it as a pending.
this._keystrokes.push(keycodes_1.keystrokeForKeydownEvent(event));
// Convert the pending keystrokes to a sequence.
var sequence = this._keystrokes.join(' ');
// Find the exact and partial matches for the key sequence.
var matches = findSequenceMatches(this._bindings, sequence);
// If there are no exact match and not partial matches, clear
// all pending state so the next key press starts from default.
if (matches.exact.length === 0 && matches.partial.length === 0) {
this._clearPendingState();
return;
}
// If there are exact matches but no partial matches, the exact
// matches can be dispatched immediately. The pending state is
// reset so the next key press starts from default.
if (matches.partial.length === 0) {
this._clearPendingState();
dispatchBindings(matches.exact, event);
return;
}
// At this point, there are partial matches.
// If there are exact matches and partial matches, the exact
// matches are stored so they can be dispatched if the timer
// expires before a more specific match is found.
if (matches.exact.length > 0) {
this._setExactData(matches.exact, event);
}
// Restart the timer for equal intervals between keystrokes.
//
// TODO - we may want to replay prevented defaults if match fails.
// - we may also want to stop propagation until match fails.
event.preventDefault();
this._startTimer();
};
/**
* Remove an array of ex key bindings from the key map.
*/
KeymapManager.prototype._removeBindings = function (arr) {
this._bindings = this._bindings.filter(function (b) { return arr.indexOf(b) === -1; });
};
/**
* Start or restart the pending timer for the key map.
*/
KeymapManager.prototype._startTimer = function () {
var _this = this;
this._clearTimer();
this._timer = setTimeout(function () {
_this._onPendingTimeout();
}, this._partialTimeout);
};
/**
* Clear the pending timer for the key map.
*/
KeymapManager.prototype._clearTimer = function () {
if (this._timer !== 0) {
clearTimeout(this._timer);
this._timer = 0;
}
};
/**
* Clear the pending state for the keymap.
*/
KeymapManager.prototype._clearPendingState = function () {
this._clearTimer();
this._exactData = null;
this._keystrokes.length = 0;
};
/**
* Set the pending exact match data.
*/
KeymapManager.prototype._setExactData = function (exact, event) {
if (!this._exactData) {
this._exactData = { exact: exact, event: event };
}
else {
this._exactData.exact = exact;
this._exactData.event = event;
}
};
/**
* Handle the partial timer timeout.
*
* This will reset the pending state and dispatch the exact matches.
*/
KeymapManager.prototype._onPendingTimeout = function () {
this._timer = 0;
var d = this._exactData;
this._clearPendingState();
if (d)
dispatchBindings(d.exact, d.event);
};
return KeymapManager;
})();
exports.KeymapManager = KeymapManager;
/**
* An extended key bind object used by a keymap manager.
*/
var ExBinding = (function () {
/**
* Construct a new extended key binding.
*
* @param selector - The valid CSS selector for the binding.
*
* @param sequence - The normalized key binding sequence.
*
* @param handler - The handler function for the binding.
*/
function ExBinding(selector, sequence, handler) {
this._id = ExBinding.idTick++;
this._selector = selector;
this._sequence = sequence;
this._handler = handler;
this._specificity = clear_cut_1.calculateSpecificity(selector);
}
/**
* A comparison function for extended bindings.
*
* This can be used to sort an array of bindings according to
* highest CSS specificity. Ties are broken according to the
* binding id, with newer bindings appearing first.
*/
ExBinding.compare = function (exA, exB) {
if (exA._specificity === exB._specificity) {
return exB._id - exA._id;
}
return exB._specificity - exA._specificity;
};
/**
* Create a public key binding object for this extended binding.
*/
ExBinding.prototype.toBinding = function () {
return { sequence: this._sequence, handler: this._handler };
};
/**
* Test whether the binding is an exact match for a key sequence.
*/
ExBinding.prototype.isExactMatch = function (sequence) {
return this._sequence === sequence;
};
/**
* Test whether the binding is a partial match for a key sequence.
*/
ExBinding.prototype.isPartialMatch = function (sequence) {
return this._sequence.indexOf(sequence) === 0;
};
/**
* Test whether the binding selector matches an element.
*/
ExBinding.prototype.isSelectorMatch = function (target) {
return matchesSelector(target, this._selector);
};
/**
* Invoke the handler for the binding and return its result.
*/
ExBinding.prototype.invoke = function () {
return this._handler.call(void 0);
};
/**
* A monotonically increasing binding identifier.
*
* The binding id is used to break sorting ties.
*/
ExBinding.idTick = 0;
return ExBinding;
})();
/**
* Filter the bindings for those which match the given sequence.
*
* The result contains both exact matches and partial matches.
*/
function findSequenceMatches(bindings, sequence) {
var exact = [];
var partial = [];
var partialSequence = sequence + ' ';
for (var i = 0, n = bindings.length; i < n; ++i) {
var exb = bindings[i];
if (exb.isExactMatch(sequence)) {
exact.push(exb);
}
else if (exb.isPartialMatch(partialSequence)) {
partial.push(exb);
}
}
return { exact: exact, partial: partial };
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
/**
* Filter the bindings for those with a matching selector.
*/
function findSelectorMatches(bindings, target) {
var matches = bindings.filter(function (exb) { return exb.isSelectorMatch(target); });
return matches.sort(ExBinding.compare);
}
/**
* Dispatch the key bindings for the given keyboard event.
*
* As the dispatcher walks up the DOM, the bindings will be filtered
* for matching selectors, and invoked in specificity order. If the
* handler for a binding returns `true`, dispatch will terminate and
* the event propagation will be stopped.
*/
function dispatchBindings(bindings, event) {
var target = event.target;
var current = event.currentTarget;
while (target) {
var matches = findSelectorMatches(bindings, target);
for (var i = 0, n = matches.length; i < n; ++i) {
if (matches[i].invoke()) {
event.preventDefault();
event.stopPropagation();
return;
}
}
if (target === current) {
return;
}
target = target.parentElement;
}
}
/**
* Test whether an element matches a CSS selector.
*/
function matchesSelector(elem, selector) {
return protoMatchFunc.call(elem, selector);
}
exports.matchesSelector = matchesSelector;
/**
* A cross-browser CSS selector matching prototype function.
*
* The function must be called with the element as `this`.
*/
var protoMatchFunc = (function () {
var proto = Element.prototype;
return (proto.matches ||
proto.matchesSelector ||
proto.mozMatchesSelector ||
proto.msMatchesSelector ||
proto.oMatchesSelector ||
proto.webkitMatchesSelector ||
(function (selector) {
var elem = this;
var matches = elem.ownerDocument.querySelectorAll(selector);
return Array.prototype.indexOf.call(matches, elem) !== -1;
}));
})();
__export(require('./keycodes'));
__export(require('./manager'));
//# sourceMappingURL=index.js.map

@@ -29,2 +29,4 @@ /**

*
* @throws An error if the keystroke has an invalid format.
*
* #### Notes

@@ -31,0 +33,0 @@ * The keystroke must adhere to the following format:

@@ -59,2 +59,4 @@ /*-----------------------------------------------------------------------------

*
* @throws An error if the keystroke has an invalid format.
*
* #### Notes

@@ -85,14 +87,6 @@ * The keystroke must adhere to the following format:

if (token === '+') {
if (key) {
if (sep || key || !(alt || cmd || ctrl || shift)) {
throwKeystrokeError(keystroke);
}
else if ((i === n - 1) && (n === 1 || sep)) {
key = token;
}
else if (!sep && (alt || cmd || ctrl || shift)) {
sep = true;
}
else {
throwKeystrokeError(keystroke);
}
sep = true;
}

@@ -99,0 +93,0 @@ else if (token === 'alt') {

{
"name": "phosphor-keymap",
"version": "0.1.0",
"version": "0.2.0",
"description": "A module for keyboard shortcut mapping.",

@@ -9,3 +9,3 @@ "main": "lib/index.js",

"clear-cut": "^2.0.1",
"phosphor-disposable": "^1.0.3"
"phosphor-disposable": "^1.0.4"
},

@@ -28,4 +28,4 @@ "devDependencies": {

"rimraf": "^2.4.2",
"typedoc": "git://github.com/phosphorjs/typedoc.git",
"typescript": "1.6.0-beta"
"typedoc": "^0.3.11",
"typescript": "^1.6.2"
},

@@ -55,3 +55,5 @@ "scripts": {

"lib/keycodes.js",
"lib/keycodes.d.ts"
"lib/keycodes.d.ts",
"lib/manager.js",
"lib/manager.d.ts"
],

@@ -58,0 +60,0 @@ "keywords": [

@@ -0,0 +0,0 @@ phosphor-keymap

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc