@neovici/cosmoz-treenode-navigator 3.1.1 → 4.0.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/CHANGELOG.md +12 -0
- package/cosmoz-treenode-button-view.js +199 -115
- package/cosmoz-treenode-navigator.js +295 -496
- package/helpers.js +252 -0
- package/package.json +22 -8
- package/test/cosmoz-treenode-navigator.test.js +62 -28
- package/test/data/basicTree.js +98 -41
- package/web-test-runner.config.mjs +1 -28
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# [4.0.0](https://github.com/neovici/cosmoz-treenode-navigator/compare/v3.1.1...v4.0.0) (2022-07-05)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Code Refactoring
|
|
5
|
+
|
|
6
|
+
* **migration:** index.html - Remove formatting changes ([c12af88](https://github.com/neovici/cosmoz-treenode-navigator/commit/c12af889c5b4f5f3b191538e2280c4b29b185b3e))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### BREAKING CHANGES
|
|
10
|
+
|
|
11
|
+
* **migration:** migration to haunted.js and Lit
|
|
12
|
+
|
|
1
13
|
## [3.1.1](https://github.com/neovici/cosmoz-treenode-navigator/compare/v3.1.0...v3.1.1) (2022-06-02)
|
|
2
14
|
|
|
3
15
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '@polymer/paper-icon-button/paper-icon-button';
|
|
2
2
|
import '@polymer/paper-button/paper-button';
|
|
3
|
+
import '@polymer/iron-icons/iron-icons';
|
|
3
4
|
|
|
4
5
|
import { Debouncer } from '@polymer/polymer/lib/utils/debounce';
|
|
5
6
|
import { timeOut } from '@polymer/polymer/lib/utils/async';
|
|
@@ -12,6 +13,7 @@ import { Tree } from '@neovici/cosmoz-tree';
|
|
|
12
13
|
import { translatable } from '@neovici/cosmoz-i18next';
|
|
13
14
|
|
|
14
15
|
import './cosmoz-treenode-navigator';
|
|
16
|
+
import { getNode, getTreePathParts } from './helpers';
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
19
|
`cosmoz-treenode-navigator`
|
|
@@ -23,94 +25,144 @@ class CosmozTreenodeButtonView extends translatable(PolymerElement) {
|
|
|
23
25
|
/* eslint-disable-next-line max-lines-per-function */
|
|
24
26
|
static get template() {
|
|
25
27
|
return html`
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
28
|
+
<style>
|
|
29
|
+
.actions {
|
|
30
|
+
display: flex;
|
|
31
|
+
}
|
|
32
|
+
.open {
|
|
33
|
+
flex: auto;
|
|
34
|
+
}
|
|
35
|
+
.pathToNode {
|
|
36
|
+
max-width: 320px;
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
text-overflow: ellipsis;
|
|
39
|
+
white-space: nowrap;
|
|
40
|
+
direction: rtl;
|
|
41
|
+
text-align: left;
|
|
42
|
+
}
|
|
43
|
+
/* Safari only css fix */
|
|
44
|
+
@media not all and (min-resolution: 0.001dpcm) {
|
|
45
|
+
@supports (-webkit-appearance: none) {
|
|
46
|
+
.pathToNode span {
|
|
47
|
+
display: inline-block;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
41
51
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
52
|
+
#chips {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-wrap: wrap;
|
|
55
|
+
max-width: 90%;
|
|
56
|
+
padding: 20px;
|
|
57
|
+
overflow-y: auto;
|
|
58
|
+
max-height: 30vh;
|
|
59
|
+
}
|
|
60
|
+
.chip {
|
|
61
|
+
border-radius: 500px;
|
|
62
|
+
background-color: #e0e0e0;
|
|
63
|
+
margin: 1px 4px 1px 0;
|
|
64
|
+
white-space: nowrap;
|
|
65
|
+
overflow: hidden;
|
|
66
|
+
display: flex;
|
|
67
|
+
align-items: center;
|
|
68
|
+
}
|
|
69
|
+
.chip > span {
|
|
70
|
+
color: #424242;
|
|
71
|
+
margin-left: 10px;
|
|
72
|
+
font-size: 13px;
|
|
73
|
+
overflow: hidden;
|
|
74
|
+
text-overflow: ellipsis;
|
|
75
|
+
}
|
|
76
|
+
.chip iron-icon {
|
|
77
|
+
margin: 2px 4px;
|
|
78
|
+
color: #cdcdcd;
|
|
79
|
+
background-color: #a6a6a6;
|
|
80
|
+
border-radius: 500px;
|
|
81
|
+
cursor: pointer;
|
|
82
|
+
min-width: 16px;
|
|
83
|
+
width: 16px;
|
|
84
|
+
min-height: 16px;
|
|
85
|
+
height: 16px;
|
|
86
|
+
}
|
|
77
87
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
#dialogTree {
|
|
89
|
+
min-width: 250px !important;
|
|
90
|
+
width: 450px;
|
|
91
|
+
}
|
|
92
|
+
</style>
|
|
93
|
+
<div class="actions">
|
|
94
|
+
<paper-button
|
|
95
|
+
part="button"
|
|
96
|
+
class="open"
|
|
97
|
+
raised
|
|
98
|
+
on-click="openDialogTree"
|
|
99
|
+
title="[[ buttonText ]]"
|
|
100
|
+
>
|
|
101
|
+
<div class="pathToNode">‎<span>[[ buttonText ]]</span></div>
|
|
102
|
+
</paper-button>
|
|
103
|
+
<paper-icon-button
|
|
104
|
+
part="clear"
|
|
105
|
+
icon="clear"
|
|
106
|
+
on-click="reset"
|
|
107
|
+
hidden$="[[ !_enableReset(nodePath, noReset) ]]"
|
|
108
|
+
></paper-icon-button>
|
|
94
109
|
</div>
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
<paper-button dialog-dismiss>[[ _('Cancel', t) ]]</paper-button>
|
|
110
|
+
<template
|
|
111
|
+
is="dom-if"
|
|
112
|
+
if="[[ _showSelectedNodes(multiSelection, selectedNodes.length) ]]"
|
|
113
|
+
>
|
|
114
|
+
<div id="chips" class="row">
|
|
115
|
+
<template is="dom-repeat" items="[[ selectedNodes ]]">
|
|
116
|
+
<div class="chip">
|
|
117
|
+
<span>[[ _getChipText(item, tree) ]]</span
|
|
118
|
+
><iron-icon
|
|
119
|
+
icon="clear"
|
|
120
|
+
on-click="_clearItemSelection"
|
|
121
|
+
></iron-icon>
|
|
122
|
+
</div>
|
|
123
|
+
</template>
|
|
110
124
|
</div>
|
|
111
125
|
</template>
|
|
112
|
-
|
|
113
|
-
|
|
126
|
+
|
|
127
|
+
<cosmoz-dialog
|
|
128
|
+
id="dialogTree"
|
|
129
|
+
class="treeDialog"
|
|
130
|
+
on-iron-overlay-opened="focusSearch"
|
|
131
|
+
modal
|
|
132
|
+
prerender
|
|
133
|
+
>
|
|
134
|
+
<template>
|
|
135
|
+
<h2>[[ dialogText ]]</h2>
|
|
136
|
+
<cosmoz-treenode-navigator
|
|
137
|
+
id="treeNavigator"
|
|
138
|
+
class="no-padding"
|
|
139
|
+
tree="[[ tree ]]"
|
|
140
|
+
selected-node="{{ selectedNode }}"
|
|
141
|
+
on-data-plane-changed="refit"
|
|
142
|
+
highlighted-node-path="{{ highlightedNodePath }}"
|
|
143
|
+
search-placeholder="[[ searchPlaceholder ]]"
|
|
144
|
+
search-global-placeholder="[[ searchGlobalPlaceholder ]]"
|
|
145
|
+
search-min-length="[[ searchMinLength ]]"
|
|
146
|
+
node-path="{{ nodePath }}"
|
|
147
|
+
nodes-on-node-path="{{ nodesOnNodePath }}"
|
|
148
|
+
on-node-dblclicked="_selectNodeAndCloseDialog"
|
|
149
|
+
on-select-node="selectNode"
|
|
150
|
+
>
|
|
151
|
+
<slot></slot>
|
|
152
|
+
</cosmoz-treenode-navigator>
|
|
153
|
+
<div class="buttons">
|
|
154
|
+
<paper-button
|
|
155
|
+
disabled="[[!highlightedNodePath]]"
|
|
156
|
+
dialog-confirm
|
|
157
|
+
autofocus
|
|
158
|
+
on-click="selectNode"
|
|
159
|
+
>[[ _('Select', t) ]]</paper-button
|
|
160
|
+
>
|
|
161
|
+
<paper-button dialog-dismiss>[[ _('Cancel', t) ]]</paper-button>
|
|
162
|
+
</div>
|
|
163
|
+
</template>
|
|
164
|
+
</cosmoz-dialog>
|
|
165
|
+
`;
|
|
114
166
|
}
|
|
115
167
|
|
|
116
168
|
static get is() {
|
|
@@ -120,20 +172,19 @@ class CosmozTreenodeButtonView extends translatable(PolymerElement) {
|
|
|
120
172
|
/* eslint-disable-next-line max-lines-per-function */
|
|
121
173
|
static get properties() {
|
|
122
174
|
return {
|
|
123
|
-
|
|
124
175
|
multiSelection: {
|
|
125
176
|
type: Boolean,
|
|
126
177
|
value: false
|
|
127
178
|
},
|
|
128
179
|
/*
|
|
129
|
-
|
|
130
|
-
|
|
180
|
+
* The main node structure
|
|
181
|
+
*/
|
|
131
182
|
tree: {
|
|
132
183
|
type: Tree
|
|
133
184
|
},
|
|
134
185
|
/*
|
|
135
|
-
|
|
136
|
-
|
|
186
|
+
* Currently selected node object
|
|
187
|
+
*/
|
|
137
188
|
selectedNode: {
|
|
138
189
|
type: Object,
|
|
139
190
|
value() {
|
|
@@ -157,14 +208,14 @@ class CosmozTreenodeButtonView extends translatable(PolymerElement) {
|
|
|
157
208
|
value: false
|
|
158
209
|
},
|
|
159
210
|
/*
|
|
160
|
-
|
|
161
|
-
|
|
211
|
+
* Placeholder for the search field
|
|
212
|
+
*/
|
|
162
213
|
searchPlaceholder: {
|
|
163
214
|
type: String
|
|
164
215
|
},
|
|
165
216
|
/*
|
|
166
|
-
|
|
167
|
-
|
|
217
|
+
* Placeholder for button text
|
|
218
|
+
*/
|
|
168
219
|
buttonTextPlaceholder: {
|
|
169
220
|
type: String,
|
|
170
221
|
computed: 'getButtonTextPlaceholder(multiSelection)'
|
|
@@ -176,42 +227,44 @@ class CosmozTreenodeButtonView extends translatable(PolymerElement) {
|
|
|
176
227
|
},
|
|
177
228
|
|
|
178
229
|
/*
|
|
179
|
-
|
|
180
|
-
|
|
230
|
+
* The path of the selected node
|
|
231
|
+
*/
|
|
181
232
|
nodePath: {
|
|
182
233
|
type: String,
|
|
183
234
|
notify: true
|
|
184
235
|
},
|
|
185
236
|
/*
|
|
186
|
-
|
|
187
|
-
|
|
237
|
+
* The nodes on the path of the selected node
|
|
238
|
+
*/
|
|
188
239
|
nodesOnNodePath: {
|
|
189
240
|
type: Array
|
|
190
241
|
},
|
|
191
242
|
/*
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
243
|
+
* Text displayed when local search has finished
|
|
244
|
+
* to suggest a search on the entire tree
|
|
245
|
+
*/
|
|
195
246
|
searchGlobalPlaceholder: {
|
|
196
|
-
type: String
|
|
247
|
+
type: String,
|
|
248
|
+
value: 'Click to search again but globally.'
|
|
197
249
|
},
|
|
198
250
|
/*
|
|
199
|
-
|
|
200
|
-
|
|
251
|
+
* Settable text for dialog title.
|
|
252
|
+
*/
|
|
201
253
|
dialogText: {
|
|
202
254
|
type: String,
|
|
203
255
|
value: 'Search or navigate to chosen destination'
|
|
204
256
|
},
|
|
205
257
|
/*
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
258
|
+
* Minimum length before an search
|
|
259
|
+
* starts.
|
|
260
|
+
*/
|
|
209
261
|
searchMinLength: {
|
|
210
|
-
type: Number
|
|
262
|
+
type: Number,
|
|
263
|
+
value: 1
|
|
211
264
|
},
|
|
212
265
|
/*
|
|
213
|
-
|
|
214
|
-
|
|
266
|
+
* Path string of highlighted (focused) node
|
|
267
|
+
*/
|
|
215
268
|
highlightedNodePath: {
|
|
216
269
|
type: String
|
|
217
270
|
}
|
|
@@ -230,6 +283,11 @@ class CosmozTreenodeButtonView extends translatable(PolymerElement) {
|
|
|
230
283
|
this.splice('selectedNodes', selectedIndex, 1);
|
|
231
284
|
// ... so we must prevent further propagation of this event, because its source is now invalid.
|
|
232
285
|
// (This has caused troubles in app-drawer-layout click event handler).
|
|
286
|
+
|
|
287
|
+
if (!this.selectedNodes.length) {
|
|
288
|
+
this.reset();
|
|
289
|
+
}
|
|
290
|
+
|
|
233
291
|
event.preventDefault();
|
|
234
292
|
event.stopPropagation();
|
|
235
293
|
}
|
|
@@ -239,7 +297,9 @@ class CosmozTreenodeButtonView extends translatable(PolymerElement) {
|
|
|
239
297
|
* @returns {string} Text label.
|
|
240
298
|
*/
|
|
241
299
|
getButtonTextPlaceholder(multiSelection) {
|
|
242
|
-
return multiSelection
|
|
300
|
+
return multiSelection
|
|
301
|
+
? this._('Select a node')
|
|
302
|
+
: this._('No selection made');
|
|
243
303
|
}
|
|
244
304
|
/**
|
|
245
305
|
* Whether the reset button should be enabled or not.
|
|
@@ -263,7 +323,10 @@ class CosmozTreenodeButtonView extends translatable(PolymerElement) {
|
|
|
263
323
|
if (!Array.isArray(pathParts) || pathParts.length === 0) {
|
|
264
324
|
return placeholder;
|
|
265
325
|
}
|
|
266
|
-
return pathParts
|
|
326
|
+
return pathParts
|
|
327
|
+
.filter(n => n)
|
|
328
|
+
.map(part => part[this.tree.searchProperty])
|
|
329
|
+
.join(' / ');
|
|
267
330
|
}
|
|
268
331
|
/**
|
|
269
332
|
* Get text from a node to set on a node chip.
|
|
@@ -293,7 +356,10 @@ class CosmozTreenodeButtonView extends translatable(PolymerElement) {
|
|
|
293
356
|
*/
|
|
294
357
|
reset() {
|
|
295
358
|
this.nodePath = '';
|
|
359
|
+
this.selectedNode = {};
|
|
360
|
+
this.nodesOnNodePath = [];
|
|
296
361
|
this.selectedNodes = [];
|
|
362
|
+
this.highlightedNodePath = '';
|
|
297
363
|
}
|
|
298
364
|
/**
|
|
299
365
|
* Select the node in the treenode navigator.
|
|
@@ -301,9 +367,25 @@ class CosmozTreenodeButtonView extends translatable(PolymerElement) {
|
|
|
301
367
|
*/
|
|
302
368
|
selectNode() {
|
|
303
369
|
// nodePath selects the node, without it no selectedNode
|
|
304
|
-
|
|
370
|
+
|
|
371
|
+
this.selectedNode = getNode(
|
|
372
|
+
this.highlightedNodePath || this.nodePath,
|
|
373
|
+
this.tree
|
|
374
|
+
);
|
|
375
|
+
if (this.highlightedNodePath) {
|
|
376
|
+
this.nodePath = this.highlightedNodePath;
|
|
377
|
+
}
|
|
378
|
+
this.nodesOnNodePath = getTreePathParts(
|
|
379
|
+
this.highlightedNodePath || this.nodePath,
|
|
380
|
+
this.tree
|
|
381
|
+
);
|
|
382
|
+
|
|
305
383
|
if (this.multiSelection) {
|
|
306
|
-
if (
|
|
384
|
+
if (
|
|
385
|
+
!this.selectedNodes.some(
|
|
386
|
+
node => node.pathLocator === this.highlightedNodePath
|
|
387
|
+
)
|
|
388
|
+
) {
|
|
307
389
|
this.push('selectedNodes', this.selectedNode);
|
|
308
390
|
}
|
|
309
391
|
this.nodePath = '';
|
|
@@ -325,7 +407,7 @@ class CosmozTreenodeButtonView extends translatable(PolymerElement) {
|
|
|
325
407
|
* @returns {boolean} Whether the selected nodes container should be visible or not.
|
|
326
408
|
*/
|
|
327
409
|
_showSelectedNodes(multiSelection, selectedNodesLength) {
|
|
328
|
-
return
|
|
410
|
+
return multiSelection && selectedNodesLength > 0;
|
|
329
411
|
}
|
|
330
412
|
/**
|
|
331
413
|
* Callback event handler to refit the treenode navigator dialog when
|
|
@@ -333,11 +415,13 @@ class CosmozTreenodeButtonView extends translatable(PolymerElement) {
|
|
|
333
415
|
* @returns {void}
|
|
334
416
|
*/
|
|
335
417
|
refit() {
|
|
336
|
-
this._debouncer = Debouncer.debounce(
|
|
418
|
+
this._debouncer = Debouncer.debounce(
|
|
419
|
+
this._debouncer,
|
|
337
420
|
timeOut.after(50), // 5 was enough during test
|
|
338
421
|
() => {
|
|
339
422
|
this.$.dialogTree.fit();
|
|
340
|
-
}
|
|
423
|
+
}
|
|
424
|
+
);
|
|
341
425
|
}
|
|
342
426
|
}
|
|
343
427
|
customElements.define(CosmozTreenodeButtonView.is, CosmozTreenodeButtonView);
|