UNPKG

@paperbits/core

Version:
118 lines (100 loc) 4.99 kB
import { Bag } from "@paperbits/common"; import { IWidgetBinding } from "@paperbits/common/editing"; import { EventManager, Events } from "@paperbits/common/events"; import { NavigationEvents, NavigationItemModel } from "@paperbits/common/navigation"; import { HyperlinkModel } from "@paperbits/common/permalinks"; import { StyleCompiler } from "@paperbits/common/styles"; import { ViewModelBinder } from "@paperbits/common/widgets"; import { MenuContract, MenuModelBinder } from ".."; import { MenuHandlers } from "../menuHandlers"; import { MenuModel } from "../menuModel"; import { MenuItemViewModel } from "./menuItemViewModel"; import { MenuViewModel } from "./menuViewModel"; import { ComponentFlow } from "@paperbits/common/components"; export class MenuViewModelBinder implements ViewModelBinder<MenuModel, MenuViewModel> { constructor( private readonly eventManager: EventManager, private readonly menuModelBinder: MenuModelBinder, private readonly styleCompiler: StyleCompiler ) { } private menuItemModelToViewModel(navitem: NavigationItemModel, level: number = 0): MenuItemViewModel { level++; const targetUrl = navitem.targetUrl ? `${navitem.targetUrl}${navitem.anchor ? "#" + navitem.anchor : ""}` : "#"; const viewModel = new MenuItemViewModel(); viewModel.label(navitem.label || "< No label >"); viewModel.isActive(navitem.isActive); viewModel.level(level); const hyperlink = new HyperlinkModel(); hyperlink.href = targetUrl; hyperlink.targetKey = navitem.targetKey; hyperlink.target = navitem.targetWindow; hyperlink.triggerEvent = navitem.triggerEvent; viewModel.hyperlink(hyperlink); if (navitem.nodes) { viewModel.nodes(navitem.nodes.map(childNavitem => this.menuItemModelToViewModel(childNavitem, level))); } return viewModel; } public async modelToViewModel(model: MenuModel, viewModel?: MenuViewModel, bindingContext?: Bag<any>): Promise<MenuViewModel> { if (!viewModel) { viewModel = new MenuViewModel(); } const menuItems = model.items.map(menuItem => this.menuItemModelToViewModel(menuItem)); viewModel.nodes(menuItems); viewModel.layout(model.layout); viewModel.security(model.security); if (model.styles) { viewModel.styles(await this.styleCompiler.getStyleModelAsync(model.styles, bindingContext?.styleManager)); } const onUpdate = async (updatedRootModel: NavigationItemModel): Promise<void> => { if (updatedRootModel.key === model.navigationItem?.key) { const menuItems = updatedRootModel.nodes.map(menuItem => this.menuItemModelToViewModel(menuItem)); viewModel.nodes(menuItems); } }; const binding: IWidgetBinding<MenuModel, MenuViewModel> = { name: "menu", displayName: "Menu", layer: bindingContext?.layer, model: model, flow: ComponentFlow.Inline, // Commented out due do discovered backward compatibility issues. draggable: true, handler: MenuHandlers, editor: "menu-editor", applyChanges: async (updates: MenuModel) => { const contract: MenuContract = { type: "menu", navigationItemKey: updates.navigationItem?.key, layout: updates.layout, security: updates.security, minHeading: updates.minHeading, maxHeading: updates.maxHeading, styles: updates.styles }; const model1 = await this.menuModelBinder.contractToModel(contract, bindingContext); model.navigationItem = model1.navigationItem; model.items = model1.items; model.layout = model1.layout; model.security = model1.security; model.minHeading = model1.minHeading; model.maxHeading = model1.maxHeading; model.styles = model1.styles; await this.modelToViewModel(model, viewModel, bindingContext); this.eventManager.dispatchEvent(Events.ContentUpdate); }, onCreate: () => { this.eventManager.addEventListener(NavigationEvents.onNavigationItemUpdate, onUpdate); }, onDispose: () => { this.eventManager.removeEventListener(NavigationEvents.onNavigationItemUpdate, onUpdate); } }; viewModel["widgetBinding"] = binding; return viewModel; } public canHandleModel(model: MenuModel): boolean { return model instanceof MenuModel; } }