Source RapidContext_Widget_TextField.js

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 text 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 field value, defaults to ""
28 * @param {string} [attrs.helpText] the help text when empty (deprecated)
29 * @param {boolean} [attrs.disabled] the disabled widget flag, defaults to
30 *            false
31 * @param {boolean} [attrs.hidden] the hidden widget flag, defaults to false
32 * @param {...(string|Node)} [value] the initial text content
33 *
34 * @return {Widget} the widget DOM node
35 *
36 * @class The text field widget class. Used to provide a text input field for a
37 *     single line, using the `<input>` HTML element.
38 * @property {boolean} disabled The read-only widget disabled flag.
39 * @property {string} defaultValue The value to use on form reset.
40 * @extends RapidContext.Widget
41 *
42 * @example <caption>JavaScript</caption>
43 * var attrs = { name: "name", placeholder: "Your Name Here" };
44 * var field = RapidContext.Widget.TextField(attrs);
45 *
46 * @example <caption>User Interface XML</caption>
47 * <TextField name="name" placeholder="Your Name Here" />
48 */
49RapidContext.Widget.TextField = function (attrs/*, ...*/) {
50    function scrape(val) {
51        return String(val && val.textContent || val || "");
52    }
53    var type = (attrs && attrs.type) || "text";
54    var text = (attrs && attrs.value) || "";
55    text += Array.from(arguments).slice(1).map(scrape).join("");
56    var o = MochiKit.DOM.INPUT({ type: type, value: text });
57    RapidContext.Widget._widgetMixin(o, RapidContext.Widget.TextField);
58    o.addClass("widgetTextField");
59    o.setAttrs(Object.assign({}, attrs, { value: text }));
60    o.on("input", o._handleChange);
61    return o;
62};
63
64// Register widget class
65RapidContext.Widget.Classes.TextField = RapidContext.Widget.TextField;
66
67/**
68 * Emitted when the text is modified. This event is triggered by either
69 * user events (keypress, paste, cut, blur) or by setting the value via
70 * setAttrs(). The DOM standard onchange event has no 'event.detail'
71 * data and is triggered on blur. The synthetic onchange events all
72 * contain an 'event.detail' object with 'before', 'after' and 'cause'
73 * properties.
74 *
75 * @name RapidContext.Widget.TextField#onchange
76 * @event
77 */
78
79/**
80 * Updates the widget or HTML DOM node attributes.
81 *
82 * @param {Object} attrs the widget and node attributes to set
83 * @param {string} [attrs.name] the form field name
84 * @param {string} [attrs.value] the field value
85 * @param {string} [attrs.helpText] the help text when empty (deprecated)
86 * @param {boolean} [attrs.disabled] the disabled widget flag
87 * @param {boolean} [attrs.hidden] the hidden widget flag
88 */
89RapidContext.Widget.TextField.prototype.setAttrs = function (attrs) {
90    attrs = Object.assign({}, attrs);
91    if ("helpText" in attrs) {
92        console.warn("deprecated: setting 'helpText' attribute, use 'placeholder' instead");
93        attrs.placeholder = attrs.placeholder || attrs.helpText;
94        delete attrs.helpText;
95    }
96    if ("value" in attrs) {
97        // FIXME: This is wrong, since we're setting an attribute here.
98        // But until Form.update() has some other way to set a field
99        // value and trigger changes, this will remain.
100        this.value = attrs.value || "";
101        this._handleChange(null);
102        delete attrs.value;
103    }
104    this.__setAttrs(attrs);
105};
106
107/**
108 * Resets the text area form value to the initial value.
109 */
110RapidContext.Widget.TextField.prototype.reset = function () {
111    this.setAttrs({ value: this.defaultValue });
112};
113
114/**
115 * Returns the text field value.
116 *
117 * @return {string} the field value
118 */
119RapidContext.Widget.TextField.prototype.getValue = function () {
120    return this.value;
121};
122
123/**
124 * Handles input events for this this widget.
125 *
126 * @param {Event} [evt] the DOM Event object or null for manual
127 */
128RapidContext.Widget.TextField.prototype._handleChange = function (evt) {
129    var cause = (evt && evt.inputType) || "set";
130    var detail = { before: this.storedValue || "", after: this.value, cause: cause };
131    this.emit("change", { detail: detail, bubbles: true });
132    this.storedValue = this.value;
133};
134