// 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';
providers: [
DatePipe,
CurrencyPipe,
+ HtmlToTxtService,
HatchService,
PrintService,
FormatService
isAvailable: boolean;
msgId: number;
- messages: {[msgid:number]: HatchMessage};
+ messages: {[msgid: number]: HatchMessage};
constructor() {
this.isAvailable = null;
this.handleResponse(event.data);
}
- });
+ });
return this.isAvailable = true;
}
// 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;
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',
private elm: ElementRef,
private store: StoreService,
private serverStore: ServerStoreService,
+ private h2txt: HtmlToTxtService,
private hatch: HatchService,
private printer: PrintService) {
this.isPrinting = false;
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'),
--- /dev/null
+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 <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');
+ }
+}
+
<h4>PCRUD auto flesh and FormatService detection</h4>
<div *ngIf="aMetarecord">Fingerprint: {{aMetarecord}}</div>
+
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'
private strings: StringService,
private toast: ToastService,
private format: FormatService,
+ private h2txt: HtmlToTxtService,
private printer: PrintService
) {
}
idlField: 'metarecord'
});
});
+
+ const str = 'César & Me';
+ console.log(this.h2txt.htmlToTxt(str));
}
openEditor() {