diff --git a/src/panels/lovelace/ha-panel-lovelace.ts b/src/panels/lovelace/ha-panel-lovelace.ts index f6edee5e0b..07445a9291 100644 --- a/src/panels/lovelace/ha-panel-lovelace.ts +++ b/src/panels/lovelace/ha-panel-lovelace.ts @@ -16,6 +16,8 @@ interface LovelacePanelConfig { mode: "yaml" | "storage"; } +let editorLoaded = false; + class LovelacePanel extends hassLocalizeLitMixin(LitElement) { public panel?: PanelInfo; public hass?: HomeAssistant; @@ -23,7 +25,7 @@ class LovelacePanel extends hassLocalizeLitMixin(LitElement) { public showMenu?: boolean; public route?: object; private _columns?: number; - private _state?: "loading" | "loaded" | "error"; + private _state?: "loading" | "loaded" | "error" | "yaml-editor"; private _errorMsg?: string; private lovelace?: Lovelace; private mqls?: MediaQueryList[]; @@ -42,6 +44,11 @@ class LovelacePanel extends hassLocalizeLitMixin(LitElement) { }; } + constructor() { + super(); + this._closeEditor = this._closeEditor.bind(this); + } + public render(): TemplateResult { const state = this._state!; @@ -80,6 +87,15 @@ class LovelacePanel extends hassLocalizeLitMixin(LitElement) { `; } + if (state === "yaml-editor") { + return html` + + `; + } + return html` cols + Number(mql.matches), @@ -144,6 +164,13 @@ class LovelacePanel extends hassLocalizeLitMixin(LitElement) { config: conf, editMode: this.lovelace ? this.lovelace.editMode : false, mode: confMode, + enableFullEditMode: () => { + if (!editorLoaded) { + editorLoaded = true; + import("./hui-editor"); + } + this._state = "yaml-editor"; + }, setEditMode: (editMode: boolean) => { if (!editMode || this.lovelace!.mode !== "generated") { this._updateLovelace({ editMode }); diff --git a/src/panels/lovelace/hui-editor.ts b/src/panels/lovelace/hui-editor.ts new file mode 100644 index 0000000000..b1e7ace684 --- /dev/null +++ b/src/panels/lovelace/hui-editor.ts @@ -0,0 +1,128 @@ +import { LitElement, html } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import yaml from "js-yaml"; + +import "@polymer/app-layout/app-header-layout/app-header-layout"; +import "@polymer/app-layout/app-header/app-header"; +import "@polymer/app-layout/app-toolbar/app-toolbar"; +import "@polymer/paper-button/paper-button"; +import "@polymer/paper-icon-button/paper-icon-button"; + +import { Lovelace } from "./types"; +import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin"; + +const TAB_INSERT = " "; + +class LovelaceFullConfigEditor extends hassLocalizeLitMixin(LitElement) { + public lovelace?: Lovelace; + public closeEditor?: () => void; + private _haStyle?: DocumentFragment; + + static get properties() { + return { + lovelace: {}, + }; + } + + public render(): TemplateResult { + return html` + ${this.renderStyle()} + + + + +
Edit Config
+ Save +
+
+
+ +
+
+ `; + } + + protected firstUpdated() { + const textArea = this.textArea; + textArea.value = yaml.safeDump(this.lovelace!.config); + textArea.addEventListener("keydown", (e) => { + if (e.keyCode !== 9) { + return; + } + + e.preventDefault(); + + // tab was pressed, get caret position/selection + const val = textArea.value; + const start = textArea.selectionStart; + const end = textArea.selectionEnd; + + // set textarea value to: text before caret + tab + text after caret + textArea.value = + val.substring(0, start) + TAB_INSERT + val.substring(end); + + // put caret at right position again + textArea.selectionStart = textArea.selectionEnd = + start + TAB_INSERT.length; + }); + } + + protected renderStyle() { + if (!this._haStyle) { + this._haStyle = document.importNode( + (document.getElementById("ha-style")! + .children[0] as HTMLTemplateElement).content, + true + ); + } + + return html` + ${this._haStyle} + + `; + } + + private _handleSave() { + let value; + try { + value = yaml.safeLoad(this.textArea.value); + } catch (err) { + alert(`Unable to parse YAML: ${err}`); + return; + } + + this.lovelace!.saveConfig(value); + } + + private get textArea(): HTMLTextAreaElement { + return this.shadowRoot!.querySelector("textarea")!; + } +} + +customElements.define("hui-editor", LovelaceFullConfigEditor); diff --git a/src/panels/lovelace/hui-root.js b/src/panels/lovelace/hui-root.js index 537359b4ee..415855e555 100644 --- a/src/panels/lovelace/hui-root.js +++ b/src/panels/lovelace/hui-root.js @@ -124,11 +124,14 @@ class HUIRoot extends NavigateMixin( > -