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.
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * Wunderbaum - util
3
3
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
4
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
4
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
5
5
  */
6
6
  /** @module util */
7
7
  /** Readable names for `MouseEvent.button` */
@@ -707,7 +707,7 @@ var util = /*#__PURE__*/Object.freeze({
707
707
  /*!
708
708
  * Wunderbaum - types
709
709
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
710
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
710
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
711
711
  */
712
712
  /** Possible values for `setModified()`. */
713
713
  var ChangeType;
@@ -737,29 +737,29 @@ var NodeStatusType;
737
737
  // paging = "paging",
738
738
  })(NodeStatusType || (NodeStatusType = {}));
739
739
  /** Define the subregion of a node, where an event occurred. */
740
- var TargetType;
741
- (function (TargetType) {
742
- TargetType["unknown"] = "";
743
- TargetType["checkbox"] = "checkbox";
744
- TargetType["column"] = "column";
745
- TargetType["expander"] = "expander";
746
- TargetType["icon"] = "icon";
747
- TargetType["prefix"] = "prefix";
748
- TargetType["title"] = "title";
749
- })(TargetType || (TargetType = {}));
740
+ var NodeRegion;
741
+ (function (NodeRegion) {
742
+ NodeRegion["unknown"] = "";
743
+ NodeRegion["checkbox"] = "checkbox";
744
+ NodeRegion["column"] = "column";
745
+ NodeRegion["expander"] = "expander";
746
+ NodeRegion["icon"] = "icon";
747
+ NodeRegion["prefix"] = "prefix";
748
+ NodeRegion["title"] = "title";
749
+ })(NodeRegion || (NodeRegion = {}));
750
750
  /** Initial navigation mode and possible transition. */
751
- var NavigationOptions;
752
- (function (NavigationOptions) {
753
- NavigationOptions["startRow"] = "startRow";
754
- NavigationOptions["cell"] = "cell";
755
- NavigationOptions["startCell"] = "startCell";
756
- NavigationOptions["row"] = "row";
757
- })(NavigationOptions || (NavigationOptions = {}));
751
+ var NavModeEnum;
752
+ (function (NavModeEnum) {
753
+ NavModeEnum["startRow"] = "startRow";
754
+ NavModeEnum["cell"] = "cell";
755
+ NavModeEnum["startCell"] = "startCell";
756
+ NavModeEnum["row"] = "row";
757
+ })(NavModeEnum || (NavModeEnum = {}));
758
758
 
759
759
  /*!
760
760
  * Wunderbaum - wb_extension_base
761
761
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
762
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
762
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
763
763
  */
