From 73fdf5d5ce7fa824c74e301659aebf86d7736d62 Mon Sep 17 00:00:00 2001 From: Donnie Date: Mon, 12 Oct 2020 16:55:55 -0700 Subject: [PATCH 1/2] Resolve conflicts --- .eslintrc.json | 2 + src/layouts/home-assistant.ts | 29 ++++++++- src/mixins/keyboard-shortcut-mixin.ts | 65 +++++++++++++++---- .../config/automation/ha-automation-editor.ts | 25 +++++-- src/panels/config/scene/ha-scene-editor.ts | 13 ++-- src/panels/config/script/ha-script-editor.ts | 18 +++-- 6 files changed, 119 insertions(+), 33 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index dd3bdc9c00f1..463bde3a0306 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -75,11 +75,13 @@ "object-curly-newline": 0, "default-case": 0, "wc/no-self-class": 0, + "no-shadow": 0, "@typescript-eslint/camelcase": 0, "@typescript-eslint/ban-ts-comment": 0, "@typescript-eslint/no-use-before-define": 0, "@typescript-eslint/no-non-null-assertion": 0, "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-shadow": ["error"], "@typescript-eslint/no-unused-vars": 0, "@typescript-eslint/explicit-function-return-type": 0, "@typescript-eslint/explicit-module-boundary-types": 0 diff --git a/src/layouts/home-assistant.ts b/src/layouts/home-assistant.ts index f17db8fb4681..70fb146dd7c1 100644 --- a/src/layouts/home-assistant.ts +++ b/src/layouts/home-assistant.ts @@ -17,10 +17,23 @@ import { import "./ha-init-page"; import "./home-assistant-main"; import { storeState } from "../util/ha-pref-storage"; -import QuickBarMixin from "../state/quick-bar-mixin"; +import { + KeyboardShortcutMixin, + HAKeyboardShortcut, +} from "../mixins/keyboard-shortcut-mixin"; +import { + QuickBarParams, + showQuickBar, +} from "../dialogs/quick-bar/show-dialog-quick-bar"; + +declare global { + interface HASSDomEvents { + "hass-quick-open": QuickBarParams; + } +} @customElement("home-assistant") -export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { +export class HomeAssistantAppEl extends KeyboardShortcutMixin(HassElement) { @internalProperty() private _route?: Route; @internalProperty() private _error = false; @@ -131,6 +144,18 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { const { auth, conn } = result; this._haVersion = conn.haVersion; this.initializeHass(auth, conn); + + this.registerShortcut( + HAKeyboardShortcut.CTRL_P, + () => showQuickBar(this, {}), + document + ); + + this.registerShortcut( + HAKeyboardShortcut.CTRL_SHIFT_P, + () => showQuickBar(this, { commandMode: true }), + document + ); } catch (err) { this._error = true; } diff --git a/src/mixins/keyboard-shortcut-mixin.ts b/src/mixins/keyboard-shortcut-mixin.ts index 359f386dc812..13f2d7425e4a 100644 --- a/src/mixins/keyboard-shortcut-mixin.ts +++ b/src/mixins/keyboard-shortcut-mixin.ts @@ -1,26 +1,65 @@ import { LitElement } from "lit-element"; import { Constructor } from "../types"; +type RegisteredShortcuts = { + [key in HAKeyboardShortcut]?: () => void; +}; + +export enum HAKeyboardShortcut { + CTRL_S = "CtrlS", + CTRL_P = "CtrlP", + CTRL_SHIFT_P = "CtrlShiftP", +} + +const isMac = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform); + export const KeyboardShortcutMixin = >( superClass: T ) => class extends superClass { - private _keydownEvent = (event: KeyboardEvent) => { - if ((event.ctrlKey || event.metaKey) && event.key === "s") { - event.preventDefault(); - this.handleKeyboardSave(); - } - }; + private _registeredShortcuts: RegisteredShortcuts = {}; - public connectedCallback() { - super.connectedCallback(); - this.addEventListener("keydown", this._keydownEvent); + protected registerShortcut( + shortcut: HAKeyboardShortcut, + callback: () => void, + element: HTMLElement | Document = this + ) { + element.addEventListener("keydown", this._keydownEvent); + this._registeredShortcuts[shortcut] = callback; } - public disconnectedCallback() { - this.removeEventListener("keydown", this._keydownEvent); - super.disconnectedCallback(); + private _executeShortcut( + event: KeyboardEvent, + shortcut: HAKeyboardShortcut + ) { + if (Object.keys(this._registeredShortcuts).includes(shortcut)) { + event.preventDefault(); + const shortcutAction = this._registeredShortcuts[shortcut]; + if (shortcutAction) { + shortcutAction(); + } + } } - protected handleKeyboardSave() {} + private _keydownEvent = (event: Event) => { + const _event = event as KeyboardEvent; + if (this.isOSCtrlKey(_event)) { + switch (_event.code) { + case "KeyS": + this._executeShortcut(_event, HAKeyboardShortcut.CTRL_S); + break; + case "KeyP": + if (_event.shiftKey) { + this._executeShortcut(_event, HAKeyboardShortcut.CTRL_SHIFT_P); + } else { + this._executeShortcut(_event, HAKeyboardShortcut.CTRL_P); + } + break; + } + } + }; + + private isOSCtrlKey(e: KeyboardEvent) { + return isMac ? e.metaKey : e.ctrlKey; + } }; diff --git a/src/panels/config/automation/ha-automation-editor.ts b/src/panels/config/automation/ha-automation-editor.ts index 19fffa029820..59059e311ca9 100644 --- a/src/panels/config/automation/ha-automation-editor.ts +++ b/src/panels/config/automation/ha-automation-editor.ts @@ -49,7 +49,10 @@ import { } from "../../../dialogs/generic/show-dialog-box"; import "../../../layouts/ha-app-layout"; import "../../../layouts/hass-tabs-subpage"; -import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin"; +import { + KeyboardShortcutMixin, + HAKeyboardShortcut, +} from "../../../mixins/keyboard-shortcut-mixin"; import { haStyle } from "../../../resources/styles"; import { HomeAssistant, Route } from "../../../types"; import { documentationUrl } from "../../../util/documentation-url"; @@ -473,6 +476,12 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { `; } + protected firstUpdated() { + this.registerShortcut(HAKeyboardShortcut.CTRL_S, () => + this._saveAutomation() + ); + } + protected updated(changedProps: PropertyValues): void { super.updated(changedProps); @@ -585,7 +594,10 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { } private _triggerChanged(ev: CustomEvent): void { - this._config = { ...this._config!, trigger: ev.detail.value as Trigger[] }; + this._config = { + ...this._config!, + trigger: ev.detail.value as Trigger[], + }; this._errors = undefined; this._dirty = true; } @@ -600,7 +612,10 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { } private _actionChanged(ev: CustomEvent): void { - this._config = { ...this._config!, action: ev.detail.value as Action[] }; + this._config = { + ...this._config!, + action: ev.detail.value as Action[], + }; this._errors = undefined; this._dirty = true; } @@ -730,10 +745,6 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { ); } - protected handleKeyboardSave() { - this._saveAutomation(); - } - static get styles(): CSSResult[] { return [ haStyle, diff --git a/src/panels/config/scene/ha-scene-editor.ts b/src/panels/config/scene/ha-scene-editor.ts index 5c3526ff2d13..db7615915c2c 100644 --- a/src/panels/config/scene/ha-scene-editor.ts +++ b/src/panels/config/scene/ha-scene-editor.ts @@ -58,7 +58,10 @@ import "../ha-config-section"; import { configSections } from "../ha-panel-config"; import "../../../components/ha-svg-icon"; import { mdiContentSave } from "@mdi/js"; -import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin"; +import { + HAKeyboardShortcut, + KeyboardShortcutMixin, +} from "../../../mixins/keyboard-shortcut-mixin"; interface DeviceEntities { id: string; @@ -414,6 +417,10 @@ export class HaSceneEditor extends SubscribeMixin( `; } + protected firstUpdated() { + this.registerShortcut(HAKeyboardShortcut.CTRL_S, () => this._saveScene()); + } + protected updated(changedProps: PropertyValues): void { super.updated(changedProps); @@ -719,10 +726,6 @@ export class HaSceneEditor extends SubscribeMixin( } } - protected handleKeyboardSave() { - this._saveScene(); - } - static get styles(): CSSResult[] { return [ haStyle, diff --git a/src/panels/config/script/ha-script-editor.ts b/src/panels/config/script/ha-script-editor.ts index 0bf1790075b2..d4f8ff3c8e38 100644 --- a/src/panels/config/script/ha-script-editor.ts +++ b/src/panels/config/script/ha-script-editor.ts @@ -40,7 +40,10 @@ import { } from "../../../data/script"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; import "../../../layouts/ha-app-layout"; -import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin"; +import { + HAKeyboardShortcut, + KeyboardShortcutMixin, +} from "../../../mixins/keyboard-shortcut-mixin"; import { haStyle } from "../../../resources/styles"; import { HomeAssistant, Route } from "../../../types"; import { documentationUrl } from "../../../util/documentation-url"; @@ -374,6 +377,10 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { `; } + protected firstUpdated() { + this.registerShortcut(HAKeyboardShortcut.CTRL_S, () => this._saveScript()); + } + protected updated(changedProps: PropertyValues): void { super.updated(changedProps); @@ -503,7 +510,10 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { } private _sequenceChanged(ev: CustomEvent): void { - this._config = { ...this._config!, sequence: ev.detail.value as Action[] }; + this._config = { + ...this._config!, + sequence: ev.detail.value as Action[], + }; this._errors = undefined; this._dirty = true; } @@ -596,10 +606,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { ); } - protected handleKeyboardSave() { - this._saveScript(); - } - static get styles(): CSSResult[] { return [ haStyle, From 5cd55e13b35afe3398c09a3ecc813317a4d04c83 Mon Sep 17 00:00:00 2001 From: Donnie Date: Tue, 13 Oct 2020 09:20:39 -0700 Subject: [PATCH 2/2] Resolve review comments --- .eslintrc.json | 2 + src/layouts/home-assistant.ts | 29 +++++++- src/mixins/keyboard-shortcut-mixin.ts | 67 +++++++++++++++---- .../config/automation/ha-automation-editor.ts | 25 +++++-- src/panels/config/scene/ha-scene-editor.ts | 13 ++-- src/panels/config/script/ha-script-editor.ts | 18 +++-- 6 files changed, 122 insertions(+), 32 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index dd3bdc9c00f1..463bde3a0306 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -75,11 +75,13 @@ "object-curly-newline": 0, "default-case": 0, "wc/no-self-class": 0, + "no-shadow": 0, "@typescript-eslint/camelcase": 0, "@typescript-eslint/ban-ts-comment": 0, "@typescript-eslint/no-use-before-define": 0, "@typescript-eslint/no-non-null-assertion": 0, "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-shadow": ["error"], "@typescript-eslint/no-unused-vars": 0, "@typescript-eslint/explicit-function-return-type": 0, "@typescript-eslint/explicit-module-boundary-types": 0 diff --git a/src/layouts/home-assistant.ts b/src/layouts/home-assistant.ts index f17db8fb4681..70fb146dd7c1 100644 --- a/src/layouts/home-assistant.ts +++ b/src/layouts/home-assistant.ts @@ -17,10 +17,23 @@ import { import "./ha-init-page"; import "./home-assistant-main"; import { storeState } from "../util/ha-pref-storage"; -import QuickBarMixin from "../state/quick-bar-mixin"; +import { + KeyboardShortcutMixin, + HAKeyboardShortcut, +} from "../mixins/keyboard-shortcut-mixin"; +import { + QuickBarParams, + showQuickBar, +} from "../dialogs/quick-bar/show-dialog-quick-bar"; + +declare global { + interface HASSDomEvents { + "hass-quick-open": QuickBarParams; + } +} @customElement("home-assistant") -export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { +export class HomeAssistantAppEl extends KeyboardShortcutMixin(HassElement) { @internalProperty() private _route?: Route; @internalProperty() private _error = false; @@ -131,6 +144,18 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { const { auth, conn } = result; this._haVersion = conn.haVersion; this.initializeHass(auth, conn); + + this.registerShortcut( + HAKeyboardShortcut.CTRL_P, + () => showQuickBar(this, {}), + document + ); + + this.registerShortcut( + HAKeyboardShortcut.CTRL_SHIFT_P, + () => showQuickBar(this, { commandMode: true }), + document + ); } catch (err) { this._error = true; } diff --git a/src/mixins/keyboard-shortcut-mixin.ts b/src/mixins/keyboard-shortcut-mixin.ts index 359f386dc812..169f7a0ad60d 100644 --- a/src/mixins/keyboard-shortcut-mixin.ts +++ b/src/mixins/keyboard-shortcut-mixin.ts @@ -1,26 +1,69 @@ import { LitElement } from "lit-element"; import { Constructor } from "../types"; +type RegisteredShortcuts = { + [key in HAKeyboardShortcut]?: () => void; +}; + +export enum HAKeyboardShortcut { + CTRL_S = "CtrlS", + CTRL_P = "CtrlP", + CTRL_SHIFT_P = "CtrlShiftP", +} + +const isMac = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform); + export const KeyboardShortcutMixin = >( superClass: T ) => class extends superClass { - private _keydownEvent = (event: KeyboardEvent) => { - if ((event.ctrlKey || event.metaKey) && event.key === "s") { - event.preventDefault(); - this.handleKeyboardSave(); - } - }; - - public connectedCallback() { - super.connectedCallback(); - this.addEventListener("keydown", this._keydownEvent); - } + private _registeredShortcuts: RegisteredShortcuts = {}; public disconnectedCallback() { this.removeEventListener("keydown", this._keydownEvent); super.disconnectedCallback(); } - protected handleKeyboardSave() {} + protected registerShortcut( + shortcut: HAKeyboardShortcut, + callback: () => void, + element: HTMLElement | Document = this + ) { + element.addEventListener("keydown", (event) => this._keydownEvent(event)); + this._registeredShortcuts[shortcut] = callback; + } + + private _executeShortcut( + event: KeyboardEvent, + shortcut: HAKeyboardShortcut + ) { + if (Object.keys(this._registeredShortcuts).includes(shortcut)) { + event.preventDefault(); + const shortcutAction = this._registeredShortcuts[shortcut]; + if (shortcutAction) { + shortcutAction(); + } + } + } + + private _keydownEvent = (event: KeyboardEvent) => { + if (this.isOSCtrlKey(event)) { + switch (event.code) { + case "KeyS": + this._executeShortcut(event, HAKeyboardShortcut.CTRL_S); + break; + case "KeyP": + if (event.shiftKey) { + this._executeShortcut(event, HAKeyboardShortcut.CTRL_SHIFT_P); + } else { + this._executeShortcut(event, HAKeyboardShortcut.CTRL_P); + } + break; + } + } + }; + + private isOSCtrlKey(e: KeyboardEvent) { + return isMac ? e.metaKey : e.ctrlKey; + } }; diff --git a/src/panels/config/automation/ha-automation-editor.ts b/src/panels/config/automation/ha-automation-editor.ts index 19fffa029820..59059e311ca9 100644 --- a/src/panels/config/automation/ha-automation-editor.ts +++ b/src/panels/config/automation/ha-automation-editor.ts @@ -49,7 +49,10 @@ import { } from "../../../dialogs/generic/show-dialog-box"; import "../../../layouts/ha-app-layout"; import "../../../layouts/hass-tabs-subpage"; -import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin"; +import { + KeyboardShortcutMixin, + HAKeyboardShortcut, +} from "../../../mixins/keyboard-shortcut-mixin"; import { haStyle } from "../../../resources/styles"; import { HomeAssistant, Route } from "../../../types"; import { documentationUrl } from "../../../util/documentation-url"; @@ -473,6 +476,12 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { `; } + protected firstUpdated() { + this.registerShortcut(HAKeyboardShortcut.CTRL_S, () => + this._saveAutomation() + ); + } + protected updated(changedProps: PropertyValues): void { super.updated(changedProps); @@ -585,7 +594,10 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { } private _triggerChanged(ev: CustomEvent): void { - this._config = { ...this._config!, trigger: ev.detail.value as Trigger[] }; + this._config = { + ...this._config!, + trigger: ev.detail.value as Trigger[], + }; this._errors = undefined; this._dirty = true; } @@ -600,7 +612,10 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { } private _actionChanged(ev: CustomEvent): void { - this._config = { ...this._config!, action: ev.detail.value as Action[] }; + this._config = { + ...this._config!, + action: ev.detail.value as Action[], + }; this._errors = undefined; this._dirty = true; } @@ -730,10 +745,6 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { ); } - protected handleKeyboardSave() { - this._saveAutomation(); - } - static get styles(): CSSResult[] { return [ haStyle, diff --git a/src/panels/config/scene/ha-scene-editor.ts b/src/panels/config/scene/ha-scene-editor.ts index 5c3526ff2d13..db7615915c2c 100644 --- a/src/panels/config/scene/ha-scene-editor.ts +++ b/src/panels/config/scene/ha-scene-editor.ts @@ -58,7 +58,10 @@ import "../ha-config-section"; import { configSections } from "../ha-panel-config"; import "../../../components/ha-svg-icon"; import { mdiContentSave } from "@mdi/js"; -import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin"; +import { + HAKeyboardShortcut, + KeyboardShortcutMixin, +} from "../../../mixins/keyboard-shortcut-mixin"; interface DeviceEntities { id: string; @@ -414,6 +417,10 @@ export class HaSceneEditor extends SubscribeMixin( `; } + protected firstUpdated() { + this.registerShortcut(HAKeyboardShortcut.CTRL_S, () => this._saveScene()); + } + protected updated(changedProps: PropertyValues): void { super.updated(changedProps); @@ -719,10 +726,6 @@ export class HaSceneEditor extends SubscribeMixin( } } - protected handleKeyboardSave() { - this._saveScene(); - } - static get styles(): CSSResult[] { return [ haStyle, diff --git a/src/panels/config/script/ha-script-editor.ts b/src/panels/config/script/ha-script-editor.ts index 0bf1790075b2..d4f8ff3c8e38 100644 --- a/src/panels/config/script/ha-script-editor.ts +++ b/src/panels/config/script/ha-script-editor.ts @@ -40,7 +40,10 @@ import { } from "../../../data/script"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; import "../../../layouts/ha-app-layout"; -import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin"; +import { + HAKeyboardShortcut, + KeyboardShortcutMixin, +} from "../../../mixins/keyboard-shortcut-mixin"; import { haStyle } from "../../../resources/styles"; import { HomeAssistant, Route } from "../../../types"; import { documentationUrl } from "../../../util/documentation-url"; @@ -374,6 +377,10 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { `; } + protected firstUpdated() { + this.registerShortcut(HAKeyboardShortcut.CTRL_S, () => this._saveScript()); + } + protected updated(changedProps: PropertyValues): void { super.updated(changedProps); @@ -503,7 +510,10 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { } private _sequenceChanged(ev: CustomEvent): void { - this._config = { ...this._config!, sequence: ev.detail.value as Action[] }; + this._config = { + ...this._config!, + sequence: ev.detail.value as Action[], + }; this._errors = undefined; this._dirty = true; } @@ -596,10 +606,6 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { ); } - protected handleKeyboardSave() { - this._saveScript(); - } - static get styles(): CSSResult[] { return [ haStyle,