Files
advanced-camera-card/src/card-controller/card-element-manager.ts
T

137 lines
4.2 KiB
TypeScript

import { LitElement, ReactiveControllerHost } from 'lit';
import { ActionEventTarget } from '../action-handler-directive';
import { setOrRemoveAttribute } from '../utils/basic';
import { isCardInPanel } from '../utils/ha';
import { InitializationAspect } from './initialization-manager';
import { CardElementAPI } from './types';
export type ScrollCallback = () => void;
export type MenuToggleCallback = () => void;
export type CardHTMLElement = LitElement & ReactiveControllerHost & ActionEventTarget;
export class CardElementManager {
protected _api: CardElementAPI;
protected _element: CardHTMLElement;
protected _scrollCallback: ScrollCallback;
protected _menuToggleCallback: MenuToggleCallback;
constructor(
api: CardElementAPI,
element: CardHTMLElement,
scrollCallback: ScrollCallback,
menuToggleCallback: MenuToggleCallback,
) {
this._api = api;
this._element = element;
this._scrollCallback = scrollCallback;
this._menuToggleCallback = menuToggleCallback;
}
public getElement(): HTMLElement {
return this._element;
}
public scrollReset(): void {
this._scrollCallback();
}
public toggleMenu(): void {
this._menuToggleCallback();
}
public update(): void {
this._element.requestUpdate();
}
public hasUpdated(): boolean {
return this._element.hasUpdated;
}
public getCardHeight(): number {
return this._element.getBoundingClientRect().height;
}
public elementConnected(): void {
// Set initial condition state. Must be done after the element is connected to
// allow callbacks to interact with the card.
this._api.getInteractionManager().initialize();
this._api.getFullscreenManager().initialize();
this._api.getExpandManager().initialize();
this._api.getMediaLoadedInfoManager().initialize();
this._api.getMicrophoneManager().initialize();
// Whether or not the card is in panel mode on the dashboard.
setOrRemoveAttribute(this._element, isCardInPanel(this._element), 'panel');
this._api.getFullscreenManager().connect();
this._element.addEventListener(
'mousemove',
this._api.getInteractionManager().reportInteraction,
);
this._element.addEventListener(
'll-custom',
this._api.getActionsManager().handleActionEvent,
);
this._element.addEventListener(
'@action',
this._api.getInteractionManager().reportInteraction,
);
// Listen for HA `navigate` actions.
// See: https://github.com/home-assistant/frontend/blob/273992c8e9c3062c6e49481b6d7d688a07067232/src/common/navigate.ts#L43
window.addEventListener(
'location-changed',
this._api.getQueryStringManager().executeAll,
);
// Listen for history state changes (i.e. user using the browser
// back/forward controls).
window.addEventListener('popstate', this._api.getQueryStringManager().executeAll);
// Manually call the location change handler as the card will be
// disconnected/reconnected when dashboard 'tab' changes happen within HA.
this._api.getQueryStringManager().executeAll();
}
public elementDisconnected(): void {
setOrRemoveAttribute(this._element, false, 'panel');
// When the dashboard 'tab' is changed, the media is effectively unloaded.
this._api.getMediaLoadedInfoManager().clear();
this._api.getFullscreenManager().disconnect();
// Reset and uninitialize cameras to cause them to reinitialize on
// reconnection, to ensure the state subscription/unsubscription works
// correctly for triggers.
this._api
.getCameraManager()
.reset()
.then(() =>
this._api.getInitializationManager().uninitialize(InitializationAspect.CAMERAS),
);
this._element.removeEventListener(
'mousemove',
this._api.getInteractionManager().reportInteraction,
);
this._element.removeEventListener(
'll-custom',
this._api.getActionsManager().handleActionEvent,
);
this._element.removeEventListener(
'@action',
this._api.getInteractionManager().reportInteraction,
);
window.removeEventListener(
'location-changed',
this._api.getQueryStringManager().executeAll,
);
window.removeEventListener('popstate', this._api.getQueryStringManager().executeAll);
}
}