pake-cli 3.3.5 โ 3.3.7-beta
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 +11 -4
- package/dist/cli.js +69 -29
- package/package.json +1 -1
- package/src-tauri/.cargo/config.toml +0 -6
- package/src-tauri/.pake/pake.json +3 -3
- package/src-tauri/.pake/tauri.conf.json +5 -5
- package/src-tauri/.pake/tauri.macos.conf.json +3 -3
- package/src-tauri/src/inject/event.js +56 -26
package/README.md
CHANGED
|
@@ -434,6 +434,13 @@ Pake's development can not be without these Hackers. They contributed a lot of c
|
|
|
434
434
|
<sub><b>Jiaqi Gu</b></sub>
|
|
435
435
|
</a>
|
|
436
436
|
</td>
|
|
437
|
+
<td align="center">
|
|
438
|
+
<a href="https://github.com/JohannLai">
|
|
439
|
+
<img src="https://avatars.githubusercontent.com/u/10769405?v=4" width="90;" alt="JohannLai"/>
|
|
440
|
+
<br />
|
|
441
|
+
<sub><b>Johannlai</b></sub>
|
|
442
|
+
</a>
|
|
443
|
+
</td>
|
|
437
444
|
<td align="center">
|
|
438
445
|
<a href="https://github.com/Jason6987">
|
|
439
446
|
<img src="https://avatars.githubusercontent.com/u/140222795?v=4" width="90;" alt="Jason6987"/>
|
|
@@ -441,6 +448,8 @@ Pake's development can not be without these Hackers. They contributed a lot of c
|
|
|
441
448
|
<sub><b>Luminall</b></sub>
|
|
442
449
|
</a>
|
|
443
450
|
</td>
|
|
451
|
+
</tr>
|
|
452
|
+
<tr>
|
|
444
453
|
<td align="center">
|
|
445
454
|
<a href="https://github.com/Milo123459">
|
|
446
455
|
<img src="https://avatars.githubusercontent.com/u/50248166?v=4" width="90;" alt="Milo123459"/>
|
|
@@ -448,8 +457,6 @@ Pake's development can not be without these Hackers. They contributed a lot of c
|
|
|
448
457
|
<sub><b>Milo</b></sub>
|
|
449
458
|
</a>
|
|
450
459
|
</td>
|
|
451
|
-
</tr>
|
|
452
|
-
<tr>
|
|
453
460
|
<td align="center">
|
|
454
461
|
<a href="https://github.com/princemaple">
|
|
455
462
|
<img src="https://avatars.githubusercontent.com/u/1329716?v=4" width="90;" alt="princemaple"/>
|
|
@@ -492,6 +499,8 @@ Pake's development can not be without these Hackers. They contributed a lot of c
|
|
|
492
499
|
<sub><b>Null</b></sub>
|
|
493
500
|
</a>
|
|
494
501
|
</td>
|
|
502
|
+
</tr>
|
|
503
|
+
<tr>
|
|
495
504
|
<td align="center">
|
|
496
505
|
<a href="https://github.com/liudonghua123">
|
|
497
506
|
<img src="https://avatars.githubusercontent.com/u/2276718?v=4" width="90;" alt="liudonghua123"/>
|
|
@@ -499,8 +508,6 @@ Pake's development can not be without these Hackers. They contributed a lot of c
|
|
|
499
508
|
<sub><b>Liudonghua</b></sub>
|
|
500
509
|
</a>
|
|
501
510
|
</td>
|
|
502
|
-
</tr>
|
|
503
|
-
<tr>
|
|
504
511
|
<td align="center">
|
|
505
512
|
<a href="https://github.com/liusishan">
|
|
506
513
|
<img src="https://avatars.githubusercontent.com/u/33129823?v=4" width="90;" alt="liusishan"/>
|
package/dist/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ import sharp from 'sharp';
|
|
|
22
22
|
import * as psl from 'psl';
|
|
23
23
|
|
|
24
24
|
var name = "pake-cli";
|
|
25
|
-
var version = "3.3.
|
|
25
|
+
var version = "3.3.7-beta";
|
|
26
26
|
var description = "๐คฑ๐ป Turn any webpage into a desktop app with one command. ๐คฑ๐ป ไธ้ฎๆๅ
็ฝ้กต็ๆ่ฝป้ๆก้ขๅบ็จใ";
|
|
27
27
|
var engines = {
|
|
28
28
|
node: ">=18.0.0"
|
|
@@ -328,6 +328,40 @@ async function combineFiles(files, output) {
|
|
|
328
328
|
return files;
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
+
function generateSafeFilename(name) {
|
|
332
|
+
return name
|
|
333
|
+
.replace(/[<>:"/\\|?*]/g, '_')
|
|
334
|
+
.replace(/\s+/g, '_')
|
|
335
|
+
.replace(/\.+$/g, '')
|
|
336
|
+
.slice(0, 255);
|
|
337
|
+
}
|
|
338
|
+
function generateLinuxPackageName(name) {
|
|
339
|
+
return name
|
|
340
|
+
.toLowerCase()
|
|
341
|
+
.replace(/[^a-z0-9\u4e00-\u9fff]+/g, '-')
|
|
342
|
+
.replace(/^-+|-+$/g, '')
|
|
343
|
+
.replace(/-+/g, '-');
|
|
344
|
+
}
|
|
345
|
+
function generateIdentifierSafeName(name) {
|
|
346
|
+
const cleaned = name
|
|
347
|
+
.replace(/[^a-zA-Z0-9\u4e00-\u9fff]/g, '')
|
|
348
|
+
.toLowerCase();
|
|
349
|
+
if (cleaned === '') {
|
|
350
|
+
const fallback = Array.from(name)
|
|
351
|
+
.map(char => {
|
|
352
|
+
const code = char.charCodeAt(0);
|
|
353
|
+
if ((code >= 48 && code <= 57) || (code >= 65 && code <= 90) || (code >= 97 && code <= 122)) {
|
|
354
|
+
return char.toLowerCase();
|
|
355
|
+
}
|
|
356
|
+
return code.toString(16);
|
|
357
|
+
})
|
|
358
|
+
.join('')
|
|
359
|
+
.slice(0, 50);
|
|
360
|
+
return fallback || 'pake-app';
|
|
361
|
+
}
|
|
362
|
+
return cleaned;
|
|
363
|
+
}
|
|
364
|
+
|
|
331
365
|
async function mergeConfig(url, options, tauriConf) {
|
|
332
366
|
// Ensure .pake directory exists and copy source templates if needed
|
|
333
367
|
const srcTauriDir = path.join(npmDirectory, 'src-tauri');
|
|
@@ -372,7 +406,7 @@ async function mergeConfig(url, options, tauriConf) {
|
|
|
372
406
|
tauriConf.identifier = identifier;
|
|
373
407
|
tauriConf.version = appVersion;
|
|
374
408
|
if (platform === 'linux') {
|
|
375
|
-
tauriConf.mainBinaryName = `pake-${name
|
|
409
|
+
tauriConf.mainBinaryName = `pake-${generateIdentifierSafeName(name)}`;
|
|
376
410
|
}
|
|
377
411
|
if (platform == 'win32') {
|
|
378
412
|
tauriConf.bundle.windows.wix.language[0] = installerLanguage;
|
|
@@ -418,8 +452,8 @@ async function mergeConfig(url, options, tauriConf) {
|
|
|
418
452
|
// Remove hardcoded desktop files and regenerate with correct app name
|
|
419
453
|
delete tauriConf.bundle.linux.deb.files;
|
|
420
454
|
// Generate correct desktop file configuration
|
|
421
|
-
const
|
|
422
|
-
const identifier = `com.pake.${
|
|
455
|
+
const appNameSafe = generateSafeFilename(name).toLowerCase();
|
|
456
|
+
const identifier = `com.pake.${appNameSafe}`;
|
|
423
457
|
const desktopFileName = `${identifier}.desktop`;
|
|
424
458
|
// Create desktop file content
|
|
425
459
|
const desktopContent = `[Desktop Entry]
|
|
@@ -427,8 +461,8 @@ Version=1.0
|
|
|
427
461
|
Type=Application
|
|
428
462
|
Name=${name}
|
|
429
463
|
Comment=${name}
|
|
430
|
-
Exec=pake-${
|
|
431
|
-
Icon=${
|
|
464
|
+
Exec=pake-${appNameSafe}
|
|
465
|
+
Icon=${appNameSafe}_512
|
|
432
466
|
Categories=Network;WebBrowser;
|
|
433
467
|
MimeType=text/html;text/xml;application/xhtml_xml;
|
|
434
468
|
StartupNotify=true
|
|
@@ -472,28 +506,29 @@ StartupNotify=true
|
|
|
472
506
|
const platformIconMap = {
|
|
473
507
|
win32: {
|
|
474
508
|
fileExt: '.ico',
|
|
475
|
-
path: `png/${name.toLowerCase()}_256.ico`,
|
|
509
|
+
path: `png/${generateSafeFilename(name).toLowerCase()}_256.ico`,
|
|
476
510
|
defaultIcon: 'png/icon_256.ico',
|
|
477
511
|
message: 'Windows icon must be .ico and 256x256px.',
|
|
478
512
|
},
|
|
479
513
|
linux: {
|
|
480
514
|
fileExt: '.png',
|
|
481
|
-
path: `png/${name.toLowerCase()}_512.png`,
|
|
515
|
+
path: `png/${generateSafeFilename(name).toLowerCase()}_512.png`,
|
|
482
516
|
defaultIcon: 'png/icon_512.png',
|
|
483
517
|
message: 'Linux icon must be .png and 512x512px.',
|
|
484
518
|
},
|
|
485
519
|
darwin: {
|
|
486
520
|
fileExt: '.icns',
|
|
487
|
-
path: `icons/${name.toLowerCase()}.icns`,
|
|
521
|
+
path: `icons/${generateSafeFilename(name).toLowerCase()}.icns`,
|
|
488
522
|
defaultIcon: 'icons/icon.icns',
|
|
489
523
|
message: 'macOS icon must be .icns type.',
|
|
490
524
|
},
|
|
491
525
|
};
|
|
492
526
|
const iconInfo = platformIconMap[platform];
|
|
493
|
-
const
|
|
527
|
+
const resolvedIconPath = options.icon ? path.resolve(options.icon) : null;
|
|
528
|
+
const exists = resolvedIconPath && (await fsExtra.pathExists(resolvedIconPath));
|
|
494
529
|
if (exists) {
|
|
495
530
|
let updateIconPath = true;
|
|
496
|
-
let customIconExt = path.extname(
|
|
531
|
+
let customIconExt = path.extname(resolvedIconPath).toLowerCase();
|
|
497
532
|
if (customIconExt !== iconInfo.fileExt) {
|
|
498
533
|
updateIconPath = false;
|
|
499
534
|
logger.warn(`โผ ${iconInfo.message}, but you give ${customIconExt}`);
|
|
@@ -503,10 +538,9 @@ StartupNotify=true
|
|
|
503
538
|
const iconPath = path.join(npmDirectory, 'src-tauri/', iconInfo.path);
|
|
504
539
|
tauriConf.bundle.resources = [iconInfo.path];
|
|
505
540
|
// Avoid copying if source and destination are the same
|
|
506
|
-
const absoluteIconPath = path.resolve(options.icon);
|
|
507
541
|
const absoluteDestPath = path.resolve(iconPath);
|
|
508
|
-
if (
|
|
509
|
-
await fsExtra.copy(
|
|
542
|
+
if (resolvedIconPath !== absoluteDestPath) {
|
|
543
|
+
await fsExtra.copy(resolvedIconPath, iconPath);
|
|
510
544
|
}
|
|
511
545
|
}
|
|
512
546
|
if (updateIconPath) {
|
|
@@ -528,8 +562,8 @@ StartupNotify=true
|
|
|
528
562
|
// ้่ฆๅคๆญๅพๆ ๆ ผๅผ๏ผ้ป่ฎคๅชๆฏๆicoๅpngไธค็ง
|
|
529
563
|
let iconExt = path.extname(systemTrayIcon).toLowerCase();
|
|
530
564
|
if (iconExt == '.png' || iconExt == '.ico') {
|
|
531
|
-
const trayIcoPath = path.join(npmDirectory, `src-tauri/png/${name.toLowerCase()}${iconExt}`);
|
|
532
|
-
trayIconPath = `png/${name.toLowerCase()}${iconExt}`;
|
|
565
|
+
const trayIcoPath = path.join(npmDirectory, `src-tauri/png/${generateSafeFilename(name).toLowerCase()}${iconExt}`);
|
|
566
|
+
trayIconPath = `png/${generateSafeFilename(name).toLowerCase()}${iconExt}`;
|
|
533
567
|
await fsExtra.copy(systemTrayIcon, trayIcoPath);
|
|
534
568
|
}
|
|
535
569
|
else {
|
|
@@ -854,7 +888,7 @@ class BaseBuilder {
|
|
|
854
888
|
const extension = process.platform === 'win32' ? '.exe' : '';
|
|
855
889
|
// Linux uses the unique binary name we set in merge.ts
|
|
856
890
|
if (process.platform === 'linux') {
|
|
857
|
-
return `pake-${appName
|
|
891
|
+
return `pake-${generateIdentifierSafeName(appName)}${extension}`;
|
|
858
892
|
}
|
|
859
893
|
// Windows and macOS use 'pake' as binary name
|
|
860
894
|
return `pake${extension}`;
|
|
@@ -1169,12 +1203,11 @@ const API_KEYS = {
|
|
|
1169
1203
|
logoDev: ['pk_JLLMUKGZRpaG5YclhXaTkg', 'pk_Ph745P8mQSeYFfW2Wk039A'],
|
|
1170
1204
|
brandfetch: ['1idqvJC0CeFSeyp3Yf7', '1idej-yhU_ThggIHFyG'],
|
|
1171
1205
|
};
|
|
1172
|
-
/**
|
|
1173
|
-
* Generates platform-specific icon paths and handles copying for Windows
|
|
1174
|
-
*/
|
|
1175
1206
|
function generateIconPath(appName, isDefault = false) {
|
|
1176
|
-
const safeName =
|
|
1177
|
-
|
|
1207
|
+
const safeName = isDefault
|
|
1208
|
+
? 'icon'
|
|
1209
|
+
: generateSafeFilename(appName).toLowerCase();
|
|
1210
|
+
const baseName = safeName;
|
|
1178
1211
|
if (IS_WIN) {
|
|
1179
1212
|
return path.join(npmDirectory, 'src-tauri', 'png', `${baseName}_256.ico`);
|
|
1180
1213
|
}
|
|
@@ -1237,7 +1270,7 @@ async function convertIconFormat(inputPath, appName) {
|
|
|
1237
1270
|
const platformOutputDir = path.join(outputDir, 'converted-icons');
|
|
1238
1271
|
await fsExtra.ensureDir(platformOutputDir);
|
|
1239
1272
|
const processedInputPath = await preprocessIcon(inputPath);
|
|
1240
|
-
const iconName = appName.toLowerCase();
|
|
1273
|
+
const iconName = generateSafeFilename(appName).toLowerCase();
|
|
1241
1274
|
// Generate platform-specific format
|
|
1242
1275
|
if (IS_WIN) {
|
|
1243
1276
|
// Support multiple sizes for better Windows compatibility
|
|
@@ -1513,8 +1546,8 @@ function resolveAppName(name, platform) {
|
|
|
1513
1546
|
}
|
|
1514
1547
|
function isValidName(name, platform) {
|
|
1515
1548
|
const platformRegexMapping = {
|
|
1516
|
-
linux: /^[a-z0-9][a-z0-9-]*$/,
|
|
1517
|
-
default: /^[a-zA-Z0-9][a-zA-Z0-9- ]*$/,
|
|
1549
|
+
linux: /^[a-z0-9\u4e00-\u9fff][a-z0-9\u4e00-\u9fff-]*$/,
|
|
1550
|
+
default: /^[a-zA-Z0-9\u4e00-\u9fff][a-zA-Z0-9\u4e00-\u9fff- ]*$/,
|
|
1518
1551
|
};
|
|
1519
1552
|
const reg = platformRegexMapping[platform] || platformRegexMapping.default;
|
|
1520
1553
|
return !!name && reg.test(name);
|
|
@@ -1530,10 +1563,8 @@ async function handleOptions(options, url) {
|
|
|
1530
1563
|
const namePrompt = await promptText(promptMessage, defaultName);
|
|
1531
1564
|
name = namePrompt || defaultName;
|
|
1532
1565
|
}
|
|
1533
|
-
// Handle platform-specific name formatting
|
|
1534
1566
|
if (name && platform === 'linux') {
|
|
1535
|
-
|
|
1536
|
-
name = name.toLowerCase().replace(/\s+/g, '-');
|
|
1567
|
+
name = generateLinuxPackageName(name);
|
|
1537
1568
|
}
|
|
1538
1569
|
if (!isValidName(name, platform)) {
|
|
1539
1570
|
const LINUX_NAME_ERROR = `โ Name should only include lowercase letters, numbers, and dashes (not leading dashes). Examples: com-123-xxx, 123pan, pan123, weread, we-read, 123.`;
|
|
@@ -1643,8 +1674,17 @@ program
|
|
|
1643
1674
|
.addOption(new Option('--system-tray-icon <string>', 'Custom system tray icon')
|
|
1644
1675
|
.default(DEFAULT_PAKE_OPTIONS.systemTrayIcon)
|
|
1645
1676
|
.hideHelp())
|
|
1646
|
-
.addOption(new Option('--hide-on-close', 'Hide window on close instead of exiting (default: true for macOS, false for others)')
|
|
1677
|
+
.addOption(new Option('--hide-on-close [boolean]', 'Hide window on close instead of exiting (default: true for macOS, false for others)')
|
|
1647
1678
|
.default(DEFAULT_PAKE_OPTIONS.hideOnClose)
|
|
1679
|
+
.argParser((value) => {
|
|
1680
|
+
if (value === undefined)
|
|
1681
|
+
return true; // --hide-on-close without value
|
|
1682
|
+
if (value === 'true')
|
|
1683
|
+
return true;
|
|
1684
|
+
if (value === 'false')
|
|
1685
|
+
return false;
|
|
1686
|
+
throw new Error('--hide-on-close must be true or false');
|
|
1687
|
+
})
|
|
1648
1688
|
.hideHelp())
|
|
1649
1689
|
.addOption(new Option('--title <string>', 'Window title').hideHelp())
|
|
1650
1690
|
.addOption(new Option('--incognito', 'Launch app in incognito/private mode')
|
package/package.json
CHANGED
|
@@ -8,9 +8,3 @@ registry = "sparse+https://rsproxy.cn/index/"
|
|
|
8
8
|
index = "https://rsproxy.cn/crates.io-index"
|
|
9
9
|
[net]
|
|
10
10
|
git-fetch-with-cli = true
|
|
11
|
-
|
|
12
|
-
[env]
|
|
13
|
-
# Fix for macOS 26 Beta compatibility issues
|
|
14
|
-
# Forces use of compatible SDK when building on macOS 26 Beta
|
|
15
|
-
MACOSX_DEPLOYMENT_TARGET = "15.5"
|
|
16
|
-
SDKROOT = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"windows": [
|
|
3
3
|
{
|
|
4
|
-
"url": "https://
|
|
4
|
+
"url": "https://github.com",
|
|
5
5
|
"url_type": "web",
|
|
6
|
-
"hide_title_bar":
|
|
6
|
+
"hide_title_bar": true,
|
|
7
7
|
"fullscreen": false,
|
|
8
8
|
"width": 1200,
|
|
9
|
-
"height":
|
|
9
|
+
"height": 800,
|
|
10
10
|
"resizable": true,
|
|
11
11
|
"always_on_top": false,
|
|
12
12
|
"dark_mode": false,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"productName": "
|
|
3
|
-
"identifier": "com.pake.
|
|
2
|
+
"productName": "GitHubMultiArch",
|
|
3
|
+
"identifier": "com.pake.3097fc",
|
|
4
4
|
"version": "1.0.0",
|
|
5
5
|
"app": {
|
|
6
6
|
"withGlobalTauri": true,
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
},
|
|
14
14
|
"bundle": {
|
|
15
15
|
"icon": [
|
|
16
|
-
"icons/
|
|
16
|
+
"icons/githubmultiarch.icns"
|
|
17
17
|
],
|
|
18
18
|
"active": true,
|
|
19
19
|
"targets": [
|
|
20
|
-
"
|
|
20
|
+
"app"
|
|
21
21
|
],
|
|
22
22
|
"resources": [
|
|
23
|
-
"icons/
|
|
23
|
+
"icons/githubmultiarch.icns"
|
|
24
24
|
]
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -252,40 +252,52 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
function downloadFromDataUri(dataURI, filename) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// create a view into the buffer
|
|
260
|
-
const binary = new Uint8Array(bufferArray);
|
|
255
|
+
try {
|
|
256
|
+
const byteString = atob(dataURI.split(",")[1]);
|
|
257
|
+
// write the bytes of the string to an ArrayBuffer
|
|
258
|
+
const bufferArray = new ArrayBuffer(byteString.length);
|
|
261
259
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
binary[i] = byteString.charCodeAt(i);
|
|
265
|
-
}
|
|
260
|
+
// create a view into the buffer
|
|
261
|
+
const binary = new Uint8Array(bufferArray);
|
|
266
262
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
filename,
|
|
272
|
-
binary: Array.from(binary),
|
|
273
|
-
language: userLanguage,
|
|
274
|
-
},
|
|
275
|
-
});
|
|
276
|
-
}
|
|
263
|
+
// set the bytes of the buffer to the correct values
|
|
264
|
+
for (let i = 0; i < byteString.length; i++) {
|
|
265
|
+
binary[i] = byteString.charCodeAt(i);
|
|
266
|
+
}
|
|
277
267
|
|
|
278
|
-
|
|
279
|
-
convertBlobUrlToBinary(blobUrl).then((binary) => {
|
|
268
|
+
// write the ArrayBuffer to a binary, and you're done
|
|
280
269
|
const userLanguage = navigator.language || navigator.userLanguage;
|
|
281
270
|
invoke("download_file_by_binary", {
|
|
282
271
|
params: {
|
|
283
272
|
filename,
|
|
284
|
-
binary,
|
|
273
|
+
binary: Array.from(binary),
|
|
285
274
|
language: userLanguage,
|
|
286
275
|
},
|
|
276
|
+
}).catch((error) => {
|
|
277
|
+
console.error("Failed to download data URI file:", filename, error);
|
|
278
|
+
});
|
|
279
|
+
} catch (error) {
|
|
280
|
+
console.error("Failed to process data URI:", dataURI, error);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function downloadFromBlobUrl(blobUrl, filename) {
|
|
285
|
+
convertBlobUrlToBinary(blobUrl)
|
|
286
|
+
.then((binary) => {
|
|
287
|
+
const userLanguage = navigator.language || navigator.userLanguage;
|
|
288
|
+
invoke("download_file_by_binary", {
|
|
289
|
+
params: {
|
|
290
|
+
filename,
|
|
291
|
+
binary,
|
|
292
|
+
language: userLanguage,
|
|
293
|
+
},
|
|
294
|
+
}).catch((error) => {
|
|
295
|
+
console.error("Failed to download blob file:", filename, error);
|
|
296
|
+
});
|
|
297
|
+
})
|
|
298
|
+
.catch((error) => {
|
|
299
|
+
console.error("Failed to convert blob to binary:", blobUrl, error);
|
|
287
300
|
});
|
|
288
|
-
});
|
|
289
301
|
}
|
|
290
302
|
|
|
291
303
|
// detect blob download by createElement("a")
|
|
@@ -323,8 +335,16 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
323
335
|
anchorElement.download || e.metaKey || e.ctrlKey || isDownloadableFile(url);
|
|
324
336
|
|
|
325
337
|
const handleExternalLink = (url) => {
|
|
338
|
+
// Don't try to open blob: or data: URLs with shell
|
|
339
|
+
if (isSpecialDownload(url)) {
|
|
340
|
+
console.warn("Cannot open special URL with shell:", url);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
326
344
|
invoke("plugin:shell|open", {
|
|
327
345
|
path: url,
|
|
346
|
+
}).catch((error) => {
|
|
347
|
+
console.error("Failed to open URL with shell:", url, error);
|
|
328
348
|
});
|
|
329
349
|
};
|
|
330
350
|
|
|
@@ -351,6 +371,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
351
371
|
};
|
|
352
372
|
|
|
353
373
|
const detectAnchorElementClick = (e) => {
|
|
374
|
+
// Safety check: ensure e.target exists and is an Element with closest method
|
|
375
|
+
if (!e.target || typeof e.target.closest !== "function") {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
354
378
|
const anchorElement = e.target.closest("a");
|
|
355
379
|
|
|
356
380
|
if (anchorElement && anchorElement.href) {
|
|
@@ -701,7 +725,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
701
725
|
}
|
|
702
726
|
|
|
703
727
|
// Check for parent elements with background images
|
|
704
|
-
const parentWithBg =
|
|
728
|
+
const parentWithBg =
|
|
729
|
+
target && typeof target.closest === "function"
|
|
730
|
+
? target.closest('[style*="background-image"]')
|
|
731
|
+
: null;
|
|
705
732
|
if (parentWithBg) {
|
|
706
733
|
const bgImage = parentWithBg.style.backgroundImage;
|
|
707
734
|
const urlMatch = bgImage.match(/url\(["']?([^"')]+)["']?\)/);
|
|
@@ -770,7 +797,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
770
797
|
const mediaInfo = getMediaInfo(target);
|
|
771
798
|
|
|
772
799
|
// Check for links (but not if it's media)
|
|
773
|
-
const linkElement =
|
|
800
|
+
const linkElement =
|
|
801
|
+
target && typeof target.closest === "function"
|
|
802
|
+
? target.closest("a")
|
|
803
|
+
: null;
|
|
774
804
|
const isLink = linkElement && linkElement.href && !mediaInfo.isMedia;
|
|
775
805
|
|
|
776
806
|
// Only show custom menu for media or links
|