LP1824391 Hatch print-to-file Angular edition user/berick/lp1824391-hatch-write-to-file-angular
authorBill Erickson <berickxx@gmail.com>
Mon, 15 Apr 2019 15:34:21 +0000 (11:34 -0400)
committerBill Erickson <berickxx@gmail.com>
Fri, 26 Apr 2019 15:30:57 +0000 (11:30 -0400)
Adds support for the Angular hatch service for sending 'bare' text/plain
print-to-file requests.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/common.module.ts
Open-ILS/src/eg2/src/app/share/print/hatch.service.ts
Open-ILS/src/eg2/src/app/share/print/print.component.ts
Open-ILS/src/eg2/src/app/share/util/htmltotxt.service.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts

index f1d4467..1fd78a9 100644 (file)
@@ -14,6 +14,7 @@ They do not have to be added to the providers list.
 
 // consider moving these to core...
 import {FormatService, FormatValuePipe} from '@eg/core/format.service';
+import {HtmlToTxtService} from '@eg/share/util/htmltotxt.service';
 import {HatchService} from '@eg/share/print/hatch.service';
 import {PrintService} from '@eg/share/print/print.service';
 
@@ -68,6 +69,7 @@ export class EgCommonModule {
             providers: [
                 DatePipe,
                 CurrencyPipe,
+                HtmlToTxtService,
                 HatchService,
                 PrintService,
                 FormatService
index 0150887..bd087b7 100644 (file)
@@ -27,7 +27,7 @@ export class HatchService {
 
     isAvailable: boolean;
     msgId: number;
-    messages: {[msgid:number]: HatchMessage};
+    messages: {[msgid: number]: HatchMessage};
 
     constructor() {
         this.isAvailable = null;
@@ -62,7 +62,7 @@ export class HatchService {
 
                 this.handleResponse(event.data);
             }
-        }); 
+        });
 
         return this.isAvailable = true;
     }
