@hpcc-js/common 3.6.3 → 3.6.5

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.
Files changed (54) hide show
  1. package/LICENSE +43 -43
  2. package/README.md +59 -59
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.umd.cjs +1 -1
  6. package/dist/index.umd.cjs.map +1 -1
  7. package/package.json +4 -4
  8. package/src/CanvasWidget.ts +31 -31
  9. package/src/Class.ts +72 -72
  10. package/src/Database.ts +860 -860
  11. package/src/Entity.ts +235 -235
  12. package/src/EntityCard.ts +66 -66
  13. package/src/EntityPin.ts +103 -103
  14. package/src/EntityRect.css +15 -15
  15. package/src/EntityRect.ts +254 -254
  16. package/src/EntityVertex.ts +86 -86
  17. package/src/FAChar.css +2 -2
  18. package/src/FAChar.ts +89 -89
  19. package/src/HTMLWidget.ts +191 -191
  20. package/src/IList.ts +4 -4
  21. package/src/IMenu.ts +5 -5
  22. package/src/Icon.css +9 -9
  23. package/src/Icon.ts +176 -176
  24. package/src/Image.ts +104 -104
  25. package/src/List.css +13 -13
  26. package/src/List.ts +102 -102
  27. package/src/Menu.css +23 -23
  28. package/src/Menu.ts +139 -139
  29. package/src/Palette.ts +341 -341
  30. package/src/Platform.ts +125 -125
  31. package/src/ProgressBar.ts +115 -115
  32. package/src/PropertyExt.ts +770 -770
  33. package/src/ResizeSurface.css +39 -39
  34. package/src/ResizeSurface.ts +225 -225
  35. package/src/SVGWidget.ts +583 -583
  36. package/src/SVGZoomWidget.css +12 -12
  37. package/src/SVGZoomWidget.ts +427 -427
  38. package/src/Shape.css +3 -3
  39. package/src/Shape.ts +186 -186
  40. package/src/Surface.css +35 -35
  41. package/src/Surface.ts +364 -364
  42. package/src/Text.css +4 -4
  43. package/src/Text.ts +131 -131
  44. package/src/TextBox.css +4 -4
  45. package/src/TextBox.ts +183 -183
  46. package/src/TitleBar.css +114 -114
  47. package/src/TitleBar.ts +407 -407
  48. package/src/Transition.ts +45 -45
  49. package/src/Utility.ts +839 -839
  50. package/src/Widget.css +8 -8
  51. package/src/Widget.ts +731 -731
  52. package/src/WidgetArray.ts +15 -15
  53. package/src/__package__.ts +3 -3
  54. package/src/index.ts +55 -55
