@hpcc-js/other 2.17.1 → 2.17.3

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 (46) hide show
  1. package/LICENSE +43 -43
  2. package/README.md +41 -41
  3. package/dist/index.es6.js +5 -5
  4. package/dist/index.es6.js.map +1 -1
  5. package/dist/index.js +5 -5
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.min.js +1 -1
  8. package/dist/index.min.js.map +1 -1
  9. package/package.json +5 -5
  10. package/src/Audio.ts +83 -83
  11. package/src/AutoCompleteText.css +21 -21
  12. package/src/AutoCompleteText.ts +124 -124
  13. package/src/CalendarHeatMap.css +26 -26
  14. package/src/CalendarHeatMap.ts +243 -243
  15. package/src/Comms.ts +1085 -1085
  16. package/src/ESP.ts +451 -451
  17. package/src/HPCCBadge.ts +220 -220
  18. package/src/HeatMap.ts +135 -135
  19. package/src/Html.css +5 -5
  20. package/src/Html.ts +44 -44
  21. package/src/IconList.css +3 -3
  22. package/src/IconList.ts +86 -86
  23. package/src/Legend.css +85 -85
  24. package/src/Legend.ts +220 -220
  25. package/src/MorphText.css +11 -11
  26. package/src/MorphText.ts +102 -102
  27. package/src/NestedTable.ts +51 -51
  28. package/src/Opportunity.css +80 -80
  29. package/src/Opportunity.ts +488 -488
  30. package/src/Paginator.css +120 -120
  31. package/src/Paginator.ts +164 -164
  32. package/src/Persist.ts +151 -151
  33. package/src/PropertyEditor.css +130 -130
  34. package/src/PropertyEditor.ts +750 -750
  35. package/src/RadioCheckbox.css +6 -6
  36. package/src/RadioCheckbox.ts +123 -123
  37. package/src/Select.css +7 -7
  38. package/src/Select.ts +120 -120
  39. package/src/Table.css +92 -92
  40. package/src/Table.ts +1050 -1050
  41. package/src/ThemeEditor.css +195 -195
  42. package/src/ThemeEditor.ts +744 -744
  43. package/src/__package__.ts +3 -3
  44. package/src/index.ts +23 -23
  45. package/types/__package__.d.ts +2 -2
  46. package/types-3.4/__package__.d.ts +2 -2
