1/*
2 * RapidContext <https://www.rapidcontext.com/>
3 * Copyright (c) 2007-2023 Per Cederberg. All rights reserved.
4 *
5 * This program is free software: you can redistribute it and/or
6 * modify it under the terms of the BSD license.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * See the RapidContext LICENSE for more details.
13 */
14
15// Namespace initialization
16if (typeof(RapidContext) == "undefined") {
17 RapidContext = {};
18}
19RapidContext.Widget = RapidContext.Widget || { Classes: {} };
20
21/**
22 * Creates a new field widget.
23 *
24 * @constructor
25 * @param {Object} attrs the widget and node attributes
26 * @param {string} attrs.name the form field name
27 * @param {string} [attrs.value] the initial field value, defaults
28 * to an empty string
29 * @param {string} [attrs.format] the field format string, defaults
30 * to "{:s}"
31 * @param {function} [attrs.formatter] the value formatter function
32 * @param {number} [attrs.maxLength] the maximum data length,
33 * overflow will be displayed as a tooltip, defaults to
34 * unlimited
35 * @param {boolean} [attrs.mask] the masked display flag, when set
36 * the field value is only displayed after the user has
37 * clicked the field, defaults to false
38 * @param {boolean} [attrs.hidden] the hidden widget flag, defaults to false
39 *
40 * @return {Widget} the widget DOM node
41 *
42 * @class The field widget class. This widget is useful for providing
43 * visible display of form data, using a `<span>` HTML element.
44 * @extends RapidContext.Widget
45 *
46 * @example <caption>JavaScript</caption>
47 * let attrs = { name: "ratio", value: 0.23, format: "Ratio: {:%}" };
48 * let field = RapidContext.Widget.Field(attrs);
49 *
50 * @example <caption>User Interface XML</caption>
51 * <Field name="ratio" value="0.23" format="Ratio: {:%}" />
52 */
53RapidContext.Widget.Field = function (attrs) {
54 let o = document.createElement("span");
55 RapidContext.Widget._widgetMixin(o, RapidContext.Widget.Field);
56 o.addClass("widgetField");
57 o.setAttrs(Object.assign({ name: "", value: "" }, attrs));
58 o.defaultValue = o.value;
59 o.defaultMask = !!o.mask;
60 o.on("click", o._handleClick);
61 return o;
62};
63
64// Register widget class
65RapidContext.Widget.Classes.Field = RapidContext.Widget.Field;
66
67/**
68 * Returns the widget container DOM node.
69 *
70 * @return {Node} returns null, since child nodes are not supported
71 */
72RapidContext.Widget.Field.prototype._containerNode = function () {
73 return null;
74};
75
76/**
77 * Updates the widget or HTML DOM node attributes.
78 *
79 * @param {Object} attrs the widget and node attributes to set
80 * @param {string} [attrs.name] the form field name
81 * @param {string} [attrs.value] the field value
82 * @param {string} [attrs.format] the field format string
83 * @param {function} [attrs.formatter] the value formatter function
84 * @param {number} [attrs.maxLength] the maximum data length,
85 * overflow will be displayed as a tooltip
86 * @param {boolean} [attrs.mask] the masked display flag, when set
87 * the field value is only displayed after the user has
88 * clicked the field
89 * @param {boolean} [attrs.hidden] the hidden widget flag
90 *
91 * @example
92 * field.setAttrs({ value: 0.23 });
93 */
94RapidContext.Widget.Field.prototype.setAttrs = function (attrs) {
95 attrs = Object.assign({}, attrs);
96 if ("formatter" in attrs) {
97 let valid = typeof(attrs.formatter) == "function";
98 attrs.formatter = valid ? attrs.formatter : null;
99 }
100 if ("maxLength" in attrs) {
101 let val = parseInt(attrs.maxLength, 10);
102 attrs.maxLength = isNaN(val) ? null : val;
103 }
104 if ("mask" in attrs) {
105 attrs.mask = RapidContext.Data.bool(attrs.mask);
106 }
107 this.__setAttrs(attrs);
108 this.redraw();
109};
110
111/**
112 * Redraws the field from updated values or status. Note that this
113 * method is called automatically whenever the `setAttrs()` method is
114 * called.
115 */
116RapidContext.Widget.Field.prototype.redraw = function () {
117 let str = this.value;
118 if (this.formatter) {
119 try {
120 str = this.formatter(str);
121 } catch (e) {
122 str = e.message;
123 }
124 } else if (str == null || str === "") {
125 str = "";
126 } else if (this.format) {
127 str = MochiKit.Text.format(this.format, str);
128 } else if (typeof(str) != "string") {
129 str = str.toString();
130 }
131 let longStr = str;
132 if (this.maxLength > 0) {
133 str = MochiKit.Text.truncate(str, this.maxLength, "...");
134 }
135 if (this.mask) {
136 this.addClass("widgetFieldMask");
137 this.title = "Click to show";
138 this.innerText = "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
139 this.append(RapidContext.Widget.Icon({ ref: "LOCK", tooltip: "Click to show" }));
140 } else {
141 if (str == longStr) {
142 delete this.title;
143 } else {
144 this.title = longStr;
145 }
146 this.innerText = str;
147 }
148};
149
150/**
151 * Resets the field value to the initial value.
152 */
153RapidContext.Widget.Field.prototype.reset = function () {
154 this.setAttrs({ value: this.defaultValue, mask: this.defaultMask });
155};
156
157/**
158 * Handles click events on the field (if masked).
159 */
160RapidContext.Widget.Field.prototype._handleClick = function () {
161 if (this.mask) {
162 this.mask = false;
163 this.removeClass("widgetFieldMask");
164 this.redraw();
165 }
166};
167
RapidContext
Access · Discovery · Insight
www.rapidcontext.com