"method"===e.kind&&e.descriptor&&!("value"in e.descriptor)?{...e,finisher(n){n.createProperty(e.key,i);}}:{kind:"field",key:Symbol(),placement:"own",descriptor:{},originalKey:e.key,initializer(){"function"==typeof e.initializer&&(this[e.key]=e.initializer.call(this));},finisher(n){n.createProperty(e.key,i);}};function e$2(e){return (n,t)=>void 0!==t?((i,e,n)=>{e.constructor.createProperty(n,i);})(e,n,t):i$1(e,n)}
+const i$2=(i,e)=>"method"===e.kind&&e.descriptor&&!("value"in e.descriptor)?{...e,finisher(n){n.createProperty(e.key,i);}}:{kind:"field",key:Symbol(),placement:"own",descriptor:{},originalKey:e.key,initializer(){"function"==typeof e.initializer&&(this[e.key]=e.initializer.call(this));},finisher(n){n.createProperty(e.key,i);}};function e$2(e){return (n,t)=>void 0!==t?((i,e,n)=>{e.constructor.createProperty(n,i);})(e,n,t):i$2(e,n)}
+
+/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */function t$1(t){return e$2({...t,state:!0})}
+
+/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+const o$1=({finisher:e,descriptor:t})=>(o,n)=>{var r;if(void 0===n){const n=null!==(r=o.originalKey)&&void 0!==r?r:o.key,i=null!=t?{kind:"method",placement:"prototype",key:n,descriptor:t(o.key)}:{...o,key:n};return null!=e&&(i.finisher=function(t){e(t,n);}),i}{const r=o.constructor;void 0!==t&&Object.defineProperty(o,n,t(n)),null==e||e(r,n);}};
+
+/**
+ * @license
+ * Copyright 2017 Google LLC
+ * SPDX-License-Identifier: BSD-3-Clause
+ */function i$1(i,n){return o$1({descriptor:o=>{const t={get(){var o,n;return null!==(n=null===(o=this.renderRoot)||void 0===o?void 0:o.querySelector(i))&&void 0!==n?n:null},enumerable:!0,configurable:!0};if(n){const n="symbol"==typeof o?Symbol():"__"+o;t.get=function(){var o,t;return void 0===this[n]&&(this[n]=null!==(t=null===(o=this.renderRoot)||void 0===o?void 0:o.querySelector(i))&&void 0!==t?t:null),this[n]};}return t}})}
/**
* @license
@@ -258,6 +277,18 @@ const loadLoadCardHelpers = async () => {
},
]);
await ((_c = (_b = (_a = routes === null || routes === void 0 ? void 0 : routes.routes) === null || _a === void 0 ? void 0 : _a.a) === null || _b === void 0 ? void 0 : _b.load) === null || _c === void 0 ? void 0 : _c.call(_b));
+};
+const loadHaForm = async () => {
+ if (customElements.get("ha-form"))
+ return;
+ await loadLoadCardHelpers();
+ const helpers = await window.loadCardHelpers();
+ if (!helpers)
+ return;
+ const card = await helpers.createCardElement({ type: "entity" });
+ if (!card)
+ return;
+ await card.getConfigElement();
};
const ID_STORAGE_KEY = "browser_mod-browser-id";
@@ -891,10 +922,7 @@ const ServicesMixin = (SuperClass) => {
];
for (const service of cmds) {
this.addEventListener(`command-${service}`, (ev) => {
- this._service_action({
- service,
- data: ev.detail,
- });
+ this.service(service, ev.detail);
});
}
document.body.addEventListener("ll-custom", (ev) => {
@@ -903,6 +931,9 @@ const ServicesMixin = (SuperClass) => {
}
});
}
+ async service(service, data) {
+ this._service_action({ service, data });
+ }
async _service_action({ service, data }) {
let _service = service;
if (!_service.startsWith("browser_mod.") && _service.includes(".")) ;
@@ -1019,7 +1050,7 @@ class BrowserModPopup extends s {
}, 10);
}
}
- async setupDialog(title, content, { right_button = undefined, right_button_action = undefined, left_button = undefined, left_button_action = undefined, dismissable = true, dismiss_action = undefined, timeout = undefined, timeout_action = undefined, } = {}) {
+ async setupDialog(title, content, { right_button = undefined, right_button_action = undefined, left_button = undefined, left_button_action = undefined, dismissable = true, dismiss_action = undefined, timeout = undefined, timeout_action = undefined, size = undefined, } = {}) {
this.title = title;
if (content && typeof content === "object") {
// Create a card from config in content
@@ -1046,6 +1077,8 @@ class BrowserModPopup extends s {
dismiss_action,
timeout_action,
};
+ this.wide = size === "wide" ? "" : undefined;
+ this.fullscreen = size === "fullscreen" ? "" : undefined;
}
_primary() {
var _a, _b, _c;
@@ -1247,6 +1280,12 @@ __decorate([
__decorate([
e$2()
], BrowserModPopup.prototype, "dismissable", void 0);
+__decorate([
+ e$2({ reflect: true })
+], BrowserModPopup.prototype, "wide", void 0);
+__decorate([
+ e$2({ reflect: true })
+], BrowserModPopup.prototype, "fullscreen", void 0);
customElements.define("browser-mod-popup", BrowserModPopup);
const PopupMixin = (SuperClass) => {
return class PopupMixinClass extends SuperClass {
@@ -1336,6 +1375,371 @@ var pjson = {
dependencies: dependencies
};
+const configSchema = [
+ {
+ name: "entity",
+ label: "Entity",
+ selector: { entity: {} },
+ },
+ {
+ name: "title",
+ label: "Title",
+ selector: { text: {} },
+ },
+ {
+ name: "size",
+ selector: {
+ select: { mode: "dropdown", options: ["normal", "wide", "fullscreen"] },
+ },
+ },
+ {
+ type: "grid",
+ schema: [
+ {
+ name: "right_button",
+ label: "Right button",
+ selector: { text: {} },
+ },
+ {
+ name: "left_button",
+ label: "Left button",
+ selector: { text: {} },
+ },
+ ],
+ },
+ {
+ type: "grid",
+ schema: [
+ {
+ name: "right_button_action",
+ label: "Right button action",
+ selector: { object: {} },
+ },
+ {
+ name: "left_button_action",
+ label: "Left button action",
+ selector: { object: {} },
+ },
+ ],
+ },
+ {
+ type: "grid",
+ schema: [
+ {
+ name: "dismissable",
+ label: "User dismissable",
+ selector: { boolean: {} },
+ },
+ {
+ name: "timeout",
+ label: "Auto close timeout (ms)",
+ selector: { number: { mode: "box" } },
+ },
+ ],
+ },
+ {
+ type: "grid",
+ schema: [
+ {
+ name: "dismiss_action",
+ label: "Dismiss action",
+ selector: { object: {} },
+ },
+ {
+ name: "timeout_action",
+ label: "Timeout action",
+ selector: { object: {} },
+ },
+ ],
+ },
+];
+class PopupCardEditor extends s {
+ constructor() {
+ super(...arguments);
+ this._selectedTab = 0;
+ this._cardGUIMode = true;
+ this._cardGUIModeAvailable = true;
+ }
+ setConfig(config) {
+ this._config = config;
+ }
+ connectedCallback() {
+ super.connectedCallback();
+ loadHaForm();
+ }
+ _handleSwitchTab(ev) {
+ this._selectedTab = parseInt(ev.detail.index, 10);
+ }
+ _configChanged(ev) {
+ ev.stopPropagation();
+ if (!this._config)
+ return;
+ this._config = Object.assign({}, ev.detail.value);
+ this.dispatchEvent(new CustomEvent("config-changed", { detail: { config: this._config } }));
+ }
+ _cardConfigChanged(ev) {
+ ev.stopPropagation();
+ if (!this._config)
+ return;
+ const card = Object.assign({}, ev.detail.config);
+ this._config = Object.assign(Object.assign({}, this._config), { card });
+ this._cardGUIModeAvailable = ev.detail.guiModeAvailable;
+ this.dispatchEvent(new CustomEvent("config-changed", { detail: { config: this._config } }));
+ }
+ _toggleCardMode(ev) {
+ var _a;
+ (_a = this._cardEditorEl) === null || _a === void 0 ? void 0 : _a.toggleMode();
+ }
+ _deleteCard(ev) {
+ if (!this._config)
+ return;
+ this._config = Object.assign({}, this._config);
+ delete this._config.card;
+ this.dispatchEvent(new CustomEvent("config-changed", { detail: { config: this._config } }));
+ }
+ _cardGUIModeChanged(ev) {
+ ev.stopPropagation();
+ this._cardGUIMode = ev.detail.guiMode;
+ this._cardGUIModeAvailable = ev.detail.guiModeAvailable;
+ }
+ render() {
+ if (!this.hass || !this._config) {
+ return $ ``;
+ }
+ return $ `
+
+
+
+
+
+
+
+
+ ${[this._renderSettingsEditor, this._renderCardEditor][this._selectedTab].bind(this)()}
+
+
+ `;
+ }
+ _renderSettingsEditor() {
+ return $ `
+ { var _a; return (_a = s.label) !== null && _a !== void 0 ? _a : s.name; }}
+ @value-changed=${this._configChanged}
+ >
+
`;
+ }
+ _renderCardEditor() {
+ return $ `
+
+ ${this._config.card
+ ? $ `
+
+
+ ${!this._cardEditorEl || this._cardGUIMode
+ ? "Show code editor"
+ : "Show visual editor"}
+
+
+ Change card type
+
+
+
+ `
+ : $ `
+
+ `}
+
+ `;
+ }
+ static get styles() {
+ return r$2 `
+ mwc-tab-bar {
+ border-bottom: 1px solid var(--divider-color);
+ }
+ .box {
+ margin-top: 8px;
+ border: 1px solid var(--divider-color);
+ padding: 12px;
+ }
+ .box .toolbar {
+ display: flex;
+ justify-content: flex-end;
+ width: 100%;
+ gap: 8px;
+ }
+ .gui-mode-button {
+ margin-right: auto;
+ }
+ `;
+ }
+}
+__decorate([
+ t$1()
+], PopupCardEditor.prototype, "_config", void 0);
+__decorate([
+ e$2()
+], PopupCardEditor.prototype, "lovelace", void 0);
+__decorate([
+ e$2()
+], PopupCardEditor.prototype, "hass", void 0);
+__decorate([
+ t$1()
+], PopupCardEditor.prototype, "_selectedTab", void 0);
+__decorate([
+ t$1()
+], PopupCardEditor.prototype, "_cardGUIMode", void 0);
+__decorate([
+ t$1()
+], PopupCardEditor.prototype, "_cardGUIModeAvailable", void 0);
+__decorate([
+ i$1("hui-card-element-editor")
+], PopupCardEditor.prototype, "_cardEditorEl", void 0);
+(async () => {
+ while (!window.browser_mod) {
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ }
+ await window.browser_mod.connectionPromise;
+ if (!customElements.get("popup-card-editor"))
+ customElements.define("popup-card-editor", PopupCardEditor);
+ window.customCards = window.customCards || [];
+ window.customCards.push({
+ type: "popup-card",
+ name: "Popup card",
+ preview: false,
+ description: "Replace the more-info dialog for a given entity in the view that includes this card. (Browser Mod)",
+ });
+})();
+
+class PopupCard extends s {
+ constructor() {
+ super();
+ this.popup = this.popup.bind(this);
+ }
+ static getConfigElement() {
+ return document.createElement("popup-card-editor");
+ }
+ static getStubConfig(hass, entities) {
+ const entity = entities[0];
+ return {
+ entity,
+ title: "Custom popup",
+ dismissable: true,
+ card: { type: "markdown", content: "This replaces the more-info dialog" },
+ };
+ }
+ setConfig(config) {
+ this._config = config;
+ (async () => {
+ const ch = await window.loadCardHelpers();
+ this._element = await ch.createCardElement(config.card);
+ this._element.hass = this.hass;
+ })();
+ }
+ async connectedCallback() {
+ super.connectedCallback();
+ window.addEventListener("hass-more-info", this.popup);
+ if (this.parentElement.localName === "hui-card-preview") {
+ this.editMode = true;
+ }
+ }
+ async disconnectedCallback() {
+ super.disconnectedCallback();
+ window.removeEventListener("hass-more-info", this.popup);
+ }
+ popup(ev) {
+ var _a, _b;
+ if (((_a = ev.detail) === null || _a === void 0 ? void 0 : _a.entityId) === this._config.entity) {
+ ev.stopPropagation();
+ ev.preventDefault();
+ const config = Object.assign({}, this._config);
+ delete config.card;
+ (_b = window.browser_mod) === null || _b === void 0 ? void 0 : _b.service("popup", Object.assign({ content: this._config.card }, this._config));
+ setTimeout(() => this.dispatchEvent(new CustomEvent("hass-more-info", {
+ bubbles: true,
+ composed: true,
+ cancelable: false,
+ detail: { entityID: "." },
+ })), 50);
+ }
+ }
+ updated(changedProperties) {
+ super.updated(changedProperties);
+ if (changedProperties.has("hass")) {
+ if (this._element)
+ this._element.hass = this.hass;
+ }
+ }
+ render() {
+ if (!this.editMode)
+ return $ ``;
+ return $ `
+
+
${this._config.title}
+
+ ${this._element}`;
+ }
+ static get styles() {
+ return r$2 `
+ :host {
+ display: none !important;
+ }
+ :host([edit-mode="true"]) {
+ display: block !important;
+ border: 1px solid var(--primary-color);
+ }
+ h2 {
+ padding-left: 16px;
+ padding-top: 16px;
+ margin: 0;
+ }
+ `;
+ }
+}
+__decorate([
+ e$2()
+], PopupCard.prototype, "hass", void 0);
+__decorate([
+ t$1()
+], PopupCard.prototype, "_config", void 0);
+__decorate([
+ e$2({ attribute: "edit-mode", reflect: true })
+], PopupCard.prototype, "editMode", void 0);
+__decorate([
+ t$1()
+], PopupCard.prototype, "_element", void 0);
+(async () => {
+ while (!window.browser_mod) {
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ }
+ await window.browser_mod.connectionPromise;
+ if (!customElements.get("popup-card"))
+ customElements.define("popup-card", PopupCard);
+})();
+
/*
TODO:
- Fix nomenclature
@@ -1346,6 +1750,7 @@ var pjson = {
- Card-mod integration
X Timeout
X Fullscreen
+ x Popup-card
x Motion/occupancy tracker
x Information about interaction requirement
x Information about fullykiosk
diff --git a/custom_components/browser_mod/services.yaml b/custom_components/browser_mod/services.yaml
index fce57e2..1b1cd25 100644
--- a/custom_components/browser_mod/services.yaml
+++ b/custom_components/browser_mod/services.yaml
@@ -61,6 +61,15 @@ popup:
description: "Popup content (Test or lovelace card configuration)"
selector:
object:
+ size:
+ name: Size
+ selector:
+ select:
+ mode: dropdown
+ options:
+ - normal
+ - wide
+ - fullscreen
right_button:
name: Right button
description: Text of the right button
@@ -99,7 +108,7 @@ popup:
number:
mode: box
timeout_action:
- name: Timeout
+ name: Timeout action
description: Action to perform when popup is closed by timeout
selector:
object:
diff --git a/js/helpers.ts b/js/helpers.ts
index c7755fe..4f0993e 100644
--- a/js/helpers.ts
+++ b/js/helpers.ts
@@ -75,3 +75,13 @@ export const loadLoadCardHelpers = async () => {
]);
await routes?.routes?.a?.load?.();
};
+
+export const loadHaForm = async () => {
+ if (customElements.get("ha-form")) return;
+ await loadLoadCardHelpers();
+ const helpers = await window.loadCardHelpers();
+ if (!helpers) return;
+ const card = await helpers.createCardElement({ type: "entity" });
+ if (!card) return;
+ await card.getConfigElement();
+};
diff --git a/js/plugin/main.ts b/js/plugin/main.ts
index 8e00f65..7215945 100644
--- a/js/plugin/main.ts
+++ b/js/plugin/main.ts
@@ -13,6 +13,7 @@ import { ActivityMixin } from "./activity";
import "./popups";
import { PopupMixin } from "./popups";
import pjson from "../../package.json";
+import "./popup-card";
/*
TODO:
@@ -24,6 +25,7 @@ import pjson from "../../package.json";
- Card-mod integration
X Timeout
X Fullscreen
+ x Popup-card
x Motion/occupancy tracker
x Information about interaction requirement
x Information about fullykiosk
diff --git a/js/plugin/popup-card-editor.ts b/js/plugin/popup-card-editor.ts
new file mode 100644
index 0000000..bd03bd3
--- /dev/null
+++ b/js/plugin/popup-card-editor.ts
@@ -0,0 +1,264 @@
+import { LitElement, html, css } from "lit";
+import { property, query, state } from "lit/decorators.js";
+import { loadHaForm } from "../helpers";
+
+const configSchema = [
+ {
+ name: "entity",
+ label: "Entity",
+ selector: { entity: {} },
+ },
+ {
+ name: "title",
+ label: "Title",
+ selector: { text: {} },
+ },
+ {
+ name: "size",
+ selector: {
+ select: { mode: "dropdown", options: ["normal", "wide", "fullscreen"] },
+ },
+ },
+ {
+ type: "grid",
+ schema: [
+ {
+ name: "right_button",
+ label: "Right button",
+ selector: { text: {} },
+ },
+ {
+ name: "left_button",
+ label: "Left button",
+ selector: { text: {} },
+ },
+ ],
+ },
+ {
+ type: "grid",
+ schema: [
+ {
+ name: "right_button_action",
+ label: "Right button action",
+ selector: { object: {} },
+ },
+ {
+ name: "left_button_action",
+ label: "Left button action",
+ selector: { object: {} },
+ },
+ ],
+ },
+ {
+ type: "grid",
+ schema: [
+ {
+ name: "dismissable",
+ label: "User dismissable",
+ selector: { boolean: {} },
+ },
+ {
+ name: "timeout",
+ label: "Auto close timeout (ms)",
+ selector: { number: { mode: "box" } },
+ },
+ ],
+ },
+ {
+ type: "grid",
+ schema: [
+ {
+ name: "dismiss_action",
+ label: "Dismiss action",
+ selector: { object: {} },
+ },
+ {
+ name: "timeout_action",
+ label: "Timeout action",
+ selector: { object: {} },
+ },
+ ],
+ },
+];
+
+class PopupCardEditor extends LitElement {
+ @state() _config;
+
+ @property() lovelace;
+ @property() hass;
+
+ @state() _selectedTab = 0;
+ @state() _cardGUIMode = true;
+ @state() _cardGUIModeAvailable = true;
+
+ @query("hui-card-element-editor") private _cardEditorEl?;
+
+ setConfig(config) {
+ this._config = config;
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ loadHaForm();
+ }
+
+ _handleSwitchTab(ev: CustomEvent) {
+ this._selectedTab = parseInt(ev.detail.index, 10);
+ }
+
+ _configChanged(ev: CustomEvent) {
+ ev.stopPropagation();
+ if (!this._config) return;
+ this._config = { ...ev.detail.value };
+ this.dispatchEvent(
+ new CustomEvent("config-changed", { detail: { config: this._config } })
+ );
+ }
+
+ _cardConfigChanged(ev: CustomEvent) {
+ ev.stopPropagation();
+ if (!this._config) return;
+ const card = { ...ev.detail.config };
+ this._config = { ...this._config, card };
+ this._cardGUIModeAvailable = ev.detail.guiModeAvailable;
+
+ this.dispatchEvent(
+ new CustomEvent("config-changed", { detail: { config: this._config } })
+ );
+ }
+ _toggleCardMode(ev) {
+ this._cardEditorEl?.toggleMode();
+ }
+ _deleteCard(ev) {
+ if (!this._config) return;
+ this._config = { ...this._config };
+ delete this._config.card;
+
+ this.dispatchEvent(
+ new CustomEvent("config-changed", { detail: { config: this._config } })
+ );
+ }
+ _cardGUIModeChanged(ev: CustomEvent) {
+ ev.stopPropagation();
+ this._cardGUIMode = ev.detail.guiMode;
+ this._cardGUIModeAvailable = ev.detail.guiModeAvailable;
+ }
+
+ render() {
+ if (!this.hass || !this._config) {
+ return html``;
+ }
+
+ return html`
+
+
+
+
+
+
+
+
+ ${[this._renderSettingsEditor, this._renderCardEditor][
+ this._selectedTab
+ ].bind(this)()}
+
+
+ `;
+ }
+
+ _renderSettingsEditor() {
+ return html`
+ s.label ?? s.name}
+ @value-changed=${this._configChanged}
+ >
+
`;
+ }
+
+ _renderCardEditor() {
+ return html`
+
+ ${this._config.card
+ ? html`
+
+
+ ${!this._cardEditorEl || this._cardGUIMode
+ ? "Show code editor"
+ : "Show visual editor"}
+
+
+ Change card type
+
+
+
+ `
+ : html`
+
+ `}
+
+ `;
+ }
+
+ static get styles() {
+ return css`
+ mwc-tab-bar {
+ border-bottom: 1px solid var(--divider-color);
+ }
+ .box {
+ margin-top: 8px;
+ border: 1px solid var(--divider-color);
+ padding: 12px;
+ }
+ .box .toolbar {
+ display: flex;
+ justify-content: flex-end;
+ width: 100%;
+ gap: 8px;
+ }
+ .gui-mode-button {
+ margin-right: auto;
+ }
+ `;
+ }
+}
+
+(async () => {
+ while (!window.browser_mod) {
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ }
+ await window.browser_mod.connectionPromise;
+
+ if (!customElements.get("popup-card-editor"))
+ customElements.define("popup-card-editor", PopupCardEditor);
+ (window as any).customCards = (window as any).customCards || [];
+ (window as any).customCards.push({
+ type: "popup-card",
+ name: "Popup card",
+ preview: false,
+ description:
+ "Replace the more-info dialog for a given entity in the view that includes this card. (Browser Mod)",
+ });
+})();
diff --git a/js/plugin/popup-card.ts b/js/plugin/popup-card.ts
new file mode 100644
index 0000000..a5deea0
--- /dev/null
+++ b/js/plugin/popup-card.ts
@@ -0,0 +1,123 @@
+import { LitElement, html, css } from "lit";
+import { property, state } from "lit/decorators.js";
+
+import "./popup-card-editor";
+
+class PopupCard extends LitElement {
+ @property() hass;
+ @state() _config;
+ @property({ attribute: "edit-mode", reflect: true }) editMode;
+ @state() _element;
+
+ static getConfigElement() {
+ return document.createElement("popup-card-editor");
+ }
+
+ static getStubConfig(hass, entities) {
+ const entity = entities[0];
+ return {
+ entity,
+ title: "Custom popup",
+ dismissable: true,
+ card: { type: "markdown", content: "This replaces the more-info dialog" },
+ };
+ }
+
+ constructor() {
+ super();
+ this.popup = this.popup.bind(this);
+ }
+
+ setConfig(config) {
+ this._config = config;
+ (async () => {
+ const ch = await window.loadCardHelpers();
+ this._element = await ch.createCardElement(config.card);
+ this._element.hass = this.hass;
+ })();
+ }
+
+ async connectedCallback() {
+ super.connectedCallback();
+ window.addEventListener("hass-more-info", this.popup);
+
+ if (this.parentElement.localName === "hui-card-preview") {
+ this.editMode = true;
+ }
+ }
+
+ async disconnectedCallback() {
+ super.disconnectedCallback();
+ window.removeEventListener("hass-more-info", this.popup);
+ }
+
+ popup(ev: CustomEvent) {
+ if (ev.detail?.entityId === this._config.entity) {
+ ev.stopPropagation();
+ ev.preventDefault();
+ const config = { ...this._config };
+ delete config.card;
+
+ window.browser_mod?.service("popup", {
+ content: this._config.card,
+ ...this._config,
+ });
+ setTimeout(
+ () =>
+ this.dispatchEvent(
+ new CustomEvent("hass-more-info", {
+ bubbles: true,
+ composed: true,
+ cancelable: false,
+ detail: { entityID: "." },
+ })
+ ),
+ 50
+ );
+ }
+ }
+
+ updated(changedProperties) {
+ super.updated(changedProperties);
+ if (changedProperties.has("hass")) {
+ if (this._element) this._element.hass = this.hass;
+ }
+ }
+
+ render() {
+ if (!this.editMode) return html``;
+ return html`
+
+
${this._config.title}
+
+ ${this._element}`;
+ }
+
+ static get styles() {
+ return css`
+ :host {
+ display: none !important;
+ }
+ :host([edit-mode="true"]) {
+ display: block !important;
+ border: 1px solid var(--primary-color);
+ }
+ h2 {
+ padding-left: 16px;
+ padding-top: 16px;
+ margin: 0;
+ }
+ `;
+ }
+}
+
+(async () => {
+ while (!window.browser_mod) {
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ }
+ await window.browser_mod.connectionPromise;
+
+ if (!customElements.get("popup-card"))
+ customElements.define("popup-card", PopupCard);
+})();
diff --git a/js/plugin/popups.ts b/js/plugin/popups.ts
index aa41b88..ee5d1ad 100644
--- a/js/plugin/popups.ts
+++ b/js/plugin/popups.ts
@@ -12,6 +12,8 @@ class BrowserModPopup extends LitElement {
@property() right_button;
@property() left_button;
@property() dismissable;
+ @property({ reflect: true }) wide;
+ @property({ reflect: true }) fullscreen;
_actions;
timeout;
_timeoutStart;
@@ -47,6 +49,7 @@ class BrowserModPopup extends LitElement {
dismiss_action = undefined,
timeout = undefined,
timeout_action = undefined,
+ size = undefined,
} = {}
) {
this.title = title;
@@ -76,6 +79,8 @@ class BrowserModPopup extends LitElement {
dismiss_action,
timeout_action,
};
+ this.wide = size === "wide" ? "" : undefined;
+ this.fullscreen = size === "fullscreen" ? "" : undefined;
}
_primary() {
diff --git a/js/plugin/services.ts b/js/plugin/services.ts
index 07a9582..a163d07 100644
--- a/js/plugin/services.ts
+++ b/js/plugin/services.ts
@@ -68,10 +68,7 @@ export const ServicesMixin = (SuperClass) => {
];
for (const service of cmds) {
this.addEventListener(`command-${service}`, (ev) => {
- this._service_action({
- service,
- data: ev.detail,
- });
+ this.service(service, ev.detail);
});
}
@@ -82,6 +79,10 @@ export const ServicesMixin = (SuperClass) => {
});
}
+ async service(service, data) {
+ this._service_action({ service, data });
+ }
+
async _service_action({ service, data }) {
let _service: String = service;
if (!_service.startsWith("browser_mod.") && _service.includes(".")) {