wunderbaum 0.0.9 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@
7
7
  /*!
8
8
  * Wunderbaum - util
9
9
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
10
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
10
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
11
11
  */
12
12
  /** @module util */
13
13
  /** Readable names for `MouseEvent.button` */
@@ -713,7 +713,7 @@
713
713
  /*!
714
714
  * Wunderbaum - types
715
715
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
716
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
716
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
717
717
  */
718
718
  /** Possible values for `setModified()`. */
719
719
  var ChangeType;
@@ -743,29 +743,29 @@
743
743
  // paging = "paging",
744
744
  })(NodeStatusType || (NodeStatusType = {}));
745
745
  /** Define the subregion of a node, where an event occurred. */
746
- var TargetType;
747
- (function (TargetType) {
748
- TargetType["unknown"] = "";
749
- TargetType["checkbox"] = "checkbox";
750
- TargetType["column"] = "column";
751
- TargetType["expander"] = "expander";
752
- TargetType["icon"] = "icon";
753
- TargetType["prefix"] = "prefix";
754
- TargetType["title"] = "title";
755
- })(TargetType || (TargetType = {}));
746
+ var NodeRegion;
747
+ (function (NodeRegion) {
748
+ NodeRegion["unknown"] = "";
749
+ NodeRegion["checkbox"] = "checkbox";
750
+ NodeRegion["column"] = "column";
751
+ NodeRegion["expander"] = "expander";
752
+ NodeRegion["icon"] = "icon";
753
+ NodeRegion["prefix"] = "prefix";
754
+ NodeRegion["title"] = "title";
755
+ })(NodeRegion || (NodeRegion = {}));
756
756
  /** Initial navigation mode and possible transition. */
757
- var NavigationOptions;
758
- (function (NavigationOptions) {
759
- NavigationOptions["startRow"] = "startRow";
760
- NavigationOptions["cell"] = "cell";
761
- NavigationOptions["startCell"] = "startCell";
762
- NavigationOptions["row"] = "row";
763
- })(NavigationOptions || (NavigationOptions = {}));
757
+ var NavModeEnum;
758
+ (function (NavModeEnum) {
759
+ NavModeEnum["startRow"] = "startRow";
760
+ NavModeEnum["cell"] = "cell";
761
+ NavModeEnum["startCell"] = "startCell";
762
+ NavModeEnum["row"] = "row";
763
+ })(NavModeEnum || (NavModeEnum = {}));
764
764
 
765
765
  /*!
766
766
  * Wunderbaum - wb_extension_base
767
767
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
768
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
768
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
769
769
  */
