cc4-embedded-system 3.1.5 → 3.1.7

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 CHANGED
@@ -2,7 +2,7 @@
2
2
  - This version based on [html-minifier-next](https://github.com/j9t/html-minifier-next) and rewrite [lwIP makefsdata](https://github.com/m-labs/lwip/tree/master/src/apps/httpd/makefsdata), run on localhost, default port: ```3000```.
3
3
  - This tool is deployed on [npm package](https://www.npmjs.com/package/cc4-embedded-system).
4
4
 
5
- ![](./Screenshot/v3.1.1.png)
5
+ ![](./Screenshot/v3.1.6.png)
6
6
 
7
7
  ## Structure
8
8
  ```text
@@ -14,7 +14,7 @@ CC4EmbeddedSystem/
14
14
  ├── public/
15
15
  │ └── index.html // Web GUI dashboard
16
16
  ├── Sereenshot/
17
- │ └── v3.1.1.png // Demo image
17
+ │ └── v3.1.6.png // Demo image
18
18
  ├── node_modules/ // Required submodules during development
19
19
  ├── dist/ // Compiled JavaScript output (Auto-generated)
20
20
  ├── package.json // Project configuration & dependencies
@@ -33,6 +33,10 @@ CC4EmbeddedSystem/
33
33
  ```bash
34
34
  npx cc4-embedded-system
35
35
  ```
36
+ - Specific port set during initialization
37
+ ```bash
38
+ cc4es --port 3002
39
+ ```
36
40
  ### Development
37
41
  ```bash
38
42
  # build
package/dist/gui.js CHANGED
@@ -83,6 +83,7 @@ if (portArgIndex !== -1 && process.argv[portArgIndex + 1]) {
83
83
  if (!isNaN(parsedPort))
84
84
  PORT = parsedPort;
85
85
  }
86
+ let activeBrowseProcess = null;
86
87
  let server;
87
88
  let shutdownTimer = null;
88
89
  app.use(express.json());
@@ -98,6 +99,15 @@ const cancelShutdown = () => {
98
99
  // console.log('🛡️ Shutdown cancelled (keep alive)');
99
100
  }
100
101
  };
102
+ const scheduleShutdown = () => {
103
+ if (!shutdownTimer) {
104
+ shutdownTimer = setTimeout(() => {
105
+ closeBrowseProcess();
106
+ console.log('👋 Window closed, shutting down ...');
107
+ process.exit(0);
108
+ }, 2000);
109
+ }
110
+ };
101
111
  const buildPowerShellArgs = (script) => {
102
112
  const encodedCommand = Buffer.from(script, 'utf16le').toString('base64');
103
113
  return [
@@ -107,18 +117,32 @@ const buildPowerShellArgs = (script) => {
107
117
  encodedCommand
108
118
  ];
109
119
  };
120
+ const closeBrowseProcess = () => {
121
+ if (activeBrowseProcess && !activeBrowseProcess.killed) {
122
+ try {
123
+ activeBrowseProcess.kill();
124
+ }
125
+ catch (e) {
126
+ // ignore child cleanup error
127
+ }
128
+ }
129
+ activeBrowseProcess = null;
130
+ };
110
131
  const runDialogCommand = (command, args) => {
111
132
  return new Promise((resolve, reject) => {
112
- execFile(command, args, {
133
+ const child = execFile(command, args, {
113
134
  windowsHide: false,
114
135
  maxBuffer: 1024 * 1024
115
136
  }, (error, stdout, stderr) => {
137
+ if (activeBrowseProcess === child)
138
+ activeBrowseProcess = null;
116
139
  if (error) {
117
140
  reject(new Error(stderr.trim() || error.message));
118
141
  return;
119
142
  }
120
143
  resolve(stdout.trim());
121
144
  });
145
+ activeBrowseProcess = child;
122
146
  });
123
147
  };
124
148
  const buildWindowsDialogScript = (dialogLines) => {
@@ -151,12 +175,8 @@ app.get('/api/version', (_req, res) => {
151
175
  });
152
176
  app.post('/api/shutdown', (_req, res) => {
153
177
  res.json({ success: true });
154
- if (!shutdownTimer) {
155
- shutdownTimer = setTimeout(() => {
156
- console.log('👋 Window closed, shutting down ...');
157
- process.exit(0);
158
- }, 2000);
159
- }
178
+ closeBrowseProcess();
179
+ scheduleShutdown();
160
180
  });
161
181
  app.post('/api/cancel-shutdown', (_req, res) => {
162
182
  cancelShutdown();
@@ -222,6 +242,12 @@ app.post('/api/change-port', (req, res) => {
222
242
  });
223
243
  app.get('/api/browse', async (req, res) => {
224
244
  cancelShutdown();
245
+ res.on('close', () => {
246
+ if (!res.writableEnded) {
247
+ closeBrowseProcess();
248
+ scheduleShutdown();
249
+ }
250
+ });
225
251
  const isDir = req.query.type === 'dir';
226
252
  const platform = os.platform();
227
253
  try {
@@ -110,23 +110,99 @@
110
110
  <button onclick="startBuild()">Generate C Code</button>
111
111
  </div>
112
112
 
113
+ <style>
114
+ body.browse-locked .container {
115
+ pointer-events: none;
116
+ user-select: none;
117
+ filter: blur(1px);
118
+ }
119
+
120
+ #browseOverlay {
121
+ position: fixed;
122
+ inset: 0;
123
+ display: none;
124
+ align-items: center;
125
+ justify-content: center;
126
+ background: rgba(0, 0, 0, 0.55);
127
+ z-index: 9999;
128
+ }
129
+
130
+ body.browse-locked #browseOverlay {
131
+ display: flex;
132
+ }
133
+
134
+ .browse-overlay-card {
135
+ background: #252526;
136
+ color: #d4d4d4;
137
+ border: 1px solid #555;
138
+ border-radius: 8px;
139
+ padding: 20px 24px;
140
+ width: min(420px, calc(100vw - 40px));
141
+ text-align: center;
142
+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.45);
143
+ font-family: 'Consolas', monospace;
144
+ }
145
+
146
+ .browse-overlay-title {
147
+ color: #9cdcfe;
148
+ font-size: 16px;
149
+ font-weight: bold;
150
+ margin-bottom: 10px;
151
+ }
152
+
153
+ .browse-overlay-text {
154
+ color: #cccccc;
155
+ font-size: 14px;
156
+ line-height: 1.6;
157
+ }
158
+ </style>
159
+
113
160
  <script>
114
161
  let isRedirecting = false;
162
+ let isBrowsing = false;
163
+ let isBrowsePending = false;
115
164
  document.getElementById('guiPort').value = window.location.port || '80';
116
165
 
166
+ function setBrowseState(active) {
167
+ isBrowsing = active;
168
+ document.body.classList.toggle('browse-locked', active);
169
+ }
170
+
117
171
  async function handleBrowse(targetId, type) {
172
+ if (isBrowsing || isBrowsePending) return;
173
+
174
+ isBrowsePending = true;
175
+
118
176
  try {
119
177
  const res = await fetch(`/api/browse?type=${type}`);
120
178
  const data = await res.json();
121
- if (data.success && data.path) {
122
- document.getElementById(targetId).value = data.path;
123
- }
179
+
180
+ if (data.success && data.path) document.getElementById(targetId).value = data.path;
124
181
  }
125
182
  catch (e) {
126
183
  console.error('Failed to open system dialog', e);
127
184
  }
185
+ finally {
186
+ isBrowsePending = false;
187
+ setBrowseState(false);
188
+ }
128
189
  }
129
190
 
191
+ window.addEventListener('blur', () => {
192
+ if (isBrowsePending) setBrowseState(true);
193
+ });
194
+
195
+
196
+ window.addEventListener('keydown', (event) => {
197
+ const isReloadKey = event.key === 'F5';
198
+ const isRefreshShortcut = (event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'r';
199
+
200
+ if (isBrowsing && (isReloadKey || isRefreshShortcut)) {
201
+ event.preventDefault();
202
+ event.stopPropagation();
203
+ }
204
+ }, true);
205
+
130
206
  window.addEventListener('DOMContentLoaded', async () => {
131
207
  await fetch('/api/cancel-shutdown', { method: 'POST' });
132
208
  try {
@@ -211,10 +287,31 @@
211
287
  alert('❌ Error: ' + result.message);
212
288
  }
213
289
  }
214
-
215
- window.addEventListener('beforeunload', () => {
290
+
291
+ function notifyShutdown() {
216
292
  if (! isRedirecting) navigator.sendBeacon('/api/shutdown');
293
+ }
294
+
295
+ window.addEventListener('beforeunload', (event) => {
296
+ if (isBrowsing || isBrowsePending) {
297
+ event.preventDefault();
298
+ event.returnValue = '';
299
+ return '';
300
+ }
217
301
  });
302
+
303
+ window.addEventListener('pagehide', notifyShutdown);
304
+ window.addEventListener('unload', notifyShutdown);
218
305
  </script>
306
+ <div id="browseOverlay">
307
+ <div class="browse-overlay-card">
308
+ <div class="browse-overlay-title">Browse Dialog Open</div>
309
+ <div class="browse-overlay-text">
310
+ Please finish the system browse dialog first.<br>
311
+ Refresh and page navigation are temporarily disabled.
312
+ </div>
313
+ </div>
314
+ </div>
315
+
219
316
  </body>
220
317
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc4-embedded-system",
3
- "version": "3.1.5",
3
+ "version": "3.1.7",
4
4
  "description": "A modern typescript version of makefsdata based on html-minifier-next and lwIP v1.3.1",
5
5
  "bin": {
6
6
  "cc4es": "dist/gui.js"