LP1825851 Server managed/processed print templates
[working/Evergreen.git] / Open-ILS / src / eg2 / src / app / share / print / print.component.ts
1 import {Component, OnInit, TemplateRef, ElementRef, Renderer2} from '@angular/core';
2 import {PrintService, PrintRequest} from './print.service';
3 import {StoreService} from '@eg/core/store.service';
4 import {ServerStoreService} from '@eg/core/server-store.service';
5 import {HatchService, HatchMessage} from './hatch.service';
6
7 @Component({
8     selector: 'eg-print',
9     templateUrl: './print.component.html'
10 })
11
12 export class PrintComponent implements OnInit {
13
14     // Template that requires local processing
15     template: TemplateRef<any>;
16
17     // Context data used for processing the template.
18     context: any;
19
20     // Insertion point for externally-compiled templates
21     htmlContainer: Element;
22
23     isPrinting: boolean;
24
25     printQueue: PrintRequest[];
26
27     constructor(
28         private renderer: Renderer2,
29         private elm: ElementRef,
30         private store: StoreService,
31         private serverStore: ServerStoreService,
32         private hatch: HatchService,
33         private printer: PrintService) {
34         this.isPrinting = false;
35         this.printQueue = [];
36     }
37
38     ngOnInit() {
39         this.printer.onPrintRequest$.subscribe(
40             printReq => this.handlePrintRequest(printReq));
41
42         this.htmlContainer =
43             this.renderer.selectRootElement('#eg-print-html-container');
44     }
45
46     handlePrintRequest(printReq: PrintRequest) {
47
48         if (this.isPrinting) {
49             // Avoid print collisions by queuing requests as needed.
50             this.printQueue.push(printReq);
51             return;
52         }
53
54         this.isPrinting = true;
55
56         this.applyTemplate(printReq).then(() => {
57             // Give templates a chance to render before printing
58             setTimeout(() => {
59                 this.dispatchPrint(printReq);
60                 this.reset();
61             });
62         });
63     }
64
65     applyTemplate(printReq: PrintRequest): Promise<any> {
66
67         if (printReq.template) {
68             // Local Angular template.
69             this.template = printReq.template;
70             this.context = {$implicit: printReq.contextData};
71             return Promise.resolve();
72         }
73
74         let promise;
75
76         // Precompiled text
77         if (printReq.text) {
78             promise = Promise.resolve();
79
80         } else if (printReq.templateName || printReq.templateId) {
81             // Server-compiled template
82
83             promise = this.printer.compileRemoteTemplate(printReq).then(
84                 response => {
85                     printReq.text = response.content;
86                     printReq.contentType = response.contentType;
87                 },
88                 err => {
89                     console.error('Error compiling template', printReq);
90                     return Promise.reject(new Error(
91                         'Error compiling server-hosted print template'));
92                 }
93             );
94
95         } else {
96             console.error('Cannot find template', printReq);
97             return Promise.reject(new Error('Cannot find print template'));
98         }
99
100         return promise.then(() => {
101
102             // Insert HTML into the browser DOM for in-browser printing.
103             if (printReq.text && !this.useHatch()) {
104
105                 if (printReq.contentType === 'text/plain') {
106                 // Wrap text/plain content in pre's to prevent
107                 // unintended html formatting.
108                     printReq.text = `<pre>${printReq.text}</pre>`;
109                 }
110
111                 this.htmlContainer.innerHTML = printReq.text;
112             }
113         });
114     }
115
116     // Clear the print data
117     reset() {
118         this.isPrinting = false;
119         this.template = null;
120         this.context = null;
121         this.htmlContainer.innerHTML = '';
122
123         if (this.printQueue.length) {
124             this.handlePrintRequest(this.printQueue.pop());
125         }
126     }
127
128     dispatchPrint(printReq: PrintRequest) {
129
130         if (!printReq.text) {
131             // Sometimes the results come from an externally-parsed HTML
132             // template, other times they come from an in-page template.
133             printReq.text = this.elm.nativeElement.innerHTML;
134         }
135
136         // Retain a copy of each printed document in localStorage
137         // so it may be reprinted.
138         this.store.setLocalItem('eg.print.last_printed', {
139             content: printReq.text,
140             context: printReq.printContext,
141             content_type: printReq.contentType,
142             show_dialog: printReq.showDialog
143         });
144
145         if (this.useHatch()) {
146             this.printViaHatch(printReq);
147         } else {
148             // Here the needed HTML is already in the page.
149             window.print();
150         }
151     }
152
153     useHatch(): boolean {
154         return this.store.getLocalItem('eg.hatch.enable.printing')
155             && this.hatch.connect();
156     }
157
158     printViaHatch(printReq: PrintRequest) {
159
160         // Send a full HTML document to Hatch
161         let html = printReq.text;
162         if (printReq.contentType === 'text/html') {
163             html = `<html><body>${printReq.text}</body></html>`;
164         }
165
166         this.serverStore.getItem(`eg.print.config.${printReq.printContext}`)
167         .then(config => {
168
169             const msg = new HatchMessage({
170                 action: 'print',
171                 content: html,
172                 settings: config || {},
173                 contentType: 'text/html',
174                 showDialog: printReq.showDialog
175             });
176
177             this.hatch.sendRequest(msg).then(
178                 ok  => console.debug('Print request succeeded'),
179                 err => console.warn('Print request failed', err)
180             );
181         });
182     }
183 }
184