@neovici/cosmoz-treenode-navigator 6.0.1 → 7.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/README.md +4 -12
- package/dist/cosmoz-treenode-button-view.d.ts +2 -0
- package/dist/cosmoz-treenode-button-view.d.ts.map +1 -0
- package/dist/cosmoz-treenode-button-view.js +203 -0
- package/dist/cosmoz-treenode-button-view.js.map +1 -0
- package/dist/cosmoz-treenode-button-view.styles.d.ts +3 -0
- package/dist/cosmoz-treenode-button-view.styles.d.ts.map +1 -0
- package/dist/cosmoz-treenode-button-view.styles.js +218 -0
- package/dist/cosmoz-treenode-button-view.styles.js.map +1 -0
- package/dist/cosmoz-treenode-navigator.d.ts +2 -0
- package/dist/cosmoz-treenode-navigator.d.ts.map +1 -0
- package/dist/cosmoz-treenode-navigator.js +233 -0
- package/dist/cosmoz-treenode-navigator.js.map +1 -0
- package/dist/cosmoz-treenode-navigator.styles.d.ts +3 -0
- package/dist/cosmoz-treenode-navigator.styles.d.ts.map +1 -0
- package/{cosmoz-treenode-navigator.styles.js → dist/cosmoz-treenode-navigator.styles.js} +12 -4
- package/dist/cosmoz-treenode-navigator.styles.js.map +1 -0
- package/dist/hooks/useKeyDown.d.ts +2 -0
- package/dist/hooks/useKeyDown.d.ts.map +1 -0
- package/dist/hooks/useKeyDown.js +16 -0
- package/dist/hooks/useKeyDown.js.map +1 -0
- package/dist/util/helpers.d.ts +51 -0
- package/dist/util/helpers.d.ts.map +1 -0
- package/dist/util/helpers.js +123 -0
- package/dist/util/helpers.js.map +1 -0
- package/package.json +61 -16
- package/test/data/basicTree.js +34 -34
- package/test/data/rtlTest.js +6 -7
- package/cosmoz-treenode-button-view.js +0 -445
- package/cosmoz-treenode-navigator.js +0 -297
- package/helpers.js +0 -124
- package/test/cosmoz-treenode-button-view.test.js +0 -52
- package/test/cosmoz-treenode-navigator.test.js +0 -102
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
component,
|
|
3
|
-
useEffect,
|
|
4
|
-
useState,
|
|
5
|
-
useMemo,
|
|
6
|
-
useCallback,
|
|
7
|
-
useRef,
|
|
8
|
-
} from '@pionjs/pion';
|
|
9
|
-
import { html, nothing } from 'lit-html';
|
|
10
|
-
import { when } from 'lit-html/directives/when.js';
|
|
11
|
-
import { guard } from 'lit-html/directives/guard.js';
|
|
12
|
-
import { ref } from 'lit-html/directives/ref.js';
|
|
13
|
-
import { virtualize } from '@lit-labs/virtualizer/virtualize.js';
|
|
14
|
-
|
|
15
|
-
import '@neovici/cosmoz-input';
|
|
16
|
-
import { useMeta } from '@neovici/cosmoz-utils/hooks/use-meta';
|
|
17
|
-
import { notifyProperty } from '@neovici/cosmoz-utils/hooks/use-notify-property';
|
|
18
|
-
|
|
19
|
-
import {
|
|
20
|
-
getParentPath,
|
|
21
|
-
computeDataPlane,
|
|
22
|
-
computeRowClass,
|
|
23
|
-
onNodeDblClicked,
|
|
24
|
-
} from './helpers';
|
|
25
|
-
import styles from './cosmoz-treenode-navigator.styles';
|
|
26
|
-
|
|
27
|
-
const TreenodeNavigator = (host) => {
|
|
28
|
-
const {
|
|
29
|
-
/**
|
|
30
|
-
* The main node structure
|
|
31
|
-
*/
|
|
32
|
-
tree,
|
|
33
|
-
/**
|
|
34
|
-
* Placeholder for search field.
|
|
35
|
-
*/
|
|
36
|
-
searchPlaceholder,
|
|
37
|
-
/**
|
|
38
|
-
* Text displayed when local search has finished
|
|
39
|
-
* to suggest a search on the entire tree
|
|
40
|
-
*/
|
|
41
|
-
searchGlobalPlaceholder,
|
|
42
|
-
/**
|
|
43
|
-
* Minimum length of searchValue to trigger a search
|
|
44
|
-
*/
|
|
45
|
-
searchMinLength,
|
|
46
|
-
nodePath,
|
|
47
|
-
opened,
|
|
48
|
-
} = host,
|
|
49
|
-
/**
|
|
50
|
-
* The path of the opened node
|
|
51
|
-
*/
|
|
52
|
-
[openNodePath, setOpenNodePath] = useState(''),
|
|
53
|
-
/**
|
|
54
|
-
* The highlighted (focused) node
|
|
55
|
-
* This is the node which is currently selected in the list
|
|
56
|
-
*/
|
|
57
|
-
[highlightedNode, setHighlightedNode] = useState(),
|
|
58
|
-
/**
|
|
59
|
-
* The search string
|
|
60
|
-
*/
|
|
61
|
-
[searchValue, setSearchValue] = useState(''),
|
|
62
|
-
search = useMemo(
|
|
63
|
-
() => (searchValue?.length > searchMinLength && searchValue) || undefined,
|
|
64
|
-
[searchValue, searchMinLength],
|
|
65
|
-
),
|
|
66
|
-
/**
|
|
67
|
-
* The currently displayed node list
|
|
68
|
-
*/
|
|
69
|
-
dataPlane = useMemo(
|
|
70
|
-
() => computeDataPlane(tree, search, openNodePath),
|
|
71
|
-
[tree, search, openNodePath],
|
|
72
|
-
),
|
|
73
|
-
/**
|
|
74
|
-
* Opens a node (renderLevel) based on a given path
|
|
75
|
-
* @param {object} clickedNode - The clicked node
|
|
76
|
-
* @return {undefined}
|
|
77
|
-
*/
|
|
78
|
-
openNode = useCallback(
|
|
79
|
-
(clickedNode) => {
|
|
80
|
-
setOpenNodePath(clickedNode?.pathLocator || '');
|
|
81
|
-
setSearchValue('');
|
|
82
|
-
setHighlightedNode();
|
|
83
|
-
},
|
|
84
|
-
[tree],
|
|
85
|
-
),
|
|
86
|
-
listRef = useRef();
|
|
87
|
-
|
|
88
|
-
useEffect(() => {
|
|
89
|
-
if (!openNodePath) {
|
|
90
|
-
notifyProperty(host, 'highlightedNodePath', '');
|
|
91
|
-
notifyProperty(host, 'nodesOnNodePath', []);
|
|
92
|
-
}
|
|
93
|
-
}, [openNodePath]);
|
|
94
|
-
|
|
95
|
-
useEffect(() => {
|
|
96
|
-
if (nodePath !== undefined) {
|
|
97
|
-
host.dispatchEvent(new CustomEvent('select-node'));
|
|
98
|
-
}
|
|
99
|
-
}, [nodePath]);
|
|
100
|
-
|
|
101
|
-
useEffect(() => {
|
|
102
|
-
notifyProperty(
|
|
103
|
-
host,
|
|
104
|
-
'highlightedNodePath',
|
|
105
|
-
highlightedNode?.pathLocator || '',
|
|
106
|
-
);
|
|
107
|
-
}, [highlightedNode]);
|
|
108
|
-
|
|
109
|
-
const meta = useMeta({ dataPlane, highlightedNode, openNode });
|
|
110
|
-
|
|
111
|
-
useEffect(() => {
|
|
112
|
-
if (!opened) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const getVlist = () => {
|
|
117
|
-
const list = listRef.current,
|
|
118
|
-
vlist = list[Object.getOwnPropertySymbols(list)[0]];
|
|
119
|
-
return vlist;
|
|
120
|
-
},
|
|
121
|
-
// eslint-disable-next-line max-lines-per-function, max-statements
|
|
122
|
-
handler = (e) => {
|
|
123
|
-
if ((e.ctrlKey && e.altKey) || e.defaultPrevented) {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const {
|
|
127
|
-
dataPlane: items,
|
|
128
|
-
highlightedNode: node,
|
|
129
|
-
openNode: open,
|
|
130
|
-
} = meta,
|
|
131
|
-
vlist = getVlist(),
|
|
132
|
-
getIndex = () =>
|
|
133
|
-
items.findIndex((i) => i.pathLocator === node?.pathLocator);
|
|
134
|
-
|
|
135
|
-
switch (e.key) {
|
|
136
|
-
case 'Up':
|
|
137
|
-
case 'ArrowUp':
|
|
138
|
-
{
|
|
139
|
-
const idx = getIndex(),
|
|
140
|
-
nidx = Math.max(idx - 1, 0);
|
|
141
|
-
e.preventDefault();
|
|
142
|
-
setHighlightedNode(items[nidx]);
|
|
143
|
-
if (nidx < vlist._firstVisible) {
|
|
144
|
-
vlist.scrollToIndex = { index: nidx, position: 'start' };
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
break;
|
|
148
|
-
case 'Down':
|
|
149
|
-
case 'ArrowDown':
|
|
150
|
-
{
|
|
151
|
-
const idx = getIndex();
|
|
152
|
-
if (idx < items.length - 1) {
|
|
153
|
-
const nidx = idx + 1;
|
|
154
|
-
e.preventDefault();
|
|
155
|
-
setHighlightedNode(items[nidx]);
|
|
156
|
-
if (nidx > vlist._lastVisible) {
|
|
157
|
-
vlist.scrollToIndex = { index: nidx, position: 'end' };
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
break;
|
|
162
|
-
|
|
163
|
-
case 'Enter':
|
|
164
|
-
if (node) {
|
|
165
|
-
e.preventDefault();
|
|
166
|
-
host.dispatchEvent(new CustomEvent('node-dblclicked'));
|
|
167
|
-
}
|
|
168
|
-
break;
|
|
169
|
-
|
|
170
|
-
case 'Right':
|
|
171
|
-
case 'ArrowRight':
|
|
172
|
-
if (node && tree.hasChildren(node)) {
|
|
173
|
-
e.preventDefault();
|
|
174
|
-
open(node);
|
|
175
|
-
}
|
|
176
|
-
break;
|
|
177
|
-
default:
|
|
178
|
-
break;
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
// autoscroll on open
|
|
183
|
-
(() => {
|
|
184
|
-
getVlist().scrollToIndex = {
|
|
185
|
-
index: meta.dataPlane?.indexOf(meta.highlightedNode),
|
|
186
|
-
position: 'center',
|
|
187
|
-
};
|
|
188
|
-
})();
|
|
189
|
-
|
|
190
|
-
document.addEventListener('keydown', handler, true);
|
|
191
|
-
return () => document.removeEventListener('keydown', handler, true);
|
|
192
|
-
}, [opened, meta]);
|
|
193
|
-
|
|
194
|
-
const renderItem = (node, index) =>
|
|
195
|
-
node
|
|
196
|
-
? html` <div class="item">
|
|
197
|
-
${((parentPath) =>
|
|
198
|
-
when(
|
|
199
|
-
search &&
|
|
200
|
-
(index === 0 ||
|
|
201
|
-
parentPath !== getParentPath(tree, dataPlane[index - 1])),
|
|
202
|
-
() => html`
|
|
203
|
-
<div class="section">
|
|
204
|
-
${tree.getPathString(parentPath, tree.searchProperty)}
|
|
205
|
-
</div>
|
|
206
|
-
`,
|
|
207
|
-
))(getParentPath(tree, node))}
|
|
208
|
-
<div
|
|
209
|
-
class=${computeRowClass('node', node, highlightedNode)}
|
|
210
|
-
@click=${() => setHighlightedNode(node)}
|
|
211
|
-
@dblclick=${(e) => onNodeDblClicked(e, host)}
|
|
212
|
-
>
|
|
213
|
-
<div class="name">${node[tree.searchProperty]}</div>
|
|
214
|
-
${when(
|
|
215
|
-
tree.hasChildren(node),
|
|
216
|
-
() => html`
|
|
217
|
-
<span class="icon" @click=${() => openNode(node)}>
|
|
218
|
-
<svg
|
|
219
|
-
viewBox="0 0 24 24"
|
|
220
|
-
preserveAspectRatio="xMidYMid meet"
|
|
221
|
-
focusable="false"
|
|
222
|
-
style="pointer-events: none; display: block; width: 100%; height: 100%;"
|
|
223
|
-
>
|
|
224
|
-
<g>
|
|
225
|
-
<path
|
|
226
|
-
d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"
|
|
227
|
-
></path>
|
|
228
|
-
</g>
|
|
229
|
-
</svg>
|
|
230
|
-
</span>
|
|
231
|
-
`,
|
|
232
|
-
)}
|
|
233
|
-
</div>
|
|
234
|
-
</div>`
|
|
235
|
-
: nothing;
|
|
236
|
-
|
|
237
|
-
return html`
|
|
238
|
-
<style>
|
|
239
|
-
${styles}
|
|
240
|
-
</style>
|
|
241
|
-
<div class="header">
|
|
242
|
-
<h3 class="path">
|
|
243
|
-
<span class="icon" @click=${() => openNode()}>
|
|
244
|
-
<svg
|
|
245
|
-
viewBox="0 0 24 24"
|
|
246
|
-
preserveAspectRatio="xMidYMid meet"
|
|
247
|
-
focusable="false"
|
|
248
|
-
style="pointer-events: none; display: block; width: 100%; height: 100%;"
|
|
249
|
-
>
|
|
250
|
-
<g><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"></path></g>
|
|
251
|
-
</svg>
|
|
252
|
-
</span>
|
|
253
|
-
${guard([tree, openNodePath], () =>
|
|
254
|
-
((openNodePath && tree?.getPathNodes(openNodePath)) || []).map(
|
|
255
|
-
(node) => html`
|
|
256
|
-
<span class="slash">/</span>
|
|
257
|
-
<span class="pointer" tabindex="0" @click=${() => openNode(node)}
|
|
258
|
-
>${node[tree.searchProperty]}</span
|
|
259
|
-
>
|
|
260
|
-
`,
|
|
261
|
-
),
|
|
262
|
-
)}
|
|
263
|
-
</h3>
|
|
264
|
-
<cosmoz-input
|
|
265
|
-
tabindex="0"
|
|
266
|
-
.value=${searchValue}
|
|
267
|
-
.placeholder=${searchPlaceholder}
|
|
268
|
-
@input=${(e) => setSearchValue(e.target.value)}
|
|
269
|
-
/>
|
|
270
|
-
</div>
|
|
271
|
-
${when(
|
|
272
|
-
tree,
|
|
273
|
-
() =>
|
|
274
|
-
html` <div class="items" ${ref((el) => (listRef.current = el))}>
|
|
275
|
-
<div virtualizer-sizer></div>
|
|
276
|
-
${virtualize({
|
|
277
|
-
items: dataPlane,
|
|
278
|
-
renderItem,
|
|
279
|
-
scroller: true,
|
|
280
|
-
})}
|
|
281
|
-
</div>`,
|
|
282
|
-
)}
|
|
283
|
-
${when(
|
|
284
|
-
search && openNodePath,
|
|
285
|
-
() => html`
|
|
286
|
-
<button class="btn-ghost" @click=${() => setOpenNodePath('')}>
|
|
287
|
-
${searchGlobalPlaceholder}
|
|
288
|
-
</button>
|
|
289
|
-
`,
|
|
290
|
-
)}
|
|
291
|
-
`;
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
customElements.define(
|
|
295
|
-
'cosmoz-treenode-navigator',
|
|
296
|
-
component(TreenodeNavigator),
|
|
297
|
-
);
|
package/helpers.js
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
export const //
|
|
2
|
-
getParentPath = (tree, node) => {
|
|
3
|
-
const path = node.pathLocator || node.path,
|
|
4
|
-
pathLocatorSeparator = tree.pathLocatorSeparator;
|
|
5
|
-
return path.includes(pathLocatorSeparator)
|
|
6
|
-
? path.substring(0, path.lastIndexOf(pathLocatorSeparator))
|
|
7
|
-
: path;
|
|
8
|
-
},
|
|
9
|
-
/**
|
|
10
|
-
* Returns a node array with the children of a node on the given path
|
|
11
|
-
* If the node doesn't have children, the node gets returned
|
|
12
|
-
* @param {Tree} tree - The main tree
|
|
13
|
-
* @param {String} pathLocator - The separated address parts of a node
|
|
14
|
-
* @return {Array} - Nodes
|
|
15
|
-
*/
|
|
16
|
-
renderLevel = (tree, pathLocator) => {
|
|
17
|
-
if (!tree) {
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
const node = tree.getNodeByPathLocator(pathLocator),
|
|
21
|
-
children = tree.getChildren(node),
|
|
22
|
-
searchProperty = tree.searchProperty,
|
|
23
|
-
sortFunc = (a, b) => {
|
|
24
|
-
// First sort based on "folder" status (containing children)
|
|
25
|
-
if (tree.hasChildren(a)) {
|
|
26
|
-
if (!tree.hasChildren(b)) {
|
|
27
|
-
return -1;
|
|
28
|
-
}
|
|
29
|
-
} else if (tree.hasChildren(b)) {
|
|
30
|
-
return 1;
|
|
31
|
-
}
|
|
32
|
-
// Then sort on searchProperty
|
|
33
|
-
const val1 = a[searchProperty],
|
|
34
|
-
val2 = b[searchProperty];
|
|
35
|
-
|
|
36
|
-
if (val1 > val2) {
|
|
37
|
-
return 1;
|
|
38
|
-
}
|
|
39
|
-
if (val1 < val2) {
|
|
40
|
-
return -1;
|
|
41
|
-
}
|
|
42
|
-
return 0;
|
|
43
|
-
};
|
|
44
|
-
return children.length > 0 ? children.sort(sortFunc) : node;
|
|
45
|
-
},
|
|
46
|
-
/**
|
|
47
|
-
* Returns the found nodes based on a search string and a given tree to be searched
|
|
48
|
-
* @param {Tree} tree - The main tree
|
|
49
|
-
* @param {String|undefined} search - The search string
|
|
50
|
-
* @param {String} pathLocator - The separated address parts of a node
|
|
51
|
-
* @return {Array} - The found nodes
|
|
52
|
-
*/
|
|
53
|
-
computeDataPlane = (tree, search, pathLocator) => {
|
|
54
|
-
if (!tree) {
|
|
55
|
-
return [];
|
|
56
|
-
}
|
|
57
|
-
const nodes = renderLevel(tree, pathLocator);
|
|
58
|
-
return search ? tree.searchNodes(search, nodes, false) : nodes;
|
|
59
|
-
},
|
|
60
|
-
/**
|
|
61
|
-
* Returns the classes of a row based its selection state
|
|
62
|
-
* @param {String} classes - The default classes
|
|
63
|
-
* @param {object} node - Node to check
|
|
64
|
-
* @param {object} highlightedNode - Currently highlighted node
|
|
65
|
-
* @return {String} - The CSS classes
|
|
66
|
-
*/
|
|
67
|
-
computeRowClass = (classes, node, highlightedNode) => {
|
|
68
|
-
let selected = false;
|
|
69
|
-
if (highlightedNode) {
|
|
70
|
-
selected =
|
|
71
|
-
node === highlightedNode ||
|
|
72
|
-
(node.id && node.id === highlightedNode.id) ||
|
|
73
|
-
node.pathLocator === highlightedNode.pathLocator;
|
|
74
|
-
}
|
|
75
|
-
return selected ? classes + ' selected' : classes;
|
|
76
|
-
},
|
|
77
|
-
/**
|
|
78
|
-
* Selects the doubled clicked node and dispatches an node-dblclicked event.
|
|
79
|
-
* @param {Event} event The triggering event
|
|
80
|
-
* @param {object} host Host
|
|
81
|
-
* @return {undefined}
|
|
82
|
-
*/
|
|
83
|
-
onNodeDblClicked = (event, host) => {
|
|
84
|
-
host.dispatchEvent(
|
|
85
|
-
new CustomEvent('node-dblclicked', {
|
|
86
|
-
detail: {
|
|
87
|
-
model: event.model,
|
|
88
|
-
},
|
|
89
|
-
})
|
|
90
|
-
);
|
|
91
|
-
},
|
|
92
|
-
/**
|
|
93
|
-
* Returns the nodes on a path specified by a given path locator
|
|
94
|
-
* @param {String} pathLocator - The separated address parts of a node
|
|
95
|
-
* @param {Tree} tree - The main tree
|
|
96
|
-
* @return {Array} - The found nodes or empty array
|
|
97
|
-
*/
|
|
98
|
-
getTreePathParts = (pathLocator, tree) => {
|
|
99
|
-
if (!tree || !pathLocator) {
|
|
100
|
-
return [];
|
|
101
|
-
}
|
|
102
|
-
return tree.getPathNodes(pathLocator);
|
|
103
|
-
},
|
|
104
|
-
/**
|
|
105
|
-
* Returns a node based on a given path locator.
|
|
106
|
-
* If pathLocator is empty or not defined, null gets returned.
|
|
107
|
-
* If pathLocator is only partly valid, the last valid node gets returned.
|
|
108
|
-
* @param {String} pathLocator - The separated address parts of a node
|
|
109
|
-
* @param {Tree} tree - The main tree
|
|
110
|
-
* @return {Object} - The found node
|
|
111
|
-
*/
|
|
112
|
-
getNode = (pathLocator, tree) => {
|
|
113
|
-
if (!tree || !pathLocator) {
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const node = tree.getNodeByPathLocator(pathLocator);
|
|
118
|
-
let nodes;
|
|
119
|
-
|
|
120
|
-
if (!node) {
|
|
121
|
-
nodes = tree.getPathNodes(pathLocator).filter((n) => n != null);
|
|
122
|
-
}
|
|
123
|
-
return nodes && nodes.length > 0 ? nodes.pop() : node;
|
|
124
|
-
};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { assert, fixture, html } from '@open-wc/testing';
|
|
2
|
-
import { DefaultTree } from '@neovici/cosmoz-tree/cosmoz-default-tree';
|
|
3
|
-
import rtlData from './data/rtlTest.js';
|
|
4
|
-
import '../cosmoz-treenode-button-view';
|
|
5
|
-
|
|
6
|
-
suite('rtl', () => {
|
|
7
|
-
let treeButton;
|
|
8
|
-
|
|
9
|
-
suiteSetup(async () => {
|
|
10
|
-
treeButton = await fixture(html`<cosmoz-treenode-button-view .tree=${ new DefaultTree(rtlData) }>`);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test('button renders selected path', done => {
|
|
14
|
-
treeButton.nodePath = '1.2.3';
|
|
15
|
-
|
|
16
|
-
// Button view label depends on a binding in a cosmoz-treenode-navigator
|
|
17
|
-
// stamped asynchronously, so we need to wait a bit.
|
|
18
|
-
setTimeout(() => {
|
|
19
|
-
const buttonLabel = treeButton.shadowRoot.querySelector('.pathToNode').textContent;
|
|
20
|
-
assert.isTrue(buttonLabel.endsWith('1 / 2 / 3'));
|
|
21
|
-
done();
|
|
22
|
-
}, 500);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
/*
|
|
26
|
-
// commented out because test is unstable
|
|
27
|
-
function isIdActiveElement(id, element, idPreviouslyFound) {
|
|
28
|
-
let idFound = idPreviouslyFound || element && element.id === id;
|
|
29
|
-
|
|
30
|
-
if (element != null && element.shadowRoot != null) {
|
|
31
|
-
return isIdActiveElement(id, element.shadowRoot.activeElement, idFound);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// active element not null means that it has focus
|
|
35
|
-
return element != null && idFound;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
test('search input has focus when dialog has opened', done => {
|
|
39
|
-
treeButton.$$('.pathToNode').click();
|
|
40
|
-
Polymer.Base.async(() => {
|
|
41
|
-
// real focus can only be tested here, not valid outside test()
|
|
42
|
-
if (window.document.hasFocus()) {
|
|
43
|
-
assert.equal(isIdActiveElement('searchInput', window.document.activeElement), true);
|
|
44
|
-
}
|
|
45
|
-
if (treeButton.$.dialogTree != null) {
|
|
46
|
-
treeButton.$.dialogTree.close();
|
|
47
|
-
}
|
|
48
|
-
done();
|
|
49
|
-
}, 50);
|
|
50
|
-
});
|
|
51
|
-
*/
|
|
52
|
-
});
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { assert, fixture, html } from '@open-wc/testing';
|
|
2
|
-
import { DefaultTree } from '@neovici/cosmoz-tree/cosmoz-default-tree';
|
|
3
|
-
import basicTree from './data/basicTree.js';
|
|
4
|
-
import '../cosmoz-treenode-navigator';
|
|
5
|
-
import { computeDataPlane } from '../helpers';
|
|
6
|
-
|
|
7
|
-
suite('cosmoz-treenode-navigator', () => {
|
|
8
|
-
let navigator;
|
|
9
|
-
|
|
10
|
-
setup(async () => {
|
|
11
|
-
navigator = await fixture(html` <cosmoz-treenode-navigator
|
|
12
|
-
.tree=${new DefaultTree(basicTree)}
|
|
13
|
-
.searchPlaceholder="${'Custom search placeholder'}"
|
|
14
|
-
.searchMinLength="${2}"
|
|
15
|
-
></cosmoz-treenode-navigator>`);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test('instantiating the element', () => {
|
|
19
|
-
assert.equal(navigator.tagName, 'COSMOZ-TREENODE-NAVIGATOR');
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test('tree length and sort', () => {
|
|
23
|
-
// given a node navigator with some data
|
|
24
|
-
|
|
25
|
-
// when I enter the first node
|
|
26
|
-
navigator.openNodePath = '1000';
|
|
27
|
-
|
|
28
|
-
const dataPlane = computeDataPlane(
|
|
29
|
-
navigator.tree,
|
|
30
|
-
navigator.searchValue,
|
|
31
|
-
navigator.openNodePath
|
|
32
|
-
);
|
|
33
|
-
// then I can see the contents of the node
|
|
34
|
-
// and it is ordered folder-first, then alphabetically
|
|
35
|
-
assert.equal(dataPlane[0].name, 'Data');
|
|
36
|
-
assert.equal(dataPlane[1].name, 'Backup');
|
|
37
|
-
assert.equal(dataPlane.length, 2);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test('set proper search placeholder', () => {
|
|
41
|
-
assert.equal(
|
|
42
|
-
navigator.shadowRoot
|
|
43
|
-
.querySelector('cosmoz-input')
|
|
44
|
-
.shadowRoot.querySelector('input').placeholder,
|
|
45
|
-
'Custom search placeholder'
|
|
46
|
-
);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('should check if node has children', () => {
|
|
50
|
-
const node = {
|
|
51
|
-
name: 'D:',
|
|
52
|
-
path: '1000',
|
|
53
|
-
children: {
|
|
54
|
-
1001: {
|
|
55
|
-
name: 'Data',
|
|
56
|
-
pathLocator: '1000.1001',
|
|
57
|
-
children: { 1002: { name: 'John', pathLocator: '1000.1001.1002' } },
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
parentSectionName: 'D:',
|
|
61
|
-
pathLocator: '1000',
|
|
62
|
-
};
|
|
63
|
-
assert.equal(navigator.tree.hasChildren(node), true);
|
|
64
|
-
const node2 = {
|
|
65
|
-
name: 'Git',
|
|
66
|
-
path: '1.5.7',
|
|
67
|
-
parentSectionName: 'C:/Program Files',
|
|
68
|
-
pathLocator: '1.5.7',
|
|
69
|
-
};
|
|
70
|
-
assert.equal(navigator.tree.hasChildren(node2), false);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test('match search string', () => {
|
|
74
|
-
// given a node navigator with some data
|
|
75
|
-
// when I search for 'John'
|
|
76
|
-
navigator.searchValue = 'John';
|
|
77
|
-
|
|
78
|
-
const dataPlane = computeDataPlane(
|
|
79
|
-
navigator.tree,
|
|
80
|
-
navigator.searchValue,
|
|
81
|
-
'1000'
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
//then I can see only 1 item matching 'John'
|
|
85
|
-
assert.lengthOf(dataPlane, 1);
|
|
86
|
-
assert.equal(dataPlane[0].name, 'John');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
test('not match search string', () => {
|
|
90
|
-
// given a node navigator with some data
|
|
91
|
-
// when I search for 'NONEXISTING'
|
|
92
|
-
navigator.searchValue = 'NONEXISTING';
|
|
93
|
-
const dataPlane = computeDataPlane(
|
|
94
|
-
navigator.tree,
|
|
95
|
-
navigator.searchValue,
|
|
96
|
-
'1000'
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
//then I can see that is no contents
|
|
100
|
-
assert.lengthOf(dataPlane, 0);
|
|
101
|
-
});
|
|
102
|
-
});
|