764
764
  class WunderbaumExtension {
765
765
  constructor(tree, id, defaults) {
@@ -1050,7 +1050,7 @@ function debounce(func, wait = 0, options = {}) {
1050
1050
  /*!
1051
1051
  * Wunderbaum - ext-filter
1052
1052
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
1053
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
1053
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
1054
1054
  */
1055
1055
  const START_MARKER = "\uFFF7";
1056
1056
  const END_MARKER = "\uFFF8";
@@ -1235,18 +1235,18 @@ class FilterExtension extends WunderbaumExtension {
1235
1235
  /**
1236
1236
  * [ext-filter] Dim or hide nodes.
1237
1237
  *
1238
- * @param {boolean} [opts={autoExpand: false, leavesOnly: false}]
1238
+ * @param {boolean} [options={autoExpand: false, leavesOnly: false}]
1239
1239
  */
1240
- filterNodes(filter, opts) {
1241
- return this._applyFilterNoUpdate(filter, false, opts);
1240
+ filterNodes(filter, options) {
1241
+ return this._applyFilterNoUpdate(filter, false, options);
1242
1242
  }
1243
1243
  /**
1244
1244
  * [ext-filter] Dim or hide whole branches.
1245
1245
  *
1246
- * @param {boolean} [opts={autoExpand: false}]
1246
+ * @param {boolean} [options={autoExpand: false}]
1247
1247
  */
1248
- filterBranches(filter, opts) {
1249
- return this._applyFilterNoUpdate(filter, true, opts);
1248
+ filterBranches(filter, options) {
1249
+ return this._applyFilterNoUpdate(filter, true, options);
1250
1250
  }
1251
1251
  /**
1252
1252
  * [ext-filter] Re-apply current filter.
@@ -1355,7 +1355,7 @@ function _markFuzzyMatchedChars(text, matches, escapeTitles = true) {
1355
1355
  /*!
1356
1356
  * Wunderbaum - ext-keynav
1357
1357
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
1358
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
1358
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
1359
1359
  */
1360
1360
  const QUICKSEARCH_DELAY = 500;
1361
1361
  class KeynavExtension extends WunderbaumExtension {
@@ -1444,19 +1444,30 @@ class KeynavExtension extends WunderbaumExtension {
1444
1444
  }
1445
1445
  // Pre-Evaluate expand/collapse action for LEFT/RIGHT
1446
1446
  switch (eventName) {
1447
+ case "Enter":
1448
+ if (node.isActive()) {
1449
+ if (node.isExpanded()) {
1450
+ eventName = "Subtract"; // callapse
1451
+ }
1452
+ else if (node.isExpandable(true)) {
1453
+ eventName = "Add"; // expand
1454
+ }
1455
+ }
1456
+ break;
1447
1457
  case "ArrowLeft":
1448
1458
  if (node.expanded) {
1449
1459
  eventName = "Subtract"; // collapse
1450
1460
  }
1451
1461
  break;
1452
1462
  case "ArrowRight":
1453
- if (!node.expanded && (node.children || node.lazy)) {
1463
+ if (!node.expanded && node.isExpandable(true)) {
1454
1464
  eventName = "Add"; // expand
1455
1465
  }
1456
- else if (navModeOption === NavigationOptions.startCell ||
1457
- navModeOption === NavigationOptions.startRow) {
1466
+ else if (navModeOption === NavModeEnum.startCell ||
1467
+ navModeOption === NavModeEnum.startRow) {
1468
+ event.preventDefault();
1458
1469
  tree.setCellNav();
1459
- return;
1470
+ return false;
1460
1471
  }
1461
1472
  break;
1462
1473
  }
@@ -1471,7 +1482,7 @@ class KeynavExtension extends WunderbaumExtension {
1471
1482
  case "Subtract":
1472
1483
  node.setExpanded(false);
1473
1484
  break;
1474
- case " ":
1485
+ case " ": // Space
1475
1486
  // if (node.isPagingNode()) {
1476
1487
  // tree._triggerNodeEvent("clickPaging", ctx, event);
1477
1488
  // } else
@@ -1546,7 +1557,16 @@ class KeynavExtension extends WunderbaumExtension {
1546
1557
  }
1547
1558
  else ;
1548
1559
  switch (eventName) {
1549
- case " ":
1560
+ case "+":
1561
+ case "Add":
1562
+ // case "=": // 187: '+' @ Chrome, Safari
1563
+ node.setExpanded(true);
1564
+ break;
1565
+ case "-":
1566
+ case "Subtract":
1567
+ node.setExpanded(false);
1568
+ break;
1569
+ case " ": // Space
1550
1570
  if (tree.activeColIdx === 0 && node.getOption("checkbox")) {
1551
1571
  node.setSelected(!node.isSelected());
1552
1572
  handled = true;
@@ -1567,7 +1587,7 @@ class KeynavExtension extends WunderbaumExtension {
1567
1587
  break;
1568
1588
  case "Enter":
1569
1589
  tree.setFocus(); // Blur prev. input if any
1570
- if (tree.activeColIdx === 0 && node.isExpandable()) {
1590
+ if ((tree.activeColIdx === 0 || isColspan) && node.isExpandable()) {
1571
1591
  node.setExpanded(!node.isExpanded());
1572
1592
  handled = true;
1573
1593
  }
@@ -1578,7 +1598,7 @@ class KeynavExtension extends WunderbaumExtension {
1578
1598
  break;
1579
1599
  case "Escape":
1580
1600
  tree.setFocus(); // Blur prev. input if any
1581
- if (tree.isCellNav() && navModeOption !== NavigationOptions.cell) {
1601
+ if (tree.isCellNav() && navModeOption !== NavModeEnum.cell) {
1582
1602
  tree.setCellNav(false); // row-nav mode
1583
1603
  handled = true;
1584
1604
  }
@@ -1591,7 +1611,7 @@ class KeynavExtension extends WunderbaumExtension {
1591
1611
  else if (!isColspan && tree.activeColIdx > 0) {
1592
1612
  tree.setColumn(tree.activeColIdx - 1);
1593
1613
  }
1594
- else if (navModeOption !== NavigationOptions.cell) {
1614
+ else if (navModeOption !== NavModeEnum.cell) {
1595
1615
  tree.setCellNav(false); // row-nav mode
1596
1616
  }
1597
1617
  handled = true;
@@ -1607,16 +1627,16 @@ class KeynavExtension extends WunderbaumExtension {
1607
1627
  }
1608
1628
  handled = true;
1609
1629
  break;
1610
- case "Home": // Generated by FN + ArrowLeft on Mac
1611
- case "Meta+ArrowLeft":
1630
+ case "Home": // Generated by [Fn] + ArrowLeft on Mac
1631
+ // case "Meta+ArrowLeft":
1612
1632
  tree.setFocus(); // Blur prev. input if any
1613
1633
  if (!isColspan && tree.activeColIdx > 0) {
1614
1634
  tree.setColumn(0);
1615
1635
  }
1616
1636
  handled = true;
1617
1637
  break;
1618
- case "End": // Generated by FN + ArrowRight on Mac
1619
- case "Meta+ArrowRight":
1638
+ case "End": // Generated by [Fn] + ArrowRight on Mac
1639
+ // case "Meta+ArrowRight":
1620
1640
  tree.setFocus(); // Blur prev. input if any
1621
1641
  if (!isColspan && tree.activeColIdx < tree.columns.length - 1) {
1622
1642
  tree.setColumn(tree.columns.length - 1);
@@ -1626,12 +1646,12 @@ class KeynavExtension extends WunderbaumExtension {
1626
1646
  case "ArrowDown":
1627
1647
  case "ArrowUp":
1628
1648
  case "Backspace":
1629
- case "Control+End": // Generated by FN + Control + ArrowRight on Mac
1630
- case "Control+Home": // Generated by FN + Control + Arrowleft on Mac
1631
- case "Meta+ArrowDown":
1632
- case "Meta+ArrowUp":
1633
- case "PageDown": // Generated by FN + ArrowDown on Mac
1634
- case "PageUp": // Generated by FN + ArrowUp on Mac
1649
+ case "Control+End": // Generated by Control + [Fn] + ArrowRight on Mac
1650
+ case "Control+Home": // Generated by Control + [Fn] + Arrowleft on Mac
1651
+ case "Meta+ArrowDown": // [⌘] + ArrowDown on Mac
1652
+ case "Meta+ArrowUp": // [⌘] + ArrowUp on Mac
1653
+ case "PageDown": // Generated by [Fn] + ArrowDown on Mac
1654
+ case "PageUp": // Generated by [Fn] + ArrowUp on Mac
1635
1655
  node.navigate(eventName, { activate: activate, event: event });
1636
1656
  // if (isCellEditMode) {
1637
1657
  // this._getEmbeddedInputElem(null, true); // set focus to input
@@ -1652,7 +1672,7 @@ class KeynavExtension extends WunderbaumExtension {
1652
1672
  /*!
1653
1673
  * Wunderbaum - ext-logger
1654
1674
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
1655
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
1675
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
1656
1676
  */
1657
1677
  class LoggerExtension extends WunderbaumExtension {
1658
1678
  constructor(tree) {
@@ -1692,7 +1712,7 @@ class LoggerExtension extends WunderbaumExtension {
1692
1712
  /*!
1693
1713
  * Wunderbaum - common
1694
1714
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
1695
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
1715
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
1696
1716
  */
1697
1717
  const DEFAULT_DEBUGLEVEL = 4; // Replaced by rollup script
1698
1718
  /**
@@ -1932,7 +1952,7 @@ function inflateSourceData(source) {
1932
1952
  /*!
1933
1953
  * Wunderbaum - ext-dnd
1934
1954
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
1935
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
1955
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
1936
1956
  */
1937
1957
  const nodeMimeType = "application/x-wunderbaum-node";
1938
1958
  class DndExtension extends WunderbaumExtension {
@@ -2046,7 +2066,7 @@ class DndExtension extends WunderbaumExtension {
2046
2066
  }
2047
2067
  /* Implement auto scrolling when drag cursor is in top/bottom area of scroll parent. */
2048
2068
  autoScroll(event) {
2049
- let tree = this.tree, dndOpts = tree.options.dnd, sp = tree.scrollContainerElement, sensitivity = dndOpts.scrollSensitivity, speed = dndOpts.scrollSpeed, scrolled = 0;
2069
+ let tree = this.tree, dndOpts = tree.options.dnd, sp = tree.listContainerElement, sensitivity = dndOpts.scrollSensitivity, speed = dndOpts.scrollSpeed, scrolled = 0;
2050
2070
  const scrollTop = sp.offsetTop;
2051
2071
  if (scrollTop + sp.offsetHeight - event.pageY < sensitivity) {
2052
2072
  const delta = sp.scrollHeight - sp.clientHeight - scrollTop;
@@ -2205,7 +2225,7 @@ class DndExtension extends WunderbaumExtension {
2205
2225
  /*!
2206
2226
  * Wunderbaum - drag_observer
2207
2227
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
2208
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
2228
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
2209
2229
  */
2210
2230
  /**
2211
2231
  * Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'.
@@ -2341,7 +2361,7 @@ class DragObserver {
2341
2361
  /*!
2342
2362
  * Wunderbaum - ext-grid
2343
2363
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
2344
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
2364
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
2345
2365
  */
2346
2366
  class GridExtension extends WunderbaumExtension {
2347
2367
  constructor(tree) {
@@ -2378,7 +2398,7 @@ class GridExtension extends WunderbaumExtension {
2378
2398
  /*!
2379
2399
  * Wunderbaum - deferred
2380
2400
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
2381
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
2401
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
2382
2402
  */
2383
2403
  /**
2384
2404
  * Implement a ES6 Promise, that exposes a resolve() and reject() method.
@@ -2431,7 +2451,7 @@ class Deferred {
2431
2451
  /*!
2432
2452
  * Wunderbaum - wunderbaum_node
2433
2453
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
2434
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
2454
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
2435
2455
  */
2436
2456
  /** Top-level properties that can be passed with `data`. */
2437
2457
  const NODE_PROPS = new Set([
@@ -2694,8 +2714,8 @@ class WunderbaumNode {
2694
2714
  *
2695
2715
  * @see {@link Wunderbaum.applyCommand}
2696
2716
  */
2697
- applyCommand(cmd, opts) {
2698
- return this.tree.applyCommand(cmd, this, opts);
2717
+ applyCommand(cmd, options) {
2718
+ return this.tree.applyCommand(cmd, this, options);
2699
2719
  }
2700
2720
  /**
2701
2721
  * Add/remove one or more classes to `<div class='wb-row'>`.
@@ -2903,7 +2923,7 @@ class WunderbaumNode {
2903
2923
  }
2904
2924
  }
2905
2925
  /**
2906
- * Return multiline string representation of a node/subnode hierarchy.
2926
+ * Return a multiline string representation of a node/subnode hierarchy.
2907
2927
  * Mostly useful for debugging.
2908
2928
  *
2909
2929
  * Example:
@@ -2915,7 +2935,6 @@ class WunderbaumNode {
2915
2935
  * Books
2916
2936
  * ├─ Art of War
2917
2937
  * ╰─ Don Quixote
2918
- * ...
2919
2938
  * ```
2920
2939
  * @see {@link WunderbaumNode.format_iter}
2921
2940
  */
@@ -3037,11 +3056,17 @@ class WunderbaumNode {
3037
3056
  isActive() {
3038
3057
  return this.tree.activeNode === this;
3039
3058
  }
3040
- /** Return true if this node is a *direct* child of `other`.
3059
+ /** Return true if this node is a direct or indirect parent of `other`.
3060
+ * (See also [[isParentOf]].)
3061
+ */
3062
+ isAncestorOf(other) {
3063
+ return other && other.isDescendantOf(this);
3064
+ }
3065
+ /** Return true if this node is a **direct** subnode of `other`.
3041
3066
  * (See also [[isDescendantOf]].)
3042
3067
  */
3043
3068
  isChildOf(other) {
3044
- return this.parent && this.parent === other;
3069
+ return other && this.parent === other;
3045
3070
  }
3046
3071
  /** Return true if this node's title spans all columns, i.e. the node has no
3047
3072
  * grid cells.
@@ -3049,7 +3074,7 @@ class WunderbaumNode {
3049
3074
  isColspan() {
3050
3075
  return !!this.getOption("colspan");
3051
3076
  }
3052
- /** Return true if this node is a direct or indirect sub node of `other`.
3077
+ /** Return true if this node is a direct or indirect subnode of `other`.
3053
3078
  * (See also [[isChildOf]].)
3054
3079
  */
3055
3080
  isDescendantOf(other) {
@@ -3062,7 +3087,7 @@ class WunderbaumNode {
3062
3087
  return true;
3063
3088
  }
3064
3089
  if (p === p.parent) {
3065
- error("Recursive parent link: " + p);
3090
+ error(`Recursive parent link: ${p}`);
3066
3091
  }
3067
3092
  p = p.parent;
3068
3093
  }
@@ -3110,6 +3135,12 @@ class WunderbaumNode {
3110
3135
  isPagingNode() {
3111
3136
  return this.statusNodeType === "paging";
3112
3137
  }
3138
+ /** Return true if this node is a **direct** parent of `other`.
3139
+ * (See also [[isAncestorOf]].)
3140
+ */
3141
+ isParentOf(other) {
3142
+ return other && other.parent === this;
3143
+ }
3113
3144
  /** (experimental) Return true if this node is partially loaded. */
3114
3145
  isPartload() {
3115
3146
  return !!this._partload;
@@ -3756,16 +3787,23 @@ class WunderbaumNode {
3756
3787
  const treeOptions = tree.options;
3757
3788
  const rowDiv = this._rowElem;
3758
3789
  const isNew = !!opts.isNew; // Called by _render_markup()?
3790
+ const preventScroll = !!opts.preventScroll;
3759
3791
  const columns = tree.columns;
3760
3792
  const isColspan = this.isColspan();
3761
3793
  // Row markup already exists
3762
3794
  const nodeElem = rowDiv.querySelector("span.wb-node");
3763
3795
  const titleSpan = nodeElem.querySelector("span.wb-title");
3796
+ const scrollTop = tree.element.scrollTop;
3764
3797
  if (this.titleWithHighlight) {
3765
3798
  titleSpan.innerHTML = this.titleWithHighlight;
3766
3799
  }
3767
3800
  else {
3768
- titleSpan.textContent = this.title;
3801
+ titleSpan.textContent = this.title; // TODO: this triggers scroll events
3802
+ }
3803
+ // NOTE: At least on Safari, this render call triggers a scroll event
3804
+ // probably when a focused input is replaced.
3805
+ if (preventScroll) {
3806
+ tree.element.scrollTop = scrollTop;
3769
3807
  }
3770
3808
  // Set the width of the title span, so overflow ellipsis work
3771
3809
  if (!treeOptions.skeleton) {
@@ -3790,6 +3828,7 @@ class WunderbaumNode {
3790
3828
  this._callEvent("renderStatusNode", {
3791
3829
  isNew: isNew,
3792
3830
  nodeElem: nodeElem,
3831
+ isColspan: isColspan,
3793
3832
  });
3794
3833
  }
3795
3834
  else if (this.parent) {
@@ -3797,9 +3836,8 @@ class WunderbaumNode {
3797
3836
  const renderInfo = this._getRenderInfo();
3798
3837
  this._callEvent("render", {
3799
3838
  isNew: isNew,
3800
- isColspan: isColspan,
3801
- // isDataChange: true,
3802
3839
  nodeElem: nodeElem,
3840
+ isColspan: isColspan,
3803
3841
  allColInfosById: renderInfo.allColInfosById,
3804
3842
  renderColInfosById: renderInfo.renderColInfosById,
3805
3843
  });
@@ -3881,6 +3919,19 @@ class WunderbaumNode {
3881
3919
  this._createIcon(nodeElem, iconSpan, !expanderSpan);
3882
3920
  }
3883
3921
  }
3922
+ // Adjust column width
3923
+ if (opts.resizeCols !== false && !this.isColspan()) {
3924
+ const colElems = rowDiv.querySelectorAll("span.wb-col");
3925
+ let idx = 0;
3926
+ let ofs = 0;
3927
+ for (let colDef of this.tree.columns) {
3928
+ const colElem = colElems[idx];
3929
+ colElem.style.left = `${ofs}px`;
3930
+ colElem.style.width = `${colDef._widthPx}px`;
3931
+ idx++;
3932
+ ofs += colDef._widthPx;
3933
+ }
3934
+ }
3884
3935
  }
3885
3936
  /**
3886
3937
  * Create or update node's markup.
@@ -3900,7 +3951,7 @@ class WunderbaumNode {
3900
3951
  // this.log("render", options);
3901
3952
  const opts = Object.assign({ change: ChangeType.data }, options);
3902
3953
  if (!this._rowElem) {
3903
- opts.change = "row";
3954
+ opts.change = ChangeType.row;
3904
3955
  }
3905
3956
  switch (opts.change) {
3906
3957
  case "status":
@@ -4052,11 +4103,11 @@ class WunderbaumNode {
4052
4103
  if (prev !== this || retrigger) {
4053
4104
  if ((prev === null || prev === void 0 ? void 0 : prev._callEvent("deactivate", {
4054
4105
  nextNode: this,
4055
- orgEvent: orgEvent,
4106
+ event: orgEvent,
4056
4107
  })) === false ||
4057
4108
  this._callEvent("beforeActivate", {
4058
4109
  prevNode: prev,
4059
- orgEvent: orgEvent,
4110
+ event: orgEvent,
4060
4111
  }) === false) {
4061
4112
  return;
4062
4113
  }
@@ -4065,7 +4116,7 @@ class WunderbaumNode {
4065
4116
  }
4066
4117
  }
4067
4118
  else if (prev === this || retrigger) {
4068
- this._callEvent("deactivate", { nextNode: null, orgEvent: orgEvent });
4119
+ this._callEvent("deactivate", { nextNode: null, event: orgEvent });
4069
4120
  }
4070
4121
  }
4071
4122
  if (prev !== this) {
@@ -4086,7 +4137,7 @@ class WunderbaumNode {
4086
4137
  tree.setColumn(options.colIdx);
4087
4138
  }
4088
4139
  if (flag && !noEvents) {
4089
- this._callEvent("activate", { prevNode: prev, orgEvent: orgEvent });
4140
+ this._callEvent("activate", { prevNode: prev, event: orgEvent });
4090
4141
  }
4091
4142
  return this.makeVisible();
4092
4143
  }
@@ -4352,7 +4403,7 @@ WunderbaumNode.sequence = 0;
4352
4403
  /*!
4353
4404
  * Wunderbaum - ext-edit
4354
4405
  * Copyright (c) 2021-2022, Martin Wendt. Released under the MIT license.
4355
- * v0.0.9, Mon, 31 Oct 2022 17:06:10 GMT (https://github.com/mar10/wunderbaum)
4406
+ * v0.1.1, Sun, 27 Nov 2022 07:35:11 GMT (https://github.com/mar10/wunderbaum)
4356
4407
  */
4357
4408
  // const START_MARKER = "\uFFF7";
4358
4409
  class EditExtension extends WunderbaumExtension {
@@ -4502,7 +4553,7 @@ class EditExtension extends WunderbaumExtension {
4502
4553
  // (we also treat a `true` return value as 'use default'):
4503
4554
  if (inputHtml === true || !inputHtml) {
4504
4555
  const title = escapeHtml(node.title);
4505
- inputHtml = `<input type=text class="wb-input-edit" value="${title}" required autocorrect=off>`;
4556
+ inputHtml = `<input type=text class="wb-input-edit" tabindex=-1 value="${title}" required autocorrect=off>`;
4506
4557
  }
4507
4558
  const titleSpan = node
4508
4559
  .getColElem(0)
@@ -4538,11 +4589,11 @@ class EditExtension extends WunderbaumExtension {
4538
4589
  * @param apply
4539
4590
  * @param opts.canKeepOpen
4540
4591
  */
4541
- _stopEditTitle(apply, opts) {
4592
+ _stopEditTitle(apply, options) {
4542
4593
  const focusElem = document.activeElement;
4543
4594
  let newValue = focusElem ? getValueFromElem(focusElem) : null;
4544
4595
  const node = this.curEditNode;
4545
- const forceClose = !!opts.forceClose;
4596
+ const forceClose = !!options.forceClose;
4546
4597
  const validity = this.getPluginOption("validity");
4547
4598
  if (newValue && this.getPluginOption("trim")) {
4548
4599
  newValue = newValue.trim();
@@ -4551,7 +4602,7 @@ class EditExtension extends WunderbaumExtension {
4551
4602
  this.tree.logDebug("stopEditTitle: not in edit mode.");
4552
4603
  return;
4553
4604
  }
4554
- node.logDebug(`stopEditTitle(${apply})`, opts, focusElem, newValue);
4605
+ node.logDebug(`stopEditTitle(${apply})`, options, focusElem, newValue);
4555
4606
  if (apply && newValue !== null && newValue !== node.title) {
4556
4607
  const errMsg = focusElem.validationMessage;
4557
4608
  if (errMsg) {
@@ -4577,22 +4628,24 @@ class EditExtension extends WunderbaumExtension {
4577
4628
  return;
4578
4629
  }
4579
4630
  node === null || node === void 0 ? void 0 : node.setTitle(newValue);
4580
- this.curEditNode.render();
4631
+ // NOTE: At least on Safari, this render call triggers a scroll event
4632
+ // probably because the focused input is replaced.
4633
+ this.curEditNode.render({ preventScroll: true });
4581
4634
  this.curEditNode = null;
4582
4635
  this.relatedNode = null;
4583
4636
  this.tree.setFocus(); // restore focus that was in the input element
4584
4637
  })
4585
4638
  .catch((err) => {
4586
- // this.curEditNode!.render();
4587
- // this.curEditNode = null;
4588
- // this.relatedNode = null;
4639
+ node.logError(err);
4589
4640
  });
4590
4641
  // Trigger 'change' event for embedded `<input>`
4591
4642
  // focusElem.blur();
4592
4643
  }
4593
4644
  else {
4594
4645
  // Discard the embedded `<input>`
4595
- this.curEditNode.render();
4646
+ // NOTE: At least on Safari, this render call triggers a scroll event
4647
+ // probably because the focused input is replaced.
4648
+ this.curEditNode.render({ preventScroll: true });
4596
4649
  this.curEditNode = null;
4597
4650
  this.relatedNode = null;
4598
4651
  // We discarded the <input>, so we have to acquire keyboard focus again
@@ -4645,8 +4698,8 @@ class EditExtension extends WunderbaumExtension {
4645
4698
  * https://github.com/mar10/wunderbaum
4646
4699
  *
4647
4700
  * Released under the MIT license.
4648
- * @version v0.0.9
4649
- * @date Mon, 31 Oct 2022 17:06:10 GMT
4701
+ * @version v0.1.1
4702
+ * @date Sun, 27 Nov 2022 07:35:11 GMT
4650
4703
  */
4651
4704
  class WbSystemRoot extends WunderbaumNode {
4652
4705
  constructor(tree) {
@@ -4830,11 +4883,11 @@ class Wunderbaum {
4830
4883
  }
4831
4884
  //
4832
4885
  this.element.innerHTML += `
4833
- <div class="wb-scroll-container">
4886
+ <div class="wb-list-container">
4834
4887
  <div class="wb-node-list"></div>
4835
4888
  </div>`;
4836
- this.scrollContainerElement = this.element.querySelector("div.wb-scroll-container");
4837
- this.nodeListElement = this.scrollContainerElement.querySelector("div.wb-node-list");
4889
+ this.listContainerElement = this.element.querySelector("div.wb-list-container");
4890
+ this.nodeListElement = this.listContainerElement.querySelector("div.wb-node-list");
4838
4891
  this.headerElement = this.element.querySelector("div.wb-header");
4839
4892
  this.element.classList.toggle("wb-grid", this.columns.length > 1);
4840
4893
  this._initExtensions();
@@ -4855,10 +4908,10 @@ class Wunderbaum {
4855
4908
  // The source may have defined columns, so we may adjust the nav mode
4856
4909
  if (opts.navigationModeOption == null) {
4857
4910
  if (this.isGrid()) {
4858
- this.setNavigationOption(NavigationOptions.cell);
4911
+ this.setNavigationOption(NavModeEnum.cell);
4859
4912
  }
4860
4913
  else {
4861
- this.setNavigationOption(NavigationOptions.row);
4914
+ this.setNavigationOption(NavModeEnum.row);
4862
4915
  }
4863
4916
  }
4864
4917
  else {
@@ -4883,13 +4936,9 @@ class Wunderbaum {
4883
4936
  this.setModified(ChangeType.any);
4884
4937
  // --- Bind listeners
4885
4938
  this.element.addEventListener("scroll", (e) => {
4886
- // this.log("scroll", e);
4939
+ // this.log(`scroll, scrollTop:${e.target.scrollTop}`, e);
4887
4940
  this.setModified(ChangeType.vscroll);
4888
4941
  });
4889
- // this.scrollContainerElement.addEventListener("scroll", (e: Event) => {
4890
- // this.log("scroll", e)
4891
- // this.setModified(ChangeType.vscroll);
4892
- // });
4893
4942
  this.resizeObserver = new ResizeObserver((entries) => {
4894
4943
  this.setModified(ChangeType.vscroll);
4895
4944
  // this.log("ResizeObserver: Size changed", entries);
@@ -4899,16 +4948,6 @@ class Wunderbaum {
4899
4948
  const info = Wunderbaum.getEventInfo(e);
4900
4949
  const node = info.node;
4901
4950
  // this.log("click", info, e);
4902
- // if( (e.target as HTMLElement).matches("input[type=checkbox]")){
4903
- // // Click on an embedded checkbox triggers a change event.
4904
- // // We return here, before the `setActive()` performs a render
4905
- // this.log("click - cb", info, e);
4906
- // // e.preventDefault()
4907
- // setTimeout(()=>{
4908
- // // (e.target as HTMLElement).click()
4909
- // }, 50)
4910
- // // return
4911
- // }
4912
4951
  if (this._callEvent("click", { event: e, node: node, info: info }) === false) {
4913
4952
  this.lastClickTime = Date.now();
4914
4953
  return false;
@@ -4929,15 +4968,27 @@ class Wunderbaum {
4929
4968
  else {
4930
4969
  node.setActive(true, { event: e });
4931
4970
  }
4932
- if (info.region === TargetType.expander) {
4971
+ if (info.region === NodeRegion.expander) {
4933
4972
  node.setExpanded(!node.isExpanded());
4934
4973
  }
4935
- else if (info.region === TargetType.checkbox) {
4974
+ else if (info.region === NodeRegion.checkbox) {
4936
4975
  node.setSelected(!node.isSelected());
4937
4976
  }
4938
4977
  }
4939
4978
  this.lastClickTime = Date.now();
4940
4979
  });
4980
+ onEvent(this.nodeListElement, "dblclick", "div.wb-row", (e) => {
4981
+ const info = Wunderbaum.getEventInfo(e);
4982
+ const node = info.node;
4983
+ // this.log("dblclick", info, e);
4984
+ if (this._callEvent("dblclick", { event: e, node: node, info: info }) ===
4985
+ false) {
4986
+ return false;
4987
+ }
4988
+ if (node && info.colIdx === 0 && node.isExpandable()) {
4989
+ node.setExpanded(!node.isExpanded());
4990
+ }
4991
+ });
4941
4992
  onEvent(this.element, "keydown", (e) => {
4942
4993
  const info = Wunderbaum.getEventInfo(e);
4943
4994
  const eventName = eventToString(e);
@@ -5555,7 +5606,7 @@ class Wunderbaum {
5555
5606
  */
5556
5607
  findRelatedNode(node, where, includeHidden = false) {
5557
5608
  let res = null;
5558
- const pageSize = Math.floor(this.scrollContainerElement.clientHeight / ROW_HEIGHT);
5609
+ const pageSize = Math.floor(this.listContainerElement.clientHeight / ROW_HEIGHT);
5559
5610
  switch (where) {
5560
5611
  case "parent":
5561
5612
  if (node.parent && node.parent.parent) {
@@ -5706,37 +5757,37 @@ class Wunderbaum {
5706
5757
  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 = {
5707
5758
  tree: tree,
5708
5759
  node: node,
5709
- region: TargetType.unknown,
5760
+ region: NodeRegion.unknown,
5710
5761
  colDef: undefined,
5711
5762
  colIdx: -1,
5712
5763
  colId: undefined,
5713
5764
  colElem: parentCol,
5714
5765
  };
5715
5766
  if (cl.contains("wb-title")) {
5716
- res.region = TargetType.title;
5767
+ res.region = NodeRegion.title;
5717
5768
  }
5718
5769
  else if (cl.contains("wb-expander")) {
5719
5770
  res.region =
5720
- node.hasChildren() === false ? TargetType.prefix : TargetType.expander;
5771
+ node.hasChildren() === false ? NodeRegion.prefix : NodeRegion.expander;
5721
5772
  }
5722
5773
  else if (cl.contains("wb-checkbox")) {
5723
- res.region = TargetType.checkbox;
5774
+ res.region = NodeRegion.checkbox;
5724
5775
  }
5725
5776
  else if (cl.contains("wb-icon")) {
5726
5777
  //|| cl.contains("wb-custom-icon")) {
5727
- res.region = TargetType.icon;
5778
+ res.region = NodeRegion.icon;
5728
5779
  }
5729
5780
  else if (cl.contains("wb-node")) {
5730
- res.region = TargetType.title;
5781
+ res.region = NodeRegion.title;
5731
5782
  }
5732
5783
  else if (parentCol) {
5733
- res.region = TargetType.column;
5784
+ res.region = NodeRegion.column;
5734
5785
  const idx = Array.prototype.indexOf.call(parentCol.parentNode.children, parentCol);
5735
5786
  res.colIdx = idx;
5736
5787
  }
5737
5788
  else if (cl.contains("wb-row")) {
5738
5789
  // Plain tree
5739
- res.region = TargetType.title;
5790
+ res.region = NodeRegion.title;
5740
5791
  }
5741
5792
  else {
5742
5793
  // Somewhere near the title
@@ -5753,14 +5804,6 @@ class Wunderbaum {
5753
5804
  // this.log("Event", event, res);
5754
5805
  return res;
5755
5806
  }
5756
- // /** Return a string describing the affected node region for a mouse event.
5757
- // *
5758
- // * @param {Event} event Mouse event, e.g. click, mousemove, ...
5759
- // * @returns {string} 'title' | 'prefix' | 'expander' | 'checkbox' | 'icon' | undefined
5760
- // */
5761
- // getEventNodeRegion(event: Event) {
5762
- // return this.getEventInfo(event).region;
5763
- // }
5764
5807
  /**
5765
5808
  * Return readable string representation for this instance.
5766
5809
  * @internal
@@ -5854,7 +5897,7 @@ class Wunderbaum {
5854
5897
  const vpRowTop = rowTop - scrollTop;
5855
5898
  const vpRowBottom = vpRowTop + ROW_HEIGHT;
5856
5899
  const topNode = options === null || options === void 0 ? void 0 : options.topNode;
5857
- // this.log( `scrollTo(${node.title}), vpTop:${vpTop}px, scrollTop:${scrollTop}, vpHeight:${vpHeight}, rowTop:${rowTop}, vpRowTop:${vpRowTop}`, nodeOrOpts );
5900
+ // this.log( `scrollTo(${node.title}), vpTop:${vpTop}px, scrollTop:${scrollTop}, vpHeight:${vpHeight}, rowTop:${rowTop}, vpRowTop:${vpRowTop}`, nodeOrOpts , options);
5858
5901
  let newScrollTop = null;
5859
5902
  if (vpRowTop >= vpTop) {
5860
5903
  if (vpRowBottom <= vpHeight) ;
@@ -5888,9 +5931,6 @@ class Wunderbaum {
5888
5931
  const fixedWidth = this.columns[0]._widthPx;
5889
5932
  const vpWidth = this.element.clientWidth;
5890
5933
  const scrollLeft = this.element.scrollLeft;
5891
- // if (scrollLeft <= 0) {
5892
- // return; // Not scrolled horizontally: Nothing to do
5893
- // }
5894
5934
  const colElem = this.getActiveColElem();
5895
5935
  const colLeft = Number.parseInt(colElem === null || colElem === void 0 ? void 0 : colElem.style.left, 10);
5896
5936
  const colRight = colLeft + Number.parseInt(colElem === null || colElem === void 0 ? void 0 : colElem.style.width, 10);
@@ -5903,13 +5943,11 @@ class Wunderbaum {
5903
5943
  // The current column is scrolled outside the right side
5904
5944
  newLeft = colRight - vpWidth;
5905
5945
  }
5946
+ newLeft = Math.max(0, newLeft);
5906
5947
  // util.assert(node._rowIdx != null);
5907
- // this.log(
5908
- // `scrollToHorz(${this.activeColIdx}): ${colLeft}..${colRight}, fixedOfs=${fixedWidth}, vpWidth=${vpWidth}, curLeft=${scrollLeft} -> ${newLeft}`
5909
- // );
5948
+ this.log(`scrollToHorz(${this.activeColIdx}): ${colLeft}..${colRight}, fixedOfs=${fixedWidth}, vpWidth=${vpWidth}, curLeft=${scrollLeft} -> ${newLeft}`);
5910
5949
  this.element.scrollLeft = newLeft;
5911
5950
  // this.setModified(ChangeType.vscroll);
5912
- // }
5913
5951
  }
5914
5952
  /**
5915
5953
  * Set column #colIdx to 'active'.
@@ -6050,24 +6088,24 @@ class Wunderbaum {
6050
6088
  }
6051
6089
  /** Set the tree's navigation mode option. */
6052
6090
  setNavigationOption(mode, reset = false) {
6053
- if (!this.isGrid() && mode !== NavigationOptions.row) {
6091
+ if (!this.isGrid() && mode !== NavModeEnum.row) {
6054
6092
  this.logWarn("Plain trees only support row navigation mode.");
6055
6093
  return;
6056
6094
  }
6057
6095
  this.options.navigationModeOption = mode;
6058
6096
  switch (mode) {
6059
- case NavigationOptions.cell:
6097
+ case NavModeEnum.cell:
6060
6098
  this.setCellNav(true);
6061
6099
  break;
6062
- case NavigationOptions.row:
6100
+ case NavModeEnum.row:
6063
6101
  this.setCellNav(false);
6064
6102
  break;
6065
- case NavigationOptions.startCell:
6103
+ case NavModeEnum.startCell:
6066
6104
  if (reset) {
6067
6105
  this.setCellNav(true);
6068
6106
  }
6069
6107
  break;
6070
- case NavigationOptions.startRow:
6108
+ case NavModeEnum.startRow:
6071
6109
  if (reset) {
6072
6110
  this.setCellNav(false);
6073
6111
  }
@@ -6096,7 +6134,9 @@ class Wunderbaum {
6096
6134
  }
6097
6135
  }
6098
6136
  }
6099
- /** Update column headers and width. */
6137
+ /** Update column headers and width.
6138
+ * Return true if at least one column width changed.
6139
+ */
6100
6140
  updateColumns(options) {
6101
6141
  options = Object.assign({ calculateCols: true, updateRows: true }, options);
6102
6142
  const defaultMinWidth = 4;
@@ -6136,7 +6176,7 @@ class Wunderbaum {
6136
6176
  fixedWidth += px;
6137
6177
  }
6138
6178
  else {
6139
- error(`Invalid column width: ${cw}`);
6179
+ error(`Invalid column width: ${cw} (expected string ending with 'px' or number, e.g. "<num>px" or <int>)`);
6140
6180
  }
6141
6181
  }
6142
6182
  // Share remaining space between non-fixed columns
@@ -6171,7 +6211,7 @@ class Wunderbaum {
6171
6211
  // 'position: fixed' requires that the content has the correct size
6172
6212
  const tw = `${totalWidth}px`;
6173
6213
  this.headerElement.style.width = tw;
6174
- this.scrollContainerElement.style.width = tw;
6214
+ this.listContainerElement.style.width = tw;
6175
6215
  // }
6176
6216
  // Every column has now a calculated `_ofsPx` and `_widthPx`
6177
6217
  // this.logInfo("UC", this.columns, vpWidth, this.element.clientWidth, this.element);
@@ -6183,6 +6223,7 @@ class Wunderbaum {
6183
6223
  this._updateRows();
6184
6224
  }
6185
6225
  }
6226
+ return modified;
6186
6227
  }
6187
6228
  /** Create/update header markup from `this.columns` definition.
6188
6229
  * @internal
@@ -6214,6 +6255,9 @@ class Wunderbaum {
6214
6255
  resizer = '<span class="wb-col-resizer"></span>';
6215
6256
  }
6216
6257
  colElem.innerHTML = `<span class="wb-col-title"${tooltip}>${title}</span>${resizer}`;
6258
+ if (this.isCellNav()) {
6259
+ colElem.classList.toggle("wb-active", i === this.activeColIdx);
6260
+ }
6217
6261
  }
6218
6262
  }
6219
6263
  /**
@@ -6251,7 +6295,7 @@ class Wunderbaum {
6251
6295
  const newNodesOnly = !this.changeRedrawRequestPending;
6252
6296
  this.changeRedrawRequestPending = false;
6253
6297
  this.changeScrollRequestPending = false;
6254
- let height = this.scrollContainerElement.clientHeight;
6298
+ let height = this.listContainerElement.clientHeight;
6255
6299
  // We cannot get the height for absolute positioned parent, so look at first col
6256
6300
  // let headerHeight = this.headerElement.clientHeight
6257
6301
  // let headerHeight = this.headerElement.children[0].children[0].clientHeight;
@@ -6260,12 +6304,12 @@ class Wunderbaum {
6260
6304
  const wantHeight = this.element.clientHeight - headerHeight - FIX_ADJUST_HEIGHT;
6261
6305
  if (Math.abs(height - wantHeight) > 1.0) {
6262
6306
  // this.log("resize", height, wantHeight);
6263
- this.scrollContainerElement.style.height = wantHeight + "px";
6307
+ this.listContainerElement.style.height = wantHeight + "px";
6264
6308
  height = wantHeight;
6265
6309
  }
6266
6310
  // console.profile(`_updateViewportImmediately()`)
6267
- this.updateColumns({ updateRows: false });
6268
- this._updateRows({ newNodesOnly: newNodesOnly });
6311
+ const modified = this.updateColumns({ updateRows: false });
6312
+ this._updateRows({ newNodesOnly: newNodesOnly && !modified });
6269
6313
  // console.profileEnd(`_updateViewportImmediately()`)
6270
6314
  if (this.options.connectTopBreadcrumb) {
6271
6315
  let path = (_a = this.getTopmostVpNode(true)) === null || _a === void 0 ? void 0 : _a.getPath(false, "title", " > ");
@@ -6387,7 +6431,7 @@ class Wunderbaum {
6387
6431
  // Resize tree container
6388
6432
  this.nodeListElement.style.height = `${top}px`;
6389
6433
  // this.log(
6390
- // `render(scrollOfs:${ofs}, ${startIdx}..${endIdx})`,
6434
+ // `_updateRows(scrollOfs:${ofs}, ${startIdx}..${endIdx})`,
6391
6435
  // this.nodeListElement.style.height
6392
6436
  // );
6393
6437
  // this.logTimeEnd(label);
@@ -6495,9 +6539,9 @@ class Wunderbaum {
6495
6539
  * Call fn(node) for all nodes in vertical order, bottom up.
6496
6540
  * @internal
6497
6541
  */
6498
- _visitRowsUp(callback, opts) {
6499
- let children, idx, parent, includeHidden = !!opts.includeHidden, node = opts.start || this.root.children[0];
6500
- if (opts.includeSelf !== false) {
6542
+ _visitRowsUp(callback, options) {
6543
+ let children, idx, parent, includeHidden = !!options.includeHidden, node = options.start || this.root.children[0];
6544
+ if (options.includeSelf !== false) {
6501
6545
  if (callback(node) === false) {
6502
6546
  return false;
6503
6547
  }
@@ -6619,7 +6663,7 @@ class Wunderbaum {
6619
6663
  }
6620
6664
  Wunderbaum.sequence = 0;
6621
6665
  /** Wunderbaum release version number "MAJOR.MINOR.PATCH". */
6622
- Wunderbaum.version = "v0.0.9"; // Set to semver by 'grunt release'
6666
+ Wunderbaum.version = "v0.1.1"; // Set to semver by 'grunt release'
6623
6667
  /** Expose some useful methods of the util.ts module as `Wunderbaum.util`. */
6624
6668
  Wunderbaum.util = util;
6625
6669