1/*
2 * RapidContext <https://www.rapidcontext.com/>
3 * Copyright (c) 2007-2026 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/**
16 * Provides functions for managing the app user interface.
17 * @namespace RapidContext.UI
18 */
19(function (window) {
20
21 // The global error dialog
22 let errorDialog = null;
23
24 /**
25 * Displays an error message for the user. This operation may or may
26 * not block the user interface, while the message is being
27 * displayed (depending on implementation). All arguments will be
28 * concatenated and displayed.
29 *
30 * @param {...(String|Error)} [args] the messages or errors to display
31 *
32 * @return {(String|Error|Array)} the call argument or arguments array
33 *
34 * @memberof RapidContext.UI
35 */
36 function showError(...args) {
37 const msg = args.map((arg) => arg instanceof Error && arg.message || arg).join(", ");
38 console.warn(msg, ...args);
39 if (!errorDialog) {
40 const xml = [
41 "<Dialog title='Error' system='true' style='width: 25rem;'>",
42 " <i class='fa fa-exclamation-circle fa-3x color-danger mr-3'></i>",
43 " <div class='inline-block vertical-top' style='width: calc(100% - 4em);'>",
44 " <h4>Error message:</h4>",
45 " <div class='text-pre-wrap' data-message='error'></div>",
46 " </div>",
47 " <div class='text-right mt-1'>",
48 " <Button icon='fa fa-lg fa-times' data-dialog='close'>",
49 " Close",
50 " </Button>",
51 " </div>",
52 "</Dialog>"
53 ].join("");
54 errorDialog = RapidContext.UI.create(xml);
55 window.document.body.append(errorDialog);
56 }
57 const el = errorDialog.querySelector("[data-message]");
58 if (errorDialog.isHidden()) {
59 el.innerText = msg;
60 errorDialog.show();
61 } else if (!el.innerText.includes(msg)) {
62 el.innerText += `\n\n${msg}`;
63 }
64 return (args.length == 1) ? args[0] : args;
65 }
66
67 /**
68 * Connects the default UI signals for a procedure. This includes a default
69 * error handler, a loading icon with cancellation handler and a reload icon
70 * with the appropriate click handler.
71 *
72 * @param {Procedure} proc the `RapidContext.Procedure` instance
73 * @param {Icon} [loadingIcon] the loading icon, or `null`
74 * @param {Icon} [reloadIcon] the reload icon, or `null`
75 *
76 * @see RapidContext.Procedure
77 *
78 * @memberof RapidContext.UI
79 */
80 function connectProc(proc, loadingIcon, reloadIcon) {
81 // TODO: error signal not automatically cleaned up on stop()...
82 MochiKit.Signal.connect(proc, "onerror", showError);
83 if (loadingIcon) {
84 MochiKit.Signal.connect(proc, "oncall", loadingIcon, "show");
85 MochiKit.Signal.connect(proc, "onresponse", loadingIcon, "hide");
86 MochiKit.Signal.connect(loadingIcon, "onclick", proc, "cancel");
87 }
88 if (reloadIcon) {
89 MochiKit.Signal.connect(proc, "oncall", reloadIcon, "hide");
90 MochiKit.Signal.connect(proc, "onresponse", reloadIcon, "show");
91 MochiKit.Signal.connect(reloadIcon, "onclick", proc, "recall");
92 }
93 }
94
95 // Export module API
96 const RapidContext = window.RapidContext ?? (window.RapidContext = {});
97 const module = RapidContext.UI ?? (RapidContext.UI = {});
98 Object.assign(module, { showError, connectProc });
99
100})(globalThis);
101
RapidContext
Access · Discovery · Insight
www.rapidcontext.com