@paperbits/core
Version:
Paperbits core components.
118 lines (100 loc) • 4.99 kB
text/typescript
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;
}
}