mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2024-12-13 16:06:21 +00:00
7855801d62
Rewritten codes for home uploader config. All options are now defined in a single config object in home.js. Config tab content will be dynamically generated through that config. This should eliminate the need of modifying home.njk whenever a new option needs to be added, make the codes more readable, and easier to extend. Upgrade stylelint dev dependency. Bumped v1 version string.
1 line
47 KiB
Plaintext
1 line
47 KiB
Plaintext
{"version":3,"sources":["home.js"],"names":["const","lsKeys","token","chunkSize","parallelUploads","uploadsHistoryOrder","previewImages","fileLength","uploadAge","page","localStorage","private","enableUserAccounts","maxSize","temporaryUploadAges","fileIdentifierLength","album","maxSizeBytes","urlMaxSize","urlMaxSizeBytes","tabs","activeTab","albumSelect","previewTemplate","dropzone","clipboardJS","lazyLoad","imageExts","videoExts","albumTitleMaxLength","albumDescMaxLength","onInitError","error","document","querySelector","classList","add","querySelectorAll","forEach","element","uploadButton","innerText","remove","addEventListener","location","reload","response","onAxiosError","onError","console","content","createElement","innerHTML","toString","swal","title","icon","statusText","520","521","522","523","524","525","526","527","530","status","description","data","checkIfPublic","let","renderShown","axios","get","onDownloadProgress","doRender","then","parseInt","preparePage","catch","prepareUpload","verifyToken","button","href","reloadOnError","post","success","text","removeItem","value","prepareShareX","fetchAlbums","prepareUploadConfig","getPrettyBytes","prepareDropzone","event","uploadUrls","currentTarget","tabsContainer","loop","i","id","dataset","tabContent","setActiveTab","push","tab","length","index","headers","Array","isArray","albums","option","name","appendChild","previewNode","parentNode","removeChild","tabDiv","div","className","previewsContainer","Dropzone","body","url","paramName","clickable","maxFilesize","uploadMultiple","createImageThumbnails","autoProcessQueue","chunking","Boolean","parallelChunkUploads","chunksUploaded","file","done","previewElement","setAttribute","files","uuid","upload","original","type","albumid","filelength","age","updateTemplate","on","xhr","chunked","setRequestHeader","progress","test","size","updateTemplateIcon","contains","urls","split","filter","trim","join","map","firstChild","posted","result","removeAttribute","run","templateElement","iconClass","iconElement","a","clipboard","clipboardText","parentElement","exec","extname","toLowerCase","includes","img","src","onerror","update","expirydate","expiryDate","getPrettyDate","Date","createAlbum","buttons","cancel","confirm","closeModal","download","checked","public","selected","fallback","min","max","config","siBytes","label","select","help","valueHandler","display","number","round","undefined","disabled","force","isNaN","suffix","uploadFields","stored","parseFloat","String","getPrettyUploadAge","default","form","preventDefault","configKeys","Object","keys","key","conf","field","parsed","control","opts","j","opt","tmp","submit","checkValidity","elements","Math","hours","minutes","days","window","items","clipboardData","originalEvent","item","kind","blob","getAsFile","File","match","addFile","onload","ClipboardJS","LazyLoad","elements_selector"],"mappings":"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","file":"home.js","sourcesContent":["/* global swal, axios, Dropzone, ClipboardJS, LazyLoad */\n\nconst lsKeys = {\n token: 'token',\n chunkSize: 'chunkSize',\n parallelUploads: 'parallelUploads',\n uploadsHistoryOrder: 'uploadsHistoryOrder',\n previewImages: 'previewImages',\n fileLength: 'fileLength',\n uploadAge: 'uploadAge'\n}\n\nconst page = {\n // user token\n token: localStorage[lsKeys.token],\n\n // configs from api/check\n private: null,\n enableUserAccounts: null,\n maxSize: null,\n chunkSize: null,\n temporaryUploadAges: null,\n fileIdentifierLength: null,\n\n // store album id that will be used with upload requests\n album: null,\n\n parallelUploads: 2,\n previewImages: null,\n fileLength: null,\n uploadAge: null,\n\n maxSizeBytes: null,\n urlMaxSize: null,\n urlMaxSizeBytes: null,\n\n tabs: [],\n activeTab: null,\n albumSelect: null,\n previewTemplate: null,\n\n dropzone: null,\n clipboardJS: null,\n lazyLoad: null,\n\n // Include BMP for uploads preview only, cause the real images will be used\n // Sharp isn't capable of making their thumbnails for dashboard and album public pages\n imageExts: ['.webp', '.jpg', '.jpeg', '.bmp', '.gif', '.png', '.tiff', '.tif', '.svg'],\n videoExts: ['.webm', '.mp4', '.wmv', '.avi', '.mov', '.mkv'],\n\n albumTitleMaxLength: 70,\n albumDescMaxLength: 4000\n}\n\n// Handler for errors during initialization\npage.onInitError = error => {\n // Hide these elements\n document.querySelector('#albumDiv').classList.add('is-hidden')\n document.querySelector('#tabs').classList.add('is-hidden')\n document.querySelectorAll('.tab-content').forEach(element => {\n return element.classList.add('is-hidden')\n })\n\n // Update upload button\n const uploadButton = document.querySelector('#loginToUpload')\n uploadButton.innerText = 'An error occurred. Try to reload?'\n uploadButton.classList.remove('is-loading')\n uploadButton.classList.remove('is-hidden')\n\n uploadButton.addEventListener('click', () => {\n location.reload()\n })\n\n if (error.response)\n page.onAxiosError(error)\n else\n page.onError(error)\n}\n\n// Handler for regular JS errors\npage.onError = error => {\n console.error(error)\n\n const content = document.createElement('div')\n content.innerHTML = `<code>${error.toString()}</code>`\n return swal({\n title: 'An error occurred!',\n icon: 'error',\n content\n })\n}\n\n// Handler for Axios errors\npage.onAxiosError = error => {\n console.error(error)\n\n // Better Cloudflare errors\n const cloudflareErrors = {\n 520: 'Unknown Error',\n 521: 'Web Server Is Down',\n 522: 'Connection Timed Out',\n 523: 'Origin Is Unreachable',\n 524: 'A Timeout Occurred',\n 525: 'SSL Handshake Failed',\n 526: 'Invalid SSL Certificate',\n 527: 'Railgun Error',\n 530: 'Origin DNS Error'\n }\n\n const statusText = cloudflareErrors[error.response.status] || error.response.statusText\n const description = error.response.data && error.response.data.description\n ? error.response.data.description\n : 'There was an error with the request, please check the console for more information.'\n\n return swal(`${error.response.status} ${statusText}`, description, 'error')\n}\n\npage.checkIfPublic = () => {\n let renderShown = false\n return axios.get('api/check', {\n onDownloadProgress: () => {\n // Only show render after this request has been initiated\n if (!renderShown && typeof page.doRender === 'function') {\n page.doRender()\n renderShown = true\n }\n }\n }).then(response => {\n page.private = response.data.private\n page.enableUserAccounts = response.data.enableUserAccounts\n page.maxSize = parseInt(response.data.maxSize)\n page.maxSizeBytes = page.maxSize * 1e6\n page.chunkSize = parseInt(response.data.chunkSize)\n page.temporaryUploadAges = response.data.temporaryUploadAges\n page.fileIdentifierLength = response.data.fileIdentifierLength\n return page.preparePage()\n }).catch(page.onInitError)\n}\n\npage.preparePage = () => {\n if (page.private)\n if (page.token) {\n return page.verifyToken(page.token, true)\n } else {\n const button = document.querySelector('#loginToUpload')\n button.href = 'auth'\n button.classList.remove('is-loading')\n if (page.enableUserAccounts)\n button.innerText = 'Anonymous upload is disabled. Log in to upload.'\n else\n button.innerText = 'Running in private mode. Log in to upload.'\n }\n else\n return page.prepareUpload()\n}\n\npage.verifyToken = (token, reloadOnError) => {\n return axios.post('api/tokens/verify', { token }).then(response => {\n if (response.data.success === false)\n return swal({\n title: 'An error occurred!',\n text: response.data.description,\n icon: 'error'\n }).then(() => {\n if (!reloadOnError) return\n localStorage.removeItem('token')\n location.reload()\n })\n\n localStorage[lsKeys.token] = token\n page.token = token\n return page.prepareUpload()\n }).catch(page.onInitError)\n}\n\npage.prepareUpload = () => {\n // I think this fits best here because we need to check for a valid token before we can get the albums\n if (page.token) {\n // Display the album selection\n document.querySelector('#albumDiv').classList.remove('is-hidden')\n\n page.albumSelect = document.querySelector('#albumSelect')\n page.albumSelect.addEventListener('change', () => {\n page.album = parseInt(page.albumSelect.value)\n // Re-generate ShareX config file\n if (typeof page.prepareShareX === 'function')\n page.prepareShareX()\n })\n\n // Fetch albums\n page.fetchAlbums()\n }\n\n // Prepare & generate config tab\n page.prepareUploadConfig()\n\n // Update elements wherever applicable\n document.querySelector('#maxSize > span').innerHTML = page.getPrettyBytes(page.maxSizeBytes)\n document.querySelector('#loginToUpload').classList.add('is-hidden')\n\n if (!page.token && page.enableUserAccounts)\n document.querySelector('#loginLinkText').innerHTML = 'Create an account and keep track of your uploads'\n\n // Prepare & generate files upload tab\n page.prepareDropzone()\n\n // Generate ShareX config file\n if (typeof page.prepareShareX === 'function')\n page.prepareShareX()\n\n // Prepare urls upload tab\n const urlMaxSize = document.querySelector('#urlMaxSize')\n if (urlMaxSize) {\n page.urlMaxSize = parseInt(urlMaxSize.innerHTML)\n page.urlMaxSizeBytes = page.urlMaxSize * 1e6\n urlMaxSize.innerHTML = page.getPrettyBytes(page.urlMaxSizeBytes)\n document.querySelector('#uploadUrls').addEventListener('click', event => {\n page.uploadUrls(event.currentTarget)\n })\n }\n\n // Get all tabs\n const tabsContainer = document.querySelector('#tabs')\n const tabs = tabsContainer.querySelectorAll('li')\n for (let i = 0; i < tabs.length; i++) {\n const id = tabs[i].dataset.id\n const tabContent = document.querySelector(`#${id}`)\n if (!tabContent) continue\n\n tabs[i].addEventListener('click', () => {\n page.setActiveTab(i)\n })\n page.tabs.push({ tab: tabs[i], content: tabContent })\n }\n\n // Set first valid tab as the default active tab\n if (page.tabs.length) {\n page.setActiveTab(0)\n tabsContainer.classList.remove('is-hidden')\n }\n}\n\npage.setActiveTab = index => {\n for (let i = 0; i < page.tabs.length; i++)\n if (i === index) {\n page.tabs[i].tab.classList.add('is-active')\n page.tabs[i].content.classList.remove('is-hidden')\n page.activeTab = index\n } else {\n page.tabs[i].tab.classList.remove('is-active')\n page.tabs[i].content.classList.add('is-hidden')\n }\n}\n\npage.fetchAlbums = () => {\n return axios.get('api/albums', { headers: { token: page.token } }).then(response => {\n if (response.data.success === false)\n return swal('An error occurred!', response.data.description, 'error')\n\n // Create an option for each album\n if (Array.isArray(response.data.albums) && response.data.albums.length)\n for (let i = 0; i < response.data.albums.length; i++) {\n const album = response.data.albums[i]\n const option = document.createElement('option')\n option.value = album.id\n option.innerHTML = album.name\n page.albumSelect.appendChild(option)\n }\n }).catch(page.onInitError)\n}\n\npage.prepareDropzone = () => {\n // Parse template element\n const previewNode = document.querySelector('#tpl')\n page.previewTemplate = previewNode.innerHTML\n previewNode.parentNode.removeChild(previewNode)\n\n // Generate files upload tab\n const tabDiv = document.querySelector('#tab-files')\n const div = document.createElement('div')\n div.className = 'control is-expanded'\n div.innerHTML = `\n <div id=\"dropzone\" class=\"button is-danger is-outlined is-fullwidth is-unselectable\">\n <span class=\"icon\">\n <i class=\"icon-upload-cloud\"></i>\n </span>\n <span>Click here or drag & drop files</span>\n </div>\n `\n tabDiv.querySelector('.dz-container').appendChild(div)\n\n const previewsContainer = tabDiv.querySelector('#tab-files .field.uploads')\n\n page.dropzone = new Dropzone(document.body, {\n url: 'api/upload',\n paramName: 'files[]',\n clickable: tabDiv.querySelector('#dropzone'),\n maxFilesize: page.maxSizeBytes / 1024 / 1024, // this option expects MiB\n parallelUploads: page.parallelUploads,\n uploadMultiple: false,\n previewsContainer,\n previewTemplate: page.previewTemplate,\n createImageThumbnails: false,\n autoProcessQueue: true,\n headers: { token: page.token },\n chunking: Boolean(page.chunkSize),\n chunkSize: page.chunkSize * 1e6, // the option below expects Bytes\n parallelChunkUploads: false, // when set to true, it often hangs with hundreds of parallel uploads\n chunksUploaded (file, done) {\n file.previewElement.querySelector('.progress').setAttribute('value', 100)\n file.previewElement.querySelector('.progress').innerHTML = '100%'\n\n return axios.post('api/upload/finishchunks', {\n // This API supports an array of multiple files\n files: [{\n uuid: file.upload.uuid,\n original: file.name,\n type: file.type,\n albumid: page.album,\n filelength: page.fileLength,\n age: page.uploadAge\n }]\n }, { headers: { token: page.token } }).catch(error => {\n // Format error for display purpose\n return error.response.data ? error.response : {\n data: {\n success: false,\n description: error.toString()\n }\n }\n }).then(response => {\n file.previewElement.querySelector('.progress').classList.add('is-hidden')\n\n if (response.data.success === false)\n file.previewElement.querySelector('.error').innerHTML = response.data.description\n\n if (response.data.files && response.data.files[0])\n page.updateTemplate(file, response.data.files[0])\n\n return done()\n })\n }\n })\n\n page.dropzone.on('addedfile', file => {\n // Set active tab to file uploads, if necessary\n if (page.activeTab !== 0)\n page.setActiveTab(0)\n // Add file entry\n tabDiv.querySelector('.uploads').classList.remove('is-hidden')\n file.previewElement.querySelector('.name').innerHTML = file.name\n })\n\n page.dropzone.on('sending', (file, xhr) => {\n if (file.upload.chunked) return\n // Add headers if not uploading chunks\n if (page.album !== null) xhr.setRequestHeader('albumid', page.album)\n if (page.fileLength !== null) xhr.setRequestHeader('filelength', page.fileLength)\n if (page.uploadAge !== null) xhr.setRequestHeader('age', page.uploadAge)\n })\n\n // Update the total progress bar\n page.dropzone.on('uploadprogress', (file, progress) => {\n // For some reason, chunked uploads fire 100% progress event\n // for each chunk's successful uploads\n if (file.upload.chunked && progress === 100) return\n file.previewElement.querySelector('.progress').setAttribute('value', progress)\n file.previewElement.querySelector('.progress').innerHTML = `${progress}%`\n })\n\n page.dropzone.on('success', (file, response) => {\n if (!response) return\n file.previewElement.querySelector('.progress').classList.add('is-hidden')\n\n if (response.success === false)\n file.previewElement.querySelector('.error').innerHTML = response.description\n\n if (response.files && response.files[0])\n page.updateTemplate(file, response.files[0])\n })\n\n page.dropzone.on('error', (file, error) => {\n // Clean up file size errors\n if ((typeof error === 'string' && /^File is too big/.test(error)) ||\n (typeof error === 'object' && /File too large/.test(error.description)))\n error = `File too large (${page.getPrettyBytes(file.size)}).`\n\n page.updateTemplateIcon(file.previewElement, 'icon-block')\n file.previewElement.querySelector('.progress').classList.add('is-hidden')\n file.previewElement.querySelector('.name').innerHTML = file.name\n file.previewElement.querySelector('.error').innerHTML = error.description || error\n })\n}\n\npage.uploadUrls = button => {\n const tabDiv = document.querySelector('#tab-urls')\n if (!tabDiv || button.classList.contains('is-loading'))\n return\n\n button.classList.add('is-loading')\n\n function done (error) {\n if (error) swal('An error occurred!', error, 'error')\n button.classList.remove('is-loading')\n }\n\n function run () {\n const headers = {\n token: page.token,\n albumid: page.album,\n age: page.uploadAge,\n filelength: page.fileLength\n }\n\n const previewsContainer = tabDiv.querySelector('.uploads')\n const urls = document.querySelector('#urls').value\n .split(/\\r?\\n/)\n .filter(url => {\n return url.trim().length\n })\n document.querySelector('#urls').value = urls.join('\\n')\n\n if (!urls.length)\n return done('You have not entered any URLs.')\n\n tabDiv.querySelector('.uploads').classList.remove('is-hidden')\n const files = urls.map(url => {\n const previewTemplate = document.createElement('template')\n previewTemplate.innerHTML = page.previewTemplate.trim()\n const previewElement = previewTemplate.content.firstChild\n previewElement.querySelector('.name').innerHTML = url\n previewsContainer.appendChild(previewElement)\n return { url, previewElement }\n })\n\n function post (i) {\n if (i === files.length)\n return done()\n\n function posted (result) {\n files[i].previewElement.querySelector('.progress').classList.add('is-hidden')\n if (result.success) {\n page.updateTemplate(files[i], result.files[0])\n } else {\n page.updateTemplateIcon(files[i].previewElement, 'icon-block')\n files[i].previewElement.querySelector('.error').innerHTML = result.description\n }\n return post(i + 1)\n }\n\n // Animate progress bar\n files[i].previewElement.querySelector('.progress').removeAttribute('value')\n\n return axios.post('api/upload', { urls: [files[i].url] }, { headers }).then(response => {\n return posted(response.data)\n }).catch(error => {\n return posted({\n success: false,\n description: error.response ? error.response.data.description : error.toString()\n })\n })\n }\n return post(0)\n }\n return run()\n}\n\npage.updateTemplateIcon = (templateElement, iconClass) => {\n const iconElement = templateElement.querySelector('.icon')\n if (!iconElement) return\n iconElement.classList.add(iconClass)\n iconElement.classList.remove('is-hidden')\n}\n\npage.updateTemplate = (file, response) => {\n if (!response.url) return\n\n const a = file.previewElement.querySelector('.link > a')\n const clipboard = file.previewElement.querySelector('.clipboard-mobile > .clipboard-js')\n a.href = a.innerHTML = clipboard.dataset.clipboardText = response.url\n clipboard.parentElement.classList.remove('is-hidden')\n\n const exec = /.[\\w]+(\\?|$)/.exec(response.url)\n const extname = exec && exec[0]\n ? exec[0].toLowerCase()\n : null\n\n if (page.imageExts.includes(extname))\n if (page.previewImages) {\n const img = file.previewElement.querySelector('img')\n img.setAttribute('alt', response.name || '')\n img.dataset.src = response.url\n img.classList.remove('is-hidden')\n img.onerror = event => {\n // Hide image elements that fail to load\n // Consequently include WEBP in browsers that do not have WEBP support (e.i. IE)\n event.currentTarget.classList.add('is-hidden')\n page.updateTemplateIcon(file.previewElement, 'icon-picture')\n }\n page.lazyLoad.update(file.previewElement.querySelectorAll('img'))\n } else {\n page.updateTemplateIcon(file.previewElement, 'icon-picture')\n }\n else if (page.videoExts.includes(extname))\n page.updateTemplateIcon(file.previewElement, 'icon-video')\n else\n page.updateTemplateIcon(file.previewElement, 'icon-doc-inv')\n\n if (response.expirydate) {\n const expiryDate = file.previewElement.querySelector('.expiry-date')\n expiryDate.innerHTML = `EXP: ${page.getPrettyDate(new Date(response.expirydate * 1000))}`\n expiryDate.classList.remove('is-hidden')\n }\n}\n\npage.createAlbum = () => {\n const div = document.createElement('div')\n div.innerHTML = `\n <div class=\"field\">\n <div class=\"controls\">\n <input id=\"swalName\" class=\"input\" type=\"text\" placeholder=\"Name\" maxlength=\"${page.albumTitleMaxLength}\">\n </div>\n <p class=\"help\">Max length is ${page.albumTitleMaxLength} characters.</p>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <textarea id=\"swalDescription\" class=\"textarea\" placeholder=\"Description\" rows=\"2\" maxlength=\"${page.albumDescMaxLength}\"></textarea>\n </div>\n <p class=\"help\">Max length is ${page.albumDescMaxLength} characters.</p>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <label class=\"checkbox\">\n <input id=\"swalDownload\" type=\"checkbox\" checked>\n Enable download\n </label>\n </div>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <label class=\"checkbox\">\n <input id=\"swalPublic\" type=\"checkbox\" checked>\n Enable public link\n </label>\n </div>\n </div>\n `\n\n swal({\n title: 'Create new album',\n icon: 'info',\n content: div,\n buttons: {\n cancel: true,\n confirm: {\n closeModal: false\n }\n }\n }).then(value => {\n if (!value) return\n\n const name = document.querySelector('#swalName').value.trim()\n axios.post('api/albums', {\n name,\n description: document.querySelector('#swalDescription').value.trim(),\n download: document.querySelector('#swalDownload').checked,\n public: document.querySelector('#swalPublic').checked\n }, {\n headers: {\n token: page.token\n }\n }).then(response => {\n if (response.data.success === false)\n return swal('An error occurred!', response.data.description, 'error')\n\n const option = document.createElement('option')\n page.albumSelect.appendChild(option)\n option.value = response.data.id\n option.innerHTML = name\n option.selected = true\n\n swal('Woohoo!', 'Album was created successfully.', 'success')\n }).catch(page.onError)\n })\n}\n\npage.prepareUploadConfig = () => {\n const fallback = {\n chunkSize: page.chunkSize,\n parallelUploads: page.parallelUploads\n }\n\n const temporaryUploadAges = Array.isArray(page.temporaryUploadAges) && page.temporaryUploadAges.length\n const fileIdentifierLength = page.fileIdentifierLength &&\n typeof page.fileIdentifierLength.min === 'number' &&\n typeof page.fileIdentifierLength.max === 'number'\n\n const config = {\n siBytes: {\n label: 'File size display',\n select: [\n { value: 'default', text: '1000 B = 1 kB = 1 Kilobyte' },\n { value: '0', text: '1024 B = 1 KiB = 1 Kibibyte' }\n ],\n help: 'This will be used in our homepage, dashboard, and album public pages.',\n valueHandler () {} // Do nothing\n },\n fileLength: {\n display: fileIdentifierLength,\n label: 'File identifier length',\n number: fileIdentifierLength ? {\n min: page.fileIdentifierLength.min,\n max: page.fileIdentifierLength.max,\n round: true\n } : undefined,\n help: true, // true means auto-generated, for number-based configs only\n disabled: fileIdentifierLength && page.fileIdentifierLength.force\n },\n uploadAge: {\n display: temporaryUploadAges,\n label: 'Upload age',\n select: [],\n help: 'This allows your files to automatically be deleted after a certain period of time.'\n },\n chunkSize: {\n display: !isNaN(page.chunkSize),\n label: 'Upload chunk size (MB)',\n number: {\n min: 1,\n max: 95,\n suffix: ' MB',\n round: true\n },\n help: true\n },\n parallelUploads: {\n label: 'Parallel uploads',\n number: {\n min: 1,\n max: 10,\n round: true\n },\n help: true\n },\n uploadsHistoryOrder: {\n label: 'Uploads history order',\n select: [\n { value: 'default', text: 'Older files on top' },\n { value: '0', text: 'Newer files on top' }\n ],\n help: `Newer files on top will use <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction#Accessibility_Concerns\" target=\"_blank\" rel=\"noopener\">a CSS technique</a>.<br>\n Trying to select their texts manually from top to bottom will end up selecting the texts from bottom to top instead.`,\n valueHandler (value) {\n if (value === '0') {\n const uploadFields = document.querySelectorAll('.tab-content > .uploads')\n for (let i = 0; i < uploadFields.length; i++)\n uploadFields[i].classList.add('is-reversed')\n }\n }\n },\n previewImages: {\n label: 'Load images for preview',\n select: [\n { value: 'default', text: 'Yes' },\n { value: '0', text: 'No' }\n ],\n help: 'By default, uploaded images will be loaded as their previews.',\n valueHandler (value) {\n page.previewImages = value !== '0'\n }\n }\n }\n\n if (temporaryUploadAges) {\n const stored = parseFloat(localStorage[lsKeys.uploadAge])\n for (let i = 0; i < page.temporaryUploadAges.length; i++) {\n const age = page.temporaryUploadAges[i]\n config.uploadAge.select.push({\n value: i === 0 ? 'default' : String(age),\n text: page.getPrettyUploadAge(age)\n })\n if (age === stored)\n config.uploadAge.value = stored\n }\n }\n\n if (fileIdentifierLength) {\n fallback.fileLength = page.fileIdentifierLength.default || undefined\n const stored = parseInt(localStorage[lsKeys.fileLength])\n if (!page.fileIdentifierLength.force &&\n !isNaN(stored) &&\n stored >= page.fileIdentifierLength.min &&\n stored <= page.fileIdentifierLength.max)\n config.fileLength.value = stored\n }\n\n const tabContent = document.querySelector('#tab-config')\n const form = document.createElement('form')\n form.addEventListener('submit', event => event.preventDefault())\n\n const configKeys = Object.keys(config)\n for (let i = 0; i < configKeys.length; i++) {\n const key = configKeys[i]\n const conf = config[key]\n\n // Skip only if display attribute is explicitly set to false\n if (conf.display === false)\n continue\n\n const field = document.createElement('div')\n field.className = 'field'\n\n let value\n if (!conf.disabled) {\n if (conf.value !== undefined) {\n value = conf.value\n } else if (conf.number !== undefined) {\n const parsed = parseInt(localStorage[lsKeys[key]])\n if (!isNaN(parsed))\n value = parsed\n } else {\n value = localStorage[lsKeys[key]]\n }\n\n // If valueHandler function exists, defer to the function,\n // otherwise pass value to global page object\n if (typeof conf.valueHandler === 'function')\n conf.valueHandler(value)\n else if (value !== undefined)\n page[key] = value\n }\n\n let control\n if (Array.isArray(conf.select)) {\n control = document.createElement('div')\n control.className = 'select is-fullwidth'\n\n const opts = []\n for (let j = 0; j < conf.select.length; j++) {\n const opt = conf.select[j]\n const selected = value && (opt.value === String(value))\n opts.push(`\n <option value=\"${opt.value}\"${selected ? ' selected' : ''}>\n ${opt.text}${opt.value === 'default' ? ' (default)' : ''}\n </option>\n `)\n }\n\n control.innerHTML = `\n <select id=\"${key}\">\n ${opts.join('\\n')}\n </select>\n `\n } else if (conf.number !== undefined) {\n control = document.createElement('input')\n control.id = control.name = key\n control.className = 'input is-fullwidth'\n control.type = 'number'\n\n if (conf.number.min !== undefined)\n control.min = conf.number.min\n if (conf.number.max !== undefined)\n control.max = conf.number.max\n if (typeof value === 'number')\n control.value = value\n else if (fallback[key] !== undefined)\n control.value = fallback[key]\n }\n\n let help\n if (conf.disabled) {\n control.disabled = conf.disabled\n help = 'This option is currently disabled.'\n } else if (typeof conf.help === 'string') {\n help = conf.help\n } else if (conf.help === true && conf.number !== undefined) {\n const tmp = []\n\n if (fallback[key] !== undefined)\n tmp.push(`Default is ${fallback[key]}${conf.number.suffix || ''}.`)\n if (conf.number.min !== undefined)\n tmp.push(`Min is ${conf.number.min}${conf.number.suffix || ''}.`)\n if (conf.number.max !== undefined)\n tmp.push(`Max is ${conf.number.max}${conf.number.suffix || ''}.`)\n\n help = tmp.join(' ')\n }\n\n field.innerHTML = `\n <label class=\"label\">${conf.label}</label>\n <div class=\"control\"></div>\n ${help ? `<p class=\"help\">${help}</p>` : ''}\n `\n field.querySelector('div.control').appendChild(control)\n\n form.appendChild(field)\n }\n\n const submit = document.createElement('div')\n submit.className = 'field'\n submit.innerHTML = `\n <p class=\"control\">\n <button id=\"saveConfig\" type=\"submit\" class=\"button is-danger is-outlined is-fullwidth\">\n <span class=\"icon\">\n <i class=\"icon-floppy\"></i>\n </span>\n <span>Save & reload</span>\n </button>\n </p>\n <p class=\"help\">\n This configuration will only be used in this browser.<br>\n After reloading the page, some of them will also be applied to the ShareX config that you can download by clicking on the ShareX icon below.\n </p>\n `\n\n form.appendChild(submit)\n form.querySelector('#saveConfig').addEventListener('click', () => {\n if (!form.checkValidity())\n return\n\n const keys = Object.keys(config)\n .filter(key => config[key].display !== false && config[key].disabled !== true)\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i]\n\n let value\n if (config[key].select !== undefined) {\n if (form.elements[key].value !== 'default')\n value = form.elements[key].value\n } else if (config[key].number !== undefined) {\n const parsed = parseInt(form.elements[key].value)\n if (!isNaN(parsed))\n value = Math.min(Math.max(parsed, config[key].number.min), config[key].number.max)\n }\n\n if (value !== undefined && value !== fallback[key])\n localStorage[lsKeys[key]] = value\n else\n localStorage.removeItem(lsKeys[key])\n }\n\n swal({\n title: 'Woohoo!',\n text: 'Configuration saved into this browser.',\n icon: 'success'\n }).then(() => {\n location.reload()\n })\n })\n\n tabContent.appendChild(form)\n}\n\npage.getPrettyUploadAge = hours => {\n if (hours === 0) {\n return 'Permanent'\n } else if (hours < 1) {\n const minutes = hours * 60\n return `${minutes} minute${minutes === 1 ? '' : 's'}`\n } else if (hours >= 24) {\n const days = hours / 24\n return `${days} day${days === 1 ? '' : 's'}`\n } else {\n return `${hours} hour${hours === 1 ? '' : 's'}`\n }\n}\n\n// Handle image paste event\nwindow.addEventListener('paste', event => {\n const items = (event.clipboardData || event.originalEvent.clipboardData).items\n const index = Object.keys(items)\n for (let i = 0; i < index.length; i++) {\n const item = items[index[i]]\n if (item.kind === 'file') {\n const blob = item.getAsFile()\n const file = new File([blob], `pasted-image.${blob.type.match(/(?:[^/]*\\/)([^;]*)/)[1]}`, {\n type: blob.type\n })\n page.dropzone.addFile(file)\n }\n }\n})\n\nwindow.onload = () => {\n page.checkIfPublic()\n\n page.clipboardJS = new ClipboardJS('.clipboard-js')\n\n page.clipboardJS.on('success', () => {\n return swal('Copied!', 'The link has been copied to clipboard.', 'success')\n })\n\n page.clipboardJS.on('error', page.onError)\n\n page.lazyLoad = new LazyLoad({\n elements_selector: '.field.uploads img'\n })\n\n document.querySelector('#createAlbum').addEventListener('click', () => {\n page.createAlbum()\n })\n}\n"]} |