770
770
  class WunderbaumExtension {
771
771
  constructor(tree, id, defaults) {
@@ -1056,7 +1056,7 @@
1056
1056
  /*!
1057
1057
  * Wunderbaum - ext-filter
1058
1058
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
1059
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
1059
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
1060
1060
  */
1061
1061
  const START_MARKER = "\uFFF7";
1062
1062
  const END_MARKER = "\uFFF8";
@@ -1241,18 +1241,18 @@
1241
1241
  /**
1242
1242
  * [ext-filter] Dim or hide nodes.
1243
1243
  *
1244
- * @param {boolean} [opts={autoExpand: false, leavesOnly: false}]
1244
+ * @param {boolean} [options={autoExpand: false, leavesOnly: false}]
1245
1245
  */
1246
- filterNodes(filter, opts) {
1247
- return this._applyFilterNoUpdate(filter, false, opts);
1246
+ filterNodes(filter, options) {
1247
+ return this._applyFilterNoUpdate(filter, false, options);
1248
1248
  }
1249
1249
  /**
1250
1250
  * [ext-filter] Dim or hide whole branches.
1251
1251
  *
1252
- * @param {boolean} [opts={autoExpand: false}]
1252
+ * @param {boolean} [options={autoExpand: false}]
1253
1253
  */
1254
- filterBranches(filter, opts) {
1255
- return this._applyFilterNoUpdate(filter, true, opts);
1254
+ filterBranches(filter, options) {
1255
+ return this._applyFilterNoUpdate(filter, true, options);
1256
1256
  }
1257
1257
  /**
1258
1258
  * [ext-filter] Re-apply current filter.
@@ -1361,7 +1361,7 @@
1361
1361
  /*!
1362
1362
  * Wunderbaum - ext-keynav
1363
1363
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
1364
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
1364
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
1365
1365
  */
1366
1366
  const QUICKSEARCH_DELAY = 500;
1367
1367
  class KeynavExtension extends WunderbaumExtension {
@@ -1450,19 +1450,30 @@
1450
1450
  }
1451
1451
  // Pre-Evaluate expand/collapse action for LEFT/RIGHT
1452
1452
  switch (eventName) {
1453
+ case "Enter":
1454
+ if (node.isActive()) {
1455
+ if (node.isExpanded()) {
1456
+ eventName = "Subtract"; // callapse
1457
+ }
1458
+ else if (node.isExpandable(true)) {
1459
+ eventName = "Add"; // expand
1460
+ }
1461
+ }
1462
+ break;
1453
1463
  case "ArrowLeft":
1454
1464
  if (node.expanded) {
1455
1465
  eventName = "Subtract"; // collapse
1456
1466
  }
1457
1467
  break;
1458
1468
  case "ArrowRight":
1459
- if (!node.expanded && (node.children || node.lazy)) {
1469
+ if (!node.expanded && node.isExpandable(true)) {
1460
1470
  eventName = "Add"; // expand
1461
1471
  }
1462
- else if (navModeOption === NavigationOptions.startCell ||
1463
- navModeOption === NavigationOptions.startRow) {
1472
+ else if (navModeOption === NavModeEnum.startCell ||
1473
+ navModeOption === NavModeEnum.startRow) {
1474
+ event.preventDefault();
1464
1475
  tree.setCellNav();
1465
- return;
1476
+ return false;
1466
1477
  }
1467
1478
  break;
1468
1479
  }
@@ -1477,7 +1488,7 @@
1477
1488
  case "Subtract":
1478
1489
  node.setExpanded(false);
1479
1490
  break;
1480
- case " ":
1491
+ case " ": // Space
1481
1492
  // if (node.isPagingNode()) {
1482
1493
  // tree._triggerNodeEvent("clickPaging", ctx, event);
1483
1494
  // } else
@@ -1552,7 +1563,16 @@
1552
1563
  }
1553
1564
  else ;
1554
1565
  switch (eventName) {
1555
- case " ":
1566
+ case "+":
1567
+ case "Add":
1568
+ // case "=": // 187: '+' @ Chrome, Safari
1569
+ node.setExpanded(true);
1570
+ break;
1571
+ case "-":
1572
+ case "Subtract":
1573
+ node.setExpanded(false);
1574
+ break;
1575
+ case " ": // Space
1556
1576
  if (tree.activeColIdx === 0 && node.getOption("checkbox")) {
1557
1577
  node.setSelected(!node.isSelected());
1558
1578
  handled = true;
@@ -1573,7 +1593,7 @@
1573
1593
  break;
1574
1594
  case "Enter":
1575
1595
  tree.setFocus(); // Blur prev. input if any
1576
- if (tree.activeColIdx === 0 && node.isExpandable()) {
1596
+ if ((tree.activeColIdx === 0 || isColspan) && node.isExpandable()) {
1577
1597
  node.setExpanded(!node.isExpanded());
1578
1598
  handled = true;
1579
1599
  }
@@ -1584,7 +1604,7 @@
1584
1604
  break;
1585
1605
  case "Escape":
1586
1606
  tree.setFocus(); // Blur prev. input if any
1587
- if (tree.isCellNav() && navModeOption !== NavigationOptions.cell) {
1607
+ if (tree.isCellNav() && navModeOption !== NavModeEnum.cell) {
1588
1608
  tree.setCellNav(false); // row-nav mode
1589
1609
  handled = true;
1590
1610
  }
@@ -1597,7 +1617,7 @@
1597
1617
  else if (!isColspan && tree.activeColIdx > 0) {
1598
1618
  tree.setColumn(tree.activeColIdx - 1);
1599
1619
  }
1600
- else if (navModeOption !== NavigationOptions.cell) {
1620
+ else if (navModeOption !== NavModeEnum.cell) {
1601
1621
  tree.setCellNav(false); // row-nav mode
1602
1622
  }
1603
1623
  handled = true;
@@ -1613,16 +1633,16 @@
1613
1633
  }
1614
1634
  handled = true;
1615
1635
  break;
1616
- case "Home": // Generated by FN + ArrowLeft on Mac
1617
- case "Meta+ArrowLeft":
1636
+ case "Home": // Generated by [Fn] + ArrowLeft on Mac
1637
+ // case "Meta+ArrowLeft":
1618
1638
  tree.setFocus(); // Blur prev. input if any
1619
1639
  if (!isColspan && tree.activeColIdx > 0) {
1620
1640
  tree.setColumn(0);
1621
1641
  }
1622
1642
  handled = true;
1623
1643
  break;
1624
- case "End": // Generated by FN + ArrowRight on Mac
1625
- case "Meta+ArrowRight":
1644
+ case "End": // Generated by [Fn] + ArrowRight on Mac
1645
+ // case "Meta+ArrowRight":
1626
1646
  tree.setFocus(); // Blur prev. input if any
1627
1647
  if (!isColspan && tree.activeColIdx < tree.columns.length - 1) {
1628
1648
  tree.setColumn(tree.columns.length - 1);
@@ -1632,12 +1652,12 @@
1632
1652
  case "ArrowDown":
1633
1653
  case "ArrowUp":
1634
1654
  case "Backspace":
1635
- case "Control+End": // Generated by FN + Control + ArrowRight on Mac
1636
- case "Control+Home": // Generated by FN + Control + Arrowleft on Mac
1637
- case "Meta+ArrowDown":
1638
- case "Meta+ArrowUp":
1639
- case "PageDown": // Generated by FN + ArrowDown on Mac
1640
- case "PageUp": // Generated by FN + ArrowUp on Mac
1655
+ case "Control+End": // Generated by Control + [Fn] + ArrowRight on Mac
1656
+ case "Control+Home": // Generated by Control + [Fn] + Arrowleft on Mac
1657
+ case "Meta+ArrowDown": // [⌘] + ArrowDown on Mac
1658
+ case "Meta+ArrowUp": // [⌘] + ArrowUp on Mac
1659
+ case "PageDown": // Generated by [Fn] + ArrowDown on Mac
1660
+ case "PageUp": // Generated by [Fn] + ArrowUp on Mac
1641
1661
  node.navigate(eventName, { activate: activate, event: event });
1642
1662
  // if (isCellEditMode) {
1643
1663
  // this._getEmbeddedInputElem(null, true); // set focus to input
@@ -1658,7 +1678,7 @@
1658
1678
  /*!
1659
1679
  * Wunderbaum - ext-logger
1660
1680
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
1661
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
1681
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
1662
1682
  */
1663
1683
  class LoggerExtension extends WunderbaumExtension {
1664
1684
  constructor(tree) {
@@ -1698,7 +1718,7 @@
1698
1718
  /*!
1699
1719
  * Wunderbaum - common
1700
1720
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
1701
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
1721
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
1702
1722
  */
1703
1723
  const DEFAULT_DEBUGLEVEL = 4; // Replaced by rollup script
1704
1724
  /**
@@ -1938,7 +1958,7 @@
1938
1958
  /*!
1939
1959
  * Wunderbaum - ext-dnd
1940
1960
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
1941
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
1961
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
1942
1962
  */
1943
1963
  const nodeMimeType = "application/x-wunderbaum-node";
1944
1964
  class DndExtension extends WunderbaumExtension {
@@ -2052,7 +2072,7 @@
2052
2072
  }
2053
2073
  /* Implement auto scrolling when drag cursor is in top/bottom area of scroll parent. */
2054
2074
  autoScroll(event) {
2055
- let tree = this.tree, dndOpts = tree.options.dnd, sp = tree.scrollContainerElement, sensitivity = dndOpts.scrollSensitivity, speed = dndOpts.scrollSpeed, scrolled = 0;
2075
+ let tree = this.tree, dndOpts = tree.options.dnd, sp = tree.listContainerElement, sensitivity = dndOpts.scrollSensitivity, speed = dndOpts.scrollSpeed, scrolled = 0;
2056
2076
  const scrollTop = sp.offsetTop;
2057
2077
  if (scrollTop + sp.offsetHeight - event.pageY < sensitivity) {
2058
2078
  const delta = sp.scrollHeight - sp.clientHeight - scrollTop;
@@ -2211,7 +2231,7 @@
2211
2231
  /*!
2212
2232
  * Wunderbaum - drag_observer
2213
2233
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
2214
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
2234
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
2215
2235
  */
2216
2236
  /**
2217
2237
  * Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'.
@@ -2347,7 +2367,7 @@
2347
2367
  /*!
2348
2368
  * Wunderbaum - ext-grid
2349
2369
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
2350
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
2370
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
2351
2371
  */
2352
2372
  class GridExtension extends WunderbaumExtension {
2353
2373
  constructor(tree) {
@@ -2384,7 +2404,7 @@
2384
2404
  /*!
2385
2405
  * Wunderbaum - deferred
2386
2406
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
2387
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
2407
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
2388
2408
  */
2389
2409
  /**
2390
2410
  * Implement a ES6 Promise, that exposes a resolve() and reject() method.
@@ -2437,7 +2457,7 @@
2437
2457
  /*!
2438
2458
  * Wunderbaum - wunderbaum_node
2439
2459
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
2440
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
2460
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
2441
2461
  */
2442
2462
  /** Top-level properties that can be passed with `data`. */
2443
2463
  const NODE_PROPS = new Set([
@@ -2700,8 +2720,8 @@
2700
2720
  *
2701
2721
  * @see {@link Wunderbaum.applyCommand}
2702
2722
  */
2703
- applyCommand(cmd, opts) {
2704
- return this.tree.applyCommand(cmd, this, opts);
2723
+ applyCommand(cmd, options) {
2724
+ return this.tree.applyCommand(cmd, this, options);
2705
2725
  }
2706
2726
  /**
2707
2727
  * Add/remove one or more classes to `<div class='wb-row'>`.
@@ -2909,7 +2929,7 @@
2909
2929
  }
2910
2930
  }
2911
2931
  /**
2912
- * Return multiline string representation of a node/subnode hierarchy.
2932
+ * Return a multiline string representation of a node/subnode hierarchy.
2913
2933
  * Mostly useful for debugging.
2914
2934
  *
2915
2935
  * Example:
@@ -2921,7 +2941,6 @@
2921
2941
  * Books
2922
2942
  * ├─ Art of War
2923
2943
  * ╰─ Don Quixote
2924
- * ...
2925
2944
  * ```
2926
2945
  * @see {@link WunderbaumNode.format_iter}
2927
2946
  */
@@ -3043,11 +3062,17 @@
3043
3062
  isActive() {
3044
3063
  return this.tree.activeNode === this;
3045
3064
  }
3046
- /** Return true if this node is a *direct* child of `other`.
3065
+ /** Return true if this node is a direct or indirect parent of `other`.
3066
+ * (See also [[isParentOf]].)
3067
+ */
3068
+ isAncestorOf(other) {
3069
+ return other && other.isDescendantOf(this);
3070
+ }
3071
+ /** Return true if this node is a **direct** subnode of `other`.
3047
3072
  * (See also [[isDescendantOf]].)
3048
3073
  */
3049
3074
  isChildOf(other) {
3050
- return this.parent && this.parent === other;
3075
+ return other && this.parent === other;
3051
3076
  }
3052
3077
  /** Return true if this node's title spans all columns, i.e. the node has no
3053
3078
  * grid cells.
@@ -3055,7 +3080,7 @@
3055
3080
  isColspan() {
3056
3081
  return !!this.getOption("colspan");
3057
3082
  }
3058
- /** Return true if this node is a direct or indirect sub node of `other`.
3083
+ /** Return true if this node is a direct or indirect subnode of `other`.
3059
3084
  * (See also [[isChildOf]].)
3060
3085
  */
3061
3086
  isDescendantOf(other) {
@@ -3068,7 +3093,7 @@
3068
3093
  return true;
3069
3094
  }
3070
3095
  if (p === p.parent) {
3071
- error("Recursive parent link: " + p);
3096
+ error(`Recursive parent link: ${p}`);
3072
3097
  }
3073
3098
  p = p.parent;
3074
3099
  }
@@ -3116,6 +3141,12 @@
3116
3141
  isPagingNode() {
3117
3142
  return this.statusNodeType === "paging";
3118
3143
  }
3144
+ /** Return true if this node is a **direct** parent of `other`.
3145
+ * (See also [[isAncestorOf]].)
3146
+ */
3147
+ isParentOf(other) {
3148
+ return other && other.parent === this;
3149
+ }
3119
3150
  /** (experimental) Return true if this node is partially loaded. */
3120
3151
  isPartload() {
3121
3152
  return !!this._partload;
@@ -3762,16 +3793,23 @@
3762
3793
  const treeOptions = tree.options;
3763
3794
  const rowDiv = this._rowElem;
3764
3795
  const isNew = !!opts.isNew; // Called by _render_markup()?
3796
+ const preventScroll = !!opts.preventScroll;
3765
3797
  const columns = tree.columns;
3766
3798
  const isColspan = this.isColspan();
3767
3799
  // Row markup already exists
3768
3800
  const nodeElem = rowDiv.querySelector("span.wb-node");
3769
3801
  const titleSpan = nodeElem.querySelector("span.wb-title");
3802
+ const scrollTop = tree.element.scrollTop;
3770
3803
  if (this.titleWithHighlight) {
3771
3804
  titleSpan.innerHTML = this.titleWithHighlight;
3772
3805
  }
3773
3806
  else {
3774
- titleSpan.textContent = this.title;
3807
+ titleSpan.textContent = this.title; // TODO: this triggers scroll events
3808
+ }
3809
+ // NOTE: At least on Safari, this render call triggers a scroll event
3810
+ // probably when a focused input is replaced.
3811
+ if (preventScroll) {
3812
+ tree.element.scrollTop = scrollTop;
3775
3813
  }
3776
3814
  // Set the width of the title span, so overflow ellipsis work
3777
3815
  if (!treeOptions.skeleton) {
@@ -3796,6 +3834,7 @@
3796
3834
  this._callEvent("renderStatusNode", {
3797
3835
  isNew: isNew,
3798
3836
  nodeElem: nodeElem,
3837
+ isColspan: isColspan,
3799
3838
  });
3800
3839
  }
3801
3840
  else if (this.parent) {
@@ -3803,9 +3842,8 @@
3803
3842
  const renderInfo = this._getRenderInfo();
3804
3843
  this._callEvent("render", {
3805
3844
  isNew: isNew,
3806
- isColspan: isColspan,
3807
- // isDataChange: true,
3808
3845
  nodeElem: nodeElem,
3846
+ isColspan: isColspan,
3809
3847
  allColInfosById: renderInfo.allColInfosById,
3810
3848
  renderColInfosById: renderInfo.renderColInfosById,
3811
3849
  });
@@ -3887,6 +3925,19 @@
3887
3925
  this._createIcon(nodeElem, iconSpan, !expanderSpan);
3888
3926
  }
3889
3927
  }
3928
+ // Adjust column width
3929
+ if (opts.resizeCols !== false && !this.isColspan()) {
3930
+ const colElems = rowDiv.querySelectorAll("span.wb-col");
3931
+ let idx = 0;
3932
+ let ofs = 0;
3933
+ for (let colDef of this.tree.columns) {
3934
+ const colElem = colElems[idx];
3935
+ colElem.style.left = `${ofs}px`;
3936
+ colElem.style.width = `${colDef._widthPx}px`;
3937
+ idx++;
3938
+ ofs += colDef._widthPx;
3939
+ }
3940
+ }
3890
3941
  }
3891
3942
  /**
3892
3943
  * Create or update node's markup.
@@ -3906,7 +3957,7 @@
3906
3957
  // this.log("render", options);
3907
3958
  const opts = Object.assign({ change: ChangeType.data }, options);
3908
3959
  if (!this._rowElem) {
3909
- opts.change = "row";
3960
+ opts.change = ChangeType.row;
3910
3961
  }
3911
3962
  switch (opts.change) {
3912
3963
  case "status":
@@ -4058,11 +4109,11 @@
4058
4109
  if (prev !== this || retrigger) {
4059
4110
  if ((prev === null || prev === void 0 ? void 0 : prev._callEvent("deactivate", {
4060
4111
  nextNode: this,
4061
- orgEvent: orgEvent,
4112
+ event: orgEvent,
4062
4113
  })) === false ||
4063
4114
  this._callEvent("beforeActivate", {
4064
4115
  prevNode: prev,
4065
- orgEvent: orgEvent,
4116
+ event: orgEvent,
4066
4117
  }) === false) {
4067
4118
  return;
4068
4119
  }
@@ -4071,7 +4122,7 @@
4071
4122
  }
4072
4123
  }
4073
4124
  else if (prev === this || retrigger) {
4074
- this._callEvent("deactivate", { nextNode: null, orgEvent: orgEvent });
4125
+ this._callEvent("deactivate", { nextNode: null, event: orgEvent });
4075
4126
  }
4076
4127
  }
4077
4128
  if (prev !== this) {
@@ -4092,7 +4143,7 @@
4092
4143
  tree.setColumn(options.colIdx);
4093
4144
  }
4094
4145
  if (flag && !noEvents) {
4095
- this._callEvent("activate", { prevNode: prev, orgEvent: orgEvent });
4146
+ this._callEvent("activate", { prevNode: prev, event: orgEvent });
4096
4147
  }
4097
4148
  return this.makeVisible();
4098
4149
  }
@@ -4358,7 +4409,7 @@
4358
4409
  /*!
4359
4410
  * Wunderbaum - ext-edit
4360
4411
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
4361
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
4412
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
4362
4413
  */
4363
4414
  // const START_MARKER = "\uFFF7";
4364
4415
  class EditExtension extends WunderbaumExtension {
@@ -4508,7 +4559,7 @@
4508
4559
  // (we also treat a `true` return value as 'use default'):
4509
4560
  if (inputHtml === true || !inputHtml) {
4510
4561
  const title = escapeHtml(node.title);
4511
- inputHtml = `<input type=text class="wb-input-edit" value="${title}" required autocorrect=off>`;
4562
+ inputHtml = `<input type=text class="wb-input-edit" tabindex=-1 value="${title}" required autocorrect=off>`;
4512
4563
  }
4513
4564
  const titleSpan = node
4514
4565
  .getColElem(0)
@@ -4544,11 +4595,11 @@
4544
4595
  * @param apply
4545
4596
  * @param opts.canKeepOpen
4546
4597
  */
4547
- _stopEditTitle(apply, opts) {
4598
+ _stopEditTitle(apply, options) {
4548
4599
  const focusElem = document.activeElement;
4549
4600
  let newValue = focusElem ? getValueFromElem(focusElem) : null;
4550
4601
  const node = this.curEditNode;
4551
- const forceClose = !!opts.forceClose;
4602
+ const forceClose = !!options.forceClose;
4552
4603
  const validity = this.getPluginOption("validity");
4553
4604
  if (newValue && this.getPluginOption("trim")) {
4554
4605
  newValue = newValue.trim();
@@ -4557,7 +4608,7 @@
4557
4608
  this.tree.logDebug("stopEditTitle: not in edit mode.");
4558
4609
  return;
4559
4610
  }
4560
- node.logDebug(`stopEditTitle(${apply})`, opts, focusElem, newValue);
4611
+ node.logDebug(`stopEditTitle(${apply})`, options, focusElem, newValue);
4561
4612
  if (apply && newValue !== null && newValue !== node.title) {
4562
4613
  const errMsg = focusElem.validationMessage;
4563
4614
  if (errMsg) {
@@ -4583,22 +4634,24 @@
4583
4634
  return;
4584
4635
  }
4585
4636
  node === null || node === void 0 ? void 0 : node.setTitle(newValue);
4586
- this.curEditNode.render();
4637
+ // NOTE: At least on Safari, this render call triggers a scroll event
4638
+ // probably because the focused input is replaced.
4639
+ this.curEditNode.render({ preventScroll: true });
4587
4640
  this.curEditNode = null;
4588
4641
  this.relatedNode = null;
4589
4642
  this.tree.setFocus(); // restore focus that was in the input element
4590
4643
  })
4591
4644
  .catch((err) => {
4592
- // this.curEditNode!.render();
4593
- // this.curEditNode = null;
4594
- // this.relatedNode = null;
4645
+ node.logError(err);
4595
4646
  });
4596
4647
  // Trigger 'change' event for embedded `<input>`
4597
4648
  // focusElem.blur();
4598
4649
  }
4599
4650
  else {
4600
4651
  // Discard the embedded `<input>`
4601
- this.curEditNode.render();
4652
+ // NOTE: At least on Safari, this render call triggers a scroll event
4653
+ // probably because the focused input is replaced.
4654
+ this.curEditNode.render({ preventScroll: true });
4602
4655
  this.curEditNode = null;
4603
4656
  this.relatedNode = null;
4604
4657
  // We discarded the <input>, so we have to acquire keyboard focus again
@@ -4651,8 +4704,8 @@
4651
4704
  * https://github.com/mar10/wunderbaum
4652
4705
  *
4653
4706
  * Released under the MIT license.
4654
- * @version v0.0.9
4655
- * @date Mon, 31 Oct 2022 17:06:10 GMT
4707
+ * @version v0.1.1
4708
+ * @date Sun, 27 Nov 2022 07:35:11 GMT
4656
4709
  */
4657
4710
  class WbSystemRoot extends WunderbaumNode {
4658
4711
  constructor(tree) {
@@ -4836,11 +4889,11 @@
4836
4889
  }
4837
4890
  //
4838
4891
  this.element.innerHTML += `
4839
- <div class="wb-scroll-container">
4892
+ <div class="wb-list-container">
4840
4893
  <div class="wb-node-list"></div>
4841
4894
  </div>`;
4842
- this.scrollContainerElement = this.element.querySelector("div.wb-scroll-container");
4843
- this.nodeListElement = this.scrollContainerElement.querySelector("div.wb-node-list");
4895
+ this.listContainerElement = this.element.querySelector("div.wb-list-container");
4896
+ this.nodeListElement = this.listContainerElement.querySelector("div.wb-node-list");
4844
4897
  this.headerElement = this.element.querySelector("div.wb-header");
4845
4898
  this.element.classList.toggle("wb-grid", this.columns.length > 1);
4846
4899
  this._initExtensions();
@@ -4861,10 +4914,10 @@
4861
4914
  // The source may have defined columns, so we may adjust the nav mode
4862
4915
  if (opts.navigationModeOption == null) {
4863
4916
  if (this.isGrid()) {
4864
- this.setNavigationOption(NavigationOptions.cell);
4917
+ this.setNavigationOption(NavModeEnum.cell);
4865
4918
  }
4866
4919
  else {
4867
- this.setNavigationOption(NavigationOptions.row);
4920
+ this.setNavigationOption(NavModeEnum.row);
4868
4921
  }
4869
4922
  }
4870
4923
  else {
@@ -4889,13 +4942,9 @@
4889
4942
  this.setModified(ChangeType.any);
4890
4943
  // --- Bind listeners
4891
4944
  this.element.addEventListener("scroll", (e) => {
4892
- // this.log("scroll", e);
4945
+ // this.log(`scroll, scrollTop:${e.target.scrollTop}`, e);
4893
4946
  this.setModified(ChangeType.vscroll);
4894
4947
  });
4895
- // this.scrollContainerElement.addEventListener("scroll", (e: Event) => {
4896
- // this.log("scroll", e)
4897
- // this.setModified(ChangeType.vscroll);
4898
- // });
4899
4948
  this.resizeObserver = new ResizeObserver((entries) => {
4900
4949
  this.setModified(ChangeType.vscroll);
4901
4950
  // this.log("ResizeObserver: Size changed", entries);
@@ -4905,16 +4954,6 @@
4905
4954
  const info = Wunderbaum.getEventInfo(e);
4906
4955
  const node = info.node;
4907
4956
  // this.log("click", info, e);
4908
- // if( (e.target as HTMLElement).matches("input[type=checkbox]")){
4909
- // // Click on an embedded checkbox triggers a change event.
4910
- // // We return here, before the `setActive()` performs a render
4911
- // this.log("click - cb", info, e);
4912
- // // e.preventDefault()
4913
- // setTimeout(()=>{
4914
- // // (e.target as HTMLElement).click()
4915
- // }, 50)
4916
- // // return
4917
- // }
4918
4957
  if (this._callEvent("click", { event: e, node: node, info: info }) === false) {
4919
4958
  this.lastClickTime = Date.now();
4920
4959
  return false;
@@ -4935,15 +4974,27 @@
4935
4974
  else {
4936
4975
  node.setActive(true, { event: e });
4937
4976
  }
4938
- if (info.region === TargetType.expander) {
4977
+ if (info.region === NodeRegion.expander) {
4939
4978
  node.setExpanded(!node.isExpanded());
4940
4979
  }
4941
- else if (info.region === TargetType.checkbox) {
4980
+ else if (info.region === NodeRegion.checkbox) {
4942
4981
  node.setSelected(!node.isSelected());
4943
4982
  }
4944
4983
  }
4945
4984
  this.lastClickTime = Date.now();
4946
4985
  });
4986
+ onEvent(this.nodeListElement, "dblclick", "div.wb-row", (e) => {
4987
+ const info = Wunderbaum.getEventInfo(e);
4988
+ const node = info.node;
4989
+ // this.log("dblclick", info, e);
4990
+ if (this._callEvent("dblclick", { event: e, node: node, info: info }) ===
4991
+ false) {
4992
+ return false;
4993
+ }
4994
+ if (node && info.colIdx === 0 && node.isExpandable()) {
4995
+ node.setExpanded(!node.isExpanded());
4996
+ }
4997
+ });
4947
4998
  onEvent(this.element, "keydown", (e) => {
4948
4999
  const info = Wunderbaum.getEventInfo(e);
4949
5000
  const eventName = eventToString(e);
@@ -5561,7 +5612,7 @@
5561
5612
  */
5562
5613
  findRelatedNode(node, where, includeHidden = false) {
5563
5614
  let res = null;
5564
- const pageSize = Math.floor(this.scrollContainerElement.clientHeight / ROW_HEIGHT);
5615
+ const pageSize = Math.floor(this.listContainerElement.clientHeight / ROW_HEIGHT);
5565
5616
  switch (where) {
5566
5617
  case "parent":
5567
5618
  if (node.parent && node.parent.parent) {
@@ -5712,37 +5763,37 @@
5712
5763
  let target = event.target, cl = target.classList, parentCol = target.closest("span.wb-col"), node = Wunderbaum.getNode(target), tree = node ? node.tree : Wunderbaum.getTree(event), res = {
5713
5764
  tree: tree,
5714
5765
  node: node,
5715
- region: TargetType.unknown,
5766
+ region: NodeRegion.unknown,
5716
5767
  colDef: undefined,
5717
5768
  colIdx: -1,
5718
5769
  colId: undefined,
5719
5770
  colElem: parentCol,
5720
5771
  };
5721
5772
  if (cl.contains("wb-title")) {
5722
- res.region = TargetType.title;
5773
+ res.region = NodeRegion.title;
5723
5774
  }
5724
5775
  else if (cl.contains("wb-expander")) {
5725
5776
  res.region =
5726
- node.hasChildren() === false ? TargetType.prefix : TargetType.expander;
5777
+ node.hasChildren() === false ? NodeRegion.prefix : NodeRegion.expander;
5727
5778
  }
5728
5779
  else if (cl.contains("wb-checkbox")) {
5729
- res.region = TargetType.checkbox;
5780
+ res.region = NodeRegion.checkbox;
5730
5781
  }
5731
5782
  else if (cl.contains("wb-icon")) {
5732
5783
  //|| cl.contains("wb-custom-icon")) {
5733
- res.region = TargetType.icon;
5784
+ res.region = NodeRegion.icon;
5734
5785
  }
5735
5786
  else if (cl.contains("wb-node")) {
5736
- res.region = TargetType.title;
5787
+ res.region = NodeRegion.title;
5737
5788
  }
5738
5789
  else if (parentCol) {
5739
- res.region = TargetType.column;
5790
+ res.region = NodeRegion.column;
5740
5791
  const idx = Array.prototype.indexOf.call(parentCol.parentNode.children, parentCol);
5741
5792
  res.colIdx = idx;
5742
5793
  }
5743
5794
  else if (cl.contains("wb-row")) {
5744
5795
  // Plain tree
5745
- res.region = TargetType.title;
5796
+ res.region = NodeRegion.title;
5746
5797
  }
5747
5798
  else {
5748
5799
  // Somewhere near the title
@@ -5759,14 +5810,6 @@
5759
5810
  // this.log("Event", event, res);
5760
5811
  return res;
5761
5812
  }
5762
- // /** Return a string describing the affected node region for a mouse event.
5763
- // *
5764
- // * @param {Event} event Mouse event, e.g. click, mousemove, ...
5765
- // * @returns {string} 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined
5766
- // */
5767
- // getEventNodeRegion(event: Event) {
5768
- // return this.getEventInfo(event).region;
5769
- // }
5770
5813
  /**
5771
5814
  * Return readable string representation for this instance.
5772
5815
  * @internal
@@ -5860,7 +5903,7 @@
5860
5903
  const vpRowTop = rowTop - scrollTop;
5861
5904
  const vpRowBottom = vpRowTop + ROW_HEIGHT;
5862
5905
  const topNode = options === null || options === void 0 ? void 0 : options.topNode;
5863
- // this.log( `scrollTo(${node.title}), vpTop:${vpTop}px, scrollTop:${scrollTop}, vpHeight:${vpHeight}, rowTop:${rowTop}, vpRowTop:${vpRowTop}`, nodeOrOpts );
5906
+ // this.log( `scrollTo(${node.title}), vpTop:${vpTop}px, scrollTop:${scrollTop}, vpHeight:${vpHeight}, rowTop:${rowTop}, vpRowTop:${vpRowTop}`, nodeOrOpts , options);
5864
5907
  let newScrollTop = null;
5865
5908
  if (vpRowTop >= vpTop) {
5866
5909
  if (vpRowBottom <= vpHeight) ;
@@ -5894,9 +5937,6 @@
5894
5937
  const fixedWidth = this.columns[0]._widthPx;
5895
5938
  const vpWidth = this.element.clientWidth;
5896
5939
  const scrollLeft = this.element.scrollLeft;
5897
- // if (scrollLeft <= 0) {
5898
- // return; // Not scrolled horizontally: Nothing to do
5899
- // }
5900
5940
  const colElem = this.getActiveColElem();
5901
5941
  const colLeft = Number.parseInt(colElem === null || colElem === void 0 ? void 0 : colElem.style.left, 10);
5902
5942
  const colRight = colLeft + Number.parseInt(colElem === null || colElem === void 0 ? void 0 : colElem.style.width, 10);
@@ -5909,13 +5949,11 @@
5909
5949
  // The current column is scrolled outside the right side
5910
5950
  newLeft = colRight - vpWidth;
5911
5951
  }
5952
+ newLeft = Math.max(0, newLeft);
5912
5953
  // util.assert(node._rowIdx != null);
5913
- // this.log(
5914
- // `scrollToHorz(${this.activeColIdx}): ${colLeft}..${colRight}, fixedOfs=${fixedWidth}, vpWidth=${vpWidth}, curLeft=${scrollLeft} -> ${newLeft}`
5915
- // );
5954
+ this.log(`scrollToHorz(${this.activeColIdx}): ${colLeft}..${colRight}, fixedOfs=${fixedWidth}, vpWidth=${vpWidth}, curLeft=${scrollLeft} -> ${newLeft}`);
5916
5955
  this.element.scrollLeft = newLeft;
5917
5956
  // this.setModified(ChangeType.vscroll);
5918
- // }
5919
5957
  }
5920
5958
  /**
5921
5959
  * Set column #colIdx to 'active'.
@@ -6056,24 +6094,24 @@
6056
6094
  }
6057
6095
  /** Set the tree's navigation mode option. */
6058
6096
  setNavigationOption(mode, reset = false) {
6059
- if (!this.isGrid() && mode !== NavigationOptions.row) {
6097
+ if (!this.isGrid() && mode !== NavModeEnum.row) {
6060
6098
  this.logWarn("Plain trees only support row navigation mode.");
6061
6099
  return;
6062
6100
  }
6063
6101
  this.options.navigationModeOption = mode;
6064
6102
  switch (mode) {
6065
- case NavigationOptions.cell:
6103
+ case NavModeEnum.cell:
6066
6104
  this.setCellNav(true);
6067
6105
  break;
6068
- case NavigationOptions.row:
6106
+ case NavModeEnum.row:
6069
6107
  this.setCellNav(false);
6070
6108
  break;
6071
- case NavigationOptions.startCell:
6109
+ case NavModeEnum.startCell:
6072
6110
  if (reset) {
6073
6111
  this.setCellNav(true);
6074
6112
  }
6075
6113
  break;
6076
- case NavigationOptions.startRow:
6114
+ case NavModeEnum.startRow:
6077
6115
  if (reset) {
6078
6116
  this.setCellNav(false);
6079
6117
  }
@@ -6102,7 +6140,9 @@
6102
6140
  }
6103
6141
  }
6104
6142
  }
6105
- /** Update column headers and width. */
6143
+ /** Update column headers and width.
6144
+ * Return true if at least one column width changed.
6145
+ */
6106
6146
  updateColumns(options) {
6107
6147
  options = Object.assign({ calculateCols: true, updateRows: true }, options);
6108
6148
  const defaultMinWidth = 4;
@@ -6142,7 +6182,7 @@
6142
6182
  fixedWidth += px;
6143
6183
  }
6144
6184
  else {
6145
- error(`Invalid column width: ${cw}`);
6185
+ error(`Invalid column width: ${cw} (expected string ending with 'px' or number, e.g. "<num>px" or <int>)`);
6146
6186
  }
6147
6187
  }
6148
6188
  // Share remaining space between non-fixed columns
@@ -6177,7 +6217,7 @@
6177
6217
  // 'position: fixed' requires that the content has the correct size
6178
6218
  const tw = `${totalWidth}px`;
6179
6219
  this.headerElement.style.width = tw;
6180
- this.scrollContainerElement.style.width = tw;
6220
+ this.listContainerElement.style.width = tw;
6181
6221
  // }
6182
6222
  // Every column has now a calculated `_ofsPx` and `_widthPx`
6183
6223
  // this.logInfo("UC", this.columns, vpWidth, this.element.clientWidth, this.element);
@@ -6189,6 +6229,7 @@
6189
6229
  this._updateRows();
6190
6230
  }
6191
6231
  }
6232
+ return modified;
6192
6233
  }
6193
6234
  /** Create/update header markup from `this.columns` definition.
6194
6235
  * @internal
@@ -6220,6 +6261,9 @@
6220
6261
  resizer = '<span class="wb-col-resizer"></span>';
6221
6262
  }
6222
6263
  colElem.innerHTML = `<span class="wb-col-title"${tooltip}>${title}</span>${resizer}`;
6264
+ if (this.isCellNav()) {
6265
+ colElem.classList.toggle("wb-active", i === this.activeColIdx);
6266
+ }
6223
6267
  }
6224
6268
  }
6225
6269
  /**
@@ -6257,7 +6301,7 @@
6257
6301
  const newNodesOnly = !this.changeRedrawRequestPending;
6258
6302
  this.changeRedrawRequestPending = false;
6259
6303
  this.changeScrollRequestPending = false;
6260
- let height = this.scrollContainerElement.clientHeight;
6304
+ let height = this.listContainerElement.clientHeight;
6261
6305
  // We cannot get the height for absolute positioned parent, so look at first col
6262
6306
  // let headerHeight = this.headerElement.clientHeight
6263
6307
  // let headerHeight = this.headerElement.children[0].children[0].clientHeight;
@@ -6266,12 +6310,12 @@
6266
6310
  const wantHeight = this.element.clientHeight - headerHeight - FIX_ADJUST_HEIGHT;
6267
6311
  if (Math.abs(height - wantHeight) > 1.0) {
6268
6312
  // this.log("resize", height, wantHeight);
6269
- this.scrollContainerElement.style.height = wantHeight + "px";
6313
+ this.listContainerElement.style.height = wantHeight + "px";
6270
6314
  height = wantHeight;
6271
6315
  }
6272
6316
  // console.profile(`_updateViewportImmediately()`)
6273
- this.updateColumns({ updateRows: false });
6274
- this._updateRows({ newNodesOnly: newNodesOnly });
6317
+ const modified = this.updateColumns({ updateRows: false });
6318
+ this._updateRows({ newNodesOnly: newNodesOnly && !modified });
6275
6319
  // console.profileEnd(`_updateViewportImmediately()`)
6276
6320
  if (this.options.connectTopBreadcrumb) {
6277
6321
  let path = (_a = this.getTopmostVpNode(true)) === null || _a === void 0 ? void 0 : _a.getPath(false, "title", " > ");
@@ -6393,7 +6437,7 @@
6393
6437
  // Resize tree container
6394
6438
  this.nodeListElement.style.height = `${top}px`;
6395
6439
  // this.log(
6396
- // `render(scrollOfs:${ofs}, ${startIdx}..${endIdx})`,
6440
+ // `_updateRows(scrollOfs:${ofs}, ${startIdx}..${endIdx})`,
6397
6441
  // this.nodeListElement.style.height
6398
6442
  // );
6399
6443
  // this.logTimeEnd(label);
@@ -6501,9 +6545,9 @@
6501
6545
  * Call fn(node) for all nodes in vertical order, bottom up.
6502
6546
  * @internal
6503
6547
  */
6504
- _visitRowsUp(callback, opts) {
6505
- let children, idx, parent, includeHidden = !!opts.includeHidden, node = opts.start || this.root.children[0];
6506
- if (opts.includeSelf !== false) {
6548
+ _visitRowsUp(callback, options) {
6549
+ let children, idx, parent, includeHidden = !!options.includeHidden, node = options.start || this.root.children[0];
6550
+ if (options.includeSelf !== false) {
6507
6551
  if (callback(node) === false) {
6508
6552
  return false;
6509
6553
  }
@@ -6625,7 +6669,7 @@
6625
6669
  }
6626
6670
  Wunderbaum.sequence = 0;
6627
6671
  /** Wunderbaum release version number "MAJOR.MINOR.PATCH". */
6628
- Wunderbaum.version = "v0.0.9"; // Set to semver by 'grunt release'
6672
+ Wunderbaum.version = "v0.1.1"; // Set to semver by 'grunt release'
6629
6673
  /** Expose some useful methods of the util.ts module as `Wunderbaum.util`. */
6630
6674
  Wunderbaum.util = util;
6631
6675