@@ -1,750 +1,750 @@
1
- import { HTMLWidget, Platform, PropertyExt, Widget } from "@hpcc-js/common";
2
- import { Grid } from "@hpcc-js/layout";
3
- import { local as d3Local, select as d3Select, selectAll as d3SelectAll } from "d3-selection";
4
- import * as Persist from "./Persist";
5
-
6
- import "../src/PropertyEditor.css";
7
-
8
- function hasProperties(type) {
9
- switch (type) {
10
- case "widget":
11
- case "widgetArray":
12
- case "propertyArray":
13
- return true;
14
- default:
15
- }
16
- return false;
17
- }
18
-
19
- export class PropertyEditor extends HTMLWidget {
20
- _widgetOrig;
21
- _parentPropertyEditor;
22
- _show_settings: boolean;
23
- _selectedItems;
24
- __meta_sorting;
25
- _watch;
26
- private _childPE = d3Local<PropertyEditor>();
27
-
28
- constructor() {
29
- super();
30
- this._parentPropertyEditor = null;
31
-
32
- this._tag = "div";
33
- this._show_settings = false;
34
- }
35
-
36
- parentPropertyEditor(_?: PropertyEditor): PropertyEditor {
37
- if (!arguments.length) return this._parentPropertyEditor;
38
- this._parentPropertyEditor = _;
39
- return this;
40
- }
41
-
42
- depth(): number {
43
- let retVal = 0;
44
- let parent = this.parentPropertyEditor();
45
- while (parent) {
46
- ++retVal;
47
- parent = parent.parentPropertyEditor();
48
- }
49
- return retVal;
50
- }
51
-
52
- _show_header = true;
53
- show_header(): boolean;
54
- show_header(_: boolean): PropertyEditor;
55
- show_header(_?: boolean): boolean | PropertyEditor {
56
- if (!arguments.length) {
57
- return this._show_header;
58
- }
59
- this._show_header = _;
60
- return this;
61
- }
62
-
63
- show_settings(): boolean;
64
- show_settings(_: boolean): PropertyEditor;
65
- show_settings(_?: boolean): boolean | PropertyEditor {
66
- if (!arguments.length) {
67
- return this._show_settings;
68
- }
69
- this._show_settings = _;
70
- return this;
71
- }
72
-
73
- rootWidgets() {
74
- if (this._selectedItems && this._selectedItems.length) {
75
- return this._selectedItems;
76
- }
77
- return this.show_settings() ? [this] : this.widget() ? [this.widget()] : [];
78
- }
79
-
80
- update(domNode, element) {
81
- super.update(domNode, element);
82
-
83
- const context = this;
84
-
85
- const rootWidgets = this.rootWidgets().filter(function (w) {
86
- if (w._owningWidget && w._owningWidget.excludeObjs instanceof Array) {
87
- if (w._owningWidget.excludeObjs.indexOf(w.classID()) !== -1) {
88
- return false;
89
- }
90
- }
91
- return true;
92
- });
93
-
94
- const table = element.selectAll(`table.property-table.table-${this.depth()}`).data(rootWidgets, function (d) {
95
- // We reuse the existing DOM Nodes and this node _might_ have been a regular Input previously ---
96
- if (typeof d.id !== "function") {
97
- return `meta-${d.id}`;
98
- }
99
- return d.id();
100
- });
101
- table.enter().append("table")
102
- .attr("class", `property-table table-${this.depth()}`)
103
- .each(function () {
104
- const tableElement = d3Select(this);
105
-
106
- // Header ---
107
- if (context._show_header && context.parentPropertyEditor() === null) {
108
- tableElement.append("thead").append("tr").append("th")// .datum(tableElement)
109
- .attr("colspan", "2")
110
- .each(function () {
111
- context.enterHeader(d3Select(this));
112
- })
113
- ;
114
- }
115
-
116
- // Body ---
117
- tableElement.append("tbody");
118
- })
119
- .merge(table)
120
- .each(function (tableData) {
121
- const tableElement = d3Select(this);
122
-
123
- // Header ---
124
- if (context._show_header && context.parentPropertyEditor() === null) {
125
- context.updateHeader(tableElement.select("thead > tr > th"));
126
- }
127
-
128
- // Body ---
129
- context.renderInputs(tableElement.select("tbody"), tableData);
130
- })
131
- ;
132
- table.exit()
133
- .each(function () {
134
- context.renderInputs(element.select("tbody"), null);
135
- })
136
- .remove()
137
- ;
138
- }
139
-
140
- exit(domNode, element) {
141
- super.exit(domNode, element);
142
- this.watchWidget(null);
143
- }
144
-
145
- private watchDepth = 0;
146
- watchWidget(widget) {
147
- if (this._watch) {
148
- if ((window as any).__hpcc_debug) {
149
- --this.watchDepth;
150
- console.info("watchDepth: " + this.watchDepth);
151
- }
152
- this._watch.remove();
153
- delete this._watch;
154
- }
155
- if (widget) {
156
- const context = this;
157
- this._watch = widget.monitor(function (_paramId, newVal, oldVal) {
158
- if (oldVal !== newVal) {
159
- const propEditor = context.parentPropertyEditor() || context;
160
- propEditor.lazyRender();
161
- }
162
- });
163
- if ((window as any).__hpcc_debug) {
164
- ++this.watchDepth;
165
- console.info("watchDepth: " + this.watchDepth);
166
- }
167
- }
168
- }
169
-
170
- enterHeader(th) {
171
- const context = this;
172
-
173
- th.append("span");
174
- th.append("i")
175
- .attr("class", "expandIcon fa")
176
- .on("click", function () {
177
- switch (context.peInputIcon()) {
178
- case "fa-caret-up":
179
- case "fa-caret-right":
180
- context.element().selectAll(`.table-${context.depth()} > tbody > tr > .headerRow > .peInput > .property-table-collapsed`)
181
- .classed("property-table-collapsed", false)
182
- ;
183
- context.element().selectAll(`.table-${context.depth()} > tbody > tr > .headerRow > .peInput > i`)
184
- .classed("fa-minus-square-o", true)
185
- .classed("fa-plus-square-o", false)
186
- ;
187
- break;
188
- case "fa-caret-down":
189
- context.element().selectAll(`.table-${context.depth()} > tbody > tr > .headerRow > .peInput > div`)
190
- .classed("property-table-collapsed", true)
191
- ;
192
- context.element().selectAll(`.table-${context.depth()} > tbody > tr > .headerRow > .peInput > i`)
193
- .classed("fa-minus-square-o", false)
194
- .classed("fa-plus-square-o", true)
195
- ;
196
- break;
197
- }
198
- context.refreshExpandIcon();
199
- })
200
- ;
201
-
202
- const sortIcon = th.append("i")
203
- .attr("class", "sortIcon fa")
204
- .on("click", function () {
205
- context.refreshSortIcon(sortIcon, true);
206
- })
207
- ;
208
-
209
- th.append("i")
210
- .attr("class", "hideParamsIcon fa")
211
- .on("click", function () {
212
- context.hideNonWidgets(!context.hideNonWidgets()).render();
213
- })
214
- ;
215
- }
216
-
217
- updateHeader(th) {
218
- const widget: any = this.widget();
219
- let spanText = "";
220
- if (widget) {
221
- if (widget.label) {
222
- spanText += widget.label();
223
- }
224
- if (widget.classID) {
225
- if (spanText) {
226
- spanText += " - ";
227
- }
228
- spanText += widget.classID();
229
- }
230
- }
231
- th.select("span")
232
- .text(spanText)
233
- ;
234
- this.refreshExpandIcon();
235
- this.refreshSortIcon(th.select(".sortIcon"));
236
- this.refreshHideParamsIcon(th.select(".hideParamsIcon"));
237
- }
238
-
239
- peInputCount() {
240
- return this.element().selectAll(`.table-${this.depth()} > tbody > tr > .headerRow > .peInput > div`).size();
241
- }
242
-
243
- peInputCollapsedCount() {
244
- return this.element().selectAll(`.table-${this.depth()} > tbody > tr > .headerRow > .peInput > div.property-table-collapsed`).size();
245
- }
246
-
247
- peInputIcon(): "fa-caret-down" | "fa-caret-up" | "fa-caret-right" {
248
- const collapsed = this.peInputCollapsedCount();
249
- if (collapsed === 0) {
250
- return "fa-caret-down";
251
- } else if (collapsed === this.peInputCount()) {
252
- return "fa-caret-up";
253
- }
254
- return "fa-caret-right";
255
- }
256
-
257
- refreshExpandIcon() {
258
- const newIcon = this.peInputIcon();
259
- this.element().select(`.table-${this.depth()} > thead > tr > th > .expandIcon`)
260
- .classed("fa-caret-up", false)
261
- .classed("fa-caret-right", false)
262
- .classed("fa-caret-down", false)
263
- .classed(newIcon, true)
264
- ;
265
- }
266
-
267
- refreshSortIcon(sortIcon, increment = false) {
268
- const sort = this.sorting();
269
- const types = this.sorting_options();
270
- const icons = this.__meta_sorting.ext.icons;
271
- if (increment) {
272
- sortIcon.classed(icons[types.indexOf(sort)], false);
273
- this.sorting(types[(types.indexOf(sort) + 1) % types.length]).render();
274
- } else {
275
- sortIcon
276
- .classed(icons[(types.indexOf(sort)) % types.length], true)
277
- .attr("title", sort)
278
- ;
279
- }
280
- }
281
-
282
- refreshHideParamsIcon(hideParamsIcon) {
283
- hideParamsIcon
284
- .classed("fa-eye", !this.hideNonWidgets())
285
- .classed("fa-eye-slash", this.hideNonWidgets())
286
- ;
287
- }
288
-
289
- gatherDataTree(widget) {
290
- if (!widget) return null;
291
- const retVal = {
292
- label: widget.id() + " (" + widget.classID() + ")",
293
- children: []
294
- };
295
- const arr2 = Persist.discover(widget);
296
- arr2.forEach(function (prop) {
297
- const node = {
298
- label: prop.id,
299
- children: []
300
- };
301
- switch (prop.type) {
302
- case "widget":
303
- node.children.push(this.gatherDataTree(widget[prop.id]()));
304
- break;
305
- case "widgetArray":
306
- case "propertyArray":
307
- const arr = widget[prop.id]();
308
- if (arr) {
309
- arr.forEach(function (item) {
310
- node.children.push(this.gatherDataTree(item));
311
- }, this);
312
- }
313
- break;
314
- default:
315
- }
316
- retVal.children.push(node);
317
- }, this);
318
- return retVal;
319
- }
320
-
321
- getDataTree() {
322
- return this.gatherDataTree(this.widget());
323
- }
324
-
325
- _rowSorting(paramArr) {
326
- if (this.sorting() === "type") {
327
- const typeOrder = ["boolean", "number", "string", "html-color", "array", "object", "widget", "widgetArray", "propertyArray"];
328
- paramArr.sort(function (a, b) {
329
- if (a.type === b.type) {
330
- return a.id < b.id ? -1 : 1;
331
- } else {
332
- return typeOrder.indexOf(a.type) < typeOrder.indexOf(b.type) ? -1 : 1;
333
- }
334
- });
335
- } else if (this.sorting() === "A-Z") {
336
- paramArr.sort(function (a, b) { return a.id < b.id ? -1 : 1; });
337
- } else if (this.sorting() === "Z-A") {
338
- paramArr.sort(function (a, b) { return a.id > b.id ? -1 : 1; });
339
- }
340
- }
341
-
342
- filterInputs(d) {
343
- const discArr = Persist.discover(d);
344
- if ((this.filterTags() || this.excludeTags().length > 0 || this.excludeParams.length > 0) && d instanceof PropertyEditor === false) {
345
- const context = this;
346
- return discArr.filter(function (param, _idx) {
347
- if (d[param.id + "_hidden"] && d[param.id + "_hidden"]()) return false;
348
- for (const excludeParamItem of context.excludeParams()) {
349
- const arr = excludeParamItem.split(".");
350
- let widgetName;
351
- let excludeParam;
352
- if (arr.length > 2) {
353
- widgetName = arr[0];
354
- excludeParam = arr[2];
355
- } else {
356
- widgetName = arr[0];
357
- excludeParam = arr[1];
358
- }
359
- if (d.class().indexOf(widgetName) !== -1) {
360
- if (param.id === excludeParam) {
361
- return false;
362
- }
363
- return true;
364
- }
365
- }
366
- if (context.excludeTags().length > 0 && param.ext && param.ext.tags && param.ext.tags.some(function (item) { return (context.excludeTags().indexOf(item) > -1); })) {
367
- return false;
368
- }
369
- if ((context.filterTags() && param.ext && param.ext.tags && param.ext.tags.indexOf(context.filterTags()) !== -1) || !context.filterTags()) {
370
- return true;
371
- }
372
- return false;
373
- });
374
- }
375
- return discArr;
376
- }
377
-
378
- renderInputs(element, d) {
379
- const context = this;
380
- let discArr = [];
381
- const showFields = !this.show_settings() && this.showFields();
382
- if (d) {
383
- discArr = this.filterInputs(d).filter(function (prop) { return prop.id !== "fields" ? true : showFields; });
384
- if (!this.show_settings() && this.showData() && d.data) {
385
- discArr.push({ id: "data", type: "array" });
386
- }
387
- if (this.hideNonWidgets()) {
388
- discArr = discArr.filter(function (n) {
389
- return hasProperties(n.type);
390
- });
391
- }
392
- this._rowSorting(discArr);
393
- }
394
-
395
- const rows = element.selectAll("tr.prop" + this.id()).data(discArr, function (d2) { return d2.id; });
396
- rows.enter().append("tr")
397
- .attr("class", "property-wrapper prop" + this.id())
398
- .each(function (param) {
399
- const tr = d3Select(this);
400
- if (hasProperties(param.type)) {
401
- tr.classed("property-widget-wrapper", true);
402
- tr.append("td")
403
- .attr("colspan", "2")
404
- ;
405
- } else {
406
- tr.classed("property-input-wrapper", true);
407
- tr.append("td")
408
- .classed("property-label", true)
409
- .text(param.id)
410
- ;
411
- const inputCell = tr.append("td")
412
- .classed("property-input-cell", true)
413
- ;
414
- context.enterInputs(d, inputCell, param);
415
- }
416
- }).merge(rows)
417
- .each(function (param) {
418
- const tr = d3Select(this);
419
- tr.classed("disabled", d[param.id + "_disabled"] && d[param.id + "_disabled"]());
420
- tr.classed("invalid", d[param.id + "_valid"] && !d[param.id + "_valid"]());
421
- tr.attr("title", param.description);
422
- if (hasProperties(param.type)) {
423
- context.updateWidgetRow(d, tr.select("td"), param);
424
- } else {
425
- context.updateInputs(d, param);
426
- }
427
- });
428
- rows.exit().each(function (param) {
429
- const tr = d3Select(this);
430
- if (hasProperties(param.type)) {
431
- context.updateWidgetRow(d, tr.select("td"), null);
432
- }
433
- }).remove();
434
- rows.order();
435
- }
436
-
437
- updateWidgetRow(widget: PropertyExt, element, param) {
438
- let tmpWidget = [];
439
- if (widget && param) {
440
- tmpWidget = widget[param.id]() || [];
441
- }
442
- let widgetArr = tmpWidget instanceof Array ? tmpWidget : [tmpWidget];
443
- if (param && param.ext && param.ext.autoExpand) {
444
- // remove empties and ensure last row is an empty ---
445
- let lastModified = true;
446
- const noEmpties = widgetArr.filter(function (row, idx) {
447
- lastModified = row.valid();
448
- row._owner = widget;
449
- return lastModified || idx === widgetArr.length - 1;
450
- }, this);
451
- const widgetDisabled = widget[param.id + "_disabled"] && widget[param.id + "_disabled"]();
452
- let changed = !!(widgetArr.length - noEmpties.length);
453
- if (lastModified && !widgetDisabled) {
454
- changed = true;
455
- const autoExpandWidget = new param.ext.autoExpand()
456
- .owner(widget)
457
- ;
458
- // autoExpandWidget.monitor((id, newVal, oldVal, source) => {
459
- // widget.broadcast(param.id, newVal, oldVal, source);
460
- // });
461
- noEmpties.push(autoExpandWidget);
462
- }
463
- if (changed) {
464
- widget[param.id](noEmpties);
465
- widgetArr = noEmpties;
466
- }
467
- }
468
-
469
- const context = this;
470
- element.classed("headerRow", true);
471
- const peInput = element.selectAll(`div.peInput-${this.depth()}`).data(widgetArr, function (d) { return d.id(); });
472
- peInput.enter().append("div")
473
- .attr("class", `peInput peInput-${this.depth()}`)
474
- .each(function (w) {
475
- const peInputElement = d3Select(this);
476
-
477
- // Header ---
478
- peInputElement.append("span");
479
- peInputElement.append("i")
480
- .attr("class", "fa")
481
- .on("click", function (d) {
482
- const clickTarget = peInputElement.select("div");
483
- clickTarget
484
- .classed("property-table-collapsed", !clickTarget.classed("property-table-collapsed"))
485
- ;
486
- d3Select(this)
487
- .classed("fa-minus-square-o", !clickTarget.classed("property-table-collapsed"))
488
- .classed("fa-plus-square-o", clickTarget.classed("property-table-collapsed"))
489
- ;
490
- context.refreshExpandIcon();
491
- })
492
- ;
493
-
494
- // Body ---
495
- const peDiv = peInputElement.append("div")
496
- // .attr("class", `property- input - cell propEditor-${context.depth() }`)
497
- ;
498
- context._childPE.set(this, new PropertyEditor().label(param.id).target(peDiv.node() as HTMLElement));
499
- })
500
- .merge(peInput)
501
- .each(function (w) {
502
- const peInputElement = d3Select(this);
503
- const clickTarget = peInputElement.select("div");
504
-
505
- // Header ---
506
- d3Select(this).select("span")
507
- .text(`${param.id}`)
508
- ;
509
-
510
- d3Select(this).select("i")
511
- .classed("fa-minus-square-o", !clickTarget.classed("property-table-collapsed"))
512
- .classed("fa-plus-square-o", clickTarget.classed("property-table-collapsed"))
513
- ;
514
-
515
- // Body ---
516
- context._childPE.get(this)
517
- .parentPropertyEditor(context)
518
- .showFields(context.showFields())
519
- .showData(context.showData())
520
- .sorting(context.sorting())
521
- .filterTags(context.filterTags())
522
- .excludeTags(context.excludeTags())
523
- .excludeParams(context.excludeParams())
524
- .hideNonWidgets(context.hideNonWidgets() && w._class.indexOf("layout_") >= 0)
525
- .widget(w)
526
- .render()
527
- ;
528
- })
529
- ;
530
- peInput.exit()
531
- .each(function (w) {
532
- context._childPE.get(this)
533
- .widget(null)
534
- .render()
535
- .target(null)
536
- ;
537
- context._childPE.remove(this);
538
- })
539
- .remove()
540
- ;
541
- }
542
-
543
- setProperty(widget, id, value) {
544
- // With PropertyExt not all "widgets" have a render, if not use top most render...
545
- let topWidget: Widget;
546
- let topPropEditor: Widget;
547
- let propEditor: PropertyEditor = this;
548
- let oldValue;
549
- while (propEditor && widget) {
550
- if (propEditor === this) {
551
- oldValue = widget[id]();
552
- widget[id](value);
553
- }
554
- if (propEditor) {
555
- topPropEditor = propEditor;
556
- const w: PropertyExt = propEditor.widget();
557
- if (w instanceof Widget) {
558
- topWidget = w;
559
- }
560
- }
561
- propEditor = propEditor.parentPropertyEditor();
562
- }
563
- if (topWidget) {
564
- topWidget.render();
565
- }
566
- if (topPropEditor) {
567
- topPropEditor.broadcast(id, value, oldValue, widget);
568
- }
569
- }
570
-
571
- enterInputs(widget, cell, param) {
572
- cell.classed(param.type + "-cell", true);
573
- const context = this;
574
- if (typeof (param.ext.editor_input) === "function") {
575
- param.ext.editor_input(this, widget, cell, param);
576
- }
577
- switch (param.type) {
578
- case "boolean":
579
- cell.append("input")
580
- .attr("id", this.id() + "_" + param.id)
581
- .classed("property-input", true)
582
- .attr("type", "checkbox")
583
- .on("change", function () {
584
- context.setProperty(widget, param.id, this.checked);
585
- })
586
- ;
587
- break;
588
- case "set":
589
- cell.append("select")
590
- .attr("id", this.id() + "_" + param.id)
591
- .classed("property-input", true)
592
- .on("change", function () {
593
- context.setProperty(widget, param.id, this.value);
594
- })
595
- ;
596
- break;
597
- case "array":
598
- case "object":
599
- cell.append("textarea")
600
- .attr("id", this.id() + "_" + param.id)
601
- .classed("property-input", true)
602
- .attr("autocomplete", "off")
603
- .attr("autocorrect", "off")
604
- .attr("autocapitalize", "off")
605
- .attr("spellcheck", "false")
606
- .on("change", function () {
607
- let value;
608
- try {
609
- value = JSON.parse(this.value);
610
- } catch (e) {
611
- value = this.value;
612
- }
613
- context.setProperty(widget, param.id, value);
614
- })
615
- ;
616
- break;
617
- default:
618
- if (param.ext && param.ext.range) {
619
- cell.append("span")
620
- .classed("property-input-span", true)
621
- .attr("id", this.id() + "_" + param.id + "_currentVal")
622
- .text(param.defaultValue)
623
- ;
624
- cell.append("input")
625
- .attr("type", "range")
626
- .attr("step", param.ext.range.step)
627
- .attr("min", param.ext.range.min)
628
- .attr("max", param.ext.range.max)
629
- .attr("id", this.id() + "_" + param.id)
630
- .classed("property-input", true)
631
- .on("input", function () {
632
- context.setProperty(widget, param.id, this.value);
633
- d3Select("#" + this.id + "_currentVal").text("Current Value: " + this.value);
634
- })
635
- .on("change", function () {
636
- context.setProperty(widget, param.id, this.value);
637
- d3Select("#" + this.id + "_currentVal").text("Current Value: " + this.value);
638
- })
639
- ;
640
- } else {
641
- cell.append(param.ext && param.ext.multiline ? "textarea" : "input")
642
- .attr("id", this.id() + "_" + param.id)
643
- .classed("property-input", true)
644
- .attr("autocomplete", "off")
645
- .attr("autocorrect", "off")
646
- .attr("autocapitalize", "off")
647
- .attr("spellcheck", "false")
648
- .on("change", function () {
649
- context.setProperty(widget, param.id, this.value);
650
- })
651
- ;
652
- if (param.type === "html-color" && !Platform.isIE) {
653
- cell.append("input")
654
- .attr("id", this.id() + "_" + param.id + "_2")
655
- .classed("property-input", true)
656
- .attr("type", "color")
657
- .on("change", function () {
658
- context.setProperty(widget, param.id, this.value);
659
- })
660
- ;
661
- }
662
- }
663
- break;
664
- }
665
- }
666
-
667
- updateInputs(widget, param) {
668
- const element = d3SelectAll("#" + this.id() + "_" + param.id + ", #" + this.id() + "_" + param.id + "_2");
669
- const val = widget ? widget[param.id]() : "";
670
- element.property("disabled", widget[param.id + "_disabled"] && widget[param.id + "_disabled"]());
671
- element.property("invalid", widget[param.id + "_valid"] && !widget[param.id + "_valid"]());
672
- switch (param.type) {
673
- case "boolean":
674
- element.property("checked", val);
675
- break;
676
- case "set":
677
- const options = element.selectAll("option").data<string | { value: string, text: string }>(widget[param.id + "_options"]());
678
- options.enter().append("option")
679
- .merge(options as any)
680
- .attr("value", (d: any) => (d && d.value !== undefined) ? d.value : d)
681
- .text((d: any) => (d && d.text !== undefined) ? d.text : d)
682
- ;
683
- options.exit().remove();
684
- element.property("value", val);
685
- break;
686
- case "array":
687
- case "object":
688
- element.property("value", JSON.stringify(val, function replacer(_key, value) {
689
- if (value instanceof Widget) {
690
- return Persist.serialize(value);
691
- }
692
- return value;
693
- }, " "));
694
- break;
695
- default:
696
- if (param.ext && param.ext.range) {
697
- d3Select("#" + this.id() + "_" + param.id + "_currentVal").text("Current Value: " + val);
698
- }
699
- element.property("value", val && val.length && val.length > 100000 ? "...too big to display..." : val);
700
- break;
701
- }
702
- }
703
-
704
- showFields: { (): boolean; (_: boolean): PropertyEditor; };
705
- showData: { (): boolean; (_: boolean): PropertyEditor; };
706
-
707
- sorting: { (): string; (_: string): PropertyEditor; };
708
- sorting_options: () => string[];
709
-
710
- hideNonWidgets: { (): boolean; (_: boolean): PropertyEditor; };
711
-
712
- label: { (): string; (_: string): PropertyEditor; };
713
- filterTags: { (): string; (_: string): PropertyEditor; };
714
- excludeTags: { (): string[]; (_: string[]): PropertyEditor; };
715
- excludeParams: { (): string[]; (_: string[]): PropertyEditor; };
716
-
717
- widget: { (): PropertyExt; (_: PropertyExt): PropertyEditor };
718
- }
719
- PropertyEditor.prototype._class += " other_PropertyEditor";
720
-
721
- PropertyEditor.prototype.publish("showFields", false, "boolean", "If true, widget.fields() will display as if it was a publish parameter.", null, { tags: ["Basic"] });
722
- PropertyEditor.prototype.publish("showData", false, "boolean", "If true, widget.data() will display as if it was a publish parameter.", null, { tags: ["Basic"] });
723
-
724
- PropertyEditor.prototype.publish("sorting", "none", "set", "Specify the sorting type", ["none", "A-Z", "Z-A", "type"], { tags: ["Basic"], icons: ["fa-sort", "fa-sort-alpha-asc", "fa-sort-alpha-desc", "fa-sort-amount-asc"] });
725
-
726
- PropertyEditor.prototype.publish("hideNonWidgets", false, "boolean", "Hides non-widget params (at this tier only)", null, { tags: ["Basic"] });
727
-
728
- PropertyEditor.prototype.publish("label", "", "string", "Label to display in header of property editor table", null, { tags: ["Basic"] });
729
- PropertyEditor.prototype.publish("filterTags", "", "set", "Only show Publish Params of this type", ["Basic", "Intermediate", "Advance", ""], {});
730
- PropertyEditor.prototype.publish("excludeTags", ["Private"], "array", "Exclude this array of tags", null, {});
731
- PropertyEditor.prototype.publish("excludeParams", [], "array", "Exclude this array of params (widget.param)", null, {});
732
-
733
- PropertyEditor.prototype.publish("widget", null, "widget", "Widget", null, { tags: ["Basic"], render: false });
734
-
735
- const _widgetOrig = PropertyEditor.prototype.widget;
736
- (PropertyEditor.prototype as any).widget = function (_?: Widget): Widget | PropertyEditor {
737
- if (arguments.length && _widgetOrig.call(this) === _) return this;
738
- const retVal = _widgetOrig.apply(this, arguments);
739
- if (arguments.length) {
740
- this.watchWidget(_);
741
- if (_ instanceof Grid) {
742
- const context = this;
743
- _.postSelectionChange = function () {
744
- context._selectedItems = _._selectionBag.get().map(function (item) { return item.widget; });
745
- context.lazyRender();
746
- };
747
- }
748
- }
749
- return retVal;
750
- };
1
+ import { HTMLWidget, Platform, PropertyExt, Widget } from "@hpcc-js/common";
2
+ import { Grid } from "@hpcc-js/layout";
3
+ import { local as d3Local, select as d3Select, selectAll as d3SelectAll } from "d3-selection";
4
+ import * as Persist from "./Persist";
5
+
6
+ import "../src/PropertyEditor.css";
7
+
8
+ function hasProperties(type) {
9
+ switch (type) {
10
+ case "widget":
11
+ case "widgetArray":
12
+ case "propertyArray":
13
+ return true;
14
+ default:
15
+ }
16
+ return false;
17
+ }
18
+
19
+ export class PropertyEditor extends HTMLWidget {
20
+ _widgetOrig;
21
+ _parentPropertyEditor;
22
+ _show_settings: boolean;
23
+ _selectedItems;
24
+ __meta_sorting;
25
+ _watch;
26
+ private _childPE = d3Local<PropertyEditor>();
27
+
28
+ constructor() {
29
+ super();
30
+ this._parentPropertyEditor = null;
31
+
32
+ this._tag = "div";
33
+ this._show_settings = false;
34
+ }
35
+
36
+ parentPropertyEditor(_?: PropertyEditor): PropertyEditor {
37
+ if (!arguments.length) return this._parentPropertyEditor;
38
+ this._parentPropertyEditor = _;
39
+ return this;
40
+ }
41
+
42
+ depth(): number {
43
+ let retVal = 0;
44
+ let parent = this.parentPropertyEditor();
45
+ while (parent) {
46
+ ++retVal;
47
+ parent = parent.parentPropertyEditor();
48
+ }
49
+ return retVal;
50
+ }
51
+
52
+ _show_header = true;
53
+ show_header(): boolean;
54
+ show_header(_: boolean): PropertyEditor;
55
+ show_header(_?: boolean): boolean | PropertyEditor {
56
+ if (!arguments.length) {
57
+ return this._show_header;
58
+ }
59
+ this._show_header = _;
60
+ return this;
61
+ }
62
+
63
+ show_settings(): boolean;
64
+ show_settings(_: boolean): PropertyEditor;
65
+ show_settings(_?: boolean): boolean | PropertyEditor {
66
+ if (!arguments.length) {
67
+ return this._show_settings;
68
+ }
69
+ this._show_settings = _;
70
+ return this;
71
+ }
72
+
73
+ rootWidgets() {
74
+ if (this._selectedItems && this._selectedItems.length) {
75
+ return this._selectedItems;
76
+ }
77
+ return this.show_settings() ? [this] : this.widget() ? [this.widget()] : [];
78
+ }
79
+
80
+ update(domNode, element) {
81
+ super.update(domNode, element);
82
+
83
+ const context = this;
84
+
85
+ const rootWidgets = this.rootWidgets().filter(function (w) {
86
+ if (w._owningWidget && w._owningWidget.excludeObjs instanceof Array) {
87
+ if (w._owningWidget.excludeObjs.indexOf(w.classID()) !== -1) {
88
+ return false;
89
+ }
90
+ }
91
+ return true;
92
+ });
93
+
94
+ const table = element.selectAll(`table.property-table.table-${this.depth()}`).data(rootWidgets, function (d) {
95
+ // We reuse the existing DOM Nodes and this node _might_ have been a regular Input previously ---
96
+ if (typeof d.id !== "function") {
97
+ return `meta-${d.id}`;
98
+ }
99
+ return d.id();
100
+ });
101
+ table.enter().append("table")
102
+ .attr("class", `property-table table-${this.depth()}`)
103
+ .each(function () {
104
+ const tableElement = d3Select(this);
105
+
106
+ // Header ---
107
+ if (context._show_header && context.parentPropertyEditor() === null) {
108
+ tableElement.append("thead").append("tr").append("th")// .datum(tableElement)
109
+ .attr("colspan", "2")
110
+ .each(function () {
111
+ context.enterHeader(d3Select(this));
112
+ })
113
+ ;
114
+ }
115
+
116
+ // Body ---
117
+ tableElement.append("tbody");
118
+ })
119
+ .merge(table)
120
+ .each(function (tableData) {
121
+ const tableElement = d3Select(this);
122
+
123
+ // Header ---
124
+ if (context._show_header && context.parentPropertyEditor() === null) {
125
+ context.updateHeader(tableElement.select("thead > tr > th"));
126
+ }
127
+
128
+ // Body ---
129
+ context.renderInputs(tableElement.select("tbody"), tableData);
130
+ })
131
+ ;
132
+ table.exit()
133
+ .each(function () {
134
+ context.renderInputs(element.select("tbody"), null);
135
+ })
136
+ .remove()
137
+ ;
138
+ }
139
+
140
+ exit(domNode, element) {
141
+ super.exit(domNode, element);
142
+ this.watchWidget(null);
143
+ }
144
+
145
+ private watchDepth = 0;
146
+ watchWidget(widget) {
147
+ if (this._watch) {
148
+ if ((window as any).__hpcc_debug) {
149
+ --this.watchDepth;
150
+ console.info("watchDepth: " + this.watchDepth);
151
+ }
152
+ this._watch.remove();
153
+ delete this._watch;
154
+ }
155
+ if (widget) {
156
+ const context = this;
157
+ this._watch = widget.monitor(function (_paramId, newVal, oldVal) {
158
+ if (oldVal !== newVal) {
159
+ const propEditor = context.parentPropertyEditor() || context;
160
+ propEditor.lazyRender();
161
+ }
162
+ });
163
+ if ((window as any).__hpcc_debug) {
164
+ ++this.watchDepth;
165
+ console.info("watchDepth: " + this.watchDepth);
166
+ }
167
+ }
168
+ }
169
+
170
+ enterHeader(th) {
171
+ const context = this;
172
+
173
+ th.append("span");
174
+ th.append("i")
175
+ .attr("class", "expandIcon fa")
176
+ .on("click", function () {
177
+ switch (context.peInputIcon()) {
178
+ case "fa-caret-up":
179
+ case "fa-caret-right":
180
+ context.element().selectAll(`.table-${context.depth()} > tbody > tr > .headerRow > .peInput > .property-table-collapsed`)
181
+ .classed("property-table-collapsed", false)
182
+ ;
183
+ context.element().selectAll(`.table-${context.depth()} > tbody > tr > .headerRow > .peInput > i`)
184
+ .classed("fa-minus-square-o", true)
185
+ .classed("fa-plus-square-o", false)
186
+ ;
187
+ break;
188
+ case "fa-caret-down":
189
+ context.element().selectAll(`.table-${context.depth()} > tbody > tr > .headerRow > .peInput > div`)
190
+ .classed("property-table-collapsed", true)
191
+ ;
192
+ context.element().selectAll(`.table-${context.depth()} > tbody > tr > .headerRow > .peInput > i`)
193
+ .classed("fa-minus-square-o", false)
194
+ .classed("fa-plus-square-o", true)
195
+ ;
196
+ break;
197
+ }
198
+ context.refreshExpandIcon();
199
+ })
200
+ ;
201
+
202
+ const sortIcon = th.append("i")
203
+ .attr("class", "sortIcon fa")
204
+ .on("click", function () {
205
+ context.refreshSortIcon(sortIcon, true);
206
+ })
207
+ ;
208
+
209
+ th.append("i")
210
+ .attr("class", "hideParamsIcon fa")
211
+ .on("click", function () {
212
+ context.hideNonWidgets(!context.hideNonWidgets()).render();
213
+ })
214
+ ;
215
+ }
216
+
217
+ updateHeader(th) {
218
+ const widget: any = this.widget();
219
+ let spanText = "";
220
+ if (widget) {
221
+ if (widget.label) {
222
+ spanText += widget.label();
223
+ }
224
+ if (widget.classID) {
225
+ if (spanText) {
226
+ spanText += " - ";
227
+ }
228
+ spanText += widget.classID();
229
+ }
230
+ }
231
+ th.select("span")
232
+ .text(spanText)
233
+ ;
234
+ this.refreshExpandIcon();
235
+ this.refreshSortIcon(th.select(".sortIcon"));
236
+ this.refreshHideParamsIcon(th.select(".hideParamsIcon"));
237
+ }
238
+
239
+ peInputCount() {
240
+ return this.element().selectAll(`.table-${this.depth()} > tbody > tr > .headerRow > .peInput > div`).size();
241
+ }
242
+
243
+ peInputCollapsedCount() {
244
+ return this.element().selectAll(`.table-${this.depth()} > tbody > tr > .headerRow > .peInput > div.property-table-collapsed`).size();
245
+ }
246
+
247
+ peInputIcon(): "fa-caret-down" | "fa-caret-up" | "fa-caret-right" {
248
+ const collapsed = this.peInputCollapsedCount();
249
+ if (collapsed === 0) {
250
+ return "fa-caret-down";
251
+ } else if (collapsed === this.peInputCount()) {
252
+ return "fa-caret-up";
253
+ }
254
+ return "fa-caret-right";
255
+ }
256
+
257
+ refreshExpandIcon() {
258
+ const newIcon = this.peInputIcon();
259
+ this.element().select(`.table-${this.depth()} > thead > tr > th > .expandIcon`)
260
+ .classed("fa-caret-up", false)
261
+ .classed("fa-caret-right", false)
262
+ .classed("fa-caret-down", false)
263
+ .classed(newIcon, true)
264
+ ;
265
+ }
266
+
267
+ refreshSortIcon(sortIcon, increment = false) {
268
+ const sort = this.sorting();
269
+ const types = this.sorting_options();
270
+ const icons = this.__meta_sorting.ext.icons;
271
+ if (increment) {
272
+ sortIcon.classed(icons[types.indexOf(sort)], false);
273
+ this.sorting(types[(types.indexOf(sort) + 1) % types.length]).render();
274
+ } else {
275
+ sortIcon
276
+ .classed(icons[(types.indexOf(sort)) % types.length], true)
277
+ .attr("title", sort)
278
+ ;
279
+ }
280
+ }
281
+
282
+ refreshHideParamsIcon(hideParamsIcon) {
283
+ hideParamsIcon
284
+ .classed("fa-eye", !this.hideNonWidgets())
285
+ .classed("fa-eye-slash", this.hideNonWidgets())
286
+ ;
287
+ }
288
+
289
+ gatherDataTree(widget) {
290
+ if (!widget) return null;
291
+ const retVal = {
292
+ label: widget.id() + " (" + widget.classID() + ")",
293
+ children: []
294
+ };
295
+ const arr2 = Persist.discover(widget);
296
+ arr2.forEach(function (prop) {
297
+ const node = {
298
+ label: prop.id,
299
+ children: []
300
+ };
301
+ switch (prop.type) {
302
+ case "widget":
303
+ node.children.push(this.gatherDataTree(widget[prop.id]()));
304
+ break;
305
+ case "widgetArray":
306
+ case "propertyArray":
307
+ const arr = widget[prop.id]();
308
+ if (arr) {
309
+ arr.forEach(function (item) {
310
+ node.children.push(this.gatherDataTree(item));
311
+ }, this);
312
+ }
313
+ break;
314
+ default:
315
+ }
316
+ retVal.children.push(node);
317
+ }, this);
318
+ return retVal;
319
+ }
320
+
321
+ getDataTree() {
322
+ return this.gatherDataTree(this.widget());
323
+ }
324
+
325
+ _rowSorting(paramArr) {
326
+ if (this.sorting() === "type") {
327
+ const typeOrder = ["boolean", "number", "string", "html-color", "array", "object", "widget", "widgetArray", "propertyArray"];
328
+ paramArr.sort(function (a, b) {
329
+ if (a.type === b.type) {
330
+ return a.id < b.id ? -1 : 1;
331
+ } else {
332
+ return typeOrder.indexOf(a.type) < typeOrder.indexOf(b.type) ? -1 : 1;
333
+ }
334
+ });
335
+ } else if (this.sorting() === "A-Z") {
336
+ paramArr.sort(function (a, b) { return a.id < b.id ? -1 : 1; });
337
+ } else if (this.sorting() === "Z-A") {
338
+ paramArr.sort(function (a, b) { return a.id > b.id ? -1 : 1; });
339
+ }
340
+ }
341
+
342
+ filterInputs(d) {
343
+ const discArr = Persist.discover(d);
344
+ if ((this.filterTags() || this.excludeTags().length > 0 || this.excludeParams.length > 0) && d instanceof PropertyEditor === false) {
345
+ const context = this;
346
+ return discArr.filter(function (param, _idx) {
347
+ if (d[param.id + "_hidden"] && d[param.id + "_hidden"]()) return false;
348
+ for (const excludeParamItem of context.excludeParams()) {
349
+ const arr = excludeParamItem.split(".");
350
+ let widgetName;
351
+ let excludeParam;
352
+ if (arr.length > 2) {
353
+ widgetName = arr[0];
354
+ excludeParam = arr[2];
355
+ } else {
356
+ widgetName = arr[0];
357
+ excludeParam = arr[1];
358
+ }
359
+ if (d.class().indexOf(widgetName) !== -1) {
360
+ if (param.id === excludeParam) {
361
+ return false;
362
+ }
363
+ return true;
364
+ }
365
+ }
366
+ if (context.excludeTags().length > 0 && param.ext && param.ext.tags && param.ext.tags.some(function (item) { return (context.excludeTags().indexOf(item) > -1); })) {
367
+ return false;
368
+ }
369
+ if ((context.filterTags() && param.ext && param.ext.tags && param.ext.tags.indexOf(context.filterTags()) !== -1) || !context.filterTags()) {
370
+ return true;
371
+ }
372
+ return false;
373
+ });
374
+ }
375
+ return discArr;
376
+ }
377
+
378
+ renderInputs(element, d) {
379
+ const context = this;
380
+ let discArr = [];
381
+ const showFields = !this.show_settings() && this.showFields();
382
+ if (d) {
383
+ discArr = this.filterInputs(d).filter(function (prop) { return prop.id !== "fields" ? true : showFields; });
384
+ if (!this.show_settings() && this.showData() && d.data) {
385
+ discArr.push({ id: "data", type: "array" });
386
+ }
387
+ if (this.hideNonWidgets()) {
388
+ discArr = discArr.filter(function (n) {
389
+ return hasProperties(n.type);
390
+ });
391
+ }
392
+ this._rowSorting(discArr);
393
+ }
394
+
395
+ const rows = element.selectAll("tr.prop" + this.id()).data(discArr, function (d2) { return d2.id; });
396
+ rows.enter().append("tr")
397
+ .attr("class", "property-wrapper prop" + this.id())
398
+ .each(function (param) {
399
+ const tr = d3Select(this);
400
+ if (hasProperties(param.type)) {
401
+ tr.classed("property-widget-wrapper", true);
402
+ tr.append("td")
403
+ .attr("colspan", "2")
404
+ ;
405
+ } else {
406
+ tr.classed("property-input-wrapper", true);
407
+ tr.append("td")
408
+ .classed("property-label", true)
409
+ .text(param.id)
410
+ ;
411
+ const inputCell = tr.append("td")
412
+ .classed("property-input-cell", true)
413
+ ;
414
+ context.enterInputs(d, inputCell, param);
415
+ }
416
+ }).merge(rows)
417
+ .each(function (param) {
418
+ const tr = d3Select(this);
419
+ tr.classed("disabled", d[param.id + "_disabled"] && d[param.id + "_disabled"]());
420
+ tr.classed("invalid", d[param.id + "_valid"] && !d[param.id + "_valid"]());
421
+ tr.attr("title", param.description);
422
+ if (hasProperties(param.type)) {
423
+ context.updateWidgetRow(d, tr.select("td"), param);
424
+ } else {
425
+ context.updateInputs(d, param);
426
+ }
427
+ });
428
+ rows.exit().each(function (param) {
429
+ const tr = d3Select(this);
430
+ if (hasProperties(param.type)) {
431
+ context.updateWidgetRow(d, tr.select("td"), null);
432
+ }
433
+ }).remove();
434
+ rows.order();
435
+ }
436
+
437
+ updateWidgetRow(widget: PropertyExt, element, param) {
438
+ let tmpWidget = [];
439
+ if (widget && param) {
440
+ tmpWidget = widget[param.id]() || [];
441
+ }
442
+ let widgetArr = tmpWidget instanceof Array ? tmpWidget : [tmpWidget];
443
+ if (param && param.ext && param.ext.autoExpand) {
444
+ // remove empties and ensure last row is an empty ---
445
+ let lastModified = true;
446
+ const noEmpties = widgetArr.filter(function (row, idx) {
447
+ lastModified = row.valid();
448
+ row._owner = widget;
449
+ return lastModified || idx === widgetArr.length - 1;
450
+ }, this);
451
+ const widgetDisabled = widget[param.id + "_disabled"] && widget[param.id + "_disabled"]();
452
+ let changed = !!(widgetArr.length - noEmpties.length);
453
+ if (lastModified && !widgetDisabled) {
454
+ changed = true;
455
+ const autoExpandWidget = new param.ext.autoExpand()
456
+ .owner(widget)
457
+ ;
458
+ // autoExpandWidget.monitor((id, newVal, oldVal, source) => {
459
+ // widget.broadcast(param.id, newVal, oldVal, source);
460
+ // });
461
+ noEmpties.push(autoExpandWidget);
462
+ }
463
+ if (changed) {
464
+ widget[param.id](noEmpties);
465
+ widgetArr = noEmpties;
466
+ }
467
+ }
468
+
469
+ const context = this;
470
+ element.classed("headerRow", true);
471
+ const peInput = element.selectAll(`div.peInput-${this.depth()}`).data(widgetArr, function (d) { return d.id(); });
472
+ peInput.enter().append("div")
473
+ .attr("class", `peInput peInput-${this.depth()}`)
474
+ .each(function (w) {
475
+ const peInputElement = d3Select(this);
476
+
477
+ // Header ---
478
+ peInputElement.append("span");
479
+ peInputElement.append("i")
480
+ .attr("class", "fa")
481
+ .on("click", function (d) {
482
+ const clickTarget = peInputElement.select("div");
483
+ clickTarget
484
+ .classed("property-table-collapsed", !clickTarget.classed("property-table-collapsed"))
485
+ ;
486
+ d3Select(this)
487
+ .classed("fa-minus-square-o", !clickTarget.classed("property-table-collapsed"))
488
+ .classed("fa-plus-square-o", clickTarget.classed("property-table-collapsed"))
489
+ ;
490
+ context.refreshExpandIcon();
491
+ })
492
+ ;
493
+
494
+ // Body ---
495
+ const peDiv = peInputElement.append("div")
496
+ // .attr("class", `property- input - cell propEditor-${context.depth() }`)
497
+ ;
498
+ context._childPE.set(this, new PropertyEditor().label(param.id).target(peDiv.node() as HTMLElement));
499
+ })
500
+ .merge(peInput)
501
+ .each(function (w) {
502
+ const peInputElement = d3Select(this);
503
+ const clickTarget = peInputElement.select("div");
504
+
505
+ // Header ---
506
+ d3Select(this).select("span")
507
+ .text(`${param.id}`)
508
+ ;
509
+
510
+ d3Select(this).select("i")
511
+ .classed("fa-minus-square-o", !clickTarget.classed("property-table-collapsed"))
512
+ .classed("fa-plus-square-o", clickTarget.classed("property-table-collapsed"))
513
+ ;
514
+
515
+ // Body ---
516
+ context._childPE.get(this)
517
+ .parentPropertyEditor(context)
518
+ .showFields(context.showFields())
519
+ .showData(context.showData())
520
+ .sorting(context.sorting())
521
+ .filterTags(context.filterTags())
522
+ .excludeTags(context.excludeTags())
523
+ .excludeParams(context.excludeParams())
524
+ .hideNonWidgets(context.hideNonWidgets() && w._class.indexOf("layout_") >= 0)
525
+ .widget(w)
526
+ .render()
527
+ ;
528
+ })
529
+ ;
530
+ peInput.exit()
531
+ .each(function (w) {
532
+ context._childPE.get(this)
533
+ .widget(null)
534
+ .render()
535
+ .target(null)
536
+ ;
537
+ context._childPE.remove(this);
538
+ })
539
+ .remove()
540
+ ;
541
+ }
542
+
543
+ setProperty(widget, id, value) {
544
+ // With PropertyExt not all "widgets" have a render, if not use top most render...
545
+ let topWidget: Widget;
546
+ let topPropEditor: Widget;
547
+ let propEditor: PropertyEditor = this;
548
+ let oldValue;
549
+ while (propEditor && widget) {
550
+ if (propEditor === this) {
551
+ oldValue = widget[id]();
552
+ widget[id](value);
553
+ }
554
+ if (propEditor) {
555
+ topPropEditor = propEditor;
556
+ const w: PropertyExt = propEditor.widget();
557
+ if (w instanceof Widget) {
558
+ topWidget = w;
559
+ }
560
+ }
561
+ propEditor = propEditor.parentPropertyEditor();
562
+ }
563
+ if (topWidget) {
564
+ topWidget.render();
565
+ }
566
+ if (topPropEditor) {
567
+ topPropEditor.broadcast(id, value, oldValue, widget);
568
+ }
569
+ }
570
+
571
+ enterInputs(widget, cell, param) {
572
+ cell.classed(param.type + "-cell", true);
573
+ const context = this;
574
+ if (typeof (param.ext.editor_input) === "function") {
575
+ param.ext.editor_input(this, widget, cell, param);
576
+ }
577
+ switch (param.type) {
578
+ case "boolean":
579
+ cell.append("input")
580
+ .attr("id", this.id() + "_" + param.id)
581
+ .classed("property-input", true)
582
+ .attr("type", "checkbox")
583
+ .on("change", function () {
584
+ context.setProperty(widget, param.id, this.checked);
585
+ })
586
+ ;
587
+ break;
588
+ case "set":
589
+ cell.append("select")
590
+ .attr("id", this.id() + "_" + param.id)
591
+ .classed("property-input", true)
592
+ .on("change", function () {
593
+ context.setProperty(widget, param.id, this.value);
594
+ })
595
+ ;
596
+ break;
597
+ case "array":
598
+ case "object":
599
+ cell.append("textarea")
600
+ .attr("id", this.id() + "_" + param.id)
601
+ .classed("property-input", true)
602
+ .attr("autocomplete", "off")
603
+ .attr("autocorrect", "off")
604
+ .attr("autocapitalize", "off")
605
+ .attr("spellcheck", "false")
606
+ .on("change", function () {
607
+ let value;
608
+ try {
609
+ value = JSON.parse(this.value);
610
+ } catch (e) {
611
+ value = this.value;
612
+ }
613
+ context.setProperty(widget, param.id, value);
614
+ })
615
+ ;
616
+ break;
617
+ default:
618
+ if (param.ext && param.ext.range) {
619
+ cell.append("span")
620
+ .classed("property-input-span", true)
621
+ .attr("id", this.id() + "_" + param.id + "_currentVal")
622
+ .text(param.defaultValue)
623
+ ;
624
+ cell.append("input")
625
+ .attr("type", "range")
626
+ .attr("step", param.ext.range.step)
627
+ .attr("min", param.ext.range.min)
628
+ .attr("max", param.ext.range.max)
629
+ .attr("id", this.id() + "_" + param.id)
630
+ .classed("property-input", true)
631
+ .on("input", function () {
632
+ context.setProperty(widget, param.id, this.value);
633
+ d3Select("#" + this.id + "_currentVal").text("Current Value: " + this.value);
634
+ })
635
+ .on("change", function () {
636
+ context.setProperty(widget, param.id, this.value);
637
+ d3Select("#" + this.id + "_currentVal").text("Current Value: " + this.value);
638
+ })
639
+ ;
640
+ } else {
641
+ cell.append(param.ext && param.ext.multiline ? "textarea" : "input")
642
+ .attr("id", this.id() + "_" + param.id)
643
+ .classed("property-input", true)
644
+ .attr("autocomplete", "off")
645
+ .attr("autocorrect", "off")
646
+ .attr("autocapitalize", "off")
647
+ .attr("spellcheck", "false")
648
+ .on("change", function () {
649
+ context.setProperty(widget, param.id, this.value);
650
+ })
651
+ ;
652
+ if (param.type === "html-color" && !Platform.isIE) {
653
+ cell.append("input")
654
+ .attr("id", this.id() + "_" + param.id + "_2")
655
+ .classed("property-input", true)
656
+ .attr("type", "color")
657
+ .on("change", function () {
658
+ context.setProperty(widget, param.id, this.value);
659
+ })
660
+ ;
661
+ }
662
+ }
663
+ break;
664
+ }
665
+ }
666
+
667
+ updateInputs(widget, param) {
668
+ const element = d3SelectAll("#" + this.id() + "_" + param.id + ", #" + this.id() + "_" + param.id + "_2");
669
+ const val = widget ? widget[param.id]() : "";
670
+ element.property("disabled", widget[param.id + "_disabled"] && widget[param.id + "_disabled"]());
671
+ element.property("invalid", widget[param.id + "_valid"] && !widget[param.id + "_valid"]());
672
+ switch (param.type) {
673
+ case "boolean":
674
+ element.property("checked", val);
675
+ break;
676
+ case "set":
677
+ const options = element.selectAll("option").data<string | { value: string, text: string }>(widget[param.id + "_options"]());
678
+ options.enter().append("option")
679
+ .merge(options as any)
680
+ .attr("value", (d: any) => (d && d.value !== undefined) ? d.value : d)
681
+ .text((d: any) => (d && d.text !== undefined) ? d.text : d)
682
+ ;
683
+ options.exit().remove();
684
+ element.property("value", val);
685
+ break;
686
+ case "array":
687
+ case "object":
688
+ element.property("value", JSON.stringify(val, function replacer(_key, value) {
689
+ if (value instanceof Widget) {
690
+ return Persist.serialize(value);
691
+ }
692
+ return value;
693
+ }, " "));
694
+ break;
695
+ default:
696
+ if (param.ext && param.ext.range) {
697
+ d3Select("#" + this.id() + "_" + param.id + "_currentVal").text("Current Value: " + val);
698
+ }
699
+ element.property("value", val && val.length && val.length > 100000 ? "...too big to display..." : val);
700
+ break;
701
+ }
702
+ }
703
+
704
+ showFields: { (): boolean; (_: boolean): PropertyEditor; };
705
+ showData: { (): boolean; (_: boolean): PropertyEditor; };
706
+
707
+ sorting: { (): string; (_: string): PropertyEditor; };
708
+ sorting_options: () => string[];
709
+
710
+ hideNonWidgets: { (): boolean; (_: boolean): PropertyEditor; };
711
+
712
+ label: { (): string; (_: string): PropertyEditor; };
713
+ filterTags: { (): string; (_: string): PropertyEditor; };
714
+ excludeTags: { (): string[]; (_: string[]): PropertyEditor; };
715
+ excludeParams: { (): string[]; (_: string[]): PropertyEditor; };
716
+
717
+ widget: { (): PropertyExt; (_: PropertyExt): PropertyEditor };
718
+ }
719
+ PropertyEditor.prototype._class += " other_PropertyEditor";
720
+
721
+ PropertyEditor.prototype.publish("showFields", false, "boolean", "If true, widget.fields() will display as if it was a publish parameter.", null, { tags: ["Basic"] });
722
+ PropertyEditor.prototype.publish("showData", false, "boolean", "If true, widget.data() will display as if it was a publish parameter.", null, { tags: ["Basic"] });
723
+
724
+ PropertyEditor.prototype.publish("sorting", "none", "set", "Specify the sorting type", ["none", "A-Z", "Z-A", "type"], { tags: ["Basic"], icons: ["fa-sort", "fa-sort-alpha-asc", "fa-sort-alpha-desc", "fa-sort-amount-asc"] });
725
+
726
+ PropertyEditor.prototype.publish("hideNonWidgets", false, "boolean", "Hides non-widget params (at this tier only)", null, { tags: ["Basic"] });
727
+
728
+ PropertyEditor.prototype.publish("label", "", "string", "Label to display in header of property editor table", null, { tags: ["Basic"] });
729
+ PropertyEditor.prototype.publish("filterTags", "", "set", "Only show Publish Params of this type", ["Basic", "Intermediate", "Advance", ""], {});
730
+ PropertyEditor.prototype.publish("excludeTags", ["Private"], "array", "Exclude this array of tags", null, {});
731
+ PropertyEditor.prototype.publish("excludeParams", [], "array", "Exclude this array of params (widget.param)", null, {});
732
+
733
+ PropertyEditor.prototype.publish("widget", null, "widget", "Widget", null, { tags: ["Basic"], render: false });
734
+
735
+ const _widgetOrig = PropertyEditor.prototype.widget;
736
+ (PropertyEditor.prototype as any).widget = function (_?: Widget): Widget | PropertyEditor {
737
+ if (arguments.length && _widgetOrig.call(this) === _) return this;
738
+ const retVal = _widgetOrig.apply(this, arguments);
739
+ if (arguments.length) {
740
+ this.watchWidget(_);
741
+ if (_ instanceof Grid) {
742
+ const context = this;
743
+ _.postSelectionChange = function () {
744
+ context._selectedItems = _._selectionBag.get().map(function (item) { return item.widget; });
745
+ context.lazyRender();
746
+ };
747
+ }
748
+ }
749
+ return retVal;
750
+ };