Last active
March 20, 2024 15:53
-
-
Save tam710562/67ce3c4387d72e94a83cf0ae9f890cec to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Easy Files | |
* Written by Tam710562 | |
*/ | |
(function () { | |
'use strict'; | |
const gnoh = { | |
file: { | |
verifyAccept({ fileName, mimeType }, accept) { | |
if (!accept) { | |
return true; | |
} | |
const mimeTypes = accept.split(',') | |
.map(x => x.trim()) | |
.filter(x => !!x && (x.startsWith('.') || /\w+\/([-+.\w]+|\*)/.test(x))); | |
for (const mt of mimeTypes) { | |
if ( | |
mt.startsWith('.') | |
? new RegExp(mt.replace('.', '.+\\.') + '$').test(fileName) | |
: new RegExp(mt.replace('*', '.+')).test(mimeType) | |
) { | |
return true; | |
} | |
} | |
return false; | |
}, | |
}, | |
i18n: { | |
getMessageName(message, type) { | |
message = (type ? type + '\x04' : '') + message; | |
return message.replace(/[^a-z0-9]/g, function (i) { | |
return '_' + i.codePointAt(0) + '_'; | |
}) + '0'; | |
}, | |
getMessage(message, type) { | |
return chrome.i18n.getMessage(this.getMessageName(message, type)) || message; | |
}, | |
}, | |
addStyle(css, id, isNotMin) { | |
this.styles = this.styles || {}; | |
if (Array.isArray(css)) { | |
css = css.join(isNotMin === true ? '\n' : ''); | |
} | |
id = id || this.uuid.generate(Object.keys(this.styles)); | |
this.styles[id] = this.createElement('style', { | |
html: css || '', | |
'data-id': id, | |
}, document.head); | |
return this.styles[id]; | |
}, | |
array: { | |
chunks(arr, n) { | |
const result = []; | |
for (let i = 0; i < arr.length; i += n) { | |
result.push(arr.slice(i, i + n)); | |
} | |
return result; | |
}, | |
}, | |
createElement(tagName, attribute, parent, inner, options) { | |
if (typeof tagName === 'undefined') { | |
return; | |
} | |
if (typeof options === 'undefined') { | |
options = {}; | |
} | |
if (typeof options.isPrepend === 'undefined') { | |
options.isPrepend = false; | |
} | |
const el = document.createElement(tagName); | |
if (!!attribute && typeof attribute === 'object') { | |
for (const key in attribute) { | |
if (key === 'text') { | |
el.textContent = attribute[key]; | |
} else if (key === 'html') { | |
el.innerHTML = attribute[key]; | |
} else if (key === 'style' && typeof attribute[key] === 'object') { | |
for (const css in attribute.style) { | |
el.style.setProperty(css, attribute.style[css]); | |
} | |
} else if (key === 'events' && typeof attribute[key] === 'object') { | |
for (const event in attribute.events) { | |
if (typeof attribute.events[event] === 'function') { | |
el.addEventListener(event, attribute.events[event]); | |
} | |
} | |
} else if (typeof el[key] !== 'undefined') { | |
el[key] = attribute[key]; | |
} else { | |
if (typeof attribute[key] === 'object') { | |
attribute[key] = JSON.stringify(attribute[key]); | |
} | |
el.setAttribute(key, attribute[key]); | |
} | |
} | |
} | |
if (!!inner) { | |
if (!Array.isArray(inner)) { | |
inner = [inner]; | |
} | |
for (let i = 0; i < inner.length; i++) { | |
if (inner[i].nodeName) { | |
el.append(inner[i]); | |
} else { | |
el.append(this.createElementFromHTML(inner[i])); | |
} | |
} | |
} | |
if (typeof parent === 'string') { | |
parent = document.querySelector(parent); | |
} | |
if (!!parent) { | |
if (options.isPrepend) { | |
parent.prepend(el); | |
} else { | |
parent.append(el); | |
} | |
} | |
return el; | |
}, | |
createElementFromHTML(html) { | |
return this.createElement('template', { | |
html: (html || '').trim(), | |
}).content; | |
}, | |
string: { | |
toColor(str) { | |
let hash = 0; | |
str.split('').forEach(char => { | |
hash = char.charCodeAt(0) + ((hash << 5) - hash); | |
}); | |
let r = (hash >> (0 * 8)) & 0xff; | |
let g = (hash >> (1 * 8)) & 0xff; | |
let b = (hash >> (2 * 8)) & 0xff; | |
return { r, g, b }; | |
}, | |
}, | |
color: { | |
rgbToHex(r, g, b) { | |
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); | |
}, | |
getLuminance(r, g, b) { | |
return 0.2126 * r + 0.7152 * g + 0.0722 * b; | |
}, | |
isLight(r, g, b) { | |
return gnoh.color.getLuminance(r, g, b) < 156; | |
}, | |
shadeColor(r, g, b, percent) { | |
r = Math.max(Math.min(255, r + percent), 0); | |
g = Math.max(Math.min(255, g + percent), 0); | |
b = Math.max(Math.min(255, b + percent), 0); | |
return { r, g, b }; | |
}, | |
}, | |
get constant() { | |
return { | |
dialogButtons: { | |
submit: { | |
label: this.i18n.getMessage('OK'), | |
type: 'submit' | |
}, | |
cancel: { | |
label: this.i18n.getMessage('Cancel'), | |
cancel: true | |
}, | |
primary: { | |
class: 'primary' | |
}, | |
danger: { | |
class: 'danger' | |
}, | |
default: {}, | |
} | |
}; | |
}, | |
dialog(title, content, buttons = [], config) { | |
let modalBg; | |
let dialog; | |
let cancelEvent; | |
const id = this.uuid.generate(); | |
const inner = document.querySelector('#main > .inner, #main > .webpageview'); | |
if (!config) { | |
config = {}; | |
} | |
if (typeof config.autoClose === 'undefined') { | |
config.autoClose = true; | |
} | |
function onKeyCloseDialog(windowId, key) { | |
if ( | |
windowId === vivaldiWindowId | |
&& key === 'Esc' | |
) { | |
closeDialog(true); | |
} | |
} | |
function onClickCloseDialog(event) { | |
if ( | |
config.autoClose | |
&& !event.target.closest('.dialog-custom[data-dialog-id="' + id + '"]') | |
) { | |
closeDialog(true); | |
} | |
} | |
function closeDialog(isCancel) { | |
if (isCancel === true && cancelEvent) { | |
cancelEvent.bind(this)(); | |
} | |
if (modalBg) { | |
modalBg.remove(); | |
} | |
vivaldi.tabsPrivate.onKeyboardShortcut.removeListener(onKeyCloseDialog); | |
document.removeEventListener('mousedown', onClickCloseDialog); | |
} | |
vivaldi.tabsPrivate.onKeyboardShortcut.addListener(onKeyCloseDialog); | |
document.addEventListener('mousedown', onClickCloseDialog); | |
const buttonElements = []; | |
for (let button of buttons) { | |
button.type = button.type || 'button'; | |
const clickEvent = button.click; | |
if (button.cancel === true && typeof clickEvent === 'function') { | |
cancelEvent = clickEvent; | |
} | |
button.events = { | |
click(event) { | |
event.preventDefault(); | |
if (typeof clickEvent === 'function') { | |
clickEvent.bind(this)(); | |
} | |
if (button.closeDialog !== false) { | |
closeDialog(); | |
} | |
} | |
}; | |
delete button.click; | |
if (button.label) { | |
button.value = button.label; | |
delete button.label; | |
} | |
buttonElements.push(this.createElement('input', button)); | |
} | |
const focusModal = this.createElement('span', { | |
class: 'focus_modal', | |
tabindex: '0', | |
}); | |
const div = this.createElement('div', { | |
style: { | |
width: config.width ? config.width + 'px' : '', | |
margin: '0 auto', | |
} | |
}); | |
dialog = this.createElement('form', { | |
'data-dialog-id': id, | |
class: 'dialog-custom modal-wrapper', | |
}, div); | |
if (config.class) { | |
dialog.classList.add(config.class); | |
} | |
const dialogHeader = this.createElement('header', { | |
class: 'dialog-header', | |
}, dialog, '<h1>' + (title || '') + '</h1>'); | |
const dialogContent = this.createElement('div', { | |
class: 'dialog-content', | |
style: { | |
maxHeight: '65vh', | |
}, | |
}, dialog, content); | |
if (buttons && buttons.length > 0) { | |
const dialogFooter = this.createElement('footer', { | |
class: 'dialog-footer', | |
}, dialog, buttonElements); | |
} | |
modalBg = this.createElement('div', { | |
id: 'modal-bg', | |
class: 'slide', | |
}, inner, [focusModal.cloneNode(true), div, focusModal.cloneNode(true)]); | |
return { | |
dialog: dialog, | |
dialogHeader: dialogHeader, | |
dialogContent: dialogContent, | |
buttons: buttonElements, | |
close: closeDialog, | |
}; | |
}, | |
timeOut(callback, conditon, timeOut = 300) { | |
let timeOutId = setTimeout(function wait() { | |
let result; | |
if (!conditon) { | |
result = document.getElementById('browser'); | |
} else if (typeof conditon === 'string') { | |
result = document.querySelector(conditon); | |
} else if (typeof conditon === 'function') { | |
result = conditon(); | |
} else { | |
return; | |
} | |
if (result) { | |
callback(result); | |
} else { | |
timeOutId = setTimeout(wait, timeOut); | |
} | |
}, timeOut); | |
function stop() { | |
if (timeOutId) { | |
clearTimeout(timeOutId); | |
} | |
} | |
return { | |
stop, | |
}; | |
}, | |
uuid: { | |
generate(ids) { | |
let d = Date.now() + performance.now(); | |
let r; | |
const id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { | |
r = (d + Math.random() * 16) % 16 | 0; | |
d = Math.floor(d / 16); | |
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); | |
}); | |
if (Array.isArray(ids) && ids.includes(id)) { | |
return this.uuid.generate(ids); | |
} | |
return id; | |
}, | |
}, | |
}; | |
const nameKey = 'easy-files'; | |
const langs = { | |
showAllFiles: gnoh.i18n.getMessage('Show all files...'), | |
downloaded: gnoh.i18n.getMessage('Downloaded'), | |
chooseAFile: gnoh.i18n.getMessage('Choose a File...'), | |
}; | |
const chunkSize = 1024 * 1024 * 10; // 10MB | |
const maxAllowedSize = 1024 * 1024 * 5; // 5MB | |
gnoh.addStyle([ | |
`.${nameKey}.dialog-custom .dialog-content { flex-flow: wrap; gap: 18px; }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper { overflow: hidden; margin: -2px; padding: 2px; }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper .selectbox-container { overflow: auto; margin: -2px; padding: 2px; flex: 0 1 auto; }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper .selectbox-container .selectbox-image { background-color: var(--colorBgLighter); width: 120px; height: 120px; display: flex; justify-content: center; align-items: center; }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper .selectbox-container .selectbox-image:hover { box-shadow: 0 0 0 2px var(--colorHighlightBg); }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper .selectbox-container .selectbox-image.preview img { object-fit: cover; width: 120px; height: 120px; flex: 0 0 auto; }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper .selectbox-container .selectbox-image.icon .file-icon { width: 54px; height: 69px; padding: 15px 0 0; position: relative; font-family: sans-serif; }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper .selectbox-container .selectbox-image.icon .file-icon:before { position: absolute; content: ''; left: 0; top: 0; height: 15px; left: 0; background-color: var(--colorFileIconBg, #007bff); right: 15px; }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper .selectbox-container .selectbox-image.icon .file-icon:after { position: absolute; content: ''; width: 0; height: 0; border-style: solid; border-width: 15.5px 0 0 15.5px; border-color: transparent transparent transparent var(--colorFileIconBgLighter, #66b0ff); top: 0; right: 0; }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper .selectbox-container .selectbox-image.icon .file-icon .file-icon-content { background-color: var(--colorFileIconBg, #007bff); top: 15px; color: var(--colorFileIconFg, #fff); position: absolute; left: 0; bottom: 0; right: 0; padding: 24.75px 0.3em 0; font-size: 19.5px; font-weight: 500; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper .selectbox-container .selectbox-title { width: 120px; }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper .selectbox-container .selectbox-title .filename-container { display: flex; flex-direction: row; overflow: hidden; width: 120px; }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper .selectbox-container .selectbox-title .filename-container .filename-text { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }`, | |
`.${nameKey}.dialog-custom .dialog-content .selectbox-wrapper .selectbox-container .selectbox-title .filename-container .filename-extension { white-space: nowrap; }`, | |
], nameKey); | |
function inject(nameKey) { | |
if (window.easyFiles) { | |
return; | |
} else { | |
window.easyFiles = true; | |
} | |
const fileData = []; | |
let fileInput = null; | |
function handleClick(event) { | |
if (event.target.matches('input[type=file]:not([webkitdirectory])')) { | |
event.preventDefault(); | |
event.stopPropagation(); | |
fileInput = event.target; | |
const attributes = {}; | |
for (const attr of fileInput.attributes) { | |
attributes[attr.name] = attr.value; | |
} | |
fileData.length = 0; | |
chrome.runtime.sendMessage({ | |
type: nameKey, | |
action: 'click', | |
attributes, | |
}); | |
} | |
} | |
window.addEventListener('click', handleClick); | |
function changeFile(dataTransfer) { | |
fileInput.files = dataTransfer.files; | |
fileInput.dispatchEvent(new Event('input', { bubbles: true })); | |
fileInput.dispatchEvent(new Event('change', { bubbles: true })); | |
} | |
chrome.runtime.onMessage.addListener((info, sender, sendResponse) => { | |
if (info.type === nameKey) { | |
switch (info.action) { | |
case 'file': | |
fileData[info.file.fileDataIndex] = info.file.fileData; | |
if (Object.entries(fileData).length === info.file.fileDataLength) { | |
const dataTransfer = new DataTransfer(); | |
dataTransfer.items.add(new File( | |
[new Uint8Array(fileData.flat())], | |
info.file.fileName, | |
{ type: info.file.mimeType }, | |
)); | |
changeFile(dataTransfer); | |
} | |
break; | |
case 'picker': | |
fileInput.showPicker(); | |
break; | |
default: | |
return false; | |
} | |
} | |
}); | |
} | |
async function simulatePaste() { | |
return new Promise((resolve, reject) => { | |
document.addEventListener('paste', (e) => { | |
e.preventDefault(); | |
const items = []; | |
let isRealFile = true; | |
for (const item of e.clipboardData.items) { | |
const file = item.getAsFile(); | |
const entry = item.webkitGetAsEntry(); | |
if (file) { | |
if (!entry || entry.isFile) { | |
items.push({ | |
file, | |
isFile: true, | |
isRealFile: !!entry, | |
}); | |
} else if (entry.isDirectory) { | |
items.push({ | |
file, | |
isDirectory: true, | |
}); | |
} | |
} | |
} | |
resolve({ | |
items, | |
isRealFile, | |
}); | |
}, { once: true }); | |
document.execCommand('paste'); | |
}); | |
} | |
async function readClipboard(accept) { | |
const clipboardFiles = []; | |
try { | |
const supportedTypes = [ | |
{ | |
extension: 'png', | |
mimeType: 'image/png', | |
}, | |
{ | |
extension: 'jpeg', | |
mimeType: 'image/jpeg', | |
}, | |
{ | |
extension: 'jpg', | |
mimeType: 'image/jpeg', | |
}, | |
]; | |
const supportedType = supportedTypes.find(s => gnoh.file.verifyAccept({ fileName: 'image.' + s.extension, mimeType: s.mimeType }, accept)); | |
const pasteData = await simulatePaste(); | |
for (const item of pasteData.items) { | |
const file = item.file; | |
let checkType = false; | |
if (item.isFile) { | |
if (item.isRealFile) { | |
checkType = gnoh.file.verifyAccept({ fileName: file.name, mimeType: file.type }, accept); | |
} else { | |
checkType = supportedType && file.type === 'image/png'; | |
} | |
} | |
if (checkType && file.size <= maxAllowedSize) { | |
let blob = new Blob([file], { type: file.type }); | |
if (!item.isRealFile && supportedType.mimeType === 'image/jpeg') { | |
blob = await convertPngToJpeg(blob); | |
} | |
const uint8Array = new Uint8Array(await blob.arrayBuffer()); | |
const fileData = gnoh.array.chunks(uint8Array, chunkSize).map(a => Array.from(a)); | |
const clipboardFile = { | |
fileData: fileData, | |
fileDataLength: fileData.length, | |
mimeType: blob.type, | |
category: 'clipboard', | |
}; | |
if (item.isRealFile) { | |
clipboardFile.fileName = file.name; | |
} else { | |
clipboardFile.extension = supportedType.extension; | |
} | |
switch (clipboardFile.mimeType) { | |
case 'image/jpeg': | |
case 'image/png': | |
case 'image/svg+xml': | |
case 'image/webp': | |
case 'image/gif': | |
case 'image/bmp': | |
clipboardFile.previewUrl = await vivaldi.utilities.storeImage({ | |
data: uint8Array, | |
mimeType: blob.type, | |
}); | |
break; | |
} | |
clipboardFiles.push(clipboardFile); | |
} | |
} | |
} catch (error) { | |
console.error(error); | |
} | |
return clipboardFiles; | |
} | |
async function convertPngToJpeg(blob) { | |
const image = gnoh.createElement('img', { | |
src: URL.createObjectURL(blob), | |
}); | |
await image.decode(); | |
const canvas = gnoh.createElement('canvas', { | |
width: image.width, | |
height: image.height, | |
}); | |
const ctx = canvas.getContext('2d'); | |
ctx.drawImage(image, 0, 0); | |
return new Promise((resolve) => { | |
canvas.toBlob(blob => { | |
URL.revokeObjectURL(image.src); | |
if (blob) { | |
resolve(blob); | |
} | |
}, 'image/jpeg'); | |
}); | |
} | |
async function getDownloadedFiles(accept) { | |
const downloadedFiles = await chrome.downloads.search({ exists: true, state: 'complete', orderBy: ['-startTime'] }); | |
const result = {}; | |
for (let downloadedFile of downloadedFiles) { | |
if ( | |
downloadedFile.mime | |
&& downloadedFile.mime !== 'application/x-msdownload' | |
&& gnoh.file.verifyAccept({ fileName: downloadedFile.filename, mimeType: downloadedFile.mime }, accept) | |
) { | |
downloadedFile = (await chrome.downloads.search({ id: downloadedFile.id }))[0]; | |
if ( | |
downloadedFile | |
&& downloadedFile.exists === true | |
&& downloadedFile.state === 'complete' | |
&& downloadedFile.fileSize <= maxAllowedSize | |
&& !result[downloadedFile.filename] | |
) { | |
const file = { | |
mimeType: downloadedFile.mime, | |
path: downloadedFile.filename, | |
fileName: downloadedFile.filename.replace(/^.*[\\/]/, ''), | |
category: 'downloaded-file', | |
}; | |
switch (file.mimeType) { | |
case 'image/jpeg': | |
case 'image/png': | |
case 'image/svg+xml': | |
case 'image/webp': | |
case 'image/gif': | |
case 'image/bmp': | |
file.previewUrl = await vivaldi.utilities.storeImage({ | |
url: file.path, | |
}); | |
break; | |
} | |
result[downloadedFile.filename] = file; | |
} | |
} | |
} | |
return Object.values(result); | |
} | |
function createFileIcon(extension) { | |
const colorBg = gnoh.string.toColor(extension); | |
const isLightBg = gnoh.color.isLight(colorBg.r, colorBg.g, colorBg.b); | |
const colorBgLighter = gnoh.color.shadeColor(colorBg.r, colorBg.g, colorBg.b, isLightBg ? 80 : -80); | |
const fileIcon = gnoh.createElement('div', { | |
class: 'file-icon', | |
style: { | |
'--colorFileIconBg': gnoh.color.rgbToHex(colorBg.r, colorBg.g, colorBg.b), | |
'--colorFileIconBgLighter': gnoh.color.rgbToHex(colorBgLighter.r, colorBgLighter.g, colorBgLighter.b), | |
'--colorFileIconFg': isLightBg ? '#f6f6f6' : '#111111', | |
} | |
}); | |
const fileIconContent = gnoh.createElement('div', { | |
class: 'file-icon-content', | |
text: extension, | |
}, fileIcon); | |
return fileIcon; | |
} | |
async function createSelectbox(sender, file, dialog) { | |
const selectbox = gnoh.createElement('button', { | |
title: file.fileName || '', | |
class: 'selectbox', | |
events: { | |
click: async (event) => { | |
event.preventDefault(); | |
dialog.close(); | |
switch (file.category) { | |
case 'downloaded-file': | |
if (!file.fileData) { | |
const fileData = await vivaldi.utilities.readImage(file.path); | |
file.fileData = gnoh.array.chunks(fileData.data, chunkSize); | |
file.fileDataLength = file.fileData.length; | |
} | |
break; | |
case 'clipboard': | |
if (!file.fileName) { | |
const d = new Date(); | |
const year = d.getFullYear(); | |
const month = (d.getMonth() + 1).toString().padStart(2, '0'); | |
const date = d.getDate().toString().padStart(2, '0'); | |
const hour = d.getHours().toString().padStart(2, '0'); | |
const minute = d.getMinutes().toString().padStart(2, '0'); | |
const second = d.getSeconds().toString().padStart(2, '0'); | |
const millisecond = d.getMilliseconds().toString().padStart(3, '0'); | |
file.fileName = `image_${year}-${month}-${date}_${hour}${minute}${second}${millisecond}.${file.extension}`; | |
} | |
break; | |
} | |
chooseFile(sender, file); | |
}, | |
}, | |
}); | |
const selectboxImage = gnoh.createElement('div', { | |
class: 'selectbox-image', | |
}, selectbox); | |
if (file.previewUrl) { | |
selectboxImage.classList.add('preview'); | |
} else { | |
selectboxImage.classList.add('icon'); | |
} | |
if (file.previewUrl) { | |
const image = gnoh.createElement('img', { | |
src: file.previewUrl, | |
}, selectboxImage); | |
} else { | |
const extension = file.extension || file.fileName.split('.').pop(); | |
selectboxImage.append(createFileIcon(extension)); | |
} | |
const selectboxTitle = gnoh.createElement('div', { | |
class: 'selectbox-title', | |
}, selectbox); | |
const filenameText = gnoh.createElement('div', { | |
class: 'filename-container', | |
}, selectboxTitle); | |
if (file.fileName) { | |
const extension = file.extension || file.fileName.split('.').pop(); | |
const name = file.fileName.substring(0, file.fileName.length - extension.length - 1); | |
const filenameContainer = gnoh.createElement('div', { | |
class: 'filename-text', | |
text: name, | |
}, filenameText); | |
const filenameExtension = gnoh.createElement('div', { | |
class: 'filename-extension', | |
text: '.' + extension, | |
}, filenameText); | |
} | |
return selectbox; | |
} | |
async function showDialogChooseFile(data) { | |
const buttonShowAllFilesElement = Object.assign({}, gnoh.constant.dialogButtons.submit, { | |
label: langs.showAllFiles, | |
click: () => showAllFiles(data.sender), | |
}); | |
const buttonCancelElement = Object.assign({}, gnoh.constant.dialogButtons.cancel); | |
const dialog = gnoh.dialog( | |
langs.chooseAFile, | |
null, | |
[buttonShowAllFilesElement, buttonCancelElement], | |
{ | |
class: nameKey, | |
} | |
); | |
dialog.dialog.style.maxWidth = 570 + 'px'; | |
if (data.clipboardFiles.length) { | |
const selectboxWrapperClipboard = gnoh.createElement('div', { | |
class: 'selectbox-wrapper', | |
}); | |
const h3Clipboard = gnoh.createElement('h3', { | |
text: 'Clipboard', | |
}, selectboxWrapperClipboard); | |
const selectboxContainerClipboard = gnoh.createElement('div', { | |
class: 'selectbox-container', | |
}, selectboxWrapperClipboard); | |
for (const clipboardFile of data.clipboardFiles) { | |
selectboxContainerClipboard.append(await createSelectbox(data.sender, clipboardFile, dialog)); | |
} | |
dialog.dialogContent.append(selectboxWrapperClipboard); | |
} | |
if (data.downloadedFiles.length) { | |
const selectboxWrapperDownloaded = gnoh.createElement('div', { | |
class: 'selectbox-wrapper', | |
}); | |
const h3Downloaded = gnoh.createElement('h3', { | |
text: 'Downloaded', | |
}, selectboxWrapperDownloaded); | |
const selectboxContainerDownloaded = gnoh.createElement('div', { | |
class: 'selectbox-container', | |
}, selectboxWrapperDownloaded); | |
for (const downloadedFile of data.downloadedFiles) { | |
selectboxContainerDownloaded.append(await createSelectbox(data.sender, downloadedFile, dialog)); | |
} | |
dialog.dialogContent.append(selectboxWrapperDownloaded); | |
} | |
} | |
function showAllFiles(sender) { | |
chrome.tabs.sendMessage(sender.tab.id, { | |
type: nameKey, | |
action: 'picker', | |
tabId: sender.tab.id, | |
frameId: sender.frameId, | |
}, { | |
frameId: sender.frameId, | |
}); | |
} | |
async function chooseFile(sender, file) { | |
if (!file.fileData.length) { | |
file.fileData.push([]); | |
} | |
for (const [index, chunk] of file.fileData.entries()) { | |
await chrome.tabs.sendMessage(sender.tab.id, { | |
type: nameKey, | |
action: 'file', | |
tabId: sender.tab.id, | |
frameId: sender.frameId, | |
file: { | |
fileData: chunk, | |
fileDataIndex: index, | |
fileDataLength: file.fileData.length, | |
fileName: file.fileName, | |
mimeType: file.mimeType, | |
}, | |
}, { | |
frameId: sender.frameId, | |
}); | |
} | |
} | |
chrome.runtime.onMessage.addListener(async (info, sender, sendResponse) => { | |
if (sender.tab.windowId === vivaldiWindowId && info.type === nameKey) { | |
switch (info.action) { | |
case 'click': | |
const clipboardFiles = await readClipboard(info.attributes.accept); | |
const downloadedFiles = await getDownloadedFiles(info.attributes.accept); | |
if (clipboardFiles.length || downloadedFiles.length) { | |
showDialogChooseFile({ | |
info, | |
sender, | |
clipboardFiles, | |
downloadedFiles, | |
}) | |
} else { | |
showAllFiles(sender); | |
} | |
break; | |
} | |
} | |
}); | |
gnoh.timeOut(() => { | |
chrome.tabs.query({ windowId: window.vivaldiWindowId, windowType: 'normal' }, (tabs) => { | |
tabs.forEach((tab) => { | |
chrome.webNavigation.getAllFrames({ tabId: tab.id }, (details) => { | |
details.forEach((detail) => { | |
chrome.scripting.executeScript({ | |
target: { | |
tabId: tab.id, | |
frameIds: [detail.frameId] | |
}, | |
func: inject, | |
args: [nameKey], | |
}); | |
}); | |
}); | |
}); | |
}); | |
chrome.webNavigation.onCommitted.addListener((details) => { | |
chrome.scripting.executeScript({ | |
target: { | |
tabId: details.tabId, | |
frameIds: [details.frameId] | |
}, | |
func: inject, | |
args: [nameKey], | |
}); | |
}); | |
}, () => { | |
return window.vivaldiWindowId != null; | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment