pinokiod 3.86.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 +1 -1
- package/kernel/api/shell/index.js +6 -0
- package/kernel/api/terminal/index.js +166 -0
- 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 -15
- 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/shells.js +21 -1
- package/kernel/util.js +2 -2
- package/package.json +2 -1
- package/script/install-mode.js +33 -0
- package/script/pinokio.json +7 -0
- package/server/index.js +513 -173
- package/server/public/Socket.js +48 -0
- package/server/public/common.js +1441 -276
- 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/style.css +97 -105
- package/server/public/tab-idle-notifier.js +629 -0
- package/server/public/terminal_input_tracker.js +63 -0
- package/server/public/urldropdown.css +319 -53
- package/server/public/urldropdown.js +615 -159
- package/server/public/window_storage.js +97 -28
- package/server/socket.js +40 -9
- package/server/views/500.ejs +2 -2
- package/server/views/app.ejs +3136 -1367
- package/server/views/bookmarklet.ejs +1 -1
- package/server/views/bootstrap.ejs +1 -1
- package/server/views/columns.ejs +2 -13
- package/server/views/connect.ejs +3 -4
- package/server/views/container.ejs +1 -2
- package/server/views/d.ejs +223 -53
- package/server/views/editor.ejs +1 -1
- package/server/views/file_explorer.ejs +1 -1
- package/server/views/index.ejs +12 -11
- package/server/views/index2.ejs +4 -4
- package/server/views/init/index.ejs +4 -5
- package/server/views/install.ejs +1 -1
- package/server/views/layout.ejs +105 -0
- package/server/views/net.ejs +39 -7
- package/server/views/network.ejs +20 -6
- package/server/views/network2.ejs +1 -1
- package/server/views/old_network.ejs +2 -2
- 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 +1 -1
- package/server/views/prototype/index.ejs +1 -1
- package/server/views/review.ejs +11 -23
- package/server/views/rows.ejs +2 -13
- package/server/views/screenshots.ejs +293 -138
- package/server/views/settings.ejs +3 -4
- package/server/views/setup.ejs +1 -2
- package/server/views/shell.ejs +277 -26
- package/server/views/terminal.ejs +322 -49
- package/server/views/tools.ejs +448 -4
|
@@ -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);
|
|
@@ -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,31 +358,32 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
247
358
|
// await this.save()
|
|
248
359
|
await this.socket.close()
|
|
249
360
|
|
|
250
|
-
|
|
251
|
-
|
|
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
|
|
252
369
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
<% if (script_id) { %>
|
|
256
|
-
id: "<%-JSON.stringify(script_id).slice(1, -1)%>",
|
|
257
|
-
<% } %>
|
|
258
|
-
<% if (cwd) { %>
|
|
259
|
-
cwd: "<%-JSON.stringify(cwd).slice(1, -1)%>",
|
|
260
|
-
<% } %>
|
|
261
|
-
<% if (script_path) { %>
|
|
262
|
-
uri: "<%-JSON.stringify(script_path).slice(1, -1)%>",
|
|
263
|
-
<% } else { %>
|
|
264
|
-
uri: "~" + location.pathname,
|
|
265
|
-
<% } %>
|
|
266
|
-
//uri: "<%-uri%>",
|
|
370
|
+
const payload = {
|
|
371
|
+
uri: scriptUri || ("~" + location.pathname),
|
|
267
372
|
mode,
|
|
268
373
|
input: query,
|
|
269
374
|
client: {
|
|
270
375
|
cols: this.term.cols,
|
|
271
376
|
rows: this.term.rows,
|
|
272
377
|
}
|
|
273
|
-
}
|
|
274
|
-
|
|
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) => {
|
|
275
387
|
if (packet.type === 'start') {
|
|
276
388
|
refreshParent(packet)
|
|
277
389
|
reloadMemory()
|
|
@@ -299,6 +411,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
299
411
|
</b>`
|
|
300
412
|
}
|
|
301
413
|
} else if (packet.type === "stream") {
|
|
414
|
+
refreshParent(packet)
|
|
302
415
|
// set the current shell id
|
|
303
416
|
if (packet.data.id) {
|
|
304
417
|
shell_id = packet.data.id
|
|
@@ -615,6 +728,36 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
615
728
|
n.Noty(payload)
|
|
616
729
|
}
|
|
617
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
|
+
}
|
|
618
761
|
refreshParent(packet)
|
|
619
762
|
reloadMemory()
|
|
620
763
|
} else if (packet.type === "info") {
|
|
@@ -735,6 +878,71 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
735
878
|
<% } %>
|
|
736
879
|
await this.start(mode)
|
|
737
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
|
+
}
|
|
738
946
|
async createTerm (_theme) {
|
|
739
947
|
if (!this.term) {
|
|
740
948
|
const theme = Object.assign({ }, _theme, {
|
|
@@ -746,7 +954,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
746
954
|
<% } %>
|
|
747
955
|
let config = {
|
|
748
956
|
scrollback: 9999999,
|
|
749
|
-
|
|
957
|
+
fontSize: 12,
|
|
750
958
|
//fontSize: 14,
|
|
751
959
|
theme,
|
|
752
960
|
//theme: xtermTheme.FrontEndDelight
|
|
@@ -769,6 +977,40 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
769
977
|
}
|
|
770
978
|
const term = new Terminal(config)
|
|
771
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
|
+
})
|
|
772
1014
|
term.attachCustomKeyEventHandler(event => {
|
|
773
1015
|
if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
|
|
774
1016
|
const selection = term.getSelection();
|
|
@@ -785,6 +1027,7 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
785
1027
|
id: shell_id,
|
|
786
1028
|
paste: true
|
|
787
1029
|
})
|
|
1030
|
+
this.captureTextInput(text)
|
|
788
1031
|
|
|
789
1032
|
|
|
790
1033
|
// this.socket.run({
|
|
@@ -804,14 +1047,48 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
804
1047
|
////term.resize(cols, rows-5);
|
|
805
1048
|
//term.resize(cols, rows);
|
|
806
1049
|
|
|
807
|
-
term.onKey(({ key }) => {
|
|
808
|
-
if (this.socket) {
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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()
|
|
814
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)
|
|
815
1092
|
}
|
|
816
1093
|
});
|
|
817
1094
|
|
|
@@ -860,19 +1137,15 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
860
1137
|
<% if (mod && runnable) { %>
|
|
861
1138
|
window.addEventListener('message', function(event) {
|
|
862
1139
|
console.log("Message received from the parent: ", event.data); // Message received from parent
|
|
863
|
-
// "foreground" message
|
|
864
|
-
// Needed to fix the issue where the terminal won't write anything when in background
|
|
865
|
-
// 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.
|
|
866
1141
|
if (event.data && event.data.action === "foreground") {
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
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
|
+
}
|
|
874
1148
|
rpc.dirty = false
|
|
875
|
-
} else {
|
|
876
1149
|
}
|
|
877
1150
|
|
|
878
1151
|
//console.log("buffer", rpc.term.buffer)
|