diff --git a/.hass/config/ui-lovelace.yaml b/.hass/config/ui-lovelace.yaml
index 3562f62..3e5d751 100644
--- a/.hass/config/ui-lovelace.yaml
+++ b/.hass/config/ui-lovelace.yaml
@@ -1,86 +1,31 @@
kiosk_mode:
- entity_settings:
- - entity:
- input_boolean.kiosk: 'on'
- kiosk: true
- - entity:
- input_boolean.kiosk_hide_header: 'on'
- hide_header: true
- - entity:
- input_boolean.kiosk_hide_sidebar: 'on'
- hide_sidebar: true
- - entity:
- input_boolean.kiosk_hide_menubutton: 'on'
- hide_menubutton: true
- - entity:
- input_boolean.kiosk_hide_overflow: 'on'
- hide_overflow: true
- - entity:
- input_boolean.kiosk_hide_notifications: 'on'
- hide_notifications: true
- - entity:
- input_boolean.kiosk_hide_account: 'on'
- hide_account: true
- - entity:
- input_boolean.kiosk_hide_search: 'on'
- hide_search: true
- - entity:
- input_boolean.kiosk_hide_assistant: 'on'
- hide_assistant: true
- - entity:
- input_boolean.kiosk_hide_edit_dashboard: 'on'
- hide_edit_dashboard: true
- - entity:
- input_boolean.kiosk_hide_refresh: 'on'
- hide_refresh: true
- - entity:
- input_boolean.kiosk_hide_unused_entities: 'on'
- hide_unused_entities: true
- - entity:
- input_boolean.kiosk_hide_reload_resources: 'on'
- hide_reload_resources: true
- - entity:
- input_boolean.kiosk_hide_dialog_header_history: 'on'
- hide_dialog_header_history: true
- - entity:
- input_boolean.kiosk_hide_dialog_header_settings: 'on'
- hide_dialog_header_settings: true
- - entity:
- input_boolean.kiosk_hide_dialog_header_action_items: 'on'
- hide_dialog_header_action_items: true
- - entity:
- input_boolean.kiosk_hide_dialog_header_overflow: 'on'
- hide_dialog_header_overflow: true
- - entity:
- input_boolean.kiosk_hide_dialog_history: 'on'
- hide_dialog_history: true
- - entity:
- input_boolean.kiosk_hide_dialog_logbook: 'on'
- hide_dialog_logbook: true
- - entity:
- input_boolean.kiosk_hide_dialog_attributes: 'on'
- hide_dialog_attributes: true
- - entity:
- input_boolean.kiosk_hide_dialog_update_actions: 'on'
- hide_dialog_update_actions: true
- - entity:
- input_boolean.kiosk_hide_dialog_timer_actions: 'on'
- hide_dialog_timer_actions: true
- - entity:
- input_boolean.kiosk_hide_dialog_history_show_more: 'on'
- hide_dialog_history_show_more: true
- - entity:
- input_boolean.kiosk_hide_dialog_logbook_show_more: 'on'
- hide_dialog_logbook_show_more: true
- - entity:
- input_boolean.kiosk_block_overflow: 'on'
- block_overflow: true
- - entity:
- input_boolean.kiosk_block_mouse: 'on'
- block_mouse: true
- - entity:
- input_boolean.kiosk_block_context_menu: 'on'
- block_context_menu: true
+ kiosk: "{{ is_state('input_boolean.kiosk', 'on') }}"
+ hide_header: "{{ is_state('input_boolean.kiosk_hide_header', 'on') }}"
+ hide_sidebar: "{{ is_state('input_boolean.kiosk_hide_sidebar', 'on') }}"
+ hide_menubutton: "{{ is_state('input_boolean.kiosk_hide_menubutton', 'on') }}"
+ hide_overflow: "{{ is_state('input_boolean.kiosk_hide_overflow', 'on') }}"
+ hide_notifications: "{{ is_state('input_boolean.kiosk_hide_notifications', 'on') }}"
+ hide_account: "{{ is_state('input_boolean.kiosk_hide_account', 'on') }}"
+ hide_search: "{{ is_state('input_boolean.kiosk_hide_search', 'on') }}"
+ hide_assistant: "{{ is_state('input_boolean.kiosk_hide_assistant', 'on') }}"
+ hide_edit_dashboard: "{{ is_state('input_boolean.kiosk_hide_edit_dashboard', 'on') }}"
+ hide_refresh: "{{ is_state('input_boolean.kiosk_hide_refresh', 'on') }}"
+ hide_unused_entities: "{{ is_state('input_boolean.kiosk_hide_unused_entities', 'on') }}"
+ hide_reload_resources: "{{ is_state('input_boolean.kiosk_hide_reload_resources', 'on') }}"
+ hide_dialog_header_history: "{{ is_state('input_boolean.kiosk_hide_dialog_header_history', 'on') }}"
+ hide_dialog_header_settings: "{{ is_state('input_boolean.kiosk_hide_dialog_header_settings', 'on') }}"
+ hide_dialog_header_action_items: "{{ is_state('input_boolean.kiosk_hide_dialog_header_action_items', 'on') }}"
+ hide_dialog_header_overflow: "{{ is_state('input_boolean.kiosk_hide_dialog_header_overflow', 'on') }}"
+ hide_dialog_history: "{{ is_state('input_boolean.kiosk_hide_dialog_history', 'on') }}"
+ hide_dialog_logbook: "{{ is_state('input_boolean.kiosk_hide_dialog_logbook', 'on') }}"
+ hide_dialog_attributes: "{{ is_state('input_boolean.kiosk_hide_dialog_attributes', 'on') }}"
+ hide_dialog_update_actions: "{{ is_state('input_boolean.kiosk_hide_dialog_update_actions', 'on') }}"
+ hide_dialog_timer_actions: "{{ is_state('input_boolean.kiosk_hide_dialog_timer_actions', 'on') }}"
+ hide_dialog_history_show_more: "{{ is_state('input_boolean.kiosk_hide_dialog_history_show_more', 'on') }}"
+ hide_dialog_logbook_show_more: "{{ is_state('input_boolean.kiosk_hide_dialog_logbook_show_more', 'on') }}"
+ block_overflow: "{{ is_state('input_boolean.kiosk_block_overflow', 'on') }}"
+ block_mouse: "{{ is_state('input_boolean.kiosk_block_mouse', 'on') }}"
+ block_context_menu: "{{ is_state('input_boolean.kiosk_block_context_menu', 'on') }}"
title: Kiosk-mode Overview
views:
- theme: Backend-selected
diff --git a/README.md b/README.md
index 2205211..8241efa 100644
--- a/README.md
+++ b/README.md
@@ -81,56 +81,60 @@ frontend:
YAML mode users need to add the configuration manually to the lovelace dashboard file in which they want to enable `kiosk-mode`. Non-YAML users (Storage Mode) need to add the configuration to each lovelace panel going to `Edit Dashboard` option (located in the overflow menu that appears when one clicks on the top-right three-dots button). Once in `Edit Dashboard` mode, click again on the top-right three-dots button and select `Raw configuration editor`.
-```
+```yaml
kiosk_mode:
hide_header: true
-
+ hide_sidebar: '{{ is_state("input_boolean.hide_sidebar", "on") }}'
views:
```
*Note: `views:` is added in the example above to show where `kiosk_mode:` should be placed in your Lovelace config*
## Config Options
-| Config Option | Type | Default | Description |
-|:-----------------------------------------|:--------|:--------|:------------|
-|`kiosk` | Boolean | false | Hides both the header and sidebar. |
-|`hide_header`1 | Boolean | false | Hides only the header. |
-|`hide_sidebar` | Boolean | false | Hides only the sidebar. |
-|`hide_menubutton`1 | Boolean | false | Hides only the sidebar menu icon. |
-|`hide_notifications` | Boolean | false | Hide the notifications entry-point. |
-|`hide_account` | Boolean | false | Hides the account icon. |
-|`hide_search` | Boolean | false | Hides the search icon. |
-|`hide_assistant` | Boolean | false | Hides the assistant icon. |
-|`hide_overflow` | Boolean | false | Hides the top right overflow menu. |
-|`block_overflow` | Boolean | false | Blocks the top right overflow menu mouse interactions. |
-|`hide_refresh` | Boolean | false | Hides the "Refresh" button inside the top right overflow menu in lovelace yaml mode. |
-|`hide_unused_entities` | Boolean | false | Hides the "Unused entities" button inside the top right overflow menu in lovelace yaml mode. |
-|`hide_reload_resources` | Boolean | false | Hides the "Reload resources" button inside the top right overflow menu in lovelace yaml mode. |
-|`hide_edit_dashboard` | Boolean | false | Hides the "Edit dashboard" button inside the top right overflow menu. |
-|`block_mouse` | Boolean | false | Blocks completely the mouse. No interaction is allowed and the mouse will not be visible. **Can only be disabled with `?disable_km` query parameter in the URL.**. |
-|`block_context_menu` | Boolean | false | Prevents opening a right-click context menu (sometimes accessible via tap-and-hold on touchscreen devices). |
-|`hide_dialog_header_history` | Boolean | false | Hides the "History" icon in the header of more-info dialogs. |
-|`hide_dialog_header_settings`2 | Boolean | false | Hides the "Settings" icon in the header of more-info dialogs. |
-|`hide_dialog_header_overflow`2 | Boolean | false | Hides the top right overflow menu in the header of more-info dialogs. |
-|`hide_dialog_header_action_items` | Boolean | false | Hides all the action items from the header of more-info dialogs. |
-|`hide_dialog_history` | Boolean | false | Hides the "History" section in the more-info dialogs. |
-|`hide_dialog_history_show_more` | Boolean | false | Hides the "Show more" link in the "History" section of more-info dialogs. |
-|`hide_dialog_logbook` | Boolean | false | Hides the "Logbook" section in the more-info dialogs. |
-|`hide_dialog_logbook_show_more` | Boolean | false | Hides the "Show more" link in the "Logbook" section of more-info dialogs. |
-|`hide_dialog_attributes` | Boolean | false | Hides the "Attributes" section in the more-info dialogs. |
-|`hide_dialog_media_actions` | Boolean | false | Hides the actions block in the more-info dialogs of media-player entities. |
-|`hide_dialog_update_actions` | Boolean | false | Hides the actions block in the more-info dialogs of update entities. |
-|`hide_dialog_timer_actions` | Boolean | false | Hides the actions block in the more-info dialogs of timer entities. |
-|`hide_dialog_climate_actions` | Boolean | false | Hides all the actions in the more-info dialogs of climate entities. |
-|`hide_dialog_climate_temperature_actions` | Boolean | false | Hides the temperature cotrol actions in the more-info dialogs of climate entities. |
-|`hide_dialog_climate_settings_actions` | Boolean | false | Hides the mode and preset actions in the more-info dialogs of climate entities. |
-|`hide_dialog_light_actions` | Boolean | false | Hides all the actions in the more-info dialogs of light entities. |
-|`hide_dialog_light_control_actions` | Boolean | false | Hides the control actions in the more-info dialogs of light entities. |
-|`hide_dialog_light_color_actions` | Boolean | false | Hides the favorite colors actions in the more-info dialogs of light entities. |
-|`hide_dialog_light_settings_actions` | Boolean | false | Hides the settings actions in the more-info dialogs of light entities. |
-|`ignore_entity_settings`3 | Boolean | false | Useful for [conditional configs](#conditional-lovelace-config) and will cause `entity_settings` to be ignored. |
-|`ignore_mobile_settings`4 | Boolean | false | Useful for [conditional configs](#conditional-lovelace-config) and will cause `mobile_settings` to be ignored. |
-|`ignore_disable_km`3 | Boolean | false | Useful for [conditional configs](#conditional-lovelace-config) and will cause `disable_km` URL parameter to be ignored. |
+All the options can be set as a boolean and all of them are `false` by default. Excluding `ignore_mobile_settings` and `ignore_disable_km`, all the options can be set as a Jinja template that returns a boolean.
+
+>**Note:** If you set the option as a string but it is not a valid Jinja template, the library will throw an error. If you set a Jinja template and it doesn't return a boolean, the option will be set as false and a warning will be thrown.
+
+
+| Config Option | Description |
+|:-----------------------------------------|:------------|
+|`kiosk` | Hides both the header and sidebar. |
+|`hide_header`1 | Hides only the header. |
+|`hide_sidebar` | Hides only the sidebar. |
+|`hide_menubutton`1 | Hides only the sidebar menu icon. |
+|`hide_notifications` | Hide the notifications entry-point. |
+|`hide_account` | Hides the account icon. |
+|`hide_search` | Hides the search icon. |
+|`hide_assistant` | Hides the assistant icon. |
+|`hide_overflow` | Hides the top right overflow menu. |
+|`block_overflow` | Blocks the top right overflow menu mouse interactions. |
+|`hide_refresh` | Hides the "Refresh" button inside the top right overflow menu in lovelace yaml mode. |
+|`hide_unused_entities` | Hides the "Unused entities" button inside the top right overflow menu in lovelace yaml mode. |
+|`hide_reload_resources` | Hides the "Reload resources" button inside the top right overflow menu in lovelace yaml mode. |
+|`hide_edit_dashboard` | Hides the "Edit dashboard" button inside the top right overflow menu. |
+|`block_mouse` | Blocks completely the mouse. No interaction is allowed and the mouse will not be visible. **Can only be disabled with `?disable_km` query parameter in the URL.**. |
+|`block_context_menu` | Prevents opening a right-click context menu (sometimes accessible via tap-and-hold on touchscreen devices).|
+|`hide_dialog_header_history` | Hides the "History" icon in the header of more-info dialogs. |
+|`hide_dialog_header_settings`2 | Hides the "Settings" icon in the header of more-info dialogs. |
+|`hide_dialog_header_overflow`2 | Hides the top right overflow menu in the header of more-info dialogs. |
+|`hide_dialog_header_action_items` | Hides all the action items from the header of more-info dialogs. |
+|`hide_dialog_history` | Hides the "History" section in the more-info dialogs. |
+|`hide_dialog_history_show_more` | Hides the "Show more" link in the "History" section of more-info dialogs. |
+|`hide_dialog_logbook` | Hides the "Logbook" section in the more-info dialogs. |
+|`hide_dialog_logbook_show_more` | Hides the "Show more" link in the "Logbook" section of more-info dialogs. |
+|`hide_dialog_attributes` | Hides the "Attributes" section in the more-info dialogs. |
+|`hide_dialog_media_actions` | Hides the actions block in the more-info dialogs of media-player entities. |
+|`hide_dialog_update_actions` | Hides the actions block in the more-info dialogs of update entities. |
+|`hide_dialog_timer_actions` | Hides the actions block in the more-info dialogs of timer entities. |
+|`hide_dialog_climate_actions` | Hides all the actions in the more-info dialogs of climate entities. |
+|`hide_dialog_climate_temperature_actions` | Hides the temperature cotrol actions in the more-info dialogs of climate entities. |
+|`hide_dialog_climate_settings_actions` | Hides the mode and preset actions in the more-info dialogs of climate entities. |
+|`hide_dialog_light_actions` | Hides all the actions in the more-info dialogs of light entities. |
+|`hide_dialog_light_control_actions` | Hides the control actions in the more-info dialogs of light entities. |
+|`hide_dialog_light_color_actions` | Hides the favorite colors actions in the more-info dialogs of light entities. |
+|`hide_dialog_light_settings_actions` | Hides the settings actions in the more-info dialogs of light entities. |
+|`ignore_disable_km` | Useful for [conditional configs](#conditional-lovelace-config) and will cause `disable_km` URL parameter to be ignored. |
+|`ignore_mobile_settings`3 | Useful for [conditional configs](#conditional-lovelace-config) and will cause `mobile_settings` to be ignored. |
@@ -138,12 +142,37 @@ views:
>
>2 These elements are not visible by default if the account is not an admin account.
>
->3 These options only work if they are placed inside [admin_settings](#admin_settings), [non_admin_settings](#non_admin_settings), [user_settings](#user_settings) or [mobile_settings](#mobile_settings). They will not have any effect if they are placed inside [entity_settings](#entity_settings)
->
->4 This option only works if it is placed inside [admin_settings](#admin_settings), [non_admin_settings](#non_admin_settings) or [user_settings](#user_settings). It will not have any effect if it is placed inside [mobile_settings](#mobile_settings) or [entity_settings](#entity_settings)
+>3 This option only works if it is placed inside [admin_settings](#admin_settings), [non_admin_settings](#non_admin_settings) or [user_settings](#user_settings). It will not have any effect if it is placed inside [mobile_settings](#mobile_settings).
+If you us Jinja templates for the options, the next variables will be available:
+
+* `user_name`: String with the logged user's name
+* `user_is_admin`: Bolean value than indicates if the logged user is admin or not
+* `user_is_owner`: Bolean value than indicates if the logged user is the owner or not
+* `user_agent`: User agent of the browser in which Home Assistant is being executed
+
+This gives a lot of flexibility and depending on your objectives you can omit the usage of the [conditional configs](#conditional-lovelace-config). For example, this configuration:
+
+```yaml
+kiosk_mode:
+ hide_header: false
+ user_settings:
+ - users:
+ - "ryan meek"
+ - "maykar"
+ hide_header: true
+```
+
+Can be transformed in a simpler version:
+
+```yaml
+kiosk_mode:
+ hide_header: '{{ user_name in ("maykar", "ryan meek") }}'
+```
+
+
## Options through screenshots
@@ -247,7 +276,7 @@ These use the same options as above, but placed under one of the following user/
### admin_settings:
Sets the config for every admin user.
-*Overwritten by user_settings, mobile_settings, and entity_settings ( unless one of the ignore options is used ).*
+*Overwritten by user_settings and mobile_settings ( unless `ignore_mobile_settings` is used ).*
```
kiosk_mode:
@@ -258,19 +287,18 @@ kiosk_mode:
### non_admin_settings:
Sets the config for every regular user.
-*Overwritten by user_settings, mobile_settings, and entity_settings ( unless one of the ignore options is used ).*
+*Overwritten by user_settings and mobile_settings ( unless `ignore_mobile_settings` is used ).*
```
kiosk_mode:
non_admin_settings:
hide_header: true
- ignore_entity_settings: true
```
### user_settings:
Sets the config for specific users. **This uses a user's name, not their username (if they're different)**.
-*Overwritten by mobile_settings, and entity_settings ( unless one of the ignore options is used ).*
+*Overwritten by mobile_settings ( unless `ignore_mobile_settings` is used ).*
```
kiosk_mode:
@@ -282,55 +310,20 @@ kiosk_mode:
- users:
- "the wife"
kiosk: true
- ignore_entity_settings: true
```
### mobile_settings:
-Sets the config for mobile devices. The default breakpoint is 812px, which can be changed by setting the `custom_width` option.
-*Overwritten by entity_settings, unless `ignore_entity_settings` is used, can be ignored with `ignore_mobile_settings`.*
+Sets the config for mobile devices. The default breakpoint is `812px`, which can be changed by setting the `custom_width` option.
```
kiosk_mode:
mobile_settings:
hide_header: true
- ignore_entity_settings: true
custom_width: 768
```
-### entity_settings:
-Dynamically change config on any entity's state. Under `entity:` list the entity followed by the state that will enable the config below. For more complex logic use this with a template sensor.
-*Takes priority over all other config settings unless they use `ignore_entity_settings`.*
-
-*Any condition that doesn't match will then fall back to previous configurations if another "false" entity condition hasn't also been set (see the 2nd example).*
-```
-kiosk_mode:
- entity_settings:
- - entity:
- input_boolean.hide_sidebar: 'on'
- hide_sidebar: true
- - entity:
- sensor.hide_header: 'on'
- hide_header: true
- - entity:
- input_text.kiosk: 'true'
- kiosk: true
-```
-
-```
-kiosk_mode:
- entity_settings:
- # hide_sidebar has both true and false conditions to be a true override.
- - entity:
- input_boolean.hide_sidebar: 'on'
- hide_sidebar: true
- - entity:
- input_boolean.hide_sidebar: 'off'
- hide_sidebar: false
-```
-
-
## Query Strings
Add a query string such as `?kiosk` to the end of your URL:
@@ -391,6 +384,8 @@ You save settings in a devices cache by using the cache keyword once on the devi
Example: `?hide_header&cache` makes all views & dashboards hide the header.
This works for all query strings except for the utility strings listed below.
+>**Note:** Do not use the query string cache if you are using Jinja templates for the options or you will get weird results.
+
**Utility Query Strings**
* `?clear_km_cache` will clear all cached preferences
diff --git a/src/constants/index.ts b/src/constants/index.ts
index 1e56c72..c087441 100644
--- a/src/constants/index.ts
+++ b/src/constants/index.ts
@@ -41,7 +41,6 @@ export enum OPTION {
}
export enum CONDITIONAL_OPTION {
- IGNORE_ENTITY_SETTINGS = 'ignore_entity_settings',
IGNORE_MOBILE_SETTINGS = 'ignore_mobile_settings',
IGNORE_DISABLE_KM = 'ignore_disable_km'
}
@@ -128,10 +127,12 @@ export enum ELEMENT {
}
export const TRUE = 'true';
+export const JINJA_TEMPLATE_REG = /\{\{[\s\S]*\}\}|\{%[\s\S]*%\}/;
export const CUSTOM_MOBILE_WIDTH_DEFAULT = 812;
-export const SUSCRIBE_EVENTS_TYPE = 'subscribe_events';
-export const STATE_CHANGED_EVENT = 'state_changed';
export const TOGGLE_MENU_EVENT = 'hass-toggle-menu';
+export const CONTEXT_MENU_EVENT = 'contextmenu';
+export const RESIZE_EVENT = 'resize';
+export const SUBSCRIBE_RENDER_TEMPLATE = 'render_template';
export const MAX_ATTEMPTS = 500;
export const RETRY_DELAY = 50;
export const WINDOW_RESIZE_DELAY = 250;
\ No newline at end of file
diff --git a/src/kiosk-mode.ts b/src/kiosk-mode.ts
index 856eae6..5ee22ca 100644
--- a/src/kiosk-mode.ts
+++ b/src/kiosk-mode.ts
@@ -12,8 +12,10 @@ import {
Lovelace,
KioskConfig,
ConditionalKioskConfig,
- SuscriberEvent,
- EntitySetting,
+ Options,
+ HassConnection,
+ SubscriberTemplate,
+ MoreInfoDialog,
Version
} from '@types';
import {
@@ -23,9 +25,11 @@ import {
ELEMENT,
TRUE,
CUSTOM_MOBILE_WIDTH_DEFAULT,
- SUSCRIBE_EVENTS_TYPE,
- STATE_CHANGED_EVENT,
TOGGLE_MENU_EVENT,
+ CONTEXT_MENU_EVENT,
+ RESIZE_EVENT,
+ JINJA_TEMPLATE_REG,
+ SUBSCRIBE_RENDER_TEMPLATE,
WINDOW_RESIZE_DELAY,
NAMESPACE,
NON_CRITICAL_WARNING
@@ -54,9 +58,7 @@ class KioskMode implements KioskModeRunner {
resetCache();
}
- window.kioskModeEntities = {};
-
- this.options = {};
+ this.panelOptions = new Map();
const selector = new HAQuerySelector();
@@ -104,7 +106,6 @@ class KioskMode implements KioskModeRunner {
});
selector.listen();
- this.entityWatch();
this.resizeWindowBinded = this.resizeWindow.bind(this);
}
@@ -125,12 +126,26 @@ class KioskMode implements KioskModeRunner {
private version: Version | null;
// Kiosk Mode options
- private options: Partial<
- Record<
- OPTION | CONDITIONAL_OPTION,
- boolean
- >
- >;
+ private panelOptions: Map;
+
+ private _getPanelUrl(): string {
+ return this.ha.hass.panelUrl;
+ }
+
+ private _hasStoredOptions(): boolean {
+ const panelUrl = this._getPanelUrl();
+ return this.panelOptions.has(panelUrl);
+ }
+
+ private _getOptions(): Options {
+ const panelUrl = this._getPanelUrl();
+ return this.panelOptions.get(panelUrl);
+ }
+
+ private _storeOptions(options: Options): void {
+ const panelUrl = this._getPanelUrl();
+ this.panelOptions.set(panelUrl, options);
+ }
public async run() {
@@ -140,38 +155,46 @@ class KioskMode implements KioskModeRunner {
return;
}
- // Get the configuration and process it
- return getPromisableElement(
- () => lovelace?.lovelace?.config,
- (config: Lovelace['lovelace']['config']) => !!config,
- 'Lovelace config'
- )
- .then((config: Lovelace['lovelace']['config']) => {
- return this.processConfig(
- config.kiosk_mode || {}
- );
- });
+ if (this._hasStoredOptions()) {
+ // Insert styles
+ this.insertStyles();
+ } else {
+ // Get the configuration from the lovalace panel and process it
+ return getPromisableElement(
+ () => lovelace?.lovelace?.config,
+ (config: Lovelace['lovelace']['config']) => !!config,
+ 'Lovelace config'
+ )
+ .then((config: Lovelace['lovelace']['config']) => {
+ return this.processConfig(
+ config.kiosk_mode || {}
+ );
+ });
+ }
}
- public runDialogs(dialog: Element = this.ha?.shadowRoot?.querySelector(ELEMENT.HA_MORE_INFO_DIALOG)) {
- if (!dialog) return;
+ public runDialogs() {
+ const dialog = this.ha?.shadowRoot?.querySelector(ELEMENT.HA_MORE_INFO_DIALOG);
+ const haDialog = dialog?.shadowRoot.querySelector(ELEMENT.HA_DIALOG);
+ if (
+ !haDialog ||
+ !haDialog.__open
+ ) {
+ return;
+ }
this.insertMoreInfoDialogStyles();
}
protected async processConfig(config: KioskConfig) {
- const dash = this.ha.hass.panelUrl;
-
- if (!window.kioskModeEntities[dash]) {
- window.kioskModeEntities[dash] = [];
- }
+ const options: Options = {};
// Set all the options to false
Object.values(OPTION).forEach((option: OPTION) => {
- this.options[option] = false;
+ options[option] = false;
});
Object.values(CONDITIONAL_OPTION).forEach((option: CONDITIONAL_OPTION) => {
- this.options[option] = false;
+ options[option] = false;
});
// Get menu translations
@@ -190,11 +213,11 @@ class KioskMode implements KioskModeRunner {
queryString(Object.values(OPTION))
) {
Object.values(OPTION).forEach((option: OPTION): void => {
- this.options[option] = cached(option) || queryString(option);
+ options[option] = cached(option) || queryString(option);
});
} else {
// Use config values only if config strings and cache aren't used.
- this.setOptions(config, false);
+ this.setOptions(options, config, false);
}
// Admin non-admin config
@@ -203,20 +226,20 @@ class KioskMode implements KioskModeRunner {
: config.non_admin_settings;
if (adminConfig) {
- this.setOptions(adminConfig, true);
+ this.setOptions(options, adminConfig, true);
}
// User settings config
if (config.user_settings) {
toArray(config.user_settings).forEach((conf) => {
- if (toArray(conf.users).some((x) => x.toLowerCase() === this.user.name.toLowerCase())) {
- this.setOptions(conf, true);
+ if (toArray(conf.users).some((user) => user.toLowerCase() === this.user.name.toLowerCase())) {
+ this.setOptions(options, conf, true);
}
});
}
// Mobile config
- const mobileConfig = this.options[CONDITIONAL_OPTION.IGNORE_MOBILE_SETTINGS]
+ const mobileConfig = options[CONDITIONAL_OPTION.IGNORE_MOBILE_SETTINGS]
? null
: config.mobile_settings;
@@ -225,44 +248,34 @@ class KioskMode implements KioskModeRunner {
? mobileConfig.custom_width
: CUSTOM_MOBILE_WIDTH_DEFAULT;
if (window.innerWidth <= mobileWidth) {
- this.setOptions(mobileConfig, true);
+ this.setOptions(options, mobileConfig, true);
}
}
- // Entity config
- const entityConfig = this.options[CONDITIONAL_OPTION.IGNORE_ENTITY_SETTINGS]
- ? null
- : config.entity_settings;
+ this._storeOptions(options);
- if (entityConfig) {
- entityConfig.forEach((conf: EntitySetting) => {
- const entity = Object.keys(conf.entity)[0];
- if (!window.kioskModeEntities[dash].includes(entity)) {
- window.kioskModeEntities[dash].push(entity);
- }
- if (this.ha.hass.states[entity].state == conf.entity[entity]) {
- this.setOptions(conf, false);
- }
- });
- }
+ this.insertStyles();
+ }
+
+ // INSERT REGULAR STYLES
+ protected insertStyles() {
+
+ const options = this._getOptions();
// Do not run kiosk-mode if it is disabled
if (
- queryString(SPECIAL_QUERY_PARAMS.DISABLE_KIOSK_MODE) &&
- !this.options[CONDITIONAL_OPTION.IGNORE_DISABLE_KM]
+ !options ||
+ (
+ queryString(SPECIAL_QUERY_PARAMS.DISABLE_KIOSK_MODE) &&
+ !options[CONDITIONAL_OPTION.IGNORE_DISABLE_KM]
+ )
) {
return;
}
- this.insertStyles();
- }
-
- // INSERT REGULAR STYLES
- protected insertStyles() {
-
if (
- this.options[OPTION.KIOSK] ||
- this.options[OPTION.HIDE_HEADER]
+ options[OPTION.KIOSK] ||
+ options[OPTION.HIDE_HEADER]
) {
addStyle(STYLES.HEADER, this.huiRoot);
if (queryString(SPECIAL_QUERY_PARAMS.CACHE)) setCache(OPTION.HIDE_HEADER, TRUE);
@@ -274,8 +287,8 @@ class KioskMode implements KioskModeRunner {
this.main?.host?.removeEventListener(TOGGLE_MENU_EVENT, this.blockEventHandler, true);
if (
- this.options[OPTION.KIOSK] ||
- this.options[OPTION.HIDE_SIDEBAR]
+ options[OPTION.KIOSK] ||
+ options[OPTION.HIDE_SIDEBAR]
) {
this.main?.host?.addEventListener(TOGGLE_MENU_EVENT, this.blockEventHandler, true);
addStyle(STYLES.SIDEBAR, this.drawerLayout);
@@ -287,109 +300,122 @@ class KioskMode implements KioskModeRunner {
}
if (
- this.options[OPTION.HIDE_ACCOUNT] ||
- this.options[OPTION.HIDE_NOTIFICATIONS] ||
- this.options[OPTION.HIDE_MENU_BUTTON]
+ options[OPTION.HIDE_ACCOUNT] ||
+ options[OPTION.HIDE_NOTIFICATIONS] ||
+ options[OPTION.HIDE_MENU_BUTTON]
) {
const styles = [
- this.options[OPTION.HIDE_ACCOUNT]
+ options[OPTION.HIDE_ACCOUNT]
? STYLES.ACCOUNT : '',
- this.options[OPTION.HIDE_NOTIFICATIONS]
+ options[OPTION.HIDE_NOTIFICATIONS]
? STYLES.NOTIFICATIONS : '',
- this.options[OPTION.HIDE_ACCOUNT] && this.options[OPTION.HIDE_NOTIFICATIONS]
+ options[OPTION.HIDE_ACCOUNT] && options[OPTION.HIDE_NOTIFICATIONS]
? STYLES.DIVIDER
: '',
- this.options[OPTION.HIDE_ACCOUNT] || this.options[OPTION.HIDE_NOTIFICATIONS]
+ options[OPTION.HIDE_ACCOUNT] || options[OPTION.HIDE_NOTIFICATIONS]
? STYLES.PAPER_LISTBOX(
- this.options[OPTION.HIDE_ACCOUNT],
- this.options[OPTION.HIDE_NOTIFICATIONS]
+ options[OPTION.HIDE_ACCOUNT],
+ options[OPTION.HIDE_NOTIFICATIONS]
)
: '',
- this.options[OPTION.HIDE_MENU_BUTTON]
+ options[OPTION.HIDE_MENU_BUTTON]
? STYLES.MENU_BUTTON : '',
];
addStyle(styles.join(''), this.sideBarRoot);
if (queryString(SPECIAL_QUERY_PARAMS.CACHE)) {
- if (this.options[OPTION.HIDE_ACCOUNT]) setCache(OPTION.HIDE_ACCOUNT, TRUE);
- if (this.options[OPTION.HIDE_NOTIFICATIONS]) setCache(OPTION.HIDE_NOTIFICATIONS, TRUE);
+ if (options[OPTION.HIDE_ACCOUNT]) setCache(OPTION.HIDE_ACCOUNT, TRUE);
+ if (options[OPTION.HIDE_NOTIFICATIONS]) setCache(OPTION.HIDE_NOTIFICATIONS, TRUE);
}
} else {
removeStyle(this.sideBarRoot);
}
if (
- this.options[OPTION.HIDE_SEARCH] ||
- this.options[OPTION.HIDE_ASSISTANT] ||
- this.options[OPTION.HIDE_REFRESH] ||
- this.options[OPTION.HIDE_UNUSED_ENTITIES] ||
- this.options[OPTION.HIDE_RELOAD_RESOURCES] ||
- this.options[OPTION.HIDE_EDIT_DASHBOARD] ||
- this.options[OPTION.HIDE_OVERFLOW] ||
- this.options[OPTION.BLOCK_OVERFLOW] ||
- this.options[OPTION.HIDE_SIDEBAR] ||
- this.options[OPTION.HIDE_MENU_BUTTON]
+ options[OPTION.HIDE_SEARCH] ||
+ options[OPTION.HIDE_ASSISTANT] ||
+ options[OPTION.HIDE_REFRESH] ||
+ options[OPTION.HIDE_UNUSED_ENTITIES] ||
+ options[OPTION.HIDE_RELOAD_RESOURCES] ||
+ options[OPTION.HIDE_EDIT_DASHBOARD] ||
+ options[OPTION.HIDE_OVERFLOW] ||
+ options[OPTION.BLOCK_OVERFLOW] ||
+ options[OPTION.HIDE_SIDEBAR] ||
+ options[OPTION.HIDE_MENU_BUTTON]
) {
const styles = [
- this.options[OPTION.HIDE_SEARCH]
+ options[OPTION.HIDE_SEARCH]
? STYLES.SEARCH : '',
- this.options[OPTION.HIDE_ASSISTANT]
+ options[OPTION.HIDE_ASSISTANT]
? STYLES.ASSISTANT : '',
- this.options[OPTION.HIDE_REFRESH]
+ options[OPTION.HIDE_REFRESH]
? STYLES.REFRESH : '',
- this.options[OPTION.HIDE_UNUSED_ENTITIES]
+ options[OPTION.HIDE_UNUSED_ENTITIES]
? STYLES.UNUSED_ENTITIES : '',
- this.options[OPTION.HIDE_RELOAD_RESOURCES]
+ options[OPTION.HIDE_RELOAD_RESOURCES]
? STYLES.RELOAD_RESOURCES : '',
- this.options[OPTION.HIDE_EDIT_DASHBOARD]
+ options[OPTION.HIDE_EDIT_DASHBOARD]
? STYLES.EDIT_DASHBOARD : '',
- this.options[OPTION.HIDE_OVERFLOW]
+ options[OPTION.HIDE_OVERFLOW]
? STYLES.OVERFLOW_MENU : '',
- this.options[OPTION.BLOCK_OVERFLOW]
+ options[OPTION.BLOCK_OVERFLOW]
? STYLES.BLOCK_OVERFLOW : '',
- this.options[OPTION.HIDE_MENU_BUTTON] || this.options[OPTION.HIDE_SIDEBAR]
+ options[OPTION.HIDE_MENU_BUTTON] || options[OPTION.HIDE_SIDEBAR]
? STYLES.MENU_BUTTON_BURGER : '',
];
addStyle(styles.join(''), this.appToolbar);
if (queryString(SPECIAL_QUERY_PARAMS.CACHE)) {
- if (this.options[OPTION.HIDE_SEARCH]) setCache(OPTION.HIDE_SEARCH, TRUE);
- if (this.options[OPTION.HIDE_ASSISTANT]) setCache(OPTION.HIDE_ASSISTANT, TRUE);
- if (this.options[OPTION.HIDE_REFRESH]) setCache(OPTION.HIDE_REFRESH, TRUE);
- if (this.options[OPTION.HIDE_UNUSED_ENTITIES]) setCache(OPTION.HIDE_UNUSED_ENTITIES, TRUE);
- if (this.options[OPTION.HIDE_RELOAD_RESOURCES]) setCache(OPTION.HIDE_RELOAD_RESOURCES, TRUE);
- if (this.options[OPTION.HIDE_EDIT_DASHBOARD]) setCache(OPTION.HIDE_EDIT_DASHBOARD, TRUE);
- if (this.options[OPTION.HIDE_OVERFLOW]) setCache(OPTION.HIDE_OVERFLOW, TRUE);
- if (this.options[OPTION.BLOCK_OVERFLOW]) setCache(OPTION.BLOCK_OVERFLOW, TRUE);
- if (this.options[OPTION.HIDE_MENU_BUTTON]) setCache(OPTION.HIDE_MENU_BUTTON, TRUE);
+ if (options[OPTION.HIDE_SEARCH]) setCache(OPTION.HIDE_SEARCH, TRUE);
+ if (options[OPTION.HIDE_ASSISTANT]) setCache(OPTION.HIDE_ASSISTANT, TRUE);
+ if (options[OPTION.HIDE_REFRESH]) setCache(OPTION.HIDE_REFRESH, TRUE);
+ if (options[OPTION.HIDE_UNUSED_ENTITIES]) setCache(OPTION.HIDE_UNUSED_ENTITIES, TRUE);
+ if (options[OPTION.HIDE_RELOAD_RESOURCES]) setCache(OPTION.HIDE_RELOAD_RESOURCES, TRUE);
+ if (options[OPTION.HIDE_EDIT_DASHBOARD]) setCache(OPTION.HIDE_EDIT_DASHBOARD, TRUE);
+ if (options[OPTION.HIDE_OVERFLOW]) setCache(OPTION.HIDE_OVERFLOW, TRUE);
+ if (options[OPTION.BLOCK_OVERFLOW]) setCache(OPTION.BLOCK_OVERFLOW, TRUE);
+ if (options[OPTION.HIDE_MENU_BUTTON]) setCache(OPTION.HIDE_MENU_BUTTON, TRUE);
}
} else {
removeStyle(this.appToolbar);
}
- if (this.options[OPTION.BLOCK_MOUSE]) {
+ if (options[OPTION.BLOCK_MOUSE]) {
addStyle(STYLES.MOUSE, document.body);
if (queryString(SPECIAL_QUERY_PARAMS.CACHE)) setCache(OPTION.BLOCK_MOUSE, TRUE);
} else {
removeStyle(document.body);
}
- window.removeEventListener('contextmenu', this.blockEventHandler, true);
+ window.removeEventListener(CONTEXT_MENU_EVENT, this.blockEventHandler, true);
- if (this.options[OPTION.BLOCK_CONTEXT_MENU]) {
- window.addEventListener('contextmenu', this.blockEventHandler, true);
+ if (options[OPTION.BLOCK_CONTEXT_MENU]) {
+ window.addEventListener(CONTEXT_MENU_EVENT, this.blockEventHandler, true);
if (queryString(SPECIAL_QUERY_PARAMS.CACHE)) setCache(OPTION.BLOCK_CONTEXT_MENU, TRUE);
}
// Resize event
- window.removeEventListener('resize', this.resizeWindowBinded);
- window.addEventListener('resize', this.resizeWindowBinded);
+ window.removeEventListener(RESIZE_EVENT, this.resizeWindowBinded);
+ window.addEventListener(RESIZE_EVENT, this.resizeWindowBinded);
// Resize window to 'refresh' view.
- window.dispatchEvent(new Event('resize'));
+ window.dispatchEvent(new Event(RESIZE_EVENT));
}
// INSERT MORE INFO DIALOG STYLES
protected async insertMoreInfoDialogStyles() {
+ const options = this._getOptions();
+
+ // Do not run kiosk-mode if it is disabled
+ if (
+ !options ||
+ (
+ queryString(SPECIAL_QUERY_PARAMS.DISABLE_KIOSK_MODE) &&
+ !options[CONDITIONAL_OPTION.IGNORE_DISABLE_KM]
+ )
+ ) {
+ return;
+ }
+
this.HAMoreInfoDialogElements.HA_DIALOG
.selector.query(`${ELEMENT.HA_DIALOG_HEADER} > ${ELEMENT.MENU_ITEM}`)
.all
@@ -407,25 +433,25 @@ class KioskMode implements KioskModeRunner {
// General dialog elements
if (
- this.options[OPTION.HIDE_DIALOG_HEADER_ACTION_ITEMS] ||
- this.options[OPTION.HIDE_DIALOG_HEADER_HISTORY] ||
- this.options[OPTION.HIDE_DIALOG_HEADER_SETTINGS] ||
- this.options[OPTION.HIDE_DIALOG_HEADER_OVERFLOW]
+ options[OPTION.HIDE_DIALOG_HEADER_ACTION_ITEMS] ||
+ options[OPTION.HIDE_DIALOG_HEADER_HISTORY] ||
+ options[OPTION.HIDE_DIALOG_HEADER_SETTINGS] ||
+ options[OPTION.HIDE_DIALOG_HEADER_OVERFLOW]
) {
const styles = [
- this.options[OPTION.HIDE_DIALOG_HEADER_ACTION_ITEMS] || this.options[OPTION.HIDE_DIALOG_HEADER_HISTORY]
+ options[OPTION.HIDE_DIALOG_HEADER_ACTION_ITEMS] || options[OPTION.HIDE_DIALOG_HEADER_HISTORY]
? STYLES.DIALOG_HEADER_HISTORY : '',
- this.options[OPTION.HIDE_DIALOG_HEADER_ACTION_ITEMS] || this.options[OPTION.HIDE_DIALOG_HEADER_SETTINGS]
+ options[OPTION.HIDE_DIALOG_HEADER_ACTION_ITEMS] || options[OPTION.HIDE_DIALOG_HEADER_SETTINGS]
? STYLES.DIALOG_HEADER_SETTINGS : '',
- this.options[OPTION.HIDE_DIALOG_HEADER_ACTION_ITEMS] || this.options[OPTION.HIDE_DIALOG_HEADER_OVERFLOW]
+ options[OPTION.HIDE_DIALOG_HEADER_ACTION_ITEMS] || options[OPTION.HIDE_DIALOG_HEADER_OVERFLOW]
? STYLES.DIALOG_HEADER_OVERFLOW : ''
];
addStyle(styles.join(''), dialog);
if (queryString(SPECIAL_QUERY_PARAMS.CACHE)) {
- if (this.options[OPTION.HIDE_DIALOG_HEADER_ACTION_ITEMS]) setCache(OPTION.HIDE_DIALOG_HEADER_ACTION_ITEMS, TRUE);
- if (this.options[OPTION.HIDE_DIALOG_HEADER_HISTORY]) setCache(OPTION.HIDE_DIALOG_HEADER_HISTORY, TRUE);
- if (this.options[OPTION.HIDE_DIALOG_HEADER_SETTINGS]) setCache(OPTION.HIDE_DIALOG_HEADER_SETTINGS, TRUE);
- if (this.options[OPTION.HIDE_DIALOG_HEADER_OVERFLOW]) setCache(OPTION.HIDE_DIALOG_HEADER_OVERFLOW, TRUE);
+ if (options[OPTION.HIDE_DIALOG_HEADER_ACTION_ITEMS]) setCache(OPTION.HIDE_DIALOG_HEADER_ACTION_ITEMS, TRUE);
+ if (options[OPTION.HIDE_DIALOG_HEADER_HISTORY]) setCache(OPTION.HIDE_DIALOG_HEADER_HISTORY, TRUE);
+ if (options[OPTION.HIDE_DIALOG_HEADER_SETTINGS]) setCache(OPTION.HIDE_DIALOG_HEADER_SETTINGS, TRUE);
+ if (options[OPTION.HIDE_DIALOG_HEADER_OVERFLOW]) setCache(OPTION.HIDE_DIALOG_HEADER_OVERFLOW, TRUE);
}
} else {
removeStyle(dialog);
@@ -448,13 +474,13 @@ class KioskMode implements KioskModeRunner {
haDialogClimate.element.then((haDialogClimate: ShadowRoot): void => {
if (
- this.options[OPTION.HIDE_DIALOG_CLIMATE_ACTIONS] ||
- this.options[OPTION.HIDE_DIALOG_CLIMATE_SETTINGS_ACTIONS]
+ options[OPTION.HIDE_DIALOG_CLIMATE_ACTIONS] ||
+ options[OPTION.HIDE_DIALOG_CLIMATE_SETTINGS_ACTIONS]
) {
addStyle(STYLES.DIALOG_CLIMATE_CONTROL_SELECT, haDialogClimate);
if (queryString(SPECIAL_QUERY_PARAMS.CACHE)) {
- if (this.options[OPTION.HIDE_DIALOG_CLIMATE_ACTIONS]) setCache(OPTION.HIDE_DIALOG_CLIMATE_ACTIONS, TRUE);
- if (this.options[OPTION.HIDE_DIALOG_CLIMATE_SETTINGS_ACTIONS]) setCache(OPTION.HIDE_DIALOG_CLIMATE_SETTINGS_ACTIONS, TRUE);
+ if (options[OPTION.HIDE_DIALOG_CLIMATE_ACTIONS]) setCache(OPTION.HIDE_DIALOG_CLIMATE_ACTIONS, TRUE);
+ if (options[OPTION.HIDE_DIALOG_CLIMATE_SETTINGS_ACTIONS]) setCache(OPTION.HIDE_DIALOG_CLIMATE_SETTINGS_ACTIONS, TRUE);
}
} else {
removeStyle(haDialogClimate);
@@ -463,12 +489,12 @@ class KioskMode implements KioskModeRunner {
haDialogClimateTemperature.element.then((haDialogClimateTemperature: ShadowRoot): void => {
if (
- this.options[OPTION.HIDE_DIALOG_CLIMATE_ACTIONS] ||
- this.options[OPTION.HIDE_DIALOG_CLIMATE_TEMPERATURE_ACTIONS]
+ options[OPTION.HIDE_DIALOG_CLIMATE_ACTIONS] ||
+ options[OPTION.HIDE_DIALOG_CLIMATE_TEMPERATURE_ACTIONS]
) {
addStyle(STYLES.DIALOG_CLIMATE_TEMPERATURE_BUTTONS, haDialogClimateTemperature);
if (queryString(SPECIAL_QUERY_PARAMS.CACHE)) {
- if (this.options[OPTION.HIDE_DIALOG_CLIMATE_TEMPERATURE_ACTIONS]) setCache(OPTION.HIDE_DIALOG_CLIMATE_TEMPERATURE_ACTIONS, TRUE);
+ if (options[OPTION.HIDE_DIALOG_CLIMATE_TEMPERATURE_ACTIONS]) setCache(OPTION.HIDE_DIALOG_CLIMATE_TEMPERATURE_ACTIONS, TRUE);
}
} else {
removeStyle(haDialogClimateTemperature);
@@ -477,8 +503,8 @@ class KioskMode implements KioskModeRunner {
haDialogClimateCircularSlider.element.then((haDialogClimateCircularSlider: ShadowRoot) => {
if (
- this.options[OPTION.HIDE_DIALOG_CLIMATE_ACTIONS] ||
- this.options[OPTION.HIDE_DIALOG_CLIMATE_TEMPERATURE_ACTIONS]
+ options[OPTION.HIDE_DIALOG_CLIMATE_ACTIONS] ||
+ options[OPTION.HIDE_DIALOG_CLIMATE_TEMPERATURE_ACTIONS]
) {
addStyle(STYLES.DIALOG_CLIMATE_CIRCULAR_SLIDER_INTERACTION, haDialogClimateCircularSlider);
} else {
@@ -507,63 +533,63 @@ class KioskMode implements KioskModeRunner {
.then((dialogChild: ShadowRoot) => {
if (
- this.options[OPTION.HIDE_DIALOG_ATTRIBUTES] ||
- this.options[OPTION.HIDE_DIALOG_TIMER_ACTIONS] ||
- this.options[OPTION.HIDE_DIALOG_MEDIA_ACTIONS] ||
- this.options[OPTION.HIDE_DIALOG_UPDATE_ACTIONS] ||
- this.options[OPTION.HIDE_DIALOG_LIGHT_ACTIONS] ||
- this.options[OPTION.HIDE_DIALOG_LIGHT_CONTROL_ACTIONS] ||
- this.options[OPTION.HIDE_DIALOG_LIGHT_COLOR_ACTIONS] ||
- this.options[OPTION.HIDE_DIALOG_LIGHT_SETTINGS_ACTIONS]
+ options[OPTION.HIDE_DIALOG_ATTRIBUTES] ||
+ options[OPTION.HIDE_DIALOG_TIMER_ACTIONS] ||
+ options[OPTION.HIDE_DIALOG_MEDIA_ACTIONS] ||
+ options[OPTION.HIDE_DIALOG_UPDATE_ACTIONS] ||
+ options[OPTION.HIDE_DIALOG_LIGHT_ACTIONS] ||
+ options[OPTION.HIDE_DIALOG_LIGHT_CONTROL_ACTIONS] ||
+ options[OPTION.HIDE_DIALOG_LIGHT_COLOR_ACTIONS] ||
+ options[OPTION.HIDE_DIALOG_LIGHT_SETTINGS_ACTIONS]
) {
const styles = [
- this.options[OPTION.HIDE_DIALOG_ATTRIBUTES] ? STYLES.DIALOG_ATTRIBUTES : '',
+ options[OPTION.HIDE_DIALOG_ATTRIBUTES] ? STYLES.DIALOG_ATTRIBUTES : '',
(
- this.options[OPTION.HIDE_DIALOG_TIMER_ACTIONS] &&
+ options[OPTION.HIDE_DIALOG_TIMER_ACTIONS] &&
dialogChild.host.localName === ELEMENT.HA_DIALOG_TIMER
)
? STYLES.DIALOG_TIMER_ACTIONS
: '',
(
- this.options[OPTION.HIDE_DIALOG_MEDIA_ACTIONS] &&
+ options[OPTION.HIDE_DIALOG_MEDIA_ACTIONS] &&
dialogChild.host.localName === ELEMENT.HA_DIALOG_MEDIA_PLAYER
)
? STYLES.DIALOG_MEDIA_ACTIONS
: '',
(
- this.options[OPTION.HIDE_DIALOG_UPDATE_ACTIONS] &&
+ options[OPTION.HIDE_DIALOG_UPDATE_ACTIONS] &&
dialogChild.host.localName === ELEMENT.HA_DIALOG_UPDATE
) ? STYLES.DIALOG_UPDATE_ACTIONS
: '',
(
- this.options[OPTION.HIDE_DIALOG_LIGHT_ACTIONS] ||
- this.options[OPTION.HIDE_DIALOG_LIGHT_CONTROL_ACTIONS]
+ options[OPTION.HIDE_DIALOG_LIGHT_ACTIONS] ||
+ options[OPTION.HIDE_DIALOG_LIGHT_CONTROL_ACTIONS]
)
? STYLES.DIALOG_LIGHT_CONTROL_ACTIONS
: '',
(
- this.options[OPTION.HIDE_DIALOG_LIGHT_ACTIONS] ||
- this.options[OPTION.HIDE_DIALOG_LIGHT_COLOR_ACTIONS]
+ options[OPTION.HIDE_DIALOG_LIGHT_ACTIONS] ||
+ options[OPTION.HIDE_DIALOG_LIGHT_COLOR_ACTIONS]
)
? STYLES.DIALOG_LIGHT_COLOR_ACTIONS
: '',
(
- this.options[OPTION.HIDE_DIALOG_LIGHT_ACTIONS] ||
- this.options[OPTION.HIDE_DIALOG_LIGHT_SETTINGS_ACTIONS]
+ options[OPTION.HIDE_DIALOG_LIGHT_ACTIONS] ||
+ options[OPTION.HIDE_DIALOG_LIGHT_SETTINGS_ACTIONS]
)
? STYLES.DIALOG_LIGHT_SETTINGS_ACTIONS
: ''
];
addStyle(styles.join(''), dialogChild);
if (queryString(SPECIAL_QUERY_PARAMS.CACHE)) {
- if (this.options[OPTION.HIDE_DIALOG_ATTRIBUTES]) setCache(OPTION.HIDE_DIALOG_ATTRIBUTES, TRUE);
- if (this.options[OPTION.HIDE_DIALOG_TIMER_ACTIONS]) setCache(OPTION.HIDE_DIALOG_TIMER_ACTIONS, TRUE);
- if (this.options[OPTION.HIDE_DIALOG_MEDIA_ACTIONS]) setCache(OPTION.HIDE_DIALOG_MEDIA_ACTIONS, TRUE);
- if (this.options[OPTION.HIDE_DIALOG_UPDATE_ACTIONS]) setCache(OPTION.HIDE_DIALOG_UPDATE_ACTIONS, TRUE);
- if (this.options[OPTION.HIDE_DIALOG_LIGHT_ACTIONS]) setCache(OPTION.HIDE_DIALOG_LIGHT_ACTIONS, TRUE);
- if (this.options[OPTION.HIDE_DIALOG_LIGHT_CONTROL_ACTIONS]) setCache(OPTION.HIDE_DIALOG_LIGHT_CONTROL_ACTIONS, TRUE);
- if (this.options[OPTION.HIDE_DIALOG_LIGHT_COLOR_ACTIONS]) setCache(OPTION.HIDE_DIALOG_LIGHT_COLOR_ACTIONS, TRUE);
- if (this.options[OPTION.HIDE_DIALOG_LIGHT_SETTINGS_ACTIONS]) setCache(OPTION.HIDE_DIALOG_LIGHT_SETTINGS_ACTIONS, TRUE);
+ if (options[OPTION.HIDE_DIALOG_ATTRIBUTES]) setCache(OPTION.HIDE_DIALOG_ATTRIBUTES, TRUE);
+ if (options[OPTION.HIDE_DIALOG_TIMER_ACTIONS]) setCache(OPTION.HIDE_DIALOG_TIMER_ACTIONS, TRUE);
+ if (options[OPTION.HIDE_DIALOG_MEDIA_ACTIONS]) setCache(OPTION.HIDE_DIALOG_MEDIA_ACTIONS, TRUE);
+ if (options[OPTION.HIDE_DIALOG_UPDATE_ACTIONS]) setCache(OPTION.HIDE_DIALOG_UPDATE_ACTIONS, TRUE);
+ if (options[OPTION.HIDE_DIALOG_LIGHT_ACTIONS]) setCache(OPTION.HIDE_DIALOG_LIGHT_ACTIONS, TRUE);
+ if (options[OPTION.HIDE_DIALOG_LIGHT_CONTROL_ACTIONS]) setCache(OPTION.HIDE_DIALOG_LIGHT_CONTROL_ACTIONS, TRUE);
+ if (options[OPTION.HIDE_DIALOG_LIGHT_COLOR_ACTIONS]) setCache(OPTION.HIDE_DIALOG_LIGHT_COLOR_ACTIONS, TRUE);
+ if (options[OPTION.HIDE_DIALOG_LIGHT_SETTINGS_ACTIONS]) setCache(OPTION.HIDE_DIALOG_LIGHT_SETTINGS_ACTIONS, TRUE);
}
} else {
removeStyle(dialogChild);
@@ -573,19 +599,19 @@ class KioskMode implements KioskModeRunner {
// History and Logbook
if (
- this.options[OPTION.HIDE_DIALOG_HISTORY] ||
- this.options[OPTION.HIDE_DIALOG_LOGBOOK]
+ options[OPTION.HIDE_DIALOG_HISTORY] ||
+ options[OPTION.HIDE_DIALOG_LOGBOOK]
) {
const styles = [
- this.options[OPTION.HIDE_DIALOG_HISTORY]
+ options[OPTION.HIDE_DIALOG_HISTORY]
? STYLES.DIALOG_HISTORY : '',
- this.options[OPTION.HIDE_DIALOG_LOGBOOK]
+ options[OPTION.HIDE_DIALOG_LOGBOOK]
? STYLES.DIALOG_LOGBOOK : ''
];
addStyle(styles.join(''), moreInfo);
if (queryString(SPECIAL_QUERY_PARAMS.CACHE)) {
- if (this.options[OPTION.HIDE_DIALOG_HISTORY]) setCache(OPTION.HIDE_DIALOG_HISTORY, TRUE);
- if (this.options[OPTION.HIDE_DIALOG_LOGBOOK]) setCache(OPTION.HIDE_DIALOG_LOGBOOK, TRUE);
+ if (options[OPTION.HIDE_DIALOG_HISTORY]) setCache(OPTION.HIDE_DIALOG_HISTORY, TRUE);
+ if (options[OPTION.HIDE_DIALOG_LOGBOOK]) setCache(OPTION.HIDE_DIALOG_LOGBOOK, TRUE);
}
} else {
removeStyle(moreInfo);
@@ -596,7 +622,7 @@ class KioskMode implements KioskModeRunner {
.$
.element
.then((dialogHistory: ShadowRoot) => {
- if (this.options[OPTION.HIDE_DIALOG_HISTORY_SHOW_MORE]) {
+ if (options[OPTION.HIDE_DIALOG_HISTORY_SHOW_MORE]) {
addStyle(STYLES.DIALOG_SHOW_MORE, dialogHistory);
if (queryString(SPECIAL_QUERY_PARAMS.CACHE)) setCache(OPTION.HIDE_DIALOG_HISTORY_SHOW_MORE, TRUE);
} else {
@@ -609,7 +635,7 @@ class KioskMode implements KioskModeRunner {
.$
.element
.then((dialogLogbook: ShadowRoot) => {
- if (this.options[OPTION.HIDE_DIALOG_LOGBOOK_SHOW_MORE]) {
+ if (options[OPTION.HIDE_DIALOG_LOGBOOK_SHOW_MORE]) {
addStyle(STYLES.DIALOG_SHOW_MORE, dialogLogbook);
if (queryString(SPECIAL_QUERY_PARAMS.CACHE)) setCache(OPTION.HIDE_DIALOG_LOGBOOK_SHOW_MORE, TRUE);
} else {
@@ -641,11 +667,7 @@ class KioskMode implements KioskModeRunner {
this.HAElements.HEADER.selector.query(`${ELEMENT.TOOLBAR} ${ELEMENT.OVERLAY_MENU_ITEM}`).all
.then((overflowMenuItems: NodeListOf) => {
overflowMenuItems.forEach((overflowMenuItem: HTMLElement): void => {
- if (
- overflowMenuItem &&
- overflowMenuItem.dataset &&
- !overflowMenuItem.dataset.selector
- ) {
+ if (!overflowMenuItem?.dataset?.selector) {
const textContent = overflowMenuItem.textContent.trim();
overflowMenuItem.dataset.selector = this.menuTranslations[textContent];
}
@@ -654,49 +676,75 @@ class KioskMode implements KioskModeRunner {
}
}
- // Run on entity change
- protected async entityWatch() {
- (await window.hassConnection).conn.subscribeMessage((e) => this.entityWatchCallback(e), {
- type: SUSCRIBE_EVENTS_TYPE,
- event_type: STATE_CHANGED_EVENT,
- });
- }
-
- protected async entityWatchCallback(event: SuscriberEvent) {
- const entities = window.kioskModeEntities[this.ha?.hass?.panelUrl] || [];
- if (
- entities.length &&
- event.event_type === STATE_CHANGED_EVENT &&
- entities.includes(event.data.entity_id) &&
- (
- !event.data.old_state ||
- event.data.new_state.state !== event.data.old_state.state
- )
- ) {
- await this.run();
- this.runDialogs();
- }
- }
-
protected blockEventHandler(event: Event) {
event.preventDefault();
event.stopImmediatePropagation();
}
- protected setOptions(config: ConditionalKioskConfig, conditional: boolean) {
+ protected setOptions(options: Options, config: ConditionalKioskConfig, conditional: boolean) {
Object.values(OPTION).forEach((option: OPTION): void => {
if (option in config) {
- this.options[option] = config[option];
+ this.setOptionsOrSubscribe(options, config, option);
}
});
if (conditional) {
Object.values(CONDITIONAL_OPTION).forEach((option: CONDITIONAL_OPTION): void => {
if (option in config) {
- this.options[option] = config[option];
+ if (typeof config[option] === 'boolean') {
+ options[option] = config[option];
+ } else {
+ throw SyntaxError(`${NAMESPACE}: the option "${option}" accepts only boolean values`);
+ }
}
});
}
}
+
+ protected setOptionsOrSubscribe(options: Options, config: ConditionalKioskConfig, option: OPTION | CONDITIONAL_OPTION) {
+ const panelUrl = this._getPanelUrl();
+ const value = config[option];
+ if (typeof value === 'boolean') {
+ options[option] = value;
+ } else if (JINJA_TEMPLATE_REG.test(value)) {
+ window.hassConnection.then((hassConnection: HassConnection): void => {
+ hassConnection.conn.subscribeMessage(
+ (message: SubscriberTemplate): void => {
+ const result = message.result;
+ if (typeof result === 'boolean') {
+ options[option] = result;
+ } else if (
+ typeof result === 'string'
+ && (
+ result === 'true' ||
+ result === 'false'
+ )
+ ) {
+ options[option] = result === 'true';
+ } else {
+ options[option] = false;
+ console.warn(`${NAMESPACE}: the Jinja template "${value}" of the option "${option}" doesn't return a boolean value. The option has been set as false`);
+ }
+ if (this._getPanelUrl() === panelUrl) {
+ this.insertStyles();
+ this.runDialogs();
+ }
+ },
+ {
+ type: SUBSCRIBE_RENDER_TEMPLATE,
+ template: value,
+ variables: {
+ user_name: this.ha.hass.user.name,
+ user_is_admin: this.ha.hass.user.is_admin,
+ user_is_owner: this.ha.hass.user.is_owner,
+ user_agent: window.navigator.userAgent
+ }
+ }
+ );
+ });
+ } else {
+ throw SyntaxError(`${NAMESPACE}: the value "${value}" of the option "${option}" is not a well formed Jinja template`);
+ }
+ }
}
// Console tag
diff --git a/src/types/index.ts b/src/types/index.ts
index 544e46a..a8ff298 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -8,10 +8,10 @@ export interface KioskModeRunner {
export interface User {
name: string;
is_admin: boolean;
+ is_owner: boolean;
}
export interface MobileSettings extends Exclude {
- hide_header: boolean;
custom_width: number;
}
@@ -19,22 +19,23 @@ export interface UserSetting extends ConditionalKioskConfig {
users: string[];
}
-export interface EntitySetting extends KioskConfig {
- entity: Record;
-}
-
-export type EntitySettings = EntitySetting[];
-
type BaseKioskConfig = Partial<
Record<
OPTION,
- boolean
+ boolean | string
>
>;
type BaseConditionalKioskConfig = Partial<
Record<
CONDITIONAL_OPTION,
+ boolean | string
+ >
+>;
+
+export type Options = Partial<
+ Record<
+ OPTION | CONDITIONAL_OPTION,
boolean
>
>;
@@ -44,15 +45,10 @@ export interface KioskConfig extends BaseKioskConfig {
non_admin_settings?: ConditionalKioskConfig;
user_settings?: UserSetting[];
mobile_settings?: MobileSettings;
- entity_settings?: EntitySettings;
}
export type ConditionalKioskConfig = KioskConfig & BaseConditionalKioskConfig;
-export interface EntityState {
- state: string;
-}
-
export class HomeAssistant extends HTMLElement {
hass: {
user: User;
@@ -62,7 +58,6 @@ export class HomeAssistant extends HTMLElement {
language: string;
resources: Record>;
panelUrl: string;
- states: Record;
};
}
@@ -75,35 +70,27 @@ export class Lovelace extends HTMLElement {
};
}
-export type SuscriberEvent = {
- event_type: string;
- data: {
- entity_id: string;
- old_state?: {
- state: string;
- };
- new_state: {
- state: string;
- };
- }
-};
-export type SuscriberCallback = (event: SuscriberEvent) => void;
-export type SuscriberOptions = {
- type: string;
- event_type: string;
+export type SubscriberTemplate = {
+ result: string;
};
export interface HassConnection {
conn: {
- subscribeMessage: (callback: SuscriberCallback, options: SuscriberOptions) => void;
+ subscribeMessage: (
+ callback: (response: T) => void,
+ options: Record>
+ ) => void;
}
}
export type StyleElement = Element | ShadowRoot | Element[] | ShadowRoot[];
+export interface MoreInfoDialog extends HTMLElement {
+ __open: boolean;
+}
+
declare global {
interface Window {
- kioskModeEntities: Record;
KioskMode: KioskModeRunner;
hassConnection: Promise;
}