activator-oce-exporter
Version:
Extract Activator binder and convert it to valid OCE mono pacakge
261 lines (222 loc) • 7.88 kB
JavaScript
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 };