Files
Pake/src-tauri/src/inject/event.js
2024-05-09 15:32:16 +08:00

269 lines
8.3 KiB
JavaScript
Vendored

const shortcuts = {
'ArrowUp': () => scrollTo(0, 0),
'ArrowDown': () => scrollTo(0, document.body.scrollHeight),
'[': () => window.history.back(),
']': () => window.history.forward(),
'r': () => window.location.reload(),
'-': () => zoomOut(),
'=': () => zoomIn(),
'+': () => zoomIn(),
'0': () => setZoom('100%'),
};
function setZoom(zoom) {
const html = document.getElementsByTagName('html')[0];
html.style.zoom = zoom;
window.localStorage.setItem('htmlZoom', zoom);
}
function zoomCommon(zoomChange) {
const currentZoom = window.localStorage.getItem('htmlZoom') || '100%';
setZoom(zoomChange(currentZoom));
}
function zoomIn() {
zoomCommon((currentZoom) => `${Math.min(parseInt(currentZoom) + 10, 200)}%`);
}
function zoomOut() {
zoomCommon((currentZoom) => `${Math.max(parseInt(currentZoom) - 10, 30)}%`);
}
function handleShortcut(event) {
if (shortcuts[event.key]) {
event.preventDefault();
shortcuts[event.key]();
}
}
// Judgment of file download.
function isDownloadLink(url) {
const fileExtensions = [
'3gp', '7z', 'ai', 'apk', 'avi', 'bmp', 'csv', 'dmg', 'doc', 'docx', 'fla', 'flv', 'gif', 'gz', 'gzip',
'ico', 'iso', 'indd', 'jar', 'jpeg', 'jpg', 'm3u8', 'mov', 'mp3', 'mp4', 'mpa', 'mpg',
'mpeg', 'msi', 'odt', 'ogg', 'ogv', 'pdf', 'png', 'ppt', 'pptx', 'psd', 'rar', 'raw', 'rss', 'svg',
'swf', 'tar', 'tif', 'tiff', 'ts', 'txt', 'wav', 'webm', 'webp', 'wma', 'wmv', 'xls', 'xlsx', 'xml', 'zip',
];
const downloadLinkPattern = new RegExp(`\\.(${fileExtensions.join('|')})$`, 'i');
return downloadLinkPattern.test(url);
}
// No need to go to the download link.
function externalDownLoadLink() {
return ['quickref.me'].indexOf(location.hostname) > -1;
}
// Directly jumping out without hostname address.
function externalTargetLink() {
return ['zbook.lol'].indexOf(location.hostname) > -1;
}
document.addEventListener('DOMContentLoaded', () => {
const tauri = window.__TAURI__;
const appWindow = tauri.window.appWindow;
const invoke = tauri.tauri.invoke;
if (!document.getElementById('pake-top-dom')) {
const topDom = document.createElement('div');
topDom.id = 'pake-top-dom';
document.body.appendChild(topDom);
}
const domEl = document.getElementById('pake-top-dom');
domEl.addEventListener('touchstart', () => {
appWindow.startDragging().then();
});
domEl.addEventListener('mousedown', (e) => {
e.preventDefault();
if (e.buttons === 1 && e.detail !== 2) {
appWindow.startDragging().then();
}
});
domEl.addEventListener('dblclick', () => {
appWindow.isFullscreen().then((fullscreen) => {
appWindow.setFullscreen(!fullscreen).then();
});
});
if (window['pakeConfig']?.disabled_web_shortcuts !== true) {
document.addEventListener('keyup', (event) => {
if (/windows|linux/i.test(navigator.userAgent) && event.ctrlKey) {
handleShortcut(event);
}
if (/macintosh|mac os x/i.test(navigator.userAgent) && event.metaKey) {
handleShortcut(event);
}
});
}
// Collect blob urls to blob by overriding window.URL.createObjectURL
function collectUrlToBlobs() {
const backupCreateObjectURL = window.URL.createObjectURL;
window.blobToUrlCaches = new Map();
window.URL.createObjectURL = (blob) => {
const url = backupCreateObjectURL.call(window.URL, blob);
window.blobToUrlCaches.set(url, blob);
return url;
};
}
function convertBlobUrlToBinary(blobUrl) {
return new Promise((resolve) => {
const blob = window.blobToUrlCaches.get(blobUrl);
const reader = new FileReader();
reader.readAsArrayBuffer(blob);
reader.onload = () => {
resolve(Array.from(new Uint8Array(reader.result)));
};
});
}
function downloadFromDataUri(dataURI, filename) {
const byteString = atob(dataURI.split(',')[1]);
// write the bytes of the string to an ArrayBuffer
const bufferArray = new ArrayBuffer(byteString.length);
// create a view into the buffer
const binary = new Uint8Array(bufferArray);
// set the bytes of the buffer to the correct values
for (let i = 0; i < byteString.length; i++) {
binary[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a binary, and you're done
invoke('download_file_by_binary', {
params: {
filename,
binary: Array.from(binary),
},
});
}
function downloadFromBlobUrl(blobUrl, filename) {
convertBlobUrlToBinary(blobUrl).then((binary) => {
invoke('download_file_by_binary', {
params: {
filename,
binary,
},
});
});
}
// detect blob download by createElement("a")
function detectDownloadByCreateAnchor() {
const createEle = document.createElement;
document.createElement = (el) => {
if (el !== 'a') return createEle.call(document, el);
const anchorEle = createEle.call(document, el);
// use addEventListener to avoid overriding the original click event.
anchorEle.addEventListener('click', (e) => {
const url = anchorEle.href;
const filename = anchorEle.download || getFilenameFromUrl(url);
if (window.blobToUrlCaches.has(url)) {
downloadFromBlobUrl(url, filename);
// case: download from dataURL -> convert dataURL ->
} else if (url.startsWith('data:')) {
downloadFromDataUri(url, filename);
} else if (isDownloadLink(url) || anchorEle.hostname !== window.location.host) {
handleExternalLink(e, url);
}
}, true);
return anchorEle;
};
}
const isExternalLink = (link) => window.location.host !== link.host;
// process special download protocol['data:','blob:']
const isSpecialDownload = (url) => ['blob', 'data'].some(protocol => url.startsWith(protocol));
const isDownloadRequired = (url, anchorElement, e) =>
anchorElement.download || e.metaKey || e.ctrlKey || isDownloadLink(url);
const handleExternalLink = (e, url) => {
e.preventDefault();
tauri.shell.open(url);
};
const handleDownloadLink = (e, url, filename) => {
e.preventDefault();
invoke('download_file', { params: { url, filename } });
};
const detectAnchorElementClick = (e) => {
const anchorElement = e.target.closest('a');
if (anchorElement && anchorElement.href) {
anchorElement.target = '_self';
const hrefUrl = new URL(anchorElement.href);
const absoluteUrl = hrefUrl.href;
let filename = anchorElement.download || getFilenameFromUrl(absoluteUrl);
// Handling external link redirection.
if (isExternalLink(absoluteUrl) && (['_blank', '_new'].includes(anchorElement.target) || externalTargetLink())) {
handleExternalLink(e, absoluteUrl);
return;
}
// Process download links for Rust to handle.
if (isDownloadRequired(absoluteUrl, anchorElement, e) && !externalDownLoadLink() && !isSpecialDownload(absoluteUrl)) {
handleDownloadLink(e, absoluteUrl, filename);
}
}
};
// Prevent some special websites from executing in advance, before the click event is triggered.
document.addEventListener('click', detectAnchorElementClick, true);
collectUrlToBlobs();
detectDownloadByCreateAnchor();
// Rewrite the window.open function.
const originalWindowOpen = window.open;
window.open = function(url, name, specs) {
// Apple login and google login
if (name === 'AppleAuthentication') {
//do nothing
} else if (specs.includes('height=') || specs.includes('width=')) {
location.href = url;
} else {
const baseUrl = window.location.origin + window.location.pathname;
const hrefUrl = new URL(url, baseUrl);
tauri.shell.open(hrefUrl.href);
}
// Call the original window.open function to maintain its normal functionality.
return originalWindowOpen.call(window, url, name, specs);
};
// Set the default zoom, There are problems with Loop without using try-catch.
try {
setDefaultZoom();
} catch (e) {
console.log(e);
}
// Fix Chinese input method "Enter" on Safari
document.addEventListener('keydown', (e) => {
if (e.keyCode === 229) e.stopPropagation();
}, true);
});
function setDefaultZoom() {
const htmlZoom = window.localStorage.getItem('htmlZoom');
if (htmlZoom) {
setZoom(htmlZoom);
}
}
function getFilenameFromUrl(url) {
const urlPath = new URL(url).pathname;
return urlPath.substring(urlPath.lastIndexOf('/') + 1);
}