@paperbits/core
Version:
Paperbits core components.
69 lines (56 loc) • 2.96 kB
text/typescript
import * as ko from "knockout";
import { HtmlPage } from "@paperbits/common/publishing/htmlPage";
import { HtmlPagePublisherPlugin } from "@paperbits/common/publishing/htmlPagePublisherPlugin";
import { ILayoutService } from "@paperbits/common/layouts";
import { ContentViewModelBinder } from "../content/ko";
import { PopupHostViewModelBinder } from "../popup/ko/popupHostViewModelBinder";
import { HtmlDocumentProvider } from "@paperbits/common/publishing";
declare var global: any;
export class KnockoutHtmlPagePublisherPlugin implements HtmlPagePublisherPlugin {
constructor(
private readonly htmlDocumentProvider: HtmlDocumentProvider,
private readonly contentViewModelBinder: ContentViewModelBinder,
private readonly layoutService: ILayoutService,
private readonly popupHostViewModelBinder: PopupHostViewModelBinder
) {
this.initialize();
}
private initialize(): void {
if (global.document) {
return;
}
const document = this.htmlDocumentProvider.createDocument(); // KO referenced global document
global.window = document.defaultView.window;
global.document = document;
// this needed to avoid rendering issues with domino in different environments.
ko.tasks.scheduler = (callback) => setImmediate(callback);
}
private renderContent(doc: Document, layoutContentViewModel: any): Promise<void> {
return new Promise((resolve, reject) => {
try {
const onDescendantsComplete = () => {
ko.cleanNode(doc.body);
resolve();
};
ko.applyBindingsToNode(doc.body, {
widget: layoutContentViewModel,
descendantsComplete: onDescendantsComplete,
}, null);
}
catch (error) {
reject(`Unable to apply knockout bindings to a template: ${error.stack || error.message}`);
}
});
}
public async apply(doc: Document, page: HtmlPage): Promise<void> {
const layoutContract = await this.layoutService.getLayoutByPermalink(page.permalink, page.bindingContext?.locale);
if (!layoutContract) {
throw new Error(`No matching layouts found for page with permalink "${page.permalink}".`);
}
const layoutContentContract = await this.layoutService.getLayoutContent(layoutContract.key, page.bindingContext?.locale);
const layoutContentViewModel = await this.contentViewModelBinder.contractToViewModel(layoutContentContract, page.bindingContext);
const popupHostViewModel = await this.popupHostViewModelBinder.contractToViewModel(page.bindingContext);
layoutContentViewModel.widgets.unshift(popupHostViewModel);
await this.renderContent(doc, layoutContentViewModel);
}
}