UNPKG

activator-oce-exporter

Version:

Extract Activator binder and convert it to valid OCE mono pacakge

261 lines (222 loc) 7.88 kB
import { LitElement, html } from '@polymer/lit-element'; import { connect } from 'pwa-helpers/connect-mixin.js'; import { store } from '../store.js'; /** * @typedef {object} LitElementProperty * @property {function} type - constructor of built-in objects, e.g. String, Boolean etc. * @property {string} fieldType - 'Select', 'Number', 'String', 'Boolean', 'ColorPicker', 'File' * @property {string} value * @property {string[]} [selectOptions] - if .fieldType === 'Select' * @property {string} [assetType] - if .fieldType === 'File' * @property {string} [min] * @property {string} [max] * @property {string} [step] * @property {boolean} [prop] - if .prop === true this property wouldn't be reflected in the style property. * @property {string[]} [attributes] - attribute names, value of which should be set together with the current property */ // These are the actions needed by this element. import { registerState, pushState, setStates, removeState, forwardState, backwardState, unregisterState, reRegisterState, } from './_actions/app.js'; import { getLevel, addLevel, removeLevel, setLevel, } from './_actions/levels.js'; import { promisifyEvent } from './utils'; const setLevelCallback = (el, level) => { const multiplier = el.constructor.options.baseLevel || 100; el.style.setProperty('--level', level * multiplier); el.level = level; }; class FusionBase extends connect(store)(LitElement) { set id(value) { if (!this.oldId) this.oldId = this.getAttribute('id'); if (value !== this.oldId) { if (this.state) { this.reRegisterState(this.state, value); if (store.getState().app.currentState && store.getState().app.currentState.indexOf(`${this.state}-${this.oldId}`) > -1) { this.pushState(this.state, value); } this.removeState(this.state, this.oldId); } this.setAttribute('id', value); this.oldId = value; } } get id() { return this.getAttribute('id'); } constructor() { super(); /** * @description use this flag to detect initial update of attributes (former isStartInit) */ this.isRendered = false; /** * @description promise that resolves when the 'publish' event fires */ this.untilPublished = promisifyEvent(this, 'published'); this.checkPublish(); } /** * @private * @returns {Promise<void>} */ async checkPublish() { await promisifyEvent(document, 'DOMContentLoaded'); this.emitCustomEvent('published'); } /** * Should be called in the firstUpdated callback. Waits until update is complete and emits 'rendered' event * @private * @returns {Promise<void>} */ async checkRender() { await this.updateComplete; this.emitCustomEvent('rendered'); this.isRendered = true; } firstUpdated(changedProperties) { super.firstUpdated(changedProperties); this.setSlotTextEditorDetection(); this.checkRender(); } // eslint-disable-next-line class-methods-use-this, no-unused-vars parentStateChanged(parentState) {} disconnectedCallback() { super.disconnectedCallback(); this.emitCustomEvent(`${this.constructor.options.componentName}:disconnected`); } setSlotTextEditorDetection() { this.isEditProp = false; const slot = this.shadowRoot && (this.shadowRoot.querySelector('slot[name="content"]') || this.shadowRoot.querySelector('slot:not([name="mo-system"])')); if (slot && this.constructor.options.isTextEdit) { slot.addEventListener('slotchange', () => { this.isEditProp = slot.assignedNodes().some(node => node.textContent.trim().length || (node.tagName && ['VIDEO', 'AUDIO', 'SVG', 'CANVAS', 'IMG'].indexOf(node.tagName) === -1 && node.tagName.indexOf('-') === -1)); }); } } propsChange(cb) { Object.keys(this.constructor.properties).forEach((key) => { const item = this.constructor.properties[key]; cb.call(this, key, item); }); } getStyleValue(key, item) { return (this[key] === undefined) ? item.value : this[key]; } setDefaultStyles(key, item) { if (!item.prop) { this.style.setProperty(`--${key}`, this.getStyleValue(key, item)); this.setAttribute(key, this.getStyleValue(key, item)); } } setElementProp(attr, value) { this.style.setProperty(`--${attr}`, value); this.style.setProperty(attr, value); // this.setAttribute(attr, value); } set isEditProp(value) { this.setAttribute('isedit', value); } static getStyle() { return ` :host button, :host textarea, :host input { font: inherit; }`; } render() { /* @todo need to remove 'this.propsChange' from here and leave clear function */ this.propsChange(this.setDefaultStyles); } static getSystemSlotTemplate() { return html`<slot name="mo-system"></slot>`; } registerState(state, id = this.id) { const stateName = `${state}-${id}`; store.dispatch(registerState(stateName)); } unregisterState(state, id = this.id) { const stateName = `${state}-${id}`; store.dispatch(unregisterState(stateName)); } reRegisterState(state, id = this.id) { const stateName = `${state}-${id}`; const stateNameOld = `${state}-${this.oldId}`; store.dispatch(reRegisterState({ stateName, stateNameOld })); } // param states is provided as a string with spaces by default // Set separator in param to update, e.g. ',' setStates(states, id = this.id, includeId = true, separator = ' ') { const stateList = states.split(separator).map((state) => { const stateName = includeId ? `${state}-${id}` : state; return stateName; }); const actualStates = stateList.filter(item => store.getState().app.registeredStates.includes(item)); store.dispatch(setStates(actualStates)); document.body.classList.add(...actualStates); } pushState(state, id = this.id, includeId = true) { const stateName = includeId ? `${state}-${id}` : state; store.dispatch(pushState(stateName)); document.body.classList.add(stateName); } removeState(state, id = this.id, includeId = true) { const stateName = includeId ? `${state}-${id}` : state; store.dispatch(removeState(stateName)); document.body.classList.remove(stateName); } static nextState() { store.dispatch(forwardState()); } static previousState() { store.dispatch(backwardState()); } addLevel() { setLevelCallback(this, FusionBase.getLevel().topLevel + 1); return store.dispatch(addLevel()); } removeLevel(transitionTime = 0) { if (transitionTime > 0) { setTimeout(() => { this.removeLevelDispatch(); }, transitionTime); } else { this.removeLevelDispatch(); } } removeLevelDispatch() { store.dispatch(removeLevel(this.level)); this.style.setProperty('--level', 0); this.level = 0; } static getLevel() { return store.dispatch(getLevel()); } setLevel(level) { setLevelCallback(this, level); return store.dispatch(setLevel(level)); } /** * @param {string} eventName name of created event * @param {{detail: Object, bubbles: Boolean, composed: Boolean}} props event properties */ emitCustomEvent(eventName, props = {}) { if (eventName) { const eventProps = { bubbles: true, composed: true, ...props }; const event = new CustomEvent(eventName, eventProps); this.dispatchEvent(event); return event; } throw new Error(`[ERR:Base:fusion] missed eventName: ${eventName}`); } /** * Get all children. * Limitation for now: should filter children via possible nestedTypes & nestedComponents * @return Array List of components * */ /* @todo should filter children via possible nestedTypes & nestedComponents */ getChildComponents() { return Array.from(this.children); } } export { FusionBase };