import {Pager} from '@eg/share/util/pager';
import {DateSelectComponent} from '@eg/share/date-select/date-select.component';
import {PrintService} from '@eg/share/print/print.service';
-import {LegacyTemplateService} from '@eg/staff/share//legacy-template.service';
@Component({
templateUrl: 'sandbox.component.html'
private pcrud: PcrudService,
private strings: StringService,
private toast: ToastService,
- private printer: PrintService,
- private parser: LegacyTemplateService
+ private printer: PrintService
) {}
ngOnInit() {
contextData: {world : this.world},
printContext: 'default'
});
+
+ this.printer.print({
+ text: '<b>hello</b>',
+ printContext: 'default'
+ });
+
}
changeDate(date) {
.then(txt => this.toast.success(txt));
}, 4000);
}
-
- testParser() {
- const template = `
- <div>
- <div>This item needs to be routed to
- <b>{{dest_location.shortname}} AKA {{dest_location.name}}</b>
- </div>
- <div ng-if="foo">i should disappear</div>
- <div ng-if="boolFalse">i should also disappear</div>
- <div ng-if="boolTrue">i should stick around</div>
- <div ng-if="dest_address">
- <div>{{dest_address.street1}}</div>
- <div>{{dest_address.street2}}</div>
- </div>
- <div>Slip Date: {{today | date:foo}}</div>
- <div>Cost: {{cost | currency}}</div>
- <ol>
- <li ng-repeat="copy in copies">
- <div>Barcode: {{copy.barcode}}</div>
- <div>Title: {{copy.title | limitTo:10}}</div>
- <div ng-repeat="part in copy.parts">
- part = {{part}}
- </div>
- </li>
- </ol>
- <div ng-switch="dest_location.shortname">
- <div ng-switch-when="BR2">THIS IS BR2</div>
- <div ng-switch-when="BR1">
- THIS IS BR1
- <div ng-repeat="cp in copies">
- swith bc = {{cp.barcode}}
- </div>
- </div>
- </div>
- `;
-
- const context = {
- dest_location: {
- shortname: 'BR1',
- name: 'Branch Uno',
- },
- dest_address: {
- street1: '123 Pineapple Rd',
- street2: 'APT #3',
- },
- boolTrue: true,
- boolFalse: false,
- today: new Date(),
- cost: 23.3,
- copies: [
- {barcode: 'abc123', title: 'welcome to the jungle', parts: ['a', 'b', 'c']},
- {barcode: 'def456', title: 'hello mudda, hello fadda', parts: ['x', 'y']}
- ]
- };
-
- this.parser.apply(template, context).then(html => {
- this.printer.print({
- text: html,
- printContext: 'default'
- });
- });
- }
}
+++ /dev/null
-/**
- * USING EVAL() OPENS A LARGE SECURITY HOLE.
- * DEPRECATE ME.
- * AngularJS-style minimal template parser.
- * Original use case is supporting AngularJS style print templates.
- * Template context data is applied only once at parsing time, there
- * is no data binding.
- *
- * Supports the following template constructs:
- * {{variables}}
- * <element ng-if="expression">
- * <element ng-repeat="expression">
- * <element ng-switch="expression">
- * <child-element ng-switch-when="string">
- */
-import {Injectable, EventEmitter} from '@angular/core';
-import {FormatService} from '@eg/share/util/format.service';
-
-// Internal class for modeling a single template parsing instance.
-class ParserInstance {
-
- private context: any;
- private format: FormatService;
-
- // FormatService injected by ParserService
- constructor(format: FormatService) {
- this.format = format;
- }
-
- // Given an HTML string and an interpolation context/scope,
- // process the HTML template declarations, apply variable
- // replacements, and return the restulting HTML string.
- parse(html: string, context: any): string {
-
- // Shallow copy the context since we modify the keys internally
- this.context = Object.assign({}, context);
-
- const parser = new DOMParser();
- const doc = parser.parseFromString(html, 'text/html');
-
- // Parsing as html wraps the content in an <html><body> wrapper
- const domNode = doc.getElementsByTagName('body')[0];
-
- this.traverse(domNode);
-
- return domNode.innerHTML;
- }
-
- // Process each node in the in-progress document.
- traverse(node: Node) {
- if (!node) { return; }
-
- switch (node.nodeType) {
- case Node.ELEMENT_NODE:
- const complete = this.processElementNode(node as Element);
- if (complete) {
- return;
- }
- break;
-
- case Node.TEXT_NODE:
- this.processTextNode(node as Text);
- break;
- }
-
- // Array.from() avoids TS compiler warnings
- Array.from(node.childNodes).forEach(child => this.traverse(child));
- }
-
- // Process expressions found on each element.
- // Returns true if the node was processed within and needs no
- // further processing, false otherwise.
- processElementNode(node: Element): boolean {
-
- const switchExp = node.getAttribute('ng-switch');
- if (switchExp) {
- node.removeAttribute('ng-switch');
- if (!this.processSwitchExpression(node, switchExp)) {
- // We removed all child nodes in the switch
- return true;
- }
- }
-
- const ifExp = node.getAttribute('ng-if');
- if (ifExp) {
- node.removeAttribute('ng-if');
- if (!this.testIfExpression(ifExp)) {
- // A failing IF expression means the node does not render.
- node.remove();
- return true;
- }
- }
-
- const loopExp = node.getAttribute('ng-repeat');
- if (loopExp) {
- node.removeAttribute('ng-repeat');
- this.processLoopExpression(node, loopExp);
- return true;
- }
-
- return false;
- }
-
- // Returns true if any of the switch expressions resulted
- // in true, thus allowing a child node to remain and require
- // future processing.
- processSwitchExpression(node: Element, expr: string): boolean {
-
- // ng-switch only works on string values
- const targetVal = this.getContextStringValue(expr);
- let matchNode: Node;
-
- // Find the switch-matching child node
- Array.from(node.childNodes).forEach(child => {
- if (!matchNode && child.nodeType === Node.ELEMENT_NODE) {
- const elm: Element = child as Element;
- const val = elm.getAttribute('ng-switch-when');
- if (val === null || val === undefined) { return; }
- if (val + '' === targetVal) {
- matchNode = child;
- }
- }
- });
-
- // Remove all child nodes
- while (node.firstChild) {
- node.removeChild(node.firstChild);
- }
-
- // Add the matching node back if found
- if (matchNode) {
- node.appendChild(matchNode);
- return true;
- }
-
- return false; // no matching switch values
- }
-
- processLoopExpression(node: Element, expr: string) {
- const parts = expr.split('in');
- const listItemKey = parts[0].trim();
- const listPath = parts[1].trim();
- const list = this.getContextValueAt(listPath);
-
- if (!Array.isArray(list)) {
- throw new Error(`Template value ${listPath} is not an Array`);
- }
-
- // Loop over the repeat array and for each iteration, add the
- // loop variable as a new value in the (temporary) context so
- // it can be referenced in the eval context.
- const origContext = this.context;
- let prevNode: Element = node;
-
- list.forEach(listItem => {
- const listCtx = {};
- listCtx[listItemKey] = listItem;
- this.context = Object.assign(this.context, listCtx);
- const newNode = node.cloneNode(true) as Element;
- // appendChild used internally when needed.
- prevNode.parentNode.insertBefore(newNode, prevNode.nextSibling);
- this.traverse(newNode);
- prevNode = newNode;
- });
-
- // recover the original context sans any loop data.
- this.context = origContext;
-
- // get rid of the source/template node
- node.remove();
- }
-
- // To evaluate free-form expressions, create an environment
- // where references to elements in the context are available.
- // For example: ng-if="foo.bar" -- the 'foo' key from the
- // context must be defined in advance for evaluation to succeed.
- generateEvalEnv() {
- let env = '';
- Object.keys(this.context).forEach(key => {
- env += `var ${key} = this.context['${key}'];\n`;
- });
- return env;
- }
-
- // Returns true of the IF expression evaluates to true,
- // false otherwise.
- testIfExpression(expr: string): boolean {
-
- const env = this.generateEvalEnv();
- const evalStr = `${env}; Boolean(${expr})`;
- // console.debug('ng-if eval string: ', evalStr);
-
- try {
- return eval(evalStr);
- } catch (err) {
- // console.debug('IF expression failed with: ', err);
- return false;
- }
- }
-
- // Replace variable {{...}} instances in a given Text node
- // with the matching data from the context.
- processTextNode(node: Text) {
- if (!node || !node.data) { return; }
-
- const matches = node.data.match(/{{.*?}}/g);
- if (!matches) { return; }
-
- matches.forEach(match => {
- const dotpath = match.replace(/[{}]/g, '');
- node.replaceData(
- node.data.indexOf(match),
- match.length,
- this.getContextStringValue(dotpath)
- );
- });
- }
-
- // Returns the context item at the given path
- getContextValueAt(dotpath: string): any {
- let idx;
- let obj = this.context;
- const parts = dotpath.split('.');
-
- for (idx = 0; idx < parts.length; idx++) {
- obj = obj[parts[idx]];
- if (obj === null || typeof obj !== 'object') {
- break;
- }
- }
-
- if (idx < parts.length - 1) {
- // Loop exited before inspecting the whole path.
- return null;
- }
-
- return obj;
- }
-
- // Find the value within the context at the given path.
- getContextStringValue(dotpath: string): string {
-
- // Variable replacements may contain filters.
- const pieces = dotpath.split('|').map(p => p.trim());
- const path = pieces[0];
- const filter = pieces[1];
- const data = {
- datatype: null, // potentially applied below
- value: this.getContextValueAt(path)
- };
-
- // TODO: teach the format service about processing due dates.
- if (filter) {
- const fParts = filter.split(':').map(p => p.trim());
- const fName = fParts[0];
- const fArgs = fParts.slice(1);
-
- switch (fName) {
- case 'date':
- data.datatype = 'timestamp';
- break;
- case 'currency':
- data.datatype = 'money';
- break;
- case 'limitTo':
- const size = fArgs[0];
- if (size) {
- const offset = fArgs[1] || 0;
- data.value =
- data.value.substring(offset, offset + size);
- }
- break;
- }
- }
-
- return this.format.transform(data);
- }
-}
-
-
-@Injectable()
-export class LegacyTemplateService {
-
- constructor(private format: FormatService) {}
-
- // make async for now, may be needed later
- public apply(html: string, context: any): Promise<string> {
- const parser = new ParserInstance(this.format);
-
- return new Promise((resolve, reject) => {
- resolve(parser.parse(html, context));
- });
- }
-}
-