pywebexec 1.2.7__py3-none-any.whl → 1.2.8__py3-none-any.whl
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.
- pywebexec/static/css/style.css +3 -2
- pywebexec/static/js/commands.js +96 -74
- pywebexec/static/js/script.js +2 -0
- pywebexec/templates/index.html +1 -1
- pywebexec/version.py +2 -2
- {pywebexec-1.2.7.dist-info → pywebexec-1.2.8.dist-info}/METADATA +1 -1
- {pywebexec-1.2.7.dist-info → pywebexec-1.2.8.dist-info}/RECORD +11 -11
- {pywebexec-1.2.7.dist-info → pywebexec-1.2.8.dist-info}/LICENSE +0 -0
- {pywebexec-1.2.7.dist-info → pywebexec-1.2.8.dist-info}/WHEEL +0 -0
- {pywebexec-1.2.7.dist-info → pywebexec-1.2.8.dist-info}/entry_points.txt +0 -0
- {pywebexec-1.2.7.dist-info → pywebexec-1.2.8.dist-info}/top_level.txt +0 -0
pywebexec/static/css/style.css
CHANGED
@@ -34,6 +34,8 @@ select { /* Safari bug */
|
|
34
34
|
font-size: 15px;
|
35
35
|
border: #aaa solid 1px;
|
36
36
|
border-radius: 5px;
|
37
|
+
padding: 0px 5px 5px 0px;
|
38
|
+
min-width: 150px;
|
37
39
|
}
|
38
40
|
.output {
|
39
41
|
white-space: pre-wrap;
|
@@ -178,7 +180,6 @@ form {
|
|
178
180
|
border: 1px solid #aaa;
|
179
181
|
border-radius: 5px;
|
180
182
|
padding: 0px 5px 0px 5px;
|
181
|
-
max-height: 300px;
|
182
183
|
overflow-y: auto;
|
183
184
|
z-index: 1000;
|
184
185
|
}
|
@@ -188,7 +189,7 @@ form {
|
|
188
189
|
cursor: pointer;
|
189
190
|
}
|
190
191
|
|
191
|
-
.command-item:hover {
|
192
|
+
.command-item:hover, .command-item.highlighted {
|
192
193
|
background-color: #eee;
|
193
194
|
}
|
194
195
|
|
pywebexec/static/js/commands.js
CHANGED
@@ -1,43 +1,41 @@
|
|
1
1
|
// commands.js
|
2
2
|
let commandInput = document.getElementById('commandName');
|
3
3
|
let paramsInput = document.getElementById('params');
|
4
|
-
let
|
4
|
+
let commandListSelect = document.getElementById('commandList');
|
5
5
|
let showCommandListButton = document.getElementById('showCommandListButton');
|
6
|
+
let isHandlingKeydown = false;
|
6
7
|
|
7
8
|
function unfilterCommands() {
|
8
|
-
const
|
9
|
-
|
10
|
-
|
11
|
-
}
|
12
|
-
|
9
|
+
const options = commandListSelect.options;
|
10
|
+
for (let i = 0; i < options.length; i++) {
|
11
|
+
options[i].style.display = 'block';
|
12
|
+
}
|
13
|
+
commandListSelect.size = Math.min(20, commandListSelect.options.length);
|
13
14
|
}
|
14
15
|
|
15
16
|
function filterCommands() {
|
16
|
-
const value = commandInput.value;
|
17
|
-
const
|
18
|
-
let
|
19
|
-
|
20
|
-
if (
|
21
|
-
|
22
|
-
|
17
|
+
const value = commandInput.value.slice(0, commandInput.selectionStart);
|
18
|
+
const options = commandListSelect.options;
|
19
|
+
let nbVisibleItems = 0;
|
20
|
+
for (let i = 0; i < options.length; i++) {
|
21
|
+
if (options[i].text.startsWith(value)) {
|
22
|
+
options[i].style.display = 'block';
|
23
|
+
nbVisibleItems += 1;
|
23
24
|
} else {
|
24
|
-
|
25
|
+
options[i].style.display = 'none';
|
25
26
|
}
|
26
|
-
}
|
27
|
-
|
28
|
-
|
29
|
-
commandListDiv.classList.add('show');
|
27
|
+
}
|
28
|
+
if (nbVisibleItems>1) {
|
29
|
+
commandListSelect.size = Math.min(20, nbVisibleItems);
|
30
30
|
} else {
|
31
|
-
|
31
|
+
commandListSelect.style.display = 'none';
|
32
32
|
}
|
33
|
-
adjustCommandListWidth(); // Adjust width after filtering commands
|
34
33
|
}
|
35
34
|
|
36
35
|
function setCommandListPosition() {
|
37
36
|
const rect = commandInput.getBoundingClientRect();
|
38
|
-
|
39
|
-
|
40
|
-
commandListDiv.style.minWidth = `${rect.width}px`;
|
37
|
+
commandListSelect.style.left = `${rect.left}px`;
|
38
|
+
commandListSelect.style.top = `${rect.bottom}px`;
|
41
39
|
}
|
42
40
|
|
43
41
|
function adjustInputWidth(input) {
|
@@ -45,20 +43,6 @@ function adjustInputWidth(input) {
|
|
45
43
|
input.style.width = `${input.scrollWidth}px`;
|
46
44
|
}
|
47
45
|
|
48
|
-
function adjustCommandListWidth() {
|
49
|
-
commandListDiv.style.width = 'auto'; // Reset width before recalculating
|
50
|
-
const items = Array.from(commandListDiv.getElementsByClassName('command-item'));
|
51
|
-
let maxWidth = 0;
|
52
|
-
items.forEach(item => {
|
53
|
-
if (item.style.display !== 'none') {
|
54
|
-
const itemWidth = item.scrollWidth;
|
55
|
-
if (itemWidth > maxWidth) {
|
56
|
-
maxWidth = itemWidth;
|
57
|
-
}
|
58
|
-
}
|
59
|
-
});
|
60
|
-
commandListDiv.style.width = `${maxWidth}px`;
|
61
|
-
}
|
62
46
|
|
63
47
|
paramsInput.addEventListener('input', () => adjustInputWidth(paramsInput));
|
64
48
|
commandInput.addEventListener('input', () => {
|
@@ -83,12 +67,12 @@ commandInput.addEventListener('input', (event) => {
|
|
83
67
|
commandInput.setSelectionRange(newValue.length, newValue.length);
|
84
68
|
}
|
85
69
|
const value = commandInput.value;
|
86
|
-
const
|
70
|
+
const options = commandListSelect.options;
|
87
71
|
if (value) {
|
88
|
-
const match =
|
72
|
+
const match = Array.from(options).find(option => option.text.startsWith(value));
|
89
73
|
if (match) {
|
90
|
-
commandInput.value = match.
|
91
|
-
commandInput.setSelectionRange(value.length, match.
|
74
|
+
commandInput.value = match.text;
|
75
|
+
commandInput.setSelectionRange(value.length, match.text.length);
|
92
76
|
} else {
|
93
77
|
commandInput.value = value.slice(0, -1);
|
94
78
|
}
|
@@ -97,47 +81,92 @@ commandInput.addEventListener('input', (event) => {
|
|
97
81
|
adjustInputWidth(commandInput); // Adjust width on input
|
98
82
|
});
|
99
83
|
|
100
|
-
commandInput.addEventListener('click', () => {
|
101
|
-
setCommandListPosition();
|
102
|
-
commandListDiv.style.display = 'block';
|
103
|
-
filterCommands();
|
104
|
-
});
|
105
|
-
|
106
84
|
commandInput.addEventListener('keydown', (event) => {
|
107
|
-
if (event.key === '
|
108
|
-
|
109
|
-
|
85
|
+
if (event.key === ' ' || event.key === 'ArrowRight') {
|
86
|
+
event.preventDefault();
|
87
|
+
paramsInput.focus();
|
88
|
+
paramsInput.setSelectionRange(0, paramsInput.value.length);
|
89
|
+
} else if (event.key === 'ArrowDown') {
|
90
|
+
/*setCommandListPosition();*/
|
110
91
|
unfilterCommands();
|
92
|
+
commandListSelect.style.display = 'block';
|
93
|
+
commandListSelect.focus();
|
94
|
+
commandListSelect.selectedIndex = 0;
|
95
|
+
event.preventDefault();
|
96
|
+
}
|
97
|
+
});
|
98
|
+
|
99
|
+
paramsInput.addEventListener('keydown', (event) => {
|
100
|
+
if (event.key === 'ArrowLeft' && paramsInput.selectionStart === 0) {
|
101
|
+
commandInput.focus();
|
102
|
+
commandInput.setSelectionRange(0, commandInput.value.length);
|
103
|
+
event.preventDefault();
|
104
|
+
}
|
105
|
+
});
|
106
|
+
|
107
|
+
commandListSelect.addEventListener('keydown', (event) => {
|
108
|
+
if (event.key === 'Enter') {
|
109
|
+
event.preventDefault(); // Prevent form submission
|
110
|
+
const selectedOption = commandListSelect.options[commandListSelect.selectedIndex];
|
111
|
+
commandInput.value = selectedOption.text;
|
112
|
+
commandListSelect.style.display = 'none';
|
113
|
+
adjustInputWidth(commandInput);
|
114
|
+
paramsInput.focus();
|
115
|
+
return;
|
111
116
|
}
|
117
|
+
if (event.key === 'ArrowUp' && commandListSelect.selectedIndex == 0) {
|
118
|
+
commandInput.focus();
|
119
|
+
commandListSelect.style.display = 'none'
|
120
|
+
}
|
121
|
+
});
|
122
|
+
|
123
|
+
commandListSelect.addEventListener('click', (event) => {
|
124
|
+
event.preventDefault(); // Prevent form submission
|
125
|
+
const selectedOption = commandListSelect.options[commandListSelect.selectedIndex];
|
126
|
+
commandInput.value = selectedOption.text;
|
127
|
+
commandListSelect.style.display = 'none';
|
128
|
+
adjustInputWidth(commandInput);
|
129
|
+
paramsInput.focus();
|
130
|
+
});
|
131
|
+
|
132
|
+
|
133
|
+
commandInput.addEventListener('click', () => {
|
134
|
+
setCommandListPosition();
|
135
|
+
if (commandListSelect.style.display == 'none')
|
136
|
+
commandListSelect.style.display = 'block';
|
137
|
+
else
|
138
|
+
commandListSelect.style.display = 'none';
|
139
|
+
filterCommands();
|
112
140
|
});
|
113
141
|
|
114
142
|
commandInput.addEventListener('blur', (event) => {
|
115
|
-
if (event.relatedTarget === showCommandListButton) {
|
143
|
+
if (event.relatedTarget === showCommandListButton || event.relatedTarget === commandListSelect) {
|
116
144
|
event.preventDefault();
|
117
145
|
return;
|
118
146
|
}
|
119
|
-
|
120
|
-
commandListDiv.classList.remove('show');
|
147
|
+
commandListSelect.style.display = 'none';
|
121
148
|
adjustInputWidth(commandInput);
|
122
149
|
});
|
123
150
|
|
124
|
-
showCommandListButton.addEventListener('
|
151
|
+
showCommandListButton.addEventListener('click', (event) => {
|
125
152
|
event.preventDefault();
|
126
153
|
setCommandListPosition();
|
127
|
-
|
154
|
+
if (commandListSelect.style.display == 'none')
|
155
|
+
commandListSelect.style.display = 'block';
|
156
|
+
else
|
157
|
+
commandListSelect.style.display = 'none';
|
128
158
|
unfilterCommands();
|
129
159
|
});
|
130
160
|
|
131
161
|
window.addEventListener('click', (event) => {
|
132
|
-
if (!commandInput.contains(event.target) && !
|
133
|
-
|
134
|
-
commandListDiv.classList.remove('show');
|
135
|
-
adjustInputWidth(commandInput);
|
162
|
+
if (!commandInput.contains(event.target) && !commandListSelect.contains(event.target) && !showCommandListButton.contains(event.target)) {
|
163
|
+
commandListSelect.style.display = 'none';
|
136
164
|
}
|
137
165
|
});
|
138
166
|
|
139
167
|
window.addEventListener('keydown', (event) => {
|
140
|
-
if (document.activeElement
|
168
|
+
if ([commandInput, paramsInput, commandListSelect].includes(document.activeElement)) return;
|
169
|
+
if (event.code === `Key${event.key.toUpperCase()}`) {
|
141
170
|
commandInput.focus();
|
142
171
|
commandInput.dispatchEvent(new KeyboardEvent('keydown', event));
|
143
172
|
}
|
@@ -161,23 +190,16 @@ async function fetchExecutables() {
|
|
161
190
|
throw new Error('Failed to fetch command status');
|
162
191
|
}
|
163
192
|
const executables = await response.json();
|
164
|
-
|
193
|
+
commandListSelect.innerHTML = '';
|
165
194
|
executables.forEach(executable => {
|
166
|
-
const
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
commandInput.value = executable;
|
171
|
-
commandListDiv.style.display = 'none';
|
172
|
-
commandListDiv.classList.remove('show');
|
173
|
-
adjustInputWidth(commandInput);
|
174
|
-
paramsInput.focus();
|
175
|
-
});
|
176
|
-
commandListDiv.appendChild(div);
|
195
|
+
const option = document.createElement('option');
|
196
|
+
option.className = 'command-item';
|
197
|
+
option.text = executable;
|
198
|
+
commandListSelect.appendChild(option);
|
177
199
|
});
|
178
|
-
// Ensure the elements are rendered before measuring their widths
|
179
|
-
requestAnimationFrame(adjustCommandListWidth);
|
180
200
|
} catch (error) {
|
181
201
|
alert("Failed to fetch executables");
|
182
202
|
}
|
203
|
+
commandListSelect.size = Math.min(20, commandListSelect.options.length)
|
204
|
+
|
183
205
|
}
|
pywebexec/static/js/script.js
CHANGED
@@ -56,6 +56,8 @@ document.getElementById('launchForm').addEventListener('submit', async (event) =
|
|
56
56
|
await new Promise(r => setTimeout(r, 200));
|
57
57
|
fetchCommands();
|
58
58
|
viewOutput(data.command_id);
|
59
|
+
commandInput.focus()
|
60
|
+
commandInput.setSelectionRange(0, commandInput.value.length)
|
59
61
|
} catch (error) {
|
60
62
|
console.log('Error running command:', error);
|
61
63
|
}
|
pywebexec/templates/index.html
CHANGED
@@ -19,11 +19,11 @@
|
|
19
19
|
<div id="showCommandListButton" class="show-command-list-button">
|
20
20
|
<span class="arrow">▼</span>
|
21
21
|
</div>
|
22
|
+
<select id="commandList" class="command-list" size="20"></select>
|
22
23
|
<input type="text" id="params" name="params" oninput="this.style.width = ((this.value.length + 1) * 8) + 'px';">
|
23
24
|
</div>
|
24
25
|
<button type="submit">Run</button>
|
25
26
|
</form>
|
26
|
-
<div id="commandList" class="command-list"></div>
|
27
27
|
<div class="table-container" id="tableContainer">
|
28
28
|
<table>
|
29
29
|
<thead>
|
pywebexec/version.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
pywebexec/__init__.py,sha256=4spIsVaF8RJt8S58AG_wWoORRNkws9Iwqprj27C3ljM,99
|
2
2
|
pywebexec/pywebexec.py,sha256=LRKJ2KgklZsHawd97mSKodBpH5gLm3oMza30hcLcekc,22735
|
3
|
-
pywebexec/version.py,sha256=
|
4
|
-
pywebexec/static/css/style.css,sha256=
|
3
|
+
pywebexec/version.py,sha256=s3iHFZtIHrLA43BEwwqCJ5Ch9SA-UTWHAi57WzfyPLM,411
|
4
|
+
pywebexec/static/css/style.css,sha256=s3rpd-sbnu_T4MogbVjjT05edhmGdMtlwAMx_9n8834,5177
|
5
5
|
pywebexec/static/css/xterm.css,sha256=gy8_LGA7Q61DUf8ElwFQzHqHMBQnbbEmpgZcbdgeSHI,5383
|
6
6
|
pywebexec/static/images/aborted.svg,sha256=_mP43hU5QdRLFZIknBgjx-dIXrHgQG23-QV27ApXK2A,381
|
7
7
|
pywebexec/static/images/copy.svg,sha256=d9OwtGh5GzzZHzYcDrLfNxZYLth1Q64x7bRyYxu4Px0,622
|
@@ -11,17 +11,17 @@ pywebexec/static/images/failed.svg,sha256=ADZ7IKrUyOXtqpivnz3VcH0-Wru-I5MOi3OJAk
|
|
11
11
|
pywebexec/static/images/favicon.svg,sha256=ti80IfuDZwIvQcmJxkOeUaB1iMsiyOPmQmVO-h0y1IU,1126
|
12
12
|
pywebexec/static/images/running.gif,sha256=iYuzQGkMxrakSIwt6gPieKCImGZoSAHmU5MUNZa7cpw,25696
|
13
13
|
pywebexec/static/images/success.svg,sha256=PJDcCSTevJh7rkfSFLtc7P0pbeh8PVQBS8DaOLQemmc,489
|
14
|
-
pywebexec/static/js/commands.js,sha256=
|
15
|
-
pywebexec/static/js/script.js,sha256=
|
14
|
+
pywebexec/static/js/commands.js,sha256=XfrnyRVjfZ8eOq9XpJXNVVzuvzLHqa81Ot99DSRL_Rk,6954
|
15
|
+
pywebexec/static/js/script.js,sha256=1ypziT5pOmHj_15MUvBf0ChjzEpAQ-ji4W9nhxoI_iM,9775
|
16
16
|
pywebexec/static/js/xterm/LICENSE,sha256=EU1P4eXTull-_T9I80VuwnJXubB-zLzUl3xpEYj2T1M,1083
|
17
17
|
pywebexec/static/js/xterm/ansi_up.min.js,sha256=KNGV0vEr30hNqKQimTAvGVy-icD5A1JqMQTtvYtKR2Y,13203
|
18
18
|
pywebexec/static/js/xterm/xterm-addon-fit.js,sha256=Pprm9pZe4SadVXS5Bc8b9VnC9Ex4QlWwA0pxOH53Gck,1460
|
19
19
|
pywebexec/static/js/xterm/xterm.js,sha256=Bzka76jZwEhVt_LlS0e0qMw7ryGa1p5qfxFyeohphBo,283371
|
20
20
|
pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
21
|
-
pywebexec/templates/index.html,sha256=
|
22
|
-
pywebexec-1.2.
|
23
|
-
pywebexec-1.2.
|
24
|
-
pywebexec-1.2.
|
25
|
-
pywebexec-1.2.
|
26
|
-
pywebexec-1.2.
|
27
|
-
pywebexec-1.2.
|
21
|
+
pywebexec/templates/index.html,sha256=M-9JUAR5vrk-19oF8CpxkWJvyWJkZIa71AI-1jpsMWE,2116
|
22
|
+
pywebexec-1.2.8.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
|
23
|
+
pywebexec-1.2.8.dist-info/METADATA,sha256=lNTx0DEKtyTGW4huTsiNf-ZPfoer9Ieaz5uTndBglCE,6936
|
24
|
+
pywebexec-1.2.8.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
25
|
+
pywebexec-1.2.8.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
|
26
|
+
pywebexec-1.2.8.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
|
27
|
+
pywebexec-1.2.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|