import {createLogger, debugType} from "@gongt/ts-stl-library/debug/create-logger"; import {LOG_LEVEL} from "@gongt/ts-stl-library/debug/levels"; import {ApiResponse, STATUS_CODE_BASE} from "@gongt/ts-stl-library/request/protocol"; import {ErrorResponse} from "@gongt/ts-stl-library/request/request-error"; import {Router} from "express-serve-static-core"; import {RequestContext} from "./base/context"; import {ExpressHandler} from "./base/handler"; import {AssignFunction, AssignObjectFunction, MultiValueResponseWrapper} from "./base/response-wrapper"; export type ViewSettings = { success: string; failed: string; }; export class WebpageHandler extends ExpressHandler> { private defaultView: ViewSettings = {success: '', failed: 'error'}; protected instanceContext(req, res) { return new WebpageRequestContext(req, res, this.defaultView); } registerRouter(route: Router) { super.registerRouter(route); Object.freeze(this.defaultView); } setDefaultView(view: string, error?: string) { this.defaultView.success = view; if (error) { this.defaultView.failed = error; } } } export class WebpageRequestContext extends RequestContext { public assign: AssignFunction; public assignObject: AssignObjectFunction; public readonly defaultView: ViewSettings; public readonly response: WebpageResponseWrapper; constructor(req, res, defaultView: ViewSettings) { super(req, res); this.defaultView = defaultView; } protected createResponseWrapper(): WebpageResponseWrapper { const resp = new WebpageResponseWrapper(this.res, this); this.assign = resp.assign.bind(resp); this.assignObject = resp.assignObject.bind(resp); return resp; } render(view?: string) { this.response.render(view); } } const debugSill = createLogger(LOG_LEVEL.SILLY, 'response'); export class WebpageResponseWrapper extends MultiValueResponseWrapper { private context: WebpageRequestContext; private view: ViewSettings = { success: null, failed: null, }; protected result: ResType&ApiResponse|ErrorResponse = this.mergeTemplateLocals(); constructor(res, context: WebpageRequestContext) { super(res); this.context = context; this.mergeTemplateLocals(); } render(view?: string) { if (view) { this.view.success = view; } this.response.header('X-UA-Compatible', 'IE=edge,chrome=1'); this.send(); } protected asyncResolve(res: ResType): void { this.assignObject(res); } protected asyncReject(error: any): void { this.internalError(error); } protected _send() { let view: string; if (this.result.status === STATUS_CODE_BASE.NO_RESPONSE || this.result.status === STATUS_CODE_BASE.SUCCESS) { view = this.view.success || this.context.defaultView.success || "success.ejs"; } else { view = this.view.failed || this.context.defaultView.failed || "success.ejs"; } if (debugSill.enabled) { debugSill(' with template: %j', debugType(this.result)); } this.response.render(view, this.result); } }