@isopodlabs/vscode_utils 0.0.2
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 +8 -0
- package/assets/shared.css +204 -0
- package/assets/shared.js +336 -0
- package/assets/tree.css +24 -0
- package/assets/tree.js +81 -0
- package/dist/fs.d.ts +119 -0
- package/dist/fs.js +625 -0
- package/dist/icon-theme.d.ts +63 -0
- package/dist/icon-theme.js +199 -0
- package/dist/utils.d.ts +91 -0
- package/dist/utils.js +430 -0
- package/package.json +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
@font-face {
|
|
2
|
+
font-family: "codicon";
|
|
3
|
+
src: url("./codicon.ttf?9642aa1d48ab4e55aa1bf3f0b8678aa1") format("truetype");
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
html {
|
|
7
|
+
scrollbar-width: none;
|
|
8
|
+
/*user-select: none;*/
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
body {
|
|
12
|
+
font-family: var(--vscode-font-family);
|
|
13
|
+
font-size: var(--vscode-font-size);
|
|
14
|
+
font-weight: var(--vscode-font-weight);
|
|
15
|
+
color: var(--vscode-foreground);
|
|
16
|
+
--icon-color: var(--vscode-foreground);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.loading-container {
|
|
20
|
+
position: fixed;
|
|
21
|
+
top: 0;
|
|
22
|
+
left: 0;
|
|
23
|
+
width: 100%;
|
|
24
|
+
height: 100%;
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
align-items: center;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.spinner {
|
|
32
|
+
width: 40px;
|
|
33
|
+
height: 40px;
|
|
34
|
+
margin-bottom: 16px;
|
|
35
|
+
border: 4px solid var(--vscode-button-background);
|
|
36
|
+
border-top: 4px solid transparent;
|
|
37
|
+
border-radius: 50%;
|
|
38
|
+
animation: spin 1s linear infinite;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.loading-text {
|
|
42
|
+
font-family: var(--vscode-font-family);
|
|
43
|
+
font-size: 14px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@keyframes spin {
|
|
47
|
+
0% { transform: rotate(0deg); }
|
|
48
|
+
100% { transform: rotate(360deg); }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* For font icons (character in icon attribute)*/
|
|
52
|
+
[icon]::before {
|
|
53
|
+
content: attr(icon);
|
|
54
|
+
font: normal normal normal 16px/1 codicon;
|
|
55
|
+
display: inline-block;
|
|
56
|
+
color: var(--icon-color);
|
|
57
|
+
text-decoration: none;
|
|
58
|
+
text-rendering: auto;
|
|
59
|
+
text-align: center;
|
|
60
|
+
vertical-align: text-top;
|
|
61
|
+
-webkit-font-smoothing: antialiased;
|
|
62
|
+
-moz-osx-font-smoothing: grayscale;
|
|
63
|
+
user-select: none;
|
|
64
|
+
-webkit-user-select: none;
|
|
65
|
+
-ms-user-select: none;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* For img icons (img in --icon)*/
|
|
69
|
+
.icon::before {
|
|
70
|
+
content: '';
|
|
71
|
+
display: inline-block;
|
|
72
|
+
text-decoration: none;
|
|
73
|
+
width: 16px;
|
|
74
|
+
height: 16px;
|
|
75
|
+
background-image: var(--icon);
|
|
76
|
+
margin-right: 5px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.codicon {
|
|
80
|
+
font: normal normal normal 16px/1 codicon;
|
|
81
|
+
display: inline-block;
|
|
82
|
+
text-decoration: none;
|
|
83
|
+
text-rendering: auto;
|
|
84
|
+
text-align: center;
|
|
85
|
+
vertical-align: text-top;
|
|
86
|
+
-webkit-font-smoothing: antialiased;
|
|
87
|
+
-moz-osx-font-smoothing: grayscale;
|
|
88
|
+
user-select: none;
|
|
89
|
+
-webkit-user-select: none;
|
|
90
|
+
-ms-user-select: none;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
button[icon] {
|
|
94
|
+
border: none;
|
|
95
|
+
background-color: transparent;
|
|
96
|
+
padding: 0;
|
|
97
|
+
cursor: pointer;
|
|
98
|
+
color: var(--vscode-icon-foreground);
|
|
99
|
+
|
|
100
|
+
&:hover {
|
|
101
|
+
background-color: var(--vscode-list-hoverBackground);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
button {
|
|
106
|
+
color: var(--vscode-button-foreground);
|
|
107
|
+
background-color: var(--vscode-button-background);
|
|
108
|
+
border: 1px solid var(--vscode-button-border, transparent);
|
|
109
|
+
border-radius: 2px;
|
|
110
|
+
padding: 4px 8px;
|
|
111
|
+
cursor: pointer;
|
|
112
|
+
&:hover {
|
|
113
|
+
background-color: var(--vscode-button-hoverBackground);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
button.codicon {
|
|
118
|
+
border: none;
|
|
119
|
+
background-color: transparent;
|
|
120
|
+
padding: 0;
|
|
121
|
+
cursor: pointer;
|
|
122
|
+
color: var(--vscode-icon-foreground);
|
|
123
|
+
&:hover {
|
|
124
|
+
opacity: 0.8;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.select {
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
width: fit-content;
|
|
131
|
+
&:hover {
|
|
132
|
+
text-decoration: underline;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.selected {
|
|
137
|
+
background-color: var(--vscode-editor-selectionBackground);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Splitter */
|
|
141
|
+
|
|
142
|
+
.splitter {
|
|
143
|
+
position: relative;
|
|
144
|
+
width: 5px;
|
|
145
|
+
flex: none;
|
|
146
|
+
cursor:ew-resize;
|
|
147
|
+
|
|
148
|
+
&::before {
|
|
149
|
+
content: '';
|
|
150
|
+
position: absolute;
|
|
151
|
+
top: 0;
|
|
152
|
+
bottom: 0;
|
|
153
|
+
left: 2px;
|
|
154
|
+
width: 1px;
|
|
155
|
+
height: 100%;
|
|
156
|
+
background-color: var(--vscode-editorGroup-border);
|
|
157
|
+
transition: background-color 0.3s;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
&:hover::before {
|
|
161
|
+
left: 0;
|
|
162
|
+
width: 100%;
|
|
163
|
+
background-color: var(--vscode-sash-hoverBorder);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* Scrollbar */
|
|
168
|
+
|
|
169
|
+
.vscrollbar, .hscrollbar {
|
|
170
|
+
position: fixed;
|
|
171
|
+
z-index: 20;
|
|
172
|
+
background: var(--vscode-scrollbarSlider-background);
|
|
173
|
+
|
|
174
|
+
opacity: 0;
|
|
175
|
+
transition: opacity .8s linear;
|
|
176
|
+
|
|
177
|
+
html:hover &, .resizing & {
|
|
178
|
+
opacity: 1;
|
|
179
|
+
transition: opacity .1s linear;
|
|
180
|
+
|
|
181
|
+
&:hover {
|
|
182
|
+
background: var(--vscode-scrollbarSlider-hoverBackground);
|
|
183
|
+
}
|
|
184
|
+
&.active {
|
|
185
|
+
background: var(--vscode-scrollbarSlider-activeBackground)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
&.invisible {
|
|
189
|
+
opacity: 0;
|
|
190
|
+
transition: opacity .8s linear;
|
|
191
|
+
pointer-events: none;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.vscrollbar {
|
|
197
|
+
right: 0;
|
|
198
|
+
width: 14px;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.hscrollbar {
|
|
202
|
+
bottom: 0;
|
|
203
|
+
height: 14px;
|
|
204
|
+
}
|
package/assets/shared.js
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
const vscode = acquireVsCodeApi();
|
|
2
|
+
|
|
3
|
+
//fix up icons in attributes
|
|
4
|
+
document.querySelectorAll('[icon]').forEach(element => {
|
|
5
|
+
const value = element.getAttribute('icon');
|
|
6
|
+
if (value.includes('/')) {
|
|
7
|
+
element.removeAttribute('icon');
|
|
8
|
+
element.classList.add('icon');
|
|
9
|
+
element.style.setProperty('--icon', `url(${value})`);
|
|
10
|
+
}
|
|
11
|
+
const col = element.getAttribute('color');
|
|
12
|
+
if (col) {
|
|
13
|
+
element.removeAttribute('color');
|
|
14
|
+
element.style.setProperty('--icon-color', col);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
document.querySelectorAll('.select').forEach(item => {
|
|
20
|
+
item.addEventListener('click', event => {
|
|
21
|
+
if (event.target === item) {
|
|
22
|
+
vscode.postMessage({
|
|
23
|
+
command: 'select',
|
|
24
|
+
selector: generateSelector(item),
|
|
25
|
+
text: item.textContent,
|
|
26
|
+
...item.dataset
|
|
27
|
+
});
|
|
28
|
+
event.stopPropagation();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
function createElement(tag, options) {
|
|
34
|
+
const e = document.createElement(tag);
|
|
35
|
+
if (options) {
|
|
36
|
+
for (const [k,v] of Object.entries(options))
|
|
37
|
+
e[k] = v;
|
|
38
|
+
}
|
|
39
|
+
return e;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getFirstText(element) {
|
|
43
|
+
for (const node of element.childNodes) {
|
|
44
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
45
|
+
const text = node.textContent.trim();
|
|
46
|
+
if (text)
|
|
47
|
+
return text;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
class Pool {
|
|
53
|
+
pool = [];
|
|
54
|
+
constructor(make) { this.make = make; }
|
|
55
|
+
|
|
56
|
+
get() {
|
|
57
|
+
if (this.pool.length === 0)
|
|
58
|
+
this.pool.push(this.make());
|
|
59
|
+
|
|
60
|
+
return this.pool.length === 1
|
|
61
|
+
? this.pool[0].cloneNode(true)
|
|
62
|
+
: this.pool.pop();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
discard(item) {
|
|
66
|
+
this.pool.push(item);
|
|
67
|
+
}
|
|
68
|
+
discardElement(item) {
|
|
69
|
+
this.discard(item);
|
|
70
|
+
item.remove();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
//-------------------------------------
|
|
76
|
+
// splitter
|
|
77
|
+
//-------------------------------------
|
|
78
|
+
|
|
79
|
+
class Splitter {
|
|
80
|
+
splitter;
|
|
81
|
+
|
|
82
|
+
constructor(splitter, notify) {
|
|
83
|
+
this.splitter = splitter;
|
|
84
|
+
|
|
85
|
+
splitter.addEventListener('pointerdown', e => {
|
|
86
|
+
e.preventDefault();
|
|
87
|
+
splitter.setPointerCapture(e.pointerId);
|
|
88
|
+
|
|
89
|
+
const left = splitter.previousSibling;
|
|
90
|
+
const style = getComputedStyle(left);
|
|
91
|
+
let split = left.clientWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight);
|
|
92
|
+
const offset = split - e.clientX;
|
|
93
|
+
|
|
94
|
+
const min = parseFloat(style.minWidth);
|
|
95
|
+
const max = Math.min(parseFloat(style.maxWidth), splitter.parentNode.clientWidth - 300);
|
|
96
|
+
|
|
97
|
+
left.style.width = `${split}px`;
|
|
98
|
+
left.style.flex = 'none';
|
|
99
|
+
|
|
100
|
+
function resizePanels(e) {
|
|
101
|
+
split = Math.min(Math.max(e.clientX + offset, min), max);
|
|
102
|
+
left.style.width = `${split}px`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function stopResizing(e) {
|
|
106
|
+
notify(split);
|
|
107
|
+
//state.split = split;
|
|
108
|
+
//vscode.setState(state);
|
|
109
|
+
|
|
110
|
+
splitter.releasePointerCapture(e.pointerId);
|
|
111
|
+
document.removeEventListener('pointermove', resizePanels);
|
|
112
|
+
document.removeEventListener('pointerup', stopResizing);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
document.addEventListener('pointermove', resizePanels);
|
|
116
|
+
document.addEventListener('pointerup', stopResizing);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
set(x) {
|
|
121
|
+
const left = this.splitter.previousSibling;
|
|
122
|
+
left.style.width = `${x}px`;
|
|
123
|
+
left.style.flex = 'none';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
//-------------------------------------
|
|
129
|
+
// Scrollbar
|
|
130
|
+
//-------------------------------------
|
|
131
|
+
|
|
132
|
+
/*
|
|
133
|
+
interface Container {
|
|
134
|
+
clientOffset: number; //pixel offset for top of track
|
|
135
|
+
clientPixels: number; //pixel size of track
|
|
136
|
+
clientSize: number; //unit size of visible region
|
|
137
|
+
scrollOffset: number; //scroll position in units
|
|
138
|
+
scrollSize: number; //size of overall region in units
|
|
139
|
+
setScroll(x: number);//set scroll position in units
|
|
140
|
+
}
|
|
141
|
+
*/
|
|
142
|
+
|
|
143
|
+
function VScrollContainer(container, offset = 0) {
|
|
144
|
+
return {
|
|
145
|
+
clientOffset: Math.max(container.clientTop, 0) + offset,
|
|
146
|
+
get clientPixels() { return container.clientHeight - offset; },
|
|
147
|
+
get clientSize() { return container.clientHeight - offset; },
|
|
148
|
+
get scrollOffset() { return container.scrollTop; },
|
|
149
|
+
get scrollSize() { return container.scrollHeight; },
|
|
150
|
+
setScroll(x) { container.scrollTop = x; },
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function HScrollContainer(container, offset = 0) {
|
|
155
|
+
return {
|
|
156
|
+
clientOffset: Math.max(container.clientLeft, 0) + offset,
|
|
157
|
+
get clientPixels() { return container.clientWidth - offset; },
|
|
158
|
+
get clientSize() { return container.clientWidth - offset; },
|
|
159
|
+
get scrollOffset() { return container.scrollLeft; },
|
|
160
|
+
get scrollSize() { return container.scrollWidth; },
|
|
161
|
+
setScroll(x) { container.scrollLeft = x; },
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
class ScrollBar {
|
|
166
|
+
thumbSize;
|
|
167
|
+
|
|
168
|
+
constructor(parent, container, horizontal) {
|
|
169
|
+
if (container instanceof HTMLElement) {
|
|
170
|
+
container = horizontal ? HScrollContainer(container) : VScrollContainer(container);
|
|
171
|
+
}
|
|
172
|
+
const thumb = createElement('div', {className: horizontal ? 'hscrollbar' : 'vscrollbar'});
|
|
173
|
+
parent.appendChild(thumb);
|
|
174
|
+
|
|
175
|
+
this.thumb = thumb;
|
|
176
|
+
this.container = container;
|
|
177
|
+
this.horizontal = horizontal;
|
|
178
|
+
this.update();
|
|
179
|
+
|
|
180
|
+
thumb.addEventListener("lostpointercapture", e => {
|
|
181
|
+
if (thumb.onMouseUp)
|
|
182
|
+
thumb.onMouseUp(e);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
thumb.addEventListener('pointerdown', event => {
|
|
186
|
+
console.log('down');
|
|
187
|
+
const pointerOffset = horizontal ? thumb.offsetLeft - event.clientX : thumb.offsetTop - event.clientY;
|
|
188
|
+
thumb.classList.add('active');
|
|
189
|
+
|
|
190
|
+
const onPointerMove = event => {
|
|
191
|
+
this.setThumbPixel(pointerOffset + (horizontal ? event.clientX : event.clientY));
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const onPointerUp = () => {
|
|
195
|
+
console.log('up');
|
|
196
|
+
thumb.classList.remove('active');
|
|
197
|
+
window.removeEventListener('pointermove', onPointerMove);
|
|
198
|
+
window.removeEventListener('pointerup', onPointerUp);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
if (thumb.setPointerCapture)
|
|
202
|
+
thumb.setPointerCapture(event.pointerId);
|
|
203
|
+
|
|
204
|
+
window.addEventListener('pointermove', onPointerMove);
|
|
205
|
+
window.addEventListener('pointerup', onPointerUp);
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
update() {
|
|
210
|
+
this.setThumb(this.container.scrollOffset);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
setScroll(scroll) {
|
|
214
|
+
this.container.setScroll(scroll);
|
|
215
|
+
this.setThumb(scroll);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
setThumbSize(size) {
|
|
219
|
+
if (size != this.thumbSize) {
|
|
220
|
+
this.thumbSize = size;
|
|
221
|
+
if (this.horizontal)
|
|
222
|
+
this.thumb.style.width = `${size}px`;
|
|
223
|
+
else
|
|
224
|
+
this.thumb.style.height = `${size}px`;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
setThumb(scroll) {
|
|
229
|
+
const clientPixels = this.container.clientPixels;
|
|
230
|
+
const clientSize = this.container.clientSize;
|
|
231
|
+
const scrollSize = this.container.scrollSize;
|
|
232
|
+
const clientOffset = this.container.clientOffset;
|
|
233
|
+
let thumbPos, thumbSize;
|
|
234
|
+
|
|
235
|
+
if (clientSize >= scrollSize) {
|
|
236
|
+
this.thumb.classList.add('invisible');
|
|
237
|
+
thumbSize = scrollSize;
|
|
238
|
+
thumbPos = clientOffset;
|
|
239
|
+
} else {
|
|
240
|
+
this.thumb.classList.remove('invisible');
|
|
241
|
+
thumbSize = Math.max(clientPixels * clientSize / scrollSize, 20);
|
|
242
|
+
thumbPos = clientOffset + scroll * (clientPixels - thumbSize) / (scrollSize - clientSize);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
this.setThumbSize(thumbSize);
|
|
246
|
+
|
|
247
|
+
if (this.horizontal)
|
|
248
|
+
this.thumb.style.left = `${thumbPos}px`;
|
|
249
|
+
else
|
|
250
|
+
this.thumb.style.top = `${thumbPos}px`;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
setThumbPixel(pos) {
|
|
254
|
+
const clientPixels = this.container.clientPixels;
|
|
255
|
+
const clientSize = this.container.clientSize;
|
|
256
|
+
const scrollSize = this.container.scrollSize;
|
|
257
|
+
const clientOffset = this.container.clientOffset;
|
|
258
|
+
const thumbPos = Math.min(Math.max(pos, clientOffset), clientOffset + clientPixels - this.thumbSize);
|
|
259
|
+
const scroll = (thumbPos - clientOffset) * (scrollSize - clientSize) / (clientPixels - this.thumbSize);
|
|
260
|
+
|
|
261
|
+
this.container.setScroll(scroll);
|
|
262
|
+
if (this.horizontal) {
|
|
263
|
+
this.thumb.style.left = `${thumbPos}px`;
|
|
264
|
+
} else {
|
|
265
|
+
this.thumb.style.top = `${thumbPos}px`;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
let resizeTimeout;
|
|
271
|
+
|
|
272
|
+
window.addEventListener('resize', () => {
|
|
273
|
+
document.documentElement.classList.add('resizing');
|
|
274
|
+
clearTimeout(resizeTimeout);
|
|
275
|
+
resizeTimeout = setTimeout(() => document.documentElement.classList.remove('resizing'), 500);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
//-------------------------------------
|
|
280
|
+
// template
|
|
281
|
+
//-------------------------------------
|
|
282
|
+
|
|
283
|
+
function replace(text, re, process) {
|
|
284
|
+
let i = 0;
|
|
285
|
+
let result = '';
|
|
286
|
+
for (let m; (m = re.exec(text)); i = re.lastIndex)
|
|
287
|
+
result += text.substring(i, m.index) + process(m);
|
|
288
|
+
return result + text.substring(i);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function replace_in_element(e, re, process) {
|
|
292
|
+
if (e.id)
|
|
293
|
+
e.id = replace(e.id, re, process);
|
|
294
|
+
if (e.attributes.name)
|
|
295
|
+
e.attributes.name.value = replace(e.attributes.name.value, re, process);
|
|
296
|
+
const childNodes = e.childNodes;
|
|
297
|
+
for (let i = 0; i < childNodes.length; i++) {
|
|
298
|
+
const node = childNodes[i];
|
|
299
|
+
if (node.nodeType === window.Node.TEXT_NODE)
|
|
300
|
+
node.textContent = replace(node.textContent, re, process);
|
|
301
|
+
else if (node.nodeType === window.Node.ELEMENT_NODE)
|
|
302
|
+
replace_in_element(node, re, process);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function template(template, parent, values) {
|
|
307
|
+
const newnodes = values.map(i => {
|
|
308
|
+
const child = template.cloneNode(true);
|
|
309
|
+
child.hidden = false;
|
|
310
|
+
replace_in_element(child, /\$\((.*)\)/g, m => i[m[1]]);
|
|
311
|
+
return child;
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// const parent = after.parentNode;
|
|
315
|
+
// const before = after.nextSibling;
|
|
316
|
+
const before = null;
|
|
317
|
+
for (const i of newnodes)
|
|
318
|
+
parent.insertBefore(i, before);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function generateSelector(e) {
|
|
322
|
+
const path = [];
|
|
323
|
+
while (e && e.nodeType === Node.ELEMENT_NODE) {
|
|
324
|
+
let index = 1;
|
|
325
|
+
for (let s = e; (s = s.previousElementSibling);) {
|
|
326
|
+
if (s.tagName === e.tagName)
|
|
327
|
+
index++;
|
|
328
|
+
}
|
|
329
|
+
//const selector = e.tagName.toLowerCase() + (index > 1 ? `:nth-of-type(${index})` : '');
|
|
330
|
+
const selector = `${e.tagName.toLowerCase()}:nth-of-type(${index})`;
|
|
331
|
+
path.unshift(selector);
|
|
332
|
+
e = e.parentNode;
|
|
333
|
+
}
|
|
334
|
+
return path.join(' > ');
|
|
335
|
+
}
|
|
336
|
+
|
package/assets/tree.css
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.caret {
|
|
2
|
+
&::before {
|
|
3
|
+
font-family: 'codicon';
|
|
4
|
+
content: '\eab6';
|
|
5
|
+
margin-right: 6px;
|
|
6
|
+
pointer-events: auto;
|
|
7
|
+
cursor: pointer;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
&.caret-down::before {
|
|
11
|
+
content: '\eab4';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
&:has(> span:first-child > .codicon) > .children {
|
|
15
|
+
padding-left: 32px;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
&:not(.caret-down) div {
|
|
19
|
+
display: none;
|
|
20
|
+
}
|
|
21
|
+
&:not(.caret-down) ul {
|
|
22
|
+
display: none;
|
|
23
|
+
}
|
|
24
|
+
}
|
package/assets/tree.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
class Tree {
|
|
2
|
+
root;
|
|
3
|
+
|
|
4
|
+
constructor(root, notify) {
|
|
5
|
+
this.root = root;
|
|
6
|
+
|
|
7
|
+
root.querySelectorAll('.caret').forEach(caret => {
|
|
8
|
+
caret.addEventListener('click', event => {
|
|
9
|
+
if (event.target === caret) {
|
|
10
|
+
caret.classList.toggle('caret-down');
|
|
11
|
+
notify(caret, caret.classList.contains('caret-down'));
|
|
12
|
+
event.stopPropagation();
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
open(element) {
|
|
19
|
+
element?.classList.add('caret-down');
|
|
20
|
+
}
|
|
21
|
+
close(element) {
|
|
22
|
+
element?.classList.remove('caret-down');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
close_all() {
|
|
26
|
+
this.root.querySelectorAll('.caret-down').forEach(e => e.classList.remove('caret-down'));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
all_open() {
|
|
30
|
+
return Array.from(this.root.querySelectorAll('.caret-down'), element => generateSelector(element));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
reveal(element) {
|
|
34
|
+
if (element) {
|
|
35
|
+
for (let parent = element.parentNode; parent; parent = parent.parentNode) {
|
|
36
|
+
if (parent.classList?.contains('caret'))
|
|
37
|
+
parent.classList.add('caret-down');
|
|
38
|
+
}
|
|
39
|
+
element.scrollIntoView({behavior: 'smooth', block: 'center'});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
lastStuck() {
|
|
44
|
+
return lastStuck(this.root);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function lastStuck(tree) {
|
|
49
|
+
const x = tree.clientWidth - 20;
|
|
50
|
+
let y = 5;
|
|
51
|
+
|
|
52
|
+
let last_stuck;
|
|
53
|
+
for(;;) {
|
|
54
|
+
const e = document.elementFromPoint(x, y);
|
|
55
|
+
if (!e || getComputedStyle(e).getPropertyValue('position') != 'sticky')
|
|
56
|
+
break;
|
|
57
|
+
|
|
58
|
+
const bottom = e.getBoundingClientRect().bottom;
|
|
59
|
+
if (e.nextElementSibling.getBoundingClientRect().top >= bottom)
|
|
60
|
+
break;
|
|
61
|
+
|
|
62
|
+
last_stuck = e;
|
|
63
|
+
y = bottom + 5;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return last_stuck;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let prev_stuck;
|
|
70
|
+
function updateStuck() {
|
|
71
|
+
const last_stuck = lastStuck(document.querySelector('.tree'));
|
|
72
|
+
if (last_stuck !== prev_stuck) {
|
|
73
|
+
if (prev_stuck)
|
|
74
|
+
prev_stuck.classList.remove('stuck');
|
|
75
|
+
|
|
76
|
+
if (last_stuck)
|
|
77
|
+
last_stuck.classList.add('stuck');
|
|
78
|
+
|
|
79
|
+
prev_stuck = last_stuck;
|
|
80
|
+
}
|
|
81
|
+
}
|