Easier to use frontend options. Set sidebar title.

This commit is contained in:
Thomas Lovén 2022-09-01 15:38:23 +00:00
parent 39f727206f
commit fffb017287
13 changed files with 821 additions and 506 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@
"dependencies": ["panel_custom", "websocket_api", "http", "frontend", "lovelace"],
"codeowners": [],
"requirements": [],
"version": "2.0.0b4",
"version": "2.0.0b5",
"iot_class": "local_push",
"config_flow": true
}

View File

@ -16,6 +16,7 @@ class SettingsStoreData:
defaultPanel = attr.ib(type=str, default=None)
sidebarPanelOrder = attr.ib(type=list, default=None)
sidebarHiddenPanels = attr.ib(type=list, default=None)
sidebarTitle = attr.ib(type=str, default=None)
faviconTemplate = attr.ib(type=str, default=None)
titleTemplate = attr.ib(type=str, default=None)

View File

@ -0,0 +1,294 @@
import { LitElement, html, css } from "lit";
import { property } from "lit/decorators.js";
import { selectTree } from "../helpers";
class BrowserModSettingsTable extends LitElement {
@property() settingKey;
@property() settingSelector = {
template: {},
};
@property() hass;
@property() default;
@property() tableData = [];
_users = undefined;
firstUpdated() {
window.browser_mod.addEventListener("browser-mod-config-update", () =>
this.updateTable()
);
}
updated(changedProperties) {
if (changedProperties.has("settingKey")) this.updateTable();
if (
changedProperties.has("hass") &&
changedProperties.get("hass") === undefined
)
this.updateTable();
}
async fetchUsers(): Promise<any[]> {
if (this._users === undefined)
this._users = await this.hass.callWS({ type: "config/auth/list" });
return this._users;
}
clearSetting(type, target) {
const clearSettingCallback = async () => {
if (this.settingKey === "sidebarPanelOrder") {
const sideBar: any = await selectTree(
document,
"home-assistant $ home-assistant-main $ app-drawer-layout app-drawer ha-sidebar"
);
window.browser_mod.setSetting(type, target, {
sidebarHiddenPanels: "[]",
sidebarPanelOrder: "[]",
});
window.browser_mod.setSetting(type, target, {
sidebarHiddenPanels: undefined,
sidebarPanelOrder: undefined,
});
return;
}
if (this.default)
window.browser_mod.setSetting(type, target, {
[this.settingKey]: this.default,
});
window.browser_mod.setSetting(type, target, {
[this.settingKey]: undefined,
});
};
window.browser_mod?.showPopup(
"Are you sure",
"Do you wish to clear this setting?",
{
right_button: "Yes",
right_button_action: clearSettingCallback,
left_button: "No",
}
);
}
changeSetting(type, target) {
const changeSettingCallback = async (newValue) => {
if (this.settingKey === "sidebarPanelOrder") {
const sideBar: any = await selectTree(
document,
"home-assistant $ home-assistant-main $ app-drawer-layout app-drawer ha-sidebar"
);
window.browser_mod.setSetting(type, target, {
sidebarHiddenPanels: JSON.stringify(sideBar._hiddenPanels),
sidebarPanelOrder: JSON.stringify(sideBar._panelOrder),
});
console.log(sideBar._hiddenPanels, sideBar._panelOrder);
return;
}
let value = newValue.value;
window.browser_mod.setSetting(type, target, { [this.settingKey]: value });
};
const settings = window.browser_mod?.getSetting?.(this.settingKey);
const def =
(type === "global" ? settings.global : settings[type][target]) ??
this.default;
window.browser_mod?.showPopup(
"Change value",
(this.settingSelector as any).plaintext ?? [
{
name: "value",
label: (this.settingSelector as any).label ?? "",
default: def,
selector: this.settingSelector,
},
],
{
right_button: "OK",
right_button_action: changeSettingCallback,
left_button: "Cancel",
}
);
}
addBrowserSetting() {
const settings = window.browser_mod?.getSetting?.(this.settingKey);
const allBrowsers = window.browser_mod._data.browsers;
const browsers = [];
for (const target of Object.keys(allBrowsers)) {
if (settings.browser[target] == null) browsers.push(target);
}
if (browsers.length === 0) {
window.browser_mod.showPopup(
"No browsers to configure",
"All registered browsers have already been configured.",
{ right_button: "OK" }
);
return;
}
window.browser_mod.showPopup(
"Select browser to configure",
[
{
name: "browser",
label: "",
selector: {
select: { options: browsers },
},
},
],
{
right_button: "Next",
right_button_action: (value) =>
this.changeSetting("browser", value.browser),
left_button: "Cancel",
}
);
}
async addUserSetting() {
const settings = window.browser_mod?.getSetting?.(this.settingKey);
const allUsers = await this.fetchUsers();
const users = [];
for (const target of allUsers) {
if (target.username && settings.user[target.id] == null)
users.push({ label: target.name, value: target.id });
}
if (users.length === 0) {
window.browser_mod.showPopup(
"No users to configure",
"All users have already been configured.",
{ right_button: "OK" }
);
return;
}
window.browser_mod.showPopup(
"Select user to configure",
[
{
name: "user",
label: "",
selector: {
select: { options: users },
},
},
],
{
right_button: "Next",
right_button_action: (value) => this.changeSetting("user", value.user),
left_button: "Cancel",
}
);
}
async updateTable() {
if (this.hass === undefined) return;
const users = await this.fetchUsers();
const settings = window.browser_mod?.getSetting?.(this.settingKey);
const data = [];
for (const [k, v] of Object.entries(settings.user)) {
const user = users.find((usr) => usr.id === k);
data.push({
name: `User: ${user.name}`,
value: String(v),
controls: html`
<ha-icon-button @click=${() => this.changeSetting("user", k)}>
<ha-icon .icon=${"mdi:pencil"} style="display:flex;"></ha-icon>
</ha-icon-button>
<ha-icon-button @click=${() => this.clearSetting("user", k)}>
<ha-icon .icon=${"mdi:delete"} style="display:flex;"></ha-icon>
</ha-icon-button>
`,
});
}
data.push({
name: "",
value: html`
<mwc-button @click=${() => this.addUserSetting()}>
<ha-icon .icon=${"mdi:plus"}></ha-icon>
Add user setting
</mwc-button>
`,
});
for (const [k, v] of Object.entries(settings.browser)) {
data.push({
name: `Browser: ${k}`,
value: String(v),
controls: html`
<ha-icon-button @click=${() => this.changeSetting("browser", k)}>
<ha-icon .icon=${"mdi:pencil"} style="display:flex;"></ha-icon>
</ha-icon-button>
<ha-icon-button @click=${() => this.clearSetting("browser", k)}>
<ha-icon .icon=${"mdi:delete"} style="display:flex;"></ha-icon>
</ha-icon-button>
`,
});
}
data.push({
name: "",
value: html`
<mwc-button @click=${() => this.addBrowserSetting()}>
<ha-icon .icon=${"mdi:plus"}></ha-icon>
Add browser setting
</mwc-button>
`,
});
data.push({
name: "GLOBAL",
value:
settings.global != null
? String(settings.global)
: html`<span style="color: var(--warning-color);">DEFAULT</span>`,
controls: html`
<ha-icon-button @click=${() => this.changeSetting("global", null)}>
<ha-icon .icon=${"mdi:pencil"} style="display:flex;"></ha-icon>
</ha-icon-button>
<ha-icon-button @click=${() => this.clearSetting("global", null)}>
<ha-icon .icon=${"mdi:delete"} style="display:flex;"></ha-icon>
</ha-icon-button>
`,
});
this.tableData = data;
}
render() {
const global = window.browser_mod?.global_settings?.[this.settingKey];
const columns = {
name: {
title: "Name",
grows: true,
},
value: {
title: "Value",
grows: true,
},
controls: {},
};
return html`
<ha-data-table .columns=${columns} .data=${this.tableData} auto-height>
</ha-data-table>
`;
}
static get styles() {
return css`
:host {
display: block;
}
`;
}
}
customElements.define("browser-mod-settings-table", BrowserModSettingsTable);

