wunderbaum 0.10.1 → 0.11.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.
- package/README.md +6 -7
- package/dist/wunderbaum.css +18 -10
- package/dist/wunderbaum.css.map +1 -1
- package/dist/wunderbaum.d.ts +204 -49
- package/dist/wunderbaum.esm.js +826 -606
- package/dist/wunderbaum.esm.min.js +26 -26
- package/dist/wunderbaum.esm.min.js.map +1 -1
- package/dist/wunderbaum.umd.js +826 -606
- package/dist/wunderbaum.umd.min.js +32 -32
- package/dist/wunderbaum.umd.min.js.map +1 -1
- package/package.json +11 -10
- package/src/common.ts +17 -2
- package/src/types.ts +126 -30
- package/src/util.ts +18 -8
- package/src/wb_ext_dnd.ts +9 -4
- package/src/wb_ext_edit.ts +4 -0
- package/src/wb_ext_grid.ts +1 -1
- package/src/wb_node.ts +164 -17
- package/src/wb_options.ts +26 -2
- package/src/wunderbaum.scss +10 -0
- package/src/wunderbaum.ts +124 -47
package/src/wb_node.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
ApplyCommandType,
|
|
14
14
|
ChangeType,
|
|
15
15
|
CheckboxOption,
|
|
16
|
+
ColumnDefinition,
|
|
16
17
|
ColumnEventInfoMap,
|
|
17
18
|
ExpandAllOptions,
|
|
18
19
|
IconOption,
|
|
@@ -27,12 +28,15 @@ import {
|
|
|
27
28
|
NodeVisitCallback,
|
|
28
29
|
NodeVisitResponse,
|
|
29
30
|
RenderOptions,
|
|
31
|
+
ResetOrderOptions,
|
|
30
32
|
ScrollIntoViewOptions,
|
|
31
33
|
SetActiveOptions,
|
|
32
34
|
SetExpandedOptions,
|
|
33
35
|
SetSelectedOptions,
|
|
34
36
|
SetStatusOptions,
|
|
37
|
+
SortByPropertyOptions,
|
|
35
38
|
SortCallback,
|
|
39
|
+
SortOrderType,
|
|
36
40
|
SourceType,
|
|
37
41
|
TooltipOption,
|
|
38
42
|
TristateType,
|
|
@@ -46,7 +50,6 @@ import {
|
|
|
46
50
|
makeNodeTitleMatcher,
|
|
47
51
|
nodeTitleSorter,
|
|
48
52
|
RESERVED_TREE_SOURCE_KEYS,
|
|
49
|
-
ROW_HEIGHT,
|
|
50
53
|
TEST_IMG,
|
|
51
54
|
TITLE_SPAN_PAD_Y,
|
|
52
55
|
} from "./common";
|
|
@@ -79,6 +82,21 @@ const NODE_DICT_PROPS = new Set<string>(NODE_PROPS);
|
|
|
79
82
|
NODE_DICT_PROPS.delete("_partsel");
|
|
80
83
|
NODE_DICT_PROPS.delete("unselectable");
|
|
81
84
|
|
|
85
|
+
// /** Node properties that are of type bool (or boolean & string).
|
|
86
|
+
// * When parsing, we accept 0 for false and 1 for true for better JSON compression.
|
|
87
|
+
// */
|
|
88
|
+
// export const NODE_BOOL_PROPS: Set<string> = new Set([
|
|
89
|
+
// "checkbox",
|
|
90
|
+
// "colspan",
|
|
91
|
+
// "expanded",
|
|
92
|
+
// "icon",
|
|
93
|
+
// "iconTooltip",
|
|
94
|
+
// "radiogroup",
|
|
95
|
+
// "selected",
|
|
96
|
+
// "tooltip",
|
|
97
|
+
// "unselectable",
|
|
98
|
+
// ]);
|
|
99
|
+
|
|
82
100
|
/**
|
|
83
101
|
* A single tree node.
|
|
84
102
|
*
|
|
@@ -104,12 +122,26 @@ export class WunderbaumNode {
|
|
|
104
122
|
* @see Use {@link setKey} to modify.
|
|
105
123
|
*/
|
|
106
124
|
public readonly refKey: string | undefined = undefined;
|
|
125
|
+
/**
|
|
126
|
+
* Array of child nodes (null for leaf nodes).
|
|
127
|
+
* For lazy nodes, this is `null` or ùndefined` until the children are loaded
|
|
128
|
+
* and leaf nodes may be `[]` (empty array).
|
|
129
|
+
* @see {@link hasChildren}, {@link addChildren}, {@link lazy}.
|
|
130
|
+
*/
|
|
107
131
|
public children: WunderbaumNode[] | null = null;
|
|
132
|
+
/** Render a checkbox or radio button @see {@link selected}. */
|
|
108
133
|
public checkbox?: CheckboxOption;
|
|
134
|
+
/** If true, this node's children are considerd radio buttons.
|
|
135
|
+
* @see {@link isRadio}.
|
|
136
|
+
*/
|
|
109
137
|
public radiogroup?: boolean;
|
|
110
138
|
/** If true, (in grid mode) no cells are rendered, except for the node title.*/
|
|
111
139
|
public colspan?: boolean;
|
|
140
|
+
/** Icon definition. */
|
|
112
141
|
public icon?: IconOption;
|
|
142
|
+
/** Lazy loading flag.
|
|
143
|
+
* @see {@link isLazy}, {@link isLoaded}, {@link isUnloaded}.
|
|
144
|
+
*/
|
|
113
145
|
public lazy?: boolean;
|
|
114
146
|
/** Expansion state.
|
|
115
147
|
* @see {@link isExpandable}, {@link isExpanded}, {@link setExpanded}. */
|
|
@@ -118,8 +150,14 @@ export class WunderbaumNode {
|
|
|
118
150
|
* @see {@link isSelected}, {@link setSelected}, {@link toggleSelected}. */
|
|
119
151
|
public selected?: boolean;
|
|
120
152
|
public unselectable?: boolean;
|
|
153
|
+
/** Node type (used for styling).
|
|
154
|
+
* @see {@link Wunderbaum.types}.
|
|
155
|
+
*/
|
|
121
156
|
public type?: string;
|
|
122
|
-
|
|
157
|
+
/** Tooltip definition (`true`: use node's title). */
|
|
158
|
+
public tooltip?: TooltipOption;
|
|
159
|
+
/** Icon tooltip definition (`true`: use node's title). */
|
|
160
|
+
public iconTooltip?: TooltipOption;
|
|
123
161
|
/** Additional classes added to `div.wb-row`.
|
|
124
162
|
* @see {@link hasClass}, {@link setClass}. */
|
|
125
163
|
public classes: Set<string> | null = null; //new Set<string>();
|
|
@@ -149,24 +187,30 @@ export class WunderbaumNode {
|
|
|
149
187
|
|
|
150
188
|
this.tree = tree;
|
|
151
189
|
this.parent = parent;
|
|
152
|
-
|
|
153
190
|
this.key = "" + (data.key ?? ++WunderbaumNode.sequence);
|
|
154
191
|
this.title = "" + (data.title ?? "<" + this.key + ">");
|
|
192
|
+
this.expanded = !!data.expanded;
|
|
193
|
+
this.lazy = !!data.lazy;
|
|
194
|
+
|
|
195
|
+
// We set the following node properties only if a matching data value is
|
|
196
|
+
// passed
|
|
155
197
|
data.refKey != null ? (this.refKey = "" + data.refKey) : 0;
|
|
156
198
|
data.type != null ? (this.type = "" + data.type) : 0;
|
|
157
|
-
this.
|
|
158
|
-
data.
|
|
159
|
-
|
|
199
|
+
data.icon != null ? (this.icon = util.intToBool(data.icon)) : 0;
|
|
200
|
+
data.tooltip != null ? (this.tooltip = util.intToBool(data.tooltip)) : 0;
|
|
201
|
+
data.iconTooltip != null
|
|
202
|
+
? (this.iconTooltip = util.intToBool(data.iconTooltip))
|
|
203
|
+
: 0;
|
|
160
204
|
data.statusNodeType != null
|
|
161
205
|
? (this.statusNodeType = ("" + data.statusNodeType) as NodeStatusType)
|
|
162
206
|
: 0;
|
|
163
207
|
data.colspan != null ? (this.colspan = !!data.colspan) : 0;
|
|
164
208
|
|
|
165
209
|
// Selection
|
|
166
|
-
data.checkbox != null ? (
|
|
210
|
+
data.checkbox != null ? util.intToBool(data.checkbox) : 0;
|
|
167
211
|
data.radiogroup != null ? (this.radiogroup = !!data.radiogroup) : 0;
|
|
168
|
-
this.selected = data.selected
|
|
169
|
-
data.unselectable
|
|
212
|
+
data.selected != null ? (this.selected = !!data.selected) : 0;
|
|
213
|
+
data.unselectable != null ? (this.unselectable = !!data.unselectable) : 0;
|
|
170
214
|
|
|
171
215
|
if (data.classes) {
|
|
172
216
|
this.setClass(data.classes);
|
|
@@ -787,7 +831,7 @@ export class WunderbaumNode {
|
|
|
787
831
|
return this.classes ? this.classes.has(className) : false;
|
|
788
832
|
}
|
|
789
833
|
|
|
790
|
-
/** Return true if node ist the currently focused node. */
|
|
834
|
+
/** Return true if node ist the currently focused node. @since 0.9.0 */
|
|
791
835
|
hasFocus(): boolean {
|
|
792
836
|
return this.tree.focusNode === this;
|
|
793
837
|
}
|
|
@@ -1054,6 +1098,8 @@ export class WunderbaumNode {
|
|
|
1054
1098
|
if (tree.options.selectMode === "hier") {
|
|
1055
1099
|
this.fixSelection3FromEndNodes();
|
|
1056
1100
|
}
|
|
1101
|
+
// Allow to un-sort nodes after sorting
|
|
1102
|
+
this.resetNativeChildOrder();
|
|
1057
1103
|
|
|
1058
1104
|
this._callEvent("load");
|
|
1059
1105
|
}
|
|
@@ -1116,9 +1162,9 @@ export class WunderbaumNode {
|
|
|
1116
1162
|
// Check for overlapping requests
|
|
1117
1163
|
if (this._requestId) {
|
|
1118
1164
|
this.logWarn(
|
|
1119
|
-
`Recursive load request #${requestId} while #${this._requestId} is pending
|
|
1165
|
+
`Recursive load request #${requestId} while #${this._requestId} is pending. ` +
|
|
1166
|
+
"The previous request will be ignored."
|
|
1120
1167
|
);
|
|
1121
|
-
// node.debug("Send load request #" + requestId);
|
|
1122
1168
|
}
|
|
1123
1169
|
this._requestId = requestId;
|
|
1124
1170
|
|
|
@@ -1636,6 +1682,7 @@ export class WunderbaumNode {
|
|
|
1636
1682
|
protected _render_markup(opts: RenderOptions) {
|
|
1637
1683
|
const tree = this.tree;
|
|
1638
1684
|
const treeOptions = tree.options;
|
|
1685
|
+
const rowHeight = treeOptions.rowHeightPx!;
|
|
1639
1686
|
const checkbox = this.getOption("checkbox");
|
|
1640
1687
|
const columns = tree.columns;
|
|
1641
1688
|
const level = this.getLevel();
|
|
@@ -1657,7 +1704,7 @@ export class WunderbaumNode {
|
|
|
1657
1704
|
rowDiv = document.createElement("div");
|
|
1658
1705
|
rowDiv.classList.add("wb-row");
|
|
1659
1706
|
|
|
1660
|
-
rowDiv.style.top = this._rowIdx! *
|
|
1707
|
+
rowDiv.style.top = this._rowIdx! * rowHeight + "px";
|
|
1661
1708
|
|
|
1662
1709
|
this._rowElem = rowDiv;
|
|
1663
1710
|
|
|
@@ -2091,7 +2138,7 @@ export class WunderbaumNode {
|
|
|
2091
2138
|
*
|
|
2092
2139
|
* @param name name of the option property (on node and tree)
|
|
2093
2140
|
* @param defaultValue return this if nothing else matched
|
|
2094
|
-
* {@link Wunderbaum.getOption|Wunderbaum.getOption
|
|
2141
|
+
* {@link Wunderbaum.getOption|Wunderbaum.getOption}
|
|
2095
2142
|
*/
|
|
2096
2143
|
getOption(name: string, defaultValue?: any) {
|
|
2097
2144
|
const tree = this.tree;
|
|
@@ -2130,7 +2177,7 @@ export class WunderbaumNode {
|
|
|
2130
2177
|
}
|
|
2131
2178
|
|
|
2132
2179
|
/** Make sure that this node is visible in the viewport.
|
|
2133
|
-
* @see {@link Wunderbaum.scrollTo|Wunderbaum.scrollTo
|
|
2180
|
+
* @see {@link Wunderbaum.scrollTo|Wunderbaum.scrollTo}
|
|
2134
2181
|
*/
|
|
2135
2182
|
async scrollIntoView(options?: ScrollIntoViewOptions) {
|
|
2136
2183
|
const opts = Object.assign({ node: this }, options);
|
|
@@ -2284,9 +2331,9 @@ export class WunderbaumNode {
|
|
|
2284
2331
|
* and column content. It can be reduced to 'ChangeType.status' if only
|
|
2285
2332
|
* active/focus/selected state has changed.
|
|
2286
2333
|
*
|
|
2287
|
-
* This method will eventually call {@link WunderbaumNode._render
|
|
2334
|
+
* This method will eventually call {@link WunderbaumNode._render} with
|
|
2288
2335
|
* default options, but may be more consistent with the tree's
|
|
2289
|
-
* {@link Wunderbaum.update
|
|
2336
|
+
* {@link Wunderbaum.update} API.
|
|
2290
2337
|
*/
|
|
2291
2338
|
update(change: ChangeType = ChangeType.data) {
|
|
2292
2339
|
util.assert(
|
|
@@ -2669,6 +2716,106 @@ export class WunderbaumNode {
|
|
|
2669
2716
|
// this.triggerModify("sort"); // TODO
|
|
2670
2717
|
}
|
|
2671
2718
|
|
|
2719
|
+
/**
|
|
2720
|
+
* Renumber nodes `_nativeIndex`. This is useful to allow to restore the
|
|
2721
|
+
* order after sorting a column.
|
|
2722
|
+
* This method is automatically called after loading new child nodes.
|
|
2723
|
+
* @since 0.11.0
|
|
2724
|
+
*/
|
|
2725
|
+
resetNativeChildOrder(options?: ResetOrderOptions) {
|
|
2726
|
+
const { recursive = true, propName = "_nativeIndex" } = options ?? {};
|
|
2727
|
+
|
|
2728
|
+
if (this.children) {
|
|
2729
|
+
this.children.forEach((child, i) => {
|
|
2730
|
+
child.data[propName] = i;
|
|
2731
|
+
if (recursive && child.children) {
|
|
2732
|
+
child.resetNativeChildOrder(options);
|
|
2733
|
+
}
|
|
2734
|
+
});
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
|
|
2738
|
+
/**
|
|
2739
|
+
* Convenience method to implement column sorting.
|
|
2740
|
+
* @since 0.11.0
|
|
2741
|
+
*/
|
|
2742
|
+
sortByProperty(options: SortByPropertyOptions) {
|
|
2743
|
+
const {
|
|
2744
|
+
caseInsensitive = true,
|
|
2745
|
+
deep = true,
|
|
2746
|
+
nativeOrderPropName = "_nativeIndex",
|
|
2747
|
+
updateColInfo = false,
|
|
2748
|
+
} = options;
|
|
2749
|
+
|
|
2750
|
+
let order: SortOrderType;
|
|
2751
|
+
let colDef: ColumnDefinition | null;
|
|
2752
|
+
|
|
2753
|
+
if (updateColInfo) {
|
|
2754
|
+
colDef = this.tree["_columnsById"][options.colId!];
|
|
2755
|
+
util.assert(colDef, `Invalid colId specified: ${options.colId}`);
|
|
2756
|
+
order =
|
|
2757
|
+
options.order ??
|
|
2758
|
+
util.rotate(colDef!.sortOrder, ["asc", "desc", undefined]);
|
|
2759
|
+
|
|
2760
|
+
for (const col of this.tree.columns) {
|
|
2761
|
+
col.sortOrder = col === colDef ? order : undefined;
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
this.tree.update(ChangeType.colStructure);
|
|
2765
|
+
} else {
|
|
2766
|
+
order = options.order ?? "asc";
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2769
|
+
let propName = options.propName ?? (options.colId || "");
|
|
2770
|
+
if (propName === "*") {
|
|
2771
|
+
propName = "title";
|
|
2772
|
+
}
|
|
2773
|
+
if (order == null) {
|
|
2774
|
+
propName = nativeOrderPropName;
|
|
2775
|
+
order = "asc";
|
|
2776
|
+
}
|
|
2777
|
+
this.logDebug(`sortByProperty(), propName=${propName}, ${order}`, options);
|
|
2778
|
+
util.assert(propName, "No property name specified");
|
|
2779
|
+
|
|
2780
|
+
const cmp = (a: WunderbaumNode, b: WunderbaumNode) => {
|
|
2781
|
+
let av, bv;
|
|
2782
|
+
if (NODE_DICT_PROPS.has(<string>propName)) {
|
|
2783
|
+
av = a[propName as keyof WunderbaumNode];
|
|
2784
|
+
bv = b[propName as keyof WunderbaumNode];
|
|
2785
|
+
} else {
|
|
2786
|
+
av = a.data[propName];
|
|
2787
|
+
bv = b.data[propName];
|
|
2788
|
+
}
|
|
2789
|
+
if (av == null && bv == null) {
|
|
2790
|
+
return 0;
|
|
2791
|
+
}
|
|
2792
|
+
if (av == null) {
|
|
2793
|
+
av = typeof bv === "string" ? "" : 0;
|
|
2794
|
+
} else if (typeof av === "boolean") {
|
|
2795
|
+
av = av ? 1 : 0;
|
|
2796
|
+
}
|
|
2797
|
+
if (bv == null) {
|
|
2798
|
+
bv = typeof av === "string" ? "" : 0;
|
|
2799
|
+
} else if (typeof bv === "boolean") {
|
|
2800
|
+
bv = bv ? 1 : 0;
|
|
2801
|
+
}
|
|
2802
|
+
if (caseInsensitive) {
|
|
2803
|
+
if (typeof av === "string") {
|
|
2804
|
+
av = av.toLowerCase();
|
|
2805
|
+
}
|
|
2806
|
+
if (typeof bv === "string") {
|
|
2807
|
+
bv = bv.toLowerCase();
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
if (order === "desc") {
|
|
2811
|
+
return av === bv ? 0 : av > bv ? -1 : 1;
|
|
2812
|
+
}
|
|
2813
|
+
return av === bv ? 0 : av > bv ? 1 : -1;
|
|
2814
|
+
};
|
|
2815
|
+
|
|
2816
|
+
return this.sortChildren(cmp, deep);
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2672
2819
|
/**
|
|
2673
2820
|
* Trigger `modifyChild` event on a parent to signal that a child was modified.
|
|
2674
2821
|
* @param {string} operation Type of change: 'add', 'remove', 'rename', 'move', 'data', ...
|
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
|
@@ -393,6 +393,16 @@ div.wunderbaum {
|
|
|
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 {
|