UNPKG

cv-dialog-sdk

Version:

Catavolt Dialog Javascript API

1,396 lines (1,395 loc) 48.4 kB
import { Log } from '../util/index'; /* IMPORTANT! Note #1: Dependency cycles - These classes must be in a single file (module) because of commonjs and circular dependency issues. Note #2 Dependent ordering - Important! : Because of typescript's 'extends' function, order matters in this file! super classes must be first! */ // Skipped in initial port: BarChart, BarcodeScanner, BarOrientation, Defaults, GaugeChart const XML_CELL = 'Cell'; const XML_FORM = 'Form'; const XML_GRID = 'Grid'; const XML_PAGE = 'Page'; const XML_BUTTON = 'Button'; const XML_CHECKBOX = 'CheckBox'; const XML_DATE_PICKER = 'DatePicker'; const XML_IMAGE = 'Image'; const XML_LABEL = 'Label'; const XML_SIGNATURE_CAPTURE = 'SignatureCapture'; const XML_TEXT_AREA = 'TextArea'; const XML_TEXT_FIELD = 'TextField'; const XML_TIME_PICKER = 'TimePicker'; const XML_VALUE_PICKER = 'ValuePicker'; const XML_CHILDREN = 'Children'; const XML_ALLOW_ANNOTATIONS = 'AllowAnnotations'; const XML_ALLOW_PICKER = 'AllowPicker'; const XML_ALLOW_PICK_OPTIONS = 'AllowPickOptions'; const XML_ALPHA = 'Alpha'; const XML_ASPECT_MODE = 'AspectMode'; const XML_BACKGROUND_COLOR = 'BackgroundColor'; const XML_BINDING = 'Binding'; const XML_BLUE = 'Blue'; const XML_BOLD = 'Bold'; const XML_BORDER_COLOR = 'BorderColor'; const XML_BORDER_WIDTHS = 'BorderWidths'; const XML_BOTTOM = 'Bottom'; const XML_CAP_INSETS = 'CapInsets'; const XML_CAPTURE_BOUNDS = 'CaptureBounds'; const XML_CHECKED_COLOR = 'CheckedColor'; const XML_COLUMN = 'Column'; const XML_ENABLED_IN_READ_MODE = 'EnabledInReadMode'; const XML_ENTRY_SEQ = 'EntrySeq'; const XML_GREEN = 'Green'; const XML_FILL_PARENT = 'FillParent'; const XML_HEIGHT = 'Height'; const XML_ID = 'Id'; const XML_ITALIC = 'Italic'; const XML_LAYOUT = 'Layout'; const XML_LEFT = 'Left'; const XML_LINE_COLOR = 'LineColor'; const XML_LINE_WIDTH = 'LineWidth'; const XML_NUMBER_OF_LINES = 'NumberOfLines'; const XML_ORIGIN = 'Origin'; const XML_PADDING = 'Padding'; const XML_RADIO_GROUP = 'RadioGroup'; const XML_RED = 'Red'; const XML_REFRESH_TIMER = 'RefreshTimer'; const XML_RESIZE_MODE = 'ResizeMode'; const XML_RIGHT = 'Right'; const XML_ROW = 'Row'; const XML_SIZE = 'Size'; const XML_TEXT = 'Text'; const XML_TEXT_ALIGNMENT = 'TextAlignment'; const XML_TEXT_COLOR = 'TextColor'; const XML_TOP = 'Top'; const XML_UNCHECKED_COLOR = 'UncheckedColor'; const XML_UNDERLINE = 'Underline'; const XML_UOM = 'UOM'; const XML_URL = 'URL'; const XML_WIDTH = 'Width'; const XML_X = 'X'; const XML_Y = 'Y'; export class TextAttributes { constructor() { this.bold = false; this.italic = false; this.underline = false; this.numberOfLines = 1; } } /** * ********************************* */ let GenID = 1; // Generate a unique number if need be for IDs export class Spec { constructor(node) { this.nodeChildDict = {}; if (node) { PrintUtil.forEachChildNode(node, (n) => { this.nodeChildDict[n.nodeName] = n; }); } } } export class Component extends Spec { constructor(parentContainer, node, overrideLayout) { super(node); this._parentContainer = parentContainer; if (node) { PrintUtil.ifChild(this.nodeChildDict[XML_BACKGROUND_COLOR], (n) => { this._backgroundColor = new Color(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_BINDING], (n) => { this._binding = new Binding(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_ID], (n) => { this._id = PrintUtil.singleChildText(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_LAYOUT], (n) => { this._layout = new Layout(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_PADDING], (n) => { this._padding = new Edges(n); }); if (!this.id) { this._id = 'GenID-' + GenID++; } } } initComponentWith(overrideLayout) { if (overrideLayout) { this._layout = overrideLayout; } if (!this.id) { this._id = 'Generated-' + GenID++; } } get backgroundColor() { return this._backgroundColor; } get binding() { return this._binding; } get id() { return this._id; } get layout() { return this._layout; } get padding() { return this._padding; } get actualHeights() { return this._actualHeights; } get actualWidths() { return this._actualWidths; } get actualX() { return this._actualX; } get actualY() { return this._actualY; } get height() { return this._height; } get parentContainer() { return this._parentContainer; } get textAttributes() { return this._textAttributes; } get width() { return this._width; } get x() { return this._x; } get y() { return this._y; } } export class Container extends Component { constructor(parentContainer, node, overrideContainerWidth) { super(parentContainer, node); this._children = []; if (this.nodeChildDict[XML_CHILDREN]) { PrintUtil.forEachChildNode(this.nodeChildDict[XML_CHILDREN], (n) => { const c = ComponentFactory.fromNode(n, this); if (c) { this._children.push(c); } }); } } get children() { return this._children; } get containerWidth() { if (!this._containerWidth) { this.calcAndAssignContainerWidth(this.parentContainer); } return this._containerWidth; } assignChildren(c) { this._children = c; } assignContainerWidth(width) { this._containerWidth = width; } assignParentWidth(parentWidth) { this.assignContainerWidth(this.layout.sumOfWidths(parentWidth)); } calcAndAssignContainerWidth(parentContainer) { // Overriden by Form and Cell for altered behavior const parentWidth = parentContainer.containerWidth; if (this.layout == null) { throw Error('Bogus'); } this.assignContainerWidth(this.layout.sumOfWidths(parentWidth)); } initContainerWith(overrideLayout, overideChildren) { this.initComponentWith(overrideLayout); if (overideChildren) { this.assignChildren(overideChildren); } } } export class PrintProperty extends Spec { constructor(node) { super(node); } } /** * ********************************* */ export var AspectMode; (function (AspectMode) { AspectMode[AspectMode["None"] = 0] = "None"; AspectMode[AspectMode["Fit"] = 1] = "Fit"; AspectMode[AspectMode["Fill"] = 2] = "Fill"; })(AspectMode || (AspectMode = {})); export var BindingType; (function (BindingType) { BindingType[BindingType["Data"] = 0] = "Data"; BindingType[BindingType["Meta"] = 1] = "Meta"; })(BindingType || (BindingType = {})); export var FormMode; (function (FormMode) { FormMode[FormMode["Display"] = 0] = "Display"; FormMode[FormMode["Edit"] = 1] = "Edit"; })(FormMode || (FormMode = {})); export var ResizeMode; (function (ResizeMode) { ResizeMode[ResizeMode["Stretch"] = 0] = "Stretch"; ResizeMode[ResizeMode["Tile"] = 1] = "Tile"; })(ResizeMode || (ResizeMode = {})); export var RichNumUsage; (function (RichNumUsage) { RichNumUsage[RichNumUsage["Undefined"] = 0] = "Undefined"; RichNumUsage[RichNumUsage["Absolute"] = 1] = "Absolute"; RichNumUsage[RichNumUsage["FillParent"] = 2] = "FillParent"; RichNumUsage[RichNumUsage["PercentOfParent"] = 3] = "PercentOfParent"; })(RichNumUsage || (RichNumUsage = {})); export var RichNumUsageRef; (function (RichNumUsageRef) { RichNumUsageRef[RichNumUsageRef["Undefined"] = 0] = "Undefined"; RichNumUsageRef[RichNumUsageRef["Absolute"] = 1] = "Absolute"; RichNumUsageRef[RichNumUsageRef["FillParent"] = 2] = "FillParent"; RichNumUsageRef[RichNumUsageRef["HorizontalCenter"] = 3] = "HorizontalCenter"; RichNumUsageRef[RichNumUsageRef["HorizontalLeft"] = 4] = "HorizontalLeft"; RichNumUsageRef[RichNumUsageRef["HorizontalRight"] = 5] = "HorizontalRight"; RichNumUsageRef[RichNumUsageRef["PercentOfParent"] = 6] = "PercentOfParent"; RichNumUsageRef[RichNumUsageRef["Remainder"] = 7] = "Remainder"; RichNumUsageRef[RichNumUsageRef["VerticalBottom"] = 8] = "VerticalBottom"; RichNumUsageRef[RichNumUsageRef["VerticalCenter"] = 9] = "VerticalCenter"; RichNumUsageRef[RichNumUsageRef["VerticalTop"] = 10] = "VerticalTop"; })(RichNumUsageRef || (RichNumUsageRef = {})); // Just for reference export var TextAlignmentUsage; (function (TextAlignmentUsage) { TextAlignmentUsage[TextAlignmentUsage["Left"] = 0] = "Left"; TextAlignmentUsage[TextAlignmentUsage["Center"] = 1] = "Center"; TextAlignmentUsage[TextAlignmentUsage["Right"] = 2] = "Right"; })(TextAlignmentUsage || (TextAlignmentUsage = {})); export var ValuePlacement; (function (ValuePlacement) { ValuePlacement[ValuePlacement["absolute"] = 0] = "absolute"; ValuePlacement[ValuePlacement["none"] = 1] = "none"; })(ValuePlacement || (ValuePlacement = {})); export var ValueType; (function (ValueType) { ValueType[ValueType["Undefined"] = 0] = "Undefined"; ValueType[ValueType["Boolean"] = 1] = "Boolean"; ValueType[ValueType["Date"] = 2] = "Date"; ValueType[ValueType["DateTime"] = 3] = "DateTime"; ValueType[ValueType["Decimal"] = 4] = "Decimal"; ValueType[ValueType["Float"] = 5] = "Float"; ValueType[ValueType["Integer"] = 6] = "Integer"; ValueType[ValueType["LargeBinary"] = 7] = "LargeBinary"; ValueType[ValueType["LargeString"] = 8] = "LargeString"; ValueType[ValueType["String"] = 9] = "String"; ValueType[ValueType["Time"] = 10] = "Time"; })(ValueType || (ValueType = {})); export class Binding extends PrintProperty { constructor(node) { super(node); this._type = BindingType.Data; this._path = PrintUtil.singleChildText(node); } get constantValue() { // Constants are of the form propName[c], where c is the constant let w = null; if (this.hasConstant) { const left = this.path.indexOf('['); const right = this.path.indexOf(']'); w = this.path.substr(left + 1, right - left - 1); } return w; } get hasAction() { return this.path.indexOf('catavolt:action') > -1; } get hasConstant() { // Constants are of the form propName[c], where c is the constant const left = this.path.indexOf('['); const right = this.path.indexOf(']'); return left > -1 && right > -1 && right - left > 0; } get path() { return this._path; } get propertyName() { let w = null; if (this.hasConstant) { // Constants are of the form propName[c], where c is the constant // The binding still refrences a property name. w = this.path.substr(0, this.path.indexOf('[')); } else if (this.hasAction) { // No property for an action } else { w = this.path; } return w; } get type() { return this._type; } } export class Button extends Component { constructor(parentContainer, node) { super(parentContainer, node); PrintUtil.ifChild(this.nodeChildDict[XML_ASPECT_MODE], (n) => { this._aspectMode = PrintUtil.enumValue(n, AspectMode); }); PrintUtil.ifChild(this.nodeChildDict[XML_CAP_INSETS], (n) => { this._capInsets = new Edges(node); }); PrintUtil.ifChild(this.nodeChildDict[XML_RESIZE_MODE], (n) => { this._resizeMode = PrintUtil.enumValue(n, ResizeMode); }); PrintUtil.ifChild(this.nodeChildDict[XML_URL], (n) => { this._urlString = PrintUtil.singleChildText(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_ENABLED_IN_READ_MODE], (n) => { this._enabledInReadMode = PrintUtil.singleChildBoolean(n); }); } get aspectMode() { return this._aspectMode; } get capInsets() { return this._capInsets; } get resizeMode() { return this._resizeMode; } get urlString() { return this._urlString; } get enableInReadMode() { return this._enabledInReadMode; } } export class CaptureBounds extends PrintProperty { constructor(node) { super(node); PrintUtil.ifChild(this.nodeChildDict[XML_HEIGHT], (n) => { this._height = PrintUtil.singleChildRichNum(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_WIDTH], (n) => { this._width = PrintUtil.singleChildRichNum(n); }); } get height() { return this._height; } get width() { return this._width; } } export class PrintCell extends Container { constructor(parentContainer, node) { super(parentContainer, node); this._grid = parentContainer; PrintUtil.ifChild(this.nodeChildDict[XML_BORDER_COLOR], (n) => { this._borderColor = new Color(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_BORDER_WIDTHS], (n) => { this._borderWidths = new Edges(n); }); } get borderColor() { return this._borderColor; } get borderWidths() { return this._borderWidths; } get cellHeight() { return this._grid.layout.heights[this.layout.row].value; } get cellWidth() { return this._grid.layout.widths[this.layout.column].resolveWithFill(this._grid.containerWidth); } get componentChildren() { const answer = []; this.children.map(c => { if (!(c instanceof Grid)) { answer.push(c); } }); return answer; } get gridChildren() { const answer = []; this.children.map(c => { if (c instanceof Grid) { answer.push(c); } }); return answer; } initCellWith(overrideLayout, overrideChildren) { let ol = overrideLayout; if (!this.layout && !overrideLayout) { ol = new Layout(null, NaN, NaN, NaN, NaN, 0, 0); } this.initContainerWith(ol, overrideChildren); if (!this.borderWidths) { this._borderWidths = new Edges(); this._borderWidths.initEdgesWith(0, 0, 0, 0); } } calcAndAssignContainerWidth(parentContainer) { if (parentContainer.layout == null) { throw Error('bogus'); } const cw = parentContainer.layout.widths[this.layout.column].resolveWithFill(parentContainer.containerWidth); this.assignContainerWidth(cw); } } export class Checkbox extends Component { constructor(parentContainer, node) { super(parentContainer, node); PrintUtil.ifChild(this.nodeChildDict[XML_CHECKED_COLOR], (n) => { this._checkedColor = new Color(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_ENTRY_SEQ], (n) => { this._entrySeq = PrintUtil.singleChildInt(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_LINE_COLOR], (n) => { this._lineColor = new Color(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_LINE_WIDTH], (n) => { this._lineWidth = PrintUtil.singleChildFloat(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_RADIO_GROUP], (n) => { this._radioGroup = PrintUtil.singleChildText(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_UNCHECKED_COLOR], (n) => { this._uncheckedColor = new Color(n); }); } get checkedColor() { return this._checkedColor; } get entrySeq() { return this._entrySeq; } get lineColor() { return this._lineColor; } get lineWidth() { return this._lineWidth; } get radioGroup() { return this._radioGroup; } get uncheckedColor() { return this._uncheckedColor; } } export class Color extends Spec { static WHITE() { const c = new Color(null); c._red = 255; c._green = 255; c._blue = 255; c._alpha = 255; return c; } static BLACK() { const c = new Color(null); c._red = 0; c._green = 0; c._blue = 0; c._alpha = 255; return c; } constructor(node, red, green, blue, alpha) { super(node); PrintUtil.ifChild(this.nodeChildDict[XML_RED], (n) => { this._red = PrintUtil.singleChildInt(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_BLUE], (n) => { this._blue = PrintUtil.singleChildInt(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_GREEN], (n) => { this._green = PrintUtil.singleChildInt(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_ALPHA], (n) => { this._alpha = PrintUtil.singleChildFloat(n); }); if (red !== undefined) { this._red = red; } if (green !== undefined) { this._green = green; } if (blue !== undefined) { this._blue = blue; } if (alpha !== undefined) { this._alpha = alpha; } } get alpha() { return this._alpha; } get red() { return this._red; } get green() { return this._green; } get blue() { return this._blue; } } export class DatePicker extends Component { constructor(parentContainer, node) { super(parentContainer, node); this._textAttributes = new TextAttributes(); PrintUtil.ifChild(this.nodeChildDict[XML_ENTRY_SEQ], (n) => { this._entrySeq = PrintUtil.singleChildInt(n); }); PrintUtil.importTextAttributes(this.nodeChildDict, this.textAttributes); } getTextAttributes() { return this.textAttributes; } get entrySeq() { return this._entrySeq; } } export class Edges extends Spec { constructor(node) { super(node); if (node) { PrintUtil.ifChild(this.nodeChildDict[XML_TOP], (n) => { this._top = PrintUtil.singleChildFloat(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_LEFT], (n) => { this._left = PrintUtil.singleChildFloat(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_BOTTOM], (n) => { this._bottom = PrintUtil.singleChildFloat(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_RIGHT], (n) => { this._right = PrintUtil.singleChildFloat(n); }); } } initEdgesWith(top, left, bottom, right) { this._top = top; this._left = left; this._bottom = bottom; this._right = right; } get top() { return this._top; } get left() { return this._left; } get bottom() { return this._bottom; } get right() { return this._right; } } export class PrintForm extends Container { static fromXMLString(xmlString) { const xml = new DOMParser().parseFromString(xmlString, 'text/xml'); return new PrintForm(xml.childNodes[0]); } constructor(node) { if (node) { // Because super fluffs children, we need to pre-get the Layout to know this Form's width PrintUtil.forEachChildNode(node, (n) => { if (n.nodeName == 'Layout') { const tempLayout = new Layout(n); this.assignContainerWidth(tempLayout.singleWidthNum()); } }); } // node.childNodes. super(null, node); // NOTE: Some forms have no pages, other forms have pages. A page always contains exactly // one 1x1 grid positioned at 0,0 and is the size of the form. // Doctor up the children such that there are always Pages. If no pages exist, then // create a Page and a Grid and add these children as the content. if (this.children && this.children.length && this.children[0] instanceof Grid) { const p = new Page(this); const g = new Grid(p); const c = new PrintCell(g); c.initCellWith(new Layout(null, 0, 0, 0, 0, 0, 0), this.children); g.initGridWith(new Layout(null, 0, 0, this.layout.singleWidthNum(), this.layout.singleHeightNum()), [c]); p.initPageWith(g); this.assignChildren([p]); } } get hideControlFraming() { return this._hideControlFraming; } get hideSaveCancelButtons() { return this._hideSaveCancelButtons; } get pageChildren() { return this.children; } get settings() { return this._settings; } calcAndAssignContainerWidth(parentContainer) { this.assignContainerWidth(this.layout.singleWidthNum()); } } export class Grid extends Container { constructor(parentContainer, node) { super(parentContainer, node); } get gridLines() { if (!this._gridLines) { this._gridLines = []; let hasHLines = false; let hasVLines = false; const cols = this.layout.widths.length; const rows = this.layout.heights.length; const vLines = new Array(rows * cols + rows); // Distinct vertical lines const hLines = new Array(rows * cols + cols); // Distinct horizointal lines let colStart = 0; for (let c = 0; c < cols; c++) { let rowStart = 0; const colWidth = this.layout.widths[c].resolveWithFill(this.parentContainer.containerWidth); for (let r = 0; r < rows; r++) { const rowHeight = this.layout.heights[r].resolveWithFill(this.parentContainer.containerWidth); // Vertical lines let lineWidth = 0; if (c == 0) { // Left most vertical lineWidth = this.cellChildren[r][c].borderWidths.left; } else { // Middle verticals lineWidth = Math.max(this.cellChildren[r][c - 1].borderWidths.right, this.cellChildren[r][c].borderWidths.left); } if (lineWidth) { vLines[c * rows + r] = new GridLine(new Point(colStart, rowStart), new Point(colStart, rowStart + rowHeight), lineWidth); hasVLines = true; } if (c == cols - 1) { // Right most vertical lineWidth = this.cellChildren[r][c].borderWidths.right; if (lineWidth) { // Place these appropriately so the combining logic can work. vLines[cols * rows + r] = new GridLine(new Point(colStart + colWidth, rowStart), new Point(colStart + colWidth, rowStart + rowHeight), lineWidth); hasVLines = true; } } // Horizontal lines lineWidth = 0; if (r == 0) { // Top most horizontal lineWidth = this.cellChildren[r][c].borderWidths.top; } else { // Middle horizontals lineWidth = Math.max(this.cellChildren[r - 1][c].borderWidths.bottom, this.cellChildren[r][c].borderWidths.top); } if (lineWidth) { hLines[r * cols + c] = new GridLine(new Point(colStart, rowStart), new Point(colStart + colWidth, rowStart), lineWidth); hasHLines = true; } if (r == rows - 1) { // Bottom most horizontal lineWidth = this.cellChildren[r][c].borderWidths.bottom; if (lineWidth) { // Place these appropriately so the combining logic can work. hLines[cols * rows + c] = new GridLine(new Point(colStart, rowStart + rowHeight), new Point(colStart + colWidth, rowStart + rowHeight), lineWidth); hasHLines = true; } } rowStart += rowHeight; } colStart += colWidth; } // Combine adjacent lines let lastX = NaN; let lastEndY = NaN; let lastLineWidth = NaN; let lastPush = this._gridLines.length - 1; if (hasVLines) { for (const gl of vLines) { if (gl) { if (isNaN(lastEndY)) { lastEndY = gl.end.y; lastX = gl.end.x; lastLineWidth = gl.lineWidth; this._gridLines.push(gl); lastPush++; } else if (gl.start.y == lastEndY && gl.start.x == lastX && gl.lineWidth == lastLineWidth) { // This line and the previous can be combined lastEndY = gl.end.y; this._gridLines[lastPush].end = gl.end; } else { this._gridLines.push(gl); lastPush++; lastEndY = gl.end.y; lastX = gl.end.x; lastLineWidth = gl.lineWidth; } } } } if (hasHLines) { let lastEndX = NaN; let lastY = NaN; lastLineWidth = NaN; lastPush = this._gridLines.length - 1; for (const gl of hLines) { if (gl) { if (isNaN(lastEndX)) { lastEndX = gl.end.x; lastY = gl.end.y; lastLineWidth = gl.lineWidth; this._gridLines.push(gl); lastPush++; } else if (gl.start.x == lastEndX && gl.start.y == lastY && gl.lineWidth == lastLineWidth) { // This line and the previous can be combined lastEndX = gl.end.x; this._gridLines[lastPush].end = gl.end; } else { this._gridLines.push(gl); lastPush++; lastEndX = gl.end.x; lastY = gl.end.y; lastLineWidth = gl.lineWidth; } } } } } return this._gridLines; } initCells() { // Structure the cells so that they can be retrieved this._cellChildren = new Array(this.layout.heights.length); for (let i = 0; i < this.layout.heights.length; i++) { this._cellChildren[i] = new Array(this.layout.widths.length); } this.children.map((c) => { this._cellChildren[c.layout.row][c.layout.column] = c; }); } get cellChildren() { if (this._cellChildren == null) { this.initCells(); } return this._cellChildren; } initGridWith(overrideLayout, overrideChildren) { super.initContainerWith(overrideLayout, overrideChildren); this.initCells(); } } export class GridLine { constructor(start, end, lineWidth) { this.start = start; this.end = end; this.lineWidth = lineWidth; } } export class Point { constructor(x, y) { this.x = x; this.y = y; } } export class Image extends Component { constructor(parentContainer, node) { super(parentContainer, node); PrintUtil.ifChild(this.nodeChildDict[XML_ALLOW_ANNOTATIONS], (n) => { this._allowAnnotations = PrintUtil.singleChildBoolean(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_ALLOW_PICKER], (n) => { this._allowPicker = PrintUtil.singleChildBoolean(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_ALLOW_PICK_OPTIONS], (n) => { this._allowPickOptions = PrintUtil.singleChildBoolean(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_ASPECT_MODE], (n) => { this._aspectMode = PrintUtil.enumValue(n, AspectMode); }); PrintUtil.ifChild(this.nodeChildDict[XML_CAP_INSETS], (n) => { this._capInsets = new Edges(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_RESIZE_MODE], (n) => { this._resizeMode = PrintUtil.enumValue(n, ResizeMode); }); PrintUtil.ifChild(this.nodeChildDict[XML_URL], (n) => { this._urlString = PrintUtil.singleChildText(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_CAPTURE_BOUNDS], (n) => { this._captureBounds = new CaptureBounds(n); }); } get allowAnnotations() { return this._allowAnnotations; } get allowPicker() { return this._allowPicker; } get allowPickOptions() { return this._allowPickOptions; } get aspectMode() { return this._aspectMode; } get capInsets() { return this._capInsets; } get resizeMode() { return this._resizeMode; } get urlString() { return this._urlString; } get capatureBounds() { return this._captureBounds; } } export class Label extends Component { constructor(parentContainer, node) { super(parentContainer, node); this._textAttributes = new TextAttributes(); PrintUtil.importTextAttributes(this.nodeChildDict, this._textAttributes); PrintUtil.ifChild(this.nodeChildDict[XML_TEXT], (n) => { this._text = PrintUtil.singleChildText(n); }); } get text() { return this._text; } } export class Layout extends Spec { constructor(node, x, y, width, height, row, col) { super(node); if (node) { PrintUtil.ifChild(this.nodeChildDict[XML_UOM], (n) => { this._uom = PrintUtil.singleChildText(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_COLUMN], (n) => { this._column = PrintUtil.singleChildInt(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_ROW], (n) => { this._row = PrintUtil.singleChildInt(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_SIZE], (n) => { this._heights = PrintUtil.arrayOfRichNums(n, 'Height'); this._widths = PrintUtil.arrayOfRichNums(n, 'Width'); }); PrintUtil.ifChild(this.nodeChildDict[XML_FILL_PARENT], (n) => { this._heights = [new RichNum(NaN, RichNumUsage.FillParent)]; this._widths = [new RichNum(NaN, RichNumUsage.FillParent)]; }); PrintUtil.ifChild(this.nodeChildDict[XML_ORIGIN], (n) => { PrintUtil.forEachChildNode(n, (n2) => { switch (n2.nodeName) { case 'X': this._x = PrintUtil.singleChildFloat(n2); break; case 'Y': this._y = PrintUtil.singleChildFloat(n2); break; } }); }); } else { this._x = x; this._y = y; this._widths = [new RichNum(width)]; this._heights = [new RichNum(height)]; this._column = col; this._row = row; } } get uom() { return this._uom; } get heights() { return this._heights; } get widths() { return this._widths; } get x() { return this._x; } get y() { return this._y; } get column() { return this._column; } get row() { return this._row; } singleHeightNum() { const rn = this.singleHeightRichNum(); if (!rn.isNumber) { throw Error('Expecting number on height layout'); } return rn.value; } singleHeightRichNum() { if (!this.heights) { throw Error('No height values on Layout'); } else if (this.heights.length != 1) { throw Error('Expecting exactly 1 height, but found: ' + this.heights.length); } else { return this.heights[0]; } } singleWidthNum() { const rn = this.singleWidthRichNum(); if (!rn.isNumber) { throw Error('Expecting number on width layout'); } return rn.value; } singleWidthRichNum() { if (!this.widths) { throw Error('No width values on Layout'); } else if (this.widths.length != 1) { throw Error('Expecting exactly 1 width, but found: ' + this.widths.length); } else { return this.widths[0]; } } sumOfHeights() { let answer = 0.0; if (!this.heights) { throw Error('No height values on Layout'); } this.heights.map((rn) => { if (!rn) { throw Error('Unsupported ricn num usage on layout.heights'); } if (!rn.isNumber) { throw Error('Expecting number on layout.heights'); } answer += rn.value; }); return answer; } sumOfWidths(parentSize) { let answer = 0.0; if (!this.widths) { throw Error('No width values on Layout'); } this.widths.map((rn) => { if (!rn) { throw Error('Unsupported ricn num usage on layout.widths'); } if (rn.isFillParent) { if (this.widths.length != 1) { throw Error('More than one value being summed and FillParentWidth used: layout.widths'); } answer = parentSize; } else if (rn.isPercentOfParent) { answer += parentSize * rn.valueOfPercent; } else if (rn.isNumber) { answer += rn.value; } else { throw Error('Unknown RichNum usage on layout.widths'); } }); return answer; } } export class Page extends Container { constructor(parentContainer, node) { super(parentContainer, node); } get gridChildren() { return this.children; } initPageWith(grid) { this.initContainerWith(null, [grid]); } calcAndAssignContainerWidth(parentContainer) { this.assignContainerWidth(parentContainer.containerWidth); } } export class Settings extends Spec { constructor(node) { super(node); PrintUtil.ifChild(this.nodeChildDict[XML_REFRESH_TIMER], (n) => { this._refreshTimer = PrintUtil.singleChildInt(n); }); } get refreshTimer() { return this._refreshTimer; } } export class RichNum { constructor(_value, _usage = RichNumUsage.Absolute) { this._value = _value; this._usage = _usage; } get value() { if (!this.isNumber) { throw Error('RichNum is not a raw number.'); } return this._value; } get valueOfPercent() { if (!this.isPercentOfParent) { throw Error('PercentOfParent requested for wrong usage.'); } return this._value * 0.01; } get isNumber() { return this._usage == RichNumUsage.Absolute; } get isFillParent() { return this._usage == RichNumUsage.FillParent; } get isPercentOfParent() { return this._usage == RichNumUsage.PercentOfParent; } resolveWithFill(n) { let answer; if (this.isNumber) { answer = this._value; } else if (this.isFillParent) { answer = n; } else if (this.isPercentOfParent) { answer = this.valueOfPercent * n; } else { throw Error('Unknown RichNum usage on resolveWithFill'); } return answer; } } RichNum.ZERO = new RichNum(0); export class SignatureCapture extends Component { constructor(parentContainer, node) { super(parentContainer, node); PrintUtil.ifChild(this.nodeChildDict[XML_CAPTURE_BOUNDS], (n) => { this._captureBounds = new CaptureBounds(n); }); PrintUtil.ifChild(this.nodeChildDict[XML_LINE_COLOR], (n) => { this._lineColor = new Color(n); }); } get captureBounds() { return this._captureBounds; } get lineColor() { return this._lineColor; } } export class TextAlignment { constructor(_usage) { this._usage = _usage; } get isCenter() { return this._usage == TextAlignmentUsage.Center; } get isLeft() { return this._usage == TextAlignmentUsage.Left; } get isRight() { return this._usage == TextAlignmentUsage.Right; } } export class TextArea extends Component { constructor(parentContainer, node) { super(parentContainer, node); this._textAttributes = new TextAttributes(); PrintUtil.ifChild(this.nodeChildDict[XML_ENTRY_SEQ], (n) => { this._entrySeq = PrintUtil.singleChildInt(n); }); PrintUtil.importTextAttributes(this.nodeChildDict, this._textAttributes); } get entrySeq() { return this._entrySeq; } } export class TextField extends Component { constructor(parentContainer, node) { super(parentContainer, node); this._textAttributes = new TextAttributes(); PrintUtil.ifChild(this.nodeChildDict[XML_ENTRY_SEQ], (n) => { this._entrySeq = PrintUtil.singleChildInt(n); }); PrintUtil.importTextAttributes(this.nodeChildDict, this._textAttributes); } get entrySeq() { return this._entrySeq; } } export class TimePicker extends Component { constructor(parentContainer, node) { super(parentContainer, node); this._textAttributes = new TextAttributes(); PrintUtil.ifChild(this.nodeChildDict[XML_ENTRY_SEQ], (n) => { this._entrySeq = PrintUtil.singleChildInt(n); }); PrintUtil.importTextAttributes(this.nodeChildDict, this._textAttributes); } get entrySeq() { return this._entrySeq; } } export class ValuePicker extends Component { constructor(parentContainer, node) { super(parentContainer, node); this._textAttributes = new TextAttributes(); PrintUtil.ifChild(this.nodeChildDict[XML_ENTRY_SEQ], (n) => { this._entrySeq = PrintUtil.singleChildInt(n); }); PrintUtil.importTextAttributes(this.nodeChildDict, this._textAttributes); } get entrySeq() { return this._entrySeq; } } // export class RichNum { // constructor(node:Node, public value?:number, public usage:RichNumUsage=RichNumUsage.Absolute) { // if (node) { // // } else { // // Values held by constructor line // } // } // // } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ComponentFactory { static fromNode(node, parentContainer) { let answer = null; switch (node.nodeName) { case XML_BUTTON: answer = new Button(parentContainer, node); break; case XML_CHECKBOX: answer = new Checkbox(parentContainer, node); break; case XML_DATE_PICKER: answer = new DatePicker(parentContainer, node); break; case XML_IMAGE: answer = new Image(parentContainer, node); break; case XML_LABEL: answer = new Label(parentContainer, node); break; case XML_SIGNATURE_CAPTURE: answer = new SignatureCapture(parentContainer, node); break; case XML_TEXT_AREA: answer = new TextArea(parentContainer, node); break; case XML_TEXT_FIELD: answer = new TextField(parentContainer, node); break; case XML_TIME_PICKER: answer = new TimePicker(parentContainer, node); break; case XML_VALUE_PICKER: answer = new ValuePicker(parentContainer, node); break; case XML_CELL: answer = new PrintCell(parentContainer, node); break; case XML_FORM: answer = new PrintForm(node); break; case XML_GRID: answer = new Grid(parentContainer, node); break; case XML_PAGE: answer = new Page(parentContainer, node); break; } return answer; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class PrintUtil { static arrayOfRichNums(node, name) { const answer = []; PrintUtil.forEachChildNode(node, (n) => { if (n.nodeName == name) { answer.push(PrintUtil.singleChildRichNum(n)); } }); return answer; } static enumValue(node, e) { const answer = null; const sv = PrintUtil.singleChildText(node); let nv; if (sv) { nv = e[sv]; } return nv; } static forEachChildNode(node, f) { for (let i = 0; i < node.childNodes.length; i++) { f(node.childNodes[i]); } } static ifChild(node, f) { if (node) { f(node); } } static importTextAttributes(nodeChildDict, textAttributes) { PrintUtil.ifChild(nodeChildDict[XML_BOLD], (n) => { textAttributes.bold = PrintUtil.singleChildBoolean(n); }); PrintUtil.ifChild(nodeChildDict[XML_ITALIC], (n) => { textAttributes.italic = PrintUtil.singleChildBoolean(n); }); PrintUtil.ifChild(nodeChildDict[XML_UNDERLINE], (n) => { textAttributes.underline = PrintUtil.singleChildBoolean(n); }); PrintUtil.ifChild(nodeChildDict[XML_TEXT_ALIGNMENT], (n) => { textAttributes.textAlignment = new TextAlignment(PrintUtil.singleChildTextAlignmentUsage(n)); }); PrintUtil.ifChild(nodeChildDict[XML_TEXT_COLOR], (n) => { textAttributes.textColor = new Color(n); }); PrintUtil.ifChild(nodeChildDict[XML_NUMBER_OF_LINES], (n) => { textAttributes.numberOfLines = PrintUtil.singleChildInt(n); }); } static singleChildBoolean(node) { const text = PrintUtil.singleChildText(node); if (text) { return text.toLocaleLowerCase() == 'true'; } else { return false; } } static singleChildInt(node) { let answer; if (node.childNodes.length != 1) { Log.error('XML error with ' + node.nodeName + '. Expected exactly one child node.'); } else if (node.childNodes[0].nodeName != '#text') { Log.error('XML error with ' + node.nodeName + '. Expected numeric node.'); } else { answer = parseInt(node.childNodes[0].textContent); } return answer; } static singleChildFloat(node) { let answer; if (node.childNodes.length != 1) { Log.error('XML error with ' + node.nodeName + '. Expected exactly one child node.'); } else if (node.childNodes[0].nodeName != '#text') { Log.error('XML error with ' + node.nodeName + '. Expected numeric node.'); } else { answer = parseFloat(node.childNodes[0].textContent); } return answer; } static singleChildRichNum(node) { // Either there is a FillParent entry with surrounding white space, or a single text entry let answer; for (let i = 0; i < node.childNodes.length; i++) { if (node.childNodes[i].nodeName == RichNumUsage[RichNumUsage.PercentOfParent].toString()) { const v = this.singleChildFloat(node.childNodes[i]); answer = new RichNum(v, RichNumUsage.PercentOfParent); break; } else if (node.childNodes[i].nodeName == RichNumUsage[RichNumUsage.FillParent].toString()) { answer = new RichNum(NaN, RichNumUsage.FillParent); break; } else if (node.childNodes[i].nodeName == '#text') { const v = parseFloat(node.childNodes[i].textContent.trim()); if (!isNaN(v)) { answer = new RichNum(v); } // Don't break, keep looking for FillParent } } return answer; } static singleChildText(node) { let text = null; if (node.childNodes.length != 1) { text = 'ExpectedExactlyOneNode'; Log.error('XML error with ' + node.nodeName + '. Expected exactly one child node.'); } else if (node.childNodes[0].nodeName != '#text') { text = 'ExpectedNodeText'; Log.error('XML error with ' + node.nodeName + '. Expected text node.'); } else { text = node.childNodes[0].textContent; } return text; } static singleChildTextAlignmentUsage(node) { // Either there is a FillParent entry with surrounding white space, or a single text entry let answer = TextAlignmentUsage.Left; if (node.childNodes.length != 1) { Log.error('XML error with ' + node.nodeName + '. Expected exactly one child node.'); } else if (node.childNodes[0].nodeName != '#text') { Log.error('XML error with ' + node.nodeName + '. Expected text node.'); } else { const a = node.childNodes[0].textContent; if (a == TextAlignmentUsage[TextAlignmentUsage.Center].toString()) { answer = TextAlignmentUsage.Center; } else if (a == TextAlignmentUsage[TextAlignmentUsage.Left].toString()) { answer = TextAlignmentUsage.Left; } else if (a == TextAlignmentUsage[TextAlignmentUsage.Right].toString()) { answer = TextAlignmentUsage.Right; } else { Log.error('XML error with ' + node.nodeName + '. Unknown TextAlignment: ' + a); } } return answer; } } /** * ********************************* */ /** * ********************************* */