wunderbaum 0.12.1 → 0.13.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/dist/wunderbaum.css +9 -0
- package/dist/wunderbaum.css.map +1 -1
- package/dist/wunderbaum.d.ts +147 -44
- package/dist/wunderbaum.esm.js +353 -187
- package/dist/wunderbaum.esm.min.js +26 -26
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +353 -187
- package/dist/wunderbaum.umd.min.js +29 -29
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/common.ts +27 -3
- package/src/types.ts +115 -12
- package/src/util.ts +0 -13
- package/src/wb_ext_edit.ts +1 -1
- package/src/wb_ext_filter.ts +117 -42
- package/src/wb_extension_base.ts +3 -2
- package/src/wb_node.ts +24 -96
- package/src/wb_options.ts +6 -12
- package/src/wunderbaum.scss +9 -1
- package/src/wunderbaum.ts +264 -40
package/src/wunderbaum.ts
CHANGED
|
@@ -33,7 +33,10 @@ import {
|
|
|
33
33
|
ExpandAllOptions,
|
|
34
34
|
FilterModeType,
|
|
35
35
|
FilterNodesOptions,
|
|
36
|
+
IconMapType,
|
|
37
|
+
GetStateOptions,
|
|
36
38
|
MatcherCallback,
|
|
39
|
+
NavigationType,
|
|
37
40
|
NavModeEnum,
|
|
38
41
|
NodeFilterCallback,
|
|
39
42
|
NodeRegion,
|
|
@@ -46,10 +49,12 @@ import {
|
|
|
46
49
|
ScrollToOptions,
|
|
47
50
|
SetActiveOptions,
|
|
48
51
|
SetColumnOptions,
|
|
52
|
+
SetStateOptions,
|
|
49
53
|
SetStatusOptions,
|
|
50
54
|
SortByPropertyOptions,
|
|
51
55
|
SortCallback,
|
|
52
56
|
SourceType,
|
|
57
|
+
TreeStateDefinition,
|
|
53
58
|
UpdateOptions,
|
|
54
59
|
VisitRowsOptions,
|
|
55
60
|
WbEventInfo,
|
|
@@ -62,6 +67,7 @@ import {
|
|
|
62
67
|
nodeTitleSorter,
|
|
63
68
|
RENDER_MAX_PREFETCH,
|
|
64
69
|
DEFAULT_ROW_HEIGHT,
|
|
70
|
+
TEST_IMG,
|
|
65
71
|
} from "./common";
|
|
66
72
|
import { WunderbaumNode } from "./wb_node";
|
|
67
73
|
import { Deferred } from "./deferred";
|
|
@@ -171,6 +177,10 @@ export class Wunderbaum {
|
|
|
171
177
|
// /** @internal */
|
|
172
178
|
// public selectRangeAnchor: WunderbaumNode | null = null;
|
|
173
179
|
|
|
180
|
+
// --- BREADCRUMB ---
|
|
181
|
+
/** Filter options (used as defaults for calls to {@link Wunderbaum.filterNodes} ) */
|
|
182
|
+
public breadcrumb: HTMLElement | null = null;
|
|
183
|
+
|
|
174
184
|
// --- FILTER ---
|
|
175
185
|
/** Filter options (used as defaults for calls to {@link Wunderbaum.filterNodes} ) */
|
|
176
186
|
public filterMode: FilterModeType = null;
|
|
@@ -210,10 +220,10 @@ export class Wunderbaum {
|
|
|
210
220
|
emptyChildListExpandable: false,
|
|
211
221
|
// updateThrottleWait: 200,
|
|
212
222
|
skeleton: false,
|
|
213
|
-
connectTopBreadcrumb: null,
|
|
223
|
+
connectTopBreadcrumb: null,
|
|
214
224
|
selectMode: "multi", // SelectModeType
|
|
215
225
|
// --- KeyNav ---
|
|
216
|
-
navigationModeOption: null, // NavModeEnum
|
|
226
|
+
navigationModeOption: null, // NavModeEnum,
|
|
217
227
|
quicksearch: true,
|
|
218
228
|
// --- Events ---
|
|
219
229
|
iconBadge: null,
|
|
@@ -225,8 +235,11 @@ export class Wunderbaum {
|
|
|
225
235
|
strings: {
|
|
226
236
|
loadError: "Error",
|
|
227
237
|
loading: "Loading...",
|
|
228
|
-
// loading: "Loading…",
|
|
229
238
|
noData: "No data",
|
|
239
|
+
breadcrumbDelimiter: " » ",
|
|
240
|
+
queryResult: "Found ${matches} of ${count}",
|
|
241
|
+
noMatch: "No results",
|
|
242
|
+
matchIndex: "${match} of ${matches}",
|
|
230
243
|
},
|
|
231
244
|
},
|
|
232
245
|
options
|
|
@@ -368,6 +381,24 @@ export class Wunderbaum {
|
|
|
368
381
|
|
|
369
382
|
this.element.classList.toggle("wb-grid", this.columns.length > 1);
|
|
370
383
|
|
|
384
|
+
if (this.options.connectTopBreadcrumb) {
|
|
385
|
+
this.breadcrumb = util.elemFromSelector(
|
|
386
|
+
this.options.connectTopBreadcrumb
|
|
387
|
+
)!;
|
|
388
|
+
util.assert(
|
|
389
|
+
!this.breadcrumb || this.breadcrumb.innerHTML != null,
|
|
390
|
+
`Invalid 'connectTopBreadcrumb' option: ${this.breadcrumb}.`
|
|
391
|
+
);
|
|
392
|
+
this.breadcrumb.addEventListener("click", (e) => {
|
|
393
|
+
// const node = Wunderbaum.getNode(e)!;
|
|
394
|
+
const elem = e.target as HTMLElement;
|
|
395
|
+
if (elem && elem.matches("a.wb-breadcrumb")) {
|
|
396
|
+
const node = this.keyMap.get(elem.dataset.key!);
|
|
397
|
+
node?.setActive();
|
|
398
|
+
e.preventDefault();
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}
|
|
371
402
|
this._initExtensions();
|
|
372
403
|
|
|
373
404
|
// --- apply initial options
|
|
@@ -597,7 +628,7 @@ export class Wunderbaum {
|
|
|
597
628
|
/**
|
|
598
629
|
* Return the icon-function -> icon-definition mapping.
|
|
599
630
|
*/
|
|
600
|
-
get iconMap():
|
|
631
|
+
get iconMap(): IconMapType {
|
|
601
632
|
const map = this.options.iconMap!;
|
|
602
633
|
if (typeof map === "string") {
|
|
603
634
|
return iconMaps[map];
|
|
@@ -771,7 +802,10 @@ export class Wunderbaum {
|
|
|
771
802
|
return <WunderbaumNode>node!;
|
|
772
803
|
}
|
|
773
804
|
|
|
774
|
-
/** Return the topmost visible node in the viewport.
|
|
805
|
+
/** Return the topmost visible node in the viewport.
|
|
806
|
+
* @param complete If `false`, the node is considered visible if at least one
|
|
807
|
+
* pixel is visible.
|
|
808
|
+
*/
|
|
775
809
|
getTopmostVpNode(complete = true) {
|
|
776
810
|
const rowHeight = this.options.rowHeightPx!;
|
|
777
811
|
const gracePx = 1; // ignore subpixel scrolling
|
|
@@ -806,30 +840,29 @@ export class Wunderbaum {
|
|
|
806
840
|
return this._getNodeByRowIdx(bottomIdx)!;
|
|
807
841
|
}
|
|
808
842
|
|
|
809
|
-
/** Return
|
|
810
|
-
protected
|
|
843
|
+
/** Return following visible node in the viewport. */
|
|
844
|
+
protected _getNextNodeInView(
|
|
845
|
+
node?: WunderbaumNode,
|
|
846
|
+
options?: {
|
|
847
|
+
ofs?: number;
|
|
848
|
+
reverse?: boolean;
|
|
849
|
+
cb?: (n: WunderbaumNode) => boolean;
|
|
850
|
+
}
|
|
851
|
+
) {
|
|
852
|
+
let ofs = options?.ofs || 1;
|
|
853
|
+
const reverse = !!options?.reverse;
|
|
854
|
+
|
|
811
855
|
this.visitRows(
|
|
812
856
|
(n) => {
|
|
813
857
|
node = n;
|
|
814
|
-
if (
|
|
858
|
+
if (options?.cb && options.cb(n)) {
|
|
815
859
|
return false;
|
|
816
860
|
}
|
|
817
|
-
},
|
|
818
|
-
{ reverse: true, start: node || this.getActiveNode() }
|
|
819
|
-
);
|
|
820
|
-
return node;
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
/** Return following visible node in the viewport. */
|
|
824
|
-
protected _getNextNodeInView(node?: WunderbaumNode, ofs = 1) {
|
|
825
|
-
this.visitRows(
|
|
826
|
-
(n) => {
|
|
827
|
-
node = n;
|
|
828
861
|
if (ofs-- <= 0) {
|
|
829
862
|
return false;
|
|
830
863
|
}
|
|
831
864
|
},
|
|
832
|
-
{ reverse:
|
|
865
|
+
{ reverse: reverse, start: node || this.getActiveNode() }
|
|
833
866
|
);
|
|
834
867
|
return node;
|
|
835
868
|
}
|
|
@@ -972,9 +1005,11 @@ export class Wunderbaum {
|
|
|
972
1005
|
case "first":
|
|
973
1006
|
case "last":
|
|
974
1007
|
case "left":
|
|
1008
|
+
case "nextMatch":
|
|
975
1009
|
case "pageDown":
|
|
976
1010
|
case "pageUp":
|
|
977
1011
|
case "parent":
|
|
1012
|
+
case "prevMatch":
|
|
978
1013
|
case "right":
|
|
979
1014
|
case "up":
|
|
980
1015
|
return node.navigate(cmd);
|
|
@@ -1190,6 +1225,12 @@ export class Wunderbaum {
|
|
|
1190
1225
|
return visible ? this.treeRowCount : this.keyMap.size;
|
|
1191
1226
|
}
|
|
1192
1227
|
|
|
1228
|
+
/** Return the number of *unique* nodes in the data model, i.e. unique `node.refKey`.
|
|
1229
|
+
*/
|
|
1230
|
+
countUnique(): number {
|
|
1231
|
+
return this.refKeyMap.size;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1193
1234
|
/** @internal sanity check. */
|
|
1194
1235
|
_check() {
|
|
1195
1236
|
let i = 0;
|
|
@@ -1255,15 +1296,18 @@ export class Wunderbaum {
|
|
|
1255
1296
|
*/
|
|
1256
1297
|
findNextNode(
|
|
1257
1298
|
match: string | MatcherCallback,
|
|
1258
|
-
startNode?: WunderbaumNode | null
|
|
1299
|
+
startNode?: WunderbaumNode | null,
|
|
1300
|
+
reverse = false
|
|
1259
1301
|
): WunderbaumNode | null {
|
|
1260
1302
|
//, visibleOnly) {
|
|
1261
1303
|
let res: WunderbaumNode | null = null;
|
|
1262
1304
|
const firstNode = this.getFirstChild()!;
|
|
1305
|
+
// Last visible node (calculation is expensive, so do only if we need it):
|
|
1306
|
+
const lastNode = reverse ? this.findRelatedNode(firstNode, "last")! : null;
|
|
1263
1307
|
|
|
1264
1308
|
const matcher =
|
|
1265
1309
|
typeof match === "string" ? makeNodeTitleStartMatcher(match) : match;
|
|
1266
|
-
startNode = startNode || firstNode;
|
|
1310
|
+
startNode = startNode || (reverse ? lastNode : firstNode);
|
|
1267
1311
|
|
|
1268
1312
|
function _checkNode(n: WunderbaumNode) {
|
|
1269
1313
|
// console.log("_check " + n)
|
|
@@ -1277,12 +1321,14 @@ export class Wunderbaum {
|
|
|
1277
1321
|
this.visitRows(_checkNode, {
|
|
1278
1322
|
start: startNode,
|
|
1279
1323
|
includeSelf: false,
|
|
1324
|
+
reverse: reverse,
|
|
1280
1325
|
});
|
|
1281
1326
|
// Wrap around search
|
|
1282
1327
|
if (!res && startNode !== firstNode) {
|
|
1283
1328
|
this.visitRows(_checkNode, {
|
|
1284
|
-
start: firstNode,
|
|
1329
|
+
start: reverse ? lastNode : firstNode,
|
|
1285
1330
|
includeSelf: true,
|
|
1331
|
+
reverse: reverse,
|
|
1286
1332
|
});
|
|
1287
1333
|
}
|
|
1288
1334
|
return res;
|
|
@@ -1297,7 +1343,11 @@ export class Wunderbaum {
|
|
|
1297
1343
|
* e.g. `$.ui.keyCode.LEFT` = 'left'.
|
|
1298
1344
|
* @param includeHidden Not yet implemented
|
|
1299
1345
|
*/
|
|
1300
|
-
findRelatedNode(
|
|
1346
|
+
findRelatedNode(
|
|
1347
|
+
node: WunderbaumNode,
|
|
1348
|
+
where: NavigationType,
|
|
1349
|
+
includeHidden = false
|
|
1350
|
+
) {
|
|
1301
1351
|
const rowHeight = this.options.rowHeightPx!;
|
|
1302
1352
|
let res = null;
|
|
1303
1353
|
const pageSize = Math.floor(
|
|
@@ -1353,7 +1403,7 @@ export class Wunderbaum {
|
|
|
1353
1403
|
// }
|
|
1354
1404
|
break;
|
|
1355
1405
|
case "up":
|
|
1356
|
-
res = this.
|
|
1406
|
+
res = this._getNextNodeInView(node, { reverse: true });
|
|
1357
1407
|
break;
|
|
1358
1408
|
case "down":
|
|
1359
1409
|
res = this._getNextNodeInView(node);
|
|
@@ -1366,7 +1416,10 @@ export class Wunderbaum {
|
|
|
1366
1416
|
if (node._rowIdx! < bottomNode._rowIdx!) {
|
|
1367
1417
|
res = bottomNode;
|
|
1368
1418
|
} else {
|
|
1369
|
-
res = this._getNextNodeInView(node,
|
|
1419
|
+
res = this._getNextNodeInView(node, {
|
|
1420
|
+
reverse: false,
|
|
1421
|
+
ofs: pageSize,
|
|
1422
|
+
});
|
|
1370
1423
|
}
|
|
1371
1424
|
}
|
|
1372
1425
|
break;
|
|
@@ -1380,10 +1433,28 @@ export class Wunderbaum {
|
|
|
1380
1433
|
if (node._rowIdx! > topNode._rowIdx!) {
|
|
1381
1434
|
res = topNode;
|
|
1382
1435
|
} else {
|
|
1383
|
-
res = this.
|
|
1436
|
+
res = this._getNextNodeInView(node, {
|
|
1437
|
+
reverse: true,
|
|
1438
|
+
ofs: pageSize,
|
|
1439
|
+
});
|
|
1384
1440
|
}
|
|
1385
1441
|
}
|
|
1386
1442
|
break;
|
|
1443
|
+
|
|
1444
|
+
case "prevMatch":
|
|
1445
|
+
// fallthrough
|
|
1446
|
+
case "nextMatch":
|
|
1447
|
+
if (!this.isFilterActive) {
|
|
1448
|
+
this.logWarn(`${where}: Filter is not active.`);
|
|
1449
|
+
break;
|
|
1450
|
+
}
|
|
1451
|
+
res = this.findNextNode(
|
|
1452
|
+
(n) => n.isMatched(),
|
|
1453
|
+
node,
|
|
1454
|
+
where === "prevMatch"
|
|
1455
|
+
);
|
|
1456
|
+
res?.setActive();
|
|
1457
|
+
break;
|
|
1387
1458
|
default:
|
|
1388
1459
|
this.logWarn("Unknown relation '" + where + "'.");
|
|
1389
1460
|
}
|
|
@@ -1454,6 +1525,13 @@ export class Wunderbaum {
|
|
|
1454
1525
|
return this.root.getFirstChild();
|
|
1455
1526
|
}
|
|
1456
1527
|
|
|
1528
|
+
/**
|
|
1529
|
+
* Return the last top level node if any (not the invisible root node).
|
|
1530
|
+
*/
|
|
1531
|
+
getLastChild() {
|
|
1532
|
+
return this.root.getLastChild();
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1457
1535
|
/**
|
|
1458
1536
|
* Return the node that currently has keyboard focus or null.
|
|
1459
1537
|
* Alias for {@link Wunderbaum.focusNode}.
|
|
@@ -1816,6 +1894,53 @@ export class Wunderbaum {
|
|
|
1816
1894
|
this._focusNode = node;
|
|
1817
1895
|
}
|
|
1818
1896
|
|
|
1897
|
+
/** Return the current selection/expansion/activation status. @experimental */
|
|
1898
|
+
getState(options: GetStateOptions): TreeStateDefinition {
|
|
1899
|
+
let expandedKeys = undefined;
|
|
1900
|
+
if (options.expandedKeys !== false) {
|
|
1901
|
+
expandedKeys = [];
|
|
1902
|
+
for (const node of this) {
|
|
1903
|
+
if (node.expanded) {
|
|
1904
|
+
expandedKeys.push(node.key);
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
const state: TreeStateDefinition = {
|
|
1910
|
+
activeKey: this.activeNode?.key ?? null,
|
|
1911
|
+
activeColIdx: this.activeColIdx,
|
|
1912
|
+
selectedKeys:
|
|
1913
|
+
options.selectedKeys === false
|
|
1914
|
+
? undefined
|
|
1915
|
+
: this.getSelectedNodes().flatMap((n) => n.key),
|
|
1916
|
+
expandedKeys: expandedKeys,
|
|
1917
|
+
};
|
|
1918
|
+
return state;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
/** Apply selection/expansion/activation status. @experimental */
|
|
1922
|
+
setState(state: TreeStateDefinition, options: SetStateOptions) {
|
|
1923
|
+
this.runWithDeferredUpdate(() => {
|
|
1924
|
+
if (state.selectedKeys) {
|
|
1925
|
+
this.selectAll(false);
|
|
1926
|
+
for (const key of state.selectedKeys) {
|
|
1927
|
+
this.findKey(key)?.setSelected(true);
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
if (state.expandedKeys) {
|
|
1931
|
+
for (const key of state.expandedKeys) {
|
|
1932
|
+
this.findKey(key)?.setExpanded(true);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
if (state.activeKey) {
|
|
1936
|
+
this.setActiveNode(state.activeKey);
|
|
1937
|
+
}
|
|
1938
|
+
if (state.activeColIdx != null) {
|
|
1939
|
+
this.setColumn(state.activeColIdx);
|
|
1940
|
+
}
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1819
1944
|
/**
|
|
1820
1945
|
* Schedule an update request to reflect a tree change.
|
|
1821
1946
|
* The render operation is async and debounced unless the `immediate` option
|
|
@@ -2149,11 +2274,11 @@ export class Wunderbaum {
|
|
|
2149
2274
|
return modified;
|
|
2150
2275
|
}
|
|
2151
2276
|
|
|
2152
|
-
protected _insertIcon(icon: string, elem: HTMLElement) {
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
}
|
|
2277
|
+
// protected _insertIcon(icon: string, elem: HTMLElement) {
|
|
2278
|
+
// const iconElem = document.createElement("i");
|
|
2279
|
+
// iconElem.className = icon;
|
|
2280
|
+
// elem.appendChild(iconElem);
|
|
2281
|
+
// }
|
|
2157
2282
|
|
|
2158
2283
|
/** Create/update header markup from `this.columns` definition.
|
|
2159
2284
|
* @internal
|
|
@@ -2257,6 +2382,111 @@ export class Wunderbaum {
|
|
|
2257
2382
|
}
|
|
2258
2383
|
}
|
|
2259
2384
|
|
|
2385
|
+
/** @internal */
|
|
2386
|
+
public _createNodeIcon(
|
|
2387
|
+
node: WunderbaumNode,
|
|
2388
|
+
showLoading: boolean,
|
|
2389
|
+
showBadge: boolean
|
|
2390
|
+
): HTMLElement | null {
|
|
2391
|
+
const iconMap = this.iconMap;
|
|
2392
|
+
let iconElem;
|
|
2393
|
+
let icon = node.getOption("icon");
|
|
2394
|
+
if (node._errorInfo) {
|
|
2395
|
+
icon = iconMap.error;
|
|
2396
|
+
} else if (node._isLoading && showLoading) {
|
|
2397
|
+
// Status nodes, or nodes without expander (< minExpandLevel) should
|
|
2398
|
+
// display the 'loading' status with the i.wb-icon span
|
|
2399
|
+
icon = iconMap.loading;
|
|
2400
|
+
}
|
|
2401
|
+
if (icon === false) {
|
|
2402
|
+
return null; // explicitly disabled: don't try default icons
|
|
2403
|
+
}
|
|
2404
|
+
if (typeof icon === "string") {
|
|
2405
|
+
// Callback returned an icon definition
|
|
2406
|
+
// icon = icon.trim()
|
|
2407
|
+
} else if (node.statusNodeType) {
|
|
2408
|
+
icon = (<any>iconMap)[node.statusNodeType];
|
|
2409
|
+
} else if (node.expanded) {
|
|
2410
|
+
icon = iconMap.folderOpen;
|
|
2411
|
+
} else if (node.children) {
|
|
2412
|
+
icon = iconMap.folder;
|
|
2413
|
+
} else if (node.lazy) {
|
|
2414
|
+
icon = iconMap.folderLazy;
|
|
2415
|
+
} else {
|
|
2416
|
+
icon = iconMap.doc;
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
if (!icon) {
|
|
2420
|
+
iconElem = document.createElement("i");
|
|
2421
|
+
iconElem.className = "wb-icon";
|
|
2422
|
+
} else if (icon.indexOf("<") >= 0) {
|
|
2423
|
+
// HTML
|
|
2424
|
+
iconElem = util.elemFromHtml(icon);
|
|
2425
|
+
} else if (TEST_IMG.test(icon)) {
|
|
2426
|
+
// Image URL
|
|
2427
|
+
iconElem = util.elemFromHtml(
|
|
2428
|
+
`<i class="wb-icon" style="background-image: url('${icon}');">`
|
|
2429
|
+
);
|
|
2430
|
+
} else {
|
|
2431
|
+
// Class name
|
|
2432
|
+
iconElem = document.createElement("i");
|
|
2433
|
+
iconElem.className = "wb-icon " + icon;
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
// Event handler `tree.iconBadge` can return a badge text or HTMLSpanElement
|
|
2437
|
+
const cbRes =
|
|
2438
|
+
showBadge && node._callEvent("iconBadge", { iconSpan: iconElem });
|
|
2439
|
+
|
|
2440
|
+
let badge = null;
|
|
2441
|
+
if (cbRes != null && cbRes !== false) {
|
|
2442
|
+
let classes = "";
|
|
2443
|
+
let tooltip = "";
|
|
2444
|
+
if (util.isPlainObject(cbRes)) {
|
|
2445
|
+
badge = "" + cbRes.badge;
|
|
2446
|
+
classes = cbRes.badgeClass ? " " + cbRes.badgeClass : "";
|
|
2447
|
+
tooltip = cbRes.badgeTooltip ? ` title="${cbRes.badgeTooltip}"` : "";
|
|
2448
|
+
} else if (typeof cbRes === "number") {
|
|
2449
|
+
badge = "" + cbRes;
|
|
2450
|
+
} else {
|
|
2451
|
+
badge = cbRes; // string or HTMLSpanElement
|
|
2452
|
+
}
|
|
2453
|
+
if (typeof badge === "string") {
|
|
2454
|
+
badge = util.elemFromHtml(
|
|
2455
|
+
`<span class="wb-badge${classes}"${tooltip}>${util.escapeHtml(
|
|
2456
|
+
badge
|
|
2457
|
+
)}</span>`
|
|
2458
|
+
);
|
|
2459
|
+
}
|
|
2460
|
+
if (badge) {
|
|
2461
|
+
iconElem.append(<HTMLSpanElement>badge);
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
return iconElem;
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
private _updateTopBreadcrumb() {
|
|
2468
|
+
const breadcrumb = this.breadcrumb!;
|
|
2469
|
+
const topmost = this.getTopmostVpNode(true);
|
|
2470
|
+
const parentList = topmost?.getParentList(false, false);
|
|
2471
|
+
if (parentList?.length) {
|
|
2472
|
+
breadcrumb.innerHTML = "";
|
|
2473
|
+
for (const n of topmost.getParentList(false, false)) {
|
|
2474
|
+
const icon = this._createNodeIcon(n, false, false);
|
|
2475
|
+
if (icon) {
|
|
2476
|
+
breadcrumb.append(icon, " ");
|
|
2477
|
+
}
|
|
2478
|
+
const part = document.createElement("a");
|
|
2479
|
+
part.textContent = n.title;
|
|
2480
|
+
part.href = "#";
|
|
2481
|
+
part.classList.add("wb-breadcrumb");
|
|
2482
|
+
part.dataset.key = n.key;
|
|
2483
|
+
breadcrumb.append(part, this.options.strings!.breadcrumbDelimiter);
|
|
2484
|
+
}
|
|
2485
|
+
} else {
|
|
2486
|
+
breadcrumb.innerHTML = " ";
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2260
2490
|
/**
|
|
2261
2491
|
* This is the actual update method, which is wrapped inside a throttle method.
|
|
2262
2492
|
* It calls `updateColumns()` and `_updateRows()`.
|
|
@@ -2321,14 +2551,8 @@ export class Wunderbaum {
|
|
|
2321
2551
|
// console.profileEnd(`_updateViewportImmediately()`)
|
|
2322
2552
|
}
|
|
2323
2553
|
|
|
2324
|
-
if (this.
|
|
2325
|
-
|
|
2326
|
-
this.options.connectTopBreadcrumb.textContent != null,
|
|
2327
|
-
`Invalid 'connectTopBreadcrumb' option (input element expected).`
|
|
2328
|
-
);
|
|
2329
|
-
let path = this.getTopmostVpNode(true)?.getPath(false, "title", " > ");
|
|
2330
|
-
path = path ? path + " >" : "";
|
|
2331
|
-
this.options.connectTopBreadcrumb.textContent = path;
|
|
2554
|
+
if (this.breadcrumb) {
|
|
2555
|
+
this._updateTopBreadcrumb();
|
|
2332
2556
|
}
|
|
2333
2557
|
this._callEvent("update");
|
|
2334
2558
|
}
|