pywebexec 1.2.7__tar.gz → 1.2.8__tar.gz

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.
Files changed (35) hide show
  1. {pywebexec-1.2.7/pywebexec.egg-info → pywebexec-1.2.8}/PKG-INFO +1 -1
  2. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/css/style.css +3 -2
  3. pywebexec-1.2.8/pywebexec/static/js/commands.js +205 -0
  4. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/js/script.js +2 -0
  5. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/templates/index.html +1 -1
  6. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/version.py +2 -2
  7. {pywebexec-1.2.7 → pywebexec-1.2.8/pywebexec.egg-info}/PKG-INFO +1 -1
  8. pywebexec-1.2.7/pywebexec/static/js/commands.js +0 -183
  9. {pywebexec-1.2.7 → pywebexec-1.2.8}/.github/workflows/python-publish.yml +0 -0
  10. {pywebexec-1.2.7 → pywebexec-1.2.8}/.gitignore +0 -0
  11. {pywebexec-1.2.7 → pywebexec-1.2.8}/LICENSE +0 -0
  12. {pywebexec-1.2.7 → pywebexec-1.2.8}/README.md +0 -0
  13. {pywebexec-1.2.7 → pywebexec-1.2.8}/pyproject.toml +0 -0
  14. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/__init__.py +0 -0
  15. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/pywebexec.py +0 -0
  16. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/css/xterm.css +0 -0
  17. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/images/aborted.svg +0 -0
  18. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/images/copy.svg +0 -0
  19. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/images/copy_ok.svg +0 -0
  20. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/images/down-arrow.svg +0 -0
  21. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/images/failed.svg +0 -0
  22. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/images/favicon.svg +0 -0
  23. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/images/running.gif +0 -0
  24. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/images/success.svg +0 -0
  25. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/js/xterm/LICENSE +0 -0
  26. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/js/xterm/ansi_up.min.js +0 -0
  27. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/js/xterm/xterm-addon-fit.js +0 -0
  28. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/static/js/xterm/xterm.js +0 -0
  29. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec/templates/__init__.py +0 -0
  30. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec.egg-info/SOURCES.txt +0 -0
  31. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec.egg-info/dependency_links.txt +0 -0
  32. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec.egg-info/entry_points.txt +0 -0
  33. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec.egg-info/requires.txt +0 -0
  34. {pywebexec-1.2.7 → pywebexec-1.2.8}/pywebexec.egg-info/top_level.txt +0 -0
  35. {pywebexec-1.2.7 → pywebexec-1.2.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pywebexec
3
- Version: 1.2.7
3
+ Version: 1.2.8
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -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
 
@@ -0,0 +1,205 @@
1
+ // commands.js
2
+ let commandInput = document.getElementById('commandName');
3
+ let paramsInput = document.getElementById('params');
4
+ let commandListSelect = document.getElementById('commandList');
5
+ let showCommandListButton = document.getElementById('showCommandListButton');
6
+ let isHandlingKeydown = false;
7
+
8
+ function unfilterCommands() {
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);
14
+ }
15
+
16
+ function filterCommands() {
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;
24
+ } else {
25
+ options[i].style.display = 'none';
26
+ }
27
+ }
28
+ if (nbVisibleItems>1) {
29
+ commandListSelect.size = Math.min(20, nbVisibleItems);
30
+ } else {
31
+ commandListSelect.style.display = 'none';
32
+ }
33
+ }
34
+
35
+ function setCommandListPosition() {
36
+ const rect = commandInput.getBoundingClientRect();
37
+ commandListSelect.style.left = `${rect.left}px`;
38
+ commandListSelect.style.top = `${rect.bottom}px`;
39
+ }
40
+
41
+ function adjustInputWidth(input) {
42
+ input.style.width = 'auto';
43
+ input.style.width = `${input.scrollWidth}px`;
44
+ }
45
+
46
+
47
+ paramsInput.addEventListener('input', () => adjustInputWidth(paramsInput));
48
+ commandInput.addEventListener('input', () => {
49
+ adjustInputWidth(commandInput);
50
+ filterCommands(); // Filter commands on input
51
+ });
52
+
53
+ paramsInput.addEventListener('mouseover', () => {
54
+ paramsInput.focus();
55
+ paramsInput.setSelectionRange(0, paramsInput.value.length);
56
+ });
57
+
58
+ commandInput.addEventListener('mouseover', () => {
59
+ commandInput.focus();
60
+ commandInput.setSelectionRange(0, commandInput.value.length);
61
+ });
62
+
63
+ commandInput.addEventListener('input', (event) => {
64
+ if (event.inputType === 'deleteContentBackward') {
65
+ const newValue = commandInput.value.slice(0, -1);
66
+ commandInput.value = newValue;
67
+ commandInput.setSelectionRange(newValue.length, newValue.length);
68
+ }
69
+ const value = commandInput.value;
70
+ const options = commandListSelect.options;
71
+ if (value) {
72
+ const match = Array.from(options).find(option => option.text.startsWith(value));
73
+ if (match) {
74
+ commandInput.value = match.text;
75
+ commandInput.setSelectionRange(value.length, match.text.length);
76
+ } else {
77
+ commandInput.value = value.slice(0, -1);
78
+ }
79
+ }
80
+ filterCommands();
81
+ adjustInputWidth(commandInput); // Adjust width on input
82
+ });
83
+
84
+ commandInput.addEventListener('keydown', (event) => {
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();*/
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;
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();
140
+ });
141
+
142
+ commandInput.addEventListener('blur', (event) => {
143
+ if (event.relatedTarget === showCommandListButton || event.relatedTarget === commandListSelect) {
144
+ event.preventDefault();
145
+ return;
146
+ }
147
+ commandListSelect.style.display = 'none';
148
+ adjustInputWidth(commandInput);
149
+ });
150
+
151
+ showCommandListButton.addEventListener('click', (event) => {
152
+ event.preventDefault();
153
+ setCommandListPosition();
154
+ if (commandListSelect.style.display == 'none')
155
+ commandListSelect.style.display = 'block';
156
+ else
157
+ commandListSelect.style.display = 'none';
158
+ unfilterCommands();
159
+ });
160
+
161
+ window.addEventListener('click', (event) => {
162
+ if (!commandInput.contains(event.target) && !commandListSelect.contains(event.target) && !showCommandListButton.contains(event.target)) {
163
+ commandListSelect.style.display = 'none';
164
+ }
165
+ });
166
+
167
+ window.addEventListener('keydown', (event) => {
168
+ if ([commandInput, paramsInput, commandListSelect].includes(document.activeElement)) return;
169
+ if (event.code === `Key${event.key.toUpperCase()}`) {
170
+ commandInput.focus();
171
+ commandInput.dispatchEvent(new KeyboardEvent('keydown', event));
172
+ }
173
+ });
174
+
175
+ window.addEventListener('resize', () => {
176
+ setCommandListPosition();
177
+ });
178
+
179
+ window.addEventListener('load', () => {
180
+ fetchExecutables();
181
+ adjustInputWidth(paramsInput); // Adjust width on load
182
+ adjustInputWidth(commandInput); // Adjust width on load
183
+ setCommandListPosition();
184
+ });
185
+
186
+ async function fetchExecutables() {
187
+ try {
188
+ const response = await fetch('/executables');
189
+ if (!response.ok) {
190
+ throw new Error('Failed to fetch command status');
191
+ }
192
+ const executables = await response.json();
193
+ commandListSelect.innerHTML = '';
194
+ executables.forEach(executable => {
195
+ const option = document.createElement('option');
196
+ option.className = 'command-item';
197
+ option.text = executable;
198
+ commandListSelect.appendChild(option);
199
+ });
200
+ } catch (error) {
201
+ alert("Failed to fetch executables");
202
+ }
203
+ commandListSelect.size = Math.min(20, commandListSelect.options.length)
204
+
205
+ }
@@ -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
  }
