pinokiod 3.8.0 → 3.8.5
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/kernel/api/fs/index.js +6 -4
- package/kernel/api/index.js +102 -31
- package/kernel/bin/cuda.js +7 -0
- package/kernel/bin/index.js +143 -4
- package/kernel/bin/node.js +9 -0
- package/kernel/index.js +32 -1
- package/kernel/info.js +1 -0
- package/kernel/prototype.js +47 -0
- package/kernel/shell.js +110 -54
- package/kernel/shells.js +16 -7
- package/kernel/store.js +58 -0
- package/kernel/util.js +106 -35
- package/package.json +1 -1
- package/script/index.js +12 -0
- package/server/index.js +466 -250
- package/server/public/SpaceMono-Bold.ttf +0 -0
- package/server/public/SpaceMono-BoldItalic.ttf +0 -0
- package/server/public/SpaceMono-Italic.ttf +0 -0
- package/server/public/SpaceMono-Regular.ttf +0 -0
- package/server/public/filepond-plugin-file-validate-type.min.js +9 -0
- package/server/public/filepond-plugin-image-crop.min.js +9 -0
- package/server/public/filepond-plugin-image-edit.min.css +8 -0
- package/server/public/filepond-plugin-image-edit.min.js +9 -0
- package/server/public/filepond-plugin-image-exif-orientation.min.js +9 -0
- package/server/public/filepond-plugin-image-preview.min.css +8 -0
- package/server/public/filepond-plugin-image-preview.min.js +9 -0
- package/server/public/filepond-plugin-image-resize.min.js +9 -0
- package/server/public/filepond-plugin-image-transform.min.js +9 -0
- package/server/public/filepond.min.css +8 -0
- package/server/public/filepond.min.js +9 -0
- package/server/public/fscreator.js +160 -0
- package/server/public/fseditor.js +189 -0
- package/server/public/github.png +0 -0
- package/server/public/opener.js +3 -1
- package/server/public/pinokio-black.png +0 -0
- package/server/public/pinokio-black2.png +0 -0
- package/server/public/style.css +131 -9
- package/server/socket.js +123 -37
- package/server/views/app.ejs +184 -11
- package/server/views/editor.ejs +12 -2
- package/server/views/explore.ejs +4 -3
- package/server/views/help.ejs +4 -2
- package/server/views/index.ejs +218 -80
- package/server/views/install.ejs +1 -1
- package/server/views/local_editor.ejs +282 -0
- package/server/views/minterm.ejs +687 -0
- package/server/views/partials/menu.ejs +7 -1
- package/server/views/prototypes.ejs +463 -0
- package/server/views/proxy.ejs +10 -4
- package/server/views/settings.ejs +4 -3
- package/server/views/terminal.ejs +99 -15
|
@@ -0,0 +1,687 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<head>
|
|
3
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
|
4
|
+
<script src="/hotkeys.min.js"></script>
|
|
5
|
+
<script src="/ace/ace.js"></script>
|
|
6
|
+
<script src="/noty.js"></script>
|
|
7
|
+
<script src="/notyq.js"></script>
|
|
8
|
+
<script src="/xterm.js"></script>
|
|
9
|
+
<script src="/xterm-addon-fit.js"></script>
|
|
10
|
+
<script src="/xterm-addon-web-links.js"></script>
|
|
11
|
+
<script src="/xterm-theme.js"></script>
|
|
12
|
+
<script src="/xterm-addon-search.js"></script>
|
|
13
|
+
<script src="/xterm-addon-search-bar.js"></script>
|
|
14
|
+
<script src="/sweetalert2.js"></script>
|
|
15
|
+
<script src="/Socket.js"></script>
|
|
16
|
+
<script src="/common.js"></script>
|
|
17
|
+
<script src="/he.js"></script>
|
|
18
|
+
<script src="/opener.js"></script>
|
|
19
|
+
<!--
|
|
20
|
+
<script src="/nav.js"></script>
|
|
21
|
+
-->
|
|
22
|
+
<script src="/autoexpand.js"></script>
|
|
23
|
+
<script src="/modalinput.js"></script>
|
|
24
|
+
<script src="/simplemodal.js"></script>
|
|
25
|
+
<script src="/waitmodal.js"></script>
|
|
26
|
+
<script src="/notifyinput.js"></script>
|
|
27
|
+
<script src="/report.js"></script>
|
|
28
|
+
<script src="/mark.min.js"></script>
|
|
29
|
+
<link href="/xterm.min.css" rel="stylesheet" />
|
|
30
|
+
<link href="/css/fontawesome.min.css" rel="stylesheet">
|
|
31
|
+
<link href="/css/solid.min.css" rel="stylesheet">
|
|
32
|
+
<link href="/css/regular.min.css" rel="stylesheet">
|
|
33
|
+
<link href="/css/brands.min.css" rel="stylesheet">
|
|
34
|
+
<link href="/style.css" rel="stylesheet"/>
|
|
35
|
+
<link href="/noty.css" rel="stylesheet"/>
|
|
36
|
+
<!--
|
|
37
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
38
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
39
|
+
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
|
|
40
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
41
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
42
|
+
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
|
|
43
|
+
-->
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<% if (agent === "electron") { %>
|
|
47
|
+
<link href="/electron.css" rel="stylesheet"/>
|
|
48
|
+
<% } %>
|
|
49
|
+
<style>
|
|
50
|
+
.stopped-btn {
|
|
51
|
+
background: silver;
|
|
52
|
+
}
|
|
53
|
+
html {
|
|
54
|
+
scroll-behavior: smooth;
|
|
55
|
+
height: 100%;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
}
|
|
58
|
+
body {
|
|
59
|
+
height: 100%;
|
|
60
|
+
overflow: hidden;
|
|
61
|
+
display: flex;
|
|
62
|
+
flex-direction: column;
|
|
63
|
+
}
|
|
64
|
+
#table > table {
|
|
65
|
+
border-left: 2px solid black;
|
|
66
|
+
padding-left: 5px;
|
|
67
|
+
margin: 10px 0;
|
|
68
|
+
}
|
|
69
|
+
.highlight {
|
|
70
|
+
background: yellow;
|
|
71
|
+
width: 100px;
|
|
72
|
+
}
|
|
73
|
+
th {
|
|
74
|
+
background: rgba(0,0,0,0.1);
|
|
75
|
+
padding: 10px;
|
|
76
|
+
font-size: 12px;
|
|
77
|
+
}
|
|
78
|
+
td {
|
|
79
|
+
font-size: 12px;
|
|
80
|
+
padding: 10px;
|
|
81
|
+
}
|
|
82
|
+
td.val {
|
|
83
|
+
background: rgba(0,0,0,0.06);
|
|
84
|
+
}
|
|
85
|
+
td.key {
|
|
86
|
+
background: rgba(0,0,0,0.1);
|
|
87
|
+
}
|
|
88
|
+
.button {
|
|
89
|
+
cursor: pointer;
|
|
90
|
+
background: rgba(0,0,0,0.8);
|
|
91
|
+
color: white;
|
|
92
|
+
padding: 5px 10px;
|
|
93
|
+
border-radius: 4px;
|
|
94
|
+
}
|
|
95
|
+
header {
|
|
96
|
+
position: relative;
|
|
97
|
+
padding: 10px 0;
|
|
98
|
+
}
|
|
99
|
+
.button:hover {
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
.terminal {
|
|
103
|
+
box-sizing: border-box;
|
|
104
|
+
}
|
|
105
|
+
.xterm .xterm-viewport {
|
|
106
|
+
width: initial !important;
|
|
107
|
+
}
|
|
108
|
+
/*
|
|
109
|
+
.navheader {
|
|
110
|
+
background: var(--dark-bg);
|
|
111
|
+
}
|
|
112
|
+
*/
|
|
113
|
+
/*
|
|
114
|
+
.btn {
|
|
115
|
+
background: royalblue;
|
|
116
|
+
}
|
|
117
|
+
*/
|
|
118
|
+
#del-bin {
|
|
119
|
+
color: royalblue;
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
font-weight: bold;
|
|
122
|
+
padding: 0 5px;
|
|
123
|
+
text-decoration: underline;
|
|
124
|
+
}
|
|
125
|
+
body.frozen {
|
|
126
|
+
overflow: auto !important;
|
|
127
|
+
}
|
|
128
|
+
</style>
|
|
129
|
+
<link href="/terminal.css" rel="stylesheet"/>
|
|
130
|
+
<script>
|
|
131
|
+
let shell_id
|
|
132
|
+
document.addEventListener("DOMContentLoaded", async () => {
|
|
133
|
+
const n = new N()
|
|
134
|
+
class RPC {
|
|
135
|
+
constructor() {
|
|
136
|
+
this.socket = new Socket()
|
|
137
|
+
this.buffer = []
|
|
138
|
+
}
|
|
139
|
+
write(text) {
|
|
140
|
+
if (text !== "\u0007") {
|
|
141
|
+
this.term.write(text)
|
|
142
|
+
}
|
|
143
|
+
this.dirty = true
|
|
144
|
+
}
|
|
145
|
+
finished() {
|
|
146
|
+
/*
|
|
147
|
+
n.Noty({
|
|
148
|
+
text: `[Success] All steps complete`,
|
|
149
|
+
})
|
|
150
|
+
*/
|
|
151
|
+
}
|
|
152
|
+
stop() {
|
|
153
|
+
this.socket.run({
|
|
154
|
+
method: "kernel.bin.shell_kill",
|
|
155
|
+
params: {
|
|
156
|
+
id: shell_id
|
|
157
|
+
}
|
|
158
|
+
}, (stream) => {
|
|
159
|
+
})
|
|
160
|
+
}
|
|
161
|
+
save() {
|
|
162
|
+
return new Promise((resolve, reject) => {
|
|
163
|
+
let cwd = "~" + location.pathname
|
|
164
|
+
|
|
165
|
+
this.socket.close()
|
|
166
|
+
this.socket.run({
|
|
167
|
+
method: "fs.write",
|
|
168
|
+
params: {
|
|
169
|
+
path: cwd,
|
|
170
|
+
text: str,
|
|
171
|
+
// string: str
|
|
172
|
+
// json: instructions
|
|
173
|
+
}
|
|
174
|
+
}, (packet) => {
|
|
175
|
+
if (packet.type === "result" && packet.id === "fs.write") {
|
|
176
|
+
dirty = false
|
|
177
|
+
document.querySelector("#save").classList.add("disabled")
|
|
178
|
+
resolve()
|
|
179
|
+
}
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
start(mode) {
|
|
184
|
+
return new Promise(async (resolve, reject) => {
|
|
185
|
+
// await this.save()
|
|
186
|
+
await this.socket.close()
|
|
187
|
+
|
|
188
|
+
let query = Object.fromEntries(new URLSearchParams(location.search))
|
|
189
|
+
console.log(">>>>>>>> 1")
|
|
190
|
+
|
|
191
|
+
this.socket.run({
|
|
192
|
+
method: "kernel.bin.shell_start",
|
|
193
|
+
input: true,
|
|
194
|
+
id: "<%=id%>",
|
|
195
|
+
// params: {
|
|
196
|
+
path: "<%=cwd%>",
|
|
197
|
+
// },
|
|
198
|
+
client: {
|
|
199
|
+
cols: this.term.cols,
|
|
200
|
+
rows: this.term.rows,
|
|
201
|
+
}
|
|
202
|
+
}, async (packet) => {
|
|
203
|
+
console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ", { packet })
|
|
204
|
+
if (packet.type === 'start') {
|
|
205
|
+
refreshParent(packet)
|
|
206
|
+
if (packet.data && packet.data.description) {
|
|
207
|
+
if ('current' in packet.data) {
|
|
208
|
+
document.querySelector("footer").innerHTML = `<b>
|
|
209
|
+
<i class="fa-solid fa-circle-notch fa-spin"></i>(${packet.data.current+1}/${packet.data.total}) ${packet.data.title ? packet.data.title : ''}
|
|
210
|
+
</b>
|
|
211
|
+
<div class='flexible content'>${packet.data.description}</div>`
|
|
212
|
+
// <div class='toggle-expand'>
|
|
213
|
+
// <i class="fa-solid fa-circle-chevron-up"></i>
|
|
214
|
+
// </div>`
|
|
215
|
+
} else {
|
|
216
|
+
document.querySelector("footer").innerHTML = `<b>
|
|
217
|
+
<i class="fa-solid fa-circle-notch fa-spin"></i> ${packet.data.title ? packet.data.title : ''}
|
|
218
|
+
</b>
|
|
219
|
+
<div class='flexible content'></div>`
|
|
220
|
+
// <div class='toggle-expand'>
|
|
221
|
+
// <i class="fa-solid fa-circle-chevron-up"></i>
|
|
222
|
+
// </div>`
|
|
223
|
+
}
|
|
224
|
+
} else if (packet.data && packet.data.method) {
|
|
225
|
+
document.querySelector("footer").innerHTML = `<b>
|
|
226
|
+
<i class="fa-solid fa-circle-notch fa-spin"></i> (${packet.data.current+1}/${packet.data.total}) ${packet.data.method}
|
|
227
|
+
</b>
|
|
228
|
+
<div class='flexible content'>${packet.data.params ? JSON.stringify(packet.data.params) : ''}</div>`
|
|
229
|
+
// <div class='toggle-expand'>
|
|
230
|
+
// <i class="fa-solid fa-circle-chevron-up"></i>
|
|
231
|
+
// </div>`
|
|
232
|
+
}
|
|
233
|
+
} else if (packet.type === "stream") {
|
|
234
|
+
console.log(">>>>>>>> 3")
|
|
235
|
+
// set the current shell id
|
|
236
|
+
if (packet.data.id) {
|
|
237
|
+
shell_id = packet.data.id
|
|
238
|
+
}
|
|
239
|
+
if (packet.data.raw) {
|
|
240
|
+
// console.log({ packet })
|
|
241
|
+
this.write(packet.data.raw)
|
|
242
|
+
} else if (packet.data.json) {
|
|
243
|
+
this.write(JSON.stringify(packet.data.json).replace(/\n/g, "\r\n"))
|
|
244
|
+
this.write("\r\n")
|
|
245
|
+
} else if (packet.data.json2) {
|
|
246
|
+
this.write(JSON.stringify(packet.data.json2, null, 2).replace(/\n/g, "\r\n"))
|
|
247
|
+
this.write("\r\n")
|
|
248
|
+
}
|
|
249
|
+
} else if (packet.type === 'disconnect') {
|
|
250
|
+
refreshParent(packet)
|
|
251
|
+
this.term.write("\r\nDisconnected...\r\n")
|
|
252
|
+
document.querySelector("footer").innerHTML = "<b>Ready</b>"
|
|
253
|
+
this.socket.close()
|
|
254
|
+
} else if (packet.type === 'connect') {
|
|
255
|
+
if (packet.data) {
|
|
256
|
+
if (packet.data.shell) {
|
|
257
|
+
shell_id = packet.data.shell
|
|
258
|
+
}
|
|
259
|
+
if (packet.data.state) {
|
|
260
|
+
this.write(packet.data.state)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/*
|
|
264
|
+
for(let i=0; i<message.length; i++) {
|
|
265
|
+
await new Promise((r, reject) => {
|
|
266
|
+
setTimeout(()=> {
|
|
267
|
+
this.term.write(message[i])
|
|
268
|
+
r()
|
|
269
|
+
}, 20)
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
*/
|
|
273
|
+
console.log(">>>>>>>> 2")
|
|
274
|
+
// } else if (packet.type === "key.set") {
|
|
275
|
+
// let keys = await fetch("/pinokio/keys").then((res) => {
|
|
276
|
+
// return res.json()
|
|
277
|
+
// })
|
|
278
|
+
// let input = await ModalInput({
|
|
279
|
+
// title: "Key",
|
|
280
|
+
// description: "select a key",
|
|
281
|
+
// form: [{
|
|
282
|
+
// key: "key",
|
|
283
|
+
// type: "select",
|
|
284
|
+
// items: keys,
|
|
285
|
+
// }, {
|
|
286
|
+
// key: "password",
|
|
287
|
+
// type: "password",
|
|
288
|
+
// }]
|
|
289
|
+
// })
|
|
290
|
+
// if (input) {
|
|
291
|
+
// this.socket.respond({
|
|
292
|
+
// response: input,
|
|
293
|
+
// uri: "~" + location.pathname,
|
|
294
|
+
// })
|
|
295
|
+
// }
|
|
296
|
+
} else if (packet.type === 'wait.end') {
|
|
297
|
+
try {
|
|
298
|
+
Swal.close()
|
|
299
|
+
} catch (e) {
|
|
300
|
+
}
|
|
301
|
+
this.socket.respond({
|
|
302
|
+
response: {},
|
|
303
|
+
// uri: "~" + location.pathname,
|
|
304
|
+
uri: packet.id
|
|
305
|
+
})
|
|
306
|
+
} else if (packet.type === 'wait') {
|
|
307
|
+
await WaitModal(packet.data)
|
|
308
|
+
} else if (packet.type === "modal") {
|
|
309
|
+
await SimpleModal(packet.data)
|
|
310
|
+
this.socket.respond({
|
|
311
|
+
response: {},
|
|
312
|
+
//uri: "~" + location.pathname,
|
|
313
|
+
uri: packet.id
|
|
314
|
+
})
|
|
315
|
+
} else if (packet.type === "input") {
|
|
316
|
+
let params = packet.data
|
|
317
|
+
let type = (params.type ? params.type : "modal")
|
|
318
|
+
let input
|
|
319
|
+
if (type === "modal") {
|
|
320
|
+
input = await ModalInput(packet.data)
|
|
321
|
+
} else if (type === "notify") {
|
|
322
|
+
input = await NotifyInput(packet.data, n)
|
|
323
|
+
}
|
|
324
|
+
if (input) {
|
|
325
|
+
this.socket.respond({
|
|
326
|
+
response: input,
|
|
327
|
+
uri: packet.id
|
|
328
|
+
// uri: "~" + location.pathname,
|
|
329
|
+
// uri: (packet.caller ? packet.caller : packet.id)
|
|
330
|
+
})
|
|
331
|
+
}
|
|
332
|
+
/*
|
|
333
|
+
params := {
|
|
334
|
+
title,
|
|
335
|
+
description,
|
|
336
|
+
form: [{
|
|
337
|
+
title,
|
|
338
|
+
description
|
|
339
|
+
}]
|
|
340
|
+
}
|
|
341
|
+
*/
|
|
342
|
+
} else if (packet.type === "tab.open") {
|
|
343
|
+
refreshParent(packet)
|
|
344
|
+
} else if (packet.type === "browser.open") {
|
|
345
|
+
/*
|
|
346
|
+
{
|
|
347
|
+
"method": "browser.open",
|
|
348
|
+
"params": {
|
|
349
|
+
"uri",
|
|
350
|
+
"target": "_self (default)"|"_blank"|"_parent"|"_top",
|
|
351
|
+
"features"
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
*/
|
|
355
|
+
|
|
356
|
+
///// DEPRECATE browser.open : Pinokio IS the browser. Everything opens in Pinokio. May bring back when necessary
|
|
357
|
+
// refreshParent()
|
|
358
|
+
// let params = packet.data
|
|
359
|
+
// window.open(
|
|
360
|
+
// params.uri,
|
|
361
|
+
// (params.target || "_self"),
|
|
362
|
+
// params.features
|
|
363
|
+
// )
|
|
364
|
+
} else if (packet.type === "browser.close") {
|
|
365
|
+
let params = packet.data
|
|
366
|
+
if (params && params.target) {
|
|
367
|
+
let targetWindow = window.open('', params.target)
|
|
368
|
+
if (targetWindow) {
|
|
369
|
+
targetWindow.close();
|
|
370
|
+
}
|
|
371
|
+
} else {
|
|
372
|
+
window.close()
|
|
373
|
+
}
|
|
374
|
+
} else if (packet.type === "browser") {
|
|
375
|
+
/*
|
|
376
|
+
{
|
|
377
|
+
"method": "browser.close"
|
|
378
|
+
}
|
|
379
|
+
*/
|
|
380
|
+
let { method, params } = packet.data
|
|
381
|
+
let resolved = window
|
|
382
|
+
let tokens = method.split(".")
|
|
383
|
+
for(let token of tokens) {
|
|
384
|
+
resolved = resolved[token]
|
|
385
|
+
}
|
|
386
|
+
let result = resolved(...params)
|
|
387
|
+
} else if (packet.type === "notify") {
|
|
388
|
+
/*
|
|
389
|
+
{
|
|
390
|
+
html: <notification html>,
|
|
391
|
+
href: <link location to open>,
|
|
392
|
+
target: <target for window.open()>,
|
|
393
|
+
features: <windowFeatures>, ("self" => opens in pinokio)
|
|
394
|
+
}
|
|
395
|
+
*/
|
|
396
|
+
if (packet.data) {
|
|
397
|
+
let payload = {}
|
|
398
|
+
if (packet.data.html) {
|
|
399
|
+
payload.text = packet.data.html
|
|
400
|
+
}
|
|
401
|
+
if (packet.data.type) {
|
|
402
|
+
payload.type = packet.data.type
|
|
403
|
+
}
|
|
404
|
+
payload.silent = packet.data.silent
|
|
405
|
+
payload.callbacks = {
|
|
406
|
+
onClick: () => {
|
|
407
|
+
let params = packet.data
|
|
408
|
+
if (params.href || params.uri) {
|
|
409
|
+
window.open(
|
|
410
|
+
params.uri || params.href,
|
|
411
|
+
(params.target || "_self"),
|
|
412
|
+
params.features
|
|
413
|
+
)
|
|
414
|
+
} else if (params.action === "close") {
|
|
415
|
+
if (params && params.target) {
|
|
416
|
+
let targetWindow = window.open('', params.target)
|
|
417
|
+
if (targetWindow) {
|
|
418
|
+
targetWindow.close();
|
|
419
|
+
}
|
|
420
|
+
} else {
|
|
421
|
+
window.close()
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
n.Noty(payload)
|
|
427
|
+
}
|
|
428
|
+
} else if (packet.type === "result") {
|
|
429
|
+
refreshParent(packet)
|
|
430
|
+
} else if (packet.type === "info") {
|
|
431
|
+
n.Noty({
|
|
432
|
+
text: `${packet.data}`,
|
|
433
|
+
})
|
|
434
|
+
} else if (packet.type === "error") {
|
|
435
|
+
// n.Noty({
|
|
436
|
+
// text: `${packet.data}`,
|
|
437
|
+
// type: "error"
|
|
438
|
+
// })
|
|
439
|
+
|
|
440
|
+
// this.socket.close()
|
|
441
|
+
// refreshParent(packet)
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
//document.querySelector("footer .content").innerHTML = document.querySelector("footer .content").innerHTML + `<pre class='error'>${packet.data}</pre>`
|
|
446
|
+
document.querySelector("footer .content").innerHTML = document.querySelector("footer .content").innerHTML + `<pre class='error'>ERROR</pre>`
|
|
447
|
+
// document.querySelector("footer .toggle-expand i").className = "fa-solid fa-circle-chevron-down"
|
|
448
|
+
// document.querySelector("footer").classList.add("expanded")
|
|
449
|
+
document.querySelector("footer i").className = "fa-solid fa-triangle-exclamation"
|
|
450
|
+
|
|
451
|
+
document.querySelector("#error-screen").classList.remove("hidden")
|
|
452
|
+
document.querySelector("#error-screen pre").textContent = packet.data
|
|
453
|
+
let instance = new Mark(document.querySelector("#error-screen pre"), {
|
|
454
|
+
separateWordSearch: false,
|
|
455
|
+
accuracy: "exactly"
|
|
456
|
+
})
|
|
457
|
+
/*
|
|
458
|
+
document.querySelector("#error-screen").addEventListener("click", (e) => {
|
|
459
|
+
document.querySelector("#error-screen").classList.add("hidden")
|
|
460
|
+
})
|
|
461
|
+
*/
|
|
462
|
+
instance.mark(packet.event)
|
|
463
|
+
let element = document.querySelector("mark")
|
|
464
|
+
element.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
} else if (packet.type === "event") {
|
|
470
|
+
if (packet.data === "stop") {
|
|
471
|
+
document.querySelector("footer").innerHTML = "<b>Ready</b>"
|
|
472
|
+
setTimeout(() => {
|
|
473
|
+
|
|
474
|
+
let params = new URLSearchParams(location.search)
|
|
475
|
+
let entries = [...params.entries()]
|
|
476
|
+
let options;
|
|
477
|
+
if (entries.length > 0) {
|
|
478
|
+
options = {}
|
|
479
|
+
for(const [key, value] of entries) {
|
|
480
|
+
options[key] = value;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (options && options.html) {
|
|
484
|
+
n.Noty({
|
|
485
|
+
text: options.html,
|
|
486
|
+
timeout: 3000,
|
|
487
|
+
callbacks: {
|
|
488
|
+
onClose: () => {
|
|
489
|
+
let uri = options.uri || options.href
|
|
490
|
+
if (uri) {
|
|
491
|
+
let target = options.target || "_self"
|
|
492
|
+
let features = options.features
|
|
493
|
+
window.open(uri, target, features)
|
|
494
|
+
} else if (options.action === "close") {
|
|
495
|
+
window.close()
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
})
|
|
500
|
+
}
|
|
501
|
+
/*
|
|
502
|
+
n.Noty({
|
|
503
|
+
text: '[Notice] finished',
|
|
504
|
+
type: 'success'
|
|
505
|
+
})
|
|
506
|
+
*/
|
|
507
|
+
}, 0)
|
|
508
|
+
//this.socket.close()
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Get the available space for the terminal
|
|
513
|
+
// let terminalContainer = document.querySelector("#terminal")
|
|
514
|
+
// const availableHeight = terminalContainer.clientHeight;
|
|
515
|
+
//
|
|
516
|
+
// // Calculate the number of columns and rows the terminal should have
|
|
517
|
+
// console.log(this.term)
|
|
518
|
+
// //const rows = Math.floor(availableHeight / this.term._core.viewport._charSizeService.height);
|
|
519
|
+
// const rows = Math.floor(this.term._core.viewport._lastRecordedViewportHeight / this.term._core.viewport._charSizeService.height);
|
|
520
|
+
//
|
|
521
|
+
//
|
|
522
|
+
// // Resize the terminal
|
|
523
|
+
// this.term.resize(this.term.cols, rows);
|
|
524
|
+
// this.term.scrollToLine(this.term.rows-1);
|
|
525
|
+
// this.fit.fit()
|
|
526
|
+
// let pageBottom = document.querySelector("#end")
|
|
527
|
+
// pageBottom.scrollIntoView()
|
|
528
|
+
})
|
|
529
|
+
})
|
|
530
|
+
}
|
|
531
|
+
async run (mode) {
|
|
532
|
+
this.mode = (mode ? mode : "run")
|
|
533
|
+
|
|
534
|
+
// if (dirty) {
|
|
535
|
+
// await this.save()
|
|
536
|
+
// n.Noty({
|
|
537
|
+
// text: `script updated`,
|
|
538
|
+
// })
|
|
539
|
+
// }
|
|
540
|
+
|
|
541
|
+
await this.createTerm()
|
|
542
|
+
await this.start(mode)
|
|
543
|
+
}
|
|
544
|
+
async createTerm () {
|
|
545
|
+
console.log(xtermTheme)
|
|
546
|
+
if (!this.term) {
|
|
547
|
+
const theme = Object.assign({ }, xtermTheme.Terminal_Basic, {
|
|
548
|
+
selectionBackground: "red",
|
|
549
|
+
selectionForeground: "white"
|
|
550
|
+
})
|
|
551
|
+
|
|
552
|
+
let config = {
|
|
553
|
+
scrollback: 9999999,
|
|
554
|
+
//fontSize: 12,
|
|
555
|
+
fontSize: 14,
|
|
556
|
+
theme,
|
|
557
|
+
//theme: xtermTheme.FrontEndDelight
|
|
558
|
+
//theme: xtermTheme.Afterglow
|
|
559
|
+
|
|
560
|
+
//theme: xtermTheme.PencilLight
|
|
561
|
+
|
|
562
|
+
//theme: xtermTheme.Flatland
|
|
563
|
+
//theme: xtermTheme.OneHalfLight
|
|
564
|
+
//theme: xtermTheme.Piatto_Light
|
|
565
|
+
//theme: xtermTheme.Spring
|
|
566
|
+
//theme: xtermTheme.Terminal_Basic
|
|
567
|
+
//theme: xtermTheme.Tomorrow
|
|
568
|
+
}
|
|
569
|
+
let res = await fetch("/xterm_config").then((res) => {
|
|
570
|
+
return res.json()
|
|
571
|
+
})
|
|
572
|
+
if (res && res.config) {
|
|
573
|
+
config = res.config
|
|
574
|
+
}
|
|
575
|
+
const term = new Terminal(config)
|
|
576
|
+
term.open(document.querySelector("#terminal"))
|
|
577
|
+
term.attachCustomKeyEventHandler(event => {
|
|
578
|
+
console.log({ event })
|
|
579
|
+
if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
|
|
580
|
+
const selection = term.getSelection();
|
|
581
|
+
if (selection) {
|
|
582
|
+
navigator.clipboard.writeText(selection);
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
if ((event.ctrlKey || event.metaKey) && event.key === 'v') {
|
|
587
|
+
navigator.clipboard.readText().then((text) => {
|
|
588
|
+
term.write(text);
|
|
589
|
+
})
|
|
590
|
+
return false
|
|
591
|
+
}
|
|
592
|
+
return true;
|
|
593
|
+
});
|
|
594
|
+
//const rows = Math.floor(document.querySelector("#terminal").clientHeight / term._core.viewport._charSizeService.height);
|
|
595
|
+
//const cols = Math.floor(document.querySelector("#terminal").clientHeight / term._core.viewport._charSizeService.width);
|
|
596
|
+
//console.log(cols, term.cols)
|
|
597
|
+
// // Resize the terminal
|
|
598
|
+
////term.resize(cols, rows-5);
|
|
599
|
+
//term.resize(cols, rows);
|
|
600
|
+
|
|
601
|
+
term.onKey(({ key }) => {
|
|
602
|
+
console.log({ key, shell_id })
|
|
603
|
+
if (this.socket) {
|
|
604
|
+
if (shell_id) {
|
|
605
|
+
this.socket.run({
|
|
606
|
+
key,
|
|
607
|
+
id: shell_id
|
|
608
|
+
})
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
const fitAddon = new FitAddon.FitAddon();
|
|
614
|
+
// const searchAddon = new SearchAddon.SearchAddon();
|
|
615
|
+
// const searchAddonBar = new SearchBarAddon.SearchBarAddon({searchAddon});
|
|
616
|
+
term.loadAddon(fitAddon);
|
|
617
|
+
<% if (agent === "electron") { %>
|
|
618
|
+
term.loadAddon(new WebLinksAddon.WebLinksAddon((event, uri) => {
|
|
619
|
+
window.open(uri, "_blank")
|
|
620
|
+
}))
|
|
621
|
+
<% } else { %>
|
|
622
|
+
term.loadAddon(new WebLinksAddon.WebLinksAddon());
|
|
623
|
+
<% } %>
|
|
624
|
+
// term.loadAddon(searchAddon)
|
|
625
|
+
// term.loadAddon(searchAddonBar);
|
|
626
|
+
// searchAddonBar.show();
|
|
627
|
+
fitAddon.fit();
|
|
628
|
+
this.term = term
|
|
629
|
+
this.fit = fitAddon
|
|
630
|
+
|
|
631
|
+
}
|
|
632
|
+
this.term.focus()
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
const rpc = new RPC()
|
|
636
|
+
document.querySelector(".stop").addEventListener("click", async (e) => {
|
|
637
|
+
await rpc.stop()
|
|
638
|
+
// socket.run({
|
|
639
|
+
// id: location.pathname,
|
|
640
|
+
// method: "kernel.api.stop"
|
|
641
|
+
// }, (stream) => {
|
|
642
|
+
// console.log("#", stream)
|
|
643
|
+
// })
|
|
644
|
+
/*
|
|
645
|
+
document.querySelector(".run .play").classList.remove("hidden")
|
|
646
|
+
document.querySelector(".run .starting").classList.add("hidden")
|
|
647
|
+
*/
|
|
648
|
+
document.querySelector(".stop-btn").classList.add("hidden")
|
|
649
|
+
document.querySelector(".stopped-btn").classList.remove("hidden")
|
|
650
|
+
})
|
|
651
|
+
|
|
652
|
+
window.addEventListener('message', function(event) {
|
|
653
|
+
console.log("Message received from the parent: ", event.data); // Message received from parent
|
|
654
|
+
// "foreground" message adds a newline to the terminal
|
|
655
|
+
// Needed to fix the issue where the terminal won't write anything when in background
|
|
656
|
+
// so when coming back from background, need to refresh by just adding a newline.
|
|
657
|
+
if (event.data && event.data.action === "foreground") {
|
|
658
|
+
// if dirty, update
|
|
659
|
+
// if not dirty, don't update
|
|
660
|
+
const delimiter = "\r\n"
|
|
661
|
+
if (rpc.dirty) {
|
|
662
|
+
rpc.term.write(delimiter)
|
|
663
|
+
rpc.dirty = false
|
|
664
|
+
} else {
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
rpc.run()
|
|
669
|
+
})
|
|
670
|
+
|
|
671
|
+
</script>
|
|
672
|
+
</head>
|
|
673
|
+
<body class='<%=theme%>'>
|
|
674
|
+
<header class='navheader2'>
|
|
675
|
+
<div class='btn run stop-btn'>
|
|
676
|
+
<span class='stop'><i class="fa-solid fa-stop"></i> Stop</span>
|
|
677
|
+
</div>
|
|
678
|
+
<div class='btn stopped-btn hidden'>
|
|
679
|
+
<span class='stopped'><i class="fa-solid fa-hand"></i> Stopped</span>
|
|
680
|
+
</div>
|
|
681
|
+
</header>
|
|
682
|
+
<div class='terminal-container'>
|
|
683
|
+
<div id='terminal'></div>
|
|
684
|
+
</div>
|
|
685
|
+
<footer><b>Ready</b></footer>
|
|
686
|
+
</body>
|
|
687
|
+
</html>
|