UNPKG

activator-oce-exporter

Version:

Extract Activator binder and convert it to valid OCE mono pacakge

476 lines (418 loc) 11.9 kB
import { html } from '@polymer/lit-element'; import { FusionBase } from '../../base'; import { FusionLogger } from '../../services/fusion-logger'; import { FusionStore } from '../../services/fusion-store'; import { FusionButton } from '../button'; import { veevaData } from '../../veeva-data'; import { FusionApi } from '../../api'; import { intersectMap, getValueObject } from '../../utils'; import { applyMixins, SlideComponent, Stateful } from '../../mixins'; const defaultTemplate = '<p>Menu item</p>'; class ActivatorBinderApi { constructor() { this.documentId = ''; } formatActivatorItem({ id, name__v: name }) { return { slideDocId: id, slideName: name, slideActive: this.isActive(id), }; } isActive(id) { return this.documentId === id; } addBinderSlides({ binder, document }, arr) { binder.documents.map((item) => { const itemData = item.viewData; this.documentId = document.id; return arr.push(this.formatActivatorItem(itemData)); }); } addSlide({ document }, arr) { arr.push(this.formatActivatorItem(document)); } static isBinder({ isBinder, binder }) { return isBinder && binder; } getActivatorPresentationSlides(data) { const slidesArr = []; if (ActivatorBinderApi.isBinder(data)) { this.addBinderSlides(data, slidesArr); } else { this.addSlide(data, slidesArr); } return slidesArr; } } class VeevaBinderApi { constructor() { this.keyMessageId = ''; } async getVeevaPresentationSlides() { this.keyMessageId = await veevaData.getCurrentKeyMessageId(); const presentationId = await veevaData.getCurrentPresentationId(); const slidesArr = await veevaData.getCurrentPresentationSlides(presentationId); let items = []; items = await this.getKeyMessageInfo(items, slidesArr, 0); return items; } async getKeyMessageInfo(items, slidesArr, index) { if (slidesArr[index]) { const data = await veevaData.getKeyMessageData(slidesArr[index].Key_Message_vod__c); const item = this.formatVeevaItem(data[0]); items.push(item); index += 1; return this.getKeyMessageInfo(items, slidesArr, index); } return items; } static getItemDocId(extId) { const PATH_SEPARATOR = '::'; return extId.split(PATH_SEPARATOR).pop(); } isActive(id) { return this.keyMessageId === id; } formatVeevaItem({ Vault_External_Id_vod__c: externalId, Name, ID }) { return { slideActive: this.isActive(ID), slideDocId: VeevaBinderApi.getItemDocId(externalId), slideName: Name, }; } } class FusionTopMenuButton extends FusionButton { static get properties() { const { top, left, ...others } = super.properties; return { ...others, }; } static get options() { return { ...FusionButton.options, componentName: 'fusion-top-menu-button', defaultTemplate, isRootNested: false, resizable: 'all', draggable: 'xy', rotatable: true, sortable: false, }; } connectedCallback() { super.connectedCallback(); this.init(); } init() { this.initListeners(); this.emitCustomEvent(`${this.constructor.options.componentName}:added`); } static goToSlide(event) { const targetSlide = event.currentTarget.dataset.slide; FusionApi.goTo(targetSlide); } disconnectedCallback() { this.removeEventListener('click', FusionTopMenuButton.goToSlide.bind(this)); } initListeners() { this.addEventListener('click', FusionTopMenuButton.goToSlide.bind(this)); } } class FusionTopMenu extends applyMixins(FusionBase, [SlideComponent, Stateful]) { static get options() { return { componentName: 'fusion-top-menu', componentUIName: 'Top Menu', componentScope: 'standard', componentType: 'static', componentCategory: 'interaction', componentDescription: 'Top menu component to enable navigation in binder', componentDomain: 'slide', isTextEdit: true, isRootNested: true, nestedTypes: [], nestedComponents: ['fusion-top-menu-button'], baseLevel: 100, defaultTemplate: '', resizable: 'all', draggable: 'xy', rotatable: true, sortable: false, }; } static get properties() { return { top: { type: String, fieldType: 'Number', value: '0px', }, left: { type: String, fieldType: 'Number', value: '0px', }, width: { type: String, fieldType: 'Number', value: '1024px', }, height: { type: String, fieldType: 'Number', value: '30px', }, 'background-color': { type: String, fieldType: 'ColorPicker', value: 'rgba(235, 235, 235, 1)', }, }; } toogleMenu() { if (this.active) { this.closeMenu(); } else { this.openMenu(); } } openMenu() { this.pushState(this.state); this.addLevel(); } closeMenu() { this.removeState(this.state); this.removeLevel(); } constructor() { super(); this.state = 'Menu'; this.veevaBinderApi = new VeevaBinderApi(); this.activatorBinderApi = new ActivatorBinderApi(); this.defaultButtonPosition = { top: 0, left: 0 }; this.btnAddEvent = `${FusionTopMenuButton.options.componentName}:added`; } connectedCallback() { super.connectedCallback(); this.environmentSetHandler = this.initMenu.bind(this); this.environmentSetEvent = 'EnvironmentDetector:environmentDetected'; } disconnectedCallback() { super.disconnectedCallback(); this.removeEventListener(this.btnAddEvent, this.buttonAddHandler.bind(this)); document.removeEventListener(this.environmentSetEvent, this.environmentSetHandler); } updateWidth() { const { unit } = getValueObject(this.width); const { offsetWidth } = this.parentNode; if (offsetWidth) { this.width = `${offsetWidth}${unit}`; } } initMenu() { this.updateWidth(); this.addEventListener(this.btnAddEvent, this.buttonAddHandler.bind(this)); if (FusionStore.isActivator) { this.initActivatorMenu(); } else if (FusionStore.isVeeva) { this.initVeevaMenu(); } else { FusionLogger.error('Environment for menu not detected', 'FusionTopMenu'); } } setBinderData(data) { this.closeMenu(); const items = this.activatorBinderApi.getActivatorPresentationSlides(data); this.generateMenuItems(items); } async sendBinderRequest() { const binderData = await FusionApi.request({ name: 'actions/setNavigationBinderData', }); this.setBinderData(binderData); } firstUpdated(changedProps) { super.firstUpdated(changedProps); if (FusionStore.environment) { this.initMenu(); } else { document.addEventListener(this.environmentSetEvent, this.environmentSetHandler); } } async generateMenuButton({ slideName, slideActive }, index) { const defaultProperties = FusionTopMenuButton.properties; const buttonWidth = 200; const buttonHeight = 30; const unit = 'px'; const buttonTemplate = `<p>${slideName}</p>`; const buttonType = slideActive ? 'Primary' : 'Normal'; const buttonPreset = FusionTopMenuButton.getPreset(buttonType); const buttonColor = buttonPreset['background-color']; const buttonTextColor = buttonPreset.color; const item = await FusionApi.createElement( FusionTopMenuButton.options.componentName, { ...defaultProperties, width: { value: `${buttonWidth}${unit}`, }, height: { value: `${buttonHeight}${unit}`, }, 'background-color': { value: buttonColor, }, color: { value: buttonTextColor, }, 'style-type': { value: buttonType, }, 'data-slide': { value: slideName, }, }, buttonTemplate, this, `#${this.id}`, {}, ); item.style.setProperty('--left', `${index * buttonWidth}px`); } removeButtons() { while (this.lastChild) { this.removeChild(this.lastChild); } } generateButtons(slides) { slides.forEach((slide, index) => { this.generateMenuButton(slide, index); }); } getMenuButtons() { const tagName = FusionTopMenuButton.options.componentName; return this.getElementsByTagName(tagName); } static isEmpty(menuButtons) { return menuButtons.length === 0; } static isDiff(slides, buttons) { return slides.length > buttons.length; } static needRegenerate(slides, buttons) { return FusionTopMenu.isEmpty(buttons) || FusionTopMenu.isDiff(slides, buttons); } generateMenuItems(slides) { const buttons = this.getMenuButtons(); if (slides && FusionTopMenu.needRegenerate(slides, buttons)) { this.generateButtons(slides); } } checkSizes(changedProps) { const sizeProps = intersectMap(changedProps, this.constructor.sizeTriggers); if (sizeProps.size) { this.updateButtonsHeight(); } } updateButtonsHeight() { const buttons = Array.from(this.getMenuButtons()); if (buttons && buttons.length) { FusionTopMenu.changeButtonsHeight(buttons, this.height); } } initVeevaMenu() { this.veevaBinderApi.getVeevaPresentationSlides() .then((data) => { if (data) { this.generateMenuItems(data); } }) .catch(err => FusionLogger.error(err, 'FusionTopMenu')); } initButtonPosition(prevBtn, curBtn) { const position = this.getButtonPosition(prevBtn); Object.keys(position).forEach((key) => { FusionTopMenu.setStyle(curBtn, key, `${position[key]}px`); }); curBtn.height = this.height; } static setStyle(target, key, value) { target.style.setProperty(`--${key}`, value); } static getLastButton(buttons) { return (buttons && buttons.length > 1) ? buttons[buttons.length - 2] : null; } getButtonPosition(prevBtn) { if (prevBtn) { const { offsetLeft, offsetWidth, offsetTop } = prevBtn; return { left: offsetLeft + offsetWidth, top: offsetTop, }; } return this.defaultButtonPosition; } buttonAddHandler(e) { const curBtn = e.target; const allBtns = this.getMenuButtons(); const prevBtn = FusionTopMenu.getLastButton(allBtns); this.initButtonPosition(prevBtn, curBtn); } static changeButtonsHeight(buttons, value) { buttons.forEach((button) => { button.height = value; }); } initActivatorMenu() { this.sendBinderRequest(); } render() { super.render(); return html` <style> ${FusionTopMenu.getStyle(0, 0)} :host { display: block; transform: translate3d(0, 0, 0); transition: transform 0.3s 0s; background: var(--background-color); } :host * { margin: 0; padding: 0; } :host(:not([active])){ transform: translate3d(0, calc(var(--height) * -1), 0) !important; } [part="handler"] { width: 50px; height: 15px; background: var(--background-color); position: absolute; top: 100%; left: 50%; border: 0; outline: none; border-bottom-left-radius: 50%; border-bottom-right-radius: 50%; transform:translate3d(-50%, 0 ,0) } [part="nav"] { position: relative; height: 100%; width: var(--width); overflow-x: auto; overflow-y: hidden; } </style> <div part="nav"> <slot></slot> </div> <button part="handler" @click="${() => this.toogleMenu()}"></button> ${FusionTopMenu.getSystemSlotTemplate()} `; } } export { FusionTopMenuButton, FusionTopMenu };