package/src/Widget.ts CHANGED
@@ -1,731 +1,731 @@
1
- import { select as d3Select } from "d3-selection";
2
- import "d3-transition";
3
- import { Field, Grid } from "./Database.ts";
4
- import { } from "./Platform.ts";
5
- import { PropertyExt } from "./PropertyExt.ts";
6
- import { debounce, textRect, TextRect, textSize, TextSize } from "./Utility.ts";
7
-
8
- import "../src/Widget.css";
9
-
10
- export { Field };
11
-
12
- export type IPrimative = boolean | number | string | object;
13
- export type IFieldType = "boolean" | "number" | "string" | "dataset" | "object" | "any";
14
- export interface InputField {
15
- id: string;
16
- type: IFieldType;
17
- multi?: boolean;
18
- default?: IPrimative | InputField[];
19
- children?: InputField[];
20
- }
21
-
22
- export interface IPos {
23
- x: number;
24
- y: number;
25
- }
26
-
27
- export interface ISize {
28
- width: number;
29
- height: number;
30
- }
31
-
32
- export interface BBox {
33
- x: number;
34
- y: number;
35
- width: number;
36
- height: number;
37
- }
38
-
39
- export interface DataMetaT {
40
- min?: number;
41
- max?: number;
42
- mean?: number;
43
- stdDev?: number;
44
- sum?: number;
45
- }
46
-
47
- let widgetID = 0;
48
- export abstract class Widget extends PropertyExt {
49
- static _idSeed: string;
50
-
51
- protected _tag: string;
52
- protected _isRootNode: boolean = true;
53
-
54
- protected _db = new Grid();
55
- protected _pos;
56
- protected _prevPos;
57
- protected _size;
58
- protected _widgetScale;
59
- protected _visible;
60
- protected _display;
61
- protected _dataMeta: DataMetaT = {};
62
-
63
- protected _target: null | HTMLElement | SVGElement;
64
- protected _placeholderElement;
65
- protected _parentWidget;
66
-
67
- protected _element;
68
-
69
- protected _renderCount;
70
-
71
- protected _overlayElement;
72
-
73
- constructor() {
74
- super();
75
- this._id = Widget._idSeed + widgetID++;
76
-
77
- this._db = new Grid();
78
- this._pos = { x: 0, y: 0 };
79
- this._size = { width: 0, height: 0 };
80
- this._widgetScale = 1;
81
- this._visible = true;
82
-
83
- this._target = null;
84
- this._placeholderElement = null;
85
- this._parentWidget = null;
86
-
87
- this._element = d3Select(null);
88
-
89
- this._renderCount = 0;
90
-
91
- if ((window as any).__hpcc_debug) {
92
- if ((window as any).g_all === undefined) {
93
- (window as any).g_all = {};
94
- }
95
- (window as any).g_all[this._id] = this;
96
- }
97
- if ((window as any).__hpcc_theme) {
98
- this.applyTheme((window as any).__hpcc_theme);
99
- }
100
- }
101
-
102
- columnChecksum() {
103
- return this._db.fieldsChecksum();
104
- }
105
-
106
- dataChecksum() {
107
- return this._db.dataChecksum();
108
- }
109
-
110
- importJSON(_: string | object): this {
111
- this._db.json(_);
112
- return this;
113
- }
114
-
115
- importCSV(_: string): this {
116
- this._db.csv(_);
117
- return this;
118
- }
119
-
120
- importTSV(_: string): this {
121
- this._db.tsv(_);
122
- return this;
123
- }
124
-
125
- export(_: "JSON" | "CSV" | "TSV" = "JSON") {
126
- switch (_) {
127
- case "CSV":
128
- return this._db.csv();
129
- case "TSV":
130
- return this._db.tsv();
131
- case "JSON":
132
- default:
133
- return this._db.json();
134
- }
135
- }
136
-
137
- leakCheck(newNode) {
138
- const context = this;
139
- const watchArray = [newNode];
140
- const destructObserver = new MutationObserver(function (mutations) {
141
- let leaks = false;
142
- mutations.forEach(function (mutation) {
143
- for (let i = 0; i < mutation.removedNodes.length; ++i) {
144
- const node = mutation.removedNodes.item(i);
145
- if (watchArray.indexOf(node) >= 0 && context._target) {
146
- leaks = true;
147
- destructObserver.disconnect();
148
- }
149
- }
150
- });
151
- if (leaks) {
152
- console.error("leak: " + context.id() + " - " + context.classID() + "\t\twidget.target(null); was not called for this widget before it was removed from the page.");
153
- }
154
- });
155
- let pNode = newNode.parentNode;
156
- while (pNode) {
157
- destructObserver.observe(pNode, { childList: true });
158
- watchArray.push(pNode);
159
- pNode = pNode.parentNode;
160
- }
161
- }
162
-
163
- renderCount(): number {
164
- return this._renderCount;
165
- }
166
-
167
- // Implementation ---
168
- columns(): string[];
169
- columns(_: string[], asDefault?: boolean): this;
170
- columns(_?: string[], asDefault?: boolean): string[] | this {
171
- if (!arguments.length) return this._db.legacyColumns();
172
- this._db.legacyColumns(_, asDefault);
173
- return this;
174
- }
175
-
176
- protected columnIdx(column: string): number {
177
- return this.columns().indexOf(column);
178
- }
179
-
180
- protected cellIdxFunc<T>(colIdx: number, defValue?: T): (row: any) => T {
181
- return colIdx < 0 ? () => defValue : row => row[colIdx];
182
- }
183
-
184
- protected cellFunc<T>(column: string, defValue?: T): (row: any) => T {
185
- return this.cellIdxFunc<T>(this.columnIdx(column), defValue);
186
- }
187
-
188
- parsedData() {
189
- return this._db.parsedData();
190
- }
191
-
192
- formattedData() {
193
- return this._db.formattedData();
194
- }
195
-
196
- data(): any;
197
- data(_: any): this;
198
- data(_?: any): any | this {
199
- if (!arguments.length) return this._db.legacyData();
200
- this._db.legacyData(_);
201
- return this;
202
- }
203
-
204
- cloneData() {
205
- return this.data().map(function (row) { return row.slice(0); });
206
- }
207
-
208
- flattenData(columns: string[] = this.columns(), data: any = this.data()) {
209
- const retVal = [];
210
- data.forEach(function (row, rowIdx) {
211
- columns.filter(function (_col, idx) { return idx > 0; }).forEach(function (_col, idx) {
212
- const val = row[idx + 1];
213
- if (typeof val !== "undefined") {
214
- const newItem = {
215
- rowIdx,
216
- colIdx: idx + 1,
217
- label: row[0],
218
- value: val
219
- };
220
- retVal.push(newItem);
221
- }
222
- }, this);
223
- }, this);
224
- return retVal;
225
- }
226
-
227
- rowToObj(row: any[]): object {
228
- if (!row) return {};
229
- const retVal: any = {};
230
- this.fields().forEach(function (field, idx) {
231
- retVal[field.label_default() || field.label()] = row[idx];
232
- });
233
- if (row.length === this.columns().length + 1) {
234
- retVal.__lparam = row[this.columns().length];
235
- }
236
- return retVal;
237
- }
238
-
239
- pos(): IPos;
240
- pos(_: IPos): this;
241
- pos(_?: IPos): IPos | this {
242
- if (!arguments.length) return this._pos;
243
- this._pos = _;
244
- if (this._overlayElement) {
245
- this._overlayElement
246
- .attr("transform", "translate(" + _.x + "," + _.y + ")scale(" + this._widgetScale + ")")
247
- ;
248
- }
249
- return this;
250
- }
251
-
252
- x(): number;
253
- x(_): this;
254
- x(_?): number | this {
255
- if (!arguments.length) return this._pos.x;
256
- this.pos({ x: _, y: this._pos.y });
257
- return this;
258
- }
259
-
260
- y(): number;
261
- y(_): this;
262
- y(_?): number | this {
263
- if (!arguments.length) return this._pos.y;
264
- this.pos({ x: this._pos.x, y: _ });
265
- return this;
266
- }
267
-
268
- size(): ISize;
269
- size(_): this;
270
- size(_?): ISize | this {
271
- if (!arguments.length) return this._size;
272
- this._size = _;
273
- if (this._overlayElement) {
274
- this._overlayElement
275
- .attr("width", _.width)
276
- .attr("height", _.height)
277
- ;
278
- }
279
- return this;
280
- }
281
-
282
- width(): number;
283
- width(_): this;
284
- width(_?): number | this {
285
- if (!arguments.length) return this._size.width;
286
- this.size({ width: _, height: this._size.height });
287
- return this;
288
- }
289
-
290
- height(): number;
291
- height(_): this;
292
- height(_?): number | this {
293
- if (!arguments.length) return this._size.height;
294
- this.size({ width: this._size.width, height: _ });
295
- return this;
296
- }
297
-
298
- resize(size?: ISize, delta: ISize = { width: 0, height: 0 }) {
299
- let width;
300
- let height;
301
- if (size && size.width && size.height) {
302
- width = size.width;
303
- height = size.height;
304
- } else {
305
- const style = window.getComputedStyle(this._target, null);
306
- width = parseFloat(style.getPropertyValue("width")) - delta.width;
307
- height = parseFloat(style.getPropertyValue("height")) - delta.height;
308
- }
309
- this.size({
310
- width,
311
- height
312
- });
313
- return this;
314
- }
315
-
316
- scale(): number;
317
- scale(_): this;
318
- scale(_?): number | this {
319
- if (!arguments.length) return this._widgetScale;
320
- this._widgetScale = _;
321
- if (this._overlayElement) {
322
- this._overlayElement
323
- .attr("transform", "translate(" + _.x + "," + _.y + ")scale(" + this._widgetScale + ")")
324
- ;
325
- }
326
- return this;
327
- }
328
-
329
- visible(): boolean;
330
- visible(_): this;
331
- visible(_?): boolean | this {
332
- if (!arguments.length) return this._visible;
333
- this._visible = _;
334
- if (this._element) {
335
- this._element
336
- .style("visibility", this._visible ? null : "hidden")
337
- .style("opacity", this._visible ? null : 0)
338
- ;
339
- }
340
- return this;
341
- }
342
-
343
- display(): boolean;
344
- display(_): this;
345
- display(_?): boolean | this {
346
- if (!arguments.length) return this._display;
347
- this._display = _;
348
- if (this._element) {
349
- this._element.style("display", this._display ? null : "none");
350
- }
351
- return this;
352
- }
353
-
354
- dataMeta(): DataMetaT;
355
- dataMeta(_): this;
356
- dataMeta(_?): DataMetaT | this {
357
- if (!arguments.length) return this._dataMeta;
358
- this._dataMeta = _;
359
- return this;
360
- }
361
-
362
- private _appData = new Object({});
363
- appData(key: string): any;
364
- appData(key: string, value: any): this;
365
- appData(key: string, value?: any): any | this {
366
- if (arguments.length < 2) return this._appData[key];
367
- this._appData[key] = value;
368
- return this;
369
- }
370
-
371
- calcSnap(snapSize) {
372
- function snap(x, gridSize) {
373
- function snapDelta(x2, gridSize2) {
374
- let dx = x2 % gridSize2;
375
- if (Math.abs(dx) > gridSize2 - Math.abs(dx)) {
376
- dx = (gridSize2 - Math.abs(dx)) * (dx < 0 ? 1 : -1);
377
- }
378
- return dx;
379
- }
380
- return x - snapDelta(x, gridSize);
381
- }
382
- const l = snap(this._pos.x - this._size.width / 2, snapSize);
383
- const t = snap(this._pos.y - this._size.height / 2, snapSize);
384
- const r = snap(this._pos.x + this._size.width / 2, snapSize);
385
- const b = snap(this._pos.y + this._size.height / 2, snapSize);
386
- const w = r - l;
387
- const h = b - t;
388
- return [{ x: l + w / 2, y: t + h / 2 }, { width: w, height: h }];
389
- }
390
-
391
- // DOM/SVG Node Helpers ---
392
- toWidget(domNode): Widget | null {
393
- if (!domNode) {
394
- return null;
395
- }
396
- const element = d3Select(domNode);
397
- if (element) {
398
- const widget = element.datum();
399
- if (widget && widget instanceof Widget) {
400
- return widget;
401
- }
402
- }
403
- return null;
404
- }
405
-
406
- parentOverlay() {
407
- return null;
408
- }
409
-
410
- locateParentWidget(domNode?): Widget | null {
411
- domNode = domNode || (this._target ? this._target.parentNode : null);
412
- if (domNode) {
413
- const widget = this.toWidget(domNode);
414
- if (widget) {
415
- return widget;
416
- } else if (domNode.parentNode) {
417
- return this.locateParentWidget(domNode.parentNode);
418
- }
419
- }
420
- return null;
421
- }
422
-
423
- locateSVGNode(domNode): SVGSVGElement | null {
424
- if (!domNode) {
425
- return null;
426
- }
427
- if (domNode.tagName === "svg") {
428
- return domNode;
429
- }
430
- return this.locateSVGNode(domNode.parentNode);
431
- }
432
-
433
- locateOverlayNode() {
434
- let widget = this.locateParentWidget(this._target);
435
- while (widget) {
436
- const retVal = widget.parentOverlay();
437
- if (retVal) {
438
- return retVal;
439
- }
440
- widget = this.locateParentWidget(widget._target.parentNode);
441
- }
442
- return null;
443
- }
444
-
445
- locateAncestor(classID): Widget | null {
446
- return this.locateClosestAncestor([classID]);
447
- }
448
-
449
- locateClosestAncestor(classIDArr): Widget | null {
450
- let widget = this.locateParentWidget(this._target);
451
- while (widget) {
452
- if (classIDArr.indexOf(widget.classID()) !== -1) {
453
- return widget;
454
- }
455
- widget = this.locateParentWidget(widget._target.parentNode);
456
- }
457
- return null;
458
- }
459
-
460
- getAbsolutePos(domNode, w, h) {
461
- const root = this.locateSVGNode(domNode);
462
- if (!root) {
463
- return null;
464
- }
465
- let pos = root.createSVGPoint();
466
- const ctm = domNode.getCTM();
467
- pos = pos.matrixTransform(ctm);
468
- const retVal: any = {
469
- x: pos.x,
470
- y: pos.y
471
- };
472
- if (w !== undefined && h !== undefined) {
473
- let size = root.createSVGPoint();
474
- size.x = w;
475
- size.y = h;
476
- size = size.matrixTransform(ctm);
477
- retVal.width = size.x - pos.x;
478
- retVal.height = size.y - pos.y;
479
- }
480
- return retVal;
481
- }
482
-
483
- hasOverlay() {
484
- return this._overlayElement;
485
- }
486
-
487
- syncOverlay() {
488
- if (this._size.width && this._size.height) {
489
- const newPos = this.getAbsolutePos(this._overlayElement.node(), this._size.width, this._size.height);
490
- if (newPos && (!this._prevPos || newPos.x !== this._prevPos.x || newPos.y !== this._prevPos.y || newPos.width !== this._prevPos.width || newPos.height !== this._prevPos.height)) {
491
- const xScale = newPos.width / this._size.width;
492
- const yScale = newPos.height / this._size.height;
493
- this._placeholderElement
494
- .style("left", newPos.x - (newPos.width / xScale) / 2 + "px")
495
- .style("top", newPos.y - (newPos.height / yScale) / 2 + "px")
496
- .style("width", newPos.width / xScale + "px")
497
- .style("height", newPos.height / yScale + "px")
498
- ;
499
- const transform = "scale(" + xScale + "," + yScale + ")";
500
- this._placeholderElement
501
- .style("transform", transform)
502
- .style("-moz-transform", transform)
503
- .style("-ms-transform", transform)
504
- .style("-webkit-transform", transform)
505
- .style("-o-transform", transform)
506
- ;
507
- }
508
- this._prevPos = newPos;
509
- }
510
- }
511
-
512
- getBBox(refresh = false, round = false): BBox {
513
- return {
514
- x: 0,
515
- y: 0,
516
- width: 0,
517
- height: 0
518
- };
519
- }
520
-
521
- textSize(_text: string | string[], fontName: string = "Verdana", fontSize: number = 12, bold: boolean = false): Readonly<TextSize> {
522
- return textSize(_text, fontName, fontSize, bold);
523
- }
524
-
525
- textRect(_text: string, fontName: string = "Verdana", fontSize: number = 12, bold: boolean = false): Readonly<TextRect> {
526
- return textRect(_text, fontName, fontSize, bold);
527
- }
528
-
529
- element() {
530
- return this._element;
531
- }
532
-
533
- node() {
534
- return this._element.node();
535
- }
536
-
537
- target(): null | HTMLElement | SVGElement;
538
- target(_: null | string | HTMLElement | SVGElement): this;
539
- target(_?: null | string | HTMLElement | SVGElement): null | HTMLElement | SVGElement | this {
540
- if (!arguments.length) return this._target;
541
- if (this._target && _) {
542
- throw new Error("Target can only be assigned once.");
543
- }
544
- if (_ === null) {
545
- this._target = null;
546
- if (this.renderCount()) {
547
- this.exit();
548
- }
549
- } else if (typeof _ === "string") {
550
- this._target = document.getElementById(_);
551
- } else if (_ instanceof HTMLElement || _ instanceof SVGElement) {
552
- this._target = _;
553
- }
554
- return this;
555
- }
556
-
557
- isDOMHidden(): boolean {
558
- // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent
559
- // Note: Will return false for visible===hidden (which is ok as it still takes up space on the page)
560
- return this._isRootNode && this._placeholderElement.node().offsetParent === null;
561
- }
562
-
563
- hasSize() {
564
- return !isNaN(this.width()) && !isNaN(this.height());
565
- }
566
-
567
- protected publishedWidgets(): Widget[] {
568
- let widgets = [];
569
- this.publishedProperties(true).forEach(function (meta) {
570
- if (!meta.ext || meta.ext.render !== false) {
571
- switch (meta.type) {
572
- case "widget":
573
- const widget = this[meta.id]();
574
- if (widget) {
575
- widgets.push(widget);
576
- }
577
- break;
578
- case "widgetArray":
579
- widgets = widgets.concat(this[meta.id]());
580
- break;
581
- }
582
- }
583
- }, this);
584
- return widgets;
585
- }
586
-
587
- // Render ---
588
- private _prevNow = 0;
589
- render(callback?: (w: Widget) => void) {
590
- if ((window as any).__hpcc_debug) {
591
- const now = Date.now();
592
- if (now - this._prevNow < 500) {
593
- console.error("Double Render: " + (now - this._prevNow) + " - " + this.id() + " - " + this.classID());
594
- }
595
- this._prevNow = now;
596
- }
597
-
598
- callback = callback || function () { };
599
- if (!this._placeholderElement || !this.visible() || this.isDOMHidden() || !this.hasSize()) {
600
- callback(this);
601
- return this;
602
- }
603
- if (this._placeholderElement) {
604
- if (!this._tag)
605
- throw new Error("No DOM tag specified");
606
-
607
- const elements = this._placeholderElement.selectAll("#" + this._id).data([this], function (d) { return d._id; });
608
- elements.enter().append(this._tag)
609
- .classed(this._class, true)
610
- .attr("id", this._id)
611
- // .attr("opacity", 0.50) // Uncomment to debug position offsets ---
612
- .each(function (context2) {
613
- context2._element = d3Select(this);
614
- context2.enter(this, context2._element);
615
- if ((window as any).__hpcc_debug) {
616
- context2.leakCheck(this);
617
- }
618
- })
619
- .merge(elements)
620
- .each(function (context2) {
621
- const element = d3Select(this);
622
- const classed = context2.classed();
623
- for (const key in classed) {
624
- element.classed(key, classed[key]);
625
- }
626
- context2.preUpdate(this, context2._element);
627
- context2.update(this, context2._element);
628
- context2.postUpdate(this, context2._element);
629
- })
630
- ;
631
- elements.exit()
632
- .each(function (context2) {
633
- d3Select(this).datum(null);
634
- context2.exit(this, context2._element);
635
- })
636
- .remove()
637
- ;
638
- this._renderCount++;
639
- }
640
-
641
- // ASync Render Contained Widgets ---
642
- const widgets = this.publishedWidgets();
643
-
644
- const context = this;
645
- switch (widgets.length) {
646
- case 0:
647
- callback(this);
648
- break;
649
- case 1:
650
- widgets[0].render(function () {
651
- callback(context);
652
- });
653
- break;
654
- default:
655
- let renderCount = widgets.length;
656
- widgets.forEach(function (widget, _idx) {
657
- setTimeout(function () {
658
- widget.render(function () {
659
- if (--renderCount === 0) {
660
- callback(context);
661
- }
662
- });
663
- }, 0);
664
- });
665
- break;
666
- }
667
- return this;
668
- }
669
-
670
- renderPromise(): Promise<Widget> {
671
- return new Promise((resolve, reject) => {
672
- this.render((w: Widget) => {
673
- resolve(w);
674
- });
675
- });
676
- }
677
-
678
- private _lazyRender = debounce(function (debouncedCallback?: (w: Widget) => void) {
679
- this.render(debouncedCallback);
680
- }, 100);
681
-
682
- lazyRender(callback?: (w: Widget) => void): this {
683
- this._lazyRender(callback);
684
- return this;
685
- }
686
-
687
- animationFrameRender(): this {
688
- if (requestAnimationFrame) {
689
- requestAnimationFrame(() => {
690
- this.render();
691
- });
692
- } else {
693
- // Not a real replacement for requestAnimationFrame ---
694
- this.renderPromise();
695
- }
696
- return this;
697
- }
698
-
699
- enter(_domNode: HTMLElement, _element) { }
700
- preUpdate(_domNode: HTMLElement, _element) { }
701
- update(_domNode: HTMLElement, _element) { }
702
- postUpdate(_domNode: HTMLElement, _element) { }
703
- exit(_domNode?: HTMLElement, _element?) {
704
- this.publishedWidgets().forEach(w => w.target(null));
705
- }
706
- }
707
- Widget.prototype._class += " common_Widget";
708
-
709
- export interface Widget {
710
- fields(): Field[];
711
- fields(_: Field[]): this;
712
- classed(classID: string): boolean;
713
- classed(classID: string, _: boolean): this;
714
- classed(): { [classID: string]: boolean };
715
- classed(_: { [classID: string]: boolean }): this;
716
- }
717
-
718
- Widget._idSeed = "_w";
719
-
720
- Widget.prototype.publishProxy("fields", "_db", "fields");
721
- Widget.prototype.publish("classed", {}, "object", "HTML Classes", null, { tags: ["Private"] });
722
- const origClassed = Widget.prototype.classed;
723
- Widget.prototype.classed = function (this: Widget, str_obj?: string | { [classID: string]: boolean }, _?: boolean) {
724
- if (typeof str_obj === "string") {
725
- if (arguments.length === 1) return origClassed.call(this)[str_obj];
726
- const classed = origClassed.call(this);
727
- origClassed.call(this, { ...classed, [str_obj]: _ });
728
- return this;
729
- }
730
- return origClassed.apply(this, arguments);
731
- };
1
+ import { select as d3Select } from "d3-selection";
2
+ import "d3-transition";
3
+ import { Field, Grid } from "./Database.ts";
4
+ import { } from "./Platform.ts";
5
+ import { PropertyExt } from "./PropertyExt.ts";
6
+ import { debounce, textRect, TextRect, textSize, TextSize } from "./Utility.ts";
7
+
8
+ import "../src/Widget.css";
9
+
10
+ export { Field };
11
+
12
+ export type IPrimative = boolean | number | string | object;
13
+ export type IFieldType = "boolean" | "number" | "string" | "dataset" | "object" | "any";
14
+ export interface InputField {
15
+ id: string;
16
+ type: IFieldType;
17
+ multi?: boolean;
18
+ default?: IPrimative | InputField[];
19
+ children?: InputField[];
20
+ }
21
+
22
+ export interface IPos {
23
+ x: number;
24
+ y: number;
25
+ }
26
+
27
+ export interface ISize {
28
+ width: number;
29
+ height: number;
30
+ }
31
+
32
+ export interface BBox {
33
+ x: number;
34
+ y: number;
35
+ width: number;
36
+ height: number;
37
+ }
38
+
39
+ export interface DataMetaT {
40
+ min?: number;
41
+ max?: number;
42
+ mean?: number;
43
+ stdDev?: number;
44
+ sum?: number;
45
+ }
46
+
47
+ let widgetID = 0;
48
+ export abstract class Widget extends PropertyExt {
49
+ static _idSeed: string;
50
+
51
+ protected _tag: string;
52
+ protected _isRootNode: boolean = true;
53
+
54
+ protected _db = new Grid();
55
+ protected _pos;
56
+ protected _prevPos;
57
+ protected _size;
58
+ protected _widgetScale;
59
+ protected _visible;
60
+ protected _display;
61
+ protected _dataMeta: DataMetaT = {};
62
+
63
+ protected _target: null | HTMLElement | SVGElement;
64
+ protected _placeholderElement;
65
+ protected _parentWidget;
66
+
67
+ protected _element;
68
+
69
+ protected _renderCount;
70
+
71
+ protected _overlayElement;
72
+
73
+ constructor() {
74
+ super();
75
+ this._id = Widget._idSeed + widgetID++;
76
+
77
+ this._db = new Grid();
78
+ this._pos = { x: 0, y: 0 };
79
+ this._size = { width: 0, height: 0 };
80
+ this._widgetScale = 1;
81
+ this._visible = true;
82
+
83
+ this._target = null;
84
+ this._placeholderElement = null;
85
+ this._parentWidget = null;
86
+
87
+ this._element = d3Select(null);
88
+
89
+ this._renderCount = 0;
90
+
91
+ if ((window as any).__hpcc_debug) {
92
+ if ((window as any).g_all === undefined) {
93
+ (window as any).g_all = {};
94
+ }
95
+ (window as any).g_all[this._id] = this;
96
+ }
97
+ if ((window as any).__hpcc_theme) {
98
+ this.applyTheme((window as any).__hpcc_theme);
99
+ }
100
+ }
101
+
102
+ columnChecksum() {
103
+ return this._db.fieldsChecksum();
104
+ }
105
+
106
+ dataChecksum() {
107
+ return this._db.dataChecksum();
108
+ }
109
+
110
+ importJSON(_: string | object): this {
111
+ this._db.json(_);
112
+ return this;
113
+ }
114
+
115
+ importCSV(_: string): this {
116
+ this._db.csv(_);
117
+ return this;
118
+ }
119
+
120
+ importTSV(_: string): this {
121
+ this._db.tsv(_);
122
+ return this;
123
+ }
124
+
125
+ export(_: "JSON" | "CSV" | "TSV" = "JSON") {
126
+ switch (_) {
127
+ case "CSV":
128
+ return this._db.csv();
129
+ case "TSV":
130
+ return this._db.tsv();
131
+ case "JSON":
132
+ default:
133
+ return this._db.json();
134
+ }
135
+ }
136
+
137
+ leakCheck(newNode) {
138
+ const context = this;
139
+ const watchArray = [newNode];
140
+ const destructObserver = new MutationObserver(function (mutations) {
141
+ let leaks = false;
142
+ mutations.forEach(function (mutation) {
143
+ for (let i = 0; i < mutation.removedNodes.length; ++i) {
144
+ const node = mutation.removedNodes.item(i);
145
+ if (watchArray.indexOf(node) >= 0 && context._target) {
146
+ leaks = true;
147
+ destructObserver.disconnect();
148
+ }
149
+ }
150
+ });
151
+ if (leaks) {
152
+ console.error("leak: " + context.id() + " - " + context.classID() + "\t\twidget.target(null); was not called for this widget before it was removed from the page.");
153
+ }
154
+ });
155
+ let pNode = newNode.parentNode;
156
+ while (pNode) {
157
+ destructObserver.observe(pNode, { childList: true });
158
+ watchArray.push(pNode);
159
+ pNode = pNode.parentNode;
160
+ }
161
+ }
162
+
163
+ renderCount(): number {
164
+ return this._renderCount;
165
+ }
166
+
167
+ // Implementation ---
168
+ columns(): string[];
169
+ columns(_: string[], asDefault?: boolean): this;
170
+ columns(_?: string[], asDefault?: boolean): string[] | this {
171
+ if (!arguments.length) return this._db.legacyColumns();
172
+ this._db.legacyColumns(_, asDefault);
173
+ return this;
174
+ }
175
+
176
+ protected columnIdx(column: string): number {
177
+ return this.columns().indexOf(column);
178
+ }
179
+
180
+ protected cellIdxFunc<T>(colIdx: number, defValue?: T): (row: any) => T {
181
+ return colIdx < 0 ? () => defValue : row => row[colIdx];
182
+ }
183
+
184
+ protected cellFunc<T>(column: string, defValue?: T): (row: any) => T {
185
+ return this.cellIdxFunc<T>(this.columnIdx(column), defValue);
186
+ }
187
+
188
+ parsedData() {
189
+ return this._db.parsedData();
190
+ }
191
+
192
+ formattedData() {
193
+ return this._db.formattedData();
194
+ }
195
+
196
+ data(): any;
197
+ data(_: any): this;
198
+ data(_?: any): any | this {
199
+ if (!arguments.length) return this._db.legacyData();
200
+ this._db.legacyData(_);
201
+ return this;
202
+ }
203
+
204
+ cloneData() {
205
+ return this.data().map(function (row) { return row.slice(0); });
206
+ }
207
+
208
+ flattenData(columns: string[] = this.columns(), data: any = this.data()) {
209
+ const retVal = [];
210
+ data.forEach(function (row, rowIdx) {
211
+ columns.filter(function (_col, idx) { return idx > 0; }).forEach(function (_col, idx) {
212
+ const val = row[idx + 1];
213
+ if (typeof val !== "undefined") {
214
+ const newItem = {
215
+ rowIdx,
216
+ colIdx: idx + 1,
217
+ label: row[0],
218
+ value: val
219
+ };
220
+ retVal.push(newItem);
221
+ }
222
+ }, this);
223
+ }, this);
224
+ return retVal;
225
+ }
226
+
227
+ rowToObj(row: any[]): object {
228
+ if (!row) return {};
229
+ const retVal: any = {};
230
+ this.fields().forEach(function (field, idx) {
231
+ retVal[field.label_default() || field.label()] = row[idx];
232
+ });
233
+ if (row.length === this.columns().length + 1) {
234
+ retVal.__lparam = row[this.columns().length];
235
+ }
236
+ return retVal;
237
+ }
238
+
239
+ pos(): IPos;
240
+ pos(_: IPos): this;
241
+ pos(_?: IPos): IPos | this {
242
+ if (!arguments.length) return this._pos;
243
+ this._pos = _;
244
+ if (this._overlayElement) {
245
+ this._overlayElement
246
+ .attr("transform", "translate(" + _.x + "," + _.y + ")scale(" + this._widgetScale + ")")
247
+ ;
248
+ }
249
+ return this;
250
+ }
251
+
252
+ x(): number;
253
+ x(_): this;
254
+ x(_?): number | this {
255
+ if (!arguments.length) return this._pos.x;
256
+ this.pos({ x: _, y: this._pos.y });
257
+ return this;
258
+ }
259
+
260
+ y(): number;
261
+ y(_): this;
262
+ y(_?): number | this {
263
+ if (!arguments.length) return this._pos.y;
264
+ this.pos({ x: this._pos.x, y: _ });
265
+ return this;
266
+ }
267
+
268
+ size(): ISize;
269
+ size(_): this;
270
+ size(_?): ISize | this {
271
+ if (!arguments.length) return this._size;
272
+ this._size = _;
273
+ if (this._overlayElement) {
274
+ this._overlayElement
275
+ .attr("width", _.width)
276
+ .attr("height", _.height)
277
+ ;
278
+ }
279
+ return this;
280
+ }
281
+
282
+ width(): number;
283
+ width(_): this;
284
+ width(_?): number | this {
285
+ if (!arguments.length) return this._size.width;
286
+ this.size({ width: _, height: this._size.height });
287
+ return this;
288
+ }
289
+
290
+ height(): number;
291
+ height(_): this;
292
+ height(_?): number | this {
293
+ if (!arguments.length) return this._size.height;
294
+ this.size({ width: this._size.width, height: _ });
295
+ return this;
296
+ }
297
+
298
+ resize(size?: ISize, delta: ISize = { width: 0, height: 0 }) {
299
+ let width;
300
+ let height;
301
+ if (size && size.width && size.height) {
302
+ width = size.width;
303
+ height = size.height;
304
+ } else {
305
+ const style = window.getComputedStyle(this._target, null);
306
+ width = parseFloat(style.getPropertyValue("width")) - delta.width;
307
+ height = parseFloat(style.getPropertyValue("height")) - delta.height;
308
+ }
309
+ this.size({
310
+ width,
311
+ height
312
+ });
313
+ return this;
314
+ }
315
+
316
+ scale(): number;
317
+ scale(_): this;
318
+ scale(_?): number | this {
319
+ if (!arguments.length) return this._widgetScale;
320
+ this._widgetScale = _;
321
+ if (this._overlayElement) {
322
+ this._overlayElement
323
+ .attr("transform", "translate(" + _.x + "," + _.y + ")scale(" + this._widgetScale + ")")
324
+ ;
325
+ }
326
+ return this;
327
+ }
328
+
329
+ visible(): boolean;
330
+ visible(_): this;
331
+ visible(_?): boolean | this {
332
+ if (!arguments.length) return this._visible;
333
+ this._visible = _;
334
+ if (this._element) {
335
+ this._element
336
+ .style("visibility", this._visible ? null : "hidden")
337
+ .style("opacity", this._visible ? null : 0)
338
+ ;
339
+ }
340
+ return this;
341
+ }
342
+
343
+ display(): boolean;
344
+ display(_): this;
345
+ display(_?): boolean | this {
346
+ if (!arguments.length) return this._display;
347
+ this._display = _;
348
+ if (this._element) {
349
+ this._element.style("display", this._display ? null : "none");
350
+ }
351
+ return this;
352
+ }
353
+
354
+ dataMeta(): DataMetaT;
355
+ dataMeta(_): this;
356
+ dataMeta(_?): DataMetaT | this {
357
+ if (!arguments.length) return this._dataMeta;
358
+ this._dataMeta = _;
359
+ return this;
360
+ }
361
+
362
+ private _appData = new Object({});
363
+ appData(key: string): any;
364
+ appData(key: string, value: any): this;
365
+ appData(key: string, value?: any): any | this {
366
+ if (arguments.length < 2) return this._appData[key];
367
+ this._appData[key] = value;
368
+ return this;
369
+ }
370
+
371
+ calcSnap(snapSize) {
372
+ function snap(x, gridSize) {
373
+ function snapDelta(x2, gridSize2) {
374
+ let dx = x2 % gridSize2;
375
+ if (Math.abs(dx) > gridSize2 - Math.abs(dx)) {
376
+ dx = (gridSize2 - Math.abs(dx)) * (dx < 0 ? 1 : -1);
377
+ }
378
+ return dx;
379
+ }
380
+ return x - snapDelta(x, gridSize);
381
+ }
382
+ const l = snap(this._pos.x - this._size.width / 2, snapSize);
383
+ const t = snap(this._pos.y - this._size.height / 2, snapSize);
384
+ const r = snap(this._pos.x + this._size.width / 2, snapSize);
385
+ const b = snap(this._pos.y + this._size.height / 2, snapSize);
386
+ const w = r - l;
387
+ const h = b - t;
388
+ return [{ x: l + w / 2, y: t + h / 2 }, { width: w, height: h }];
389
+ }
390
+
391
+ // DOM/SVG Node Helpers ---
392
+ toWidget(domNode): Widget | null {
393
+ if (!domNode) {
394
+ return null;
395
+ }
396
+ const element = d3Select(domNode);
397
+ if (element) {
398
+ const widget = element.datum();
399
+ if (widget && widget instanceof Widget) {
400
+ return widget;
401
+ }
402
+ }
403
+ return null;
404
+ }
405
+
406
+ parentOverlay() {
407
+ return null;
408
+ }
409
+
410
+ locateParentWidget(domNode?): Widget | null {
411
+ domNode = domNode || (this._target ? this._target.parentNode : null);
412
+ if (domNode) {
413
+ const widget = this.toWidget(domNode);
414
+ if (widget) {
415
+ return widget;
416
+ } else if (domNode.parentNode) {
417
+ return this.locateParentWidget(domNode.parentNode);
418
+ }
419
+ }
420
+ return null;
421
+ }
422
+
423
+ locateSVGNode(domNode): SVGSVGElement | null {
424
+ if (!domNode) {
425
+ return null;
426
+ }
427
+ if (domNode.tagName === "svg") {
428
+ return domNode;
429
+ }
430
+ return this.locateSVGNode(domNode.parentNode);
431
+ }
432
+
433
+ locateOverlayNode() {
434
+ let widget = this.locateParentWidget(this._target);
435
+ while (widget) {
436
+ const retVal = widget.parentOverlay();
437
+ if (retVal) {
438
+ return retVal;
439
+ }
440
+ widget = this.locateParentWidget(widget._target.parentNode);
441
+ }
442
+ return null;
443
+ }
444
+
445
+ locateAncestor(classID): Widget | null {
446
+ return this.locateClosestAncestor([classID]);
447
+ }
448
+
449
+ locateClosestAncestor(classIDArr): Widget | null {
450
+ let widget = this.locateParentWidget(this._target);
451
+ while (widget) {
452
+ if (classIDArr.indexOf(widget.classID()) !== -1) {
453
+ return widget;
454
+ }
455
+ widget = this.locateParentWidget(widget._target.parentNode);
456
+ }
457
+ return null;
458
+ }
459
+
460
+ getAbsolutePos(domNode, w, h) {
461
+ const root = this.locateSVGNode(domNode);
462
+ if (!root) {
463
+ return null;
464
+ }
465
+ let pos = root.createSVGPoint();
466
+ const ctm = domNode.getCTM();
467
+ pos = pos.matrixTransform(ctm);
468
+ const retVal: any = {
469
+ x: pos.x,
470
+ y: pos.y
471
+ };
472
+ if (w !== undefined && h !== undefined) {
473
+ let size = root.createSVGPoint();
474
+ size.x = w;
475
+ size.y = h;
476
+ size = size.matrixTransform(ctm);
477
+ retVal.width = size.x - pos.x;
478
+ retVal.height = size.y - pos.y;
479
+ }
480
+ return retVal;
481
+ }
482
+
483
+ hasOverlay() {
484
+ return this._overlayElement;
485
+ }
486
+
487
+ syncOverlay() {
488
+ if (this._size.width && this._size.height) {
489
+ const newPos = this.getAbsolutePos(this._overlayElement.node(), this._size.width, this._size.height);
490
+ if (newPos && (!this._prevPos || newPos.x !== this._prevPos.x || newPos.y !== this._prevPos.y || newPos.width !== this._prevPos.width || newPos.height !== this._prevPos.height)) {
491
+ const xScale = newPos.width / this._size.width;
492
+ const yScale = newPos.height / this._size.height;
493
+ this._placeholderElement
494
+ .style("left", newPos.x - (newPos.width / xScale) / 2 + "px")
495
+ .style("top", newPos.y - (newPos.height / yScale) / 2 + "px")
496
+ .style("width", newPos.width / xScale + "px")
497
+ .style("height", newPos.height / yScale + "px")
498
+ ;
499
+ const transform = "scale(" + xScale + "," + yScale + ")";
500
+ this._placeholderElement
501
+ .style("transform", transform)
502
+ .style("-moz-transform", transform)
503
+ .style("-ms-transform", transform)
504
+ .style("-webkit-transform", transform)
505
+ .style("-o-transform", transform)
506
+ ;
507
+ }
508
+ this._prevPos = newPos;
509
+ }
510
+ }
511
+
512
+ getBBox(refresh = false, round = false): BBox {
513
+ return {
514
+ x: 0,
515
+ y: 0,
516
+ width: 0,
517
+ height: 0
518
+ };
519
+ }
520
+
521
+ textSize(_text: string | string[], fontName: string = "Verdana", fontSize: number = 12, bold: boolean = false): Readonly<TextSize> {
522
+ return textSize(_text, fontName, fontSize, bold);
523
+ }
524
+
525
+ textRect(_text: string, fontName: string = "Verdana", fontSize: number = 12, bold: boolean = false): Readonly<TextRect> {
526
+ return textRect(_text, fontName, fontSize, bold);
527
+ }
528
+
529
+ element() {
530
+ return this._element;
531
+ }
532
+
533
+ node() {
534
+ return this._element.node();
535
+ }
536
+
537
+ target(): null | HTMLElement | SVGElement;
538
+ target(_: null | string | HTMLElement | SVGElement): this;
539
+ target(_?: null | string | HTMLElement | SVGElement): null | HTMLElement | SVGElement | this {
540
+ if (!arguments.length) return this._target;
541
+ if (this._target && _) {
542
+ throw new Error("Target can only be assigned once.");
543
+ }
544
+ if (_ === null) {
545
+ this._target = null;
546
+ if (this.renderCount()) {
547
+ this.exit();
548
+ }
549
+ } else if (typeof _ === "string") {
550
+ this._target = document.getElementById(_);
551
+ } else if (_ instanceof HTMLElement || _ instanceof SVGElement) {
552
+ this._target = _;
553
+ }
554
+ return this;
555
+ }
556
+
557
+ isDOMHidden(): boolean {
558
+ // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent
559
+ // Note: Will return false for visible===hidden (which is ok as it still takes up space on the page)
560
+ return this._isRootNode && this._placeholderElement.node().offsetParent === null;
561
+ }
562
+
563
+ hasSize() {
564
+ return !isNaN(this.width()) && !isNaN(this.height());
565
+ }
566
+
567
+ protected publishedWidgets(): Widget[] {
568
+ let widgets = [];
569
+ this.publishedProperties(true).forEach(function (meta) {
570
+ if (!meta.ext || meta.ext.render !== false) {
571
+ switch (meta.type) {
572
+ case "widget":
573
+ const widget = this[meta.id]();
574
+ if (widget) {
575
+ widgets.push(widget);
576
+ }
577
+ break;
578
+ case "widgetArray":
579
+ widgets = widgets.concat(this[meta.id]());
580
+ break;
581
+ }
582
+ }
583
+ }, this);
584
+ return widgets;
585
+ }
586
+
587
+ // Render ---
588
+ private _prevNow = 0;
589
+ render(callback?: (w: Widget) => void) {
590
+ if ((window as any).__hpcc_debug) {
591
+ const now = Date.now();
592
+ if (now - this._prevNow < 500) {
593
+ console.error("Double Render: " + (now - this._prevNow) + " - " + this.id() + " - " + this.classID());
594
+ }
595
+ this._prevNow = now;
596
+ }
597
+
598
+ callback = callback || function () { };
599
+ if (!this._placeholderElement || !this.visible() || this.isDOMHidden() || !this.hasSize()) {
600
+ callback(this);
601
+ return this;
602
+ }
603
+ if (this._placeholderElement) {
604
+ if (!this._tag)
605
+ throw new Error("No DOM tag specified");
606
+
607
+ const elements = this._placeholderElement.selectAll("#" + this._id).data([this], function (d) { return d._id; });
608
+ elements.enter().append(this._tag)
609
+ .classed(this._class, true)
610
+ .attr("id", this._id)
611
+ // .attr("opacity", 0.50) // Uncomment to debug position offsets ---
612
+ .each(function (context2) {
613
+ context2._element = d3Select(this);
614
+ context2.enter(this, context2._element);
615
+ if ((window as any).__hpcc_debug) {
616
+ context2.leakCheck(this);
617
+ }
618
+ })
619
+ .merge(elements)
620
+ .each(function (context2) {
621
+ const element = d3Select(this);
622
+ const classed = context2.classed();
623
+ for (const key in classed) {
624
+ element.classed(key, classed[key]);
625
+ }
626
+ context2.preUpdate(this, context2._element);
627
+ context2.update(this, context2._element);
628
+ context2.postUpdate(this, context2._element);
629
+ })
630
+ ;
631
+ elements.exit()
632
+ .each(function (context2) {
633
+ d3Select(this).datum(null);
634
+ context2.exit(this, context2._element);
635
+ })
636
+ .remove()
637
+ ;
638
+ this._renderCount++;
639
+ }
640
+
641
+ // ASync Render Contained Widgets ---
642
+ const widgets = this.publishedWidgets();
643
+
644
+ const context = this;
645
+ switch (widgets.length) {
646
+ case 0:
647
+ callback(this);
648
+ break;
649
+ case 1:
650
+ widgets[0].render(function () {
651
+ callback(context);
652
+ });
653
+ break;
654
+ default:
655
+ let renderCount = widgets.length;
656
+ widgets.forEach(function (widget, _idx) {
657
+ setTimeout(function () {
658
+ widget.render(function () {
659
+ if (--renderCount === 0) {
660
+ callback(context);
661
+ }
662
+ });
663
+ }, 0);
664
+ });
665
+ break;
666
+ }
667
+ return this;
668
+ }
669
+
670
+ renderPromise(): Promise<Widget> {
671
+ return new Promise((resolve, reject) => {
672
+ this.render((w: Widget) => {
673
+ resolve(w);
674
+ });
675
+ });
676
+ }
677
+
678
+ private _lazyRender = debounce(function (debouncedCallback?: (w: Widget) => void) {
679
+ this.render(debouncedCallback);
680
+ }, 100);
681
+
682
+ lazyRender(callback?: (w: Widget) => void): this {
683
+ this._lazyRender(callback);
684
+ return this;
685
+ }
686
+
687
+ animationFrameRender(): this {
688
+ if (requestAnimationFrame) {
689
+ requestAnimationFrame(() => {
690
+ this.render();
691
+ });
692
+ } else {
693
+ // Not a real replacement for requestAnimationFrame ---
694
+ this.renderPromise();
695
+ }
696
+ return this;
697
+ }
698
+
699
+ enter(_domNode: HTMLElement, _element) { }
700
+ preUpdate(_domNode: HTMLElement, _element) { }
701
+ update(_domNode: HTMLElement, _element) { }
702
+ postUpdate(_domNode: HTMLElement, _element) { }
703
+ exit(_domNode?: HTMLElement, _element?) {
704
+ this.publishedWidgets().forEach(w => w.target(null));
705
+ }
706
+ }
707
+ Widget.prototype._class += " common_Widget";
708
+
709
+ export interface Widget {
710
+ fields(): Field[];
711
+ fields(_: Field[]): this;
712
+ classed(classID: string): boolean;
713
+ classed(classID: string, _: boolean): this;
714
+ classed(): { [classID: string]: boolean };
715
+ classed(_: { [classID: string]: boolean }): this;
716
+ }
717
+
718
+ Widget._idSeed = "_w";
719
+
720
+ Widget.prototype.publishProxy("fields", "_db", "fields");
721
+ Widget.prototype.publish("classed", {}, "object", "HTML Classes", null, { tags: ["Private"] });
722
+ const origClassed = Widget.prototype.classed;
723
+ Widget.prototype.classed = function (this: Widget, str_obj?: string | { [classID: string]: boolean }, _?: boolean) {
724
+ if (typeof str_obj === "string") {
725
+ if (arguments.length === 1) return origClassed.call(this)[str_obj];
726
+ const classed = origClassed.call(this);
727
+ origClassed.call(this, { ...classed, [str_obj]: _ });
728
+ return this;
729
+ }
730
+ return origClassed.apply(this, arguments);
731
+ };