UNPKG

@paperbits/core

Version:
159 lines (129 loc) 6.47 kB
import { Bag } from "@paperbits/common"; import { CollectionModelBinder, IWidgetBinding } from "@paperbits/common/editing"; import { EventManager, Events } from "@paperbits/common/events"; import { IPopupService } from "@paperbits/common/popups"; import { StyleCompiler } from "@paperbits/common/styles"; import { IWidgetService, ViewModelBinder } from "@paperbits/common/widgets"; import { PopupInstanceContract } from "../popupContract"; import { ViewModelBinderSelector } from "../../ko/viewModelBinderSelector"; import { Placeholder } from "../../placeholder/ko/placeholder"; import { PopupHandlers } from "../popupHandlers"; import { PopupInstanceModel } from "../popupModel"; import { PopupViewModel } from "./popup"; import { ComponentFlow } from "@paperbits/common/components"; export class PopupViewModelBinder implements ViewModelBinder<PopupInstanceModel, PopupViewModel> { constructor( private readonly containerModelBinder: CollectionModelBinder, private readonly viewModelBinderSelector: ViewModelBinderSelector, private readonly popupService: IPopupService, private readonly eventManager: EventManager, private readonly styleCompiler: StyleCompiler, private readonly widgetService: IWidgetService ) { } public createBinding(model: PopupInstanceModel, viewModel?: PopupViewModel, bindingContext?: Bag<any>): void { let savingTimeout; const updateContent = async (): Promise<void> => { /** * TODO: Temporary hack. With current model it's impossible to tell which content (page or content) * is being modified, so we look for active popup. */ if (!bindingContext.getHostedDocument) { return; } const activePopup: HTMLElement = bindingContext.getHostedDocument().querySelector(".popup.show"); if (!activePopup) { return; } const popupIdentifier = activePopup.id.replace("popups", ""); const popupKey = `popups/${popupIdentifier}`; if (model.key !== popupKey) { return; } const popupInstanceContract: PopupInstanceContract = { type: "popup", backdrop: model.backdrop, styles: model.styles, nodes: [] }; const childNodes = this.containerModelBinder.getChildContracts(model.widgets); popupInstanceContract.nodes.push(...childNodes); await this.popupService.updatePopupContent(model.key, popupInstanceContract); }; const scheduleUpdate = (): void => { clearTimeout(savingTimeout); savingTimeout = setTimeout(updateContent, 500); }; const binding: IWidgetBinding<PopupInstanceModel, PopupViewModel> = { name: "popup", displayName: "Popup", layer: "*", flow: ComponentFlow.Block, model: model, draggable: true, editor: "popup-editor", provides: ["popup"], handler: PopupHandlers, applyChanges: async () => { await this.modelToViewModel(model, viewModel, bindingContext); this.eventManager.dispatchEvent(Events.ContentUpdate, model.key); }, onCreate: () => { this.eventManager.addEventListener(Events.ContentUpdate, scheduleUpdate); }, onDispose: () => { this.eventManager.removeEventListener(Events.ContentUpdate, scheduleUpdate); } }; viewModel["widgetBinding"] = binding; } public async modelToViewModel(model: PopupInstanceModel, viewModel?: PopupViewModel, bindingContext?: Bag<any>): Promise<PopupViewModel> { if (!viewModel) { viewModel = new PopupViewModel(); } // let childBindingContext: Bag<any> = {}; // if (bindingContext) { // childBindingContext = <Bag<any>>Objects.clone(bindingContext); // childBindingContext.layer = "*"; // } bindingContext.layer = "*"; const promises = model.widgets.map(widgetModel => { const definition = this.widgetService.getWidgetDefinitionForModel(widgetModel); if (definition) { const bindingPromise = this.widgetService.createWidgetBinding(definition, widgetModel, bindingContext); return bindingPromise; } // legacy binding resolution const widgetViewModelBinder = this.viewModelBinderSelector.getViewModelBinderByModel(widgetModel); const bindingPromise = widgetViewModelBinder.modelToViewModel(widgetModel, null, bindingContext); return bindingPromise; }); const widgetViewModels = await Promise.all(promises); // for (const widgetModel of model.widgets) { // const widgetViewModelBinder = this.viewModelBinderSelector.getViewModelBinderByModel(widgetModel); // if (widgetViewModelBinder.createWidgetBinding) { // const binding = await widgetViewModelBinder.createWidgetBinding<any>(widgetModel, bindingContext); // widgetViewModels.push(binding); // } // else { // const widgetViewModel = await widgetViewModelBinder.modelToViewModel(widgetModel, null, bindingContext); // widgetViewModels.push(widgetViewModel); // } // } if (widgetViewModels.length === 0) { widgetViewModels.push(new Placeholder("Popup content")); } if (model.styles) { viewModel.styles(await this.styleCompiler.getStyleModelAsync(model.styles, bindingContext?.styleManager)); } viewModel.identifier(model.key.replace("popups/", "popups")); viewModel.widgets(widgetViewModels); viewModel.backdrop(model.backdrop); if (!viewModel["widgetBinding"]) { this.createBinding(model, viewModel, bindingContext); } return viewModel; } public canHandleModel(model: PopupInstanceModel): boolean { return model instanceof PopupInstanceModel; } }