| |
| if (!navigator.clipboard) { |
| navigator.clipboard = { |
| writeText: text => { |
|
|
| |
| const span = document.createElement('span'); |
| span.innerText = text; |
| span.style.whiteSpace = 'pre'; |
|
|
| |
| span.style.position = 'absolute'; |
| span.style.left = '-9999px'; |
| span.style.top = '-9999px'; |
|
|
| const win = window; |
| const selection = win.getSelection(); |
| win.document.body.appendChild(span); |
|
|
| const range = win.document.createRange(); |
| selection.removeAllRanges(); |
| range.selectNode(span); |
| selection.addRange(range); |
|
|
| let success = false; |
| try { |
| success = win.document.execCommand('copy'); |
| } catch (err) { |
| return Promise.error(); |
| } |
|
|
| selection.removeAllRanges(); |
| span.remove(); |
|
|
| return Promise.resolve(); |
| } |
| } |
| } |
|
|
| |
| window.isRtcSupported = !!(window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection); |
|
|
| window.hiddenProperty = 'hidden' in document |
| ? 'hidden' |
| : 'webkitHidden' in document |
| ? 'webkitHidden' |
| : 'mozHidden' in document |
| ? 'mozHidden' |
| : null; |
|
|
| window.visibilityChangeEvent = 'visibilitychange' in document |
| ? 'visibilitychange' |
| : 'webkitvisibilitychange' in document |
| ? 'webkitvisibilitychange' |
| : 'mozvisibilitychange' in document |
| ? 'mozvisibilitychange' |
| : null; |
|
|
| window.iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; |
| window.android = /android/i.test(navigator.userAgent); |
| window.isMobile = window.iOS || window.android; |
|
|
|
|
| |
| const zipper = (() => { |
|
|
| let zipWriter; |
| return { |
| createNewZipWriter() { |
| zipWriter = new zip.ZipWriter(new zip.BlobWriter("application/zip"), { bufferedWrite: true, level: 0 }); |
| }, |
| addFile(file, options) { |
| return zipWriter.add(file.name, new zip.BlobReader(file), options); |
| }, |
| async getBlobURL() { |
| if (zipWriter) { |
| const blobURL = URL.createObjectURL(await zipWriter.close()); |
| zipWriter = null; |
| return blobURL; |
| } |
| else { |
| throw new Error("Zip file closed"); |
| } |
| }, |
| async getZipFile(filename = "archive.zip") { |
| if (zipWriter) { |
| const file = new File([await zipWriter.close()], filename, {type: "application/zip"}); |
| zipWriter = null; |
| return file; |
| } |
| else { |
| throw new Error("Zip file closed"); |
| } |
| }, |
| async getEntries(file, options) { |
| return await (new zip.ZipReader(new zip.BlobReader(file))).getEntries(options); |
| }, |
| async getData(entry, options) { |
| return await entry.getData(new zip.BlobWriter(), options); |
| }, |
| }; |
|
|
| })(); |
|
|
| const mime = (() => { |
|
|
| const suffixToMimeMap = { |
| "cpl": "application/cpl+xml", |
| "gpx": "application/gpx+xml", |
| "gz": "application/gzip", |
| "jar": "application/java-archive", |
| "war": "application/java-archive", |
| "ear": "application/java-archive", |
| "class": "application/java-vm", |
| "js": "application/javascript", |
| "mjs": "application/javascript", |
| "json": "application/json", |
| "map": "application/json", |
| "webmanifest": "application/manifest+json", |
| "doc": "application/msword", |
| "dot": "application/msword", |
| "wiz": "application/msword", |
| "bin": "application/octet-stream", |
| "dms": "application/octet-stream", |
| "lrf": "application/octet-stream", |
| "mar": "application/octet-stream", |
| "so": "application/octet-stream", |
| "dist": "application/octet-stream", |
| "distz": "application/octet-stream", |
| "pkg": "application/octet-stream", |
| "bpk": "application/octet-stream", |
| "dump": "application/octet-stream", |
| "elc": "application/octet-stream", |
| "deploy": "application/octet-stream", |
| "img": "application/octet-stream", |
| "msp": "application/octet-stream", |
| "msm": "application/octet-stream", |
| "buffer": "application/octet-stream", |
| "oda": "application/oda", |
| "oxps": "application/oxps", |
| "pdf": "application/pdf", |
| "asc": "application/pgp-signature", |
| "sig": "application/pgp-signature", |
| "prf": "application/pics-rules", |
| "p7c": "application/pkcs7-mime", |
| "cer": "application/pkix-cert", |
| "ai": "application/postscript", |
| "eps": "application/postscript", |
| "ps": "application/postscript", |
| "apk": "application/vnd.android.package-archive", |
| "m3u8": "application/vnd.apple.mpegurl", |
| "pkpass": "application/vnd.apple.pkpass", |
| "kml": "application/vnd.google-earth.kml+xml", |
| "kmz": "application/vnd.google-earth.kmz", |
| "cab": "application/vnd.ms-cab-compressed", |
| "xls": "application/vnd.ms-excel", |
| "xlm": "application/vnd.ms-excel", |
| "xla": "application/vnd.ms-excel", |
| "xlc": "application/vnd.ms-excel", |
| "xlt": "application/vnd.ms-excel", |
| "xlw": "application/vnd.ms-excel", |
| "msg": "application/vnd.ms-outlook", |
| "ppt": "application/vnd.ms-powerpoint", |
| "pot": "application/vnd.ms-powerpoint", |
| "ppa": "application/vnd.ms-powerpoint", |
| "pps": "application/vnd.ms-powerpoint", |
| "pwz": "application/vnd.ms-powerpoint", |
| "mpp": "application/vnd.ms-project", |
| "mpt": "application/vnd.ms-project", |
| "xps": "application/vnd.ms-xpsdocument", |
| "odb": "application/vnd.oasis.opendocument.database", |
| "ods": "application/vnd.oasis.opendocument.spreadsheet", |
| "odt": "application/vnd.oasis.opendocument.text", |
| "osm": "application/vnd.openstreetmap.data+xml", |
| "pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", |
| "xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", |
| "docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", |
| "pcap": "application/vnd.tcpdump.pcap", |
| "cap": "application/vnd.tcpdump.pcap", |
| "dmp": "application/vnd.tcpdump.pcap", |
| "wpd": "application/vnd.wordperfect", |
| "wasm": "application/wasm", |
| "7z": "application/x-7z-compressed", |
| "dmg": "application/x-apple-diskimage", |
| "bcpio": "application/x-bcpio", |
| "torrent": "application/x-bittorrent", |
| "cbr": "application/x-cbr", |
| "cba": "application/x-cbr", |
| "cbt": "application/x-cbr", |
| "cbz": "application/x-cbr", |
| "cb7": "application/x-cbr", |
| "vcd": "application/x-cdlink", |
| "crx": "application/x-chrome-extension", |
| "cpio": "application/x-cpio", |
| "csh": "application/x-csh", |
| "deb": "application/x-debian-package", |
| "udeb": "application/x-debian-package", |
| "dvi": "application/x-dvi", |
| "arc": "application/x-freearc", |
| "gtar": "application/x-gtar", |
| "hdf": "application/x-hdf", |
| "h5": "application/x-hdf5", |
| "php": "application/x-httpd-php", |
| "iso": "application/x-iso9660-image", |
| "key": "application/x-iwork-keynote-sffkey", |
| "numbers": "application/x-iwork-numbers-sffnumbers", |
| "pages": "application/x-iwork-pages-sffpages", |
| "latex": "application/x-latex", |
| "run": "application/x-makeself", |
| "mif": "application/x-mif", |
| "lnk": "application/x-ms-shortcut", |
| "mdb": "application/x-msaccess", |
| "exe": "application/x-msdownload", |
| "dll": "application/x-msdownload", |
| "com": "application/x-msdownload", |
| "bat": "application/x-msdownload", |
| "msi": "application/x-msdownload", |
| "pub": "application/x-mspublisher", |
| "cdf": "application/x-netcdf", |
| "nc": "application/x-netcdf", |
| "pl": "application/x-perl", |
| "pm": "application/x-perl", |
| "prc": "application/x-pilot", |
| "pdb": "application/x-pilot", |
| "p12": "application/x-pkcs12", |
| "pfx": "application/x-pkcs12", |
| "ram": "application/x-pn-realaudio", |
| "pyc": "application/x-python-code", |
| "pyo": "application/x-python-code", |
| "rar": "application/x-rar-compressed", |
| "rpm": "application/x-redhat-package-manager", |
| "sh": "application/x-sh", |
| "shar": "application/x-shar", |
| "swf": "application/x-shockwave-flash", |
| "sql": "application/x-sql", |
| "srt": "application/x-subrip", |
| "sv4cpio": "application/x-sv4cpio", |
| "sv4crc": "application/x-sv4crc", |
| "gam": "application/x-tads", |
| "tar": "application/x-tar", |
| "tcl": "application/x-tcl", |
| "tex": "application/x-tex", |
| "roff": "application/x-troff", |
| "t": "application/x-troff", |
| "tr": "application/x-troff", |
| "man": "application/x-troff-man", |
| "me": "application/x-troff-me", |
| "ms": "application/x-troff-ms", |
| "ustar": "application/x-ustar", |
| "src": "application/x-wais-source", |
| "xpi": "application/x-xpinstall", |
| "xhtml": "application/xhtml+xml", |
| "xht": "application/xhtml+xml", |
| "xsl": "application/xml", |
| "rdf": "application/xml", |
| "wsdl": "application/xml", |
| "xpdl": "application/xml", |
| "zip": "application/zip", |
| "3gp": "audio/3gp", |
| "3gpp": "audio/3gpp", |
| "3g2": "audio/3gpp2", |
| "3gpp2": "audio/3gpp2", |
| "aac": "audio/aac", |
| "adts": "audio/aac", |
| "loas": "audio/aac", |
| "ass": "audio/aac", |
| "au": "audio/basic", |
| "snd": "audio/basic", |
| "mid": "audio/midi", |
| "midi": "audio/midi", |
| "kar": "audio/midi", |
| "rmi": "audio/midi", |
| "mpga": "audio/mpeg", |
| "mp2": "audio/mpeg", |
| "mp2a": "audio/mpeg", |
| "mp3": "audio/mpeg", |
| "m2a": "audio/mpeg", |
| "m3a": "audio/mpeg", |
| "oga": "audio/ogg", |
| "ogg": "audio/ogg", |
| "spx": "audio/ogg", |
| "opus": "audio/opus", |
| "aif": "audio/x-aiff", |
| "aifc": "audio/x-aiff", |
| "aiff": "audio/x-aiff", |
| "flac": "audio/x-flac", |
| "m4a": "audio/x-m4a", |
| "m3u": "audio/x-mpegurl", |
| "wma": "audio/x-ms-wma", |
| "ra": "audio/x-pn-realaudio", |
| "wav": "audio/x-wav", |
| "otf": "font/otf", |
| "ttf": "font/ttf", |
| "woff": "font/woff", |
| "woff2": "font/woff2", |
| "emf": "image/emf", |
| "gif": "image/gif", |
| "heic": "image/heic", |
| "heif": "image/heif", |
| "ief": "image/ief", |
| "jpeg": "image/jpeg", |
| "jpg": "image/jpeg", |
| "pict": "image/pict", |
| "pct": "image/pict", |
| "pic": "image/pict", |
| "png": "image/png", |
| "svg": "image/svg+xml", |
| "svgz": "image/svg+xml", |
| "tif": "image/tiff", |
| "tiff": "image/tiff", |
| "psd": "image/vnd.adobe.photoshop", |
| "djvu": "image/vnd.djvu", |
| "djv": "image/vnd.djvu", |
| "dwg": "image/vnd.dwg", |
| "dxf": "image/vnd.dxf", |
| "dds": "image/vnd.ms-dds", |
| "webp": "image/webp", |
| "3ds": "image/x-3ds", |
| "ras": "image/x-cmu-raster", |
| "ico": "image/x-icon", |
| "bmp": "image/x-ms-bmp", |
| "pnm": "image/x-portable-anymap", |
| "pbm": "image/x-portable-bitmap", |
| "pgm": "image/x-portable-graymap", |
| "ppm": "image/x-portable-pixmap", |
| "rgb": "image/x-rgb", |
| "tga": "image/x-tga", |
| "xbm": "image/x-xbitmap", |
| "xpm": "image/x-xpixmap", |
| "xwd": "image/x-xwindowdump", |
| "eml": "message/rfc822", |
| "mht": "message/rfc822", |
| "mhtml": "message/rfc822", |
| "nws": "message/rfc822", |
| "obj": "model/obj", |
| "stl": "model/stl", |
| "dae": "model/vnd.collada+xml", |
| "ics": "text/calendar", |
| "ifb": "text/calendar", |
| "css": "text/css", |
| "csv": "text/csv", |
| "html": "text/html", |
| "htm": "text/html", |
| "shtml": "text/html", |
| "markdown": "text/markdown", |
| "md": "text/markdown", |
| "txt": "text/plain", |
| "text": "text/plain", |
| "conf": "text/plain", |
| "def": "text/plain", |
| "list": "text/plain", |
| "log": "text/plain", |
| "in": "text/plain", |
| "ini": "text/plain", |
| "rtx": "text/richtext", |
| "rtf": "text/rtf", |
| "tsv": "text/tab-separated-values", |
| "c": "text/x-c", |
| "cc": "text/x-c", |
| "cxx": "text/x-c", |
| "cpp": "text/x-c", |
| "h": "text/x-c", |
| "hh": "text/x-c", |
| "dic": "text/x-c", |
| "java": "text/x-java-source", |
| "lua": "text/x-lua", |
| "py": "text/x-python", |
| "etx": "text/x-setext", |
| "sgm": "text/x-sgml", |
| "sgml": "text/x-sgml", |
| "vcf": "text/x-vcard", |
| "xml": "text/xml", |
| "xul": "text/xul", |
| "yaml": "text/yaml", |
| "yml": "text/yaml", |
| "ts": "video/mp2t", |
| "mp4": "video/mp4", |
| "mp4v": "video/mp4", |
| "mpg4": "video/mp4", |
| "mpeg": "video/mpeg", |
| "m1v": "video/mpeg", |
| "mpa": "video/mpeg", |
| "mpe": "video/mpeg", |
| "mpg": "video/mpeg", |
| "mov": "video/quicktime", |
| "qt": "video/quicktime", |
| "webm": "video/webm", |
| "flv": "video/x-flv", |
| "m4v": "video/x-m4v", |
| "asf": "video/x-ms-asf", |
| "asx": "video/x-ms-asf", |
| "vob": "video/x-ms-vob", |
| "wmv": "video/x-ms-wmv", |
| "avi": "video/x-msvideo", |
| "*": "video/x-sgi-movie", |
| "kdbx": "application/x-keepass2" |
| } |
|
|
| return { |
| guessMimeByFilename(filename) { |
| const split = filename.split('.'); |
| if (split.length === 1) { |
| |
| return false; |
| } |
| const suffix = split[split.length - 1].toLowerCase(); |
| return suffixToMimeMap[suffix]; |
| }, |
| addMissingMimeTypesToFiles(files) { |
| |
| for (let i = 0; i < files.length; i++) { |
| if (!files[i].type) { |
| files[i] = new File([files[i]], files[i].name, {type: mime.guessMimeByFilename(files[i].name) || "application/octet-stream"}); |
| } |
| } |
| return files; |
| } |
| }; |
|
|
| })(); |
|
|
| |
| |
| |
| |
| |
| |
| const cyrb53 = function(str, seed = 0) { |
| let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; |
| for (let i = 0, ch; i < str.length; i++) { |
| ch = str.charCodeAt(i); |
| h1 = Math.imul(h1 ^ ch, 2654435761); |
| h2 = Math.imul(h2 ^ ch, 1597334677); |
| } |
| h1 = Math.imul(h1 ^ (h1>>>16), 2246822507) ^ Math.imul(h2 ^ (h2>>>13), 3266489909); |
| h2 = Math.imul(h2 ^ (h2>>>16), 2246822507) ^ Math.imul(h1 ^ (h1>>>13), 3266489909); |
| return 4294967296 * (2097151 & h2) + (h1>>>0); |
| }; |
|
|
| function onlyUnique (value, index, array) { |
| return array.indexOf(value) === index; |
| } |
|
|
| function getUrlWithoutArguments() { |
| return `${window.location.protocol}//${window.location.host}${window.location.pathname}`; |
| } |
|
|
| function changeFavicon(src) { |
| document.querySelector('[rel="icon"]').href = src; |
| document.querySelector('[rel="shortcut icon"]').href = src; |
| } |
|
|
| function arrayBufferToBase64(buffer) { |
| let binary = ''; |
| let bytes = new Uint8Array(buffer); |
| let len = bytes.byteLength; |
| for (let i = 0; i < len; i++) { |
| binary += String.fromCharCode(bytes[i]); |
| } |
| return window.btoa( binary ); |
| } |
|
|
| function base64ToArrayBuffer(base64) { |
| let binary_string = window.atob(base64); |
| let len = binary_string.length; |
| let bytes = new Uint8Array(len); |
| for (let i = 0; i < len; i++) { |
| bytes[i] = binary_string.charCodeAt(i); |
| } |
| return bytes.buffer; |
| } |
|
|
| async function fileToBlob (file) { |
| return new Blob([new Uint8Array(await file.arrayBuffer())], {type: file.type}); |
| } |
|
|
| function getThumbnailAsDataUrl(file, width = undefined, height = undefined, quality = 0.7) { |
| return new Promise(async (resolve, reject) => { |
| try { |
| if (file.type === "image/heif" || file.type === "image/heic") { |
| |
| reject(new Error(`Hotfix: Converting of HEIC/HEIF images currently disabled.`)); |
| return; |
| |
| |
| |
| |
| |
| |
| |
| } |
|
|
| let imageUrl = URL.createObjectURL(file); |
|
|
| let image = new Image(); |
| image.src = imageUrl; |
|
|
| await waitUntilImageIsLoaded(imageUrl); |
|
|
| let imageWidth = image.width; |
| let imageHeight = image.height; |
| let canvas = document.createElement('canvas'); |
|
|
| |
| if (width && height) { |
| canvas.width = width; |
| canvas.height = height; |
| } |
| else if (width) { |
| canvas.width = width; |
| canvas.height = Math.floor(imageHeight * width / imageWidth) |
| } |
| else if (height) { |
| canvas.width = Math.floor(imageWidth * height / imageHeight); |
| canvas.height = height; |
| } |
| else { |
| canvas.width = imageWidth; |
| canvas.height = imageHeight |
| } |
|
|
| let ctx = canvas.getContext("2d"); |
| ctx.drawImage(image, 0, 0, canvas.width, canvas.height); |
|
|
| let dataUrl = canvas.toDataURL("image/jpeg", quality); |
| resolve(dataUrl); |
| } catch (e) { |
| console.error(e); |
| reject(new Error(`Could not create an image thumbnail from type ${file.type}`)); |
| } |
| }) |
| } |
|
|
| |
| function waitUntilImageIsLoaded(imageUrl, timeout = 10000) { |
| return new Promise((resolve, reject) => { |
| let image = new Image(); |
| image.src = imageUrl; |
|
|
| const onLoad = () => { |
| cleanup(); |
| resolve(); |
| }; |
|
|
| const onError = () => { |
| cleanup(); |
| reject(new Error('Image failed to load.')); |
| }; |
|
|
| const cleanup = () => { |
| clearTimeout(timeoutId); |
| image.onload = null; |
| image.onerror = null; |
| URL.revokeObjectURL(imageUrl); |
| }; |
|
|
| const timeoutId = setTimeout(() => { |
| cleanup(); |
| reject(new Error('Image loading timed out.')); |
| }, timeout); |
|
|
| image.onload = onLoad; |
| image.onerror = onError; |
| }); |
| } |
|
|
| async function decodeBase64Files(base64) { |
| if (!base64) throw new Error('Base64 is empty'); |
|
|
| let bstr = atob(base64), n = bstr.length, u8arr = new Uint8Array(n); |
| while (n--) { |
| u8arr[n] = bstr.charCodeAt(n); |
| } |
|
|
| const zipBlob = new File([u8arr], 'archive.zip'); |
|
|
| let files = []; |
| const zipEntries = await zipper.getEntries(zipBlob); |
| for (let i = 0; i < zipEntries.length; i++) { |
| let fileBlob = await zipper.getData(zipEntries[i]); |
| files.push(new File([fileBlob], zipEntries[i].filename)); |
| } |
| return files |
| } |
|
|
| async function decodeBase64Text(base64) { |
| if (!base64) throw new Error('Base64 is empty'); |
|
|
| return decodeURIComponent(escape(window.atob(base64))) |
| } |
|
|
| function isUrlValid(url) { |
| try { |
| new URL(url); |
| return true; |
| } |
| catch (e) { |
| return false; |
| } |
| } |