pinokiod 3.193.0 → 3.194.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/package.json +1 -1
- package/server/views/shell.ejs +167 -31
- package/server/views/terminal.ejs +167 -31
package/package.json
CHANGED
package/server/views/shell.ejs
CHANGED
|
@@ -1163,20 +1163,111 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1163
1163
|
dropOverlay.className = "terminal-drop-overlay"
|
|
1164
1164
|
dropOverlay.textContent = "Drop files to upload"
|
|
1165
1165
|
terminalContainer.appendChild(dropOverlay)
|
|
1166
|
-
const
|
|
1166
|
+
const dedupeClipboardFiles = (inputs) => {
|
|
1167
1167
|
const seen = new Set()
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1168
|
+
const results = []
|
|
1169
|
+
inputs.forEach((file) => {
|
|
1170
|
+
if (!file || !(file instanceof File) || !(file.size > 0)) {
|
|
1171
|
+
return
|
|
1171
1172
|
}
|
|
1172
|
-
const
|
|
1173
|
-
if (
|
|
1174
|
-
return
|
|
1173
|
+
const signature = `${file.name || ''}::${file.size || 0}::${file.type || ''}`
|
|
1174
|
+
if (seen.has(signature)) {
|
|
1175
|
+
return
|
|
1175
1176
|
}
|
|
1176
|
-
seen.add(
|
|
1177
|
-
|
|
1177
|
+
seen.add(signature)
|
|
1178
|
+
results.push(file)
|
|
1178
1179
|
})
|
|
1180
|
+
return results
|
|
1181
|
+
}
|
|
1182
|
+
const collectClipboardFiles = (clipboardData) => {
|
|
1183
|
+
const files = []
|
|
1184
|
+
let hasFileFlavor = false
|
|
1185
|
+
if (!clipboardData) {
|
|
1186
|
+
return { files, hasFileFlavor }
|
|
1187
|
+
}
|
|
1188
|
+
try {
|
|
1189
|
+
const types = clipboardData.types ? Array.from(clipboardData.types) : []
|
|
1190
|
+
hasFileFlavor = types.some((type) => type === "Files" || type === "application/x-moz-file")
|
|
1191
|
+
} catch (_) {}
|
|
1192
|
+
try {
|
|
1193
|
+
Array.from(clipboardData.files || []).forEach((file) => {
|
|
1194
|
+
if (file && file.size > 0) {
|
|
1195
|
+
files.push(file)
|
|
1196
|
+
}
|
|
1197
|
+
})
|
|
1198
|
+
} catch (_) {}
|
|
1199
|
+
try {
|
|
1200
|
+
const items = clipboardData.items ? Array.from(clipboardData.items) : []
|
|
1201
|
+
items.forEach((item) => {
|
|
1202
|
+
if (!item || item.kind !== "file" || typeof item.getAsFile !== "function") {
|
|
1203
|
+
return
|
|
1204
|
+
}
|
|
1205
|
+
try {
|
|
1206
|
+
const file = item.getAsFile()
|
|
1207
|
+
if (file && file.size > 0) {
|
|
1208
|
+
files.push(file)
|
|
1209
|
+
}
|
|
1210
|
+
} catch (_) {}
|
|
1211
|
+
})
|
|
1212
|
+
} catch (_) {}
|
|
1213
|
+
return { files: dedupeClipboardFiles(files), hasFileFlavor }
|
|
1214
|
+
}
|
|
1215
|
+
const readClipboardFilesFallback = async () => {
|
|
1216
|
+
if (!navigator.clipboard || typeof navigator.clipboard.read !== "function") {
|
|
1217
|
+
return []
|
|
1218
|
+
}
|
|
1219
|
+
try {
|
|
1220
|
+
const clipboardItems = await navigator.clipboard.read()
|
|
1221
|
+
const collected = []
|
|
1222
|
+
let index = 0
|
|
1223
|
+
for (const item of clipboardItems) {
|
|
1224
|
+
if (!item || !Array.isArray(item.types)) {
|
|
1225
|
+
index += 1
|
|
1226
|
+
continue
|
|
1227
|
+
}
|
|
1228
|
+
const types = item.types
|
|
1229
|
+
const preferredType = types.find((type) => type && !type.startsWith("text/"))
|
|
1230
|
+
|| types.find((type) => /^image\//i.test(type))
|
|
1231
|
+
|| types[0]
|
|
1232
|
+
if (!preferredType) {
|
|
1233
|
+
index += 1
|
|
1234
|
+
continue
|
|
1235
|
+
}
|
|
1236
|
+
try {
|
|
1237
|
+
const blob = await item.getType(preferredType)
|
|
1238
|
+
if (!blob) {
|
|
1239
|
+
index += 1
|
|
1240
|
+
continue
|
|
1241
|
+
}
|
|
1242
|
+
let name = typeof item.name === "string" && item.name ? item.name : ""
|
|
1243
|
+
if (!name) {
|
|
1244
|
+
const ext = preferredType && preferredType.includes("/") ? preferredType.split("/").pop() : ""
|
|
1245
|
+
const safeExt = ext ? ext.replace(/[^a-z0-9]/gi, "").toLowerCase() : ""
|
|
1246
|
+
name = `clipboard-${Date.now()}-${index}${safeExt ? `.${safeExt}` : ""}`
|
|
1247
|
+
}
|
|
1248
|
+
const file = blob instanceof File ? blob : new File([blob], name, {
|
|
1249
|
+
type: blob.type || preferredType,
|
|
1250
|
+
lastModified: Date.now()
|
|
1251
|
+
})
|
|
1252
|
+
if (file && file.size > 0) {
|
|
1253
|
+
collected.push(file)
|
|
1254
|
+
}
|
|
1255
|
+
} catch (error) {
|
|
1256
|
+
if (error && error.name !== "NotAllowedError") {
|
|
1257
|
+
console.warn("Failed to extract clipboard blob", error)
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
index += 1
|
|
1261
|
+
}
|
|
1262
|
+
return dedupeClipboardFiles(collected)
|
|
1263
|
+
} catch (error) {
|
|
1264
|
+
if (error && error.name !== "NotAllowedError") {
|
|
1265
|
+
console.warn("navigator.clipboard.read() failed", error)
|
|
1266
|
+
}
|
|
1267
|
+
return []
|
|
1268
|
+
}
|
|
1179
1269
|
}
|
|
1270
|
+
let suppressClipboardText = false
|
|
1180
1271
|
let dragDepth = 0
|
|
1181
1272
|
const prevent = (event) => {
|
|
1182
1273
|
event.preventDefault()
|
|
@@ -1203,7 +1294,20 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1203
1294
|
let remoteResources = []
|
|
1204
1295
|
try {
|
|
1205
1296
|
const extra = await this.collectFilesFromDataTransfer(event.dataTransfer)
|
|
1206
|
-
|
|
1297
|
+
if (extra && Array.isArray(extra.urls) && extra.urls.length) {
|
|
1298
|
+
const seenUrls = new Set()
|
|
1299
|
+
remoteResources = extra.urls.filter((item) => {
|
|
1300
|
+
if (!item || typeof item.href !== "string") {
|
|
1301
|
+
return false
|
|
1302
|
+
}
|
|
1303
|
+
const key = item.href.trim()
|
|
1304
|
+
if (!key || seenUrls.has(key)) {
|
|
1305
|
+
return false
|
|
1306
|
+
}
|
|
1307
|
+
seenUrls.add(key)
|
|
1308
|
+
return true
|
|
1309
|
+
})
|
|
1310
|
+
}
|
|
1207
1311
|
} catch (error) {
|
|
1208
1312
|
console.warn("Failed to collect files from drop payload", error)
|
|
1209
1313
|
}
|
|
@@ -1223,23 +1327,50 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1223
1327
|
this.term.focus()
|
|
1224
1328
|
})
|
|
1225
1329
|
terminalContainer.addEventListener("paste", async (event) => {
|
|
1226
|
-
const clipboard = event.clipboardData
|
|
1227
|
-
|
|
1228
|
-
|
|
1330
|
+
const clipboard = event && event.clipboardData ? event.clipboardData : null
|
|
1331
|
+
const clipboardTypes = clipboard ? Array.from(clipboard.types || []) : []
|
|
1332
|
+
const hasFileLikeType = clipboardTypes.some((type) => {
|
|
1333
|
+
if (!type) {
|
|
1334
|
+
return false
|
|
1335
|
+
}
|
|
1336
|
+
const lower = type.toLowerCase()
|
|
1337
|
+
return lower === "text/uri-list" || lower === "text/html" || lower === "downloadurl" || lower === "text/x-moz-url" || lower.startsWith("image/")
|
|
1338
|
+
})
|
|
1339
|
+
const { files: directFiles, hasFileFlavor } = collectClipboardFiles(clipboard)
|
|
1340
|
+
let files = directFiles
|
|
1341
|
+
if (files.length === 0 && !hasFileFlavor && hasFileLikeType) {
|
|
1342
|
+
files = await readClipboardFilesFallback()
|
|
1229
1343
|
}
|
|
1230
|
-
const
|
|
1344
|
+
const allowUrlCollection = hasFileLikeType
|
|
1231
1345
|
let remoteResources = []
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1346
|
+
if (files.length === 0 && allowUrlCollection) {
|
|
1347
|
+
try {
|
|
1348
|
+
const extra = await this.collectFilesFromDataTransfer(clipboard)
|
|
1349
|
+
if (extra && Array.isArray(extra.urls) && extra.urls.length) {
|
|
1350
|
+
const seen = new Set()
|
|
1351
|
+
remoteResources = extra.urls.filter((item) => {
|
|
1352
|
+
if (!item || typeof item.href !== "string") {
|
|
1353
|
+
return false
|
|
1354
|
+
}
|
|
1355
|
+
const key = item.href.trim()
|
|
1356
|
+
if (!key || seen.has(key)) {
|
|
1357
|
+
return false
|
|
1358
|
+
}
|
|
1359
|
+
seen.add(key)
|
|
1360
|
+
return true
|
|
1361
|
+
})
|
|
1362
|
+
}
|
|
1363
|
+
} catch (error) {
|
|
1364
|
+
console.warn("Failed to collect clipboard resources", error)
|
|
1365
|
+
}
|
|
1237
1366
|
}
|
|
1238
|
-
if (
|
|
1367
|
+
if (files.length === 0 && (!remoteResources || remoteResources.length === 0)) {
|
|
1368
|
+
suppressClipboardText = false
|
|
1239
1369
|
return
|
|
1240
1370
|
}
|
|
1241
1371
|
event.preventDefault()
|
|
1242
1372
|
event.stopPropagation()
|
|
1373
|
+
suppressClipboardText = true
|
|
1243
1374
|
try {
|
|
1244
1375
|
if (remoteResources && remoteResources.length > 0) {
|
|
1245
1376
|
await this.uploadRemoteResources(remoteResources, dropOverlay)
|
|
@@ -1248,10 +1379,12 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1248
1379
|
console.warn("Clipboard remote upload failed", error)
|
|
1249
1380
|
}
|
|
1250
1381
|
if (files.length > 0) {
|
|
1251
|
-
await this.uploadFiles(files, dropOverlay)
|
|
1382
|
+
await this.uploadFiles(files, dropOverlay).catch((error) => {
|
|
1383
|
+
console.warn("Clipboard upload failed", error)
|
|
1384
|
+
})
|
|
1252
1385
|
}
|
|
1253
1386
|
this.term.focus()
|
|
1254
|
-
})
|
|
1387
|
+
}, true)
|
|
1255
1388
|
term.attachCustomKeyEventHandler(event => {
|
|
1256
1389
|
if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
|
|
1257
1390
|
const selection = term.getSelection();
|
|
@@ -1261,16 +1394,19 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1261
1394
|
}
|
|
1262
1395
|
}
|
|
1263
1396
|
if ((event.ctrlKey || event.metaKey) && event.key === 'v') {
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1397
|
+
if (!suppressClipboardText) {
|
|
1398
|
+
navigator.clipboard.readText().then((text) => {
|
|
1399
|
+
this.socket.run({
|
|
1400
|
+
//key: "\x1b[200~" + text + "\x1b[201~",
|
|
1401
|
+
key: text,
|
|
1402
|
+
id: shell_id,
|
|
1403
|
+
paste: true
|
|
1404
|
+
})
|
|
1405
|
+
this.captureTextInput(text)
|
|
1272
1406
|
|
|
1273
|
-
|
|
1407
|
+
})
|
|
1408
|
+
}
|
|
1409
|
+
suppressClipboardText = false
|
|
1274
1410
|
return false
|
|
1275
1411
|
}
|
|
1276
1412
|
return true;
|
|
@@ -1256,20 +1256,111 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1256
1256
|
dropOverlay.className = "terminal-drop-overlay"
|
|
1257
1257
|
dropOverlay.textContent = "Drop files to upload"
|
|
1258
1258
|
terminalContainer.appendChild(dropOverlay)
|
|
1259
|
-
const
|
|
1259
|
+
const dedupeClipboardFiles = (inputs) => {
|
|
1260
1260
|
const seen = new Set()
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1261
|
+
const results = []
|
|
1262
|
+
inputs.forEach((file) => {
|
|
1263
|
+
if (!file || !(file instanceof File) || !(file.size > 0)) {
|
|
1264
|
+
return
|
|
1264
1265
|
}
|
|
1265
|
-
const
|
|
1266
|
-
if (
|
|
1267
|
-
return
|
|
1266
|
+
const signature = `${file.name || ''}::${file.size || 0}::${file.type || ''}`
|
|
1267
|
+
if (seen.has(signature)) {
|
|
1268
|
+
return
|
|
1268
1269
|
}
|
|
1269
|
-
seen.add(
|
|
1270
|
-
|
|
1270
|
+
seen.add(signature)
|
|
1271
|
+
results.push(file)
|
|
1271
1272
|
})
|
|
1273
|
+
return results
|
|
1274
|
+
}
|
|
1275
|
+
const collectClipboardFiles = (clipboardData) => {
|
|
1276
|
+
const files = []
|
|
1277
|
+
let hasFileFlavor = false
|
|
1278
|
+
if (!clipboardData) {
|
|
1279
|
+
return { files, hasFileFlavor }
|
|
1280
|
+
}
|
|
1281
|
+
try {
|
|
1282
|
+
const types = clipboardData.types ? Array.from(clipboardData.types) : []
|
|
1283
|
+
hasFileFlavor = types.some((type) => type === "Files" || type === "application/x-moz-file")
|
|
1284
|
+
} catch (_) {}
|
|
1285
|
+
try {
|
|
1286
|
+
Array.from(clipboardData.files || []).forEach((file) => {
|
|
1287
|
+
if (file && file.size > 0) {
|
|
1288
|
+
files.push(file)
|
|
1289
|
+
}
|
|
1290
|
+
})
|
|
1291
|
+
} catch (_) {}
|
|
1292
|
+
try {
|
|
1293
|
+
const items = clipboardData.items ? Array.from(clipboardData.items) : []
|
|
1294
|
+
items.forEach((item) => {
|
|
1295
|
+
if (!item || item.kind !== "file" || typeof item.getAsFile !== "function") {
|
|
1296
|
+
return
|
|
1297
|
+
}
|
|
1298
|
+
try {
|
|
1299
|
+
const file = item.getAsFile()
|
|
1300
|
+
if (file && file.size > 0) {
|
|
1301
|
+
files.push(file)
|
|
1302
|
+
}
|
|
1303
|
+
} catch (_) {}
|
|
1304
|
+
})
|
|
1305
|
+
} catch (_) {}
|
|
1306
|
+
return { files: dedupeClipboardFiles(files), hasFileFlavor }
|
|
1307
|
+
}
|
|
1308
|
+
const readClipboardFilesFallback = async () => {
|
|
1309
|
+
if (!navigator.clipboard || typeof navigator.clipboard.read !== "function") {
|
|
1310
|
+
return []
|
|
1311
|
+
}
|
|
1312
|
+
try {
|
|
1313
|
+
const clipboardItems = await navigator.clipboard.read()
|
|
1314
|
+
const collected = []
|
|
1315
|
+
let index = 0
|
|
1316
|
+
for (const item of clipboardItems) {
|
|
1317
|
+
if (!item || !Array.isArray(item.types)) {
|
|
1318
|
+
index += 1
|
|
1319
|
+
continue
|
|
1320
|
+
}
|
|
1321
|
+
const types = item.types
|
|
1322
|
+
const preferredType = types.find((type) => type && !type.startsWith("text/"))
|
|
1323
|
+
|| types.find((type) => /^image\//i.test(type))
|
|
1324
|
+
|| types[0]
|
|
1325
|
+
if (!preferredType) {
|
|
1326
|
+
index += 1
|
|
1327
|
+
continue
|
|
1328
|
+
}
|
|
1329
|
+
try {
|
|
1330
|
+
const blob = await item.getType(preferredType)
|
|
1331
|
+
if (!blob) {
|
|
1332
|
+
index += 1
|
|
1333
|
+
continue
|
|
1334
|
+
}
|
|
1335
|
+
let name = typeof item.name === "string" && item.name ? item.name : ""
|
|
1336
|
+
if (!name) {
|
|
1337
|
+
const ext = preferredType && preferredType.includes("/") ? preferredType.split("/").pop() : ""
|
|
1338
|
+
const safeExt = ext ? ext.replace(/[^a-z0-9]/gi, "").toLowerCase() : ""
|
|
1339
|
+
name = `clipboard-${Date.now()}-${index}${safeExt ? `.${safeExt}` : ""}`
|
|
1340
|
+
}
|
|
1341
|
+
const file = blob instanceof File ? blob : new File([blob], name, {
|
|
1342
|
+
type: blob.type || preferredType,
|
|
1343
|
+
lastModified: Date.now()
|
|
1344
|
+
})
|
|
1345
|
+
if (file && file.size > 0) {
|
|
1346
|
+
collected.push(file)
|
|
1347
|
+
}
|
|
1348
|
+
} catch (error) {
|
|
1349
|
+
if (error && error.name !== "NotAllowedError") {
|
|
1350
|
+
console.warn("Failed to extract clipboard blob", error)
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
index += 1
|
|
1354
|
+
}
|
|
1355
|
+
return dedupeClipboardFiles(collected)
|
|
1356
|
+
} catch (error) {
|
|
1357
|
+
if (error && error.name !== "NotAllowedError") {
|
|
1358
|
+
console.warn("navigator.clipboard.read() failed", error)
|
|
1359
|
+
}
|
|
1360
|
+
return []
|
|
1361
|
+
}
|
|
1272
1362
|
}
|
|
1363
|
+
let suppressClipboardText = false
|
|
1273
1364
|
let dragDepth = 0
|
|
1274
1365
|
const prevent = (event) => {
|
|
1275
1366
|
event.preventDefault()
|
|
@@ -1296,7 +1387,20 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1296
1387
|
let remoteResources = []
|
|
1297
1388
|
try {
|
|
1298
1389
|
const extra = await this.collectFilesFromDataTransfer(event.dataTransfer)
|
|
1299
|
-
|
|
1390
|
+
if (extra && Array.isArray(extra.urls) && extra.urls.length) {
|
|
1391
|
+
const seenUrls = new Set()
|
|
1392
|
+
remoteResources = extra.urls.filter((item) => {
|
|
1393
|
+
if (!item || typeof item.href !== "string") {
|
|
1394
|
+
return false
|
|
1395
|
+
}
|
|
1396
|
+
const key = item.href.trim()
|
|
1397
|
+
if (!key || seenUrls.has(key)) {
|
|
1398
|
+
return false
|
|
1399
|
+
}
|
|
1400
|
+
seenUrls.add(key)
|
|
1401
|
+
return true
|
|
1402
|
+
})
|
|
1403
|
+
}
|
|
1300
1404
|
} catch (error) {
|
|
1301
1405
|
console.warn("Failed to collect files from drop payload", error)
|
|
1302
1406
|
}
|
|
@@ -1320,23 +1424,50 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1320
1424
|
this.term.focus()
|
|
1321
1425
|
})
|
|
1322
1426
|
terminalContainer.addEventListener("paste", async (event) => {
|
|
1323
|
-
const clipboard = event.clipboardData
|
|
1324
|
-
|
|
1325
|
-
|
|
1427
|
+
const clipboard = event && event.clipboardData ? event.clipboardData : null
|
|
1428
|
+
const clipboardTypes = clipboard ? Array.from(clipboard.types || []) : []
|
|
1429
|
+
const hasFileLikeType = clipboardTypes.some((type) => {
|
|
1430
|
+
if (!type) {
|
|
1431
|
+
return false
|
|
1432
|
+
}
|
|
1433
|
+
const lower = type.toLowerCase()
|
|
1434
|
+
return lower === "text/uri-list" || lower === "text/html" || lower === "downloadurl" || lower === "text/x-moz-url" || lower.startsWith("image/")
|
|
1435
|
+
})
|
|
1436
|
+
const { files: directFiles, hasFileFlavor } = collectClipboardFiles(clipboard)
|
|
1437
|
+
let files = directFiles
|
|
1438
|
+
if (files.length === 0 && !hasFileFlavor && hasFileLikeType) {
|
|
1439
|
+
files = await readClipboardFilesFallback()
|
|
1326
1440
|
}
|
|
1327
|
-
const
|
|
1441
|
+
const allowUrlCollection = hasFileLikeType
|
|
1328
1442
|
let remoteResources = []
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1443
|
+
if (files.length === 0 && allowUrlCollection) {
|
|
1444
|
+
try {
|
|
1445
|
+
const extra = await this.collectFilesFromDataTransfer(clipboard)
|
|
1446
|
+
if (extra && Array.isArray(extra.urls) && extra.urls.length) {
|
|
1447
|
+
const seen = new Set()
|
|
1448
|
+
remoteResources = extra.urls.filter((item) => {
|
|
1449
|
+
if (!item || typeof item.href !== "string") {
|
|
1450
|
+
return false
|
|
1451
|
+
}
|
|
1452
|
+
const key = item.href.trim()
|
|
1453
|
+
if (!key || seen.has(key)) {
|
|
1454
|
+
return false
|
|
1455
|
+
}
|
|
1456
|
+
seen.add(key)
|
|
1457
|
+
return true
|
|
1458
|
+
})
|
|
1459
|
+
}
|
|
1460
|
+
} catch (error) {
|
|
1461
|
+
console.warn("Failed to collect clipboard resources", error)
|
|
1462
|
+
}
|
|
1334
1463
|
}
|
|
1335
|
-
if (
|
|
1464
|
+
if (files.length === 0 && (!remoteResources || remoteResources.length === 0)) {
|
|
1465
|
+
suppressClipboardText = false
|
|
1336
1466
|
return
|
|
1337
1467
|
}
|
|
1338
1468
|
event.preventDefault()
|
|
1339
1469
|
event.stopPropagation()
|
|
1470
|
+
suppressClipboardText = true
|
|
1340
1471
|
try {
|
|
1341
1472
|
if (remoteResources && remoteResources.length > 0) {
|
|
1342
1473
|
await this.uploadRemoteResources(remoteResources, dropOverlay)
|
|
@@ -1345,10 +1476,12 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1345
1476
|
console.warn("Clipboard remote upload failed", error)
|
|
1346
1477
|
}
|
|
1347
1478
|
if (files.length > 0) {
|
|
1348
|
-
await this.uploadFiles(files, dropOverlay)
|
|
1479
|
+
await this.uploadFiles(files, dropOverlay).catch((error) => {
|
|
1480
|
+
console.warn("Clipboard upload failed", error)
|
|
1481
|
+
})
|
|
1349
1482
|
}
|
|
1350
1483
|
this.term.focus()
|
|
1351
|
-
})
|
|
1484
|
+
}, true)
|
|
1352
1485
|
term.attachCustomKeyEventHandler(event => {
|
|
1353
1486
|
if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
|
|
1354
1487
|
const selection = term.getSelection();
|
|
@@ -1358,14 +1491,15 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1358
1491
|
}
|
|
1359
1492
|
}
|
|
1360
1493
|
if ((event.ctrlKey || event.metaKey) && event.key === 'v') {
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1494
|
+
if (!suppressClipboardText) {
|
|
1495
|
+
navigator.clipboard.readText().then((text) => {
|
|
1496
|
+
this.socket.run({
|
|
1497
|
+
//key: "\x1b[200~" + text + "\x1b[201~",
|
|
1498
|
+
key: text,
|
|
1499
|
+
id: shell_id,
|
|
1500
|
+
paste: true
|
|
1501
|
+
})
|
|
1502
|
+
this.captureTextInput(text)
|
|
1369
1503
|
|
|
1370
1504
|
|
|
1371
1505
|
// this.socket.run({
|
|
@@ -1373,7 +1507,9 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1373
1507
|
// key: text,
|
|
1374
1508
|
// id: shell_id
|
|
1375
1509
|
// })
|
|
1376
|
-
|
|
1510
|
+
})
|
|
1511
|
+
}
|
|
1512
|
+
suppressClipboardText = false
|
|
1377
1513
|
return false
|
|
1378
1514
|
}
|
|
1379
1515
|
return true;
|