diff --git a/src/Field.ts b/src/Field.ts index 6faa0f4..6248807 100644 --- a/src/Field.ts +++ b/src/Field.ts @@ -1,5 +1,6 @@ import Widget from "./Widget"; import { replaceEntities, isTrue } from "./helpers/attributeParser"; +import { parseBoolAttribute } from "./helpers/nodeParser"; class Field extends Widget { /** @@ -125,6 +126,27 @@ class Field extends Widget { this._selectionValues = value; } + _autoRefresh?: boolean = false; + get autoRefresh(): boolean { + return this._autoRefresh ?? false; + } + + set autoRefresh(value: boolean) { + this._autoRefresh = value; + } + + get readOnly(): boolean | undefined { + if (this.autoRefresh) { + return true; + } else { + return super.readOnly; + } + } + + set readOnly(value: boolean | undefined) { + super.readOnly = value; + } + constructor(props: any) { super(props); @@ -176,6 +198,9 @@ class Field extends Widget { if (props.help_inline) { this.tooltipInline = isTrue(props.help_inline); } + if (props.autorefresh) { + this.autoRefresh = parseBoolAttribute(props.autorefresh); + } } } diff --git a/src/Form.ts b/src/Form.ts index 097021b..a22301b 100644 --- a/src/Form.ts +++ b/src/Form.ts @@ -124,6 +124,14 @@ class Form { this._invisibleFields = value; } + /** + * List of autorefreshable fields + */ + _autorefreshableFields: string[] = []; + get autorefreshableFields(): string[] { + return this._autorefreshableFields; + } + /** * Context for each field in the form */ @@ -170,6 +178,11 @@ class Form { this._contextForFields[unknownWidget._id] = widget._context; } }); + + // Also we store all the autorefreshables fields in a list + this._autorefreshableFields = allWidgets + .filter((widget) => widget instanceof Field && widget.autoRefresh) + .map((field) => (field as Field)._id); } parseNode({ diff --git a/src/Tree.ts b/src/Tree.ts index 17dee85..ef8da89 100644 --- a/src/Tree.ts +++ b/src/Tree.ts @@ -1,7 +1,7 @@ import WidgetFactory from "./WidgetFactory"; import Widget from "./Widget"; import { replaceEntities } from "./helpers/attributeParser"; -import { ParsedNode } from "./helpers/nodeParser"; +import { parseBoolAttribute, ParsedNode } from "./helpers/nodeParser"; import * as txml from "txml"; import { parseContext } from "./helpers/contextParser"; @@ -67,6 +67,14 @@ class Tree { this._contextForFields = value; } + /** + * List of autorefreshable fields + */ + _autorefreshableFields: string[] = []; + get autorefreshableFields(): string[] { + return this._autorefreshableFields; + } + /** * Is infinite */ @@ -145,6 +153,10 @@ class Tree { const widget = widgetFactory.createWidget(widgetType, mergedAttrs); this._columns.push(widget); } + + if (parseBoolAttribute(mergedAttrs.autorefresh)) { + this._autorefreshableFields.push(name); + } } }); } diff --git a/src/Widget.ts b/src/Widget.ts index 9425e3a..128f3f3 100644 --- a/src/Widget.ts +++ b/src/Widget.ts @@ -1,4 +1,5 @@ import { replaceEntities, parseWidgetProps } from "./helpers/attributeParser"; +import { parseBoolAttribute } from "./helpers/nodeParser"; abstract class Widget { /** @@ -132,19 +133,7 @@ abstract class Widget { this._colspan = +props.colspan; } if (props.readonly !== undefined) { - if ( - props.readonly === "1" || - props.readonly === 1 || - props.readonly === true - ) { - this._readOnly = true; - } else if ( - props.readonly === "0" || - props.readonly === 0 || - props.readonly === false - ) { - this._readOnly = false; - } + this._readOnly = parseBoolAttribute(props.readonly); } if (props.invisible) { if ( diff --git a/src/helpers/nodeParser.ts b/src/helpers/nodeParser.ts index 21c7287..3e49f57 100644 --- a/src/helpers/nodeParser.ts +++ b/src/helpers/nodeParser.ts @@ -5,7 +5,13 @@ type ParsedNode = { }; const parseBoolAttribute = (attr: any): boolean => { - if (attr === 1 || attr === "1" || attr === true || attr === "True") { + if ( + attr === 1 || + attr === "1" || + attr === true || + attr === "True" || + attr === "true" + ) { return true; } else { return false; diff --git a/src/spec/Field.spec.ts b/src/spec/Field.spec.ts new file mode 100644 index 0000000..35b2df1 --- /dev/null +++ b/src/spec/Field.spec.ts @@ -0,0 +1,35 @@ +import { describe, it, expect } from "vitest"; +import Field from "../Field"; + +describe("Field", () => { + describe("with the autoRefresh property", () => { + it("should be false as default", () => { + const props = {}; + const field = new Field(props); + expect(field.autoRefresh).toBe(false); + }); + it("should work with text", () => { + const props = { + autorefresh: "1", + }; + const field = new Field(props); + expect(field.autoRefresh).toBe(true); + }); + describe("if autorefresh is not a valid boold", () => { + it("should return false", () => { + const props = { + autorefresh: "abc", + }; + const field = new Field(props); + expect(field.autoRefresh).toBe(false); + }); + }); + it("should return true for readOnly if autoRefresh is set", () => { + const props = { + autorefresh: true, + }; + const field = new Field(props); + expect(field.readOnly).toBe(true); + }); + }); +}); diff --git a/src/spec/Form.spec.ts b/src/spec/Form.spec.ts index e53a9e0..10bc538 100644 --- a/src/spec/Form.spec.ts +++ b/src/spec/Form.spec.ts @@ -6015,6 +6015,56 @@ describe("A Form", () => { expect(field_char?.type).toBe("arrow_steps"); expect(field_char?.id).toBe("field_char"); }); + it("a field with autorefresh evaluated in attrs should be present in form autorefreshable fields property", () => { + const fields = { + field_char: { + string: "Etapa", + type: "char", + }, + state: { + readonly: true, + required: true, + selection: [ + ["esborrany", "Borrador"], + ["validar", "Validar"], + ["pendent", "Pendiente"], + ["activa", "Activa"], + ["cancelada", "Cancelada"], + ["contracte", "Activación Contrato"], + ["novapolissa", "Creación nuevo contrato"], + ["modcontractual", "Modificación Contractual"], + ["impagament", "Impago"], + ["tall", "Corte"], + ["running", "En ejecución"], + ["baixa", "Baja"], + ["facturacio", "Facturación"], + ], + string: "Estado", + type: "selection", + views: {}, + }, + }; + + const xmlViewForm = ` +
`; + + const form = new Form(fields); + form.parse(xmlViewForm, { + values: { + field_char: "test", + state: "running", + }, + }); + + const field_char = form.findById("field_char") as Field; + expect(field_char).toBeDefined(); + expect(field_char?.autoRefresh).toBeTruthy(); + expect(field_char?.readOnly).toBeTruthy(); + expect(form.autorefreshableFields.length).toBe(1); + expect(form.autorefreshableFields[0]).toBe("field_char"); + }); describe("If the field has widget_props", () => { it("should merge widget_props from fields definition and xml", () => { const fields = { diff --git a/src/spec/Tree.spec.ts b/src/spec/Tree.spec.ts index c51e1e2..a2c27e3 100644 --- a/src/spec/Tree.spec.ts +++ b/src/spec/Tree.spec.ts @@ -377,4 +377,23 @@ describe("A Tree", () => { const nameWidget = tree.findById("name") as Char; expect(nameWidget.isFunction).toBeTruthy(); }); + it("Should parse autorefreshable fields", () => { + const tree = new Tree({ + name: { + required: true, + select: true, + size: 128, + string: "Potència contractada (kW)", + type: "char", + views: {}, + }, + }); + tree.parse( + `