UNPKG

@dcloudio/uni-debugger

Version:

uni-app debugger

248 lines (221 loc) 7.31 kB
// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. /** * @unrestricted */ UI.ShortcutRegistry = class { /** * @param {!UI.ActionRegistry} actionRegistry * @param {!Document} document */ constructor(actionRegistry, document) { this._actionRegistry = actionRegistry; /** @type {!Multimap.<string, string>} */ this._defaultKeyToActions = new Multimap(); /** @type {!Multimap.<string, !UI.KeyboardShortcut.Descriptor>} */ this._defaultActionToShortcut = new Multimap(); this._registerBindings(document); } /** * @param {number} key * @return {!Array.<!UI.Action>} */ _applicableActions(key) { return this._actionRegistry.applicableActions(this._defaultActionsForKey(key).valuesArray(), UI.context); } /** * @param {number} key * @return {!Set.<string>} */ _defaultActionsForKey(key) { return this._defaultKeyToActions.get(String(key)); } /** * @param {string} actionId * @return {!Array.<!UI.KeyboardShortcut.Descriptor>} */ shortcutDescriptorsForAction(actionId) { return this._defaultActionToShortcut.get(actionId).valuesArray(); } /** * @param {!Array.<string>} actionIds * @return {!Array.<number>} */ keysForActions(actionIds) { const result = []; for (let i = 0; i < actionIds.length; ++i) { const descriptors = this.shortcutDescriptorsForAction(actionIds[i]); for (let j = 0; j < descriptors.length; ++j) result.push(descriptors[j].key); } return result; } /** * @param {string} actionId * @return {string|undefined} */ shortcutTitleForAction(actionId) { const descriptors = this.shortcutDescriptorsForAction(actionId); if (descriptors.length) return descriptors[0].name; } /** * @param {!KeyboardEvent} event */ handleShortcut(event) { this.handleKey(UI.KeyboardShortcut.makeKeyFromEvent(event), event.key, event); } /** * @param {!KeyboardEvent} event * @param {string} actionId * @return {boolean} */ eventMatchesAction(event, actionId) { console.assert(this._defaultActionToShortcut.has(actionId), 'Unknown action ' + actionId); const key = UI.KeyboardShortcut.makeKeyFromEvent(event); return this._defaultActionToShortcut.get(actionId).valuesArray().some(descriptor => descriptor.key === key); } /** * @param {!Element} element * @param {string} actionId * @param {function():boolean} listener * @param {boolean=} capture */ addShortcutListener(element, actionId, listener, capture) { console.assert(this._defaultActionToShortcut.has(actionId), 'Unknown action ' + actionId); element.addEventListener('keydown', event => { if (!this.eventMatchesAction(/** @type {!KeyboardEvent} */ (event), actionId) || !listener.call(null)) return; event.consume(true); }, capture); } /** * @param {number} key * @param {string} domKey * @param {!KeyboardEvent=} event */ handleKey(key, domKey, event) { const keyModifiers = key >> 8; const actions = this._applicableActions(key); if (!actions.length) return; if (UI.Dialog.hasInstance()) { if (event && !isPossiblyInputKey()) event.consume(true); return; } if (!isPossiblyInputKey()) { if (event) event.consume(true); processNextAction.call(this, false); } else { this._pendingActionTimer = setTimeout(processNextAction.bind(this, false), 0); } /** * @param {boolean} handled * @this {UI.ShortcutRegistry} */ function processNextAction(handled) { delete this._pendingActionTimer; const action = actions.shift(); if (!action || handled) return; action.execute().then(processNextAction.bind(this)); } /** * @return {boolean} */ function isPossiblyInputKey() { if (!event || !UI.isEditing() || /^F\d+|Control|Shift|Alt|Meta|Escape|Win|U\+001B$/.test(domKey)) return false; if (!keyModifiers) return true; const modifiers = UI.KeyboardShortcut.Modifiers; // Undo/Redo will also cause input, so textual undo should take precedence over DevTools undo when editing. if (Host.isMac()) { if (UI.KeyboardShortcut.makeKey('z', modifiers.Meta) === key) return true; if (UI.KeyboardShortcut.makeKey('z', modifiers.Meta | modifiers.Shift) === key) return true; } else { if (UI.KeyboardShortcut.makeKey('z', modifiers.Ctrl) === key) return true; if (UI.KeyboardShortcut.makeKey('y', modifiers.Ctrl) === key) return true; if (!Host.isWin() && UI.KeyboardShortcut.makeKey('z', modifiers.Ctrl | modifiers.Shift) === key) return true; } if ((keyModifiers & (modifiers.Ctrl | modifiers.Alt)) === (modifiers.Ctrl | modifiers.Alt)) return Host.isWin(); return !hasModifier(modifiers.Ctrl) && !hasModifier(modifiers.Alt) && !hasModifier(modifiers.Meta); } /** * @param {number} mod * @return {boolean} */ function hasModifier(mod) { return !!(keyModifiers & mod); } } /** * @param {string} actionId * @param {string} shortcut */ registerShortcut(actionId, shortcut) { const descriptor = UI.KeyboardShortcut.makeDescriptorFromBindingShortcut(shortcut); if (!descriptor) return; this._defaultActionToShortcut.set(actionId, descriptor); this._defaultKeyToActions.set(String(descriptor.key), actionId); } dismissPendingShortcutAction() { if (this._pendingActionTimer) { clearTimeout(this._pendingActionTimer); delete this._pendingActionTimer; } } /** * @param {!Document} document */ _registerBindings(document) { document.addEventListener('input', this.dismissPendingShortcutAction.bind(this), true); const extensions = self.runtime.extensions('action'); extensions.forEach(registerExtension, this); /** * @param {!Runtime.Extension} extension * @this {UI.ShortcutRegistry} */ function registerExtension(extension) { const descriptor = extension.descriptor(); const bindings = descriptor['bindings']; for (let i = 0; bindings && i < bindings.length; ++i) { if (!platformMatches(bindings[i].platform)) continue; const shortcuts = bindings[i]['shortcut'].split(/\s+/); shortcuts.forEach(this.registerShortcut.bind(this, descriptor['actionId'])); } } /** * @param {string=} platformsString * @return {boolean} */ function platformMatches(platformsString) { if (!platformsString) return true; const platforms = platformsString.split(','); let isMatch = false; const currentPlatform = Host.platform(); for (let i = 0; !isMatch && i < platforms.length; ++i) isMatch = platforms[i] === currentPlatform; return isMatch; } } }; /** * @unrestricted */ UI.ShortcutRegistry.ForwardedShortcut = class {}; UI.ShortcutRegistry.ForwardedShortcut.instance = new UI.ShortcutRegistry.ForwardedShortcut(); /** @type {!UI.ShortcutRegistry} */ UI.shortcutRegistry;