From 3aedb2e0a8180b106cdab8300cd94653f443dc01 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Mon, 15 Apr 2019 11:34:21 -0400 Subject: [PATCH] LP1824391 Hatch print-to-file Angular edition Adds support for the Angular hatch service for sending 'bare' text/plain print-to-file requests. Signed-off-by: Bill Erickson --- Open-ILS/src/eg2/src/app/common.module.ts | 2 + .../src/eg2/src/app/share/print/hatch.service.ts | 6 +- .../src/eg2/src/app/share/print/print.component.ts | 46 ++++++++++--- .../eg2/src/app/share/util/htmltotxt.service.ts | 75 ++++++++++++++++++++++ .../src/app/staff/sandbox/sandbox.component.html | 1 + .../eg2/src/app/staff/sandbox/sandbox.component.ts | 5 ++ 6 files changed, 123 insertions(+), 12 deletions(-) create mode 100644 Open-ILS/src/eg2/src/app/share/util/htmltotxt.service.ts diff --git a/Open-ILS/src/eg2/src/app/common.module.ts b/Open-ILS/src/eg2/src/app/common.module.ts index f1d4467830..1fd78a951b 100644 --- a/Open-ILS/src/eg2/src/app/common.module.ts +++ b/Open-ILS/src/eg2/src/app/common.module.ts @@ -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 diff --git a/Open-ILS/src/eg2/src/app/share/print/hatch.service.ts b/Open-ILS/src/eg2/src/app/share/print/hatch.service.ts index 015088765a..bd087b7747 100644 --- a/Open-ILS/src/eg2/src/app/share/print/hatch.service.ts +++ b/Open-ILS/src/eg2/src/app/share/print/hatch.service.ts @@ -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; diff --git a/Open-ILS/src/eg2/src/app/share/print/print.component.ts b/Open-ILS/src/eg2/src/app/share/print/print.component.ts index e7754abbd3..45571cfd86 100644 --- a/Open-ILS/src/eg2/src/app/share/print/print.component.ts +++ b/Open-ILS/src/eg2/src/app/share/print/print.component.ts @@ -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 = `${printReq.text}`; + if (!printReq.contentType) { + printReq.contentType = 'text/html'; + } + + let content = printReq.text; + if (printReq.contentType === 'text/html') { + // Send a full HTML document to Hatch + content = `${printReq.text}`; + } 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 index 0000000000..e265b3d2fa --- /dev/null +++ b/Open-ILS/src/eg2/src/app/share/util/htmltotxt.service.ts @@ -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(/&/g, '&'); + text = text.replace(/"/g, '"'); + text = text.replace(/ /g, ' '); + text = text.replace(/</g, '<'); + text = text.replace(/>/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
  • 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>/gi, ''); + line = line.replace(//gi, '\r\n'); + line = line.replace(//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(//gi, ''); + line = line.replace(//gi, '\r\n'); + line = line.replace(//gi, ''); + line = line.replace(//gi, ''); + line = line.replace(//gi, ' * '); + line = line.replace(/<.+?>/gi, ''); + + if (line) { newLines.push(line); } + }); + + return newLines.join('\n'); + } +} + diff --git a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html index 54cd87d11e..63d3736e67 100644 --- a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html +++ b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html @@ -154,3 +154,4 @@

    PCRUD auto flesh and FormatService detection

    Fingerprint: {{aMetarecord}}
    + diff --git a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts index 543e3cb72b..bf76fab225 100644 --- a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts @@ -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ésar & Me'; + console.log(this.h2txt.htmlToTxt(str)); } openEditor() { -- 2.11.0