pywebexec 1.2.7__py3-none-any.whl → 1.2.9__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.
@@ -31,9 +31,15 @@ th {
31
31
  width: 100%;
32
32
  }
33
33
  select { /* Safari bug */
34
+ -webkit-appearance: none;
35
+ -webkit-border-radius: none;
36
+ appearance: none;
37
+ outline: none;
34
38
  font-size: 15px;
35
39
  border: #aaa solid 1px;
36
40
  border-radius: 5px;
41
+ padding: 0px 5px 5px 0px;
42
+ min-width: 150px;
37
43
  }
38
44
  .output {
39
45
  white-space: pre-wrap;
@@ -178,7 +184,7 @@ form {
178
184
  border: 1px solid #aaa;
179
185
  border-radius: 5px;
180
186
  padding: 0px 5px 0px 5px;
181
- max-height: 300px;
187
+ margin-top: 2px;
182
188
  overflow-y: auto;
183
189
  z-index: 1000;
184
190
  }
@@ -188,7 +194,7 @@ form {
188
194
  cursor: pointer;
189
195
  }
190
196
 
191
- .command-item:hover {
197
+ .command-item:hover, .command-item.highlighted {
192
198
  background-color: #eee;
193
199
  }
194
200
 
@@ -1,43 +1,42 @@
1
1
  // commands.js
2
2
  let commandInput = document.getElementById('commandName');
3
3
  let paramsInput = document.getElementById('params');
4
- let commandListDiv = document.getElementById('commandList');
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 items = commandListDiv.getElementsByClassName('command-item');
9
- Array.from(items).forEach(item => {
10
- item.style.display = 'block';
11
- });
12
- adjustCommandListWidth();
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 items = commandListDiv.getElementsByClassName('command-item');
18
- let hasVisibleItems = false;
19
- Array.from(items).forEach(item => {
20
- if (item.textContent.startsWith(value)) {
21
- item.style.display = 'block';
22
- hasVisibleItems = true;
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
- item.style.display = 'none';
25
+ options[i].style.display = 'none';
25
26
  }
26
- });
27
- commandListDiv.style.display = hasVisibleItems ? 'block' : 'none';
28
- if (hasVisibleItems) {
29
- commandListDiv.classList.add('show');
27
+ }
28
+ if (nbVisibleItems>1) {
29
+ commandListSelect.size = Math.min(20, nbVisibleItems);
30
+ commandListSelect.style.display = 'block';
30
31
  } else {
31
- commandListDiv.classList.remove('show');
32
+ commandListSelect.style.display = 'none';
32
33
  }
33
- adjustCommandListWidth(); // Adjust width after filtering commands
34
34
  }
35
35
 
36
36
  function setCommandListPosition() {
37
37
  const rect = commandInput.getBoundingClientRect();
38
- commandListDiv.style.left = `${rect.left}px`;
39
- commandListDiv.style.top = `${rect.bottom}px`;
40
- commandListDiv.style.minWidth = `${rect.width}px`;
38
+ commandListSelect.style.left = `${rect.left}px`;
39
+ commandListSelect.style.top = `${rect.bottom}px`;
41
40
  }
42
41
 
43
42
  function adjustInputWidth(input) {
@@ -45,20 +44,6 @@ function adjustInputWidth(input) {
45
44
  input.style.width = `${input.scrollWidth}px`;
46
45
  }
47
46
 
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
47
 
63
48
  paramsInput.addEventListener('input', () => adjustInputWidth(paramsInput));
64
49
  commandInput.addEventListener('input', () => {
@@ -83,12 +68,12 @@ commandInput.addEventListener('input', (event) => {
83
68
  commandInput.setSelectionRange(newValue.length, newValue.length);
84
69
  }
85
70
  const value = commandInput.value;
86
- const items = Array.from(commandListDiv.getElementsByClassName('command-item'));
71
+ const options = commandListSelect.options;
87
72
  if (value) {
88
- const match = items.find(item => item.textContent.startsWith(value));
73
+ const match = Array.from(options).find(option => option.text.startsWith(value));
89
74
  if (match) {
90
- commandInput.value = match.textContent;
91
- commandInput.setSelectionRange(value.length, match.textContent.length);
75
+ commandInput.value = match.text;
76
+ commandInput.setSelectionRange(value.length, match.text.length);
92
77
  } else {
93
78
  commandInput.value = value.slice(0, -1);
94
79
  }
@@ -97,47 +82,101 @@ commandInput.addEventListener('input', (event) => {
97
82
  adjustInputWidth(commandInput); // Adjust width on input
98
83
  });
99
84
 
100
- commandInput.addEventListener('click', () => {
101
- setCommandListPosition();
102
- commandListDiv.style.display = 'block';
103
- filterCommands();
104
- });
105
-
106
85
  commandInput.addEventListener('keydown', (event) => {
107
- if (event.key === 'ArrowDown') {
108
- setCommandListPosition();
109
- commandListDiv.style.display = 'block';
86
+ if (event.key === ' ' || event.key === 'ArrowRight') {
87
+ event.preventDefault();
88
+ paramsInput.focus();
89
+ paramsInput.setSelectionRange(0, paramsInput.value.length);
90
+ } else if (event.key === 'ArrowDown') {
91
+ /*setCommandListPosition();*/
110
92
  unfilterCommands();
93
+ commandListSelect.style.display = 'block';
94
+ commandListSelect.focus();
95
+ commandListSelect.selectedIndex = 0;
96
+ event.preventDefault();
97
+ }
98
+ });
99
+
100
+ paramsInput.addEventListener('keydown', (event) => {
101
+ if (paramsInput.selectionStart > 0) return;
102
+ if (event.key === 'ArrowLeft') {
103
+ commandInput.focus();
104
+ commandInput.setSelectionRange(0, commandInput.value.length);
105
+ event.preventDefault();
106
+ return;
107
+ }
108
+ if (event.key === 'Backspace') {
109
+ val = paramsInput.value
110
+ paramsInput.value = val.slice(0, paramsInput.selectionStart) + val.slice(paramsInput.selectionEnd)
111
+ commandInput.focus();
112
+ commandInput.setSelectionRange(0, commandInput.value.length);
113
+ event.preventDefault();
114
+ }
115
+ });
116
+
117
+ commandListSelect.addEventListener('keydown', (event) => {
118
+ if (event.key === 'Enter') {
119
+ event.preventDefault(); // Prevent form submission
120
+ const selectedOption = commandListSelect.options[commandListSelect.selectedIndex];
121
+ commandInput.value = selectedOption.text;
122
+ commandListSelect.style.display = 'none';
123
+ adjustInputWidth(commandInput);
124
+ paramsInput.focus();
125
+ return;
126
+ }
127
+ if (event.key === 'ArrowUp' && commandListSelect.selectedIndex == 0) {
128
+ commandInput.focus();
129
+ commandListSelect.style.display = 'none'
111
130
  }
112
131
  });
113
132
 
133
+ commandListSelect.addEventListener('click', (event) => {
134
+ event.preventDefault(); // Prevent form submission
135
+ const selectedOption = commandListSelect.options[commandListSelect.selectedIndex];
136
+ commandInput.value = selectedOption.text;
137
+ commandListSelect.style.display = 'none';
138
+ adjustInputWidth(commandInput);
139
+ paramsInput.focus();
140
+ });
141
+
142
+
143
+ commandInput.addEventListener('click', () => {
144
+ setCommandListPosition();
145
+ if (commandListSelect.style.display == 'none')
146
+ commandListSelect.style.display = 'block';
147
+ else
148
+ commandListSelect.style.display = 'none';
149
+ filterCommands();
150
+ });
151
+
114
152
  commandInput.addEventListener('blur', (event) => {
115
- if (event.relatedTarget === showCommandListButton) {
153
+ if (event.relatedTarget === showCommandListButton || event.relatedTarget === commandListSelect) {
116
154
  event.preventDefault();
117
155
  return;
118
156
  }
119
- commandListDiv.style.display = 'none';
120
- commandListDiv.classList.remove('show');
157
+ commandListSelect.style.display = 'none';
121
158
  adjustInputWidth(commandInput);
122
159
  });
123
160
 
124
- showCommandListButton.addEventListener('mousedown', (event) => {
161
+ showCommandListButton.addEventListener('click', (event) => {
125
162
  event.preventDefault();
126
163
  setCommandListPosition();
127
- commandListDiv.style.display = 'block';
164
+ if (commandListSelect.style.display == 'none')
165
+ commandListSelect.style.display = 'block';
166
+ else
167
+ commandListSelect.style.display = 'none';
128
168
  unfilterCommands();
129
169
  });
130
170
 
131
171
  window.addEventListener('click', (event) => {
132
- if (!commandInput.contains(event.target) && !commandListDiv.contains(event.target) && !showCommandListButton.contains(event.target)) {
133
- commandListDiv.style.display = 'none';
134
- commandListDiv.classList.remove('show');
135
- adjustInputWidth(commandInput);
172
+ if (!commandInput.contains(event.target) && !commandListSelect.contains(event.target) && !showCommandListButton.contains(event.target)) {
173
+ commandListSelect.style.display = 'none';
136
174
  }
137
175
  });
138
176
 
139
177
  window.addEventListener('keydown', (event) => {
140
- if (document.activeElement !== paramsInput) {
178
+ if ([commandInput, paramsInput, commandListSelect].includes(document.activeElement)) return;
179
+ if (event.code === `Key${event.key.toUpperCase()}`) {
141
180
  commandInput.focus();
142
181
  commandInput.dispatchEvent(new KeyboardEvent('keydown', event));
143
182
  }
@@ -161,23 +200,16 @@ async function fetchExecutables() {
161
200
  throw new Error('Failed to fetch command status');
162
201
  }
163
202
  const executables = await response.json();
164
- commandListDiv.innerHTML = '';
203
+ commandListSelect.innerHTML = '';
165
204
  executables.forEach(executable => {
166
- const div = document.createElement('div');
167
- div.className = 'command-item';
168
- div.textContent = executable;
169
- div.addEventListener('mousedown', () => {
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);
205
+ const option = document.createElement('option');
206
+ option.className = 'command-item';
207
+ option.text = executable;
208
+ commandListSelect.appendChild(option);
177
209
  });
178
- // Ensure the elements are rendered before measuring their widths
179
- requestAnimationFrame(adjustCommandListWidth);
180
210
  } catch (error) {
181
211
  alert("Failed to fetch executables");
182
212
  }
213
+ commandListSelect.size = Math.min(20, commandListSelect.options.length)
214
+
183
215
  }
@@ -53,9 +53,11 @@ document.getElementById('launchForm').addEventListener('submit', async (event) =
53
53
  throw new Error('Failed to launch command');
54
54
  }
55
55
  const data = await response.json();
56
- await new Promise(r => setTimeout(r, 200));
56
+ await new Promise(r => setTimeout(r, 300));
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
  }
@@ -19,11 +19,11 @@
19
19
  <div id="showCommandListButton" class="show-command-list-button">
20
20
  <span class="arrow">&#9660;</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
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '1.2.7'
16
- __version_tuple__ = version_tuple = (1, 2, 7)
15
+ __version__ = version = '1.2.9'
16
+ __version_tuple__ = version_tuple = (1, 2, 9)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pywebexec
3
- Version: 1.2.7
3
+ Version: 1.2.9
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -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=eUTJamBaZbdGP80CUfd3WS7PTAr5iMj50aNYRf1wwQ8,411
4
- pywebexec/static/css/style.css,sha256=n9FBJQ8CWUM8Aya-Nr_7ia45GgoYBeP8LKWgiq-PIMQ,5121
3
+ pywebexec/version.py,sha256=zd_kt_wsJmqzo58jY4byL9Q3ywofrUGUVUN0VUMtx8w,411
4
+ pywebexec/static/css/style.css,sha256=nuJodEFojt_kCLPqbDBQAaBtWcRZ6uLjfI52mSf3EJA,5302
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=JvAdUqxSzPlCrF_W0v6oiwy6gcDUBBxriLtKuZTX_hE,6144
15
- pywebexec/static/js/script.js,sha256=lHQCHOrERRZ5Q9RcpnErL1ID_gngNRCBqzvwno6G_b0,9677
14
+ pywebexec/static/js/commands.js,sha256=4noexrtU-nTNV1L-qp6QpoGxokELKOdYDxGChYELb0w,7347
15
+ pywebexec/static/js/script.js,sha256=-MAcmmeRqH4b0xcbHZWiOkJaIa9C6boZ-QOHuXXbMpc,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=zpErZg3Z7eO5wc9k-pLuaZqrNNu2K768-TsQJQecgnQ,2092
22
- pywebexec-1.2.7.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
23
- pywebexec-1.2.7.dist-info/METADATA,sha256=GcjX8phAGL_HdTRBic46s-UGZ9g2q4lZVOJHOZGgu8I,6936
24
- pywebexec-1.2.7.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
25
- pywebexec-1.2.7.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
26
- pywebexec-1.2.7.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
27
- pywebexec-1.2.7.dist-info/RECORD,,
21
+ pywebexec/templates/index.html,sha256=M-9JUAR5vrk-19oF8CpxkWJvyWJkZIa71AI-1jpsMWE,2116
22
+ pywebexec-1.2.9.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
23
+ pywebexec-1.2.9.dist-info/METADATA,sha256=nvOnY9AFUD_7E79MhEIg_fhniAxF1HRB5CcuUt5I4jQ,6936
24
+ pywebexec-1.2.9.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
25
+ pywebexec-1.2.9.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
26
+ pywebexec-1.2.9.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
27
+ pywebexec-1.2.9.dist-info/RECORD,,