wunderbaum 0.10.0 → 0.11.0

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.
@@ -294,7 +294,7 @@
294
294
  /*!
295
295
  * Wunderbaum - util
296
296
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
297
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
297
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
298
298
  */
299
299
  /** @module util */
300
300
  /** Readable names for `MouseEvent.button` */
@@ -770,7 +770,7 @@
770
770
  function isArray(obj) {
771
771
  return Array.isArray(obj);
772
772
  }
773
- /** Return true if `obj` is of type `Object` and has no propertied. */
773
+ /** Return true if `obj` is of type `Object` and has no properties. */
774
774
  function isEmptyObject(obj) {
775
775
  return Object.keys(obj).length === 0 && obj.constructor === Object;
776
776
  }
@@ -926,6 +926,11 @@
926
926
  // Use value from value options dict, fallback do default
927
927
  return value !== null && value !== void 0 ? value : defaultValue;
928
928
  }
929
+ /** Return the next value from a list of values (rotating). @since 0.11 */
930
+ function rotate(value, values) {
931
+ const idx = values.indexOf(value);
932
+ return values[(idx + 1) % values.length];
933
+ }
929
934
  /** Convert an Array or space-separated string to a Set. */
930
935
  function toSet(val) {
931
936
  if (val instanceof Set) {
@@ -949,15 +954,12 @@
949
954
  *
950
955
  * Example:
951
956
  * ```js
952
- * const width = util.toPixel("123px", 100);
957
+ * let x = undefined;
958
+ * let y = "123px";
959
+ * const width = util.toPixel(x, y, 100); // returns 123
953
960
  * ```
954
961
  */
955
- function toPixel(
956
- // val: string | number | undefined | null,
957
- ...defaults) {
958
- // if (typeof val === "number") {
959
- // return val;
960
- // }
962
+ function toPixel(...defaults) {
961
963
  for (const d of defaults) {
962
964
  if (typeof d === "number") {
963
965
  return d;
@@ -969,19 +971,14 @@
969
971
  }
970
972
  throw new Error(`Expected a string like '123px': ${defaults}`);
971
973
  }
972
- /** Evaluate a boolean value using default if undefined.
974
+ /** Return the the boolean value of the first non-null element.
973
975
  * Example:
974
976
  * ```js
975
977
  * const opts = { flag: true };
976
- * const value = util.toBool(opts.flag, otherVar, false);
978
+ * const value = util.toBool(opts.foo, opts.flag, false); // returns true
977
979
  * ```
978
980
  */
979
- function toBool(
980
- // val: boolean | undefined | null,
981
- ...boolDefaults) {
982
- // if (val != null) {
983
- // return !!val;
984
- // }
981
+ function toBool(...boolDefaults) {
985
982
  for (const d of boolDefaults) {
986
983
  if (d != null) {
987
984
  return !!d;
@@ -1125,6 +1122,7 @@
1125
1122
  noop: noop,
1126
1123
  onEvent: onEvent,
1127
1124
  overrideMethod: overrideMethod,
1125
+ rotate: rotate,
1128
1126
  setElemDisplay: setElemDisplay,
1129
1127
  setTimeoutPromise: setTimeoutPromise,
1130
1128
  setValueToElem: setValueToElem,
@@ -1140,10 +1138,10 @@
1140
1138
  /*!
1141
1139
  * Wunderbaum - types
1142
1140
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
1143
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
1141
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
1144
1142
  */
1145
1143
  /**
1146
- * Possible values for {@link WunderbaumNode.update()} and {@link Wunderbaum.update()}.
1144
+ * Possible values for {@link WunderbaumNode.update} and {@link Wunderbaum.update}.
1147
1145
  */
1148
1146
  var ChangeType;
1149
1147
  (function (ChangeType) {
@@ -1172,7 +1170,7 @@
1172
1170
  RenderFlag["redraw"] = "redraw";
1173
1171
  RenderFlag["scroll"] = "scroll";
1174
1172
  })(RenderFlag || (RenderFlag = {}));
1175
- /** Possible values for {@link WunderbaumNode.setStatus()}. */
1173
+ /** Possible values for {@link WunderbaumNode.setStatus}. */
1176
1174
  var NodeStatusType;
1177
1175
  (function (NodeStatusType) {
1178
1176
  NodeStatusType["ok"] = "ok";
@@ -1204,7 +1202,7 @@
1204
1202
  /*!
1205
1203
  * Wunderbaum - wb_extension_base
1206
1204
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
1207
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
1205
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
1208
1206
  */
1209
1207
  class WunderbaumExtension {
1210
1208
  constructor(tree, id, defaults) {
@@ -1263,7 +1261,7 @@
1263
1261
  /*!
1264
1262
  * Wunderbaum - ext-filter
1265
1263
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
1266
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
1264
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
1267
1265
  */
1268
1266
  const START_MARKER = "\uFFF7";
1269
1267
  const END_MARKER = "\uFFF8";
@@ -1290,6 +1288,7 @@
1290
1288
  const connectInput = this.getPluginOption("connectInput");
1291
1289
  if (connectInput) {
1292
1290
  this.queryInput = elemFromSelector(connectInput);
1291
+ assert(this.queryInput, `Invalid 'filter.connectInput' option: ${connectInput}.`);
1293
1292
  onEvent(this.queryInput, "input", debounce((e) => {
1294
1293
  // this.tree.log("query", e);
1295
1294
  this.filterNodes(this.queryInput.value.trim(), {});
@@ -1587,7 +1586,7 @@
1587
1586
  /*!
1588
1587
  * Wunderbaum - ext-keynav
1589
1588
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
1590
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
1589
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
1591
1590
  */
1592
1591
  const QUICKSEARCH_DELAY = 500;
1593
1592
  class KeynavExtension extends WunderbaumExtension {
@@ -1951,7 +1950,7 @@
1951
1950
  /*!
1952
1951
  * Wunderbaum - ext-logger
1953
1952
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
1954
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
1953
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
1955
1954
  */
1956
1955
  class LoggerExtension extends WunderbaumExtension {
1957
1956
  constructor(tree) {
@@ -1993,7 +1992,7 @@
1993
1992
  /*!
1994
1993
  * Wunderbaum - common
1995
1994
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
1996
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
1995
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
1997
1996
  */
1998
1997
  const DEFAULT_DEBUGLEVEL = 3; // Replaced by rollup script
1999
1998
  /**
@@ -2048,6 +2047,15 @@
2048
2047
  folderOpen: "bi bi-folder2-open",
2049
2048
  folderLazy: "bi bi-folder-symlink",
2050
2049
  doc: "bi bi-file-earmark",
2050
+ colSortable: "bi bi-chevron-expand",
2051
+ // colSortable: "bi bi-arrow-down-up",
2052
+ // colSortAsc: "bi bi-chevron-down",
2053
+ // colSortDesc: "bi bi-chevron-up",
2054
+ colSortAsc: "bi bi-arrow-down",
2055
+ colSortDesc: "bi bi-arrow-up",
2056
+ colFilter: "bi bi-filter-circle",
2057
+ colFilterActive: "bi bi-filter-circle-fill wb-helper-invalid",
2058
+ colMenu: "bi bi-three-dots-vertical",
2051
2059
  },
2052
2060
  fontawesome6: {
2053
2061
  error: "fa-solid fa-triangle-exclamation",
@@ -2066,6 +2074,12 @@
2066
2074
  folderOpen: "fa-regular fa-folder-open",
2067
2075
  folderLazy: "fa-solid fa-folder-plus",
2068
2076
  doc: "fa-regular fa-file",
2077
+ colSortable: "fa-solid fa-fw fa-sort",
2078
+ colSortAsc: "fa-solid fa-fw fa-sort-up",
2079
+ colSortDesc: "fa-solid fa-fw fa-sort-down",
2080
+ colFilter: "fa-solid fa-fw fa-filter",
2081
+ colFilterActive: "fa-solid fa-fw fa-filter wb-helper-invalid",
2082
+ colMenu: "fa-solid fa-fw fa-ellipsis-v",
2069
2083
  },
2070
2084
  };
2071
2085
  /** Dict keys that are evaluated by source loader (others are added to `tree.data` instead). */
@@ -2114,7 +2128,7 @@
2114
2128
  };
2115
2129
  /** Return a callback that returns true if the node title matches the string
2116
2130
  * or regular expression.
2117
- * @see {@link WunderbaumNode.findAll()}
2131
+ * @see {@link WunderbaumNode.findAll}
2118
2132
  */
2119
2133
  function makeNodeTitleMatcher(match) {
2120
2134
  if (match instanceof RegExp) {
@@ -2318,7 +2332,7 @@
2318
2332
  /*!
2319
2333
  * Wunderbaum - ext-dnd
2320
2334
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
2321
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
2335
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
2322
2336
  */
2323
2337
  const nodeMimeType = "application/x-wunderbaum-node";
2324
2338
  class DndExtension extends WunderbaumExtension {
@@ -2763,7 +2777,7 @@
2763
2777
  /*!
2764
2778
  * Wunderbaum - drag_observer
2765
2779
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
2766
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
2780
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
2767
2781
  */
2768
2782
  /**
2769
2783
  * Convert mouse- and touch events to 'dragstart', 'drag', and 'dragstop'.
@@ -2912,7 +2926,7 @@
2912
2926
  /*!
2913
2927
  * Wunderbaum - ext-grid
2914
2928
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
2915
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
2929
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
2916
2930
  */
2917
2931
  class GridExtension extends WunderbaumExtension {
2918
2932
  constructor(tree) {
@@ -2929,7 +2943,7 @@
2929
2943
  const colDef = info.colDef;
2930
2944
  const allow = colDef &&
2931
2945
  this.tree.element.contains(e.dragElem) &&
2932
- toBool(colDef.resizable, tree.options.resizableColumns, false);
2946
+ toBool(colDef.resizable, tree.options.columnsResizable, false);
2933
2947
  // this.tree.log("dragstart", colDef, e, info);
2934
2948
  this.tree.element.classList.toggle("wb-col-resizing", !!allow);
2935
2949
  info.colElem.classList.toggle("wb-col-resizing", !!allow);
@@ -3003,7 +3017,7 @@
3003
3017
  /*!
3004
3018
  * Wunderbaum - deferred
3005
3019
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3006
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
3020
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
3007
3021
  */
3008
3022
  /**
3009
3023
  * Implement a ES6 Promise, that exposes a resolve() and reject() method.
@@ -3056,7 +3070,7 @@
3056
3070
  /*!
3057
3071
  * Wunderbaum - wunderbaum_node
3058
3072
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
3059
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
3073
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
3060
3074
  */
3061
3075
  /** WunderbaumNode properties that can be passed with source data.
3062
3076
  * (Any other source properties will be stored as `node.data.PROP`.)
@@ -3099,6 +3113,12 @@
3099
3113
  * @see Use {@link setKey} to modify.
3100
3114
  */
3101
3115
  this.refKey = undefined;
3116
+ /**
3117
+ * Array of child nodes (null for leaf nodes).
3118
+ * For lazy nodes, this is `null` or ùndefined` until the children are loaded
3119
+ * and leaf nodes may be `[]` (empty array).
3120
+ * @see {@link hasChildren}, {@link addChildren}, {@link lazy}.
3121
+ */
3102
3122
  this.children = null;
3103
3123
  /** Additional classes added to `div.wb-row`.
3104
3124
  * @see {@link hasClass}, {@link setClass}. */
@@ -3686,7 +3706,7 @@
3686
3706
  hasClass(className) {
3687
3707
  return this.classes ? this.classes.has(className) : false;
3688
3708
  }
3689
- /** Return true if node ist the currently focused node. */
3709
+ /** Return true if node ist the currently focused node. @since 0.9.0 */
3690
3710
  hasFocus() {
3691
3711
  return this.tree.focusNode === this;
3692
3712
  }
@@ -3908,6 +3928,8 @@
3908
3928
  if (tree.options.selectMode === "hier") {
3909
3929
  this.fixSelection3FromEndNodes();
3910
3930
  }
3931
+ // Allow to un-sort nodes after sorting
3932
+ this.resetNativeChildOrder();
3911
3933
  this._callEvent("load");
3912
3934
  }
3913
3935
  async _fetchWithOptions(source) {
@@ -4851,7 +4873,7 @@
4851
4873
  *
4852
4874
  * @param name name of the option property (on node and tree)
4853
4875
  * @param defaultValue return this if nothing else matched
4854
- * {@link Wunderbaum.getOption|Wunderbaum.getOption()}
4876
+ * {@link Wunderbaum.getOption|Wunderbaum.getOption}
4855
4877
  */
4856
4878
  getOption(name, defaultValue) {
4857
4879
  const tree = this.tree;
@@ -4887,7 +4909,7 @@
4887
4909
  return value !== null && value !== void 0 ? value : defaultValue;
4888
4910
  }
4889
4911
  /** Make sure that this node is visible in the viewport.
4890
- * @see {@link Wunderbaum.scrollTo|Wunderbaum.scrollTo()}
4912
+ * @see {@link Wunderbaum.scrollTo|Wunderbaum.scrollTo}
4891
4913
  */
4892
4914
  async scrollIntoView(options) {
4893
4915
  const opts = Object.assign({ node: this }, options);
@@ -5026,9 +5048,9 @@
5026
5048
  * and column content. It can be reduced to 'ChangeType.status' if only
5027
5049
  * active/focus/selected state has changed.
5028
5050
  *
5029
- * This method will eventually call {@link WunderbaumNode._render()} with
5051
+ * This method will eventually call {@link WunderbaumNode._render} with
5030
5052
  * default options, but may be more consistent with the tree's
5031
- * {@link Wunderbaum.update()} API.
5053
+ * {@link Wunderbaum.update} API.
5032
5054
  */
5033
5055
  update(change = ChangeType.data) {
5034
5056
  assert(change === ChangeType.status || change === ChangeType.data, `Invalid change type ${change}`);
@@ -5357,6 +5379,80 @@
5357
5379
  this.tree.update(ChangeType.structure);
5358
5380
  // this.triggerModify("sort"); // TODO
5359
5381
  }
5382
+ /**
5383
+ * Renumber nodes `_nativeIndex`. This is useful to allow to restore the
5384
+ * order after sorting a column.
5385
+ * This method is automatically called after loading new child nodes.
5386
+ * @since 0.11.0
5387
+ */
5388
+ resetNativeChildOrder(options) {
5389
+ const { recursive = true, propName = "_nativeIndex" } = options !== null && options !== void 0 ? options : {};
5390
+ if (this.children) {
5391
+ this.children.forEach((child, i) => {
5392
+ child.data[propName] = i;
5393
+ if (recursive && child.children) {
5394
+ child.resetNativeChildOrder(options);
5395
+ }
5396
+ });
5397
+ }
5398
+ }
5399
+ /**
5400
+ * Convenience method to implement column sorting.
5401
+ * @since 0.11.0
5402
+ */
5403
+ sortByProperty(options) {
5404
+ var _a, _b, _c;
5405
+ const { caseInsensitive = true, deep = true, nativeOrderPropName = "_nativeIndex", updateColInfo = false, } = options;
5406
+ let order;
5407
+ let colDef;
5408
+ if (updateColInfo) {
5409
+ colDef = this.tree["_columnsById"][options.colId];
5410
+ assert(colDef, `Invalid colId specified: ${options.colId}`);
5411
+ order =
5412
+ (_a = options.order) !== null && _a !== void 0 ? _a : rotate(colDef.sortOrder, ["asc", "desc", undefined]);
5413
+ for (const col of this.tree.columns) {
5414
+ col.sortOrder = col === colDef ? order : undefined;
5415
+ }
5416
+ this.tree.update(ChangeType.colStructure);
5417
+ }
5418
+ else {
5419
+ order = (_b = options.order) !== null && _b !== void 0 ? _b : "asc";
5420
+ }
5421
+ let propName = (_c = options.propName) !== null && _c !== void 0 ? _c : (options.colId || "");
5422
+ if (propName === "*") {
5423
+ propName = "title";
5424
+ }
5425
+ if (order == null) {
5426
+ propName = nativeOrderPropName;
5427
+ order = "asc";
5428
+ }
5429
+ this.logDebug(`sortByProperty(), propName=${propName}, ${order}`, options);
5430
+ assert(propName, "No property name specified");
5431
+ const cmp = (a, b) => {
5432
+ let av, bv;
5433
+ if (NODE_DICT_PROPS.has(propName)) {
5434
+ av = a[propName];
5435
+ bv = b[propName];
5436
+ }
5437
+ else {
5438
+ av = a.data[propName];
5439
+ bv = b.data[propName];
5440
+ }
5441
+ if (caseInsensitive) {
5442
+ if (typeof av === "string") {
5443
+ av = av.toLowerCase();
5444
+ }
5445
+ if (typeof bv === "string") {
5446
+ bv = bv.toLowerCase();
5447
+ }
5448
+ }
5449
+ if (order === "desc") {
5450
+ return av === bv ? 0 : av > bv ? -1 : 1;
5451
+ }
5452
+ return av === bv ? 0 : av > bv ? 1 : -1;
5453
+ };
5454
+ return this.sortChildren(cmp, deep);
5455
+ }
5360
5456
  /**
5361
5457
  * Trigger `modifyChild` event on a parent to signal that a child was modified.
5362
5458
  * @param {string} operation Type of change: 'add', 'remove', 'rename', 'move', 'data', ...
@@ -5465,7 +5561,7 @@
5465
5561
  /*!
5466
5562
  * Wunderbaum - ext-edit
5467
5563
  * Copyright (c) 2021-2024, Martin Wendt. Released under the MIT license.
5468
- * v0.10.0, Mon, 24 Jun 2024 19:17:59 GMT (https://github.com/mar10/wunderbaum)
5564
+ * v0.11.0, Sun, 04 Aug 2024 15:35:53 GMT (https://github.com/mar10/wunderbaum)
5469
5565
  */
5470
5566
  // const START_MARKER = "\uFFF7";
5471
5567
  class EditExtension extends WunderbaumExtension {
@@ -5796,8 +5892,8 @@
5796
5892
  * https://github.com/mar10/wunderbaum
5797
5893
  *
5798
5894
  * Released under the MIT license.
5799
- * @version v0.10.0
5800
- * @date Mon, 24 Jun 2024 19:17:59 GMT
5895
+ * @version v0.11.0
5896
+ * @date Sun, 04 Aug 2024 15:35:53 GMT
5801
5897
  */
5802
5898
  // import "./wunderbaum.scss";
5803
5899
  class WbSystemRoot extends WunderbaumNode {
@@ -5967,7 +6063,8 @@
5967
6063
  // Attach tree instance to <div>
5968
6064
  this.element._wb_tree = this;
5969
6065
  // Create header markup, or take it from the existing html
5970
- this.headerElement = this.element.querySelector("div.wb-header");
6066
+ this.headerElement =
6067
+ this.element.querySelector("div.wb-header");
5971
6068
  const wantHeader = opts.header == null ? this.columns.length > 1 : !!opts.header;
5972
6069
  if (this.headerElement) {
5973
6070
  // User existing header markup to define `this.columns`
@@ -6004,8 +6101,10 @@
6004
6101
  <div class="wb-node-list"></div>
6005
6102
  </div>`;
6006
6103
  this.listContainerElement = this.element.querySelector("div.wb-list-container");
6007
- this.nodeListElement = this.listContainerElement.querySelector("div.wb-node-list");
6008
- this.headerElement = this.element.querySelector("div.wb-header");
6104
+ this.nodeListElement =
6105
+ this.listContainerElement.querySelector("div.wb-node-list");
6106
+ this.headerElement =
6107
+ this.element.querySelector("div.wb-header");
6009
6108
  this.element.classList.toggle("wb-grid", this.columns.length > 1);
6010
6109
  this._initExtensions();
6011
6110
  // --- apply initial options
@@ -6062,6 +6161,16 @@
6062
6161
  this.update(ChangeType.resize);
6063
6162
  });
6064
6163
  this.resizeObserver.observe(this.element);
6164
+ onEvent(this.element, "click", ".wb-button,.wb-col-icon", (e) => {
6165
+ var _a, _b;
6166
+ const info = Wunderbaum.getEventInfo(e);
6167
+ const command = (_b = (_a = e.target) === null || _a === void 0 ? void 0 : _a.dataset) === null || _b === void 0 ? void 0 : _b.command;
6168
+ this._callEvent("buttonClick", {
6169
+ event: e,
6170
+ info: info,
6171
+ command: command,
6172
+ });
6173
+ });
6065
6174
  onEvent(this.nodeListElement, "click", "div.wb-row", (e) => {
6066
6175
  const info = Wunderbaum.getEventInfo(e);
6067
6176
  const node = info.node;
@@ -6642,7 +6751,7 @@
6642
6751
  }
6643
6752
  /** Run code, but defer rendering of viewport until done.
6644
6753
  *
6645
- * ```
6754
+ * ```js
6646
6755
  * tree.runWithDeferredUpdate(() => {
6647
6756
  * return someFuncThatWouldUpdateManyNodes();
6648
6757
  * });
@@ -7120,13 +7229,17 @@
7120
7229
  console.warn(this.toString(), ...args); // eslint-disable-line no-console
7121
7230
  }
7122
7231
  }
7123
- /** Reset column widths to default. */
7232
+ /** Reset column widths to default. @since 0.10.0 */
7124
7233
  resetColumns() {
7125
7234
  this.columns.forEach((col) => {
7126
7235
  delete col.customWidthPx;
7127
7236
  });
7128
7237
  this.update(ChangeType.colStructure);
7129
7238
  }
7239
+ // /** Renumber nodes `_nativeIndex`. @see {@link WunderbaumNode.resetNativeChildOrder} */
7240
+ // resetNativeChildOrder(options?: ResetOrderOptions) {
7241
+ // this.root.resetNativeChildOrder(options);
7242
+ // }
7130
7243
  /**
7131
7244
  * Make sure that this node is vertically scrolled into the viewport.
7132
7245
  *
@@ -7441,6 +7554,14 @@
7441
7554
  sortChildren(cmp = nodeTitleSorter, deep = false) {
7442
7555
  this.root.sortChildren(cmp, deep);
7443
7556
  }
7557
+ /**
7558
+ * Convenience method to implement column sorting.
7559
+ * @see {@link WunderbaumNode.sortByProperty}.
7560
+ * @since 0.11.0
7561
+ */
7562
+ sortByProperty(options) {
7563
+ this.root.sortByProperty(options);
7564
+ }
7444
7565
  /** Convert tree to an array of plain objects.
7445
7566
  *
7446
7567
  * @param callback is called for every node, in order to allow
@@ -7554,6 +7675,11 @@
7554
7675
  // }
7555
7676
  return modified;
7556
7677
  }
7678
+ _insertIcon(icon, elem) {
7679
+ const iconElem = document.createElement("i");
7680
+ iconElem.className = icon;
7681
+ elem.appendChild(iconElem);
7682
+ }
7557
7683
  /** Create/update header markup from `this.columns` definition.
7558
7684
  * @internal
7559
7685
  */
@@ -7564,6 +7690,7 @@
7564
7690
  if (!wantHeader) {
7565
7691
  return;
7566
7692
  }
7693
+ const iconMap = this.iconMap;
7567
7694
  const colCount = this.columns.length;
7568
7695
  const headerRow = this.headerElement.querySelector(".wb-row");
7569
7696
  assert(headerRow, "Expected a row in header element");
@@ -7582,23 +7709,54 @@
7582
7709
  else {
7583
7710
  col.classes ? colElem.classList.add(...col.classes.split(" ")) : 0;
7584
7711
  }
7585
- const title = escapeHtml(col.title || col.id);
7712
+ // Add tooltip to column title
7586
7713
  let tooltip = "";
7587
7714
  if (col.tooltip) {
7588
7715
  tooltip = escapeTooltip(col.tooltip);
7589
7716
  tooltip = ` title="${tooltip}"`;
7590
7717
  }
7591
- let resizer = "";
7718
+ // Add column header icons
7719
+ let addMarkup = "";
7720
+ // NOTE: we use CSS float: right to align icons, so they must be added in
7721
+ // reverse order
7722
+ if (toBool(col.menu, this.options.columnsMenu, false)) {
7723
+ const iconClass = "wb-col-icon-menu " + iconMap.colMenu;
7724
+ const icon = `<i data-command=menu class="wb-col-icon ${iconClass}"></i>`;
7725
+ addMarkup += icon;
7726
+ }
7727
+ if (toBool(col.sortable, this.options.columnsSortable, false)) {
7728
+ let iconClass = "wb-col-icon-sort " + iconMap.colSortable;
7729
+ if (col.sortOrder) {
7730
+ iconClass += `wb-col-sort-${col.sortOrder}`;
7731
+ iconClass +=
7732
+ col.sortOrder === "asc" ? iconMap.colSortAsc : iconMap.colSortDesc;
7733
+ }
7734
+ const icon = `<i data-command=sort class="wb-col-icon ${iconClass}"></i>`;
7735
+ addMarkup += icon;
7736
+ }
7737
+ if (toBool(col.filterable, this.options.columnsFilterable, false)) {
7738
+ colElem.classList.toggle("wb-col-filter", !!col.filterActive);
7739
+ let iconClass = "wb-col-icon-filter " + iconMap.colFilter;
7740
+ if (col.filterActive) {
7741
+ iconClass += iconMap.colFilterActive;
7742
+ }
7743
+ const icon = `<i data-command=filter class="wb-col-icon ${iconClass}"></i>`;
7744
+ addMarkup += icon;
7745
+ }
7746
+ // Add resizer to all but the last column
7592
7747
  if (i < colCount - 1) {
7593
- if (toBool(col.resizable, this.options.resizableColumns, false)) {
7594
- resizer =
7748
+ if (toBool(col.resizable, this.options.columnsResizable, false)) {
7749
+ addMarkup +=
7595
7750
  '<span class="wb-col-resizer wb-col-resizer-active"></span>';
7596
7751
  }
7597
7752
  else {
7598
- resizer = '<span class="wb-col-resizer"></span>';
7753
+ addMarkup += '<span class="wb-col-resizer"></span>';
7599
7754
  }
7600
7755
  }
7601
- colElem.innerHTML = `<span class="wb-col-title"${tooltip}>${title}</span>${resizer}`;
7756
+ // Create column header
7757
+ const title = escapeHtml(col.title || col.id);
7758
+ colElem.innerHTML = `<span class="wb-col-title"${tooltip}>${title}</span>${addMarkup}`;
7759
+ // Highlight active column
7602
7760
  if (this.isCellNav()) {
7603
7761
  colElem.classList.toggle("wb-active", i === this.activeColIdx);
7604
7762
  }
@@ -7677,6 +7835,7 @@
7677
7835
  // console.profileEnd(`_updateViewportImmediately()`)
7678
7836
  }
7679
7837
  if (this.options.connectTopBreadcrumb) {
7838
+ assert(this.options.connectTopBreadcrumb.textContent != null, `Invalid 'connectTopBreadcrumb' option (input element expected).`);
7680
7839
  let path = (_a = this.getTopmostVpNode(true)) === null || _a === void 0 ? void 0 : _a.getPath(false, "title", " > ");
7681
7840
  path = path ? path + " >" : "";
7682
7841
  this.options.connectTopBreadcrumb.textContent = path;
@@ -8014,6 +8173,7 @@
8014
8173
  /**
8015
8174
  * Return the number of nodes that match the current filter.
8016
8175
  * @see {@link Wunderbaum.filterNodes}
8176
+ * @since 0.9.0
8017
8177
  */
8018
8178
  countMatches() {
8019
8179
  return this.extensions.filter.countMatches();
@@ -8046,7 +8206,7 @@
8046
8206
  }
8047
8207
  Wunderbaum.sequence = 0;
8048
8208
  /** Wunderbaum release version number "MAJOR.MINOR.PATCH". */
8049
- Wunderbaum.version = "v0.10.0"; // Set to semver by 'grunt release'
8209
+ Wunderbaum.version = "v0.11.0"; // Set to semver by 'grunt release'
8050
8210
  /** Expose some useful methods of the util.ts module as `Wunderbaum.util`. */
8051
8211
  Wunderbaum.util = util;
8052
8212