pinokiod 3.85.0 → 3.87.0
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/Dockerfile +61 -0
- package/docker-entrypoint.sh +75 -0
- package/kernel/api/hf/index.js +1 -1
- package/kernel/api/index.js +8 -1
- package/kernel/api/shell/index.js +6 -0
- package/kernel/api/terminal/index.js +166 -0
- package/kernel/bin/caddy.js +10 -4
- package/kernel/bin/conda.js +3 -2
- package/kernel/bin/index.js +53 -2
- package/kernel/bin/setup.js +32 -0
- package/kernel/bin/vs.js +11 -2
- package/kernel/index.js +42 -2
- package/kernel/info.js +36 -0
- package/kernel/peer.js +42 -18
- package/kernel/prototype.js +1 -0
- package/kernel/router/index.js +23 -15
- package/kernel/router/localhost_static_router.js +0 -3
- package/kernel/router/pinokio_domain_router.js +333 -0
- package/kernel/shell.js +43 -2
- package/kernel/shells.js +21 -1
- package/kernel/util.js +4 -2
- package/package.json +2 -1
- package/pipe/views/login.ejs +1 -1
- package/script/install-mode.js +33 -0
- package/script/pinokio.json +7 -0
- package/server/index.js +636 -246
- package/server/public/Socket.js +48 -0
- package/server/public/common.js +1956 -257
- package/server/public/fseditor.js +71 -12
- package/server/public/install.js +1 -1
- package/server/public/layout.js +740 -0
- package/server/public/modalinput.js +0 -1
- package/server/public/opener.js +12 -11
- package/server/public/serve/style.css +1 -1
- package/server/public/style.css +122 -129
- package/server/public/tab-idle-notifier.js +629 -0
- package/server/public/terminal_input_tracker.js +63 -0
- package/server/public/urldropdown.css +780 -45
- package/server/public/urldropdown.js +806 -156
- package/server/public/window_storage.js +97 -28
- package/server/socket.js +40 -9
- package/server/views/404.ejs +1 -1
- package/server/views/500.ejs +3 -3
- package/server/views/app.ejs +3146 -1381
- package/server/views/bookmarklet.ejs +197 -0
- package/server/views/bootstrap.ejs +1 -1
- package/server/views/columns.ejs +2 -13
- package/server/views/connect/x.ejs +4 -4
- package/server/views/connect.ejs +13 -14
- package/server/views/container.ejs +3 -4
- package/server/views/d.ejs +225 -55
- package/server/views/download.ejs +1 -1
- package/server/views/editor.ejs +2 -2
- package/server/views/env_editor.ejs +3 -3
- package/server/views/explore.ejs +2 -2
- package/server/views/file_explorer.ejs +3 -3
- package/server/views/git.ejs +7 -7
- package/server/views/github.ejs +3 -3
- package/server/views/help.ejs +2 -2
- package/server/views/index.ejs +17 -16
- package/server/views/index2.ejs +7 -7
- package/server/views/init/index.ejs +15 -79
- package/server/views/install.ejs +4 -4
- package/server/views/keys.ejs +2 -2
- package/server/views/layout.ejs +105 -0
- package/server/views/mini.ejs +2 -2
- package/server/views/net.ejs +45 -13
- package/server/views/network.ejs +41 -27
- package/server/views/network2.ejs +11 -11
- package/server/views/old_network.ejs +10 -10
- package/server/views/partials/dynamic.ejs +3 -5
- package/server/views/partials/menu.ejs +3 -5
- package/server/views/partials/running.ejs +1 -1
- package/server/views/pro.ejs +369 -0
- package/server/views/prototype/index.ejs +3 -3
- package/server/views/required_env_editor.ejs +2 -2
- package/server/views/review.ejs +15 -27
- package/server/views/rows.ejs +2 -13
- package/server/views/screenshots.ejs +298 -142
- package/server/views/settings.ejs +6 -7
- package/server/views/setup.ejs +3 -4
- package/server/views/setup_home.ejs +2 -2
- package/server/views/share_editor.ejs +4 -4
- package/server/views/shell.ejs +280 -29
- package/server/views/start.ejs +2 -2
- package/server/views/task.ejs +2 -2
- package/server/views/terminal.ejs +326 -52
- package/server/views/tools.ejs +461 -17
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
<script src="/xterm-addon-search-bar.js"></script>
|
|
14
14
|
<script src="/sweetalert2.js"></script>
|
|
15
15
|
<script src="/Socket.js"></script>
|
|
16
|
+
<script src="/terminal_input_tracker.js"></script>
|
|
16
17
|
<script src="/common.js"></script>
|
|
17
18
|
<script src="/he.js"></script>
|
|
18
19
|
<script src="/opener.js"></script>
|
|
@@ -95,6 +96,28 @@ header {
|
|
|
95
96
|
.xterm .xterm-viewport {
|
|
96
97
|
width: initial !important;
|
|
97
98
|
}
|
|
99
|
+
#terminal {
|
|
100
|
+
position: relative;
|
|
101
|
+
}
|
|
102
|
+
.terminal-drop-overlay {
|
|
103
|
+
position: absolute;
|
|
104
|
+
inset: 0;
|
|
105
|
+
background: rgba(0,0,0,0.6);
|
|
106
|
+
color: #fff;
|
|
107
|
+
display: flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
justify-content: center;
|
|
110
|
+
font-size: 14px;
|
|
111
|
+
text-align: center;
|
|
112
|
+
pointer-events: none;
|
|
113
|
+
opacity: 0;
|
|
114
|
+
transition: opacity 0.15s ease-in-out;
|
|
115
|
+
padding: 12px;
|
|
116
|
+
z-index: 5;
|
|
117
|
+
}
|
|
118
|
+
.terminal-drop-overlay.active {
|
|
119
|
+
opacity: 1;
|
|
120
|
+
}
|
|
98
121
|
/*
|
|
99
122
|
.navheader {
|
|
100
123
|
background: var(--dark-bg);
|
|
@@ -102,7 +125,7 @@ header {
|
|
|
102
125
|
*/
|
|
103
126
|
/*
|
|
104
127
|
.btn {
|
|
105
|
-
background:
|
|
128
|
+
background: rgba(127, 91, 243, 0.9);
|
|
106
129
|
}
|
|
107
130
|
*/
|
|
108
131
|
#status-window {
|
|
@@ -114,7 +137,7 @@ header {
|
|
|
114
137
|
font-size: 12px;
|
|
115
138
|
}
|
|
116
139
|
#status-window strong {
|
|
117
|
-
color:
|
|
140
|
+
color: rgba(127, 91, 243, 0.9);
|
|
118
141
|
}
|
|
119
142
|
#status-window b {
|
|
120
143
|
color: black;
|
|
@@ -136,11 +159,11 @@ body.dark #status-window b {
|
|
|
136
159
|
#progress-bar {
|
|
137
160
|
width: 0%;
|
|
138
161
|
height: 100%;
|
|
139
|
-
background:
|
|
162
|
+
background: rgba(127, 91, 243, 0.9);
|
|
140
163
|
transition: width 0.2s;
|
|
141
164
|
}
|
|
142
165
|
#del-bin {
|
|
143
|
-
color:
|
|
166
|
+
color: rgba(127, 91, 243, 0.9);
|
|
144
167
|
cursor: pointer;
|
|
145
168
|
font-weight: bold;
|
|
146
169
|
padding: 0 5px;
|
|
@@ -154,6 +177,28 @@ body.frozen {
|
|
|
154
177
|
<script>
|
|
155
178
|
let shell_id
|
|
156
179
|
Dropzone.autoDiscover = false;
|
|
180
|
+
function buildBinaryRpcPayload(rpc, fileEntries) {
|
|
181
|
+
const metadata = {
|
|
182
|
+
rpc,
|
|
183
|
+
buffer_keys: fileEntries.map((entry) => entry.key)
|
|
184
|
+
}
|
|
185
|
+
const metaBytes = new TextEncoder().encode(JSON.stringify(metadata))
|
|
186
|
+
const separator = new Uint8Array([0])
|
|
187
|
+
const parts = [metaBytes, separator]
|
|
188
|
+
for (const entry of fileEntries) {
|
|
189
|
+
const lenBytes = new Uint8Array(4)
|
|
190
|
+
new DataView(lenBytes.buffer).setUint32(0, entry.buffer.byteLength)
|
|
191
|
+
parts.push(lenBytes, entry.buffer)
|
|
192
|
+
}
|
|
193
|
+
const totalLength = parts.reduce((sum, part) => sum + part.length, 0)
|
|
194
|
+
const combined = new Uint8Array(totalLength)
|
|
195
|
+
let offset = 0
|
|
196
|
+
for (const part of parts) {
|
|
197
|
+
combined.set(part, offset)
|
|
198
|
+
offset += part.length
|
|
199
|
+
}
|
|
200
|
+
return combined.buffer
|
|
201
|
+
}
|
|
157
202
|
document.addEventListener("DOMContentLoaded", async () => {
|
|
158
203
|
<% if (error) { %>
|
|
159
204
|
document.querySelector(".requirements .content").innerHTML = '<div class="loading"><i class="fa-solid fa-circle-exclamation"></i> <%=error%></div>'
|
|
@@ -177,10 +222,80 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
177
222
|
location.href = location.href
|
|
178
223
|
<% } %>
|
|
179
224
|
const n = new N()
|
|
225
|
+
const baseScriptId = <% if (script_id) { %><%- JSON.stringify(script_id) %><% } else { %>null<% } %>
|
|
226
|
+
const scriptUri = <% if (script_path) { %><%- JSON.stringify(script_path) %><% } else { %>null<% } %>
|
|
227
|
+
const scriptCwd = <% if (cwd) { %><%- JSON.stringify(cwd) %><% } else { %>null<% } %>
|
|
180
228
|
class RPC {
|
|
181
229
|
constructor() {
|
|
182
230
|
this.socket = new Socket()
|
|
183
231
|
this.buffer = []
|
|
232
|
+
this.uploadContext = {
|
|
233
|
+
cwd: "~" + location.pathname
|
|
234
|
+
}
|
|
235
|
+
this.baseScriptId = baseScriptId
|
|
236
|
+
this.currentId = baseScriptId
|
|
237
|
+
this.inputBuffer = ""
|
|
238
|
+
this.inputTracker = window.TerminalInputTracker ? new window.TerminalInputTracker({
|
|
239
|
+
getFrameName: () => window.name || null,
|
|
240
|
+
getWindow: () => window
|
|
241
|
+
}) : null
|
|
242
|
+
}
|
|
243
|
+
resetInputBuffer() {
|
|
244
|
+
if (this.inputTracker) {
|
|
245
|
+
this.inputTracker.reset()
|
|
246
|
+
return
|
|
247
|
+
}
|
|
248
|
+
this.inputBuffer = ""
|
|
249
|
+
}
|
|
250
|
+
handleBackspace() {
|
|
251
|
+
if (this.inputTracker) {
|
|
252
|
+
this.inputTracker.handleBackspace()
|
|
253
|
+
return
|
|
254
|
+
}
|
|
255
|
+
if (this.inputBuffer.length > 0) {
|
|
256
|
+
this.inputBuffer = this.inputBuffer.slice(0, -1)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
captureTextInput(text) {
|
|
260
|
+
if (this.inputTracker) {
|
|
261
|
+
this.inputTracker.capture(text)
|
|
262
|
+
return
|
|
263
|
+
}
|
|
264
|
+
if (typeof text !== "string" || text.length === 0) {
|
|
265
|
+
return
|
|
266
|
+
}
|
|
267
|
+
const normalized = text.replace(/\r/g, "\n")
|
|
268
|
+
const segments = normalized.split("\n")
|
|
269
|
+
for (let i = 0; i < segments.length; i++) {
|
|
270
|
+
const segment = segments[i]
|
|
271
|
+
const isLast = (i === segments.length - 1)
|
|
272
|
+
if (!isLast) {
|
|
273
|
+
const line = this.inputBuffer + segment
|
|
274
|
+
this.inputBuffer = ""
|
|
275
|
+
this.notifyLineSubmitted(line)
|
|
276
|
+
} else {
|
|
277
|
+
this.inputBuffer += segment
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
notifyLineSubmitted(line) {
|
|
282
|
+
if (this.inputTracker) {
|
|
283
|
+
this.inputTracker.submit(line)
|
|
284
|
+
return
|
|
285
|
+
}
|
|
286
|
+
if (!window || !window.parent || typeof window.parent.postMessage !== "function") {
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
const safeLine = (line || "").replace(/[\x00-\x1F\x7F]/g, "")
|
|
290
|
+
const preview = safeLine.trim()
|
|
291
|
+
const limit = 200
|
|
292
|
+
const truncated = preview.length > limit ? preview.slice(0, limit) + "..." : preview
|
|
293
|
+
window.parent.postMessage({
|
|
294
|
+
type: "terminal-input",
|
|
295
|
+
frame: window.name || null,
|
|
296
|
+
line: truncated,
|
|
297
|
+
hasContent: truncated.length > 0
|
|
298
|
+
}, "*")
|
|
184
299
|
}
|
|
185
300
|
write(text) {
|
|
186
301
|
if (text !== "\u0007") {
|
|
@@ -199,20 +314,16 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
199
314
|
document.querySelector(".run .starting").classList.add("hidden")
|
|
200
315
|
}
|
|
201
316
|
stop() {
|
|
317
|
+
const params = {
|
|
318
|
+
uri: scriptUri || ("~" + location.pathname)
|
|
319
|
+
}
|
|
320
|
+
const runId = this.currentId || this.baseScriptId
|
|
321
|
+
if (runId) {
|
|
322
|
+
params.id = runId
|
|
323
|
+
}
|
|
202
324
|
this.socket.run({
|
|
203
325
|
method: "kernel.api.stop",
|
|
204
|
-
params
|
|
205
|
-
<% if (script_id) { %>
|
|
206
|
-
id: "<%-JSON.stringify(script_id).slice(1, -1)%>",
|
|
207
|
-
<% } %>
|
|
208
|
-
//uri: "<%-uri%>",
|
|
209
|
-
//uri: location.pathname.slice(1).replace("api/", ""),
|
|
210
|
-
<% if (script_path) { %>
|
|
211
|
-
uri: "<%-JSON.stringify(script_path).slice(1, -1)%>",
|
|
212
|
-
<% } else { %>
|
|
213
|
-
uri: "~" + location.pathname,
|
|
214
|
-
<% } %>
|
|
215
|
-
}
|
|
326
|
+
params
|
|
216
327
|
}, (stream) => {
|
|
217
328
|
})
|
|
218
329
|
}
|
|
@@ -247,30 +358,32 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
247
358
|
// await this.save()
|
|
248
359
|
await this.socket.close()
|
|
249
360
|
|
|
250
|
-
|
|
361
|
+
const searchParams = new URLSearchParams(location.search)
|
|
362
|
+
const query = Object.fromEntries(searchParams)
|
|
363
|
+
let runId = this.baseScriptId
|
|
364
|
+
if (query.session) {
|
|
365
|
+
const baseId = this.baseScriptId || (scriptUri || ("~" + location.pathname))
|
|
366
|
+
runId = `${baseId}&session=${query.session}`
|
|
367
|
+
}
|
|
368
|
+
this.currentId = runId || null
|
|
251
369
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
<% if (script_id) { %>
|
|
255
|
-
id: "<%-JSON.stringify(script_id).slice(1, -1)%>",
|
|
256
|
-
<% } %>
|
|
257
|
-
<% if (cwd) { %>
|
|
258
|
-
cwd: "<%-JSON.stringify(cwd).slice(1, -1)%>",
|
|
259
|
-
<% } %>
|
|
260
|
-
<% if (script_path) { %>
|
|
261
|
-
uri: "<%-JSON.stringify(script_path).slice(1, -1)%>",
|
|
262
|
-
<% } else { %>
|
|
263
|
-
uri: "~" + location.pathname,
|
|
264
|
-
<% } %>
|
|
265
|
-
//uri: "<%-uri%>",
|
|
370
|
+
const payload = {
|
|
371
|
+
uri: scriptUri || ("~" + location.pathname),
|
|
266
372
|
mode,
|
|
267
373
|
input: query,
|
|
268
374
|
client: {
|
|
269
375
|
cols: this.term.cols,
|
|
270
376
|
rows: this.term.rows,
|
|
271
377
|
}
|
|
272
|
-
}
|
|
273
|
-
|
|
378
|
+
}
|
|
379
|
+
if (scriptCwd) {
|
|
380
|
+
payload.cwd = scriptCwd
|
|
381
|
+
}
|
|
382
|
+
if (runId) {
|
|
383
|
+
payload.id = runId
|
|
384
|
+
payload.useId = true
|
|
385
|
+
}
|
|
386
|
+
this.socket.run(payload, async (packet) => {
|
|
274
387
|
if (packet.type === 'start') {
|
|
275
388
|
refreshParent(packet)
|
|
276
389
|
reloadMemory()
|
|
@@ -298,6 +411,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
298
411
|
</b>`
|
|
299
412
|
}
|
|
300
413
|
} else if (packet.type === "stream") {
|
|
414
|
+
refreshParent(packet)
|
|
301
415
|
// set the current shell id
|
|
302
416
|
if (packet.data.id) {
|
|
303
417
|
shell_id = packet.data.id
|
|
@@ -614,6 +728,36 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
614
728
|
n.Noty(payload)
|
|
615
729
|
}
|
|
616
730
|
} else if (packet.type === "result") {
|
|
731
|
+
if (packet.id === "terminal.upload") {
|
|
732
|
+
const uploaded = Array.isArray(packet.data && packet.data.files) ? packet.data.files : []
|
|
733
|
+
if (uploaded.length > 0) {
|
|
734
|
+
const mappedFiles = uploaded.map((file) => {
|
|
735
|
+
const displayPath = file.displayPath || file.homeRelativePath ? `~/${(file.homeRelativePath || '').replace(/^\/+/, '')}` : (file.path || '')
|
|
736
|
+
return {
|
|
737
|
+
originalName: file.originalName || file.name || file.storedAs,
|
|
738
|
+
storedAs: file.storedAs,
|
|
739
|
+
path: file.path,
|
|
740
|
+
displayPath,
|
|
741
|
+
homeRelativePath: file.homeRelativePath || '',
|
|
742
|
+
cliPath: file.cliPath || null,
|
|
743
|
+
cliRelativePath: file.cliRelativePath || null
|
|
744
|
+
}
|
|
745
|
+
})
|
|
746
|
+
refreshParent({
|
|
747
|
+
type: "terminal.upload",
|
|
748
|
+
files: mappedFiles
|
|
749
|
+
})
|
|
750
|
+
n.Noty({
|
|
751
|
+
text: mappedFiles.length > 1 ? `${mappedFiles.length} files attached` : `File attached`,
|
|
752
|
+
timeout: 4000
|
|
753
|
+
})
|
|
754
|
+
} else {
|
|
755
|
+
refreshParent({
|
|
756
|
+
type: "terminal.upload",
|
|
757
|
+
files: []
|
|
758
|
+
})
|
|
759
|
+
}
|
|
760
|
+
}
|
|
617
761
|
refreshParent(packet)
|
|
618
762
|
reloadMemory()
|
|
619
763
|
} else if (packet.type === "info") {
|
|
@@ -734,6 +878,71 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
734
878
|
<% } %>
|
|
735
879
|
await this.start(mode)
|
|
736
880
|
}
|
|
881
|
+
async uploadFiles(files, overlay) {
|
|
882
|
+
if (!files || files.length === 0) {
|
|
883
|
+
return
|
|
884
|
+
}
|
|
885
|
+
if (!this.socket || !this.socket.ws || this.socket.ws.readyState !== WebSocket.OPEN) {
|
|
886
|
+
n.Noty({
|
|
887
|
+
text: "Terminal connection is not ready for uploads",
|
|
888
|
+
type: "error"
|
|
889
|
+
})
|
|
890
|
+
return
|
|
891
|
+
}
|
|
892
|
+
const entries = []
|
|
893
|
+
for (let i = 0; i < files.length; i++) {
|
|
894
|
+
const file = files[i]
|
|
895
|
+
if (!file || typeof file.arrayBuffer !== "function") {
|
|
896
|
+
continue
|
|
897
|
+
}
|
|
898
|
+
try {
|
|
899
|
+
const arrayBuffer = await file.arrayBuffer()
|
|
900
|
+
const key = `file_${Date.now()}_${i}_${Math.random().toString(16).slice(2, 8)}`
|
|
901
|
+
entries.push({
|
|
902
|
+
key,
|
|
903
|
+
name: file.name || `upload-${i + 1}`,
|
|
904
|
+
size: file.size,
|
|
905
|
+
type: file.type || "",
|
|
906
|
+
buffer: new Uint8Array(arrayBuffer)
|
|
907
|
+
})
|
|
908
|
+
} catch (error) {
|
|
909
|
+
console.error("Failed to read dropped file", error)
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
if (entries.length === 0) {
|
|
913
|
+
n.Noty({
|
|
914
|
+
text: "No readable files were dropped",
|
|
915
|
+
type: "error"
|
|
916
|
+
})
|
|
917
|
+
return
|
|
918
|
+
}
|
|
919
|
+
const rpcPayload = {
|
|
920
|
+
method: "terminal.upload",
|
|
921
|
+
params: {
|
|
922
|
+
id: shell_id,
|
|
923
|
+
cwd: this.uploadContext.cwd,
|
|
924
|
+
files: entries.map(({ key, name, size, type }) => ({ key, name, size, type }))
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
try {
|
|
928
|
+
if (overlay) {
|
|
929
|
+
overlay.classList.add("active")
|
|
930
|
+
overlay.textContent = "Uploading..."
|
|
931
|
+
}
|
|
932
|
+
await this.socket.sendBinary(buildBinaryRpcPayload(rpcPayload, entries))
|
|
933
|
+
} catch (error) {
|
|
934
|
+
console.error("Upload failed", error)
|
|
935
|
+
n.Noty({
|
|
936
|
+
text: `Upload failed: ${error.message}`,
|
|
937
|
+
type: "error"
|
|
938
|
+
})
|
|
939
|
+
} finally {
|
|
940
|
+
if (overlay) {
|
|
941
|
+
overlay.classList.remove("active")
|
|
942
|
+
overlay.textContent = "Drop files to upload"
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
}
|
|
737
946
|
async createTerm (_theme) {
|
|
738
947
|
if (!this.term) {
|
|
739
948
|
const theme = Object.assign({ }, _theme, {
|
|
@@ -745,7 +954,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
745
954
|
<% } %>
|
|
746
955
|
let config = {
|
|
747
956
|
scrollback: 9999999,
|
|
748
|
-
|
|
957
|
+
fontSize: 12,
|
|
749
958
|
//fontSize: 14,
|
|
750
959
|
theme,
|
|
751
960
|
//theme: xtermTheme.FrontEndDelight
|
|
@@ -768,6 +977,40 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
768
977
|
}
|
|
769
978
|
const term = new Terminal(config)
|
|
770
979
|
term.open(document.querySelector("#terminal"))
|
|
980
|
+
const terminalContainer = document.querySelector("#terminal")
|
|
981
|
+
const dropOverlay = document.createElement("div")
|
|
982
|
+
dropOverlay.className = "terminal-drop-overlay"
|
|
983
|
+
dropOverlay.textContent = "Drop files to upload"
|
|
984
|
+
terminalContainer.appendChild(dropOverlay)
|
|
985
|
+
let dragDepth = 0
|
|
986
|
+
const prevent = (event) => {
|
|
987
|
+
event.preventDefault()
|
|
988
|
+
event.stopPropagation()
|
|
989
|
+
}
|
|
990
|
+
terminalContainer.addEventListener("dragenter", (event) => {
|
|
991
|
+
prevent(event)
|
|
992
|
+
dragDepth += 1
|
|
993
|
+
dropOverlay.classList.add("active")
|
|
994
|
+
})
|
|
995
|
+
terminalContainer.addEventListener("dragover", prevent)
|
|
996
|
+
terminalContainer.addEventListener("dragleave", (event) => {
|
|
997
|
+
prevent(event)
|
|
998
|
+
dragDepth = Math.max(0, dragDepth - 1)
|
|
999
|
+
if (dragDepth === 0) {
|
|
1000
|
+
dropOverlay.classList.remove("active")
|
|
1001
|
+
}
|
|
1002
|
+
})
|
|
1003
|
+
terminalContainer.addEventListener("drop", async (event) => {
|
|
1004
|
+
prevent(event)
|
|
1005
|
+
dragDepth = 0
|
|
1006
|
+
dropOverlay.classList.remove("active")
|
|
1007
|
+
const dropped = Array.from(event.dataTransfer ? event.dataTransfer.files || [] : [])
|
|
1008
|
+
if (!dropped.length) {
|
|
1009
|
+
return
|
|
1010
|
+
}
|
|
1011
|
+
await this.uploadFiles(dropped, dropOverlay)
|
|
1012
|
+
this.term.focus()
|
|
1013
|
+
})
|
|
771
1014
|
term.attachCustomKeyEventHandler(event => {
|
|
772
1015
|
if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
|
|
773
1016
|
const selection = term.getSelection();
|
|
@@ -784,6 +1027,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
784
1027
|
id: shell_id,
|
|
785
1028
|
paste: true
|
|
786
1029
|
})
|
|
1030
|
+
this.captureTextInput(text)
|
|
787
1031
|
|
|
788
1032
|
|
|
789
1033
|
// this.socket.run({
|
|
@@ -803,14 +1047,48 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
803
1047
|
////term.resize(cols, rows-5);
|
|
804
1048
|
//term.resize(cols, rows);
|
|
805
1049
|
|
|
806
|
-
term.onKey(({ key }) => {
|
|
807
|
-
if (this.socket) {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1050
|
+
term.onKey(({ key, domEvent }) => {
|
|
1051
|
+
if (this.socket && shell_id) {
|
|
1052
|
+
this.socket.run({
|
|
1053
|
+
key,
|
|
1054
|
+
id: shell_id
|
|
1055
|
+
})
|
|
1056
|
+
}
|
|
1057
|
+
if (!domEvent) {
|
|
1058
|
+
return
|
|
1059
|
+
}
|
|
1060
|
+
if (domEvent.key === "Backspace") {
|
|
1061
|
+
this.handleBackspace()
|
|
1062
|
+
return
|
|
1063
|
+
}
|
|
1064
|
+
if (domEvent.key === "Enter") {
|
|
1065
|
+
this.captureTextInput("\n")
|
|
1066
|
+
return
|
|
1067
|
+
}
|
|
1068
|
+
if (domEvent.key === "Tab") {
|
|
1069
|
+
this.captureTextInput("\t")
|
|
1070
|
+
return
|
|
1071
|
+
}
|
|
1072
|
+
if (domEvent.key === "Escape") {
|
|
1073
|
+
this.resetInputBuffer()
|
|
1074
|
+
return
|
|
1075
|
+
}
|
|
1076
|
+
if (domEvent.ctrlKey || domEvent.metaKey || domEvent.altKey) {
|
|
1077
|
+
if (key === "\u0015" || key === "\u0017" || key === "\u000b" || key === "\u0003" || domEvent.key === "c" || domEvent.key === "C" || domEvent.key === "u" || domEvent.key === "U") {
|
|
1078
|
+
this.resetInputBuffer()
|
|
813
1079
|
}
|
|
1080
|
+
return
|
|
1081
|
+
}
|
|
1082
|
+
if (key === "\u0015" || key === "\u0017" || key === "\u000b") {
|
|
1083
|
+
this.resetInputBuffer()
|
|
1084
|
+
return
|
|
1085
|
+
}
|
|
1086
|
+
if (key === "\u0008") {
|
|
1087
|
+
this.handleBackspace()
|
|
1088
|
+
return
|
|
1089
|
+
}
|
|
1090
|
+
if (typeof key === "string" && key.length === 1 && key >= " ") {
|
|
1091
|
+
this.captureTextInput(key)
|
|
814
1092
|
}
|
|
815
1093
|
});
|
|
816
1094
|
|
|
@@ -859,19 +1137,15 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
859
1137
|
<% if (mod && runnable) { %>
|
|
860
1138
|
window.addEventListener('message', function(event) {
|
|
861
1139
|
console.log("Message received from the parent: ", event.data); // Message received from parent
|
|
862
|
-
// "foreground" message
|
|
863
|
-
// Needed to fix the issue where the terminal won't write anything when in background
|
|
864
|
-
// so when coming back from background, need to refresh by just adding a newline.
|
|
1140
|
+
// "foreground" message triggers a redraw so buffered output appears after backgrounding.
|
|
865
1141
|
if (event.data && event.data.action === "foreground") {
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
rpc.term.write(delimiter)
|
|
1142
|
+
if (rpc.dirty && rpc.term) {
|
|
1143
|
+
const endRow = Math.max(rpc.term.rows - 1, 0)
|
|
1144
|
+
rpc.term.refresh(0, endRow)
|
|
1145
|
+
if (typeof rpc.term.scrollToBottom === "function") {
|
|
1146
|
+
rpc.term.scrollToBottom()
|
|
1147
|
+
}
|
|
873
1148
|
rpc.dirty = false
|
|
874
|
-
} else {
|
|
875
1149
|
}
|
|
876
1150
|
|
|
877
1151
|
//console.log("buffer", rpc.term.buffer)
|