mt-music-player
Version:
A simply web music player app.
126 lines (110 loc) • 3.44 kB
JavaScript
import { html, render } from 'https://dev.jspm.io/lit-html';
import {
store, connect, disConnect, PAGE_KEY,
} from '../models/index.js';
import { mergeObject } from '../utils/object.js';
const uniqueDataPropMap = new WeakMap();
const uniqueConnectedPageMap = new WeakMap();
export default class Component extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
uniqueDataPropMap.set(this, Symbol('data'));
uniqueConnectedPageMap.set(this, new Set());
this.update = this.update.bind(this);
this.render = this.render.bind(this);
this.connected = this.connected.bind(this);
this.disconnected = this.disconnected.bind(this);
this.attributeChanged = this.attributeChanged.bind(this);
this.setState = this.setState.bind(this);
}
get state() {
const currentState = this[uniqueDataPropMap.get(this)];
if (currentState && currentState[PAGE_KEY]) {
return store[currentState[PAGE_KEY]];
}
return currentState;
}
set state(value) {
if (typeof value !== 'object') throw new Error('Must use the object');
if (!this[uniqueDataPropMap.get(this)]) {
this[uniqueDataPropMap.get(this)] = value;
const binding = (obj) => {
if (obj[PAGE_KEY]) {
connect(
obj[PAGE_KEY],
this.update,
);
uniqueConnectedPageMap.get(this).add(obj[PAGE_KEY]);
} else {
const keys = Object.keys(obj);
keys.forEach((key) => {
if (typeof obj[key] === 'object' && obj[key]) binding(obj[key]);
});
}
};
binding(value);
return true;
}
throw new Error('Prohibit multiple direct assignments');
}
update() {
render(this.render(), this.shadowRoot);
this.updated();
}
updated() {}
connected() {}
connectedCallback() {
this.update();
this.connected();
}
disconnected() {}
disconnectedCallback() {
uniqueConnectedPageMap.get(this).forEach((page) => {
disConnect(page, this.update);
});
this.disconnected();
}
attributeChanged() {}
attributeChangedCallback(...rest) {
this.attributeChanged(...rest);
const { observedAttributes } = this.constructor;
if (this.isConnected && observedAttributes && observedAttributes.includes(rest[0])) {
this.update();
}
}
/**
* update component
* @param {object} payload Will be merged into the state object
*/
setState(payload) {
if (typeof payload !== 'object') throw new Error('Must use the object');
let changeStore = false;
if (this.state[PAGE_KEY]) {
const page = this.state[PAGE_KEY];
// Cannot be merged into new objects
// Avoid `this.state` referencing obsolete objects
store[page] = mergeObject(this.state, payload);
} else {
// Only support for `Store` one layer packaging
// ✔ correct: `{<Store>}` or `store`
// ✖ error: `{{<Store>}}`
const keys = Object.keys(this.state);
keys.forEach((key) => {
const value = this.state[key];
const page = value && value[PAGE_KEY];
if (!(key in payload)) return;
if (page) {
changeStore = true;
store[page] = mergeObject(value, payload[key]);
} else {
this.state[key] = payload[key];
}
});
}
if (!changeStore) this.update();
}
render() {
return html``;
}
}