View File

@ -136,7 +136,7 @@ class BrowserModRegisteredBrowsersCard extends LitElement {
private _renderInteractionAlert() {
return html`
<ha-alert title="Interaction requirement">
For security reasons many browsers require the user to interact with a
For privacy reasons many browsers require the user to interact with a
webpage before allowing audio playback or video capture. This may affect
the
<code>media_player</code> and <code>camera</code> components of Browser

View File

@ -1,38 +1,73 @@
import { LitElement, html, css } from "lit";
import { property, state } from "lit/decorators.js";
import { loadDeveloperToolsTemplate } from "../helpers";
import { loadDeveloperToolsTemplate, selectTree } from "../helpers";
import "./browser-mod-settings-table";
loadDeveloperToolsTemplate();
class BrowserModFrontendSettingsCard extends LitElement {
@property() hass;
@state() _selectedTab = 0;
@state() _dashboards = [];
@state() _editSidebar = false;
_savedSidebar = { panelOrder: [], hiddenPanels: [] };
firstUpdated() {
window.browser_mod.addEventListener("browser-mod-config-update", () =>
this.requestUpdate()
);
window.browser_mod.addEventListener("browser-mod-favicon-update", () =>
this.requestUpdate()
);
}
_handleSwitchTab(ev: CustomEvent) {
this._selectedTab = parseInt(ev.detail.index, 10);
updated(changedProperties) {
if (
changedProperties.has("hass") &&
changedProperties.get("hass") === undefined
) {
(async () =>
(this._dashboards = await this.hass.callWS({
type: "lovelace/dashboards/list",
})))();
}
}
async toggleEditSidebar() {
const sideBar: any = await selectTree(
document,
"home-assistant $ home-assistant-main $ app-drawer-layout app-drawer ha-sidebar"
);
sideBar.editMode = !sideBar.editMode;
this._editSidebar = sideBar.editMode;
if (this._editSidebar) {
this._savedSidebar = {
panelOrder: sideBar._panelOrder,
hiddenPanels: sideBar._hiddenPanels,
};
} else {
sideBar._panelOrder = this._savedSidebar.panelOrder ?? [];
sideBar._hiddenPanels = this._savedSidebar.hiddenPanels ?? [];
this._savedSidebar = { panelOrder: [], hiddenPanels: [] };
}
}
render() {
const level = ["user", "browser", "global"][this._selectedTab];
const db = this._dashboards.map((d) => {
return { value: d.url_path, label: d.title };
});
const dashboardSelector = {
select: {
options: [{ value: "lovelace", label: "lovelace (default)" }, ...db],
custom_value: true,
},
};
return html`
<ha-card header="Frontend Settings" outlined>
<div class="card-content">
<ha-alert alert-type="warning">
<p>
Please note: The settings in this section severely change the way the Home
<ha-alert alert-type="warning" title="Please note:">
The settings in this section severely change the way the Home
Assistant frontend works and looks. It is very easy to forget that
you made a setting here when you switch devices or user.
</p>
<p>
Do not report any issues to Home Assistant before clearing
<b>EVERY</b> setting here and thouroghly clearing all your browser
@ -41,234 +76,119 @@ class BrowserModFrontendSettingsCard extends LitElement {
</p>
</ha-alert>
<p>
Global settings are applied for all users and browsers.</br>
User settings are applied to the current user and overrides any Global settings.</br>
Browser settings are applied for the current browser and overrides any User or Global settings.
Settings below are applied by first match. I.e. if a matching User
setting exists, it will be applied. Otherwise any matching Browser
setting and otherwise the GLOBAL setting if that differs from
DEFAULT.
</p>
<mwc-tab-bar
.activeIndex=${this._selectedTab}
@MDCTabBar:activated=${this._handleSwitchTab}
>
<mwc-tab .label=${"User (" + this.hass.user.name + ")"}></mwc-tab>
<ha-icon .icon=${"mdi:chevron-double-right"}></ha-icon>
<mwc-tab .label=${"Browser"}></mwc-tab>
<ha-icon .icon=${"mdi:chevron-double-right"}></ha-icon>
<mwc-tab .label=${"Global"}></mwc-tab>
</mwc-tab-bar>
${this._render_settings(level)}
</div>
</ha-card>
`;
}
_render_settings(level) {
const global = window.browser_mod.global_settings;
const browser = window.browser_mod.browser_settings;
const user = window.browser_mod.user_settings;
const current = { global, browser, user }[level];
const DESC_BOOLEAN = (val) =>
({ true: "Enabled", false: "Disabled", undefined: "Unset" }[String(val)]);
const DESC_SET_UNSET = (val) => (val === undefined ? "Unset" : "Set");
const OVERRIDDEN = (key) => {
if (level !== "browser" && browser[key] !== undefined)
return html`<br />Overridden by browser setting`;
if (level === "global" && user[key] !== undefined)
return html`<br />Overridden by user setting`;
};
return html`
<div class="box">
<ha-settings-row>
<span slot="heading">Favicon template</span>
${OVERRIDDEN("faviconTemplate")}
<img src="${window.browser_mod._currentFavicon}" class="favicon" />
</ha-settings-row>
<ha-code-editor
.hass=${this.hass}
.value=${current.faviconTemplate}
@value-changed=${(ev) => {
const tpl = ev.detail.value || undefined;
window.browser_mod.set_setting("faviconTemplate", tpl, level);
}}
></ha-code-editor>
<ha-settings-row>
<mwc-button
@click=${() =>
window.browser_mod.set_setting(
"faviconTemplate",
undefined,
level
)}
>
Clear
</mwc-button>
</ha-settings-row>
<div class="separator"></div>
<ha-settings-row>
<span slot="heading">Title template</span>
${OVERRIDDEN("titleTemplate")}
<span slot="description">
Jinja template for the browser window/tab title
</span>
</ha-settings-row>
<ha-code-editor
<browser-mod-settings-table
.hass=${this.hass}
.value=${current.titleTemplate}
@value-changed=${(ev) => {
const tpl = ev.detail.value || undefined;
window.browser_mod.set_setting("titleTemplate", tpl, level);
}}
></ha-code-editor>
<ha-settings-row>
<mwc-button
@click=${() =>
window.browser_mod.set_setting("titleTemplate", undefined, level)}
>
Clear
</mwc-button>
</ha-settings-row>
.settingKey=${"titleTemplate"}
></browser-mod-settings-table>
<div class="separator"></div>
<ha-settings-row>
<span slot="heading">Hide Sidebar</span>
<span slot="description">Hide the sidebar and hamburger menu</span>
Currently: ${DESC_BOOLEAN(current.hideSidebar)}
${OVERRIDDEN("hideSidebar")}
</ha-settings-row>
<ha-settings-row>
<mwc-button
@click=${() =>
window.browser_mod.set_setting("hideSidebar", true, level)}
>
Enable
</mwc-button>
<mwc-button
@click=${() =>
window.browser_mod.set_setting("hideSidebar", false, level)}
>
Disable
</mwc-button>
<mwc-button
@click=${() =>
window.browser_mod.set_setting("hideSidebar", undefined, level)}
>
Clear
</mwc-button>
<span slot="heading">Favicon template</span>
<span slot="description">
Jinja template for the browser favicon
</span>
</ha-settings-row>
<browser-mod-settings-table
.hass=${this.hass}
.settingKey=${"faviconTemplate"}
></browser-mod-settings-table>
<div class="separator"></div>
<ha-settings-row>
<span slot="heading">Hide Header</span>
<span slot="description">Hide the header on all pages</span>
Currently: ${DESC_BOOLEAN(current.hideHeader)}
${OVERRIDDEN("hideHeader")}
<span slot="heading">Hide sidebar</span>
<span slot="description">
Completely remove the sidebar from all panels
</span>
</ha-settings-row>
<browser-mod-settings-table
.hass=${this.hass}
.settingKey=${"hideSidebar"}
.settingSelector=${{ boolean: {}, label: "Hide sidebar" }}
></browser-mod-settings-table>
<div class="separator"></div>
<ha-settings-row>
<mwc-button
@click=${() =>
window.browser_mod.set_setting("hideHeader", true, level)}
>
Enable
</mwc-button>
<mwc-button
@click=${() =>
window.browser_mod.set_setting("hideHeader", false, level)}
>
Disable
</mwc-button>
<mwc-button
@click=${() =>
window.browser_mod.set_setting("hideHeader", undefined, level)}
>
Clear
</mwc-button>
<span slot="heading">Hide header</span>
<span slot="description">
Completely remove the header from all panels
</span>
</ha-settings-row>
<browser-mod-settings-table
.hass=${this.hass}
.settingKey=${"hideHeader"}
.settingSelector=${{ boolean: {}, label: "Hide header" }}
></browser-mod-settings-table>
<div class="separator"></div>
<ha-settings-row>
<span slot="heading">Default dashboard</span>
<span slot="description">
The dashboard that is showed when navigating to
${location.origin}/
</span>
</ha-settings-row>
<browser-mod-settings-table
.hass=${this.hass}
.settingKey=${"defaultPanel"}
.settingSelector=${dashboardSelector}
.default=${"lovelace"}
></browser-mod-settings-table>
<div class="separator"></div>
<ha-settings-row>
<span slot="heading">Sidebar order</span>
<span slot="description">
Order and visibility of sidebar buttons
Order and visibility of sidebar items. <br />Click EDIT and set
the sidebar up as you want. Then save the settings and finally
click RESTORE.
</span>
Currently: ${DESC_SET_UNSET(current.sidebarPanelOrder)}
${OVERRIDDEN("sidebarPanelOrder")}
</ha-settings-row>
<ha-settings-row>
<span slot="description">
Clearing this does NOT restore the original default order.
</span>
<mwc-button
@click=${() => {
window.browser_mod.set_setting(
"sidebarPanelOrder",
localStorage.getItem("sidebarPanelOrder"),
level
);
window.browser_mod.set_setting(
"sidebarHiddenPanels",
localStorage.getItem("sidebarHiddenPanels"),
level
);
}}
>
Set
</mwc-button>
<mwc-button
@click=${() => {
window.browser_mod.set_setting(
"sidebarPanelOrder",
undefined,
level
);
window.browser_mod.set_setting(
"sidebarHiddenPanels",
undefined,
level
);
}}
>
Clear
<mwc-button @click=${() => this.toggleEditSidebar()}>
${this._editSidebar ? "Restore" : "Edit"}
</mwc-button>
</ha-settings-row>
<browser-mod-settings-table
.hass=${this.hass}
.settingKey=${"sidebarPanelOrder"}
.settingSelector=${{
plaintext: "Press OK to store the current sidebar order",
}}
.default=${"lovelace"}
></browser-mod-settings-table>
<div class="separator"></div>
<ha-settings-row>
<span slot="heading">Default dashboard</span>
<span slot="description"
>The dashboard that's displayed by default</span
>
Currently: ${DESC_SET_UNSET(current.defaultPanel)}
${OVERRIDDEN("defaultPanel")}
</ha-settings-row>
<ha-settings-row>
<span slot="heading">Sidebar title</span>
<span slot="description">
Clearing this does NOT restore the original default dashboard.
The title at the top of the sidebar
</span>
<mwc-button
@click=${() => {
window.browser_mod.set_setting(
"defaultPanel",
localStorage.getItem("defaultPanel"),
level
);
}}
>
Set
</mwc-button>
<mwc-button
@click=${() => {
window.browser_mod.set_setting("defaultPanel", undefined, level);
}}
>
Clear
</mwc-button>
</ha-settings-row>
<browser-mod-settings-table
.hass=${this.hass}
.settingKey=${"sidebarTitle"}
.settingSelector=${{ text: {} }}
></browser-mod-settings-table>
</div>
</ha-card>
`;
}
@ -280,7 +200,7 @@ class BrowserModFrontendSettingsCard extends LitElement {
}
.separator {
border-bottom: 1px solid var(--divider-color);
margin: 0 -8px;
margin: 16px -16px 0px;
}
img.favicon {
width: 64px;

View File

@ -15,12 +15,13 @@ loadConfigDashboard().then(() => {
@property() connection;
firstUpdated() {
window.browser_mod.addEventListener("browser-mod-config-update", () =>
window.addEventListener("browser-mod-config-update", () =>
this.requestUpdate()
);
}
render() {
if (!window.browser_mod) return html``;
return html`
<ha-app-layout>
<app-header slot="header" fixed>

View File

@ -1,9 +1,17 @@
const TIMEOUT_ERROR = "SELECTTREE-TIMEOUT";
async function _await_el(el) {
export async function await_element(el, hard = false) {
if (el.localName?.includes("-"))
await customElements.whenDefined(el.localName);
if (el.updateComplete) await el.updateComplete;
if (hard) {
if (el.pageRendered) await el.pageRendered;
if (el._panelState) {
let rounds = 0;
while (el._panelState !== "loaded" && rounds++ < 5)
await new Promise((r) => setTimeout(r, 100));
}
}
}
async function _selectTree(root, path, all = false) {
@ -18,7 +26,7 @@ async function _selectTree(root, path, all = false) {
if (!p.trim().length) continue;
_await_el(e);
await_element(e);
el = p === "$" ? [e.shadowRoot] : e.querySelectorAll(p);
}
return all ? el : el[0];
@ -102,6 +110,7 @@ export const loadConfigDashboard = async () => {
const configRouter: any = document.createElement("ha-panel-config");
await configRouter?.routerOptions?.routes?.dashboard?.load?.(); // Load ha-config-dashboard
await configRouter?.routerOptions?.routes?.cloud?.load?.(); // Load ha-settings-row
await configRouter?.routerOptions?.routes?.entities?.load?.(); // Load ha-data-table
await customElements.whenDefined("ha-config-dashboard");
};
@ -132,3 +141,32 @@ export function throttle(timeout) {
};
};
}
export function runOnce(restart = false) {
return function (target, propertyKey, descriptor) {
const fn = descriptor.value;
let running = undefined;
const newfn = function (...rest) {
if (restart && running === false) running = true;
if (running !== undefined) return;
running = false;
const retval = fn.bind(this)(...rest);
if (running) {
running = undefined;
return newfn.bind(this)(...rest);
} else {
running = undefined;
return retval;
}
};
descriptor.value = newfn;
};
}
export async function waitRepeat(fn, times, delay) {
while (times--) {
fn();
await new Promise((r) => setTimeout(r, delay));
}
}

View File

@ -24,7 +24,7 @@ export const ConnectionMixin = (SuperClass) => {
}
private fireEvent(event, detail = undefined) {
this.dispatchEvent(new CustomEvent(event, { detail }));
this.dispatchEvent(new CustomEvent(event, { detail, bubbles: true }));
}
private incoming_message(msg) {

View File

@ -1,25 +1,37 @@
import { selectTree } from "../helpers";
import { await_element, waitRepeat, runOnce, selectTree } from "../helpers";
export const AutoSettingsMixin = (SuperClass) => {
return class AutoSettingsMixinClass extends SuperClass {
class AutoSettingsMixinClass extends SuperClass {
_faviconTemplateSubscription;
_titleTemplateSubscription;
__currentTitle = undefined;
@runOnce()
async runHideHeader() {
while (!(await this._hideHeader()))
await new Promise((r) => setTimeout(r, 500));
}
@runOnce(true)
async runUpdateTitle() {
await waitRepeat(() => this._updateTitle(), 3, 500);
}
constructor() {
super();
this._auto_settings_setup();
this.addEventListener("browser-mod-config-update", () =>
this._auto_settings_setup()
);
const runUpdates = async () => {
this.runUpdateTitle();
this.runHideHeader();
};
window.addEventListener("location-changed", () => {
this._updateTitle();
setTimeout(() => this._updateTitle(), 500);
setTimeout(() => this._updateTitle(), 1000);
setTimeout(() => this._updateTitle(), 5000);
this._auto_settings_setup();
this.addEventListener("browser-mod-config-update", () => {
this._auto_settings_setup();
runUpdates();
});
window.addEventListener("location-changed", runUpdates);
}
async _auto_settings_setup() {
@ -40,7 +52,7 @@ export const AutoSettingsMixin = (SuperClass) => {
// Default panel
if (settings.defaultPanel) {
localStorage.setItem("defaultPanel", settings.defaultPanel);
localStorage.setItem("defaultPanel", `"${settings.defaultPanel}"`);
}
// Hide sidebar
@ -55,18 +67,18 @@ export const AutoSettingsMixin = (SuperClass) => {
).then((el) => el?.remove?.());
}
// Hide header
if (settings.hideHeader === true) {
customElements.whenDefined("app-header-layout").then(() => {
const appHeader = customElements.get("app-header").prototype;
const _attached = appHeader.attached;
appHeader.attached = function () {
_attached.bind(this)();
this.style.setProperty("display", "none");
};
// Sidebar title
if (settings.sidebarTitle) {
selectTree(
document,
"home-assistant $ home-assistant-main $ app-drawer-layout app-drawer ha-sidebar $ .title"
).then((el) => {
if (el) (el as HTMLElement).innerHTML = settings.sidebarTitle;
});
}
// Hide header
// Favicon template
if (settings.faviconTemplate !== undefined) {
(async () => {
@ -111,7 +123,6 @@ export const AutoSettingsMixin = (SuperClass) => {
_updateFavicon({ result }) {
const link: any = document.head.querySelector("link[rel~='icon']");
link.href = result;
window.browser_mod.fireEvent("browser-mod-favicon-update");
}
get _currentTitle() {
@ -121,7 +132,77 @@ export const AutoSettingsMixin = (SuperClass) => {
_updateTitle(data = undefined) {
if (data) this.__currentTitle = data.result;
if (this.__currentTitle) document.title = this.__currentTitle;
window.browser_mod.fireEvent("browser-mod-favicon-update");
}
};
async _hideHeader() {
if (this.settings.hideHeader !== true) return true;
let el = await selectTree(
document,
"home-assistant $ home-assistant-main $ app-drawer-layout partial-panel-resolver"
);
if (!el) return false;
let steps = 0;
while (el && el.localName !== "ha-app-layout" && steps++ < 5) {
await await_element(el, true);
const next =
el.querySelector("ha-app-layout") ??
el.firstElementChild ??
el.shadowRoot;
el = next;
}
if (el?.localName !== "ha-app-layout") return false;
if (el.header) {
el.header.style.setProperty("display", "none");
setTimeout(() => el._updateLayoutStates(), 0);
return true;
}
return false;
}
getSetting(key) {
const retval = { global: undefined, browser: {}, user: {} };
retval.global = this._data.settings?.[key];
for (const [k, v] of Object.entries(this._data.browsers ?? {})) {
if ((v as any).settings?.[key] != null)
retval.browser[k] = (v as any).settings[key];
}
for (const [k, v] of Object.entries(this._data.user_settings ?? {})) {
if (v[key] != null) retval.user[k] = v[key];
}
return retval;
}
setSetting(type, target, settings) {
if (type === "global") {
for (const [key, value] of Object.entries(settings))
this.connection.sendMessage({
type: "browser_mod/settings",
key,
value,
});
} else if (type === "browser") {
const browser = this._data.browsers[target];
const newsettings = { ...browser.settings, ...settings };
console.log(newsettings);
this.connection.sendMessage({
type: "browser_mod/register",
browserID: target,
data: {
...browser,
settings: newsettings,
},
});
} else if (type === "user") {
const user = target;
for (const [key, value] of Object.entries(settings))
this.connection.sendMessage({
type: "browser_mod/settings",
user,
key,
value,
});
}
}
}
return AutoSettingsMixinClass;
};

View File

@ -1,7 +1,7 @@
{
"name": "browser_mod",
"private": true,
"version": "2.0.0b4",
"version": "2.0.0b5",
"description": "",
"scripts": {
"build": "rollup -c",

View File

@ -17,12 +17,6 @@
- platform: state
entity_id: light.kitchen_lights
action:
- service: browser_mod.sequence
data:
sequence:
- service: delay
data:
time: 5000
- service: browser_mod.popup
data:
title: automation