@@ -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>
@@ -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.8'
16
+ __version_tuple__ = version_tuple = (1, 2, 8)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pywebexec
3
- Version: 1.2.7
3
+ Version: 1.2.8
4
4
  Summary: Simple Python HTTP Exec Server
5
5
  Home-page: https://github.com/joknarf/pywebexec
6
6
  Author: Franck Jouvanceau
@@ -1,183 +0,0 @@
1
- // commands.js
2
- let commandInput = document.getElementById('commandName');
3
- let paramsInput = document.getElementById('params');
4
- let commandListDiv = document.getElementById('commandList');
5
- let showCommandListButton = document.getElementById('showCommandListButton');
6
-
7
- function unfilterCommands() {
8
- const items = commandListDiv.getElementsByClassName('command-item');
9
- Array.from(items).forEach(item => {
10
- item.style.display = 'block';
11
- });
12
- adjustCommandListWidth();
13
- }
14
-
15
- 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;
23
- } else {
24
- item.style.display = 'none';
25
- }
26
- });
27
- commandListDiv.style.display = hasVisibleItems ? 'block' : 'none';
28
- if (hasVisibleItems) {
29
- commandListDiv.classList.add('show');
30
- } else {
31
- commandListDiv.classList.remove('show');
32
- }
33
- adjustCommandListWidth(); // Adjust width after filtering commands
34
- }
35
-
36
- function setCommandListPosition() {
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`;
41
- }
42
-
43
- function adjustInputWidth(input) {
44
- input.style.width = 'auto';
45
- input.style.width = `${input.scrollWidth}px`;
46
- }
47
-
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
-
63
- paramsInput.addEventListener('input', () => adjustInputWidth(paramsInput));
64
- commandInput.addEventListener('input', () => {
65
- adjustInputWidth(commandInput);
66
- filterCommands(); // Filter commands on input
67
- });
68
-
69
- paramsInput.addEventListener('mouseover', () => {
70
- paramsInput.focus();
71
- paramsInput.setSelectionRange(0, paramsInput.value.length);
72
- });
73
-
74
- commandInput.addEventListener('mouseover', () => {
75
- commandInput.focus();
76
- commandInput.setSelectionRange(0, commandInput.value.length);
77
- });
78
-
79
- commandInput.addEventListener('input', (event) => {
80
- if (event.inputType === 'deleteContentBackward') {
81
- const newValue = commandInput.value.slice(0, -1);
82
- commandInput.value = newValue;
83
- commandInput.setSelectionRange(newValue.length, newValue.length);
84
- }
85
- const value = commandInput.value;
86
- const items = Array.from(commandListDiv.getElementsByClassName('command-item'));
87
- if (value) {
88
- const match = items.find(item => item.textContent.startsWith(value));
89
- if (match) {
90
- commandInput.value = match.textContent;
91
- commandInput.setSelectionRange(value.length, match.textContent.length);
92
- } else {
93
- commandInput.value = value.slice(0, -1);
94
- }
95
- }
96
- filterCommands();
97
- adjustInputWidth(commandInput); // Adjust width on input
98
- });
99
-
100
- commandInput.addEventListener('click', () => {
101
- setCommandListPosition();
102
- commandListDiv.style.display = 'block';
103
- filterCommands();
104
- });
105
-
106
- commandInput.addEventListener('keydown', (event) => {
107
- if (event.key === 'ArrowDown') {
108
- setCommandListPosition();
109
- commandListDiv.style.display = 'block';
110
- unfilterCommands();
111
- }
112
- });
113
-
114
- commandInput.addEventListener('blur', (event) => {
115
- if (event.relatedTarget === showCommandListButton) {
116
- event.preventDefault();
117
- return;
118
- }
119
- commandListDiv.style.display = 'none';
120
- commandListDiv.classList.remove('show');
121
- adjustInputWidth(commandInput);
122
- });
123
-
124
- showCommandListButton.addEventListener('mousedown', (event) => {
125
- event.preventDefault();
126
- setCommandListPosition();
127
- commandListDiv.style.display = 'block';
128
- unfilterCommands();
129
- });
130
-
131
- 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);
136
- }
137
- });
138
-
139
- window.addEventListener('keydown', (event) => {
140
- if (document.activeElement !== paramsInput) {
141
- commandInput.focus();
142
- commandInput.dispatchEvent(new KeyboardEvent('keydown', event));
143
- }
144
- });
145
-
146
- window.addEventListener('resize', () => {
147
- setCommandListPosition();
148
- });
149
-
150
- window.addEventListener('load', () => {
151
- fetchExecutables();
152
- adjustInputWidth(paramsInput); // Adjust width on load
153
- adjustInputWidth(commandInput); // Adjust width on load
154
- setCommandListPosition();
155
- });
156
-
157
- async function fetchExecutables() {
158
- try {
159
- const response = await fetch('/executables');
160
- if (!response.ok) {
161
- throw new Error('Failed to fetch command status');
162
- }
163
- const executables = await response.json();
164
- commandListDiv.innerHTML = '';
165
- 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);
177
- });
178
- // Ensure the elements are rendered before measuring their widths
179
- requestAnimationFrame(adjustCommandListWidth);
180
- } catch (error) {
181
- alert("Failed to fetch executables");
182
- }
183
- }
File without changes
File without changes
File without changes
File without changes
File without changes