@@ -87,7 +87,7 @@ export class HatchService {
     // Handle the data sent back to the browser from Hatch.
     handleResponse(data: any) {
 
-        const msg = this.messages[data.msgid]; 
+        const msg = this.messages[data.msgid];
         if (!msg) {
             console.warn(`No Hatch request found with ID ${data.msgid}`);
             return;
index e7754ab..45571cf 100644 (file)
@@ -3,6 +3,9 @@ import {PrintService, PrintRequest} from './print.service';
 import {StoreService} from '@eg/core/store.service';
 import {ServerStoreService} from '@eg/core/server-store.service';
 import {HatchService, HatchMessage} from './hatch.service';
+import {HtmlToTxtService} from '@eg/share/util/htmltotxt.service';
+
+const HATCH_FILE_WRITER_PRINTER = 'hatch_file_writer';
 
 @Component({
     selector: 'eg-print',
@@ -29,6 +32,7 @@ export class PrintComponent implements OnInit {
         private elm: ElementRef,
         private store: StoreService,
         private serverStore: ServerStoreService,
+        private h2txt: HtmlToTxtService,
         private hatch: HatchService,
         private printer: PrintService) {
         this.isPrinting = false;
@@ -128,19 +132,43 @@ export class PrintComponent implements OnInit {
 
     printViaHatch(printReq: PrintRequest) {
 
-        // Send a full HTML document to Hatch
-        const html = `<html><body>${printReq.text}</body></html>`;
+        if (!printReq.contentType) {
+            printReq.contentType = 'text/html';
+        }
+
+        let content = printReq.text;
+        if (printReq.contentType === 'text/html') {
+            // Send a full HTML document to Hatch
+            content = `<html><body>${printReq.text}</body></html>`;
+        }
 
         this.serverStore.getItem(`eg.print.config.${printReq.printContext}`)
         .then(config => {
 
-            const msg = new HatchMessage({
-                action: 'print',
-                content: html,
-                settings: config || {},
-                contentType: 'text/html',
-                showDialog: printReq.showDialog
-            });
+            let msg: HatchMessage;
+
+            if (config && config.printer === HATCH_FILE_WRITER_PRINTER) {
+
+                const text = printReq.contentType === 'text/plain' ?
+                    content : this.h2txt.htmlToTxt(content);
+
+                msg = new HatchMessage({
+                    action: 'set',
+                    key: `receipt.${printReq.printContext}.txt`,
+                    content: text,
+                    bare: true
+                });
+
+            } else {
+
+                msg = new HatchMessage({
+                    action: 'print',
+                    content: content,
+                    settings: config || {},
+                    contentType: 'text/html',
+                    showDialog: printReq.showDialog
+                });
+            }
 
             this.hatch.sendRequest(msg).then(
                 ok  => console.debug('Print request succeeded'),
diff --git a/Open-ILS/src/eg2/src/app/share/util/htmltotxt.service.ts b/Open-ILS/src/eg2/src/app/share/util/htmltotxt.service.ts
new file mode 100644 (file)
index 0000000..e265b3d
--- /dev/null
@@ -0,0 +1,75 @@
+import {Injectable} from '@angular/core';
+
+const ENTITY_REGEX = /&[^\s]+;/;
+
+/**
+ * Translates HTML text into plain text.
+ */
+
+@Injectable()
+export class HtmlToTxtService {
+
+   unEscapeHtml(text: string): string {
+        text = text.replace(/&amp;/g, '&');
+        text = text.replace(/&quot;/g, '"');
+        text = text.replace(/&nbsp;/g, ' ');
+        text = text.replace(/&lt;/g, '<');
+        text = text.replace(/&gt;/g, '>');
+        return text;
+    }
+
+    // https://stackoverflow.com/questions/7394748
+    entityToChars(text: string): string {
+        if (text && text.match(ENTITY_REGEX)) {
+            const node = document.createElement('textarea');
+            node.innerHTML = text;
+            return node.value;
+        }
+        return text;
+    }
+
+    // Translate an HTML string into plain text.
+    // Removes HTML elements.
+    // Replaces <li> with "*"
+    // Replaces HTML entities with their character equivalent.
+    htmlToTxt(html: string): string {
+        if (!html || html === '') {
+            return '';
+        }
+
+        // First remove multi-line comments.
+        html = html.replace(/<!--(.*?)-->/gs, '');
+
+        const lines = html.split(/\n/);
+        const newLines = [];
+
+        lines.forEach(line => {
+
+            if (!line) {
+                newLines.push(line);
+                return;
+            }
+
+            line = this.unEscapeHtml(line);
+            line = this.entityToChars(line);
+
+            line = line.replace(/<head.*?>.*?<\/head>/gi, '');
+            line = line.replace(/<br.*?>/gi, '\r\n');
+            line = line.replace(/<table.*?>/gi, '');
+            line = line.replace(/<\/tr>/gi, '\r\n'); // end of row
+            line = line.replace(/<\/td>/gi, ' '); // end of cell
+            line = line.replace(/<\/th>/gi, ' '); // end of th
+            line = line.replace(/<tr.*?>/gi, '');
+            line = line.replace(/<hr.*?>/gi, '\r\n');
+            line = line.replace(/<p.*?>/gi, '');
+            line = line.replace(/<block.*?>/gi, '');
+            line = line.replace(/<li.*?>/gi, ' * ');
+            line = line.replace(/<.+?>/gi, '');
+
+            if (line) { newLines.push(line); }
+        });
+
+        return newLines.join('\n');
+    }
+}
+
index 54cd87d..63d3736 100644 (file)
 <h4>PCRUD auto flesh and FormatService detection</h4>
 <div *ngIf="aMetarecord">Fingerprint: {{aMetarecord}}</div>
 
+
index 543e3cb..bf76fab 100644 (file)
@@ -15,6 +15,7 @@ import {PrintService} from '@eg/share/print/print.service';
 import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
 import {FormatService} from '@eg/core/format.service';
 import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
+import {HtmlToTxtService} from '@eg/share/util/htmltotxt.service';
 
 @Component({
   templateUrl: 'sandbox.component.html'
@@ -73,6 +74,7 @@ export class SandboxComponent implements OnInit {
         private strings: StringService,
         private toast: ToastService,
         private format: FormatService,
+        private h2txt: HtmlToTxtService,
         private printer: PrintService
     ) {
     }
@@ -134,6 +136,9 @@ export class SandboxComponent implements OnInit {
                 idlField: 'metarecord'
             });
         });
+
+        const str = 'C&#xe9;sar&nbsp;&amp;&nbsp;Me';
+        console.log(this.h2txt.htmlToTxt(str));
     }
 
     openEditor() {