wunderbaum 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/wb_node.ts CHANGED
@@ -9,25 +9,31 @@ import * as util from "./util";
9
9
 
10
10
  import { Wunderbaum } from "./wunderbaum";
11
11
  import {
12
- NavigationMode,
12
+ AddNodeType,
13
+ ApplyCommandType,
13
14
  ChangeType,
14
- iconMap,
15
- ICON_WIDTH,
16
- KEY_TO_ACTION_DICT,
17
- makeNodeTitleMatcher,
15
+ ColumnEventInfos,
16
+ MakeVisibleOptions,
18
17
  MatcherType,
19
18
  NodeAnyCallback,
20
19
  NodeStatusType,
21
20
  NodeVisitCallback,
22
21
  NodeVisitResponse,
23
- ROW_EXTRA_PAD,
24
- ROW_HEIGHT,
25
- TEST_IMG,
26
- ApplyCommandType,
27
- AddNodeType,
22
+ ScrollIntoViewOptions,
28
23
  SetActiveOptions,
29
24
  SetExpandedOptions,
30
25
  SetSelectedOptions,
26
+ SetStatusOptions,
27
+ } from "./types";
28
+ import {
29
+ iconMap,
30
+ ICON_WIDTH,
31
+ KEY_TO_ACTION_DICT,
32
+ makeNodeTitleMatcher,
33
+ RESERVED_TREE_SOURCE_KEYS,
34
+ ROW_EXTRA_PAD,
35
+ ROW_HEIGHT,
36
+ TEST_IMG,
31
37
  } from "./common";
32
38
  import { Deferred } from "./deferred";
33
39
  import { WbNodeData } from "./wb_options";
@@ -96,6 +102,7 @@ export class WunderbaumNode {
96
102
  public readonly refKey: string | undefined = undefined;
97
103
  public children: WunderbaumNode[] | null = null;
98
104
  public checkbox?: boolean;
105
+ /** If true, (in grid mode) no cells are rendered, except for the node title.*/
99
106
  public colspan?: boolean;
100
107
  public icon?: boolean | string;
101
108
  public lazy: boolean = false;
@@ -340,7 +347,7 @@ export class WunderbaumNode {
340
347
  }
341
348
  }
342
349
 
