Source RapidContext_Widget_Button.js

1/*
2 * RapidContext <https://www.rapidcontext.com/>
3 * Copyright (c) 2007-2025 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 button widget.
23 *
24 * @constructor
25 * @param {Object} attrs the widget and node attributes
26 * @param {boolean} [attrs.disabled] the disabled widget flag, defaults to
27 *            false
28 * @param {boolean} [attrs.hidden] the hidden widget flag, defaults to false
29 * @param {boolean} [attrs.highlight] the highlight option flag,
30 *            defaults to false
31 * @param {string} [attrs.icon] the icon reference to use, defaults
32 *            to null (no icon)
33 * @param {...(string|Node|Array)} [child] the child widgets or DOM nodes
34 *
35 * @return {Widget} the widget DOM node
36 *
37 * @class The button widget class. Used to provide a simple push
38 *     button, using the `<button>` HTML element.
39 * @extends RapidContext.Widget
40 *
41 * @example <caption>JavaScript</caption>
42 * let closeBtn = RapidContext.Widget.Button({ icon: "OK", highlight: true }, "Close");
43 *
44 * @example <caption>User Interface XML</caption>
45 * <Button id="closeBtn" icon="OK" highlight="true">Close</Button>
46 */
47RapidContext.Widget.Button = function (attrs/*, ...*/) {
48    function textNode(val) {
49        const el = document.createElement("t");
50        el.innerText = String(val && val.textContent || val).trim();
51        return el;
52    }
53    const o = RapidContext.UI.BUTTON({ type: attrs.type || "button" });
54    RapidContext.Widget._widgetMixin(o, RapidContext.Widget.Button);
55    o.addClass("widgetButton");
56    o.setAttrs(attrs);
57    Array.from(arguments).slice(1).filter(Boolean).forEach((item) => {
58        o.addChildNode((item.nodeType === 1) ? item : textNode(item));
59    });
60    return o;
61};
62
63// Register widget class
64RapidContext.Widget.Classes.Button = RapidContext.Widget.Button;
65
66/**
67 * Updates the widget or HTML DOM node attributes.
68 *
69 * @param {Object} attrs the widget and node attributes to set
70 * @param {boolean} [attrs.disabled] the disabled widget flag
71 * @param {boolean} [attrs.hidden] the hidden widget flag
72 * @param {boolean} [attrs.highlight] the highlight option flag
73 * @param {Icon|Object|string} [attrs.icon] the icon reference to use
74 */
75RapidContext.Widget.Button.prototype.setAttrs = function (attrs) {
76    attrs = { ...attrs };
77    if ("highlight" in attrs) {
78        this.classList.toggle("primary", RapidContext.Data.bool(attrs.highlight));
79        delete attrs.highlight;
80    }
81    if ("icon" in attrs) {
82        const child = this.querySelector("i");
83        if (!attrs.icon) {
84            child && RapidContext.Widget.destroyWidget(child);
85        } else if (!child) {
86            this.insertBefore(RapidContext.Widget.Icon(attrs.icon), this.firstChild);
87        } else if (attrs.icon.nodeType) {
88            child.replaceWith(attrs.icon);
89        } else if (child.setAttrs) {
90            child.setAttrs(attrs.icon);
91        } else if (typeof(attrs.icon) === "string") {
92            child.className = attrs.icon;
93        } else {
94            Object.keys(attrs.icon).forEach((k) => child.setAttribute(k, attrs.icon[k]));
95        }
96        delete attrs.icon;
97    }
98    this.__setAttrs(attrs);
99};
100