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