mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 17:26:42 +00:00
Allow local storage decorator to register as property (#6776)
This commit is contained in:
parent
349a5f52b1
commit
b065f002a4
@ -1,7 +1,33 @@
|
|||||||
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
|
import { PropertyDeclaration, UpdatingElement } from "lit-element";
|
||||||
import type { ClassElement } from "../../types";
|
import type { ClassElement } from "../../types";
|
||||||
|
|
||||||
|
type Callback = (oldValue: any, newValue: any) => void;
|
||||||
|
|
||||||
class Storage {
|
class Storage {
|
||||||
private _storage: any = {};
|
constructor() {
|
||||||
|
window.addEventListener("storage", (ev: StorageEvent) => {
|
||||||
|
if (ev.key && this.hasKey(ev.key)) {
|
||||||
|
this._storage[ev.key] = ev.newValue
|
||||||
|
? JSON.parse(ev.newValue)
|
||||||
|
: ev.newValue;
|
||||||
|
if (this._listeners[ev.key]) {
|
||||||
|
this._listeners[ev.key].forEach((listener) =>
|
||||||
|
listener(
|
||||||
|
ev.oldValue ? JSON.parse(ev.oldValue) : ev.oldValue,
|
||||||
|
this._storage[ev.key!]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _storage: { [storageKey: string]: any } = {};
|
||||||
|
|
||||||
|
private _listeners: {
|
||||||
|
[storageKey: string]: Callback[];
|
||||||
|
} = {};
|
||||||
|
|
||||||
public addFromStorage(storageKey: any): void {
|
public addFromStorage(storageKey: any): void {
|
||||||
if (!this._storage[storageKey]) {
|
if (!this._storage[storageKey]) {
|
||||||
@ -12,6 +38,30 @@ class Storage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public subscribeChanges(
|
||||||
|
storageKey: string,
|
||||||
|
callback: Callback
|
||||||
|
): UnsubscribeFunc {
|
||||||
|
if (this._listeners[storageKey]) {
|
||||||
|
this._listeners[storageKey].push(callback);
|
||||||
|
} else {
|
||||||
|
this._listeners[storageKey] = [callback];
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
this.unsubscribeChanges(storageKey, callback);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsubscribeChanges(storageKey: string, callback: Callback) {
|
||||||
|
if (!(storageKey in this._listeners)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const index = this._listeners[storageKey].indexOf(callback);
|
||||||
|
if (index !== -1) {
|
||||||
|
this._listeners[storageKey].splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public hasKey(storageKey: string): any {
|
public hasKey(storageKey: string): any {
|
||||||
return storageKey in this._storage;
|
return storageKey in this._storage;
|
||||||
}
|
}
|
||||||
@ -32,30 +82,49 @@ class Storage {
|
|||||||
|
|
||||||
const storage = new Storage();
|
const storage = new Storage();
|
||||||
|
|
||||||
export const LocalStorage = (key?: string) => {
|
export const LocalStorage = (
|
||||||
return (element: ClassElement, propName: string) => {
|
storageKey?: string,
|
||||||
const storageKey = key || propName;
|
property?: boolean,
|
||||||
const initVal = element.initializer ? element.initializer() : undefined;
|
propertyOptions?: PropertyDeclaration
|
||||||
|
): any => {
|
||||||
|
return (clsElement: ClassElement) => {
|
||||||
|
const key = String(clsElement.key);
|
||||||
|
storageKey = storageKey || String(clsElement.key);
|
||||||
|
const initVal = clsElement.initializer
|
||||||
|
? clsElement.initializer()
|
||||||
|
: undefined;
|
||||||
|
|
||||||
storage.addFromStorage(storageKey);
|
storage.addFromStorage(storageKey);
|
||||||
|
|
||||||
|
const subscribe = (el: UpdatingElement): UnsubscribeFunc =>
|
||||||
|
storage.subscribeChanges(storageKey!, (oldValue) => {
|
||||||
|
el.requestUpdate(clsElement.key, oldValue);
|
||||||
|
});
|
||||||
|
|
||||||
const getValue = (): any => {
|
const getValue = (): any => {
|
||||||
return storage.hasKey(storageKey)
|
return storage.hasKey(storageKey!)
|
||||||
? storage.getValue(storageKey)
|
? storage.getValue(storageKey!)
|
||||||
: initVal;
|
: initVal;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setValue = (val: any) => {
|
const setValue = (el: UpdatingElement, value: any) => {
|
||||||
storage.setValue(storageKey, val);
|
let oldValue: unknown | undefined;
|
||||||
|
if (property) {
|
||||||
|
oldValue = getValue();
|
||||||
|
}
|
||||||
|
storage.setValue(storageKey!, value);
|
||||||
|
if (property) {
|
||||||
|
el.requestUpdate(clsElement.key, oldValue);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
kind: "method",
|
kind: "method",
|
||||||
placement: "own",
|
placement: "prototype",
|
||||||
key: element.key,
|
key: clsElement.key,
|
||||||
descriptor: {
|
descriptor: {
|
||||||
set(value) {
|
set(this: UpdatingElement, value: unknown) {
|
||||||
setValue(value);
|
setValue(this, value);
|
||||||
},
|
},
|
||||||
get() {
|
get() {
|
||||||
return getValue();
|
return getValue();
|
||||||
@ -63,6 +132,24 @@ export const LocalStorage = (key?: string) => {
|
|||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true,
|
configurable: true,
|
||||||
},
|
},
|
||||||
|
finisher(cls: typeof UpdatingElement) {
|
||||||
|
if (property) {
|
||||||
|
const connectedCallback = cls.prototype.connectedCallback;
|
||||||
|
const disconnectedCallback = cls.prototype.disconnectedCallback;
|
||||||
|
cls.prototype.connectedCallback = function () {
|
||||||
|
connectedCallback.call(this);
|
||||||
|
this[`__unbsubLocalStorage${key}`] = subscribe(this);
|
||||||
|
};
|
||||||
|
cls.prototype.disconnectedCallback = function () {
|
||||||
|
disconnectedCallback.call(this);
|
||||||
|
this[`__unbsubLocalStorage${key}`]();
|
||||||
|
};
|
||||||
|
cls.createProperty(clsElement.key, {
|
||||||
|
noAccessor: true,
|
||||||
|
...propertyOptions,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
|
||||||
import "@polymer/paper-item/paper-item";
|
import "@polymer/paper-item/paper-item";
|
||||||
import "@polymer/paper-listbox/paper-listbox";
|
import "@polymer/paper-listbox/paper-listbox";
|
||||||
import {
|
import {
|
||||||
@ -12,6 +11,7 @@ import {
|
|||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
|
import "../ha-paper-dropdown-menu";
|
||||||
import { HaFormElement, HaFormSelectData, HaFormSelectSchema } from "./ha-form";
|
import { HaFormElement, HaFormSelectData, HaFormSelectSchema } from "./ha-form";
|
||||||
|
|
||||||
@customElement("ha-form-select")
|
@customElement("ha-form-select")
|
||||||
@ -24,7 +24,7 @@ export class HaFormSelect extends LitElement implements HaFormElement {
|
|||||||
|
|
||||||
@property() public suffix!: string;
|
@property() public suffix!: string;
|
||||||
|
|
||||||
@query("paper-dropdown-menu") private _input?: HTMLElement;
|
@query("ha-paper-dropdown-menu") private _input?: HTMLElement;
|
||||||
|
|
||||||
public focus() {
|
public focus() {
|
||||||
if (this._input) {
|
if (this._input) {
|
||||||
@ -34,7 +34,7 @@ export class HaFormSelect extends LitElement implements HaFormElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<paper-dropdown-menu .label=${this.label}>
|
<ha-paper-dropdown-menu .label=${this.label}>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
slot="dropdown-content"
|
slot="dropdown-content"
|
||||||
attr-for-selected="item-value"
|
attr-for-selected="item-value"
|
||||||
@ -51,7 +51,7 @@ export class HaFormSelect extends LitElement implements HaFormElement {
|
|||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</paper-listbox>
|
</paper-listbox>
|
||||||
</paper-dropdown-menu>
|
</ha-paper-dropdown-menu>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ export class HaFormSelect extends LitElement implements HaFormElement {
|
|||||||
|
|
||||||
static get styles(): CSSResult {
|
static get styles(): CSSResult {
|
||||||
return css`
|
return css`
|
||||||
paper-dropdown-menu {
|
ha-paper-dropdown-menu {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -191,11 +191,15 @@ class HaSidebar extends LitElement {
|
|||||||
private _recentKeydownActiveUntil = 0;
|
private _recentKeydownActiveUntil = 0;
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@LocalStorage("sidebarPanelOrder")
|
@LocalStorage("sidebarPanelOrder", true, {
|
||||||
|
attribute: false,
|
||||||
|
})
|
||||||
private _panelOrder: string[] = [];
|
private _panelOrder: string[] = [];
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@LocalStorage("sidebarHiddenPanels")
|
@LocalStorage("sidebarHiddenPanels", true, {
|
||||||
|
attribute: false,
|
||||||
|
})
|
||||||
private _hiddenPanels: string[] = [];
|
private _hiddenPanels: string[] = [];
|
||||||
|
|
||||||
private _sortable?;
|
private _sortable?;
|
||||||
@ -400,7 +404,9 @@ class HaSidebar extends LitElement {
|
|||||||
changedProps.has("_externalConfig") ||
|
changedProps.has("_externalConfig") ||
|
||||||
changedProps.has("_notifications") ||
|
changedProps.has("_notifications") ||
|
||||||
changedProps.has("_editMode") ||
|
changedProps.has("_editMode") ||
|
||||||
changedProps.has("_renderEmptySortable")
|
changedProps.has("_renderEmptySortable") ||
|
||||||
|
changedProps.has("_hiddenPanels") ||
|
||||||
|
(changedProps.has("_panelOrder") && !this._editMode)
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user