swing-ui 0.1.25 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +5 -4
- package/README.md +144 -7
- package/SwingUI.js +2611 -0
- package/classes/Arc.js +185 -0
- package/classes/Button.js +55 -0
- package/classes/CheckBox.js +33 -0
- package/classes/CheckBoxMenuItem.js +24 -0
- package/classes/ComboBox.js +329 -0
- package/classes/ComponentContainer.js +828 -0
- package/classes/ContextMenu.js +141 -0
- package/classes/DocumentEditor.js +168 -0
- package/classes/Ellipse.js +76 -0
- package/classes/InternalWindow.js +397 -0
- package/classes/InternalWindowContainer.js +93 -0
- package/classes/Label.js +52 -0
- package/classes/Line.js +105 -0
- package/classes/List.js +452 -0
- package/classes/MediaPlayer.js +504 -0
- package/classes/Menu.js +74 -0
- package/classes/MenuBar.js +56 -0
- package/classes/MenuItem.js +92 -0
- package/classes/Panel.js +50 -0
- package/classes/PasswordField.js +47 -0
- package/classes/Polygon.js +236 -0
- package/classes/Polyline.js +240 -0
- package/classes/ProgressBar.js +62 -0
- package/classes/RadioButton.js +110 -0
- package/classes/RadioButtonMenuItem.js +106 -0
- package/classes/Rectangle.js +199 -0
- package/classes/ScrollPane.js +53 -0
- package/classes/ScrollableComponent.js +141 -0
- package/classes/Separator.js +24 -0
- package/classes/Shape.js +584 -0
- package/classes/ShapeContainer.js +231 -0
- package/classes/Slider.js +172 -0
- package/classes/Spinner.js +172 -0
- package/classes/SplitView.js +82 -0
- package/classes/Stroke.js +115 -0
- package/classes/Table.js +982 -0
- package/classes/Tabs.js +228 -0
- package/classes/TextArea.js +125 -0
- package/classes/TextComponent.js +207 -0
- package/classes/TextField.js +128 -0
- package/classes/TextShape.js +123 -0
- package/classes/ToggleButton.js +147 -0
- package/classes/ToolBar.js +120 -0
- package/classes/TrayIcon.js +54 -0
- package/classes/Tree.js +569 -0
- package/classes/UIComponent.js +2113 -0
- package/classes/Window.js +609 -0
- package/enums.js +298 -0
- package/fonts.conf +32 -0
- package/functions.js +254 -0
- package/icon.png +0 -0
- package/index.js +109 -4
- package/jar/gui-11.jar +0 -0
- package/jar/lib/flatlaf.jar +0 -0
- package/jar/lib/jna.jar +0 -0
- package/package.json +58 -33
- package/typedefs.js +973 -0
- package/types/SwingUI.d.ts +727 -0
- package/types/classes/Arc.d.ts +111 -0
- package/types/classes/Button.d.ts +38 -0
- package/types/classes/CheckBox.d.ts +22 -0
- package/types/classes/CheckBoxMenuItem.d.ts +18 -0
- package/types/classes/ComboBox.d.ts +172 -0
- package/types/classes/ComponentContainer.d.ts +131 -0
- package/types/classes/ContextMenu.d.ts +74 -0
- package/types/classes/DocumentEditor.d.ts +95 -0
- package/types/classes/Ellipse.d.ts +34 -0
- package/types/classes/InternalWindow.d.ts +163 -0
- package/types/classes/InternalWindowContainer.d.ts +36 -0
- package/types/classes/Label.d.ts +33 -0
- package/types/classes/Line.d.ts +48 -0
- package/types/classes/List.d.ts +223 -0
- package/types/classes/MediaPlayer.d.ts +381 -0
- package/types/classes/Menu.d.ts +43 -0
- package/types/classes/MenuBar.d.ts +26 -0
- package/types/classes/MenuItem.d.ts +57 -0
- package/types/classes/Panel.d.ts +28 -0
- package/types/classes/PasswordField.d.ts +22 -0
- package/types/classes/Polygon.d.ts +93 -0
- package/types/classes/Polyline.d.ts +96 -0
- package/types/classes/ProgressBar.d.ts +36 -0
- package/types/classes/RadioButton.d.ts +70 -0
- package/types/classes/RadioButtonMenuItem.d.ts +71 -0
- package/types/classes/Rectangle.d.ts +82 -0
- package/types/classes/ScrollPane.d.ts +23 -0
- package/types/classes/ScrollableComponent.d.ts +81 -0
- package/types/classes/Separator.d.ts +14 -0
- package/types/classes/Shape.d.ts +223 -0
- package/types/classes/ShapeContainer.d.ts +92 -0
- package/types/classes/Slider.d.ts +107 -0
- package/types/classes/Spinner.d.ts +129 -0
- package/types/classes/SplitView.d.ts +47 -0
- package/types/classes/Stroke.d.ts +99 -0
- package/types/classes/Table.d.ts +652 -0
- package/types/classes/Tabs.d.ts +118 -0
- package/types/classes/TextArea.d.ts +45 -0
- package/types/classes/TextComponent.d.ts +136 -0
- package/types/classes/TextField.d.ts +94 -0
- package/types/classes/TextShape.d.ts +73 -0
- package/types/classes/ToggleButton.d.ts +84 -0
- package/types/classes/ToolBar.d.ts +82 -0
- package/types/classes/TrayIcon.d.ts +43 -0
- package/types/classes/Tree.d.ts +354 -0
- package/types/classes/UIComponent.d.ts +945 -0
- package/types/classes/Window.d.ts +334 -0
- package/types/enums.d.ts +437 -0
- package/types/functions.d.ts +109 -0
- package/types/index.d.ts +188 -0
- package/types/typedefs.d.ts +1626 -0
- package/ui-process-manager.js +317 -0
- package/video-devices-linux.sh +72 -0
- package/video-devices-mac.sh +33 -0
- package/CHANGES.md +0 -3
|
@@ -0,0 +1,2113 @@
|
|
|
1
|
+
import {ShortcutScope} from "swing-ui/enums.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base component class that other UI components extend. Not to be instantiated by itself.
|
|
5
|
+
* Most methods in this class are used by other classes that extend this class.
|
|
6
|
+
* @class
|
|
7
|
+
* @global
|
|
8
|
+
*/
|
|
9
|
+
class UIComponent
|
|
10
|
+
{
|
|
11
|
+
#id = null; // keep it private
|
|
12
|
+
#token = null;
|
|
13
|
+
parent_id = null;
|
|
14
|
+
#context_menu = null;
|
|
15
|
+
#prop = {
|
|
16
|
+
class: null, // instantiated class prototype
|
|
17
|
+
type: "UIComponent",
|
|
18
|
+
leaf: true, // true if the class is not extended by another class
|
|
19
|
+
visible: !(this instanceof Window), // true, unless it's a Window
|
|
20
|
+
size: {},
|
|
21
|
+
location: {x: 0, y: 0},
|
|
22
|
+
dragAction: DragDropAction.None,
|
|
23
|
+
dropAction: DragDropAction.None,
|
|
24
|
+
container: null // default NULL until container() getter is called.
|
|
25
|
+
};
|
|
26
|
+
callback = {
|
|
27
|
+
"onError": [e => ui.callback.onError.call(this, e)], // Default error event callback. Can be changed by .onError(callback)
|
|
28
|
+
"onRectangleUpdate": [e =>
|
|
29
|
+
{
|
|
30
|
+
if(e.type === "resize")
|
|
31
|
+
{
|
|
32
|
+
this.#prop.size.width = e.width ?? this.#prop.size.width;
|
|
33
|
+
this.#prop.size.height = e.height ?? this.#prop.size.height;
|
|
34
|
+
}
|
|
35
|
+
if(e.type === "move")
|
|
36
|
+
{
|
|
37
|
+
this.#prop.location.x = e.x ?? this.#prop.location.x;
|
|
38
|
+
this.#prop.location.y = e.y ?? this.#prop.location.y;
|
|
39
|
+
}
|
|
40
|
+
}]
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
static #controls_id = 0;
|
|
44
|
+
static #_freed_ids = [];
|
|
45
|
+
static #_components = []; // all components
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* This is used to be notified when the component loses all references to it, to notify SwingUI to destroy the component for garbage collection
|
|
49
|
+
* @private
|
|
50
|
+
*/
|
|
51
|
+
static #refRegistry = new FinalizationRegistry(id => { UIComponent.destroy(id); });
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Makes one class implements methods, setters, and getters of another class.
|
|
55
|
+
* @param toClass
|
|
56
|
+
* @param fromClass
|
|
57
|
+
* @throws {Error} When one or more parameters are `null`.
|
|
58
|
+
* @internal
|
|
59
|
+
* @ignore
|
|
60
|
+
*/
|
|
61
|
+
static implementClass(toClass, fromClass)
|
|
62
|
+
{
|
|
63
|
+
if(toClass == null || fromClass == null) throw new Error(`Invalid class parameters provided to implementClass(toClass, fromClass)`);
|
|
64
|
+
|
|
65
|
+
Object.getOwnPropertyNames(fromClass.prototype).forEach(key =>
|
|
66
|
+
{
|
|
67
|
+
if(key !== 'constructor')
|
|
68
|
+
{
|
|
69
|
+
const desc = Object.getOwnPropertyDescriptor(fromClass.prototype, key);
|
|
70
|
+
desc.configurable = false;
|
|
71
|
+
if(typeof desc.value === "function") desc.writable = false;
|
|
72
|
+
Object.defineProperty(toClass.prototype, key, desc);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Removes references to UI component with provided ID. Make sure to destroy all other references to the component to truly destroy it to free RAM.
|
|
79
|
+
*
|
|
80
|
+
* @internal
|
|
81
|
+
* @ignore
|
|
82
|
+
* @private
|
|
83
|
+
* @param {number} id - ID of a component to be destroyed
|
|
84
|
+
* @return {void} Doesn't return a value
|
|
85
|
+
*/
|
|
86
|
+
static destroy(id)
|
|
87
|
+
{
|
|
88
|
+
// makes sure that component is garbage collected and new one is not created with same ID yet before this one is not garbage collected
|
|
89
|
+
// this._components[id] should have a WeakReference object, but deref() should be undefined.
|
|
90
|
+
if(UIComponent.#_components[id] === undefined) return;
|
|
91
|
+
|
|
92
|
+
const component = UIComponent.#_components[id].deref();
|
|
93
|
+
if(component !== undefined) component.emit("onDispose", {type: "dispose"});
|
|
94
|
+
|
|
95
|
+
// if this was initiated by FinalizationRegistry for GC, then remove weak reference
|
|
96
|
+
UIComponent.#_components[id] = undefined;
|
|
97
|
+
delete UIComponent.#_components[id];
|
|
98
|
+
|
|
99
|
+
// send "delete" command to GUI
|
|
100
|
+
ui.sendToGUI({control: id, delete: true});
|
|
101
|
+
|
|
102
|
+
// recycle component's ID at a delay, to prevent events from destroyed component reach a new component with recycled ID
|
|
103
|
+
setTimeout(() => {UIComponent.#_freed_ids.push(id);}, 5000);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get UI component by ID.
|
|
108
|
+
*
|
|
109
|
+
* @param {number} id - ID of requested component
|
|
110
|
+
* @return {any|undefined} Returns UI component or `undefined` if there is no valid component with specified ID.
|
|
111
|
+
*/
|
|
112
|
+
static get(id)
|
|
113
|
+
{
|
|
114
|
+
return UIComponent.#_components[id]?.deref();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Returns last visible non-PopUp Window or null if no Window component is not found.
|
|
119
|
+
*
|
|
120
|
+
* @internal
|
|
121
|
+
* @static
|
|
122
|
+
* @readonly
|
|
123
|
+
* @returns {Window|null} Returns Window component or null.
|
|
124
|
+
*/
|
|
125
|
+
static getVisibleWindow()
|
|
126
|
+
{
|
|
127
|
+
const _ids = Object.keys(UIComponent.#_components);
|
|
128
|
+
|
|
129
|
+
for(let i = _ids.length - 1; i >= 0; i--)
|
|
130
|
+
{
|
|
131
|
+
const c = UIComponent.#_components[_ids[i]].deref();
|
|
132
|
+
if(c instanceof Window && c.visible() && c.type !== Window.Type.Popup) return c;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Not to be instantiated by itself. This call is extended dby other UI components.
|
|
140
|
+
*
|
|
141
|
+
* @param {string} type - Component type.
|
|
142
|
+
* @param {boolean} leaf - `true` if the UI component was not extended by a custom class.
|
|
143
|
+
* @param {...any} [data] - Additional component init data (used by some UI components).
|
|
144
|
+
* @internal
|
|
145
|
+
* @ignore
|
|
146
|
+
*/
|
|
147
|
+
constructor(type, leaf, ...data)
|
|
148
|
+
{
|
|
149
|
+
this.#prop.class = new.target;
|
|
150
|
+
this.#prop.type = type;
|
|
151
|
+
this.#prop.leaf = leaf;
|
|
152
|
+
|
|
153
|
+
if(this.#prop.class === UIComponent) throw new Error(`Class UIComponent cannot not to be instantiated. It must be extended by one of swing-ui components.`);
|
|
154
|
+
|
|
155
|
+
// reuse freed IDs or create a new one
|
|
156
|
+
this.#id = (UIComponent.#_freed_ids.length > 0) ? UIComponent.#_freed_ids.shift() : ++UIComponent.#controls_id;
|
|
157
|
+
|
|
158
|
+
// register it in array of components
|
|
159
|
+
UIComponent.#_components[this.#id] = new WeakRef(this);
|
|
160
|
+
|
|
161
|
+
// Create a token to be able to unregister this component when it's manually destroyed
|
|
162
|
+
this.#token = {id: this.#id};
|
|
163
|
+
|
|
164
|
+
// register this component for deletion when all references to it are lost (garbage collection).
|
|
165
|
+
UIComponent.#refRegistry.register(this, this.#id, this.#token); // token must be a Symbol, Number doesn't work.
|
|
166
|
+
|
|
167
|
+
// tell GUI about the new component
|
|
168
|
+
let msg = {control: this.#id, create: this.#prop.type};
|
|
169
|
+
if(data.length > 0) msg.data = data[0];
|
|
170
|
+
ui.sendToGUI(msg);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Locks methods from being overwritten or deleted.
|
|
175
|
+
* @param {Function} prototype_class
|
|
176
|
+
* @ignore
|
|
177
|
+
* @internal
|
|
178
|
+
*/
|
|
179
|
+
finalize(..._classes)
|
|
180
|
+
{
|
|
181
|
+
_classes.push(UIComponent); // UIComponent must be last in array
|
|
182
|
+
|
|
183
|
+
for(const c of _classes)
|
|
184
|
+
{
|
|
185
|
+
Object.getOwnPropertyNames(c.prototype).forEach(key=>
|
|
186
|
+
{
|
|
187
|
+
if(key === "constructor" || key === "finalize" || key === "isFinalized") return;
|
|
188
|
+
if(this.isFinalized(key)) return; // skip already locked method/setter/getter
|
|
189
|
+
|
|
190
|
+
const desc = Object.getOwnPropertyDescriptor(c.prototype, key);
|
|
191
|
+
|
|
192
|
+
if(typeof desc.value === "function") // lock function
|
|
193
|
+
{
|
|
194
|
+
|
|
195
|
+
Object.defineProperty(this, key, {
|
|
196
|
+
value: desc.value.bind(this),
|
|
197
|
+
writable: false,
|
|
198
|
+
configurable: false,
|
|
199
|
+
enumerable: desc.enumerable
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
else if((desc.get || desc.set) && !this.isFinalized(key)) // lock getter and setter
|
|
203
|
+
{
|
|
204
|
+
Object.defineProperty(this, key, {
|
|
205
|
+
get: desc.get?.bind(this),
|
|
206
|
+
set: desc.set?.bind(this),
|
|
207
|
+
configurable: false,
|
|
208
|
+
enumerable: desc.enumerable
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// these are no longer needed
|
|
215
|
+
this.finalize = null;
|
|
216
|
+
this.isFinalized = null;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* @internal
|
|
221
|
+
* @ignore
|
|
222
|
+
*/
|
|
223
|
+
isFinalized(methodName)
|
|
224
|
+
{
|
|
225
|
+
const desc = Object.getOwnPropertyDescriptor(this, methodName);
|
|
226
|
+
if(!desc) return false; // not directly defined on the object
|
|
227
|
+
return desc.writable === false && desc.configurable === false;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @internal
|
|
232
|
+
* @readonly
|
|
233
|
+
* @ignore
|
|
234
|
+
* @type {object}
|
|
235
|
+
*/
|
|
236
|
+
get prop()
|
|
237
|
+
{
|
|
238
|
+
return this.#prop;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
//region Property setters/getters
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Returns a unique ID of the component. ID is reusable, so one component may have an ID of a previously destroyed component.
|
|
245
|
+
* @readonly
|
|
246
|
+
* @type {number}
|
|
247
|
+
*/
|
|
248
|
+
get id()
|
|
249
|
+
{
|
|
250
|
+
return this.#id;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Gets a parent Object. If this component wasn't added to any container component, then `null` is returned.
|
|
255
|
+
* @readonly
|
|
256
|
+
* @type {Object|undefined}
|
|
257
|
+
*/
|
|
258
|
+
get parent()
|
|
259
|
+
{
|
|
260
|
+
this.verifyComponent();
|
|
261
|
+
|
|
262
|
+
if(this.parent_id == null) return null;
|
|
263
|
+
return UIComponent.get(this.parent_id);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Gets a Window component containing this component. Returns `null` if no Window contain this component.
|
|
268
|
+
* @readonly
|
|
269
|
+
* @type {Window|null}
|
|
270
|
+
*/
|
|
271
|
+
get window()
|
|
272
|
+
{
|
|
273
|
+
if(this instanceof Window) return this;
|
|
274
|
+
return this.parent?.window ?? null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Returns `true` if the component is a container (other components can be added to it), otherwise returns false.
|
|
279
|
+
* @readonly
|
|
280
|
+
* @type {boolean}
|
|
281
|
+
*/
|
|
282
|
+
get isContainer()
|
|
283
|
+
{
|
|
284
|
+
if(this.#prop.container == null) this.#prop.container = this instanceof ComponentContainer; // cache answer
|
|
285
|
+
return this.#prop.container;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Gets a position of this component relative to primary screen. Returns `null` if the component wasn't added to a container that is visible, or of this component is a Window and it was never visible.
|
|
290
|
+
*
|
|
291
|
+
* @readonly
|
|
292
|
+
* @type {Point|null}
|
|
293
|
+
* @see Point
|
|
294
|
+
* @see ui#screens
|
|
295
|
+
*/
|
|
296
|
+
get screenPosition()
|
|
297
|
+
{
|
|
298
|
+
return this.property("screenLocation", []);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Adds this component to a parent container component. An optional index specifies the Z-order position at which to insert the component. It calls {@link ComponentContainer#addChild}.
|
|
303
|
+
*
|
|
304
|
+
* @param {ComponentContainer} parent - The container component to which this component will be added.
|
|
305
|
+
* @param {number|object} [data_or_index] - An parameter to pass some extra data (such as Tab Name to add Panel to Tabs), or index at which to insert the child.
|
|
306
|
+
* @returns {this} Returns an instance of this component for chaining.
|
|
307
|
+
* @see ComponentContainer#addChild
|
|
308
|
+
* @example <h2>Adding a component at specified index</h2>
|
|
309
|
+
* let checkbox = new CheckBox("Enabled checkbox").addTo(panel, 5).position(10, 15); // adds to panel and positions at (10,15) coordinates
|
|
310
|
+
*
|
|
311
|
+
* @example <h2>Adding a component at specified index</h2>
|
|
312
|
+
* let panel = new Panel().addTo(tabs, {text: "Registration", enabled: true, tooltip: "Create new account", icon: "images/user.png"});
|
|
313
|
+
*/
|
|
314
|
+
addTo(parent, ...args)
|
|
315
|
+
{
|
|
316
|
+
// making sure that parent is instance of UIComponent
|
|
317
|
+
if(typeof parent !== "object" || !(parent instanceof UIComponent)) throw Error(`'parent' component must be derived from UIComponent of swing-ui module. ${ui._msg[2]}`);
|
|
318
|
+
|
|
319
|
+
parent.addChild(this, ...args);
|
|
320
|
+
return this;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Removes this component from its parent.
|
|
325
|
+
*
|
|
326
|
+
* @param {boolean} [recursive] - Boolean indicates if all descendents of this child should also be removed.
|
|
327
|
+
* @returns {this} Returns this component for method chaining
|
|
328
|
+
* @example
|
|
329
|
+
* child.remove(); // Removes child from it's parent container
|
|
330
|
+
* child.remove(true); // Removes child component from it's parent and all its descendants recursively
|
|
331
|
+
*/
|
|
332
|
+
remove()
|
|
333
|
+
{
|
|
334
|
+
let recursive = false;
|
|
335
|
+
|
|
336
|
+
if(arguments.length > 0)
|
|
337
|
+
{
|
|
338
|
+
if(typeof arguments[0] !== "boolean") throw new Error(`Invalid argument passed to remove(recursive). Boolean is expected, but received ${typeof recursive}.`);
|
|
339
|
+
recursive = arguments[0];
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if(this instanceof Window) // don't remove window, but only it's children, if recursive
|
|
343
|
+
{
|
|
344
|
+
// remove recursively, from back
|
|
345
|
+
if(recursive) for(let c = this.childCount - 1; c >= 0; c--) this.removeChild(c, true);
|
|
346
|
+
}
|
|
347
|
+
else
|
|
348
|
+
{
|
|
349
|
+
if(this.parent != null && this.parent instanceof UIComponent) this.parent.removeChild(this, recursive);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return this;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Removes the component from its container, destroys event callbacks, unregisters the component, recycles the component ID. Also prepares this component to be garbage-collected in JavaScript and GUI to free RAM.
|
|
357
|
+
*
|
|
358
|
+
* @param {boolean} [recursive=false] - Set to true to also destroy all of its descendants recursively
|
|
359
|
+
* @returns {void}
|
|
360
|
+
*/
|
|
361
|
+
destroy(...args)
|
|
362
|
+
{
|
|
363
|
+
if(this.destroyed) return;
|
|
364
|
+
|
|
365
|
+
UIComponent.#refRegistry.unregister(this.#token);
|
|
366
|
+
|
|
367
|
+
try
|
|
368
|
+
{
|
|
369
|
+
this.remove(); // remove this element from its parent
|
|
370
|
+
}catch(ex)
|
|
371
|
+
{
|
|
372
|
+
console.error(ex);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// remove context menu
|
|
376
|
+
if(this.#context_menu != null) this.contextMenu(null);
|
|
377
|
+
|
|
378
|
+
// remove references
|
|
379
|
+
UIComponent.destroy(this.#id);
|
|
380
|
+
|
|
381
|
+
// remove all properties
|
|
382
|
+
for(let prop of Object.keys(this))
|
|
383
|
+
{
|
|
384
|
+
if(prop !== "verifyComponent" && typeof this[prop] !== "function") delete this[prop];
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
this.destroyed = true;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* This function may be called to make sure the component wasn't destroyed yet before performing another operation with the component. If it's already destroyed, Exception is thrown.
|
|
392
|
+
*
|
|
393
|
+
* @return {this} Returns this component.
|
|
394
|
+
*/
|
|
395
|
+
verifyComponent()
|
|
396
|
+
{
|
|
397
|
+
if(this.destroyed ?? false)
|
|
398
|
+
{
|
|
399
|
+
throw new Error(ui._msg[0] + " (" + this.constructor.name + ")");
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
return this;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Checks if this component is inside specified ancestor component (at any level, not just direct child).
|
|
407
|
+
* @param {Object} ancestor - Ancestor component to test against
|
|
408
|
+
* @return {boolean}
|
|
409
|
+
* @see ComponentContainer#contains
|
|
410
|
+
*/
|
|
411
|
+
insideOf(ancestor)
|
|
412
|
+
{
|
|
413
|
+
if(!(ancestor instanceof ComponentContainer)) return false;
|
|
414
|
+
return ancestor.contains(this);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Sets or gets component's visibility.
|
|
419
|
+
* NOTE: Window and InternalWindow components visibility is set to `false` by default. Use .visible(true) or .show() to make it visible.
|
|
420
|
+
*
|
|
421
|
+
* @param {boolean} [visible] - `true` to make it visible, `false` to hide it.
|
|
422
|
+
* @return {boolean|this} If called with an argument, then `this` component instance is returned, otherwise `boolean` value is returned.
|
|
423
|
+
*/
|
|
424
|
+
visible(...args)
|
|
425
|
+
{
|
|
426
|
+
this.verifyComponent();
|
|
427
|
+
|
|
428
|
+
if(args.length === 0)
|
|
429
|
+
{
|
|
430
|
+
return this.#prop.visible;
|
|
431
|
+
}
|
|
432
|
+
else
|
|
433
|
+
{
|
|
434
|
+
if(args[0] == null) return this; // ignore null or undefined
|
|
435
|
+
this.#prop.visible = (args[0] === true);
|
|
436
|
+
}
|
|
437
|
+
return this.property("visible", [this.#prop.visible]);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Convenience function that calls this.visible(true)
|
|
442
|
+
* @return {this}
|
|
443
|
+
*/
|
|
444
|
+
show()
|
|
445
|
+
{
|
|
446
|
+
return this.visible(true);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Convenience function that calls this.visible(false)
|
|
451
|
+
* @return {this}
|
|
452
|
+
*/
|
|
453
|
+
hide()
|
|
454
|
+
{
|
|
455
|
+
return this.visible(false);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Enables or disables the component.
|
|
460
|
+
*
|
|
461
|
+
* @param {boolean} [enabled] `true` to enable, `false` to disable the component. Omit to get current value.
|
|
462
|
+
* @return {boolean|this} If called with an argument, then `this` component instance is returned, otherwise `boolean` value is returned.
|
|
463
|
+
*/
|
|
464
|
+
enabled(...args)
|
|
465
|
+
{
|
|
466
|
+
return this.property("enabled", args);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Sets or gets the size of the component.
|
|
471
|
+
*
|
|
472
|
+
* For {@link Window}, the returned and assigned size represents the entire window, including the title bar and borders. The actual area available for placing child components is smaller. Use {@link Window#innerSize} when you need to specify the content area size instead.
|
|
473
|
+
*
|
|
474
|
+
* @param {number|Size} [width_or_size] - Number as width, or `Size` formatted object.
|
|
475
|
+
* @param {number} [height] - Height of component. Required if first argument is `number`.
|
|
476
|
+
* @return {Size|this} Component size object if no arguments are set, otherwise returns `this` component.
|
|
477
|
+
* @see Size
|
|
478
|
+
* @example
|
|
479
|
+
* // Usage examples:
|
|
480
|
+
* button.size(100, 25);
|
|
481
|
+
* button.size({width: 100, height: 25});
|
|
482
|
+
* let size = button.size();
|
|
483
|
+
*/
|
|
484
|
+
size(...args)
|
|
485
|
+
{
|
|
486
|
+
if(args.length > 0)
|
|
487
|
+
{
|
|
488
|
+
const size = (args.length > 1) ? {
|
|
489
|
+
width: args[0],
|
|
490
|
+
height: args[1]
|
|
491
|
+
} : (args[0] != null && typeof args[0] === "object") ? {
|
|
492
|
+
width: args[0].width ?? this.#prop.size.width,
|
|
493
|
+
height: args[0].height ?? this.#prop.size.height
|
|
494
|
+
} : null;
|
|
495
|
+
|
|
496
|
+
if(size == null)
|
|
497
|
+
{
|
|
498
|
+
this.#prop.size = {}; // reset, to be retrieved from GUI on next request
|
|
499
|
+
return this;
|
|
500
|
+
}
|
|
501
|
+
if(this.parent instanceof Tabs || this.parent instanceof ScrollPane) return this;
|
|
502
|
+
if(size.width == null || (typeof size.width !== "string" && isNaN(size.width))) size.width = this.#prop.size.width ?? this.width();
|
|
503
|
+
if(size.height == null || (typeof size.height !== "string" && isNaN(size.height))) size.height = this.#prop.size.height ?? this.height();
|
|
504
|
+
|
|
505
|
+
// check if width is in %
|
|
506
|
+
if(typeof size.width === "string" && size.width.indexOf("%") > 0)
|
|
507
|
+
{
|
|
508
|
+
const m = parseFloat(size.width.replace("%", "")) / 100;
|
|
509
|
+
size.width = (this.parent != null) ? (("innerSize" in this.parent) ? this.parent.innerSize().width : this.parent.width()) * m : this.width();
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// check if height is in %
|
|
513
|
+
if(typeof size.height === "string" && size.height.indexOf("%") > 0)
|
|
514
|
+
{
|
|
515
|
+
const m = parseFloat(size.height.replace("%", "")) / 100;
|
|
516
|
+
size.height = (this.parent != null) ? (("innerSize" in this.parent) ? this.parent.innerSize().height : this.parent.height()) * m : this.height();
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// if size changed, then send to GUI
|
|
520
|
+
if(this.#prop.size.width !== size.width || this.#prop.size.height !== size.height)
|
|
521
|
+
{
|
|
522
|
+
this.#prop.size = size;
|
|
523
|
+
return this.property("size", [this.#prop.size]);
|
|
524
|
+
}
|
|
525
|
+
else
|
|
526
|
+
{
|
|
527
|
+
return this;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
else
|
|
531
|
+
{
|
|
532
|
+
this.verifyComponent();
|
|
533
|
+
|
|
534
|
+
// if size isn't known yet, retrieve it from GUI
|
|
535
|
+
if(!("width" in this.#prop.size && "height" in this.#prop.size))
|
|
536
|
+
{
|
|
537
|
+
const size = this.property("size", []);
|
|
538
|
+
Object.assign(this.#prop.size, size);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return {...this.#prop.size};
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Convenience method to set or get the width of component.
|
|
547
|
+
*
|
|
548
|
+
* @param {number} [width] - New width of the component.
|
|
549
|
+
* @return {number|UIComponent} Returns width if no argument is set, otherwise returns `this` component.
|
|
550
|
+
* @see UIComponent#size
|
|
551
|
+
*/
|
|
552
|
+
width(...args)
|
|
553
|
+
{
|
|
554
|
+
const size = this.size();
|
|
555
|
+
|
|
556
|
+
if(args.length === 0)
|
|
557
|
+
{
|
|
558
|
+
return size.width;
|
|
559
|
+
}
|
|
560
|
+
else
|
|
561
|
+
{
|
|
562
|
+
return this.size(parseInt(args[0]), size.height);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Convenience method to set or get the height of component.
|
|
568
|
+
*
|
|
569
|
+
* @param {number} [height] - New height of the component.
|
|
570
|
+
* @return {number|UIComponent} Returns height if no argument is set, otherwise returns `this` component.
|
|
571
|
+
* @see UIComponent#size
|
|
572
|
+
*/
|
|
573
|
+
height(...args)
|
|
574
|
+
{
|
|
575
|
+
if(args.length === 0)
|
|
576
|
+
{
|
|
577
|
+
return this.size().height;
|
|
578
|
+
}
|
|
579
|
+
else
|
|
580
|
+
{
|
|
581
|
+
return this.size(this.size().width, parseInt(args[0]));
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Sets or gets text content of the component. Even though some components don't show text, you can still set text to it.
|
|
587
|
+
*
|
|
588
|
+
* @param {string} [text=undefined] - Can be plain text or HTML. HTML is only supported in some components (e.g. Label, Button, TextDocument, ...) and should be surrounded with HTML tags. Check example below.
|
|
589
|
+
* @param {TextAction} [action=TextAction.Set] - Specific action to perform with text. Replace, append, prepend, or insert. Applies only to some components. Do not use this argument for HTML content.
|
|
590
|
+
* @param {number} [insert_position=undefined] - Position where to insert text. Applies only if `action` argument is TextAction.Insert.
|
|
591
|
+
* @return {string|this} Returns text value if no argument is set, otherwise returns `this` component.
|
|
592
|
+
* @example
|
|
593
|
+
* const txt = textfield.text(); // gets text value
|
|
594
|
+
* textfield.text("New Text"); // sets new text value
|
|
595
|
+
* textfield.text("Appended Text", TextAction.Append); // Appends new text to the end of current text
|
|
596
|
+
* textfield.text("Inserted Text", TextAction.Insert); // Inserts at current caret position
|
|
597
|
+
* textfield.text("Inserted Text", TextAction.Insert, textfield.caretPosition() - 50); // Inserts at specified position
|
|
598
|
+
* textfield.text("New Text", TextAction.ReplaceSelection); // Replaces selected text or inserts at current cursor position if no text is selected (applies only to text editing components, like TextField, TextArea, ...).
|
|
599
|
+
*/
|
|
600
|
+
text(...args)
|
|
601
|
+
{
|
|
602
|
+
if(args.length > 0)
|
|
603
|
+
{
|
|
604
|
+
ui.sendToGUI({
|
|
605
|
+
control: this.#id,
|
|
606
|
+
set: "text",
|
|
607
|
+
value: String(args[0]),
|
|
608
|
+
data: {
|
|
609
|
+
action: args.length > 1 ? args[1] : TextAction.Set,
|
|
610
|
+
index: args.length > 2 && args[1] === TextAction.Insert ? parseInt(args[2]) : undefined
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
return this;
|
|
614
|
+
}
|
|
615
|
+
else
|
|
616
|
+
{
|
|
617
|
+
return ui.sendToGUI({control: this.#id, get: "text"});
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* @internal
|
|
623
|
+
* @ignore
|
|
624
|
+
* @private
|
|
625
|
+
* @param {string} property
|
|
626
|
+
* @param {any} value
|
|
627
|
+
* @return {any}
|
|
628
|
+
*/
|
|
629
|
+
property(property, ...args)
|
|
630
|
+
{
|
|
631
|
+
if(args.length > 0) args = args[0];
|
|
632
|
+
|
|
633
|
+
this.verifyComponent();
|
|
634
|
+
|
|
635
|
+
if(args.length > 0)
|
|
636
|
+
{
|
|
637
|
+
ui.sendToGUI({control: this.#id, set: property, value: args[0]});
|
|
638
|
+
return this;
|
|
639
|
+
}
|
|
640
|
+
else
|
|
641
|
+
{
|
|
642
|
+
return ui.sendToGUI({control: this.#id, get: property});
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Registers, unregisters, and gets an event handler callback function for a specified events.
|
|
648
|
+
*
|
|
649
|
+
* - component.event(name, function, true); // unregisters one callback function (even if the same callback was registered multiple times)
|
|
650
|
+
* - component.event(name, function); // registers callback to be called when the event is emitted
|
|
651
|
+
* - component.event(name); // returns all callback functions for specified event
|
|
652
|
+
*
|
|
653
|
+
* @param {string} name - Name of event
|
|
654
|
+
* @param {function(Object):any|null} [callback=undefined] - Callback function. Pass `null` to unregister all handler functions.
|
|
655
|
+
* @param {boolean} [remove=false] - Set to true to unregister the callback function.
|
|
656
|
+
* @return {Function[]|this} If only the `name` argument is provided, returns an array of registered callback functions. Otherwise, returns `this` component.
|
|
657
|
+
* @internal
|
|
658
|
+
* @ignore
|
|
659
|
+
* @private
|
|
660
|
+
* @example
|
|
661
|
+
* const _callbacks_array = button.event("onAction"); // gets an array of previously registered handler functions
|
|
662
|
+
* button.event("onAction", _callbacks_array[0], true); // unregisters callback function, same as button.onAction(_callbacks_array[0], true);
|
|
663
|
+
* button.event("onAction", e => {console.debug(e);}); // registers new event handler function, same as button.onAction(e => {console.debug(e);});
|
|
664
|
+
*/
|
|
665
|
+
event(name, callback = undefined, remove = false)
|
|
666
|
+
{
|
|
667
|
+
if(this.callback === undefined) return this; // in case the component is disposed already
|
|
668
|
+
|
|
669
|
+
// return callbacks
|
|
670
|
+
if(callback === undefined) return Array.isArray(this.callback[name]) ? [...this.callback[name]] : [];
|
|
671
|
+
|
|
672
|
+
// remove callback
|
|
673
|
+
if(remove === true || callback === null) // removes one or all callbacks
|
|
674
|
+
{
|
|
675
|
+
if(!Array.isArray(this.callback[name])) return this;
|
|
676
|
+
|
|
677
|
+
if(callback === null)
|
|
678
|
+
{
|
|
679
|
+
this.callback[name].length = 0;
|
|
680
|
+
}
|
|
681
|
+
else
|
|
682
|
+
{
|
|
683
|
+
const i = this.callback[name].indexOf(callback); // find callback
|
|
684
|
+
if(i === -1) return this; // return if not found
|
|
685
|
+
this.callback[name].splice(i, 1); // remove it
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if(this.callback[name].length === 0)
|
|
689
|
+
{
|
|
690
|
+
delete this.callback[name]; // delete array
|
|
691
|
+
this.property(name, [false]); // notify GUI
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
// add callback
|
|
695
|
+
else
|
|
696
|
+
{
|
|
697
|
+
// make sure callback is function
|
|
698
|
+
if(typeof callback !== "function") throw new Error(`"callback" argument must be of type "function".`);
|
|
699
|
+
|
|
700
|
+
if(!Array.isArray(this.callback[name]))
|
|
701
|
+
{
|
|
702
|
+
this.callback[name] = []; // create array
|
|
703
|
+
this.property(name, [true]); // notify GUI
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
this.callback[name].push(callback); // add callback (don't bind to `this` here, it's done when called)
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
return this;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/**
|
|
713
|
+
* Sets or gets the background color of the component. <br />
|
|
714
|
+
* <br />
|
|
715
|
+
* Accepts three formats: <br />
|
|
716
|
+
* - RGB hex (e.g. `"#FF0000"`) <br />
|
|
717
|
+
* - RGBA hex with alpha (e.g. `"#FF000050"`) <br />
|
|
718
|
+
* - The string `"transparent"` (equivalent to `"#00000000"`)
|
|
719
|
+
*
|
|
720
|
+
* @param {string} [value] - Background color in supported formats. Panel and Window components also accept gradient, image position and other info like in CSS. If omitted, returns the current value.
|
|
721
|
+
* @param {boolean} [update] - For Panel or Window only. Specifies whether to update specified background attributes instead of replacing all previously set background attributes.
|
|
722
|
+
* @returns {this|string} Returns `this` when setting value, or the current background color string when getting.
|
|
723
|
+
*
|
|
724
|
+
* @example
|
|
725
|
+
* component.background("#FF0000"); // Red background
|
|
726
|
+
* component.background("#00FF0080"); // Semi-transparent green
|
|
727
|
+
* component.background("transparent"); // Fully transparent
|
|
728
|
+
*
|
|
729
|
+
* // For Panel and Window components the background value can be a string that contains a mixture of background color,
|
|
730
|
+
* // image, linear-gradient, radial-gradient, like in CSS in web browsers. Some features may not be supported though.
|
|
731
|
+
* panel.background("#FF000055 url(images/bg.png) center no-repeat opacity=0.6 10px 15px linear-gradient(#DDDDDD55, #F8F8F855 10%) / auto);
|
|
732
|
+
* panel.background("url(data:image/png;base64,As8fE4fdt1r.....)", true); // supports base64 encoded image string
|
|
733
|
+
*/
|
|
734
|
+
background(...args)
|
|
735
|
+
{
|
|
736
|
+
if(args.length > 1 && args[1] === true && (this instanceof Panel || this instanceof Window))
|
|
737
|
+
{
|
|
738
|
+
args[0] = {
|
|
739
|
+
value: args[0],
|
|
740
|
+
update: true
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
return this.property("background", args);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Sets or gets a foreground color of component (usually text color).
|
|
749
|
+
*
|
|
750
|
+
* @param {string} value Three formats are acceptable, regular RGB "#FF0000", with alpha RGBA "#FF000050", and "transparent" string, which is equivalent to "#00000000".
|
|
751
|
+
* @return {string|this} Returns color value if no argument is set, otherwise returns `this` component.
|
|
752
|
+
*/
|
|
753
|
+
color(...args)
|
|
754
|
+
{
|
|
755
|
+
return this.property("color", args);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Sets or gets the position of the component relative to its parent component's top-let corner (or to the screen's top-left corner when component is Window).
|
|
760
|
+
*
|
|
761
|
+
* @param {number|Point} [x_or_position] - X position. Alternatively, provide a single `Point` object parameter to specify the position.
|
|
762
|
+
* @param {number} [y] - Y position.
|
|
763
|
+
* @param {number} [right] - Resizes the component so that its right edge is this many pixels from the right edge of the parent component or screen.
|
|
764
|
+
* @param {number} [bottom] - Resizes the component so that its bottom edge is this many pixels from the bottom edge of the parent component or screen.
|
|
765
|
+
* @return {Point|this} If no arguments are provided, returns a {x: number, y: number} position object. Otherwise, returns `this` component.
|
|
766
|
+
* @see Point
|
|
767
|
+
* @example
|
|
768
|
+
* panel.size(50, 100); // sets position
|
|
769
|
+
* panel.size({x: 50, y: 100}); // sets position
|
|
770
|
+
* panel.size(50, 100, 20); // sets position of left, top and right sides relative to sides of parent component.
|
|
771
|
+
* const window = new Window("New Window").size(50, 100, 20, 20); // sets position of each side relative to sides of screen.
|
|
772
|
+
*/
|
|
773
|
+
position(...args)
|
|
774
|
+
{
|
|
775
|
+
if(args.length > 0)
|
|
776
|
+
{
|
|
777
|
+
delete this.#prop.location.right;
|
|
778
|
+
delete this.#prop.location.bottom;
|
|
779
|
+
let changed = false;
|
|
780
|
+
|
|
781
|
+
try
|
|
782
|
+
{
|
|
783
|
+
if(args[0] == null)
|
|
784
|
+
{
|
|
785
|
+
this.#prop.location = {}; // reset position to make it load from GUI on next request
|
|
786
|
+
return this;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
if(this.parent instanceof Tabs || this.parent instanceof ScrollPane) return this; // ignore position for tabs' or scroll pane's direct children
|
|
790
|
+
|
|
791
|
+
const position = (typeof args[0] === "object") ? {x: args[0].x, y: args[0].y} : {
|
|
792
|
+
x: args[0],
|
|
793
|
+
y: args[1]
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
if(Number.isFinite(position.x)) position.x = Number.parseInt(position.x);
|
|
797
|
+
if(Number.isFinite(position.y)) position.y = Number.parseInt(position.y);
|
|
798
|
+
|
|
799
|
+
if(isNaN(position.x) || isNaN(position.y)) throw new TypeError(`Invalid arguments for position():\n\n${stringify(args)}`);
|
|
800
|
+
|
|
801
|
+
// check if the size changed
|
|
802
|
+
if(position.x !== this.#prop.location.x || position.y !== this.#prop.location.y)
|
|
803
|
+
{
|
|
804
|
+
this.#prop.location = position;
|
|
805
|
+
this.property("location", [this.#prop.location]); // make sure this position is set before size is changed below
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
if(args.length > 2 && Number.isFinite(args[2])) args[2] = Number.parseInt(args[2]); // fix right
|
|
809
|
+
if(args.length > 3 && Number.isFinite(args[3])) args[3] = Number.parseInt(args[3]); // fix bottom
|
|
810
|
+
|
|
811
|
+
// resize to right edge
|
|
812
|
+
if(args.length > 2 && !isNaN(args[2]))
|
|
813
|
+
{
|
|
814
|
+
const parent = this.parent;
|
|
815
|
+
|
|
816
|
+
if(parent != null || this instanceof Window)
|
|
817
|
+
{
|
|
818
|
+
// get parent's or screen size
|
|
819
|
+
const containerSize = (parent != null) ? ((parent instanceof Window || parent instanceof InternalWindow) ? parent.innerSize() : parent.size()) : this.screenSize;
|
|
820
|
+
|
|
821
|
+
const w = containerSize.width - this.#prop.location.x - args[2];
|
|
822
|
+
|
|
823
|
+
// resize to bottom edge
|
|
824
|
+
if(args.length > 3 && !isNaN(args[3]))
|
|
825
|
+
{
|
|
826
|
+
const h = containerSize.height - this.#prop.location.y - args[3];
|
|
827
|
+
this.size(w, h);
|
|
828
|
+
}
|
|
829
|
+
else
|
|
830
|
+
{
|
|
831
|
+
this.width(w);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
else
|
|
835
|
+
{
|
|
836
|
+
// save for later to be applied when component gets added to a parent
|
|
837
|
+
this.#prop.size.right = args[2];
|
|
838
|
+
if(args.length > 3 && !isNaN(args[3])) this.#prop.size.bottom = args[3];
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
}catch(ex)
|
|
842
|
+
{
|
|
843
|
+
throw new TypeError(ex.message + ".\n\nArguments must be one of following:\n position(number x, number y)\n position(number x, number y, number right, number bottom)\n position(number x, number y, number right)\n position({x: number, y: number})\n");
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
return this;
|
|
847
|
+
}
|
|
848
|
+
else
|
|
849
|
+
{
|
|
850
|
+
this.verifyComponent();
|
|
851
|
+
|
|
852
|
+
// if location isn't known, retrieve it from GUI
|
|
853
|
+
if(!("x" in this.#prop.location || "y" in this.#prop.location))
|
|
854
|
+
{
|
|
855
|
+
({x: this.#prop.location.x, y: this.#prop.location.y} = this.property("location", []));
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
return {...this.#prop.location};
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* Convenience method to set or get left position of component.
|
|
864
|
+
*
|
|
865
|
+
* @param {number} [value]
|
|
866
|
+
* @return {number} Returns left position if no argument is set, otherwise returns `this` component.
|
|
867
|
+
* @see UIComponent#position
|
|
868
|
+
*/
|
|
869
|
+
x(...args)
|
|
870
|
+
{
|
|
871
|
+
if(args.length > 0)
|
|
872
|
+
{
|
|
873
|
+
if(Number.isFinite(args[0])) args[0] = Number.parseInt(args[0]);
|
|
874
|
+
if(this.parent instanceof Tabs) return this; // can't set position for tabs direct children
|
|
875
|
+
if(isNaN(args[0])) throw new TypeError(`Invalid argument type for x(). Argument is '${args[0]}' of type '${typeof args[0]}'. Must be a number.`);
|
|
876
|
+
|
|
877
|
+
delete this.#prop.location.right; // in case it was set
|
|
878
|
+
if(this.#prop.location.x !== args[0]) // check if changed
|
|
879
|
+
{
|
|
880
|
+
this.#prop.location.x = args[0];
|
|
881
|
+
return this.property("location", [this.#prop.location]);
|
|
882
|
+
}
|
|
883
|
+
return this;
|
|
884
|
+
}
|
|
885
|
+
else
|
|
886
|
+
{
|
|
887
|
+
this.verifyComponent();
|
|
888
|
+
return this.#prop.location.x;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Convenience method to set or get top position of component.
|
|
894
|
+
*
|
|
895
|
+
* @param {number} [value]
|
|
896
|
+
* @return {number} Returns top position if no argument is set, otherwise returns `this` component.
|
|
897
|
+
* @see UIComponent#position
|
|
898
|
+
*/
|
|
899
|
+
y(...args)
|
|
900
|
+
{
|
|
901
|
+
if(args.length > 0)
|
|
902
|
+
{
|
|
903
|
+
if(Number.isFinite(args[0])) args[0] = Number.parseInt(args[0]);
|
|
904
|
+
if(this.parent instanceof Tabs) return this; // can't set position for tabs direct children
|
|
905
|
+
if(isNaN(args[0])) throw new TypeError(`Invalid argument type for y(). Argument is '${args[0]}' of type '${typeof args[0]}'. Must be a number.`);
|
|
906
|
+
|
|
907
|
+
delete this.#prop.location.bottom; // in case it was set
|
|
908
|
+
args[0] = parseInt(args[0]);
|
|
909
|
+
if(this.#prop.location.y !== args[0]) // check if changed
|
|
910
|
+
{
|
|
911
|
+
this.#prop.location.y = args[0];
|
|
912
|
+
return this.property("location", [this.#prop.location]);
|
|
913
|
+
}
|
|
914
|
+
return this;
|
|
915
|
+
}
|
|
916
|
+
else
|
|
917
|
+
{
|
|
918
|
+
this.verifyComponent();
|
|
919
|
+
return this.#prop.location.y;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
/**
|
|
924
|
+
* Convenience method to get or set the distance between the right edge of this component and the right edge of its parent.
|
|
925
|
+
*
|
|
926
|
+
* @param {number} [value] - Distance from the parent's right edge.
|
|
927
|
+
* @param {boolean} [reize] - `True` to resize the width to accommodate for specified `right` position instead of moving the object. `false` to move the component.
|
|
928
|
+
* @return {number|this} Returns the current right distance if no argument is provided; otherwise, returns `this` component.
|
|
929
|
+
*/
|
|
930
|
+
right(...args)
|
|
931
|
+
{
|
|
932
|
+
const parent = this.parent;
|
|
933
|
+
|
|
934
|
+
if(args.length > 0)
|
|
935
|
+
{
|
|
936
|
+
if(Number.isFinite(args[0])) args[0] = Number.parseInt(args[0]);
|
|
937
|
+
|
|
938
|
+
if(isNaN(args[0])) throw new Error(`Invalid argument for right() method. Argument is '${args[0]}' of type '${typeof args[0]}'. Must be a number.`);
|
|
939
|
+
|
|
940
|
+
if(parent !== null)
|
|
941
|
+
{
|
|
942
|
+
if(parent instanceof Window || parent instanceof InternalWindow)
|
|
943
|
+
{
|
|
944
|
+
if(args[1] === true)
|
|
945
|
+
{
|
|
946
|
+
this.width(Math.max(0, this.parent.innerSize().width - this.x() - args[0]));
|
|
947
|
+
}
|
|
948
|
+
else
|
|
949
|
+
{
|
|
950
|
+
this.x(this.parent.innerSize().width - this.width() - args[0]);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
else
|
|
954
|
+
{
|
|
955
|
+
if(args[1] === true)
|
|
956
|
+
{
|
|
957
|
+
this.width(Math.max(0, this.parent.width() - this.x() - args[0]));
|
|
958
|
+
}
|
|
959
|
+
else
|
|
960
|
+
{
|
|
961
|
+
this.x(this.parent.width() - this.width() - args[0]);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
else
|
|
966
|
+
{
|
|
967
|
+
if(args[1] !== true) this.#prop.location.right = args[0]; // set to be applied when added to component
|
|
968
|
+
}
|
|
969
|
+
return this;
|
|
970
|
+
}
|
|
971
|
+
else
|
|
972
|
+
{
|
|
973
|
+
if(parent === null) return NaN;
|
|
974
|
+
|
|
975
|
+
if(parent instanceof Window || parent instanceof InternalWindow)
|
|
976
|
+
{
|
|
977
|
+
return this.parent.innerSize().width - (this.x() + this.width()); // calculate
|
|
978
|
+
}
|
|
979
|
+
else
|
|
980
|
+
{
|
|
981
|
+
return this.parent.width() - (this.x() + this.width()); // calculate
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
* Convenience method to get or set the distance between the bottom edge of this component and the bottom edge of its parent.
|
|
988
|
+
*
|
|
989
|
+
* @param {number} [value] - Distance from the parent's bottom edge to this component's bottom edge.
|
|
990
|
+
* @param {boolean} [reize] - `True` to resize the height to accommodate for specified `bottom` position instead of moving the object. `false` to move the component.
|
|
991
|
+
* @return {number|this} Returns the current bottom distance if no argument is provided; otherwise, returns `this` component.
|
|
992
|
+
*/
|
|
993
|
+
bottom(...args)
|
|
994
|
+
{
|
|
995
|
+
if(args.length > 0)
|
|
996
|
+
{
|
|
997
|
+
if(Number.isFinite(args[0])) args[0] = Number.parseInt(args[0]);
|
|
998
|
+
|
|
999
|
+
if(isNaN(args[0])) throw new Error(`Invalid argument for bottom() function. Argument is '${args[0]}' of type '${typeof args[0]}'. Must be a number.`);
|
|
1000
|
+
|
|
1001
|
+
if(this.parent !== null)
|
|
1002
|
+
{
|
|
1003
|
+
if(this.parent instanceof Window || this.parent instanceof InternalWindow)
|
|
1004
|
+
{
|
|
1005
|
+
if(args[1] === true)
|
|
1006
|
+
{
|
|
1007
|
+
this.height(Math.max(0, this.parent.innerSize().height - this.y() - args[0]));
|
|
1008
|
+
}
|
|
1009
|
+
else
|
|
1010
|
+
{
|
|
1011
|
+
this.y(this.parent.innerSize().height - this.height() - args[0]);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
else
|
|
1015
|
+
{
|
|
1016
|
+
if(args[1] === true)
|
|
1017
|
+
{
|
|
1018
|
+
this.height(Math.max(0, this.parent.height() - this.y() - args[0]));
|
|
1019
|
+
}
|
|
1020
|
+
else
|
|
1021
|
+
{
|
|
1022
|
+
this.y(this.parent.height() - this.height() - args[0]);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
else
|
|
1027
|
+
{
|
|
1028
|
+
if(args[1] !== true) this.#prop.location.bottom = args[0]; // set to be applied when added to component
|
|
1029
|
+
}
|
|
1030
|
+
return this;
|
|
1031
|
+
}
|
|
1032
|
+
else
|
|
1033
|
+
{
|
|
1034
|
+
if(this.parent === null) return NaN;
|
|
1035
|
+
|
|
1036
|
+
if(this.parent instanceof Window || this.parent instanceof InternalWindow)
|
|
1037
|
+
{
|
|
1038
|
+
return this.parent.innerSize().height - (this.y() + this.height()); // calculate
|
|
1039
|
+
}
|
|
1040
|
+
else
|
|
1041
|
+
{
|
|
1042
|
+
return this.parent.height() - (this.y() + this.height()); // calculate
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
/**
|
|
1048
|
+
* Moves the component by adding the specified x and y values to its current position.
|
|
1049
|
+
* The function shifts the element's position relative to current position.
|
|
1050
|
+
*
|
|
1051
|
+
* @param {number} [dx=0] - Delta x (can be positive or negative number)
|
|
1052
|
+
* @param {number} [dy=0] - Delta y (can be positive or negative number)
|
|
1053
|
+
* @return {this} Returns `this` component.
|
|
1054
|
+
*/
|
|
1055
|
+
move(dx = 0, dy = 0)
|
|
1056
|
+
{
|
|
1057
|
+
if(Number.isFinite(dx)) dx = Number.parseInt(dx);
|
|
1058
|
+
if(Number.isFinite(dy)) dy = Number.parseInt(dy);
|
|
1059
|
+
|
|
1060
|
+
if((!isNaN(dx) && !isNaN(dy)) && !(dx === 0 && dy === 0))
|
|
1061
|
+
{
|
|
1062
|
+
const _args = [];
|
|
1063
|
+
const p = this.#prop.location;
|
|
1064
|
+
_args.push(p.x + dx);
|
|
1065
|
+
_args.push(p.y + dy);
|
|
1066
|
+
|
|
1067
|
+
// update possible `right` and `bottom` in location
|
|
1068
|
+
if("right" in p) _args.push(p.right - dx);
|
|
1069
|
+
if("bottom" in p) _args.push(p.bottom - dy);
|
|
1070
|
+
|
|
1071
|
+
return this.position.apply(this, _args);
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
return this;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
/**
|
|
1078
|
+
* When called without arguments and repainting is not disabled, it flushes message queue, revalidates and repaints the component.
|
|
1079
|
+
* When the first argument is `true`, it enables repainting (enabled by default) and flushes the message queue.
|
|
1080
|
+
* When the first argument is `false`, it disables repainting.
|
|
1081
|
+
*
|
|
1082
|
+
* @param {boolean} repaint_enabled - `false` to pause repainting this element. `true` to resume repainting
|
|
1083
|
+
* @return {this} Returns `this` component.
|
|
1084
|
+
*/
|
|
1085
|
+
update(...args)
|
|
1086
|
+
{
|
|
1087
|
+
if(args.length === 0)
|
|
1088
|
+
{
|
|
1089
|
+
if(this.#prop.update !== false)
|
|
1090
|
+
{
|
|
1091
|
+
ui.sendToGUI({control: this.#id, set: "update", value: true});
|
|
1092
|
+
ui.sendMessageQueue();
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
else if((args[0] === true) !== (this.#prop.update !== false))
|
|
1096
|
+
{
|
|
1097
|
+
this.#prop.update = (args[0] === true);
|
|
1098
|
+
ui.sendToGUI({control: this.#id, set: "update", value: this.#prop.update});
|
|
1099
|
+
ui.sendMessageQueue();
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
return this;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
/**
|
|
1106
|
+
* Sets or gets context menu component for this UI component.
|
|
1107
|
+
*
|
|
1108
|
+
* @param {ContextMenu} [menu] - ContextMenu component to be assigned to this component. Set to `null` to remove ContextMenu.
|
|
1109
|
+
* @return {ContextMenu|null|this} Returns the current context menu if no argument is provided; otherwise, returns `this` component.
|
|
1110
|
+
*/
|
|
1111
|
+
contextMenu(...args)
|
|
1112
|
+
{
|
|
1113
|
+
if(args.length === 0) return this.#context_menu;
|
|
1114
|
+
|
|
1115
|
+
let menu = args[0];
|
|
1116
|
+
|
|
1117
|
+
if(menu === null) // remove context menu
|
|
1118
|
+
{
|
|
1119
|
+
if(this.#context_menu != null && typeof this.#context_menu === "object" && this.#context_menu instanceof globalThis.ContextMenu && this.#context_menu.destroyed !== true)
|
|
1120
|
+
{
|
|
1121
|
+
let i = this.#context_menu._parents.indexOf(this);
|
|
1122
|
+
|
|
1123
|
+
if(i > -1)
|
|
1124
|
+
{
|
|
1125
|
+
this.#context_menu._parents.splice(i, 1);
|
|
1126
|
+
ui.sendToGUI({control: this.#context_menu.id, set: "removeFrom", value: this.#id});
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
this.#context_menu = null;
|
|
1131
|
+
}
|
|
1132
|
+
else // add context menu
|
|
1133
|
+
{
|
|
1134
|
+
if(this === menu || typeof menu !== "object" || !(menu instanceof globalThis.ContextMenu)) // can't use !(menu instanceof ContextMenu) because ContextMenu imports this class, thus would create circular import.
|
|
1135
|
+
{
|
|
1136
|
+
throw new Error(ui._msg[10]);
|
|
1137
|
+
return this;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
if(this.#context_menu != null) this.contextMenu(null); // remove existing menu before setting a new one
|
|
1141
|
+
|
|
1142
|
+
this.#context_menu = menu;
|
|
1143
|
+
menu._parents.push(this);
|
|
1144
|
+
|
|
1145
|
+
const resp = ui.sendToGUI({control: menu.id, get: "parent", data: {parent: this.#id}});
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
return this;
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/**
|
|
1152
|
+
* Sets or gets component `focusable` property whether component can retain focus.
|
|
1153
|
+
*
|
|
1154
|
+
* @param {boolean} [value]
|
|
1155
|
+
* @return {boolean|this} If called with an argument, then `this` component instance is returned, otherwise `boolean` value is returned.
|
|
1156
|
+
*/
|
|
1157
|
+
focusable(...args)
|
|
1158
|
+
{
|
|
1159
|
+
return this.property("focusable", args);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* If value is passed, it makes component to get or loose focus, otherwise returns `boolean` indicating if it has focus or not.
|
|
1164
|
+
*
|
|
1165
|
+
* @param {boolean} [value] - `true` to get focus, `false` to attempt to shift focus to next component (if it has focus), usually by switching focus to next component.
|
|
1166
|
+
* @returns {boolean|this} If called with an argument, then `this` component instance is returned, otherwise `boolean` value is returned.
|
|
1167
|
+
*/
|
|
1168
|
+
focused(...args)
|
|
1169
|
+
{
|
|
1170
|
+
return this.property("focused", args);
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
/**
|
|
1174
|
+
* Sets or gets an index (z-order) of this component if it is added to a container, otherwise returns null.
|
|
1175
|
+
* Larger value brings component forward, smaller to the back, like z-index in CSS.
|
|
1176
|
+
*
|
|
1177
|
+
* @param {number} [index]
|
|
1178
|
+
* @returns {this|null|number} If called with an argument, then `this` component instance is returned, if component has no parent then `null` is returned, otherwise index is returned.
|
|
1179
|
+
*/
|
|
1180
|
+
index(...args)
|
|
1181
|
+
{
|
|
1182
|
+
if(this.parent == null) return args.length === 0 ? null : this; // if no parent
|
|
1183
|
+
|
|
1184
|
+
return this.parent.childIndex(this, ...args);
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
/**
|
|
1188
|
+
* Sets or gets a layer at which this component resides in Panel container. This is separate from z-index.
|
|
1189
|
+
* This applies only to components that are added to Panel or Window components.
|
|
1190
|
+
* For example components in layer 2 are always on top of components in layer 1, regardless on their z-index.
|
|
1191
|
+
* Larger value brings component forward, smaller to the back, like width z-index.
|
|
1192
|
+
*
|
|
1193
|
+
* @param {number} layer_index
|
|
1194
|
+
* @returns {number|this} If called with an argument, then `this` component instance is returned, otherwise `number` value is returned.
|
|
1195
|
+
*/
|
|
1196
|
+
layer(...args)
|
|
1197
|
+
{
|
|
1198
|
+
if(args.length > 0) args[0] = Math.max(0, parseInt(args[0]));
|
|
1199
|
+
return this.property("layer", args);
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
/**
|
|
1203
|
+
* Gets or sets the font used for the component's text. See the example for font object format.
|
|
1204
|
+
*
|
|
1205
|
+
* @param {Font} [font] - Font formatted object.
|
|
1206
|
+
* @param {boolean} [update] - If `true`, only the specified font properties will be updated instead of replacing the entire font.
|
|
1207
|
+
* @return {this|Font}
|
|
1208
|
+
* @see Font
|
|
1209
|
+
* @example <h2>Full list of supported font properties:</h2>
|
|
1210
|
+
* Font {
|
|
1211
|
+
* name: string, // Font name or family name from {@link FontFamily} enum (e.g., "sans-serif")
|
|
1212
|
+
* size: number, // Font size in pixels
|
|
1213
|
+
* bold: boolean, // Whether the text is bold
|
|
1214
|
+
* italic: boolean, // Whether the text is italic
|
|
1215
|
+
* underlined: boolean, // Whether the text is underlined
|
|
1216
|
+
* strikethrough: boolean, // Whether the text has a strikethrough
|
|
1217
|
+
* direction: string, // Text direction: "ltr" or "rtl"
|
|
1218
|
+
* kerning: boolean, // Enable or disable kerning
|
|
1219
|
+
* ligatures: boolean, // Enable or disable font ligatures
|
|
1220
|
+
* tracking: number // Letter spacing adjustment: -1, 0 (default), or 1
|
|
1221
|
+
* };
|
|
1222
|
+
* @example <h2>Usage examples:</h2>
|
|
1223
|
+
* // Sets new font
|
|
1224
|
+
* textarea.font({name: "sans-serif", size: 14, italic: true});
|
|
1225
|
+
*
|
|
1226
|
+
* // Set a new font; previously set italic style will be removed
|
|
1227
|
+
* textarea.font({name: "sans-serif", size: 14});
|
|
1228
|
+
*
|
|
1229
|
+
* // Update only the font size, preserving other properties
|
|
1230
|
+
* textarea.font({size: 20}, true);
|
|
1231
|
+
*
|
|
1232
|
+
* // get component's font
|
|
1233
|
+
* const font = textarea.font();
|
|
1234
|
+
* @see Font
|
|
1235
|
+
* @see FontFamily
|
|
1236
|
+
*/
|
|
1237
|
+
font(...args)
|
|
1238
|
+
{
|
|
1239
|
+
if(args.length > 0)
|
|
1240
|
+
{
|
|
1241
|
+
if(typeof args[0] !== "object") throw new Error("Font argument must be an Object");
|
|
1242
|
+
const msg = {control: this.id, set: "font", value: args[0]};
|
|
1243
|
+
if(args[1] === true) msg.update = true;
|
|
1244
|
+
ui.sendToGUI(msg);
|
|
1245
|
+
return this;
|
|
1246
|
+
}
|
|
1247
|
+
else
|
|
1248
|
+
{
|
|
1249
|
+
return this.property("font", []);
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
/**
|
|
1254
|
+
* Sets or gets an icon image of this component. You can set icon to any component even though not all components display the icon.
|
|
1255
|
+
* When a component is added to Tabs, that component's icon is used as a Tab icon by default.
|
|
1256
|
+
* Following image types are supported: ICO, PNG, JPG, JPEG, GIF, BMP, WBMP, TIFF/TIF, and base64 encoded images of such types.
|
|
1257
|
+
* If FFMPEG with support of these image types is installed, the following image types are also supported from local relative or absolute paths: WEBP, HEIC, HEIF, AVIF.
|
|
1258
|
+
*
|
|
1259
|
+
* @param {string|null} image_path - Relative or absolute path to image file, base64 encoded image string, or NULL to remove existing icon.
|
|
1260
|
+
* @returns {this|string|null} Returns `this` component if no arguments are set, a string of a previously set icon, or `null` if icon hasn't been set.
|
|
1261
|
+
*/
|
|
1262
|
+
icon(...args)
|
|
1263
|
+
{
|
|
1264
|
+
return this.property("icon", args);
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
/**
|
|
1268
|
+
* Sets an cursor to the control. Passing NULL value removes custom cursor.
|
|
1269
|
+
*
|
|
1270
|
+
* @param {number|null|string} cursor - A value from Cursor enum, or a relative path to image file for custom cursor icon.
|
|
1271
|
+
* @param {number} x - Used with custom image cursor to set pointer point on the image.
|
|
1272
|
+
* @param {number} y - Used with custom image cursor to set pointer point on the image.
|
|
1273
|
+
* @returns {this} Returns `this` component.
|
|
1274
|
+
*/
|
|
1275
|
+
cursor(cursor, ...point)
|
|
1276
|
+
{
|
|
1277
|
+
const msg = {control: this.#id, set: "cursor", value: cursor};
|
|
1278
|
+
|
|
1279
|
+
if(point.length > 1)
|
|
1280
|
+
{
|
|
1281
|
+
msg.x = parseInt(point[0]);
|
|
1282
|
+
msg.y = parseInt(point[1]);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
ui.sendToGUI(msg);
|
|
1286
|
+
return this;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
/**
|
|
1290
|
+
* Sets or gets the drag action for this component (e.g., `Copy`, `Move`), and enables or disables dragging accordingly.
|
|
1291
|
+
* Passing `None` disables dragging; all other values enable it.
|
|
1292
|
+
*
|
|
1293
|
+
* @param {DragDropAction} [action] - One of enum values: DragDropAction.[None|Copy|Move|CopyOrMove|Link]. `None` is default.
|
|
1294
|
+
* @returns {string|this} Returns `this` component if argument is provided, otherwise returns `string` value as one of the DragDropAction enum values.
|
|
1295
|
+
*/
|
|
1296
|
+
dragAction(...args)
|
|
1297
|
+
{
|
|
1298
|
+
if(args.length > 0)
|
|
1299
|
+
{
|
|
1300
|
+
if(!DragDropAction.hasOwnProperty(args[0])) return this; // validate argument
|
|
1301
|
+
this.#prop.dragAction = args[0];
|
|
1302
|
+
}
|
|
1303
|
+
return this.property("dragAction", args);
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
/**
|
|
1307
|
+
* Sets or gets which type of drop action is accepted by the component (e.g., `Copy`, `Move`). Setting any action other
|
|
1308
|
+
* than `None` enables dropping on the component. Action `None` disables dropping.
|
|
1309
|
+
*
|
|
1310
|
+
* @param {DragDropAction} [action] - One of enum values: DragDropAction.[None|Copy|Move|CopyOrMove|Link]. `None` is default.
|
|
1311
|
+
* @returns {string|this} Returns `this` component if argument is provided, otherwise returns `string` value as one of the DragDropAction enum values.
|
|
1312
|
+
*/
|
|
1313
|
+
dropAction(...args)
|
|
1314
|
+
{
|
|
1315
|
+
if(args.length > 0)
|
|
1316
|
+
{
|
|
1317
|
+
if(!DragDropAction.hasOwnProperty(args[0])) return this; // validate argument
|
|
1318
|
+
this.#prop.dropAction = args[0];
|
|
1319
|
+
}
|
|
1320
|
+
return this.property("dropAction", args);
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
/**
|
|
1324
|
+
* Sets or gets the types of data that should be transffered during drag operation. The data itself can be set using dragData(...) method.
|
|
1325
|
+
* More than one type can be specified by setting multiple arguments or passing an array of values.
|
|
1326
|
+
*
|
|
1327
|
+
* @param {...DataType|DataType[]} data_type - DataType.[None|Text|Image|...]
|
|
1328
|
+
* @returns {string[]|this}
|
|
1329
|
+
* @example
|
|
1330
|
+
* // Usage examples:
|
|
1331
|
+
* label.dragDataType(DataType.Text, DataType.HTML); // setting by multiple arguments
|
|
1332
|
+
* label.dragDataType([DataType.Text, DataType.HTML]); // setting by an array of values
|
|
1333
|
+
* const _types = label.dragDataType(); // getting an array of data types
|
|
1334
|
+
*/
|
|
1335
|
+
dragDataType(...args)
|
|
1336
|
+
{
|
|
1337
|
+
if(Array.isArray(args[0])) args = args[0];
|
|
1338
|
+
let _args = [];
|
|
1339
|
+
for(let v of args) if(DataType.hasOwnProperty(v) && _args.indexOf(v) === -1) _args.push(v); // validate argument and remove duplicates
|
|
1340
|
+
|
|
1341
|
+
return this.property("dragDataType", _args.length > 0 ? [_args] : []);
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
/**
|
|
1345
|
+
* Sets custom data that should be passed when dragging this component instead of passing component's data, such as text or icon.
|
|
1346
|
+
* Without setting this data a default component data will be dragged, such as text, list item, icon, what what ever applies to this component.
|
|
1347
|
+
*
|
|
1348
|
+
* @arg {string|string[]} data - String data or array of strings. For a list of files or URLs use array or separate them by new line character \n.
|
|
1349
|
+
* @return {this} Returns `this` component.
|
|
1350
|
+
*/
|
|
1351
|
+
dragData(...args)
|
|
1352
|
+
{
|
|
1353
|
+
if(args.length === 0) return this.property("dragDataType", []);
|
|
1354
|
+
|
|
1355
|
+
if(Array.isArray(args[0])) args = args[0];
|
|
1356
|
+
let _args = [];
|
|
1357
|
+
for(let v of args)
|
|
1358
|
+
{
|
|
1359
|
+
if(!(typeof v === "string")) continue;
|
|
1360
|
+
if((DataType.hasOwnProperty(v) || v.startsWith("component/")) && _args.indexOf(v) === -1) _args.push(v);// validate argument and remove duplicates
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
return this.property("dragDataType", [_args]);
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
/**
|
|
1367
|
+
* Sets acceptable data types that may be dropped on this component during drag and drop operation.
|
|
1368
|
+
*
|
|
1369
|
+
* @param {...DataType|DataType[]} data_type - DataType.[None|All|Text|Image|...]. Use `All` to accept all data types.
|
|
1370
|
+
* @return {string[]|this} Returns `this` component is argument is provided, otherwise returns `string[]` value.
|
|
1371
|
+
* @example
|
|
1372
|
+
* // Usage examples:
|
|
1373
|
+
* label.dropDataType(DataType.All); // Setting to accept all data types
|
|
1374
|
+
* label.dropDataType(.DataType.Text, DataType.HTML); // setting by multiple arguments
|
|
1375
|
+
* label.dropDataType([DataType.Text, DataType.HTML]); // setting by an array of values
|
|
1376
|
+
* const _types = label.dropDataType(); // getting an array of data types
|
|
1377
|
+
*/
|
|
1378
|
+
dropDataType(...args)
|
|
1379
|
+
{
|
|
1380
|
+
if(args.length === 0) return this.property("dropDataType", []);
|
|
1381
|
+
|
|
1382
|
+
if(Array.isArray(args[0])) args = args[0];
|
|
1383
|
+
let _args = [];
|
|
1384
|
+
for(let v of args)
|
|
1385
|
+
{
|
|
1386
|
+
if(!(typeof v === "string")) continue;
|
|
1387
|
+
if((DataType.hasOwnProperty(v) || v.startsWith("component/")) && _args.indexOf(v) === -1) _args.push(v);// validate argument and remove duplicates
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
return this.property("dropDataType", [_args]);
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
/**
|
|
1394
|
+
* Sets a drop mode for components: Table, List, Tree.
|
|
1395
|
+
*
|
|
1396
|
+
* @param {DropMode} [mode] - Enum value: DropMode.[On|Insert|OnOrInsert]. On - allows data to be dropped on list items. Insert - allows to drop data between list items.
|
|
1397
|
+
* @returns {DropMode|this} Returns `this` component if an argument is provided; otherwise, returns the current drop mode as one of the DropMode enum values.
|
|
1398
|
+
* @see DropMode
|
|
1399
|
+
*/
|
|
1400
|
+
dropMode(...args)
|
|
1401
|
+
{
|
|
1402
|
+
if(args.length > 0) args[0] = String(args[0]);
|
|
1403
|
+
return this.property("dropMode", args);
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
/**
|
|
1407
|
+
* Sets, updates, or gets component border object. Border object should contain only properties that you want to set or update.
|
|
1408
|
+
*
|
|
1409
|
+
* @param {Border} [border] - Border object.
|
|
1410
|
+
* @param {boolean} [update] - Set to `true` to only change specified border properties instead of replacing existing border.
|
|
1411
|
+
* @return {this|Border|null} - If called without arguments a `Border` object is returned or `null` if the component's border wasn't set. Otherwise and instance of the component is returned.
|
|
1412
|
+
* @see UIComponent#border
|
|
1413
|
+
*/
|
|
1414
|
+
border(...args)
|
|
1415
|
+
{
|
|
1416
|
+
if(args.length > 0)
|
|
1417
|
+
{
|
|
1418
|
+
if(typeof args[0] !== "object") throw new Error("Border argument must be an Object");
|
|
1419
|
+
const msg = {control: this.id, set: "border", value: args[0]};
|
|
1420
|
+
if(args[1] === true) msg.update = true;
|
|
1421
|
+
ui.sendToGUI(msg);
|
|
1422
|
+
return this;
|
|
1423
|
+
}
|
|
1424
|
+
else
|
|
1425
|
+
{
|
|
1426
|
+
return this.property("border", []);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
/**
|
|
1431
|
+
* Sets or gets an alignment of icon relative to text of a Label, Button, or items of a List.
|
|
1432
|
+
*
|
|
1433
|
+
* @param {string} [alignment] - A combination of one or more words: "top right bottom left center leading trailing"
|
|
1434
|
+
* @return {this|string} Returns `this` component if an argument is provided, otherwise returns `string` value.
|
|
1435
|
+
*/
|
|
1436
|
+
iconAlignment(...args)
|
|
1437
|
+
{
|
|
1438
|
+
return this.property("iconAlignment", args);
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
/**
|
|
1442
|
+
* Sets or gets an alignment of the component's content relative to the component, such as Label, Button, CheckBox, RadioBox, or items of a List.
|
|
1443
|
+
*
|
|
1444
|
+
* @param {string} [alignment] - A combination of one or more words: "top bottom right left center leading trailing"
|
|
1445
|
+
* @return {this|string} Returns `this` component if an argument is provided, otherwise returns `string` value.
|
|
1446
|
+
*/
|
|
1447
|
+
alignment()
|
|
1448
|
+
{
|
|
1449
|
+
return this.property("alignment", arguments);
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/**
|
|
1453
|
+
* Sets or get a gap in pixel between icon and text of a List item, Button, Label, ComboBox, CheckBox, and RadioBox.
|
|
1454
|
+
*
|
|
1455
|
+
* @param {number} [gap] - The gap in pixels (must be an integer ≥ 0). If omitted, returns the current gap.
|
|
1456
|
+
* @return {this|number} Returns `number` if argument is omitted, otherwise returns `this` component instance.
|
|
1457
|
+
*/
|
|
1458
|
+
iconTextGap(...args)
|
|
1459
|
+
{
|
|
1460
|
+
return this.property("iconTextGap", args);
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
/**
|
|
1464
|
+
* Captures an image of the component and all subcomponents. Returns the image as a base 64 encoded string in format "data:image/FORMAT;base64,As8fE4fdt1r.....".
|
|
1465
|
+
*
|
|
1466
|
+
* @param {string} [format="png"] - Image format: `png`, `jpg`, `jpeg`, `bmp`, `gif`.
|
|
1467
|
+
* @param {Object} [crop] - Object that holds position and size of the cropped area. Format: {x: number, y: number, width: number, height: number}.
|
|
1468
|
+
* @return {string} Returns base 64 encoded string representation of the image. To get its binary data you must extract the base 64 string, then decode it from base 64 to bytes.
|
|
1469
|
+
*/
|
|
1470
|
+
snapshot(format = "png", crop = null)
|
|
1471
|
+
{
|
|
1472
|
+
return ui.sendToGUI({control: this.#id, get: "snapshot", data: {format: format.toUpperCase(), crop: crop}});
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
/**
|
|
1476
|
+
* Sets or gets the anchor style of the component that indicates how to resize this component based on the resizing parent component.
|
|
1477
|
+
* Anchor defines which sides (top, right, bottom, left) of the component stay attached to the parent's edge when parent gets resized.
|
|
1478
|
+
* Set anchors after the component and its ancestors are added to a container to ensure expected behaviour.
|
|
1479
|
+
*
|
|
1480
|
+
* @param {string} [anchors] - Space-separated list of sides to anchor (e.g., `"top left"`). If omitted, returns the current anchor value.
|
|
1481
|
+
* @returns {this|string} Returns `this` component when setting, or the current anchor `string` when getting value.
|
|
1482
|
+
* @example
|
|
1483
|
+
* const txt1 = new TextArea().anchor("top left right"); // Horizontally resizable
|
|
1484
|
+
* const txt2 = new TextArea().anchor("top left bottom"); // Vertically resizable
|
|
1485
|
+
*/
|
|
1486
|
+
anchor(...args)
|
|
1487
|
+
{
|
|
1488
|
+
if(args.length > 0 && typeof args[0] !== "string") return this; // enforce string
|
|
1489
|
+
return this.property("anchor", args);
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
/**
|
|
1493
|
+
* Sets or gets tooltip text for the component. It's the text that pops up when cursor hovers the component.
|
|
1494
|
+
*
|
|
1495
|
+
* @param {string} text - Can be plain text or HTML. HTML string should be surrounded with HTML tags. See example.
|
|
1496
|
+
* @return {string|this} Returns `this` component if argument is set, otherwise returns `string` value.
|
|
1497
|
+
* @example
|
|
1498
|
+
* button.tooltip("<html>This is line 1<br />This is line 2</html>"); // Setting HTML string with 2 lines of text
|
|
1499
|
+
*/
|
|
1500
|
+
tooltip(...args)
|
|
1501
|
+
{
|
|
1502
|
+
return this.property("tooltip", args);
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
/**
|
|
1506
|
+
* Indicates the minimum size the component can be resized to.
|
|
1507
|
+
*
|
|
1508
|
+
* @param {number|Size} width_or_size - Minimum width, or a Size formatted object as a sole parameter.
|
|
1509
|
+
* @param {number} height - Minimum height of the component.
|
|
1510
|
+
* @returns {Size|this|null} If called without parameters, current minimum Size is returned or `null` if it wasn't previously set; otherwise returns `this` component instance for chaining.
|
|
1511
|
+
* @see Size
|
|
1512
|
+
*/
|
|
1513
|
+
minSize(...args)
|
|
1514
|
+
{
|
|
1515
|
+
if(args.length > 1) // convert (width, height) params to object
|
|
1516
|
+
{
|
|
1517
|
+
args = [{width: parseInt(args[0]), height: parseInt(args[1])}];
|
|
1518
|
+
}
|
|
1519
|
+
else if(args.length === 1 && typeof args[0] !== "object") // if only 1 arg and it's not an object, then ignore
|
|
1520
|
+
{
|
|
1521
|
+
return this;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
return this.property("minSize", args);
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
/**
|
|
1528
|
+
* Indicates the maximum size the component can be resized to.
|
|
1529
|
+
*
|
|
1530
|
+
* @param {number|Size} width_or_size - Maximum width, or a Size formatted object as a sole parameter.
|
|
1531
|
+
* @param {number} height - Maximum height of the component.
|
|
1532
|
+
* @returns {Size|this|null} If called without parameters, current maximum Size is returned or `null` if it wasn't previously set; otherwise returns `this` component instance for chaining.
|
|
1533
|
+
* @see Size
|
|
1534
|
+
*/
|
|
1535
|
+
maxSize(...args)
|
|
1536
|
+
{
|
|
1537
|
+
if(args.length > 1) // convert (width, height) params to object
|
|
1538
|
+
{
|
|
1539
|
+
args = [{width: parseInt(args[0]), height: parseInt(args[1])}];
|
|
1540
|
+
}
|
|
1541
|
+
else if(args.length > 0 && typeof args[0] !== "object") // if only 1 arg and it's not an object, then ignore
|
|
1542
|
+
{
|
|
1543
|
+
return this;
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
return this.property("maxSize", args);
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
/**
|
|
1550
|
+
* Positions the component in the center of it's parent component, owner Window (if Window has an owner Window), or screen (Window only).
|
|
1551
|
+
* Applies only to components that have position() property (not like menu, menu item, tray icon, etc.)
|
|
1552
|
+
*
|
|
1553
|
+
* @arg {Object} [component] - If provided, `this` component will be positioned in the center of the provided component.
|
|
1554
|
+
* @return {this} Returns `this` component.
|
|
1555
|
+
*/
|
|
1556
|
+
center(component = null)
|
|
1557
|
+
{
|
|
1558
|
+
let parentSize = null;
|
|
1559
|
+
let offset = {x: 0, y: 0};
|
|
1560
|
+
|
|
1561
|
+
if(component !== null) // if relative component was specified
|
|
1562
|
+
{
|
|
1563
|
+
if(!(component instanceof UIComponent)) throw new Error(`"component" argument must be of type derived from UIComponent that have size and position properties.`);
|
|
1564
|
+
if(this === component) throw new Error(`"component" should not be same object as you are trying to center.`);
|
|
1565
|
+
|
|
1566
|
+
parentSize = component.size();
|
|
1567
|
+
if(component !== this.parent) offset = component.position();
|
|
1568
|
+
}
|
|
1569
|
+
else if(this.parent !== null) // this has parent, then center to it
|
|
1570
|
+
{
|
|
1571
|
+
parentSize = (this.parent instanceof Window || this.parent instanceof InternalWindow) ? this.parent.innerSize() : this.parent.size();
|
|
1572
|
+
}
|
|
1573
|
+
else if(this instanceof Window) // if this is a Window
|
|
1574
|
+
{
|
|
1575
|
+
if(this.owner !== null) // if this Window has owner, then center to it
|
|
1576
|
+
{
|
|
1577
|
+
parentSize = this.owner.size();
|
|
1578
|
+
offset = this.owner.position();
|
|
1579
|
+
}
|
|
1580
|
+
else
|
|
1581
|
+
{
|
|
1582
|
+
parentSize = this.screenSize; // center to screen
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
if(parentSize !== null) this.position(offset.x + ((parentSize.width - this.width()) / 2), offset.y + ((parentSize.height - this.height()) / 2));
|
|
1587
|
+
|
|
1588
|
+
return this;
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
/**
|
|
1592
|
+
* Enables/disables onKey() events to be emitted for focus traversal key (usually Tab key). By default onKey() event doesn't emit for such keys.
|
|
1593
|
+
*
|
|
1594
|
+
* @param {boolean} [enable] - `true` - enabled. `false` - disabled.
|
|
1595
|
+
* @return {this|boolean} Returns `this` component if argumen is provided, otherwise returns `boolean` value.
|
|
1596
|
+
*/
|
|
1597
|
+
emitFocusKeyEvents(...args)
|
|
1598
|
+
{
|
|
1599
|
+
if(args.length > 0) args[0] = (args[0] === true);
|
|
1600
|
+
return this.property("emitFocusKeyEvents", args);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
/**
|
|
1604
|
+
* Finds and returns first ancestor component of specified class. e.g. panel.getAncestor(Window) will return Window component that panel is in, or null if panel doesn't have a parent or ancestor with specified class.
|
|
1605
|
+
*
|
|
1606
|
+
* @param {Function} ancestor_class - UI Component class that comes with `swing-ui` module.
|
|
1607
|
+
* @return {Object|null}
|
|
1608
|
+
*/
|
|
1609
|
+
getAncestor(ancestor_class)
|
|
1610
|
+
{
|
|
1611
|
+
if(this.parent == null) return null;
|
|
1612
|
+
if(this.parent instanceof ancestor_class) return this.parent;
|
|
1613
|
+
return this.parent.getAncestor(ancestor_class);
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
/**
|
|
1617
|
+
* Emits a specified event with a custom event object for this component. This event will be sent to all event handlers registered with the specified event name.
|
|
1618
|
+
*
|
|
1619
|
+
* @param {string} event_name - Name of the event is same as name of an event handler registering function, such as `onAction` or `onChange`.
|
|
1620
|
+
* @param {object} event - Custom event object
|
|
1621
|
+
* @returns {this} Returns an instance of this component.
|
|
1622
|
+
* @example
|
|
1623
|
+
* button.emit("onAction", {type: "action", command: "Click Me"}); // emits a custom event without user clicking on the button
|
|
1624
|
+
*/
|
|
1625
|
+
emit(event_name, event = {type: "custom"})
|
|
1626
|
+
{
|
|
1627
|
+
this.verifyComponent();
|
|
1628
|
+
if(!Array.isArray(this.callback[event_name])) return this;
|
|
1629
|
+
if(typeof event !== "object") throw new Error(`"properties" argument must be an object.`);
|
|
1630
|
+
|
|
1631
|
+
event.event = event_name;
|
|
1632
|
+
event.target = this;
|
|
1633
|
+
|
|
1634
|
+
for(const callback of this.callback[event_name])
|
|
1635
|
+
{
|
|
1636
|
+
try
|
|
1637
|
+
{
|
|
1638
|
+
callback.call(this, event);
|
|
1639
|
+
}catch(ex)
|
|
1640
|
+
{
|
|
1641
|
+
error(`${ui._msg[6]}${this.constructor.name}: ${event} \n\n${ex.stack}\n\nEvent ${stringify(event)}`, false);
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
return this;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
/**
|
|
1649
|
+
* Gets or sets the minimum size of the icon's largest side (in pixels).
|
|
1650
|
+
* If the icon's largest side is smaller than the specified minimum, it will be scaled up proportionally.
|
|
1651
|
+
* Applies to Button, Label, List, and ComboBox.
|
|
1652
|
+
*
|
|
1653
|
+
* @param {number|null} [min_size] - Sets the minimum size of a larger side of icon, or resets to no minimum when `null` is passed.
|
|
1654
|
+
* @return {number|null|Object} If called without arguments, returns `number` value, otherwise returns `this` component instance.
|
|
1655
|
+
*/
|
|
1656
|
+
minIconSize()
|
|
1657
|
+
{
|
|
1658
|
+
return this.property("minIconSize", arguments);
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
/**
|
|
1662
|
+
* Gets or sets the maximum size of the icon's largest side (in pixels).
|
|
1663
|
+
* If the icon's largest side is larger than the specified maximum, it will be scaled down proportionally.
|
|
1664
|
+
* Applies to Button, Label, List, and ComboBox.
|
|
1665
|
+
*
|
|
1666
|
+
* @param {number|null} [max_size] - Sets the maximum size of a larger side of icon, or resets to no maximum when `null` is passed.
|
|
1667
|
+
* @return {number|null|Object} If called without arguments, returns `number` value, otherwise returns `this` component instance.
|
|
1668
|
+
*/
|
|
1669
|
+
maxIconSize()
|
|
1670
|
+
{
|
|
1671
|
+
return this.property("maxIconSize", arguments);
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
/**
|
|
1675
|
+
* Sets or gets an array of keyboard shortcuts handled by {@link UIComponent#onShortcut|onShortcut()} event handler.
|
|
1676
|
+
*
|
|
1677
|
+
* @param {object[]|string[]} [shortcuts] - An array of shortcut objects {shortcut:{string}, scope: {ShortcutScope}}, or an Array of String shortcuts (for strings a default {@link ShortcutScope} will be assigned).
|
|
1678
|
+
* @returns {this|object[]} If called without arguments, then current shortcuts array is returned, otherwise an instance of `this` component is returned.
|
|
1679
|
+
* @see ShortcutScope
|
|
1680
|
+
* @example <h2>Setting shortcuts as strings</h2>
|
|
1681
|
+
* window.shortcuts(["f1", "ctrl+s"]);
|
|
1682
|
+
* @example <h2>Setting shortcuts as objects</h2>
|
|
1683
|
+
* window.shortcuts([
|
|
1684
|
+
* {
|
|
1685
|
+
* key: "control+s",
|
|
1686
|
+
* scope: ShortcutScope.Window, // optional
|
|
1687
|
+
* action: "save_file" // optional
|
|
1688
|
+
* }
|
|
1689
|
+
* ]);
|
|
1690
|
+
* @example <h2>Clearing all shortcuts</h2>
|
|
1691
|
+
* window.shortcuts([]); // pass an empty array
|
|
1692
|
+
* @example <h2>Retrieving current shortcuts</h2>
|
|
1693
|
+
* const shortcuts = window.shortcuts(); // returns an Array of objects with `key` and `scope` properties.
|
|
1694
|
+
*/
|
|
1695
|
+
shortcuts()
|
|
1696
|
+
{
|
|
1697
|
+
if(arguments.length > 0)
|
|
1698
|
+
{
|
|
1699
|
+
if(!Array.isArray(arguments[0])) throw new TypeError(`First argument to shortcuts() method must be an array, not '${typeof arguments[0]}'`);
|
|
1700
|
+
|
|
1701
|
+
for(let i = 0; i < arguments[0].length; i++)
|
|
1702
|
+
{
|
|
1703
|
+
if(typeof arguments[0][i] === "string")
|
|
1704
|
+
{
|
|
1705
|
+
arguments[0][i] = {key: arguments[0][i]};
|
|
1706
|
+
}
|
|
1707
|
+
else if(typeof arguments[0][i] !== "object" || typeof arguments[0][i].key !== "string")
|
|
1708
|
+
{
|
|
1709
|
+
arguments[0].splice(i--, 1); // remove invalid type
|
|
1710
|
+
continue;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
if(typeof arguments[0][i].scope !== "string")
|
|
1714
|
+
{
|
|
1715
|
+
arguments[0][i].scope = this instanceof Window ? ShortcutScope.Window : (this instanceof ComponentContainer ? ShortcutScope.Ancestor : ShortcutScope.Focused) // set default scope
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
if(typeof arguments[0][i].action !== "string") arguments[0][i].action = arguments[0][i].key; // default action is the key value
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
return this.property("shortcuts", arguments);
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
//endregion
|
|
1726
|
+
|
|
1727
|
+
//region Event Handlers
|
|
1728
|
+
|
|
1729
|
+
/**
|
|
1730
|
+
* Overrides current error handler.
|
|
1731
|
+
*
|
|
1732
|
+
* @param {function(ErrorEvent): any} [callback=undefined] - The event handler function receiving an {@link ErrorEvent} object. Pass `null` to unregister all handler functions.
|
|
1733
|
+
* @return {this}
|
|
1734
|
+
* @see ErrorEvent
|
|
1735
|
+
*/
|
|
1736
|
+
onError(callback)
|
|
1737
|
+
{
|
|
1738
|
+
if(typeof callback === "function") this.callback.onError = [callback];
|
|
1739
|
+
return this;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
/**
|
|
1743
|
+
* Registers or unregisters a handler function for an event when the component gets disposed, either by calling destroy() method or loosing all references to the component.
|
|
1744
|
+
*
|
|
1745
|
+
* @param {function(DisposeEvent): any} [callback=undefined] - The event handler function receiving {@link DisposeEvent} object. Pass `null` to unregister all handler functions.
|
|
1746
|
+
* @param {boolean} [remove=false] - Set to `true` to remove this event handler
|
|
1747
|
+
* @return {this}
|
|
1748
|
+
* @see DisposeEvent
|
|
1749
|
+
*/
|
|
1750
|
+
onDispose(callback, remove = false)
|
|
1751
|
+
{
|
|
1752
|
+
const name = "onDispose";
|
|
1753
|
+
|
|
1754
|
+
// return callbacks
|
|
1755
|
+
if(callback === null)
|
|
1756
|
+
{
|
|
1757
|
+
return Array.isArray(this.callback[name]) ?? [];
|
|
1758
|
+
}
|
|
1759
|
+
// remove callback
|
|
1760
|
+
else if(remove === true)
|
|
1761
|
+
{
|
|
1762
|
+
if(Array.isArray(this.callback[name]))
|
|
1763
|
+
{
|
|
1764
|
+
const i = this.callback[name].indexOf(callback); // find callback
|
|
1765
|
+
if(i > -1) this.callback[name].splice(i, 1); // remove it
|
|
1766
|
+
if(this.callback[name].length === 0) delete this.callback[name]; // delete array
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
// add callback
|
|
1770
|
+
else if(typeof callback === "function")
|
|
1771
|
+
{
|
|
1772
|
+
if(!Array.isArray(this.callback[name])) this.callback[name] = []; // create array
|
|
1773
|
+
this.callback[name].push(callback); // add callback (don't bind to this here, do it at call)
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
return this;
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
/**
|
|
1780
|
+
* Gets, registers or unregisters a handler function for component's primary action event.
|
|
1781
|
+
*
|
|
1782
|
+
* @param {function(ActionEvent): any} [callback=undefined] - The event handler function that receives a {@link ActionEvent} object. Pass `null` to unregister all handler functions.
|
|
1783
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
1784
|
+
* @returns {this|function[]} An array of handler functions if no arguments are passed, otherwise `this` component for method chaining.
|
|
1785
|
+
* @see ActionEvent
|
|
1786
|
+
* @example
|
|
1787
|
+
* // Example event object:
|
|
1788
|
+
* const e = {
|
|
1789
|
+
* target: object, // The component that triggered the event.
|
|
1790
|
+
* command: string, // Button text or a specified command using .command("") method
|
|
1791
|
+
* modifiers: number, // Keyboard modifiers (bitmask or flags).
|
|
1792
|
+
* alt: boolean, // Indicates if ALT key was pressed.
|
|
1793
|
+
* shift: boolean, // Indicates if SHIFT key was pressed.
|
|
1794
|
+
* ctrl: boolean, // Indicates if CTRL key was pressed.
|
|
1795
|
+
* type: string, // `action` or `index_change`. Present when applicable.
|
|
1796
|
+
* x: number, // Mouse x position relative to component
|
|
1797
|
+
* y: number, // Mouse y position relative to component
|
|
1798
|
+
* screenX: number, // Mouse x position relative to default screen
|
|
1799
|
+
* screenY: number, // Mouse y position relative to default screen
|
|
1800
|
+
* interactive: boolean, // Indicates if the action was triggered by user's interaction (not programmatically). Present when applicable.
|
|
1801
|
+
* selected: false // Present when applicable.
|
|
1802
|
+
* };
|
|
1803
|
+
*/
|
|
1804
|
+
onAction(...args)
|
|
1805
|
+
{
|
|
1806
|
+
if(args.length === 0) return this.event("onAction");
|
|
1807
|
+
return this.event("onAction", args[0], args[1] ?? false);
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
/**
|
|
1811
|
+
* Gets, registers or unregisters a mouse buttons event handler function.
|
|
1812
|
+
*
|
|
1813
|
+
* @param {function(MouseEvent): any} [callback=undefined] - The event handler function that receives a {@link MouseEvent} object. Pass `null` to unregister all handler functions.
|
|
1814
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
1815
|
+
* @returns {this|function[]} An array of handler functions if no arguments are passed, otherwise `this` component for method chaining.
|
|
1816
|
+
* @see MouseEvent
|
|
1817
|
+
* @example
|
|
1818
|
+
* // Example event object:
|
|
1819
|
+
* const e = {
|
|
1820
|
+
* target: object, // The component that triggered the event.
|
|
1821
|
+
* type: string, // `click`, `down`, `up`, `enter`, or `leave`.
|
|
1822
|
+
* button: number, // Button number. One of MouseButton enum values.
|
|
1823
|
+
* clicks: number, // Amount of time the click happened. Present when applicable.
|
|
1824
|
+
* modifiers: number, // Keyboard modifiers (bitmask or flags).
|
|
1825
|
+
* alt: boolean, // Indicates if ALT key was pressed.
|
|
1826
|
+
* shift: boolean, // Indicates if SHIFT key was pressed.
|
|
1827
|
+
* ctrl: boolean, // Indicates if CTRL key was pressed.
|
|
1828
|
+
* x: number, // Present when applicable.
|
|
1829
|
+
* y: number, // Present when applicable.
|
|
1830
|
+
* screenX: number, // Present when applicable.
|
|
1831
|
+
* screenY: number, // Present when applicable.
|
|
1832
|
+
* };
|
|
1833
|
+
*/
|
|
1834
|
+
onMouseEvents(...args)
|
|
1835
|
+
{
|
|
1836
|
+
if(args.length === 0) return this.event("onMouseEvents");
|
|
1837
|
+
return this.event("onMouseEvents", args[0], args[1] ?? false);
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
/**
|
|
1841
|
+
* Gets, registers or unregisters a mouse motion event handler function.
|
|
1842
|
+
*
|
|
1843
|
+
* @param {function(MouseMotionEvent): any} [callback=undefined] - The event handler function that receives a {@link MouseMotionEvent} object. Pass `null` to unregister all handler functions.
|
|
1844
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
1845
|
+
* @returns {this|function[]} An array of handler functions if no arguments are passed, otherwise `this` component for method chaining.
|
|
1846
|
+
* @see MouseMotionEvent
|
|
1847
|
+
* @example
|
|
1848
|
+
* // Example event object:
|
|
1849
|
+
* const e = {
|
|
1850
|
+
* target: object, // The component that triggered the event.
|
|
1851
|
+
* type: string, // `move` or `drag`.
|
|
1852
|
+
* button: number, // Button number. One of MouseButton enum values. Present when applicable.
|
|
1853
|
+
* modifiers: number, // Keyboard modifiers (bitmask or flags).
|
|
1854
|
+
* x: number, // Mouse x position relative to component
|
|
1855
|
+
* y: number, // Mouse y position relative to component
|
|
1856
|
+
* screenX: number, // Mouse x position relative to default screen
|
|
1857
|
+
* screenY: number, // Mouse y position relative to default screen
|
|
1858
|
+
* };
|
|
1859
|
+
*/
|
|
1860
|
+
onMouseMotion(...args)
|
|
1861
|
+
{
|
|
1862
|
+
if(args.length === 0) return this.event("onMouseMotion");
|
|
1863
|
+
return this.event("onMouseMotion", args[0], args[1] ?? false);
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
/**
|
|
1867
|
+
* Gets, registers or unregisters a mouse wheel event handler function.
|
|
1868
|
+
*
|
|
1869
|
+
* @param {function(MouseWheelEvent): any} [callback=undefined] - The event handler function that receives a {@link MouseWheelEvent} object. Pass `null` to unregister all handler functions.
|
|
1870
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
1871
|
+
* @returns {this|function[]} An array of handler functions if no arguments are passed, otherwise `this` component for method chaining.
|
|
1872
|
+
* @see MouseWheelEvent
|
|
1873
|
+
* @example
|
|
1874
|
+
* // Example event object:
|
|
1875
|
+
* const e = {
|
|
1876
|
+
* target: object, // The component that triggered the event.
|
|
1877
|
+
* type: string, // `wheel`.
|
|
1878
|
+
* button: number, // Button number. One of MouseButton enum values. Present when applicable.
|
|
1879
|
+
* scrollAmount: number, // Returns the number of units that should be scrolled per click of mouse wheel rotation.
|
|
1880
|
+
* rotation: number, // Indicates the number of "clicks" the mouse wheel was rotated.
|
|
1881
|
+
* // A partial rotation may occur if the mouse supports a high-resolution wheel.
|
|
1882
|
+
* // In this case, the number is zero until a full "click" has been accumulated.
|
|
1883
|
+
* modifiers: number, // Keyboard modifiers (bitmask or flags).
|
|
1884
|
+
* alt: boolean, // Indicates if ALT key was pressed.
|
|
1885
|
+
* shift: boolean, // Indicates if SHIFT key was pressed.
|
|
1886
|
+
* ctrl: boolean, // Indicates if CTRL key was pressed.
|
|
1887
|
+
* x: number, // Mouse x position relative to component
|
|
1888
|
+
* y: number, // Mouse y position relative to component
|
|
1889
|
+
* screenX: number, // Mouse x position relative to default screen
|
|
1890
|
+
* screenY: number, // Mouse y position relative to default screen
|
|
1891
|
+
* };
|
|
1892
|
+
*/
|
|
1893
|
+
onMouseWheel(...args)
|
|
1894
|
+
{
|
|
1895
|
+
if(args.length === 0) return this.event("onMouseWheel");
|
|
1896
|
+
return this.event("onMouseWheel", args[0], args[1] ?? false);
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
/**
|
|
1900
|
+
* Gets, registers or unregisters a keyboard keys' event handler function.
|
|
1901
|
+
*
|
|
1902
|
+
* @param {function(KeyEvent): any} [callback=undefined] - The event handler function that receives a {@link KeyEvent} object. Pass `null` to unregister all handler functions.
|
|
1903
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
1904
|
+
* @returns {this|function[]} An array of handler functions if no arguments are passed, otherwise `this` component for method chaining.
|
|
1905
|
+
* @see KeyEvent
|
|
1906
|
+
* @example
|
|
1907
|
+
* // Example event object:
|
|
1908
|
+
* const e = {
|
|
1909
|
+
* target: object, // The component that triggered the event.
|
|
1910
|
+
* type: string, // `up`, `down`, `type`.
|
|
1911
|
+
* keyCode: number // Numeric code associated with the key
|
|
1912
|
+
* extendedKeyCode: number // The extended key code is a unique id assigned to a key on the keyboard just like keyCode. However, unlike keyCode, this value depends on the current keyboard layout.
|
|
1913
|
+
* keyChar: string // Key character
|
|
1914
|
+
* modifiers: number, // Keyboard modifiers (bitmask or flags).
|
|
1915
|
+
* modifiersText: string // Modifiers representation as a string.
|
|
1916
|
+
* alt: boolean, // Indicates if ALT key was pressed.
|
|
1917
|
+
* shift: boolean, // Indicates if SHIFT key was pressed.
|
|
1918
|
+
* ctrl: boolean, // Indicates if CTRL key was pressed.
|
|
1919
|
+
* keyLocation: string // `standard`, `numpad`, `left`, `right`. Location of the key on keyboard. Only present when type is `up` or `down`.
|
|
1920
|
+
* };
|
|
1921
|
+
*/
|
|
1922
|
+
onKey(...args)
|
|
1923
|
+
{
|
|
1924
|
+
if(args.length === 0) return this.event("onKey");
|
|
1925
|
+
return this.event("onKey", args[0], args[1] ?? false);
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
/**
|
|
1929
|
+
* Gets, registers or unregisters a focus event handler function.
|
|
1930
|
+
*
|
|
1931
|
+
* @param {function(FocusEvent): any} [callback=undefined] - The event handler function that receives a {@link FocusEvent} object. Pass `null` to unregister all handler functions.
|
|
1932
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
1933
|
+
* @returns {this|function[]} An array of handler functions if no arguments are passed, otherwise `this` component for method chaining.
|
|
1934
|
+
* @see FocusEvent
|
|
1935
|
+
* @example
|
|
1936
|
+
* // Example event object:
|
|
1937
|
+
* const e = {
|
|
1938
|
+
* target: object, // The component that triggered the event.
|
|
1939
|
+
* type: string, // `focus`, `blur`.
|
|
1940
|
+
* cause: string // `UNKNOWN`, `ACTIVATION`, `TRAVERSAL_FORWARD`, `TRAVERSAL_BACKWARD`.
|
|
1941
|
+
* temporary: boolean, // Identifies the focus change event as temporary or permanent
|
|
1942
|
+
* };
|
|
1943
|
+
*/
|
|
1944
|
+
onFocusEvents(...args)
|
|
1945
|
+
{
|
|
1946
|
+
if(args.length === 0) return this.event("onFocusEvents");
|
|
1947
|
+
return this.event("onFocusEvents", args[0], args[1] ?? false);
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
/**
|
|
1951
|
+
* Gets, registers or unregisters an event handler function for events: resize, move, show, hide.
|
|
1952
|
+
*
|
|
1953
|
+
* @param {function(ComponentEvent): any} [callback=undefined] - The event handler function that receives a {@link ComponentEvent} object. Pass `null` to unregister all handler functions.
|
|
1954
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
1955
|
+
* @returns {this|function[]} An array of handler functions if no arguments are passed, otherwise `this` component for method chaining.
|
|
1956
|
+
* @see ComponentEvent
|
|
1957
|
+
* @example
|
|
1958
|
+
* // Example event object:
|
|
1959
|
+
* const e = {
|
|
1960
|
+
* target: object, // The component that triggered the event.
|
|
1961
|
+
* type: string, // `resize`, `move`, `show`, `hide`.
|
|
1962
|
+
* interactive: boolean, // Indicates if the event was triggered by user's interaction (not programmatically). Present when e.type is `move` or `resize`.
|
|
1963
|
+
* x: number, // New x position of component.
|
|
1964
|
+
* y: number, // New y position of component.
|
|
1965
|
+
* width: number, // New width of component. Present when e.type is `resize`.
|
|
1966
|
+
* height: number, // New height of component. Present when e.type is `resize`.
|
|
1967
|
+
* innerWidth: number, // New width of content area of the component. Present when e.type is `resize` and component is Window or InternalWindow.
|
|
1968
|
+
* innerHeight: number, // New height of content area of the component. Present when e.type is `resize` and component is Window or InternalWindow.
|
|
1969
|
+
*};
|
|
1970
|
+
*/
|
|
1971
|
+
onComponentEvents(...args)
|
|
1972
|
+
{
|
|
1973
|
+
if(args.length === 0) return this.event("onComponentEvents");
|
|
1974
|
+
return this.event("onComponentEvents", args[0], args[0] ?? false);
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
/**
|
|
1978
|
+
* Gets, registers or unregisters an event handler that listens for changes to this component's properties.
|
|
1979
|
+
*
|
|
1980
|
+
* @param {function(PropertyChangeEvent): any} [callback=undefined] - The event handler function that receives a {@link PropertyChangeEvent} object. Pass `null` to unregister all handler functions.
|
|
1981
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
1982
|
+
* @returns {this|function[]} An array of handler functions if no arguments are passed, otherwise `this` component for method chaining.
|
|
1983
|
+
* @see PropertyChangeEvent
|
|
1984
|
+
* @example
|
|
1985
|
+
* // Example event object:
|
|
1986
|
+
* const e = {
|
|
1987
|
+
* target: object, // The container component that triggered the event.
|
|
1988
|
+
* type: string, // `change`.
|
|
1989
|
+
* property: string, // The property that was changed
|
|
1990
|
+
* oldValue: any, // Previous value of the changed property
|
|
1991
|
+
* newValue: any // New value of the changed property
|
|
1992
|
+
* };
|
|
1993
|
+
*/
|
|
1994
|
+
onPropertyChange(...args)
|
|
1995
|
+
{
|
|
1996
|
+
if(args.length === 0) return this.event("onPropertyChange");
|
|
1997
|
+
return this.event("onPropertyChange", args[0], args[1] ?? false);
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
/**
|
|
2001
|
+
* Gets, registers or unregisters a handler function for drag related events. Call without parameters to get an array of already registered handler functions.
|
|
2002
|
+
*
|
|
2003
|
+
* @param {function(DragEvent): any} [callback=undefined] - The event handler function that receives a {@link DragEvent} object. Pass `null` to unregister all handler functions.
|
|
2004
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
2005
|
+
* @returns {this|function[]} An array of handler functions if no arguments are passed, otherwise `this` component for method chaining.
|
|
2006
|
+
* @see DragEvent
|
|
2007
|
+
*
|
|
2008
|
+
* @example
|
|
2009
|
+
* // Example event object:
|
|
2010
|
+
* const e = {
|
|
2011
|
+
* target: object, // The component that triggered the event.
|
|
2012
|
+
* type: string, // `dragstart`, `dragend`, `cancel`.
|
|
2013
|
+
* action: string // One of DragDropAction enum values. Present when applicable.
|
|
2014
|
+
* x: number, // X position of a pointer relative to this component. Present when e.type is `dragstart` or `dragend`.
|
|
2015
|
+
* y: number, // Y position of a pointer relative to this component. Present when e.type is `dragstart` or `dragend`.
|
|
2016
|
+
* screenX: number, // X position of a pointer relative to default screen. Present when e.type is `dragstart` or `dragend`.
|
|
2017
|
+
* screenY: number, // Y position of a pointer relative to default screen. Present when e.type is `dragstart` or `dragend`.
|
|
2018
|
+
* button: number, // Indicates a pointing device button involved in dragging. Value of MouseButton enum.
|
|
2019
|
+
* modifiers: number, // Keyboard modifiers (bitmask or flags). Present when e.type is `dragstart`.
|
|
2020
|
+
* modifiersText: string, // Keyboard modifiers. Present when e.type is `dragstart`.
|
|
2021
|
+
* alt: boolean, // Indicates if ALT key was pressed. Present when e.type is `dragstart`.
|
|
2022
|
+
* shift: boolean, // Indicates if SHIFT key was pressed. Present when e.type is `dragstart`.
|
|
2023
|
+
* ctrl: boolean, // Indicates if CTRL key was pressed. Present when e.type is `dragstart`.
|
|
2024
|
+
* selected: number[] // Array of selected indexes of a List component whose items are being dragged. Present when List items are being dragged.
|
|
2025
|
+
* };
|
|
2026
|
+
*/
|
|
2027
|
+
onDragEvents(...args)
|
|
2028
|
+
{
|
|
2029
|
+
if(args.length === 0) return this.event("onDragEvents");
|
|
2030
|
+
return this.event("onDragEvents", args[0], args[1] ?? false);
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
/**
|
|
2034
|
+
* Gets, registers or unregisters a handler function for drop related events. Call without parameters to get an array of already registered handler functions.
|
|
2035
|
+
*
|
|
2036
|
+
* @param {function(DropEvent): any} [callback=undefined] - The event handler function that receives a {@link DropEvent} object. Pass `null` to unregister all handler functions.
|
|
2037
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
2038
|
+
* @returns {this|function[]} An array of handler functions if no arguments are passed, otherwise `this` component for method chaining.
|
|
2039
|
+
* @see DropEvent
|
|
2040
|
+
* @example <h2>{@link DropEvent} object format:</h2>
|
|
2041
|
+
* const e = {
|
|
2042
|
+
* target: object, // The component that triggered the event.
|
|
2043
|
+
* type: string, // `dragenter`, `dragover`, `dragleave`, `drop`.
|
|
2044
|
+
* action: string // One of the values of enum DragDropAction. Present when applicable.
|
|
2045
|
+
* data: object // An object that contains the data that is being dropped. Present only when e.type is `drop` or `dragenter`.
|
|
2046
|
+
* source: object, // A component that is being dragged or dropped onto this component.
|
|
2047
|
+
* // Present only when a another UI component is dragged onto this component and `DataType.Component` is of the types set by dragDataType().
|
|
2048
|
+
* x: number, // X position of a pointer relative to this component. Present when e.type is `dragstart` or `drop`.
|
|
2049
|
+
* y: number, // Y position of a pointer relative to this component. Present when e.type is `dragstart` or `drop`.
|
|
2050
|
+
* screenX: number, // X position of a pointer relative to default screen. Present when e.type is `dragstart` or `drop`.
|
|
2051
|
+
* screenY: number, // Y position of a pointer relative to default screen. Present when e.type is `dragstart` or `drop`.
|
|
2052
|
+
* selected: number[] // Array of selected indexes of a List component whose items are being dragged. Present when List items are being dragged.
|
|
2053
|
+
* };
|
|
2054
|
+
*/
|
|
2055
|
+
onDropEvents(...args)
|
|
2056
|
+
{
|
|
2057
|
+
if(args.length === 0) return this.event("onDropEvents");
|
|
2058
|
+
|
|
2059
|
+
return this.event("onDropEvents", args[0], args[1] ?? false);
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
/**
|
|
2063
|
+
* Gets, registers or unregisters a handler function for component's text value change event. Applied to components where text can be changed by user, such as TextField, PasswordField, TextArea, DocumentEditor, ComboBox, Spinner, etc.
|
|
2064
|
+
*
|
|
2065
|
+
* @param {function(ChangeEvent): any} [callback=undefined] - The event handler function that receives a {@link ChangeEvent} object. Pass `null` to unregister all handler functions.
|
|
2066
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
2067
|
+
* @returns {this|function[]} An array of handler functions if no arguments are passed, otherwise `this` component for method chaining.
|
|
2068
|
+
* @see ChangeEvent
|
|
2069
|
+
*/
|
|
2070
|
+
onChange(...args)
|
|
2071
|
+
{
|
|
2072
|
+
if(args.length === 0) return this.event("onChange");
|
|
2073
|
+
return this.event("onChange", args[0], args[1] ?? false);
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
/**
|
|
2077
|
+
* Gets, registers or unregisters a handler function for component's event when ancestor is added, removed, or moved.
|
|
2078
|
+
*
|
|
2079
|
+
* @param {function(AncestorEvent): any} [callback=undefined] - The event handler function that receives a {@link AncestorEvent} object. Pass `null` to unregister all handler functions.
|
|
2080
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
2081
|
+
* @returns {this|function[]} An array of handler functions if no arguments are passed, otherwise `this` component for method chaining.
|
|
2082
|
+
* @see AncestorEvent
|
|
2083
|
+
* @example
|
|
2084
|
+
* // Example event object:
|
|
2085
|
+
* const e = {
|
|
2086
|
+
* target: object, // The component that triggered the event.
|
|
2087
|
+
* type: string, // `add`, `remove`, `move`.
|
|
2088
|
+
* ancestor: object, // The ancestor component.
|
|
2089
|
+
* };
|
|
2090
|
+
*/
|
|
2091
|
+
onAncestorEvents(...args)
|
|
2092
|
+
{
|
|
2093
|
+
if(args.length === 0) return this.event("onAncestorEvents");
|
|
2094
|
+
return this.event("onAncestorEvents", args[0], args[1] ?? false);
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
/**
|
|
2098
|
+
* Gets, registers or unregisters a handler function for component's {@link ShortcutEvent} when a shortcut is invoked.
|
|
2099
|
+
*
|
|
2100
|
+
* @param {function(ShortcutEvent): any} [callback=undefined] - The event handler function that receives a {@link ShortcutEvent} object. Pass `null` to unregister all handler functions.
|
|
2101
|
+
* @param {boolean} [remove=false] - Set to `true` to unregister the event handler.
|
|
2102
|
+
* @returns {Function[]|UIComponent}
|
|
2103
|
+
*/
|
|
2104
|
+
onShortcut(...args)
|
|
2105
|
+
{
|
|
2106
|
+
if(args.length === 0) return this.event("onShortcut");
|
|
2107
|
+
return this.event("onShortcut", args[0], args[1] ?? false);
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
//endregion
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
export {UIComponent};
|