343
- /** */
350
+ /** Call `setExpanded()` on al child nodes*/
344
351
  async expandAll(flag: boolean = true) {
345
352
  this.visit((node) => {
346
353
  node.setExpanded(flag);
@@ -553,6 +560,13 @@ export class WunderbaumNode {
553
560
  return this.parent && this.parent === other;
554
561
  }
555
562
 
563
+ /** Return true if this node's title spans all columns, i.e. the node has no
564
+ * grid cells.
565
+ */
566
+ isColspan() {
567
+ return !!this.getOption("colspan");
568
+ }
569
+
556
570
  /** Return true if this node is a direct or indirect sub node of `other`.
557
571
  * (See also [[isChildOf]].)
558
572
  */
@@ -719,14 +733,26 @@ export class WunderbaumNode {
719
733
  "If `source` is an object, it must have a `children` property"
720
734
  );
721
735
  if (source.types) {
736
+ tree.logInfo("Redefine types", source.columns);
722
737
  tree.setTypes(source.types, false);
738
+ delete source.types;
723
739
  }
724
740
  if (source.columns) {
741
+ tree.logInfo("Redefine columns", source.columns);
725
742
  tree.columns = source.columns;
743
+ delete source.columns;
726
744
  tree.updateColumns({ calculateCols: false });
727
745
  }
728
-
729
746
  this.addChildren(source.children);
747
+ delete source.columns;
748
+
749
+ // Add extra data to `tree.data`
750
+ for (const [key, value] of Object.entries(source)) {
751
+ if (!RESERVED_TREE_SOURCE_KEYS.has(key)) {
752
+ tree.data[key] = value;
753
+ tree.logDebug(`Add source.${key} to tree.data.${key}`);
754
+ }
755
+ }
730
756
 
731
757
  this._callEvent("load");
732
758
  }
@@ -734,10 +760,13 @@ export class WunderbaumNode {
734
760
  /** Download data from the cloud, then call `.update()`. */
735
761
  async load(source: any) {
736
762
  const tree = this.tree;
737
- // const opts = tree.options;
738
763
  const requestId = Date.now();
739
764
  const prevParent = this.parent;
740
765
  const url = typeof source === "string" ? source : source.url;
766
+ const start = Date.now();
767
+ let elap = 0,
768
+ elapLoad = 0,
769
+ elapProcess = 0;
741
770
 
742
771
  // Check for overlapping requests
743
772
  if (this._requestId) {
@@ -748,11 +777,12 @@ export class WunderbaumNode {
748
777
  }
749
778
  this._requestId = requestId;
750
779
 
751
- const timerLabel = tree.logTime(this + ".load()");
780
+ // const timerLabel = tree.logTime(this + ".load()");
752
781
 
753
782
  try {
754
783
  if (!url) {
755
784
  this._loadSourceObject(source);
785
+ elapProcess = Date.now() - start;
756
786
  } else {
757
787
  this.setStatus(NodeStatusType.loading);
758
788
  const response = await fetch(url, { method: "GET" });
@@ -760,6 +790,7 @@ export class WunderbaumNode {
760
790
  util.error(`GET ${url} returned ${response.status}, ${response}`);
761
791
  }
762
792
  const data = await response.json();
793
+ elapLoad = Date.now() - start;
763
794
 
764
795
  if (this._requestId && this._requestId > requestId) {
765
796
  this.logWarn(
@@ -776,23 +807,32 @@ export class WunderbaumNode {
776
807
  return;
777
808
  }
778
809
  this.setStatus(NodeStatusType.ok);
779
- if (data.columns) {
780
- tree.logInfo("Re-define columns", data.columns);
781
- util.assert(!this.parent);
782
- tree.columns = data.columns;
783
- delete data.columns;
784
- tree.updateColumns({ calculateCols: false });
785
- }
810
+ // if (data.columns) {
811
+ // tree.logInfo("Re-define columns", data.columns);
812
+ // util.assert(!this.parent);
813
+ // tree.columns = data.columns;
814
+ // delete data.columns;
815
+ // tree.updateColumns({ calculateCols: false });
816
+ // }
817
+ const startProcess = Date.now();
786
818
  this._loadSourceObject(data);
819
+ elapProcess = Date.now() - startProcess;
787
820
  }
788
821
  } catch (error) {
789
822
  this.logError("Error during load()", source, error);
790
823
  this._callEvent("error", { error: error });
791
- this.setStatus(NodeStatusType.error, "" + error);
824
+ this.setStatus(NodeStatusType.error, { message: "" + error });
792
825
  throw error;
793
826
  } finally {
794
827
  this._requestId = 0;
795
- tree.logTimeEnd(timerLabel);
828
+ elap = Date.now() - start;
829
+ if (tree.options.debugLevel >= 3) {
830
+ tree.logInfo(
831
+ `Load source took ${elap / 1000} seconds (transfer: ${
832
+ elapLoad / 1000
833
+ }s, processing: ${elapProcess / 1000}s)`
834
+ );
835
+ }
796
836
  }
797
837
  }
798
838
 
@@ -833,7 +873,7 @@ export class WunderbaumNode {
833
873
  } catch (e) {
834
874
  this.logError("Error during loadLazy()", e);
835
875
  this._callEvent("error", { error: e });
836
- this.setStatus(NodeStatusType.error, "" + e);
876
+ this.setStatus(NodeStatusType.error, { message: "" + e });
837
877
  }
838
878
  return;
839
879
  }
@@ -880,25 +920,29 @@ export class WunderbaumNode {
880
920
  * @param {object} [opts] passed to `setExpanded()`.
881
921
  * Defaults to {noAnimation: false, noEvents: false, scrollIntoView: true}
882
922
  */
883
- async makeVisible(opts: any) {
923
+ async makeVisible(opts?: MakeVisibleOptions) {
884
924
  let i,
885
925
  dfd = new Deferred(),
886
926
  deferreds = [],
887
927
  parents = this.getParentList(false, false),
888
928
  len = parents.length,
889
- effects = !(opts && opts.noAnimation === true),
929
+ // effects = !(opts && opts.noAnimation === true),
890
930
  scroll = !(opts && opts.scrollIntoView === false);
891
931
 
892
932
  // Expand bottom-up, so only the top node is animated
893
933
  for (i = len - 1; i >= 0; i--) {
894
934
  // self.debug("pushexpand" + parents[i]);
895
- deferreds.push(parents[i].setExpanded(true, opts));
935
+ const seOpts = { noAnimation: opts?.noAnimation };
936
+ deferreds.push(parents[i].setExpanded(true, seOpts));
896
937
  }
897
938
  Promise.all(deferreds).then(() => {
898
939
  // All expands have finished
899
940
  // self.debug("expand DONE", scroll);
900
- if (scroll) {
901
- this.scrollIntoView(effects).then(() => {
941
+ // Note: this.tree may be none when switching demo trees
942
+ if (scroll && this.tree) {
943
+ // Make sure markup and _rowIdx is updated before we do the scroll calculations
944
+ this.tree.updatePendingModifications();
945
+ this.scrollIntoView().then(() => {
902
946
  // self.debug("scroll DONE");
903
947
  dfd.resolve();
904
948
  });
@@ -1092,25 +1136,35 @@ export class WunderbaumNode {
1092
1136
  }
1093
1137
  }
1094
1138
 
1095
- protected _getRenderInfo() {
1096
- let colInfosById: { [key: string]: any } = {};
1097
- let idx = 0;
1098
- let colElems = this._rowElem
1139
+ protected _getRenderInfo(): any {
1140
+ const allColInfosById: ColumnEventInfos = {};
1141
+ const renderColInfosById: ColumnEventInfos = {};
1142
+ const isColspan = this.isColspan();
1143
+
1144
+ const colElems = this._rowElem
1099
1145
  ? ((<unknown>(
1100
1146
  this._rowElem.querySelectorAll("span.wb-col")
1101
- )) as HTMLElement[])
1147
+ )) as HTMLSpanElement[])
1102
1148
  : null;
1103
1149
 
1150
+ let idx = 0;
1104
1151
  for (let col of this.tree.columns) {
1105
- colInfosById[col.id] = {
1152
+ allColInfosById[col.id] = {
1106
1153
  id: col.id,
1107
1154
  idx: idx,
1108
1155
  elem: colElems ? colElems[idx] : null,
1109
1156
  info: col,
1110
1157
  };
1158
+ // renderColInfosById only contains columns that need rendering:
1159
+ if (!isColspan && col.id !== "*") {
1160
+ renderColInfosById[col.id] = allColInfosById[col.id];
1161
+ }
1111
1162
  idx++;
1112
1163
  }
1113
- return colInfosById;
1164
+ return {
1165
+ allColInfosById: allColInfosById,
1166
+ renderColInfosById: renderColInfosById,
1167
+ };
1114
1168
  }
1115
1169
 
1116
1170
  protected _createIcon(
@@ -1163,7 +1217,7 @@ export class WunderbaumNode {
1163
1217
 
1164
1218
  /**
1165
1219
  * Create a whole new `<div class="wb-row">` element.
1166
- * @see {@link Wunderbaumode.render}
1220
+ * @see {@link WunderbaumNode.render}
1167
1221
  */
1168
1222
  protected _render_markup(opts: any) {
1169
1223
  const tree = this.tree;
@@ -1178,8 +1232,7 @@ export class WunderbaumNode {
1178
1232
  let checkboxSpan: HTMLElement | null = null;
1179
1233
  let iconSpan: HTMLElement | null;
1180
1234
  let expanderSpan: HTMLElement | null = null;
1181
- const activeColIdx =
1182
- tree.navMode === NavigationMode.row ? null : tree.activeColIdx;
1235
+ const activeColIdx = tree.isRowNav() ? null : tree.activeColIdx;
1183
1236
 
1184
1237
  const isNew = !rowDiv;
1185
1238
  util.assert(isNew);
@@ -1247,7 +1300,9 @@ export class WunderbaumNode {
1247
1300
  }
1248
1301
 
1249
1302
  // Render columns
1250
- if (!this.colspan && columns.length > 1) {
1303
+ const isColspan = this.isColspan();
1304
+
1305
+ if (!isColspan && columns.length > 1) {
1251
1306
  let colIdx = 0;
1252
1307
  for (let col of columns) {
1253
1308
  colIdx++;
@@ -1275,11 +1330,6 @@ export class WunderbaumNode {
1275
1330
  }
1276
1331
  }
1277
1332
  }
1278
-
1279
- // Now go on and fill in data and update classes
1280
- opts.isNew = true;
1281
- this._render_data(opts);
1282
-
1283
1333
  // Attach to DOM as late as possible
1284
1334
  const after = opts ? opts.after : "last";
1285
1335
  switch (after) {
@@ -1292,12 +1342,15 @@ export class WunderbaumNode {
1292
1342
  default:
1293
1343
  opts.after.after(rowDiv);
1294
1344
  }
1345
+ // Now go on and fill in data and update classes
1346
+ opts.isNew = true;
1347
+ this._render_data(opts);
1295
1348
  }
1296
1349
 
1297
1350
  /**
1298
1351
  * Render `node.title`, `.icon` into an existing row.
1299
1352
  *
1300
- * @see {@link Wunderbaumode.render}
1353
+ * @see {@link WunderbaumNode.render}
1301
1354
  */
1302
1355
  protected _render_data(opts: any) {
1303
1356
  util.assert(this._rowElem);
@@ -1307,7 +1360,7 @@ export class WunderbaumNode {
1307
1360
  const rowDiv = this._rowElem!;
1308
1361
  const isNew = !!opts.isNew; // Called by _render_markup()?
1309
1362
  const columns = tree.columns;
1310
- const typeInfo = this.type ? tree.types[this.type] : null;
1363
+ const isColspan = this.isColspan();
1311
1364
 
1312
1365
  // Row markup already exists
1313
1366
  const nodeElem = rowDiv.querySelector("span.wb-node") as HTMLSpanElement;
@@ -1323,13 +1376,13 @@ export class WunderbaumNode {
1323
1376
 
1324
1377
  // Set the width of the title span, so overflow ellipsis work
1325
1378
  if (!treeOptions.skeleton) {
1326
- if (this.colspan) {
1379
+ if (isColspan) {
1327
1380
  let vpWidth = tree.element.clientWidth;
1328
1381
  titleSpan.style.width =
1329
1382
  vpWidth - (<any>nodeElem)._ofsTitlePx - ROW_EXTRA_PAD + "px";
1330
1383
  } else {
1331
1384
  titleSpan.style.width =
1332
- columns[0]._widthPx -
1385
+ columns[0]._widthPx! -
1333
1386
  (<any>nodeElem)._ofsTitlePx -
1334
1387
  ROW_EXTRA_PAD +
1335
1388
  "px";
@@ -1348,19 +1401,22 @@ export class WunderbaumNode {
1348
1401
  });
1349
1402
  } else if (this.parent) {
1350
1403
  // Skip root node
1404
+ const renderInfo = this._getRenderInfo();
1405
+
1351
1406
  this._callEvent("render", {
1352
1407
  isNew: isNew,
1353
- isDataChange: true,
1408
+ isColspan: isColspan,
1409
+ // isDataChange: true,
1354
1410
  nodeElem: nodeElem,
1355
- typeInfo: typeInfo,
1356
- colInfosById: this._getRenderInfo(),
1411
+ allColInfosById: renderInfo.allColInfosById,
1412
+ renderColInfosById: renderInfo.renderColInfosById,
1357
1413
  });
1358
1414
  }
1359
1415
  }
1360
1416
 
1361
1417
  /**
1362
1418
  * Update row classes to reflect active, focuses, etc.
1363
- * @see {@link Wunderbaumode.render}
1419
+ * @see {@link WunderbaumNode.render}
1364
1420
  */
1365
1421
  protected _render_status(opts: any) {
1366
1422
  // this.log("_render_status", opts);
@@ -1377,8 +1433,6 @@ export class WunderbaumNode {
1377
1433
  const checkboxSpan = nodeElem.querySelector(
1378
1434
  "i.wb-checkbox"
1379
1435
  ) as HTMLLIElement;
1380
- // TODO: update icon (if not opts.isNew)
1381
- // const iconSpan = nodeElem.querySelector("i.wb-icon") as HTMLElement;
1382
1436
 
1383
1437
  let rowClasses = ["wb-row"];
1384
1438
  this.expanded ? rowClasses.push("wb-expanded") : 0;
@@ -1388,6 +1442,7 @@ export class WunderbaumNode {
1388
1442
  this === tree.focusNode ? rowClasses.push("wb-focus") : 0;
1389
1443
  this._errorInfo ? rowClasses.push("wb-error") : 0;
1390
1444
  this._isLoading ? rowClasses.push("wb-loading") : 0;
1445
+ this.isColspan() ? rowClasses.push("wb-colspan") : 0;
1391
1446
  this.statusNodeType
1392
1447
  ? rowClasses.push("wb-status-" + this.statusNodeType)
1393
1448
  : 0;
@@ -1435,6 +1490,11 @@ export class WunderbaumNode {
1435
1490
  for (let colSpan of rowDiv.children) {
1436
1491
  colSpan.classList.toggle("wb-active", i++ === tree.activeColIdx);
1437
1492
  }
1493
+ // Update icon (if not opts.isNew, which would rebuild markup anyway)
1494
+ const iconSpan = nodeElem.querySelector("i.wb-icon") as HTMLElement;
1495
+ if (iconSpan) {
1496
+ this._createIcon(nodeElem, iconSpan);
1497
+ }
1438
1498
  }
1439
1499
  }
1440
1500
 
@@ -1592,8 +1652,9 @@ export class WunderbaumNode {
1592
1652
  /** Make sure that this node is visible in the viewport.
1593
1653
  * @see {@link Wunderbaum.scrollTo|Wunderbaum.scrollTo()}
1594
1654
  */
1595
- async scrollIntoView(options?: any) {
1596
- return this.tree.scrollTo(this);
1655
+ async scrollIntoView(options?: ScrollIntoViewOptions) {
1656
+ const opts = Object.assign({ node: this }, options);
1657
+ return this.tree.scrollTo(opts);
1597
1658
  }
1598
1659
 
1599
1660
  /**
@@ -1602,31 +1663,29 @@ export class WunderbaumNode {
1602
1663
  async setActive(flag: boolean = true, options?: SetActiveOptions) {
1603
1664
  const tree = this.tree;
1604
1665
  const prev = tree.activeNode;
1605
- const retrigger = options?.retrigger;
1606
- const noEvents = options?.noEvents;
1666
+ const retrigger = options?.retrigger; // Default: false
1667
+ const focusTree = options?.focusTree; // Default: false
1668
+ const focusNode = options?.focusNode !== false; // Default: true
1669
+ const noEvents = options?.noEvents; // Default: false
1670
+ const orgEvent = options?.event; // Default: false
1607
1671
 
1608
1672
  if (!noEvents) {
1609
- let orgEvent = options?.event;
1610
1673
  if (flag) {
1611
1674
  if (prev !== this || retrigger) {
1612
1675
  if (
1613
1676
  prev?._callEvent("deactivate", {
1614
1677
  nextNode: this,
1615
1678
  orgEvent: orgEvent,
1616
- }) === false
1617
- ) {
1618
- return;
1619
- }
1620
- if (
1621
- this._callEvent("activate", {
1679
+ }) === false ||
1680
+ this._callEvent("beforeActivate", {
1622
1681
  prevNode: prev,
1623
1682
  orgEvent: orgEvent,
1624
1683
  }) === false
1625
1684
  ) {
1626
- tree.activeNode = null;
1627
- prev?.setModified();
1628
1685
  return;
1629
1686
  }
1687
+ tree.activeNode = null;
1688
+ prev?.setModified(ChangeType.status);
1630
1689
  }
1631
1690
  } else if (prev === this || retrigger) {
1632
1691
  this._callEvent("deactivate", { nextNode: null, orgEvent: orgEvent });
@@ -1634,7 +1693,11 @@ export class WunderbaumNode {
1634
1693
  }
1635
1694
 
1636
1695
  if (prev !== this) {
1637
- tree.activeNode = this;
1696
+ if (flag) {
1697
+ tree.activeNode = this;
1698
+ if (focusNode || focusTree) tree.focusNode = this;
1699
+ if (focusTree) tree.setFocus();
1700
+ }
1638
1701
  prev?.setModified(ChangeType.status);
1639
1702
  this.setModified(ChangeType.status);
1640
1703
  }
@@ -1642,42 +1705,46 @@ export class WunderbaumNode {
1642
1705
  options &&
1643
1706
  options.colIdx != null &&
1644
1707
  options.colIdx !== tree.activeColIdx &&
1645
- tree.navMode !== NavigationMode.row
1708
+ tree.isCellNav()
1646
1709
  ) {
1647
1710
  tree.setColumn(options.colIdx);
1648
1711
  }
1649
- // requestAnimationFrame(() => {
1650
- // this.scrollIntoView();
1651
- // })
1652
- return this.scrollIntoView();
1712
+ if (flag && !noEvents) {
1713
+ this._callEvent("activate", { prevNode: prev, orgEvent: orgEvent });
1714
+ }
1715
+ return this.makeVisible();
1653
1716
  }
1654
1717
 
1655
1718
  /**
1656
1719
  * Expand or collapse this node.
1657
1720
  */
1658
1721
  async setExpanded(flag: boolean = true, options?: SetExpandedOptions) {
1659
- // alert("" + this.getLevel() + ", "+ this.getOption("minExpandLevel");
1660
1722
  if (
1661
1723
  !flag &&
1662
1724
  this.isExpanded() &&
1663
- this.getLevel() < this.getOption("minExpandLevel") &&
1725
+ this.getLevel() <= this.tree.getOption("minExpandLevel") &&
1664
1726
  !util.getOption(options, "force")
1665
1727
  ) {
1666
1728
  this.logDebug("Ignored collapse request below expandLevel.");
1667
1729
  return;
1668
1730
  }
1731
+ if (!flag === !this.expanded) {
1732
+ return; // Nothing to do
1733
+ }
1669
1734
  if (flag && this.lazy && this.children == null) {
1670
1735
  await this.loadLazy();
1671
1736
  }
1672
1737
  this.expanded = flag;
1673
- this.tree.setModified(ChangeType.structure);
1738
+ const updateOpts = { immediate: !!util.getOption(options, "immediate") };
1739
+ this.tree.setModified(ChangeType.structure, updateOpts);
1674
1740
  }
1675
1741
 
1676
1742
  /**
1677
1743
  * Set keyboard focus here.
1678
1744
  * @see {@link setActive}
1679
1745
  */
1680
- setFocus(flag: boolean = true, options?: any) {
1746
+ setFocus(flag: boolean = true) {
1747
+ util.assert(!!flag, "blur is not yet implemented");
1681
1748
  const prev = this.tree.focusNode;
1682
1749
  this.tree.focusNode = this;
1683
1750
  prev?.setModified();
@@ -1720,10 +1787,12 @@ export class WunderbaumNode {
1720
1787
  /** Display node status (ok, loading, error, noData) using styles and a dummy child node. */
1721
1788
  setStatus(
1722
1789
  status: NodeStatusType,
1723
- message?: string,
1724
- details?: string
1790
+ options?: SetStatusOptions
1725
1791
  ): WunderbaumNode | null {
1726
1792
  const tree = this.tree;
1793
+ const message = options?.message;
1794
+ const details = options?.details;
1795
+
1727
1796
  let statusNode: WunderbaumNode | null = null;
1728
1797
 
1729
1798
  const _clearStatusNode = () => {
package/src/wb_options.ts CHANGED
@@ -6,11 +6,14 @@
6
6
 
7
7
  import {
8
8
  BoolOptionResolver,
9
- NavigationModeOption,
9
+ ColumnDefinitionList,
10
+ DndOptionsType,
11
+ NavigationOptions,
12
+ NodeTypeDefinitions,
10
13
  WbNodeEventType,
14
+ WbRenderEventType,
11
15
  WbTreeEventType,
12
- } from "./common";
13
- import { DndOptionsType } from "./wb_ext_dnd";
16
+ } from "./types";
14
17
 
15
18
  export interface WbNodeData {
16
19
  title: string;
@@ -23,43 +26,6 @@ export interface WbNodeData {
23
26
  // ...any?: Any;
24
27
  }
25
28
 
26
- export interface ColumnDefinition {
27
- /** Column ID (pass "*" for the main tree nodes column ) */
28
- id: string;
29
- /** Column header (defaults to id) */
30
- title: string;
31
- /** Column width or weight.
32
- * Either an absolute pixel value (e.g. `"50px"`) or a relative weight (e.g. `1`)
33
- * that is used to calculate the width inside the remaining available space.
34
- * Default: `"*"`, which is interpreted as `1`.
35
- */
36
- width?: string | number;
37
- /** Only used for columns with a relative weight.
38
- * Default: `4px`.
39
- */
40
- minWidth?: string | number;
41
- /** Optional class names that are added to all `span.wb-col` elements of that column.*/
42
- classes?: string;
43
- /** Optional HTML content that is rendered into all `span.wb-col` elements of that column.*/
44
- html: string;
45
- }
46
-
47
- export interface TypeDefinition {
48
- // /** Type ID that matches `node.type`. */
49
- // id: string;
50
- /** En/disable checkbox for matching nodes.*/
51
- checkbox?: boolean | BoolOptionResolver;
52
- /** Optional class names that are added to all `div.wb-row` elements of matching nodes.*/
53
- classes?: string;
54
- /**Default icon for matching nodes.*/
55
- icon?: boolean | string | BoolOptionResolver;
56
- /**
57
- * See also {@link WunderbaumNode.getOption|WunderbaumNode.getOption()}
58
- * to evaluate `node.NAME` setting and `tree.types[node.type].NAME`.
59
- */
60
- _any: any;
61
- }
62
-
63
29
  /**
64
30
  * Available options for [[Wunderbaum]].
65
31
  *
@@ -116,7 +82,7 @@ export interface WunderbaumOptions {
116
82
  *
117
83
  * Default: `{}`.
118
84
  */
119
- types?: { [key: string]: TypeDefinition };
85
+ types?: NodeTypeDefinitions; // { [key: string]: NodeTypeDefinition };
120
86
  /**
121
87
  * A list of maps that define column headers. If this option is set,
122
88
  * Wunderbaum becomes a treegrid control instead of a plain tree.
@@ -124,7 +90,7 @@ export interface WunderbaumOptions {
124
90
  * response.
125
91
  * Default: `[]` meaning this is a plain tree.
126
92
  */
127
- columns?: Array<ColumnDefinition>;
93
+ columns?: ColumnDefinitionList;
128
94
  /**
129
95
  * If true, add a `wb-skeleton` class to all nodes, that will result in a
130
96
  * 'glow' effect. Typically used with initial dummy nodes, while loading the
@@ -143,15 +109,16 @@ export interface WunderbaumOptions {
143
109
  debugLevel: number;
144
110
  /**
145
111
  * Number of levels that are forced to be expanded, and have no expander icon.
112
+ * E.g. 1 would keep all toplevel nodes expanded.
146
113
  * Default: 0
147
114
  */
148
115
  minExpandLevel?: number;
149
116
  // escapeTitles: boolean;
150
- /**
151
- * Height of the header row div.
152
- * Default: 22
153
- */
154
- headerHeightPx: number;
117
+ // /**
118
+ // * Height of the header row div.
119
+ // * Default: 22
120
+ // */
121
+ // headerHeightPx: number;
155
122
  /**
156
123
  * Height of a node row div.
157
124
  * Default: 22
@@ -166,13 +133,17 @@ export interface WunderbaumOptions {
166
133
  * HTMLElement that receives the top nodes breadcrumb.
167
134
  * Default: undefined
168
135
  */
169
- attachBreadcrumb?: HTMLElement;
136
+ connectTopBreadcrumb?: HTMLElement;
170
137
  /**
171
- * Default: NavigationModeOption.startRow
138
+ * Default: NavigationOptions.startRow
172
139
  */
173
- navigationMode?: NavigationModeOption;
140
+ navigationModeOption?: NavigationOptions;
174
141
  /**
175
- * Show/hide header (pass bool or string)
142
+ * Show/hide header (default: null)
143
+ * null: assume false for plain tree and true for grids.
144
+ * string: use text as header (only for plain trees)
145
+ * true: display a header (use tree's id as text for plain trees)
146
+ * false: do not display a header
176
147
  */
177
148
  header?: boolean | string | null;
178
149
  /**
@@ -180,7 +151,9 @@ export interface WunderbaumOptions {
180
151
  */
181
152
  showSpinner?: boolean;
182
153
  /**
183
- * Default: true
154
+ * If true, render a checkbox before the node tile to allow selection with the
155
+ * mouse.
156
+ * Default: false.
184
157
  */
185
158
  checkbox?: boolean | "radio" | BoolOptionResolver;
186
159
  /**
@@ -228,6 +201,15 @@ export interface WunderbaumOptions {
228
201
  click?: (e: WbTreeEventType) => void;
229
202
  /**
230
203
  *
204
+ * Return `false` to prevent default handling, e.g. activating the node.
205
+ * @category Callback
206
+ */
207
+ beforeActivate?: (e: WbNodeEventType) => void;
208
+ /**
209
+ /**
210
+ *
211
+ * Return `false` to prevent default handling, e.g. deactivating the node
212
+ * and activating the next.
231
213
  * @category Callback
232
214
  */
233
215
  deactivate?: (e: WbNodeEventType) => void;
@@ -298,7 +280,7 @@ export interface WunderbaumOptions {
298
280
  * See also `Custom Rendering` for details.
299
281
  * @category Callback
300
282
  */
301
- render?: (e: WbNodeEventType) => void;
283
+ render?: (e: WbRenderEventType) => void;
302
284
  /**
303
285
  *
304
286
  * @category Callback