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.
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/dist/wunderbaum.css +13 -5
- package/dist/wunderbaum.css.map +1 -1
- package/dist/wunderbaum.d.ts +194 -45
- package/dist/wunderbaum.esm.js +212 -52
- package/dist/wunderbaum.esm.min.js +22 -22
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +212 -52
- package/dist/wunderbaum.umd.min.js +29 -29
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +5 -6
- package/src/common.ts +16 -1
- package/src/types.ts +122 -25
- package/src/util.ts +12 -12
- package/src/wb_ext_filter.ts +4 -0
- package/src/wb_ext_grid.ts +1 -1
- package/src/wb_node.ts +116 -5
- package/src/wb_options.ts +26 -2
- package/src/wunderbaum.scss +15 -5
- package/src/wunderbaum.ts +96 -29
package/src/wb_options.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
NodeTypeDefinitionMap,
|
|
21
21
|
SelectModeType,
|
|
22
22
|
WbActivateEventType,
|
|
23
|
+
WbButtonClickEventType,
|
|
23
24
|
WbCancelableEventResultType,
|
|
24
25
|
WbChangeEventType,
|
|
25
26
|
WbClickEventType,
|
|
@@ -217,11 +218,30 @@ export interface WunderbaumOptions {
|
|
|
217
218
|
* Default: false
|
|
218
219
|
*/
|
|
219
220
|
fixedCol?: boolean;
|
|
221
|
+
/**
|
|
222
|
+
* Default value for ColumnDefinition.filterable option.
|
|
223
|
+
* Default: false
|
|
224
|
+
* @since 0.11.0
|
|
225
|
+
*/
|
|
226
|
+
columnsFilterable?: boolean;
|
|
227
|
+
/**
|
|
228
|
+
* Default value for ColumnDefinition.menu option.
|
|
229
|
+
* Default: false
|
|
230
|
+
* @since 0.11.0
|
|
231
|
+
*/
|
|
232
|
+
columnsMenu?: boolean;
|
|
220
233
|
/**
|
|
221
234
|
* Default value for ColumnDefinition.resizable option.
|
|
222
235
|
* Default: false
|
|
236
|
+
* @since 0.10.0
|
|
237
|
+
*/
|
|
238
|
+
columnsResizable?: boolean;
|
|
239
|
+
/**
|
|
240
|
+
* Default value for ColumnDefinition.sortable option.
|
|
241
|
+
* Default: false
|
|
242
|
+
* @since 0.11.0
|
|
223
243
|
*/
|
|
224
|
-
|
|
244
|
+
columnsSortable?: boolean;
|
|
225
245
|
|
|
226
246
|
// --- Selection ---
|
|
227
247
|
/**
|
|
@@ -271,11 +291,15 @@ export interface WunderbaumOptions {
|
|
|
271
291
|
*/
|
|
272
292
|
beforeExpand?: (e: WbExpandEventType) => WbCancelableEventResultType;
|
|
273
293
|
/**
|
|
274
|
-
*
|
|
275
294
|
* Return `false` to prevent default handling, i.e. (de)selecting the node.
|
|
276
295
|
* @category Callback
|
|
277
296
|
*/
|
|
278
297
|
beforeSelect?: (e: WbSelectEventType) => WbCancelableEventResultType;
|
|
298
|
+
/**
|
|
299
|
+
* Return `false` to prevent default handling, i.e. (de)selecting the node.
|
|
300
|
+
* @category Callback
|
|
301
|
+
*/
|
|
302
|
+
buttonClick?: (e: WbButtonClickEventType) => void;
|
|
279
303
|
/**
|
|
280
304
|
*
|
|
281
305
|
* @category Callback
|
package/src/wunderbaum.scss
CHANGED
|
@@ -183,8 +183,8 @@ div.wunderbaum {
|
|
|
183
183
|
position: sticky;
|
|
184
184
|
top: 0;
|
|
185
185
|
z-index: 2;
|
|
186
|
-
user-select: none;
|
|
187
186
|
-webkit-user-select: none; /* Safari */
|
|
187
|
+
user-select: none;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
div.wb-header,
|
|
@@ -386,13 +386,23 @@ div.wunderbaum {
|
|
|
386
386
|
border: none;
|
|
387
387
|
border-right: 2px solid var(--wb-border-color);
|
|
388
388
|
height: 100%;
|
|
389
|
-
user-select: none;
|
|
390
389
|
-webkit-user-select: none; // Safari
|
|
390
|
+
user-select: none;
|
|
391
391
|
&.wb-col-resizer-active {
|
|
392
392
|
cursor: col-resize;
|
|
393
393
|
// border-right-color: red;
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
|
+
|
|
397
|
+
i.wb-col-icon {
|
|
398
|
+
float: inline-end;
|
|
399
|
+
padding-left: 2px;
|
|
400
|
+
|
|
401
|
+
&:hover {
|
|
402
|
+
cursor: pointer;
|
|
403
|
+
color: var(--wb-focus-border-color);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
396
406
|
}
|
|
397
407
|
|
|
398
408
|
span.wb-col {
|
|
@@ -412,8 +422,8 @@ div.wunderbaum {
|
|
|
412
422
|
}
|
|
413
423
|
|
|
414
424
|
span.wb-node {
|
|
415
|
-
user-select: none;
|
|
416
425
|
-webkit-user-select: none; // Safari
|
|
426
|
+
user-select: none;
|
|
417
427
|
// &:first-of-type {
|
|
418
428
|
// margin-left: 8px; // leftmost icon gets a little margin
|
|
419
429
|
// }
|
|
@@ -773,12 +783,12 @@ div.wunderbaum {
|
|
|
773
783
|
}
|
|
774
784
|
|
|
775
785
|
.wb-no-select {
|
|
776
|
-
user-select: none;
|
|
777
786
|
-webkit-user-select: none; // Safari
|
|
787
|
+
user-select: none;
|
|
778
788
|
|
|
779
789
|
span.wb-title {
|
|
780
|
-
user-select: contain;
|
|
781
790
|
-webkit-user-select: contain; // Safari
|
|
791
|
+
user-select: contain;
|
|
782
792
|
}
|
|
783
793
|
}
|
|
784
794
|
|
package/src/wunderbaum.ts
CHANGED
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
SetActiveOptions,
|
|
48
48
|
SetColumnOptions,
|
|
49
49
|
SetStatusOptions,
|
|
50
|
+
SortByPropertyOptions,
|
|
50
51
|
SortCallback,
|
|
51
52
|
SourceType,
|
|
52
53
|
UpdateOptions,
|
|
@@ -285,7 +286,7 @@ export class Wunderbaum {
|
|
|
285
286
|
delete opts.types;
|
|
286
287
|
|
|
287
288
|
// --- Create Markup
|
|
288
|
-
this.element = util.elemFromSelector(opts.element)
|
|
289
|
+
this.element = util.elemFromSelector<HTMLDivElement>(opts.element)!;
|
|
289
290
|
util.assert(!!this.element, `Invalid 'element' option: ${opts.element}`);
|
|
290
291
|
|
|
291
292
|
this.element.classList.add("wunderbaum");
|
|
@@ -298,9 +299,8 @@ export class Wunderbaum {
|
|
|
298
299
|
|
|
299
300
|
// Create header markup, or take it from the existing html
|
|
300
301
|
|
|
301
|
-
this.headerElement =
|
|
302
|
-
"div.wb-header"
|
|
303
|
-
) as HTMLDivElement;
|
|
302
|
+
this.headerElement =
|
|
303
|
+
this.element.querySelector<HTMLDivElement>("div.wb-header")!;
|
|
304
304
|
|
|
305
305
|
const wantHeader =
|
|
306
306
|
opts.header == null ? this.columns.length > 1 : !!opts.header;
|
|
@@ -312,9 +312,8 @@ export class Wunderbaum {
|
|
|
312
312
|
"`opts.columns` must not be set if markup already contains a header"
|
|
313
313
|
);
|
|
314
314
|
this.columns = [];
|
|
315
|
-
const rowElement =
|
|
316
|
-
"div.wb-row"
|
|
317
|
-
) as HTMLDivElement;
|
|
315
|
+
const rowElement =
|
|
316
|
+
this.headerElement.querySelector<HTMLDivElement>("div.wb-row")!;
|
|
318
317
|
for (const colDiv of rowElement.querySelectorAll("div")) {
|
|
319
318
|
this.columns.push({
|
|
320
319
|
id: colDiv.dataset.id || `col_${this.columns.length}`,
|
|
@@ -337,9 +336,7 @@ export class Wunderbaum {
|
|
|
337
336
|
</div>`;
|
|
338
337
|
|
|
339
338
|
if (!wantHeader) {
|
|
340
|
-
const he = this.element.querySelector(
|
|
341
|
-
"div.wb-header"
|
|
342
|
-
) as HTMLDivElement;
|
|
339
|
+
const he = this.element.querySelector<HTMLDivElement>("div.wb-header")!;
|
|
343
340
|
he.style.display = "none";
|
|
344
341
|
}
|
|
345
342
|
}
|
|
@@ -349,15 +346,15 @@ export class Wunderbaum {
|
|
|
349
346
|
<div class="wb-list-container">
|
|
350
347
|
<div class="wb-node-list"></div>
|
|
351
348
|
</div>`;
|
|
352
|
-
this.listContainerElement = this.element.querySelector(
|
|
349
|
+
this.listContainerElement = this.element.querySelector<HTMLDivElement>(
|
|
353
350
|
"div.wb-list-container"
|
|
354
|
-
)
|
|
355
|
-
this.nodeListElement =
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
351
|
+
)!;
|
|
352
|
+
this.nodeListElement =
|
|
353
|
+
this.listContainerElement.querySelector<HTMLDivElement>(
|
|
354
|
+
"div.wb-node-list"
|
|
355
|
+
)!;
|
|
356
|
+
this.headerElement =
|
|
357
|
+
this.element.querySelector<HTMLDivElement>("div.wb-header")!;
|
|
361
358
|
|
|
362
359
|
this.element.classList.toggle("wb-grid", this.columns.length > 1);
|
|
363
360
|
|
|
@@ -418,6 +415,17 @@ export class Wunderbaum {
|
|
|
418
415
|
});
|
|
419
416
|
this.resizeObserver.observe(this.element);
|
|
420
417
|
|
|
418
|
+
util.onEvent(this.element, "click", ".wb-button,.wb-col-icon", (e) => {
|
|
419
|
+
const info = Wunderbaum.getEventInfo(e);
|
|
420
|
+
const command = (<HTMLElement>e.target)?.dataset?.command;
|
|
421
|
+
|
|
422
|
+
this._callEvent("buttonClick", {
|
|
423
|
+
event: e,
|
|
424
|
+
info: info,
|
|
425
|
+
command: command,
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
|
|
421
429
|
util.onEvent(this.nodeListElement, "click", "div.wb-row", (e) => {
|
|
422
430
|
const info = Wunderbaum.getEventInfo(e);
|
|
423
431
|
const node = info.node;
|
|
@@ -1078,7 +1086,7 @@ export class Wunderbaum {
|
|
|
1078
1086
|
|
|
1079
1087
|
/** Run code, but defer rendering of viewport until done.
|
|
1080
1088
|
*
|
|
1081
|
-
* ```
|
|
1089
|
+
* ```js
|
|
1082
1090
|
* tree.runWithDeferredUpdate(() => {
|
|
1083
1091
|
* return someFuncThatWouldUpdateManyNodes();
|
|
1084
1092
|
* });
|
|
@@ -1602,7 +1610,7 @@ export class Wunderbaum {
|
|
|
1602
1610
|
}
|
|
1603
1611
|
}
|
|
1604
1612
|
|
|
1605
|
-
/** Reset column widths to default. */
|
|
1613
|
+
/** Reset column widths to default. @since 0.10.0 */
|
|
1606
1614
|
resetColumns() {
|
|
1607
1615
|
this.columns.forEach((col) => {
|
|
1608
1616
|
delete col.customWidthPx;
|
|
@@ -1610,6 +1618,11 @@ export class Wunderbaum {
|
|
|
1610
1618
|
this.update(ChangeType.colStructure);
|
|
1611
1619
|
}
|
|
1612
1620
|
|
|
1621
|
+
// /** Renumber nodes `_nativeIndex`. @see {@link WunderbaumNode.resetNativeChildOrder} */
|
|
1622
|
+
// resetNativeChildOrder(options?: ResetOrderOptions) {
|
|
1623
|
+
// this.root.resetNativeChildOrder(options);
|
|
1624
|
+
// }
|
|
1625
|
+
|
|
1613
1626
|
/**
|
|
1614
1627
|
* Make sure that this node is vertically scrolled into the viewport.
|
|
1615
1628
|
*
|
|
@@ -1790,15 +1803,15 @@ export class Wunderbaum {
|
|
|
1790
1803
|
* The render operation is async and debounced unless the `immediate` option
|
|
1791
1804
|
* is set.
|
|
1792
1805
|
*
|
|
1793
|
-
* Use {@link WunderbaumNode.update
|
|
1794
|
-
* or {@link WunderbaumNode._render
|
|
1806
|
+
* Use {@link WunderbaumNode.update} if only a single node has changed,
|
|
1807
|
+
* or {@link WunderbaumNode._render}) to pass special options.
|
|
1795
1808
|
*/
|
|
1796
1809
|
update(change: ChangeType, options?: UpdateOptions): void;
|
|
1797
1810
|
|
|
1798
1811
|
/**
|
|
1799
1812
|
* Update a row to reflect a single node's modification.
|
|
1800
1813
|
*
|
|
1801
|
-
* @see {@link WunderbaumNode.update
|
|
1814
|
+
* @see {@link WunderbaumNode.update}, {@link WunderbaumNode._render}
|
|
1802
1815
|
*/
|
|
1803
1816
|
update(
|
|
1804
1817
|
change: ChangeType,
|
|
@@ -1988,6 +2001,15 @@ export class Wunderbaum {
|
|
|
1988
2001
|
this.root.sortChildren(cmp, deep);
|
|
1989
2002
|
}
|
|
1990
2003
|
|
|
2004
|
+
/**
|
|
2005
|
+
* Convenience method to implement column sorting.
|
|
2006
|
+
* @see {@link WunderbaumNode.sortByProperty}.
|
|
2007
|
+
* @since 0.11.0
|
|
2008
|
+
*/
|
|
2009
|
+
sortByProperty(options: SortByPropertyOptions) {
|
|
2010
|
+
this.root.sortByProperty(options);
|
|
2011
|
+
}
|
|
2012
|
+
|
|
1991
2013
|
/** Convert tree to an array of plain objects.
|
|
1992
2014
|
*
|
|
1993
2015
|
* @param callback is called for every node, in order to allow
|
|
@@ -2109,6 +2131,12 @@ export class Wunderbaum {
|
|
|
2109
2131
|
return modified;
|
|
2110
2132
|
}
|
|
2111
2133
|
|
|
2134
|
+
protected _insertIcon(icon: string, elem: HTMLElement) {
|
|
2135
|
+
const iconElem = document.createElement("i");
|
|
2136
|
+
iconElem.className = icon;
|
|
2137
|
+
elem.appendChild(iconElem);
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2112
2140
|
/** Create/update header markup from `this.columns` definition.
|
|
2113
2141
|
* @internal
|
|
2114
2142
|
*/
|
|
@@ -2119,6 +2147,7 @@ export class Wunderbaum {
|
|
|
2119
2147
|
if (!wantHeader) {
|
|
2120
2148
|
return;
|
|
2121
2149
|
}
|
|
2150
|
+
const iconMap = this.iconMap;
|
|
2122
2151
|
const colCount = this.columns.length;
|
|
2123
2152
|
const headerRow = this.headerElement.querySelector(".wb-row")!;
|
|
2124
2153
|
util.assert(headerRow, "Expected a row in header element");
|
|
@@ -2139,22 +2168,55 @@ export class Wunderbaum {
|
|
|
2139
2168
|
col.classes ? colElem.classList.add(...col.classes.split(" ")) : 0;
|
|
2140
2169
|
}
|
|
2141
2170
|
|
|
2142
|
-
|
|
2171
|
+
// Add tooltip to column title
|
|
2143
2172
|
let tooltip = "";
|
|
2144
2173
|
if (col.tooltip) {
|
|
2145
2174
|
tooltip = util.escapeTooltip(col.tooltip);
|
|
2146
2175
|
tooltip = ` title="${tooltip}"`;
|
|
2147
2176
|
}
|
|
2148
|
-
|
|
2177
|
+
// Add column header icons
|
|
2178
|
+
let addMarkup = "";
|
|
2179
|
+
// NOTE: we use CSS float: right to align icons, so they must be added in
|
|
2180
|
+
// reverse order
|
|
2181
|
+
if (util.toBool(col.menu, this.options.columnsMenu, false)) {
|
|
2182
|
+
const iconClass = "wb-col-icon-menu " + iconMap.colMenu;
|
|
2183
|
+
const icon = `<i data-command=menu class="wb-col-icon ${iconClass}"></i>`;
|
|
2184
|
+
addMarkup += icon;
|
|
2185
|
+
}
|
|
2186
|
+
if (util.toBool(col.sortable, this.options.columnsSortable, false)) {
|
|
2187
|
+
let iconClass = "wb-col-icon-sort " + iconMap.colSortable;
|
|
2188
|
+
if (col.sortOrder) {
|
|
2189
|
+
iconClass += `wb-col-sort-${col.sortOrder}`;
|
|
2190
|
+
iconClass +=
|
|
2191
|
+
col.sortOrder === "asc" ? iconMap.colSortAsc : iconMap.colSortDesc;
|
|
2192
|
+
}
|
|
2193
|
+
const icon = `<i data-command=sort class="wb-col-icon ${iconClass}"></i>`;
|
|
2194
|
+
addMarkup += icon;
|
|
2195
|
+
}
|
|
2196
|
+
if (util.toBool(col.filterable, this.options.columnsFilterable, false)) {
|
|
2197
|
+
colElem.classList.toggle("wb-col-filter", !!col.filterActive);
|
|
2198
|
+
let iconClass = "wb-col-icon-filter " + iconMap.colFilter;
|
|
2199
|
+
if (col.filterActive) {
|
|
2200
|
+
iconClass += iconMap.colFilterActive;
|
|
2201
|
+
}
|
|
2202
|
+
const icon = `<i data-command=filter class="wb-col-icon ${iconClass}"></i>`;
|
|
2203
|
+
addMarkup += icon;
|
|
2204
|
+
}
|
|
2205
|
+
// Add resizer to all but the last column
|
|
2149
2206
|
if (i < colCount - 1) {
|
|
2150
|
-
if (util.toBool(col.resizable, this.options.
|
|
2151
|
-
|
|
2207
|
+
if (util.toBool(col.resizable, this.options.columnsResizable, false)) {
|
|
2208
|
+
addMarkup +=
|
|
2152
2209
|
'<span class="wb-col-resizer wb-col-resizer-active"></span>';
|
|
2153
2210
|
} else {
|
|
2154
|
-
|
|
2211
|
+
addMarkup += '<span class="wb-col-resizer"></span>';
|
|
2155
2212
|
}
|
|
2156
2213
|
}
|
|
2157
|
-
|
|
2214
|
+
|
|
2215
|
+
// Create column header
|
|
2216
|
+
const title = util.escapeHtml(col.title || col.id);
|
|
2217
|
+
colElem.innerHTML = `<span class="wb-col-title"${tooltip}>${title}</span>${addMarkup}`;
|
|
2218
|
+
|
|
2219
|
+
// Highlight active column
|
|
2158
2220
|
if (this.isCellNav()) {
|
|
2159
2221
|
colElem.classList.toggle("wb-active", i === this.activeColIdx);
|
|
2160
2222
|
}
|
|
@@ -2242,6 +2304,10 @@ export class Wunderbaum {
|
|
|
2242
2304
|
}
|
|
2243
2305
|
|
|
2244
2306
|
if (this.options.connectTopBreadcrumb) {
|
|
2307
|
+
util.assert(
|
|
2308
|
+
this.options.connectTopBreadcrumb.textContent != null,
|
|
2309
|
+
`Invalid 'connectTopBreadcrumb' option (input element expected).`
|
|
2310
|
+
);
|
|
2245
2311
|
let path = this.getTopmostVpNode(true)?.getPath(false, "title", " > ");
|
|
2246
2312
|
path = path ? path + " >" : "";
|
|
2247
2313
|
this.options.connectTopBreadcrumb.textContent = path;
|
|
@@ -2629,6 +2695,7 @@ export class Wunderbaum {
|
|
|
2629
2695
|
/**
|
|
2630
2696
|
* Return the number of nodes that match the current filter.
|
|
2631
2697
|
* @see {@link Wunderbaum.filterNodes}
|
|
2698
|
+
* @since 0.9.0
|
|
2632
2699
|
*/
|
|
2633
2700
|
countMatches(): number {
|
|
2634
2701
|
return (this.extensions.filter as FilterExtension).countMatches();
|