diff --git a/package.json b/package.json
index c54c656c04..00ead71952 100644
--- a/package.json
+++ b/package.json
@@ -74,7 +74,7 @@
"@webcomponents/webcomponentsjs": "^2.2.7",
"chart.js": "~2.8.0",
"chartjs-chart-timeline": "^0.3.0",
- "codemirror": "^5.45.0",
+ "codemirror": "^5.49.0",
"cpx": "^1.5.0",
"deep-clone-simple": "^1.1.1",
"es6-object-assign": "^1.1.0",
@@ -117,6 +117,7 @@
"@types/chai": "^4.1.7",
"@types/chromecast-caf-receiver": "^3.0.12",
"@types/chromecast-caf-sender": "^1.0.1",
+ "@types/codemirror": "^0.0.78",
"@types/hls.js": "^0.12.3",
"@types/leaflet": "^1.4.3",
"@types/memoize-one": "4.1.0",
diff --git a/src/components/ha-code-editor.ts b/src/components/ha-code-editor.ts
new file mode 100644
index 0000000000..fcbc24306b
--- /dev/null
+++ b/src/components/ha-code-editor.ts
@@ -0,0 +1,160 @@
+import { loadCodeMirror } from "../resources/codemirror.ondemand";
+import { fireEvent } from "../common/dom/fire_event";
+import {
+ UpdatingElement,
+ property,
+ customElement,
+ PropertyValues,
+} from "lit-element";
+import { Editor } from "codemirror";
+
+declare global {
+ interface HASSDomEvents {
+ "editor-save": undefined;
+ }
+}
+
+@customElement("ha-code-editor")
+export class HaCodeEditor extends UpdatingElement {
+ public codemirror?: Editor;
+ @property() public mode?: string;
+ @property() public autofocus = false;
+ @property() public rtl = false;
+ @property() public error = false;
+ @property() private _value = "";
+
+ public set value(value: string) {
+ this._value = value;
+ }
+
+ public get value(): string {
+ return this.codemirror ? this.codemirror.getValue() : this._value;
+ }
+
+ public get hasComments(): boolean {
+ return this.shadowRoot!.querySelector("span.cm-comment") ? true : false;
+ }
+
+ public connectedCallback() {
+ super.connectedCallback();
+ if (!this.codemirror) {
+ return;
+ }
+ this.codemirror.refresh();
+ if (this.autofocus !== false) {
+ this.codemirror.focus();
+ }
+ }
+
+ protected update(changedProps: PropertyValues): void {
+ super.update(changedProps);
+
+ if (!this.codemirror) {
+ return;
+ }
+
+ if (changedProps.has("mode")) {
+ this.codemirror.setOption("mode", this.mode);
+ }
+ if (changedProps.has("autofocus")) {
+ this.codemirror.setOption("autofocus", this.autofocus !== false);
+ }
+ if (changedProps.has("_value") && this._value !== this.value) {
+ this.codemirror.setValue(this._value);
+ }
+ if (changedProps.has("rtl")) {
+ this.codemirror.setOption("gutters", this._calcGutters());
+ this._setScrollBarDirection();
+ }
+ if (changedProps.has("error")) {
+ this.classList.toggle("error-state", this.error);
+ }
+ }
+
+ protected firstUpdated(changedProps: PropertyValues): void {
+ super.firstUpdated(changedProps);
+ this._load();
+ }
+
+ private async _load(): Promise {
+ const loaded = await loadCodeMirror();
+
+ const codeMirror = loaded.codeMirror;
+
+ const shadowRoot = this.attachShadow({ mode: "open" });
+
+ shadowRoot!.innerHTML = `
+ `;
+
+ this.codemirror = codeMirror(shadowRoot, {
+ value: this._value,
+ lineNumbers: true,
+ tabSize: 2,
+ mode: this.mode,
+ autofocus: this.autofocus !== false,
+ viewportMargin: Infinity,
+ extraKeys: {
+ Tab: "indentMore",
+ "Shift-Tab": "indentLess",
+ },
+ gutters: this._calcGutters(),
+ });
+ this._setScrollBarDirection();
+ this.codemirror!.on("changes", () => this._onChange());
+ }
+
+ private _onChange(): void {
+ const newValue = this.value;
+ if (newValue === this._value) {
+ return;
+ }
+ this._value = newValue;
+ fireEvent(this, "value-changed", { value: this._value });
+ }
+
+ private _calcGutters(): string[] {
+ return this.rtl ? ["rtl-gutter", "CodeMirror-linenumbers"] : [];
+ }
+
+ private _setScrollBarDirection(): void {
+ if (this.codemirror) {
+ this.codemirror.getWrapperElement().classList.toggle("rtl", this.rtl);
+ }
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-code-editor": HaCodeEditor;
+ }
+}
diff --git a/src/components/ha-yaml-editor.ts b/src/components/ha-yaml-editor.ts
deleted file mode 100644
index 11190cbfef..0000000000
--- a/src/components/ha-yaml-editor.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-// @ts-ignore
-import CodeMirror from "codemirror";
-import "codemirror/mode/yaml/yaml";
-// @ts-ignore
-import codeMirrorCSS from "codemirror/lib/codemirror.css";
-import { fireEvent } from "../common/dom/fire_event";
-import { customElement } from "lit-element";
-
-declare global {
- interface HASSDomEvents {
- "yaml-changed": {
- value: string;
- };
- "yaml-save": undefined;
- }
-}
-
-@customElement("ha-yaml-editor")
-export class HaYamlEditor extends HTMLElement {
- public codemirror?: any;
- private _autofocus = false;
- private _rtl = false;
- private _value: string;
-
- public constructor() {
- super();
- CodeMirror.commands.save = (cm: CodeMirror) => {
- fireEvent(cm.getWrapperElement(), "yaml-save");
- };
- this._value = "";
- const shadowRoot = this.attachShadow({ mode: "open" });
- shadowRoot.innerHTML = `
- `;
- }
-
- set value(value: string) {
- if (this.codemirror) {
- if (value !== this.codemirror.getValue()) {
- this.codemirror.setValue(value);
- }
- }
- this._value = value;
- }
-
- get value(): string {
- return this.codemirror.getValue();
- }
-
- set rtl(rtl: boolean) {
- this._rtl = rtl;
- this.setScrollBarDirection();
- }
-
- set autofocus(autofocus: boolean) {
- this._autofocus = autofocus;
- if (this.codemirror) {
- this.codemirror.focus();
- }
- }
-
- set error(error: boolean) {
- this.classList.toggle("error-state", error);
- }
-
- get hasComments(): boolean {
- return this.shadowRoot!.querySelector("span.cm-comment") ? true : false;
- }
-
- public connectedCallback(): void {
- if (!this.codemirror) {
- this.codemirror = CodeMirror(
- (this.shadowRoot as unknown) as HTMLElement,
- {
- value: this._value,
- lineNumbers: true,
- mode: "yaml",
- tabSize: 2,
- autofocus: this._autofocus,
- viewportMargin: Infinity,
- extraKeys: {
- Tab: "indentMore",
- "Shift-Tab": "indentLess",
- },
- gutters: this._rtl ? ["rtl-gutter", "CodeMirror-linenumbers"] : [],
- }
- );
- this.setScrollBarDirection();
- this.codemirror.on("changes", () => this._onChange());
- } else {
- this.codemirror.refresh();
- }
- }
-
- private _onChange(): void {
- fireEvent(this, "yaml-changed", { value: this.codemirror.getValue() });
- }
-
- private setScrollBarDirection(): void {
- if (this.codemirror) {
- this.codemirror.getWrapperElement().classList.toggle("rtl", this._rtl);
- }
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- "ha-yaml-editor": HaYamlEditor;
- }
-}
diff --git a/src/panels/config/js/preact-types.ts b/src/panels/config/js/preact-types.ts
index f103f63230..617fe5d2dd 100644
--- a/src/panels/config/js/preact-types.ts
+++ b/src/panels/config/js/preact-types.ts
@@ -20,7 +20,7 @@ declare global {
"ha-device-picker": any;
"ha-device-condition-picker": any;
"ha-textarea": any;
- "ha-yaml-editor": any;
+ "ha-code-editor": any;
"ha-service-picker": any;
"mwc-button": any;
"ha-device-trigger-picker": any;
diff --git a/src/panels/config/js/yaml_textarea.tsx b/src/panels/config/js/yaml_textarea.tsx
index f9e8edf634..5050576db2 100644
--- a/src/panels/config/js/yaml_textarea.tsx
+++ b/src/panels/config/js/yaml_textarea.tsx
@@ -1,8 +1,6 @@
import { h, Component } from "preact";
import yaml from "js-yaml";
-import "../../../components/ha-yaml-editor";
-// tslint:disable-next-line
-import { HaYamlEditor } from "../../../components/ha-yaml-editor";
+import "../../../components/ha-code-editor";
const isEmpty = (obj: object) => {
for (const key in obj) {
@@ -14,8 +12,6 @@ const isEmpty = (obj: object) => {
};
export default class YAMLTextArea extends Component {
- private _yamlEditor!: HaYamlEditor;
-
constructor(props) {
super(props);
@@ -63,12 +59,6 @@ export default class YAMLTextArea extends Component {
}
}
- public componentDidMount() {
- setTimeout(() => {
- this._yamlEditor.codemirror.refresh();
- }, 1);
- }
-
public render({ label }, { value, isValid }) {
const style: any = {
minWidth: 300,
@@ -77,16 +67,14 @@ export default class YAMLTextArea extends Component {
return (
);
}
-
- private _storeYamlEditorRef = (yamlEditor) => (this._yamlEditor = yamlEditor);
}
diff --git a/src/panels/developer-tools/event/developer-tools-event.js b/src/panels/developer-tools/event/developer-tools-event.js
index 25fd569034..c1b50bd068 100644
--- a/src/panels/developer-tools/event/developer-tools-event.js
+++ b/src/panels/developer-tools/event/developer-tools-event.js
@@ -1,17 +1,18 @@
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
import "@material/mwc-button";
import "@polymer/paper-input/paper-input";
-import "@polymer/paper-input/paper-textarea";
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import yaml from "js-yaml";
+import "../../../components/ha-code-editor";
import "../../../resources/ha-style";
import "./events-list";
import "./event-subscribe-card";
import { EventsMixin } from "../../../mixins/events-mixin";
+const ERROR_SENTINEL = {};
/*
* @appliesMixin EventsMixin
*/
@@ -32,6 +33,11 @@ class HaPanelDevEvent extends EventsMixin(PolymerElement) {
.ha-form {
margin-right: 16px;
+ max-width: 400px;
+ }
+
+ mwc-button {
+ margin-top: 8px;
}
.header {
@@ -62,11 +68,16 @@ class HaPanelDevEvent extends EventsMixin(PolymerElement) {
required
value="{{eventType}}"
>
-
- Fire Event
+ Event Data (YAML, optional)
+
+ Fire Event
@@ -97,6 +108,16 @@ class HaPanelDevEvent extends EventsMixin(PolymerElement) {
type: String,
value: "",
},
+
+ parsedJSON: {
+ type: Object,
+ computed: "_computeParsedEventData(eventData)",
+ },
+
+ validJSON: {
+ type: Boolean,
+ computed: "_computeValidJSON(parsedJSON)",
+ },
};
}
@@ -104,19 +125,28 @@ class HaPanelDevEvent extends EventsMixin(PolymerElement) {
this.eventType = ev.detail.eventType;
}
- fireEvent() {
- var eventData;
-
+ _computeParsedEventData(eventData) {
try {
- eventData = this.eventData ? yaml.safeLoad(this.eventData) : {};
+ return eventData.trim() ? yaml.safeLoad(eventData) : {};
} catch (err) {
- /* eslint-disable no-alert */
- alert("Error parsing YAML: " + err);
- /* eslint-enable no-alert */
+ return ERROR_SENTINEL;
+ }
+ }
+
+ _computeValidJSON(parsedJSON) {
+ return parsedJSON !== ERROR_SENTINEL;
+ }
+
+ _yamlChanged(ev) {
+ this.eventData = ev.detail.value;
+ }
+
+ fireEvent() {
+ if (!this.eventType) {
+ alert("Event type is a mandatory field");
return;
}
-
- this.hass.callApi("POST", "events/" + this.eventType, eventData).then(
+ this.hass.callApi("POST", "events/" + this.eventType, this.parsedJSON).then(
function() {
this.fire("hass-notification", {
message: "Event " + this.eventType + " successful fired!",
diff --git a/src/panels/developer-tools/mqtt/developer-tools-mqtt.ts b/src/panels/developer-tools/mqtt/developer-tools-mqtt.ts
index 3320eb52c3..93f0215ee9 100644
--- a/src/panels/developer-tools/mqtt/developer-tools-mqtt.ts
+++ b/src/panels/developer-tools/mqtt/developer-tools-mqtt.ts
@@ -9,12 +9,12 @@ import {
} from "lit-element";
import "@material/mwc-button";
import "@polymer/paper-input/paper-input";
-import "@polymer/paper-input/paper-textarea";
import { HomeAssistant } from "../../../types";
import { haStyle } from "../../../resources/styles";
import "../../../components/ha-card";
+import "../../../components/ha-code-editor";
import "./mqtt-subscribe-card";
@customElement("developer-tools-mqtt")
@@ -48,12 +48,12 @@ class HaPanelDevMqtt extends LitElement {
@value-changed=${this._handleTopic}
>
- Payload (template allowed)
+
+ >
Publish
diff --git a/src/panels/developer-tools/service/developer-tools-service.js b/src/panels/developer-tools/service/developer-tools-service.js
index 1656816d12..de04bd4ed9 100644
--- a/src/panels/developer-tools/service/developer-tools-service.js
+++ b/src/panels/developer-tools/service/developer-tools-service.js
@@ -1,5 +1,4 @@
import "@material/mwc-button";
-import "@polymer/paper-input/paper-textarea";
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
@@ -7,6 +6,7 @@ import yaml from "js-yaml";
import { ENTITY_COMPONENT_DOMAINS } from "../../../data/entity";
import "../../../components/entity/ha-entity-picker";
+import "../../../components/ha-code-editor";
import "../../../components/ha-service-picker";
import "../../../resources/ha-style";
import "../../../util/app-localstorage-document";
@@ -30,6 +30,10 @@ class HaPanelDevService extends PolymerElement {
max-width: 400px;
}
+ mwc-button {
+ margin-top: 8px;
+ }
+
.description {
margin-top: 24px;
white-space: pre-wrap;
@@ -109,20 +113,16 @@ class HaPanelDevService extends PolymerElement {
allow-custom-entity
>
-
+
Service Data (YAML, optional)
+
Call Service
-
- Invalid YAML
-
@@ -305,6 +305,10 @@ class HaPanelDevService extends PolymerElement {
entity_id: ev.target.value,
});
}
+
+ _yamlChanged(ev) {
+ this.serviceData = ev.detail.value;
+ }
}
customElements.define("developer-tools-service", HaPanelDevService);
diff --git a/src/panels/developer-tools/state/developer-tools-state.js b/src/panels/developer-tools/state/developer-tools-state.js
index 65c518253a..d1b67e70b7 100644
--- a/src/panels/developer-tools/state/developer-tools-state.js
+++ b/src/panels/developer-tools/state/developer-tools-state.js
@@ -1,16 +1,17 @@
import "@material/mwc-button";
import "@polymer/paper-checkbox/paper-checkbox";
import "@polymer/paper-input/paper-input";
-import "@polymer/paper-input/paper-textarea";
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import yaml from "js-yaml";
import "../../../components/entity/ha-entity-picker";
+import "../../../components/ha-code-editor";
import "../../../resources/ha-style";
import { EventsMixin } from "../../../mixins/events-mixin";
+const ERROR_SENTINEL = {};
/*
* @appliesMixin EventsMixin
*/
@@ -27,13 +28,14 @@ class HaPanelDevState extends EventsMixin(PolymerElement) {
direction: ltr;
}
- ha-entity-picker,
- .state-input,
- paper-textarea {
- display: block;
+ .inputs {
max-width: 400px;
}
+ mwc-button {
+ margin-top: 8px;
+ }
+
.entities th {
text-align: left;
}
@@ -66,7 +68,7 @@ class HaPanelDevState extends EventsMixin(PolymerElement) {
}
-
+
Current entities
@@ -166,6 +170,16 @@ class HaPanelDevState extends EventsMixin(PolymerElement) {
type: Object,
},
+ parsedJSON: {
+ type: Object,
+ computed: "_computeParsedStateAttributes(_stateAttributes)",
+ },
+
+ validJSON: {
+ type: Boolean,
+ computed: "_computeValidJSON(parsedJSON)",
+ },
+
_entityId: {
type: String,
value: "",
@@ -229,20 +243,13 @@ class HaPanelDevState extends EventsMixin(PolymerElement) {
}
handleSetState() {
- var attr;
-
- try {
- attr = this._stateAttributes ? yaml.safeLoad(this._stateAttributes) : {};
- } catch (err) {
- /* eslint-disable no-alert */
- alert("Error parsing YAML: " + err);
- /* eslint-enable no-alert */
+ if (!this._entityId) {
+ alert("Entity is a mandatory field");
return;
}
-
this.hass.callApi("POST", "states/" + this._entityId, {
state: this._state,
- attributes: attr,
+ attributes: this.parsedJSON,
});
}
@@ -341,6 +348,22 @@ class HaPanelDevState extends EventsMixin(PolymerElement) {
return output;
}
+
+ _computeParsedStateAttributes(stateAttributes) {
+ try {
+ return stateAttributes.trim() ? yaml.safeLoad(stateAttributes) : {};
+ } catch (err) {
+ return ERROR_SENTINEL;
+ }
+ }
+
+ _computeValidJSON(parsedJSON) {
+ return parsedJSON !== ERROR_SENTINEL;
+ }
+
+ _yamlChanged(ev) {
+ this._stateAttributes = ev.detail.value;
+ }
}
customElements.define("developer-tools-state", HaPanelDevState);
diff --git a/src/panels/developer-tools/template/developer-tools-template.js b/src/panels/developer-tools/template/developer-tools-template.js
index 31e15812a3..998b653b19 100644
--- a/src/panels/developer-tools/template/developer-tools-template.js
+++ b/src/panels/developer-tools/template/developer-tools-template.js
@@ -1,9 +1,9 @@
-import "@polymer/paper-input/paper-textarea";
import "@polymer/paper-spinner/paper-spinner";
import { timeOut } from "@polymer/polymer/lib/utils/async";
import { Debouncer } from "@polymer/polymer/lib/utils/debounce";
import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
+import "../../../components/ha-code-editor";
import "../../../resources/ha-style";
@@ -46,12 +46,6 @@ class HaPanelDevTemplate extends PolymerElement {
right: 8px;
}
- paper-textarea {
- --paper-input-container-input: {
- @apply --paper-font-code1;
- }
- }
-
.rendered {
@apply --paper-font-code1;
clear: both;
@@ -85,11 +79,14 @@ class HaPanelDevTemplate extends PolymerElement {
>
-
Template editor
+
+ on-value-changed="templateChanged"
+ >
@@ -144,7 +141,6 @@ For loop example:
{{ state.name | lower }} is {{state.state_with_unit}}
{%- endfor %}.`,
/* eslint-enable max-len */
- observer: "templateChanged",
},
processed: {
@@ -154,6 +150,11 @@ For loop example:
};
}
+ ready() {
+ super.ready();
+ this.renderTemplate();
+ }
+
computeFormClasses(narrow) {
return narrow ? "content fit" : "content fit layout horizontal";
}
@@ -162,7 +163,8 @@ For loop example:
return error ? "error rendered" : "rendered";
}
- templateChanged() {
+ templateChanged(ev) {
+ this.template = ev.detail.value;
if (this.error) {
this.error = false;
}
diff --git a/src/panels/lovelace/editor/card-editor/hui-card-editor.ts b/src/panels/lovelace/editor/card-editor/hui-card-editor.ts
index 792cd9c118..0825bddbc4 100644
--- a/src/panels/lovelace/editor/card-editor/hui-card-editor.ts
+++ b/src/panels/lovelace/editor/card-editor/hui-card-editor.ts
@@ -17,10 +17,10 @@ import { LovelaceCardEditor } from "../../types";
import { getCardElementTag } from "../../common/get-card-element-tag";
import { computeRTL } from "../../../../common/util/compute_rtl";
-import "../../../../components/ha-yaml-editor";
+import "../../../../components/ha-code-editor";
// This is not a duplicate import, one is for types, one is for element.
// tslint:disable-next-line
-import { HaYamlEditor } from "../../../../components/ha-yaml-editor";
+import { HaCodeEditor } from "../../../../components/ha-code-editor";
import { fireEvent } from "../../../../common/dom/fire_event";
import { EntityConfig } from "../../entity-rows/types";
@@ -65,12 +65,6 @@ export class HuiCardEditor extends LitElement {
try {
this._config = yaml.safeLoad(this.yaml);
this._updateConfigElement();
- setTimeout(() => {
- if (this._yamlEditor) {
- this._yamlEditor.codemirror.refresh();
- }
- fireEvent(this as HTMLElement, "iron-resize");
- }, 1);
this._error = undefined;
} catch (err) {
this._error = err.message;
@@ -94,14 +88,19 @@ export class HuiCardEditor extends LitElement {
return this._error !== undefined;
}
- private get _yamlEditor(): HaYamlEditor {
- return this.shadowRoot!.querySelector("ha-yaml-editor")!;
+ private get _yamlEditor(): HaCodeEditor {
+ return this.shadowRoot!.querySelector("ha-code-editor")! as HaCodeEditor;
}
public toggleMode() {
this._GUImode = !this._GUImode;
}
+ public connectedCallback() {
+ super.connectedCallback();
+ this._refreshYamlEditor();
+ }
+
protected render(): TemplateResult {
return html`
@@ -121,12 +120,14 @@ export class HuiCardEditor extends LitElement {
`
: html`
-
+ .error=${this._error}
+ .rtl=${computeRTL(this.hass)}
+ @value-changed=${this._handleYAMLChanged}
+ >
`}
${this._error
@@ -165,13 +166,25 @@ export class HuiCardEditor extends LitElement {
if (changedProperties.has("_GUImode")) {
if (this._GUImode === false) {
// Refresh code editor when switching to yaml mode
- this._yamlEditor.codemirror.refresh();
- this._yamlEditor.codemirror.focus();
+ this._refreshYamlEditor(true);
}
fireEvent(this as HTMLElement, "iron-resize");
}
}
+ private _refreshYamlEditor(focus = false) {
+ // wait on render
+ setTimeout(() => {
+ if (this._yamlEditor && this._yamlEditor.codemirror) {
+ this._yamlEditor.codemirror.refresh();
+ if (focus) {
+ this._yamlEditor.codemirror.focus();
+ }
+ }
+ fireEvent(this as HTMLElement, "iron-resize");
+ }, 1);
+ }
+
private _handleUIConfigChanged(ev: UIConfigChangedEvent) {
ev.stopPropagation();
const config = ev.detail.config;
diff --git a/src/panels/lovelace/hui-editor.ts b/src/panels/lovelace/hui-editor.ts
index ba225a95f5..169c4b1809 100644
--- a/src/panels/lovelace/hui-editor.ts
+++ b/src/panels/lovelace/hui-editor.ts
@@ -14,10 +14,10 @@ import { Lovelace } from "./types";
import "../../components/ha-icon";
import { haStyle } from "../../resources/styles";
-import "../../components/ha-yaml-editor";
+import "../../components/ha-code-editor";
// This is not a duplicate import, one is for types, one is for element.
// tslint:disable-next-line
-import { HaYamlEditor } from "../../components/ha-yaml-editor";
+import { HaCodeEditor } from "../../components/ha-code-editor";
import { HomeAssistant } from "../../types";
import { computeRTL } from "../../common/util/compute_rtl";
@@ -33,7 +33,7 @@ class LovelaceFullConfigEditor extends LitElement {
public closeEditor?: () => void;
private _saving?: boolean;
private _changed?: boolean;
- private _generation?: number;
+ private _generation = 1;
static get properties() {
return {
@@ -81,14 +81,15 @@ class LovelaceFullConfigEditor extends LitElement {
-
-
+
`;
@@ -96,8 +97,6 @@ class LovelaceFullConfigEditor extends LitElement {
protected firstUpdated() {
this.yamlEditor.value = yaml.safeDump(this.lovelace!.config);
- this.yamlEditor.codemirror.clearHistory();
- this._generation = this.yamlEditor.codemirror.changeGeneration(true);
}
static get styles(): CSSResult[] {
@@ -143,10 +142,9 @@ class LovelaceFullConfigEditor extends LitElement {
}
private _yamlChanged() {
- if (!this._generation) {
- return;
- }
- this._changed = !this.yamlEditor.codemirror.isClean(this._generation);
+ this._changed = !this.yamlEditor
+ .codemirror!.getDoc()
+ .isClean(this._generation);
if (this._changed && !window.onbeforeunload) {
window.onbeforeunload = () => {
return true;
@@ -202,14 +200,16 @@ class LovelaceFullConfigEditor extends LitElement {
} catch (err) {
alert(`Unable to save YAML: ${err}`);
}
- this._generation = this.yamlEditor.codemirror.changeGeneration(true);
+ this._generation = this.yamlEditor
+ .codemirror!.getDoc()
+ .changeGeneration(true);
window.onbeforeunload = null;
this._saving = false;
this._changed = false;
}
- private get yamlEditor(): HaYamlEditor {
- return this.shadowRoot!.querySelector("ha-yaml-editor")!;
+ private get yamlEditor(): HaCodeEditor {
+ return this.shadowRoot!.querySelector("ha-code-editor")! as HaCodeEditor;
}
}
diff --git a/src/resources/codemirror.ondemand.ts b/src/resources/codemirror.ondemand.ts
new file mode 100644
index 0000000000..dd4f59db5e
--- /dev/null
+++ b/src/resources/codemirror.ondemand.ts
@@ -0,0 +1,13 @@
+interface LoadedCodeMirror {
+ codeMirror: any;
+ codeMirrorCss: any;
+}
+
+let loaded: Promise
;
+
+export const loadCodeMirror = async (): Promise => {
+ if (!loaded) {
+ loaded = import(/* webpackChunkName: "codemirror" */ "./codemirror");
+ }
+ return loaded;
+};
diff --git a/src/resources/codemirror.ts b/src/resources/codemirror.ts
new file mode 100644
index 0000000000..a741a8b157
--- /dev/null
+++ b/src/resources/codemirror.ts
@@ -0,0 +1,13 @@
+// @ts-ignore
+import _CodeMirror, { Editor } from "codemirror";
+// @ts-ignore
+import _codeMirrorCss from "codemirror/lib/codemirror.css";
+import "codemirror/mode/yaml/yaml";
+import "codemirror/mode/jinja2/jinja2";
+import { fireEvent } from "../common/dom/fire_event";
+
+_CodeMirror.commands.save = (cm: Editor) => {
+ fireEvent(cm.getWrapperElement(), "editor-save");
+};
+export const codeMirror: any = _CodeMirror;
+export const codeMirrorCss: any = _codeMirrorCss;
diff --git a/yarn.lock b/yarn.lock
index 66fb23f266..6e51ae9efa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1652,6 +1652,13 @@
resolved "https://registry.yarnpkg.com/@types/clone/-/clone-0.1.30.tgz#e7365648c1b42136a59c7d5040637b3b5c83b614"
integrity sha1-5zZWSMG0ITalnH1QQGN7O1yDthQ=
+"@types/codemirror@^0.0.78":
+ version "0.0.78"
+ resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-0.0.78.tgz#75a8eabda268c8e734855fb24e8c86192e2e18ad"
+ integrity sha512-QpMQUpEL+ZNcpEhjvYM/H6jqDx9nNcJqymA2kbkNthFS2I7ekL7ofEZ7+MoQAFTBuJers91K0FGCMpL7MwC9TQ==
+ dependencies:
+ "@types/tern" "*"
+
"@types/compression@^0.0.33":
version "0.0.33"
resolved "https://registry.yarnpkg.com/@types/compression/-/compression-0.0.33.tgz#95dc733a2339aa846381d7f1377792d2553dc27d"
@@ -1686,7 +1693,7 @@
resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-0.0.20.tgz#cae698714dd61ebee5ab3f2aeb9a34ba1011735a"
integrity sha512-6dhZJLbA7aOwkYB2GDGdIqJ20wmHnkDzaxV9PJXe7O02I2dSFTERzRB6JrX6cWKaS+VqhhY7cQUMCbO5kloFUw==
-"@types/estree@0.0.39":
+"@types/estree@*", "@types/estree@0.0.39":
version "0.0.39"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
@@ -1894,6 +1901,13 @@
dependencies:
"@types/node" "*"
+"@types/tern@*":
+ version "0.23.3"
+ resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.3.tgz#4b54538f04a88c9ff79de1f6f94f575a7f339460"
+ integrity sha512-imDtS4TAoTcXk0g7u4kkWqedB3E4qpjXzCpD2LU5M5NAXHzCDsypyvXSaG7mM8DKYkCRa7tFp4tS/lp/Wo7Q3w==
+ dependencies:
+ "@types/estree" "*"
+
"@types/ua-parser-js@^0.7.31":
version "0.7.32"
resolved "https://registry.yarnpkg.com/@types/ua-parser-js/-/ua-parser-js-0.7.32.tgz#8827d451d6702307248073b5d98aa9293d02b5e5"
@@ -4041,10 +4055,10 @@ code-point-at@^1.0.0:
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
-codemirror@^5.45.0:
- version "5.45.0"
- resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.45.0.tgz#db5ebbb3bf44028c684053f3954d011efcec27ad"
- integrity sha512-c19j644usCE8gQaXa0jqn2B/HN9MnB2u6qPIrrhrMkB+QAP42y8G4QnTwuwbVSoUS1jEl7JU9HZMGhCDL0nsAw==
+codemirror@^5.49.0:
+ version "5.49.0"
+ resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.49.0.tgz#adedbffcc81091e4a0334bcb96b1ae3b7ada5e3f"
+ integrity sha512-Hyzr0HToBdZpLBN9dYFO/KlJAsKH37/cXVHPAqa+imml0R92tb9AkmsvjnXL+SluEvjjdfkDgRjc65NG5jnMYA==
collection-map@^1.0.0:
version "1.0.0"