mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2024-12-15 00:46:22 +00:00
a362d63e25
Fixed table row when file is not in an album. Sigh, I always miss something..
1 line
110 KiB
Plaintext
1 line
110 KiB
Plaintext
{"version":3,"sources":["dashboard.js"],"names":["const","lsKeys","token","viewType","uploads","uploadsAll","selected","users","page","dom","localStorage","username","permissions","menusContainer","menus","currentView","views","type","album","pageNum","filters","all","checkboxes","lastSelected","upload","user","selectAlbumContainer","cache","albums","clipboardJS","lazyLoad","imageExts","videoExts","isTriggerLoading","fadingIn","preparePage","verifyToken","window","location","reloadOnError","axios","post","then","response","data","success","swal","title","text","description","icon","removeItem","defaults","headers","common","prepareDashboard","catch","error","console","document","querySelector","addEventListener","domClick","event","target","classList","contains","preventDefault","itemMenus","selector","onclick","getUploads","deleteUploadsByNames","getAlbums","changeToken","changePassword","logout","inactive","params","group","getStatistics","getUsers","loop","i","item","call","Object","assign","trigger","currentTarget","remove","push","length","moderator","innerHTML","getAlbumsSidebar","prepareShareX","updateTrigger","newState","add","parentNode","tagName","let","getItemID","element","parent","parseInt","dataset","id","includes","action","hasAttribute","stopPropagation","setUploadsView","clearSelection","addSelectedUploadsToAlbum","select","selectAll","addToAlbum","deleteUpload","bulkDeleteUploads","displayThumbnail","submitAlbum","editAlbum","deleteAlbum","getNewToken","editUser","disableUser","filtersHelp","filterUploads","viewUserUploads","focusJumpToPage","switchPage","fadeAndScroll","content","clearTimeout","setTimeout","scrollIntoView","func","goto","jumpToPage","checkValidity","parsed","value","isNaN","focus","undefined","url","get","files","autoPage","Math","ceil","count","basedomain","pagination","paginate","filter","extraControls","controls","unselected","hasExpiryDateColumn","some","file","expirydate","thumb","name","original","prettyBytes","getPrettyBytes","size","prettyDate","getPrettyDate","Date","timestamp","prettyExpiryDate","appendix","userid","albumid","table","div","createElement","className","extname","appendChild","querySelectorAll","update","tr","ip","checked","view","exec","toLowerCase","isimage","isvideo","src","onload","body","onerror","video","autoplay","insertAdjacentElement","buttons","splice","indexOf","JSON","stringify","selectInBetween","lastElement","thisIndex","index","lastIndex","abs","shiftKey","suffix","substring","proceed","style","trim","replace","postBulkDeleteUploads","field","values","cb","failed","textArea","seen","names","split","map","trimmed","test","prototype","hasOwnProperty","join","objective","dangerMode","cancel","confirm","closeModal","fields","Array","isArray","addUploadsToAlbum","ids","callback","choose","added","list","getElementsByTagName","removeAttribute","homeDomain","albumUrl","download","public","requestLink","identifier","purge","albumsContainer","oldAlbums","li","a","sendNewPassword","pass","password","admin","displayGroup","groups","keys","enabled","usage","groupOptions","g","resetPassword","totalItems","itemsPerPage","currentPage","numPages","template","start","end","elementsToShow","step","stats","rows","types","_types","valKeys","j","number","toLocaleString","byte","byteUsage","used","total","round","toUpperCase","defineProperty","varArgs","arguments$1","arguments","TypeError","to","nextSource","nextKey","writable","configurable","documentElement","selectedKeys","ls","parse","ClipboardJS","on","LazyLoad"],"mappings":"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","file":"dashboard.js","sourcesContent":["/* global swal, axios, ClipboardJS, LazyLoad */\n\nconst lsKeys = {\n token: 'token',\n viewType: {\n uploads: 'viewTypeUploads',\n uploadsAll: 'viewTypeUploadsAll'\n },\n selected: {\n uploads: 'selectedUploads',\n uploadsAll: 'selectedUploadsAll',\n users: 'selectedUsers'\n }\n}\n\nconst page = {\n // #page\n dom: null,\n\n // user token\n token: localStorage[lsKeys.token],\n\n // from api/tokens/verify\n username: null,\n permissions: null,\n\n // sidebar menus\n menusContainer: null,\n menus: [],\n\n currentView: null,\n views: {\n // config of uploads view\n uploads: {\n type: localStorage[lsKeys.viewType.uploads],\n album: null, // album's id\n pageNum: null // page num\n },\n // config of uploads view (all)\n uploadsAll: {\n type: localStorage[lsKeys.viewType.uploadsAll],\n filters: null, // uploads' filters\n pageNum: null, // page num\n all: true\n },\n // config of users view\n users: {\n pageNum: null\n }\n },\n\n // id of selected items (shared across pages and will be synced with localStorage)\n selected: {\n uploads: [],\n uploadsAll: [],\n users: []\n },\n checkboxes: {\n uploads: [],\n uploadsAll: [],\n users: []\n },\n lastSelected: {\n upload: null,\n uploadsAll: null,\n user: null\n },\n\n // select album dom for dialogs/modals\n selectAlbumContainer: null,\n\n // cache for dialogs/modals\n cache: {\n uploads: {},\n albums: {},\n users: {}\n },\n\n clipboardJS: null,\n lazyLoad: null,\n\n imageExts: ['.webp', '.jpg', '.jpeg', '.gif', '.png', '.tiff', '.tif', '.svg'],\n // some of these extensions can not be played directly in browsers\n videoExts: ['.webm', '.mp4', '.wmv', '.avi', '.mov', '.mkv'],\n\n isTriggerLoading: null,\n fadingIn: null\n}\n\npage.preparePage = () => {\n if (!page.token) {\n window.location = 'auth'\n return\n }\n page.verifyToken(page.token, true)\n}\n\npage.verifyToken = (token, reloadOnError) => {\n 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(lsKeys.token)\n window.location = 'auth'\n })\n\n axios.defaults.headers.common.token = token\n localStorage[lsKeys.token] = token\n page.token = token\n page.username = response.data.username\n page.permissions = response.data.permissions\n page.prepareDashboard()\n }).catch(error => {\n console.error(error)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n}\n\npage.prepareDashboard = () => {\n page.dom = document.querySelector('#page')\n\n // Capture all click events\n page.dom.addEventListener('click', page.domClick, true)\n\n // Capture all submit events\n page.dom.addEventListener('submit', event => {\n // Prevent default if necessary\n if (event.target && event.target.classList.contains('prevent-default'))\n return event.preventDefault()\n }, true)\n\n page.menusContainer = document.querySelector('#menu')\n\n // All item menus in the sidebar\n const itemMenus = [\n { selector: '#itemUploads', onclick: page.getUploads },\n { selector: '#itemDeleteUploadsByNames', onclick: page.deleteUploadsByNames },\n { selector: '#itemManageAlbums', onclick: page.getAlbums },\n { selector: '#itemManageToken', onclick: page.changeToken },\n { selector: '#itemChangePassword', onclick: page.changePassword },\n { selector: '#itemLogout', onclick: page.logout, inactive: true },\n { selector: '#itemManageUploads', onclick: page.getUploads, params: { all: true }, group: 'moderator' },\n { selector: '#itemStatistics', onclick: page.getStatistics, group: 'admin' },\n { selector: '#itemManageUsers', onclick: page.getUsers, group: 'admin' }\n ]\n\n for (let i = 0; i < itemMenus.length; i++) {\n // Skip item menu if not enough permission\n if (itemMenus[i].group && !page.permissions[itemMenus[i].group])\n continue\n\n // Add onclick event listener\n const item = document.querySelector(itemMenus[i].selector)\n item.addEventListener('click', event => {\n // This class name isn't actually being applied fast enough\n if (page.menusContainer.classList.contains('is-loading'))\n return\n // eslint-disable-next-line compat/compat\n itemMenus[i].onclick.call(null, Object.assign({\n trigger: event.currentTarget\n }, itemMenus[i].params || {}))\n })\n\n item.classList.remove('is-hidden')\n page.menus.push(item)\n }\n\n // If at least a moderator, show administration section\n if (page.permissions.moderator) {\n document.querySelector('#itemLabelAdmin').classList.remove('is-hidden')\n document.querySelector('#itemListAdmin').classList.remove('is-hidden')\n }\n\n // Update text of logout button\n document.querySelector('#itemLogout').innerHTML = `Logout ( ${page.username} )`\n\n // Finally display dashboard\n document.querySelector('#dashboard').classList.remove('is-hidden')\n\n // Load albums sidebar\n page.getAlbumsSidebar()\n\n if (typeof page.prepareShareX === 'function')\n page.prepareShareX()\n}\n\npage.logout = () => {\n localStorage.removeItem(lsKeys.token)\n window.location = 'auth'\n}\n\npage.updateTrigger = (trigger, newState) => {\n if (!trigger) return\n\n // Disable menus container when loading\n if (newState === 'loading')\n page.menusContainer.classList.add('is-loading')\n else\n page.menusContainer.classList.remove('is-loading')\n\n if (newState === 'loading') {\n trigger.classList.add('is-loading')\n } else if (newState === 'active') {\n if (trigger.parentNode.tagName !== 'LI')\n return\n for (let i = 0; i < page.menus.length; i++)\n page.menus[i].classList.remove('is-active')\n trigger.classList.remove('is-loading')\n trigger.classList.add('is-active')\n } else {\n trigger.classList.remove('is-loading')\n trigger.classList.remove('is-active')\n }\n}\n\npage.getItemID = element => {\n // This expects the item's parent to have the item's ID\n let parent = element.parentNode\n // If the element is part of a set of controls, use the container's parent instead\n if (element.parentNode.classList.contains('controls')) parent = parent.parentNode\n return parseInt(parent.dataset.id)\n}\n\npage.domClick = event => {\n // We are processing clicks this way to avoid using \"onclick\" attribute\n // Apparently we will need to use \"unsafe-inline\" for \"script-src\" directive\n // of Content Security Policy (CSP), if we want to use \"onclick\" attribute\n // Though I think that only applies to some browsers (?)\n // Of course it wouldn't have mattered if we didn't use CSP to begin with\n // Anyway, I personally would rather not use \"onclick\" attribute\n let element = event.target\n if (!element) return\n\n // Delegate click events to their A or BUTTON parents\n if (['I'].includes(element.tagName) && ['SPAN'].includes(element.parentNode.tagName))\n element = element.parentNode\n if (['SPAN'].includes(element.tagName) && ['A', 'BUTTON'].includes(element.parentNode.tagName))\n element = element.parentNode\n\n // Skip elements that have no action data\n if (!element.dataset || !element.dataset.action) return\n\n // Skip disabled elements\n if (element.hasAttribute('disabled')) return\n\n event.stopPropagation() // maybe necessary\n const id = page.getItemID(element)\n const action = element.dataset.action\n\n switch (action) {\n case 'view-list':\n return page.setUploadsView('list', element)\n case 'view-thumbs':\n return page.setUploadsView('thumbs', element)\n case 'clear-selection':\n return page.clearSelection()\n case 'add-selected-uploads-to-album':\n return page.addSelectedUploadsToAlbum()\n case 'select':\n return page.select(element, event)\n case 'select-all':\n return page.selectAll(element)\n case 'add-to-album':\n return page.addToAlbum(id)\n case 'delete-upload':\n return page.deleteUpload(id)\n case 'bulk-delete-uploads':\n return page.bulkDeleteUploads()\n case 'display-thumbnail':\n return page.displayThumbnail(id)\n case 'submit-album':\n return page.submitAlbum(element)\n case 'edit-album':\n return page.editAlbum(id)\n case 'delete-album':\n return page.deleteAlbum(id)\n case 'get-new-token':\n return page.getNewToken(element)\n case 'edit-user':\n return page.editUser(id)\n case 'disable-user':\n return page.disableUser(id)\n case 'filters-help':\n return page.filtersHelp(element)\n case 'filter-uploads':\n return page.filterUploads(element)\n case 'view-user-uploads':\n return page.viewUserUploads(id, element)\n case 'page-ellipsis':\n return page.focusJumpToPage()\n case 'page-prev':\n case 'page-next':\n case 'page-goto':\n case 'jump-to-page':\n return page.switchPage(action, element)\n }\n}\n\npage.fadeAndScroll = content => {\n if (page.fadingIn) {\n clearTimeout(page.fadingIn)\n page.dom.classList.remove('fade-in')\n }\n page.dom.classList.add('fade-in')\n page.fadingIn = setTimeout(() => {\n page.dom.classList.remove('fade-in')\n }, 500)\n page.dom.scrollIntoView(true)\n}\n\npage.switchPage = (action, element) => {\n // eslint-disable-next-line compat/compat\n const params = Object.assign({\n trigger: element\n }, page.views[page.currentView])\n const func = page.currentView === 'users' ? page.getUsers : page.getUploads\n switch (action) {\n case 'page-prev':\n params.pageNum = page.views[page.currentView].pageNum - 1\n if (params.pageNum < 0)\n return swal('An error occurred!', 'This is already the first page.', 'error')\n return func(params)\n case 'page-next':\n params.pageNum = page.views[page.currentView].pageNum + 1\n return func(params)\n case 'page-goto':\n params.pageNum = parseInt(element.dataset.goto)\n return func(params)\n case 'jump-to-page': {\n const jumpToPage = document.querySelector('#jumpToPage')\n if (!jumpToPage.checkValidity()) return\n const parsed = parseInt(jumpToPage.value)\n params.pageNum = isNaN(parsed) ? 0 : (parsed - 1)\n if (params.pageNum < 0) params.pageNum = 0\n return func(params)\n }\n }\n}\n\npage.focusJumpToPage = () => {\n const element = document.querySelector('#jumpToPage')\n if (!element) return\n element.focus()\n element.select()\n}\n\npage.getUploads = (params = {}) => {\n if (params === undefined)\n params = {}\n\n if ((params.all || params.filters) && !page.permissions.moderator)\n return swal('An error occurred!', 'You can not do this!', 'error')\n\n page.updateTrigger(params.trigger, 'loading')\n\n if (typeof params.pageNum !== 'number' || params.pageNum < 0)\n params.pageNum = 0\n\n const url = params.album !== undefined\n ? `api/album/${params.album}/${params.pageNum}`\n : `api/uploads/${params.pageNum}`\n\n const headers = {\n all: params.all ? '1' : '',\n filters: params.filters || ''\n }\n\n axios.get(url, { headers }).then(response => {\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else {\n page.updateTrigger(params.trigger)\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n const files = response.data.files\n if (params.pageNum && (files.length === 0))\n if (params.autoPage) {\n params.pageNum = Math.ceil(response.data.count / 25) - 1\n return page.getUploads(params)\n } else {\n page.updateTrigger(params.trigger)\n return swal('An error occurred!', `There are no more uploads to populate page ${params.pageNum + 1}.`, 'error')\n }\n\n page.currentView = params.all ? 'uploadsAll' : 'uploads'\n page.cache.uploads = {}\n\n const albums = response.data.albums\n const users = response.data.users\n const basedomain = response.data.basedomain\n const pagination = page.paginate(response.data.count, 25, params.pageNum)\n\n let filter = '<div class=\"column is-hidden-mobile\"></div>'\n if (params.all)\n filter = `\n <div class=\"column\">\n <form class=\"prevent-default\">\n <div class=\"field has-addons\">\n <div class=\"control is-expanded\">\n <input id=\"filters\" class=\"input is-small\" type=\"text\" placeholder=\"Filters\" value=\"${params.filters || ''}\">\n </div>\n <div class=\"control\">\n <button type=\"button\" class=\"button is-small is-info\" title=\"Help?\" data-action=\"filters-help\">\n <span class=\"icon\">\n <i class=\"icon-help-circled\"></i>\n </span>\n </button>\n </div>\n <div class=\"control\">\n <button type=\"submit\" class=\"button is-small is-info\" title=\"Filter uploads\" data-action=\"filter-uploads\">\n <span class=\"icon\">\n <i class=\"icon-filter\"></i>\n </span>\n </button>\n </div>\n </div>\n </form>\n </div>\n `\n const extraControls = `\n <div class=\"columns\">\n ${filter}\n <div class=\"column is-one-quarter\">\n <form class=\"prevent-default\">\n <div class=\"field has-addons\">\n <div class=\"control is-expanded\">\n <input id=\"jumpToPage\" class=\"input is-small\" type=\"number\" value=\"${params.pageNum + 1}\">\n </div>\n <div class=\"control\">\n <button type=\"submit\" class=\"button is-small is-info\" title=\"Jump to page\" data-action=\"jump-to-page\">\n <span class=\"icon\">\n <i class=\"icon-paper-plane\"></i>\n </span>\n </button>\n </div>\n </div>\n </form>\n </div>\n </div>\n `\n\n const controls = `\n <div class=\"columns\">\n <div class=\"column is-hidden-mobile\"></div>\n <div class=\"column has-text-centered\">\n <a class=\"button is-small is-danger\" title=\"List view\" data-action=\"view-list\">\n <span class=\"icon\">\n <i class=\"icon-th-list\"></i>\n </span>\n </a>\n <a class=\"button is-small is-danger\" title=\"Thumbs view\" data-action=\"view-thumbs\">\n <span class=\"icon\">\n <i class=\"icon-th-large\"></i>\n </span>\n </a>\n </div>\n <div class=\"column has-text-right\">\n <a class=\"button is-small is-info\" title=\"Clear selection\" data-action=\"clear-selection\">\n <span class=\"icon\">\n <i class=\"icon-cancel\"></i>\n </span>\n </a>\n ${params.all ? '' : `\n <a class=\"button is-small is-warning\" title=\"Bulk add to album\" data-action=\"add-selected-uploads-to-album\">\n <span class=\"icon\">\n <i class=\"icon-plus\"></i>\n </span>\n </a>`}\n <a class=\"button is-small is-danger\" title=\"Bulk delete\" data-action=\"bulk-delete-uploads\">\n <span class=\"icon\">\n <i class=\"icon-trash\"></i>\n </span>\n <span>Bulk delete</span>\n </a>\n </div>\n </div>\n `\n\n // Whether there are any unselected items\n let unselected = false\n\n const hasExpiryDateColumn = files.some(file => {\n return file.expirydate !== undefined\n })\n\n for (let i = 0; i < files.length; i++) {\n // Build full URLs\n files[i].file = `${basedomain}/${files[i].name}`\n if (files[i].thumb)\n files[i].thumb = `${basedomain}/${files[i].thumb}`\n\n // Cache bare minimum data for thumbnails viewer\n page.cache.uploads[files[i].id] = {\n name: files[i].name,\n thumb: files[i].thumb,\n original: files[i].file\n }\n\n // Prettify\n files[i].prettyBytes = page.getPrettyBytes(parseInt(files[i].size))\n files[i].prettyDate = page.getPrettyDate(new Date(files[i].timestamp * 1000))\n\n if (hasExpiryDateColumn)\n files[i].prettyExpiryDate = files[i].expirydate\n ? page.getPrettyDate(new Date(files[i].expirydate * 1000))\n : '-'\n\n // Update selected status\n files[i].selected = page.selected[page.currentView].includes(files[i].id)\n if (!files[i].selected) unselected = true\n\n // Appendix (display album or user)\n if (params.all)\n files[i].appendix = files[i].userid\n ? users[files[i].userid] || ''\n : ''\n else if (params.album === undefined)\n files[i].appendix = files[i].albumid\n ? albums[files[i].albumid] || ''\n : ''\n }\n\n if (page.views[page.currentView].type === 'thumbs') {\n page.dom.innerHTML = `\n ${pagination}\n ${extraControls}\n ${controls}\n <div id=\"table\" class=\"columns is-multiline is-mobile is-centered\">\n </div>\n <hr>\n ${pagination}\n `\n\n const table = document.querySelector('#table')\n\n for (let i = 0; i < files.length; i++) {\n const upload = files[i]\n const div = document.createElement('div')\n div.className = 'image-container column is-narrow is-relative'\n div.dataset.id = upload.id\n\n if (upload.thumb !== undefined)\n div.innerHTML = `<a class=\"image\" href=\"${upload.file}\" target=\"_blank\" rel=\"noopener\"><img alt=\"${upload.name}\" data-src=\"${upload.thumb}\"/></a>`\n else\n div.innerHTML = `<a class=\"image\" href=\"${upload.file}\" target=\"_blank\" rel=\"noopener\"><h1 class=\"title\">${upload.extname || 'N/A'}</h1></a>`\n\n div.innerHTML += `\n <input type=\"checkbox\" class=\"checkbox\" title=\"Select\" data-index=\"${i}\" data-action=\"select\"${upload.selected ? ' checked' : ''}>\n <div class=\"controls\">\n ${upload.thumb ? `\n <a class=\"button is-small is-primary\" title=\"View thumbnail\" data-action=\"display-thumbnail\">\n <span class=\"icon\">\n <i class=\"icon-picture\"></i>\n </span>\n </a>` : ''}\n <a class=\"button is-small is-info clipboard-js\" title=\"Copy link to clipboard\" data-clipboard-text=\"${upload.file}\">\n <span class=\"icon\">\n <i class=\"icon-clipboard\"></i>\n </span>\n </a>\n <a class=\"button is-small is-warning\" title=\"Add to album\" data-action=\"add-to-album\">\n <span class=\"icon\">\n <i class=\"icon-plus\"></i>\n </span>\n </a>\n <a class=\"button is-small is-danger\" title=\"Delete\" data-action=\"delete-upload\">\n <span class=\"icon\">\n <i class=\"icon-trash\"></i>\n </span>\n </a>\n </div>\n <div class=\"details\">\n <p><span class=\"name\" title=\"${upload.file}\">${upload.name}</span></p>\n <p>${upload.appendix ? `<span>${upload.appendix}</span> – ` : ''}${upload.prettyBytes}</p>\n </div>\n `\n\n table.appendChild(div)\n page.checkboxes[page.currentView] = table.querySelectorAll('.checkbox[data-action=\"select\"]')\n page.lazyLoad.update()\n }\n } else {\n page.dom.innerHTML = `\n ${pagination}\n ${extraControls}\n ${controls}\n <div class=\"table-container\">\n <table class=\"table is-narrow is-fullwidth is-hoverable\">\n <thead>\n <tr>\n <th><input id=\"selectAll\" class=\"checkbox\" type=\"checkbox\" title=\"Select all\" data-action=\"select-all\"></th>\n <th>File</th>\n ${params.album === undefined ? `<th>${params.all ? 'User' : 'Album'}</th>` : ''}\n <th>Size</th>\n ${params.all ? '<th>IP</th>' : ''}\n <th>Date</th>\n ${hasExpiryDateColumn ? '<th>Expiry date</th>' : ''}\n <th></th>\n </tr>\n </thead>\n <tbody id=\"table\">\n </tbody>\n </table>\n </div>\n <hr>\n ${pagination}\n `\n\n const table = document.querySelector('#table')\n\n for (let i = 0; i < files.length; i++) {\n const upload = files[i]\n const tr = document.createElement('tr')\n tr.dataset.id = upload.id\n tr.innerHTML = `\n <td class=\"controls\"><input type=\"checkbox\" class=\"checkbox\" title=\"Select\" data-index=\"${i}\" data-action=\"select\"${upload.selected ? ' checked' : ''}></td>\n <th><a href=\"${upload.file}\" target=\"_blank\" rel=\"noopener\" title=\"${upload.file}\">${upload.name}</a></th>\n ${params.album === undefined ? `<th>${upload.appendix}</th>` : ''}\n <td>${upload.prettyBytes}</td>\n ${params.all ? `<td>${upload.ip || ''}</td>` : ''}\n <td>${upload.prettyDate}</td>\n ${hasExpiryDateColumn ? `<td>${upload.prettyExpiryDate}</td>` : ''}\n <td class=\"controls has-text-right\">\n <a class=\"button is-small is-primary\" title=\"${upload.thumb ? 'View thumbnail' : 'File doesn\\'t have thumbnail'}\" data-action=\"display-thumbnail\"${upload.thumb ? '' : ' disabled'}>\n <span class=\"icon\">\n <i class=\"icon-picture\"></i>\n </span>\n </a>\n <a class=\"button is-small is-info clipboard-js\" title=\"Copy link to clipboard\" data-clipboard-text=\"${upload.file}\">\n <span class=\"icon\">\n <i class=\"icon-clipboard\"></i>\n </span>\n </a>\n ${params.all ? '' : `\n <a class=\"button is-small is-warning\" title=\"Add to album\" data-action=\"add-to-album\">\n <span class=\"icon\">\n <i class=\"icon-plus\"></i>\n </span>\n </a>`}\n <a class=\"button is-small is-danger\" title=\"Delete\" data-action=\"delete-upload\">\n <span class=\"icon\">\n <i class=\"icon-trash\"></i>\n </span>\n </a>\n </td>\n `\n\n table.appendChild(tr)\n page.checkboxes[page.currentView] = table.querySelectorAll('.checkbox[data-action=\"select\"]')\n }\n }\n\n const selectAll = document.querySelector('#selectAll')\n if (selectAll && !unselected) {\n selectAll.checked = true\n selectAll.title = 'Unselect all'\n }\n\n page.fadeAndScroll()\n page.updateTrigger(params.trigger, 'active')\n\n if (page.currentView === 'uploads')\n page.views.uploads.album = params.album\n if (page.currentView === 'uploadsAll')\n page.views.uploadsAll.filters = params.filters\n page.views[page.currentView].pageNum = files.length ? params.pageNum : 0\n }).catch(error => {\n console.error(error)\n page.updateTrigger(params.trigger)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n}\n\npage.setUploadsView = (view, element) => {\n localStorage[lsKeys.viewType[page.currentView]] = view\n page.views[page.currentView].type = view\n // eslint-disable-next-line compat/compat\n page.getUploads(Object.assign({\n trigger: element\n }, page.views[page.currentView]))\n}\n\npage.displayThumbnail = id => {\n const file = page.cache.uploads[id]\n if (!file.thumb) return\n\n const div = document.createElement('div')\n div.innerHTML = `\n <div class=\"field has-text-centered\">\n <label class=\"label\">${file.name}</label>\n <div class=\"controls swal-display-thumb-container\">\n <img id=\"swalThumb\" src=\"${file.thumb}\">\n </div>\n </div>\n `\n\n if (file.original) {\n const exec = /.[\\w]+(\\?|$)/.exec(file.original)\n const extname = exec && exec[0] ? exec[0].toLowerCase() : null\n const isimage = page.imageExts.includes(extname)\n const isvideo = !isimage && page.videoExts.includes(extname)\n\n if (isimage || isvideo) {\n div.innerHTML += `\n <div class=\"field has-text-centered\">\n <div class=\"controls\">\n <a id=\"swalOriginal\" type=\"button\" class=\"button is-info is-fullwidth\" data-original=\"${file.original}\">\n <span class=\"icon\">\n <i class=\"icon-arrows-cw\"></i>\n </span>\n <span>Load original</span>\n </a>\n </div>\n </div>\n `\n\n div.querySelector('#swalOriginal').addEventListener('click', event => {\n const trigger = event.currentTarget\n if (trigger.classList.contains('is-danger'))\n return\n\n trigger.classList.add('is-loading')\n const thumb = div.querySelector('#swalThumb')\n\n if (isimage) {\n thumb.src = file.original\n thumb.onload = () => {\n trigger.classList.add('is-hidden')\n document.body.querySelector('.swal-overlay .swal-modal:not(.is-expanded)').classList.add('is-expanded')\n }\n thumb.onerror = event => {\n event.currentTarget.classList.add('is-hidden')\n trigger.className = 'button is-danger is-fullwidth'\n trigger.innerHTML = `\n <span class=\"icon\">\n <i class=\"icon-block\"></i>\n </span>\n <span>Unable to load original</span>\n `\n }\n } else if (isvideo) {\n thumb.classList.add('is-hidden')\n const video = document.createElement('video')\n video.id = 'swalVideo'\n video.controls = true\n video.autoplay = true\n video.src = file.original\n thumb.insertAdjacentElement('afterend', video)\n\n trigger.classList.add('is-hidden')\n document.body.querySelector('.swal-overlay .swal-modal:not(.is-expanded)').classList.add('is-expanded')\n }\n })\n }\n }\n\n return swal({\n content: div,\n buttons: false\n }).then(() => {\n // Destroy video, if necessary\n const video = div.querySelector('#swalVideo')\n if (video) video.remove()\n\n // Restore modal size\n document.body.querySelector('.swal-overlay .swal-modal').classList.remove('is-expanded')\n })\n}\n\npage.selectAll = element => {\n for (let i = 0; i < page.checkboxes[page.currentView].length; i++) {\n const id = page.getItemID(page.checkboxes[page.currentView][i])\n if (isNaN(id)) continue\n if (page.checkboxes[page.currentView][i].checked !== element.checked) {\n page.checkboxes[page.currentView][i].checked = element.checked\n if (page.checkboxes[page.currentView][i].checked)\n page.selected[page.currentView].push(id)\n else\n page.selected[page.currentView].splice(page.selected[page.currentView].indexOf(id), 1)\n }\n }\n\n if (page.selected[page.currentView].length)\n localStorage[lsKeys.selected[page.currentView]] = JSON.stringify(page.selected[page.currentView])\n else\n delete localStorage[lsKeys.selected[page.currentView]]\n\n element.title = element.checked ? 'Unselect all' : 'Select all'\n}\n\npage.selectInBetween = (element, lastElement) => {\n const thisIndex = parseInt(element.dataset.index)\n const lastIndex = parseInt(lastElement.dataset.index)\n\n const distance = Math.abs(thisIndex - lastIndex)\n if (distance < 2)\n return\n\n for (let i = 0; i < page.checkboxes[page.currentView].length; i++)\n if ((thisIndex > lastIndex && i > lastIndex && i < thisIndex) ||\n (thisIndex < lastIndex && i > thisIndex && i < lastIndex)) {\n // Check or uncheck depending on the state of the initial checkbox\n const checked = page.checkboxes[page.currentView][i].checked = lastElement.checked\n const id = page.getItemID(page.checkboxes[page.currentView][i])\n if (!page.selected[page.currentView].includes(id) && checked)\n page.selected[page.currentView].push(id)\n else if (page.selected[page.currentView].includes(id) && !checked)\n page.selected[page.currentView].splice(page.selected[page.currentView].indexOf(id), 1)\n }\n}\n\npage.select = (element, event) => {\n const id = page.getItemID(element)\n if (isNaN(id)) return\n\n const lastSelected = page.lastSelected[page.currentView]\n if (event.shiftKey && lastSelected) {\n page.selectInBetween(element, lastSelected)\n // Check or uncheck depending on the state of the initial checkbox\n element.checked = lastSelected.checked\n } else {\n page.lastSelected[page.currentView] = element\n }\n\n if (!page.selected[page.currentView].includes(id) && element.checked)\n page.selected[page.currentView].push(id)\n else if (page.selected[page.currentView].includes(id) && !element.checked)\n page.selected[page.currentView].splice(page.selected[page.currentView].indexOf(id), 1)\n\n // Update local storage\n if (page.selected[page.currentView].length)\n localStorage[lsKeys.selected[page.currentView]] = JSON.stringify(page.selected[page.currentView])\n else\n delete localStorage[lsKeys.selected[page.currentView]]\n}\n\npage.clearSelection = () => {\n const selected = page.selected[page.currentView]\n const type = page.currentView === 'users' ? 'users' : 'uploads'\n const count = selected.length\n if (!count)\n return swal('An error occurred!', `You have not selected any ${type}.`, 'error')\n\n const suffix = count === 1 ? type.substring(0, type.length - 1) : type\n return swal({\n title: 'Are you sure?',\n text: `You are going to unselect ${count} ${suffix}.`,\n buttons: true\n }).then(proceed => {\n if (!proceed) return\n\n const checkboxes = page.checkboxes[page.currentView]\n for (let i = 0; i < checkboxes.length; i++)\n if (checkboxes[i].checked)\n checkboxes[i].checked = false\n\n page.selected[page.currentView] = []\n delete localStorage[lsKeys.selected[page.currentView]]\n\n const selectAll = document.querySelector('#selectAll')\n if (selectAll) selectAll.checked = false\n\n return swal('Cleared selection!', `Unselected ${count} ${suffix}.`, 'success')\n })\n}\n\npage.filtersHelp = element => {\n const content = document.createElement('div')\n content.style = 'text-align: left'\n content.innerHTML = `\n This supports 3 filter keys, namely <b>user</b> (username), <b>ip</b> and <b>name</b> (upload name).\n Each key can be specified more than once.\n Backlashes should be used if the usernames have spaces.\n There are also 2 additional flags, namely <b>-user</b> and <b>-ip</b>, which will match uploads by non-registered users and have no IPs respectively.\n\n How does it work?\n First, it will filter uploads matching ANY of the supplied <b>user</b> or <b>ip</b> keys.\n Then, it will refine the matches using the supplied <b>name</b> keys.\n\n Examples:\n\n Uploads from user with username \"demo\":\n <code>user:demo</code>\n\n Uploads from users with username either \"John Doe\" OR \"demo\":\n <code>user:John\\\\ Doe user:demo</code>\n\n Uploads from IP \"127.0.0.1\" AND which upload names match \"*.rar\" OR \"*.zip\":\n <code>ip:127.0.0.1 name:*.rar name:*.zip</code>\n\n Uploads from user with username \"test\" OR from non-registered users:\n <code>user:test -user</code>\n `.trim().replace(/^ {6}/gm, '').replace(/\\n/g, '<br>')\n swal({ content })\n}\n\npage.filterUploads = element => {\n const filters = document.querySelector('#filters').value\n page.getUploads({ all: true, filters }, element)\n}\n\npage.viewUserUploads = (id, element) => {\n const user = page.cache.users[id]\n if (!user) return\n element.classList.add('is-loading')\n page.getUploads({\n all: true,\n filters: `user:${user.username.replace(/ /g, '\\\\ ')}`,\n trigger: document.querySelector('#itemManageUploads')\n })\n}\n\npage.deleteUpload = id => {\n page.postBulkDeleteUploads({\n all: page.currentView === 'uploadsAll',\n field: 'id',\n values: [id],\n cb (failed) {\n // Remove from remembered checkboxes if necessary\n if (!failed.length && page.selected[page.currentView].includes(id))\n page.selected[page.currentView].splice(page.selected[page.currentView].indexOf(id), 1)\n\n // Update local storage\n if (page.selected[page.currentView].length)\n localStorage[lsKeys.selected[page.currentView]] = JSON.stringify(page.selected[page.currentView])\n else\n delete localStorage[lsKeys.selected[page.currentView]]\n\n // Reload upload list\n // eslint-disable-next-line compat/compat\n page.getUploads(Object.assign({\n autoPage: true\n }, page.views[page.currentView]))\n }\n })\n}\n\npage.bulkDeleteUploads = () => {\n const count = page.selected[page.currentView].length\n if (!count)\n return swal('An error occurred!', 'You have not selected any uploads.', 'error')\n\n page.postBulkDeleteUploads({\n all: page.currentView === 'uploadsAll',\n field: 'id',\n values: page.selected[page.currentView],\n cb (failed) {\n // Update state of checkboxes\n if (failed.length)\n page.selected[page.currentView] = page.selected[page.currentView]\n .filter(id => {\n return failed.includes(id)\n })\n else\n page.selected[page.currentView] = []\n\n // Update local storage\n if (page.selected[page.currentView].length)\n localStorage[lsKeys.selected[page.currentView]] = JSON.stringify(page.selected[page.currentView])\n else\n delete localStorage[lsKeys.selected[page.currentView]]\n\n // Reload uploads list\n // eslint-disable-next-line compat/compat\n page.getUploads(Object.assign({\n autoPage: true\n }, page.views[page.currentView]))\n }\n })\n}\n\npage.deleteUploadsByNames = (params = {}) => {\n let appendix = ''\n if (page.permissions.moderator)\n appendix = '<br><b>Hint:</b> You can use this feature to delete uploads by other users.'\n\n page.dom.innerHTML = `\n <form class=\"prevent-default\">\n <div class=\"field\">\n <label class=\"label\">Upload names:</label>\n <div class=\"control\">\n <textarea id=\"bulkDeleteNames\" class=\"textarea\"></textarea>\n </div>\n <p class=\"help\">Separate each entry with a new line.${appendix}</p>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <button type=\"submit\" id=\"submitBulkDelete\" class=\"button is-danger is-fullwidth\">\n <span class=\"icon\">\n <i class=\"icon-trash\"></i>\n </span>\n <span>Bulk delete</span>\n </button>\n </div>\n </div>\n </form>\n `\n page.fadeAndScroll()\n page.updateTrigger(params.trigger, 'active')\n\n document.querySelector('#submitBulkDelete').addEventListener('click', () => {\n const textArea = document.querySelector('#bulkDeleteNames')\n\n // Clean up\n const seen = {}\n const names = textArea.value\n .split(/\\r?\\n/)\n .map(name => {\n const trimmed = name.trim()\n return /^[^\\s]+$/.test(trimmed)\n ? trimmed\n : ''\n })\n .filter(name => {\n // Filter out invalid and duplicate names\n return (!name || Object.prototype.hasOwnProperty.call(seen, name))\n ? false\n : (seen[name] = true)\n })\n\n // Update textarea with cleaned names\n textArea.value = names.join('\\n')\n\n if (!names.length)\n return swal('An error occurred!', 'You have not entered any upload names.', 'error')\n\n page.postBulkDeleteUploads({\n all: true,\n field: 'name',\n values: names,\n cb (failed) {\n textArea.value = failed.join('\\n')\n }\n })\n })\n}\n\npage.postBulkDeleteUploads = (params = {}) => {\n const count = params.values.length\n\n const objective = `${params.values.length} upload${count === 1 ? '' : 's'}`\n const boldObjective = objective.replace(/^(\\d*)(.*)/, '<b>$1</b>$2')\n let text = `<p>You won't be able to recover ${boldObjective}!</p>`\n\n if (params.all) {\n const obj1 = count === 1 ? 'an upload' : 'some uploads'\n const obj2 = count === 1 ? 'another user' : 'other users'\n text += `\\n<p><b>Warning:</b> You may be nuking ${obj1} by ${obj2}!</p>`\n }\n\n const content = document.createElement('div')\n content.innerHTML = text\n\n swal({\n title: 'Are you sure?',\n content,\n icon: 'warning',\n dangerMode: true,\n buttons: {\n cancel: true,\n confirm: {\n text: `Yes, nuke ${params.values.length === 1 ? 'it' : 'them'}!`,\n closeModal: false\n }\n }\n }).then(proceed => {\n if (!proceed) return\n\n axios.post('api/upload/bulkdelete', {\n field: params.fields,\n values: params.values\n }).then(response => {\n if (!response) return\n\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else {\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n const failed = Array.isArray(response.data.failed) ? response.data.failed : []\n if (failed.length === params.values.length)\n swal('An error occurred!', `Unable to delete any of the ${objective}.`, 'error')\n else if (failed.length && failed.length < params.values.length)\n swal('Warning!', `From ${objective}, unable to delete ${failed.length} of them.`, 'warning')\n else\n swal('Deleted!', `${objective} ${count === 1 ? 'has' : 'have'} been deleted.`, 'success')\n\n if (typeof params.cb === 'function')\n params.cb(failed)\n }).catch(error => {\n console.error(error)\n swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n })\n}\n\npage.addSelectedUploadsToAlbum = () => {\n if (page.currentView !== 'uploads')\n return\n\n const count = page.selected[page.currentView].length\n if (!count)\n return swal('An error occurred!', 'You have not selected any uploads.', 'error')\n\n page.addUploadsToAlbum(page.selected[page.currentView], failed => {\n if (!failed) return\n if (failed.length)\n page.selected[page.currentView] = page.selected[page.currentView].filter(id => {\n return failed.includes(id)\n })\n else\n page.selected[page.currentView] = []\n\n localStorage[lsKeys.selected[page.currentView]] = JSON.stringify(page.selected[page.currentView])\n page.getUploads(page.views[page.currentView])\n })\n}\n\npage.addToAlbum = id => {\n page.addUploadsToAlbum([id], failed => {\n if (!failed) return\n page.getUploads(page.views[page.currentView])\n })\n}\n\npage.addUploadsToAlbum = (ids, callback) => {\n const count = ids.length\n\n const content = document.createElement('div')\n content.innerHTML = `\n <div class=\"field has-text-centered\">\n <p>You are about to add <b>${count}</b> upload${count === 1 ? '' : 's'} to an album.</p>\n <p><b>If an upload is already in an album, it will be moved.</b></p>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <div class=\"select is-fullwidth\">\n <select id=\"swalAlbum\" disabled>\n <option value=\"-1\">Remove from album</option>\n <option value=\"\" selected disabled>Fetching albums list\\u2026</option>\n </select>\n </div>\n </div>\n </div>\n `\n\n swal({\n icon: 'warning',\n content,\n buttons: {\n cancel: true,\n confirm: {\n text: 'OK',\n closeModal: false\n }\n }\n }).then(choose => {\n if (!choose) return\n\n const albumid = parseInt(document.querySelector('#swalAlbum').value)\n if (isNaN(albumid))\n return swal('An error occurred!', 'You did not choose an album.', 'error')\n\n axios.post('api/albums/addfiles', {\n ids,\n albumid\n }).then(add => {\n if (!add) return\n\n if (add.data.success === false) {\n if (add.data.description === 'No token provided')\n page.verifyToken(page.token)\n else\n swal('An error occurred!', add.data.description, 'error')\n\n return\n }\n\n let added = ids.length\n if (add.data.failed && add.data.failed.length)\n added -= add.data.failed.length\n\n const suffix = `upload${ids.length === 1 ? '' : 's'}`\n if (!added)\n return swal('An error occurred!', `Could not add the ${suffix} to the album.`, 'error')\n\n swal('Woohoo!', `Successfully ${albumid < 0 ? 'removed' : 'added'} ${added} ${suffix} ${albumid < 0 ? 'from' : 'to'} the album.`, 'success')\n callback(add.data.failed)\n }).catch(error => {\n console.error(error)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n }).catch(error => {\n console.error(error)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n\n // Get albums list then update content of swal\n axios.get('api/albums').then(list => {\n if (list.data.success === false) {\n if (list.data.description === 'No token provided')\n page.verifyToken(page.token)\n else\n swal('An error occurred!', list.data.description, 'error')\n\n return\n }\n\n // If the prompt was replaced, the container would be missing\n const select = document.querySelector('#swalAlbum')\n if (!select) return\n\n select.innerHTML += list.data.albums\n .map(album => {\n return `<option value=\"${album.id}\">${album.name}</option>`\n })\n .join('\\n')\n\n select.getElementsByTagName('option')[1].innerHTML = 'Choose an album'\n select.removeAttribute('disabled')\n }).catch(error => {\n console.error(error)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n}\n\npage.getAlbums = (params = {}) => {\n page.updateTrigger(params.trigger, 'loading')\n axios.get('api/albums').then(response => {\n if (!response) return\n\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else {\n page.updateTrigger(params.trigger)\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n page.cache.albums = {}\n\n page.dom.innerHTML = `\n <h2 class=\"subtitle\">Create new album</h2>\n <form class=\"prevent-default\">\n <div class=\"field\">\n <div class=\"control\">\n <input id=\"albumName\" class=\"input\" type=\"text\" placeholder=\"Name\">\n </div>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <textarea id=\"albumDescription\" class=\"textarea\" placeholder=\"Description\" rows=\"1\"></textarea>\n </div>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <button type=\"submit\" id=\"submitAlbum\" class=\"button is-info is-fullwidth\" data-action=\"submit-album\">\n <span class=\"icon\">\n <i class=\"icon-paper-plane\"></i>\n </span>\n <span>Create</span>\n </button>\n </div>\n </div>\n </form>\n <hr>\n <h2 class=\"subtitle\">List of albums</h2>\n <div class=\"table-container\">\n <table class=\"table is-fullwidth is-hoverable\">\n <thead>\n <tr>\n <th>ID</th>\n <th>Name</th>\n <th>Files</th>\n <th>Created at</th>\n <th>Public link</th>\n <th></th>\n </tr>\n </thead>\n <tbody id=\"table\">\n </tbody>\n </table>\n </div>\n `\n\n const homeDomain = response.data.homeDomain\n const table = document.querySelector('#table')\n\n for (let i = 0; i < response.data.albums.length; i++) {\n const album = response.data.albums[i]\n const albumUrl = `${homeDomain}/a/${album.identifier}`\n\n // Prettify\n album.prettyDate = page.getPrettyDate(new Date(album.timestamp * 1000))\n\n page.cache.albums[album.id] = {\n name: album.name,\n download: album.download,\n public: album.public,\n description: album.description\n }\n\n const tr = document.createElement('tr')\n tr.innerHTML = `\n <th>${album.id}</th>\n <th>${album.name}</th>\n <th>${album.files}</th>\n <td>${album.prettyDate}</td>\n <td><a ${album.public ? `href=\"${albumUrl}\"` : 'class=\"is-linethrough\"'} target=\"_blank\" rel=\"noopener\">${albumUrl}</a></td>\n <td class=\"has-text-right\" data-id=\"${album.id}\">\n <a class=\"button is-small is-primary\" title=\"Edit album\" data-action=\"edit-album\">\n <span class=\"icon is-small\">\n <i class=\"icon-pencil\"></i>\n </span>\n </a>\n <a class=\"button is-small is-info clipboard-js\" title=\"Copy link to clipboard\" ${album.public ? `data-clipboard-text=\"${albumUrl}\"` : 'disabled'}>\n <span class=\"icon is-small\">\n <i class=\"icon-clipboard\"></i>\n </span>\n </a>\n <a class=\"button is-small is-warning\" title=\"Download album\" ${album.download ? `href=\"api/album/zip/${album.identifier}?v=${album.editedAt}\"` : 'disabled'}>\n <span class=\"icon is-small\">\n <i class=\"icon-download\"></i>\n </span>\n </a>\n <a class=\"button is-small is-danger\" title=\"Delete album\" data-action=\"delete-album\">\n <span class=\"icon is-small\">\n <i class=\"icon-trash\"></i>\n </span>\n </a>\n </td>\n `\n\n table.appendChild(tr)\n }\n page.fadeAndScroll()\n page.updateTrigger(params.trigger, 'active')\n }).catch(error => {\n console.error(error)\n page.updateTrigger(params.trigger)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n}\n\npage.editAlbum = id => {\n const album = page.cache.albums[id]\n if (!album) return\n\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\" value=\"${album.name || ''}\">\n </div>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <textarea id=\"swalDescription\" class=\"textarea\" placeholder=\"Description\" rows=\"2\">${album.description || ''}</textarea>\n </div>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <label class=\"checkbox\">\n <input id=\"swalDownload\" type=\"checkbox\" ${album.download ? '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\" ${album.public ? 'checked' : ''}>\n Enable public link\n </label>\n </div>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <label class=\"checkbox\">\n <input id=\"swalRequestLink\" type=\"checkbox\">\n Request new public link\n </label>\n </div>\n </div>\n `\n\n swal({\n title: 'Edit 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 axios.post('api/albums/edit', {\n id,\n name: document.querySelector('#swalName').value.trim(),\n description: document.querySelector('#swalDescription').value.trim(),\n download: document.querySelector('#swalDownload').checked,\n public: document.querySelector('#swalPublic').checked,\n requestLink: document.querySelector('#swalRequestLink').checked\n }).then(response => {\n if (!response) return\n\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else {\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n if (response.data.identifier)\n swal('Success!', `Your album's new identifier is: ${response.data.identifier}.`, 'success')\n else if (response.data.name !== album.name)\n swal('Success!', `Your album was renamed to: ${response.data.name}.`, 'success')\n else\n swal('Success!', 'Your album was edited!', 'success')\n\n page.getAlbumsSidebar()\n page.getAlbums()\n }).catch(error => {\n console.error(error)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n })\n}\n\npage.deleteAlbum = id => {\n swal({\n title: 'Are you sure?',\n text: 'This won\\'t delete your uploads, only the album!',\n icon: 'warning',\n dangerMode: true,\n buttons: {\n cancel: true,\n confirm: {\n text: 'Yes, delete it!',\n closeModal: false\n },\n purge: {\n text: 'Umm, delete the uploads too please?',\n value: 'purge',\n className: 'swal-button--danger',\n closeModal: false\n }\n }\n }).then(proceed => {\n if (!proceed) return\n\n axios.post('api/albums/delete', {\n id,\n purge: proceed === 'purge'\n }).then(response => {\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else if (Array.isArray(response.data.failed) && response.data.failed.length) {\n return swal('An error occurred!', 'Unable to delete ', 'error')\n } else {\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n swal('Deleted!', 'Your album has been deleted.', 'success')\n page.getAlbumsSidebar()\n page.getAlbums()\n }).catch(error => {\n console.error(error)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n })\n}\n\npage.submitAlbum = element => {\n page.updateTrigger(element, 'loading')\n axios.post('api/albums', {\n name: document.querySelector('#albumName').value,\n description: document.querySelector('#albumDescription').value\n }).then(response => {\n if (!response) return\n\n page.updateTrigger(element)\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else {\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n swal('Woohoo!', 'Album was created successfully.', 'success')\n page.getAlbumsSidebar()\n page.getAlbums()\n }).catch(error => {\n console.error(error)\n page.updateTrigger(element)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n}\n\npage.getAlbumsSidebar = () => {\n axios.get('api/albums/sidebar').then(response => {\n if (!response) return\n\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else {\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n const albumsContainer = document.querySelector('#albumsContainer')\n\n // Clear albums sidebar if necessary\n const oldAlbums = albumsContainer.querySelectorAll('li > a')\n if (oldAlbums.length) {\n for (let i = 0; i < oldAlbums.length; i++)\n page.menus.splice(page.menus.indexOf(oldAlbums[i]), 1)\n albumsContainer.innerHTML = ''\n }\n\n if (response.data.albums === undefined)\n return\n\n for (let i = 0; i < response.data.albums.length; i++) {\n const album = response.data.albums[i]\n const li = document.createElement('li')\n const a = document.createElement('a')\n a.id = album.id\n a.innerHTML = album.name\n a.className = 'is-relative'\n\n a.addEventListener('click', event => {\n page.getUploads({\n album: parseInt(event.currentTarget.id),\n trigger: event.currentTarget\n })\n })\n page.menus.push(a)\n\n li.appendChild(a)\n albumsContainer.appendChild(li)\n }\n }).catch(error => {\n console.error(error)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n}\n\npage.changeToken = (params = {}) => {\n page.updateTrigger(params.trigger, 'loading')\n axios.get('api/tokens').then(response => {\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else {\n page.updateTrigger(params.trigger)\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n page.dom.innerHTML = `\n <div class=\"field\">\n <label class=\"label\">Your current token:</label>\n <div class=\"field\">\n <div class=\"control\">\n <input id=\"token\" readonly class=\"input\" type=\"text\" placeholder=\"Your token\" value=\"${response.data.token}\">\n </div>\n </div>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <a id=\"getNewToken\" class=\"button is-info is-fullwidth\">\n <span class=\"icon\">\n <i class=\"icon-arrows-cw\"></i>\n </span>\n <span>Request new token</span>\n </a>\n </div>\n </div>\n `\n page.fadeAndScroll()\n page.updateTrigger(params.trigger, 'active')\n\n document.querySelector('#getNewToken').addEventListener('click', event => {\n const trigger = event.currentTarget\n page.updateTrigger(trigger, 'loading')\n axios.post('api/tokens/change').then(response => {\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else {\n page.updateTrigger(trigger)\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n page.updateTrigger(trigger)\n swal({\n title: 'Woohoo!',\n text: 'Your token was successfully changed.',\n icon: 'success'\n }).then(() => {\n axios.defaults.headers.common.token = response.data.token\n localStorage[lsKeys.token] = response.data.token\n page.token = response.data.token\n page.changeToken()\n })\n }).catch(error => {\n console.error(error)\n page.updateTrigger(trigger)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n })\n }).catch(error => {\n console.error(error)\n page.updateTrigger(params.trigger)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n}\n\npage.changePassword = (params = {}) => {\n page.dom.innerHTML = `\n <form class=\"prevent-default\">\n <div class=\"field\">\n <label class=\"label\">New password:</label>\n <div class=\"control\">\n <input id=\"password\" class=\"input\" type=\"password\" min=\"6\" max=\"64\">\n </div>\n </div>\n <div class=\"field\">\n <label class=\"label\">Re-type new password:</label>\n <div class=\"control\">\n <input id=\"passwordConfirm\" class=\"input\" type=\"password\" min=\"6\" max=\"64\">\n </div>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <button type=\"submit\" id=\"sendChangePassword\" class=\"button is-info is-fullwidth\">\n <span class=\"icon\">\n <i class=\"icon-paper-plane\"></i>\n </span>\n <span>Set new password</span>\n </button>\n </div>\n </div>\n </form>\n `\n page.fadeAndScroll()\n page.updateTrigger(params.trigger, 'active')\n\n document.querySelector('#sendChangePassword').addEventListener('click', event => {\n if (document.querySelector('#password').value === document.querySelector('#passwordConfirm').value)\n page.sendNewPassword(document.querySelector('#password').value, event.currentTarget)\n else\n swal({\n title: 'Password mismatch!',\n text: 'Your passwords do not match, please try again.',\n icon: 'error'\n })\n })\n}\n\npage.sendNewPassword = (pass, element) => {\n page.updateTrigger(element, 'loading')\n\n axios.post('api/password/change', { password: pass }).then(response => {\n page.updateTrigger(element)\n\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else {\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n swal({\n title: 'Woohoo!',\n text: 'Your password was successfully changed.',\n icon: 'success'\n }).then(() => {\n page.changePassword()\n })\n }).catch(error => {\n console.error(error)\n page.updateTrigger(element)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n}\n\npage.getUsers = (params = {}) => {\n page.updateTrigger(params.trigger, 'loading')\n\n if (params.pageNum === undefined)\n params.pageNum = 0\n\n if (!page.permissions.admin)\n return swal('An error occurred!', 'You can not do this!', 'error')\n\n const url = `api/users/${params.pageNum}`\n axios.get(url).then(response => {\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else {\n page.updateTrigger(params.trigger)\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n if (params.pageNum && (response.data.users.length === 0)) {\n // Only remove loading class here, since beyond this the entire page will be replaced anyways\n page.updateTrigger(params.trigger)\n return swal('An error occurred!', `There are no more users to populate page ${params.pageNum + 1}.`, 'error')\n }\n\n page.currentView = 'users'\n page.cache.users = {}\n\n const pagination = page.paginate(response.data.count, 25, params.pageNum)\n\n const extraControls = `\n <div class=\"columns\">\n <div class=\"column is-hidden-mobile\"></div>\n <div class=\"column is-one-quarter\">\n <form class=\"prevent-default\">\n <div class=\"field has-addons\">\n <div class=\"control is-expanded\">\n <input id=\"jumpToPage\" class=\"input is-small\" type=\"number\" value=\"${params.pageNum + 1}\">\n </div>\n <div class=\"control\">\n <button type=\"submit\" class=\"button is-small is-info\" title=\"Jump to page\" data-action=\"jump-to-page\">\n <span class=\"icon\">\n <i class=\"icon-paper-plane\"></i>\n </span>\n </button>\n </div>\n </div>\n </form>\n </div>\n </div>\n `\n\n const controls = `\n <div class=\"columns is-hidden\">\n <div class=\"column is-hidden-mobile\"></div>\n <div class=\"column has-text-right\">\n <a class=\"button is-small is-info\" title=\"Clear selection\" data-action=\"clear-selection\">\n <span class=\"icon\">\n <i class=\"icon-cancel\"></i>\n </span>\n </a>\n <a class=\"button is-small is-warning\" title=\"Bulk disable (WIP)\" data-action=\"bulk-disable-users\" disabled>\n <span class=\"icon\">\n <i class=\"icon-hammer\"></i>\n </span>\n <span>Bulk disable</span>\n </a>\n <a class=\"button is-small is-danger\" title=\"Bulk delete (WIP)\" data-action=\"bulk-delete-users\" disabled>\n <span class=\"icon\">\n <i class=\"icon-trash\"></i>\n </span>\n <span>Bulk delete</span>\n </a>\n </div>\n </div>\n `\n\n // Whether there are any unselected items\n let unselected = false\n\n page.dom.innerHTML = `\n ${pagination}\n ${extraControls}\n ${controls}\n <div class=\"table-container\">\n <table class=\"table is-narrow is-fullwidth is-hoverable\">\n <thead>\n <tr>\n <th class=\"is-hidden\"><input id=\"selectAll\" class=\"checkbox\" type=\"checkbox\" title=\"Select all\" data-action=\"select-all\"></th>\n <th>ID</th>\n <th>Username</th>\n <th>Uploads</th>\n <th>Usage</th>\n <th>Group</th>\n <th></th>\n </tr>\n </thead>\n <tbody id=\"table\">\n </tbody>\n </table>\n </div>\n <hr>\n ${pagination}\n `\n\n const table = document.querySelector('#table')\n\n for (let i = 0; i < response.data.users.length; i++) {\n const user = response.data.users[i]\n const selected = page.selected.users.includes(user.id)\n if (!selected) unselected = true\n\n let displayGroup = null\n const groups = Object.keys(user.groups)\n for (let i = 0; i < groups.length; i++) {\n if (!user.groups[groups[i]]) break\n displayGroup = groups[i]\n }\n\n // Server-side explicitly expects either of these two values to consider a user as disabled\n const enabled = user.enabled !== false && user.enabled !== 0\n page.cache.users[user.id] = {\n username: user.username,\n groups: user.groups,\n enabled,\n displayGroup\n }\n\n const tr = document.createElement('tr')\n tr.dataset.id = user.id\n tr.innerHTML = `\n <td class=\"controls is-hidden\"><input type=\"checkbox\" class=\"checkbox\" title=\"Select\" data-action=\"select\"${selected ? ' checked' : ''}></td>\n <th>${user.id}</th>\n <th${enabled ? '' : ' class=\"is-linethrough\"'}>${user.username}</td>\n <th>${user.uploads}</th>\n <td>${page.getPrettyBytes(user.usage)}</td>\n <td>${displayGroup}</td>\n <td class=\"controls has-text-right\">\n <a class=\"button is-small is-primary\" title=\"Edit user\" data-action=\"edit-user\">\n <span class=\"icon\">\n <i class=\"icon-pencil\"></i>\n </span>\n </a>\n <a class=\"button is-small is-info\" title=\"${user.uploads ? 'View uploads' : 'User doesn\\'t have uploads'}\" data-action=\"view-user-uploads\" ${user.uploads ? '' : 'disabled'}>\n <span class=\"icon\">\n <i class=\"icon-docs\"></i>\n </span>\n </a>\n <a class=\"button is-small is-warning\" title=\"${enabled ? 'Disable user' : 'User is disabled'}\" data-action=\"disable-user\" ${enabled ? '' : 'disabled'}>\n <span class=\"icon\">\n <i class=\"icon-hammer\"></i>\n </span>\n </a>\n <a class=\"button is-small is-danger is-hidden\" title=\"Delete user (WIP)\" data-action=\"delete-user\" disabled>\n <span class=\"icon\">\n <i class=\"icon-trash\"></i>\n </span>\n </a>\n </td>\n `\n\n table.appendChild(tr)\n page.checkboxes.users = table.querySelectorAll('.checkbox[data-action=\"select\"]')\n }\n\n const selectAll = document.querySelector('#selectAll')\n if (selectAll && !unselected) {\n selectAll.checked = true\n selectAll.title = 'Unselect all'\n }\n\n page.fadeAndScroll()\n page.updateTrigger(params.trigger, 'active')\n\n page.views.users.pageNum = response.data.users.length ? params.pageNum : 0\n }).catch(error => {\n page.updateTrigger(params.trigger)\n console.error(error)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n}\n\npage.editUser = id => {\n const user = page.cache.users[id]\n if (!user) return\n\n const groupOptions = Object.keys(page.permissions).map((g, i, a) => {\n const selected = g === user.displayGroup\n const disabled = !(a[i + 1] && page.permissions[a[i + 1]])\n return `<option value=\"${g}\"${selected ? ' selected' : ''}${disabled ? ' disabled' : ''}>${g}</option>`\n }).join('\\n')\n\n const div = document.createElement('div')\n div.innerHTML = `\n <div class=\"field\">\n <label class=\"label\">Username</label>\n <div class=\"controls\">\n <input id=\"swalUsername\" class=\"input\" type=\"text\" value=\"${user.username || ''}\">\n </div>\n </div>\n <div class=\"field\">\n <label class=\"label\">User group</label>\n <div class=\"control\">\n <div class=\"select is-fullwidth\">\n <select id=\"swalGroup\">\n ${groupOptions}\n </select>\n </div>\n </div>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <label class=\"checkbox\">\n <input id=\"swalEnabled\" type=\"checkbox\" ${user.enabled ? 'checked' : ''}>\n Enabled\n </label>\n </div>\n </div>\n <div class=\"field\">\n <div class=\"control\">\n <label class=\"checkbox\">\n <input id=\"swalResetPassword\" type=\"checkbox\">\n Reset password\n </label>\n </div>\n </div>\n `\n\n swal({\n title: 'Edit user',\n icon: 'info',\n content: div,\n buttons: {\n cancel: true,\n confirm: {\n closeModal: false\n }\n }\n }).then(proceed => {\n if (!proceed) return\n\n axios.post('api/users/edit', {\n id,\n username: document.querySelector('#swalUsername').value,\n group: document.querySelector('#swalGroup').value,\n enabled: document.querySelector('#swalEnabled').checked,\n resetPassword: document.querySelector('#swalResetPassword').checked\n }).then(response => {\n if (!response) return\n\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else {\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n if (response.data.password) {\n const div = document.createElement('div')\n div.innerHTML = `\n <p><b>${user.username}</b>'s new password is:</p>\n <p><code>${response.data.password}</code></p>\n `\n swal({\n title: 'Success!',\n icon: 'success',\n content: div\n })\n } else if (response.data.update && response.data.update.username !== user.username) {\n swal('Success!', `${user.username} was renamed into: ${response.data.update.name}.`, 'success')\n } else {\n swal('Success!', 'The user was edited!', 'success')\n }\n\n page.getUsers(page.views.users)\n }).catch(error => {\n console.error(error)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n })\n}\n\npage.disableUser = id => {\n const user = page.cache.users[id]\n if (!user || !user.enabled) return\n\n const content = document.createElement('div')\n content.innerHTML = `You will be disabling a user with the username <b>${page.cache.users[id].username}</b>.`\n\n swal({\n title: 'Are you sure?',\n icon: 'warning',\n content,\n dangerMode: true,\n buttons: {\n cancel: true,\n confirm: {\n text: 'Yes, disable them!',\n closeModal: false\n }\n }\n }).then(proceed => {\n if (!proceed) return\n\n axios.post('api/users/disable', { id }).then(response => {\n if (!response) return\n\n if (response.data.success === false)\n if (response.data.description === 'No token provided')\n return page.verifyToken(page.token)\n else\n return swal('An error occurred!', response.data.description, 'error')\n\n swal('Success!', 'The user has been disabled.', 'success')\n page.getUsers(page.views.users)\n }).catch(error => {\n console.error(error)\n return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')\n })\n })\n}\n\n// Roughly based on https://github.com/mayuska/pagination/blob/master/index.js\npage.paginate = (totalItems, itemsPerPage, currentPage) => {\n currentPage = currentPage + 1\n const step = 3\n const numPages = Math.ceil(totalItems / itemsPerPage)\n\n let template = ''\n const elementsToShow = step * 2\n const add = {\n pageNum (start, end) {\n for (let i = start; i <= end; ++i)\n template += `<li><a class=\"button pagination-link ${i === currentPage ? ' is-current' : ''}\" aria-label=\"Goto page ${i}\" data-action=\"page-goto\" data-goto=\"${i - 1}\">${i}</a></li>`\n },\n startDots () {\n template += `\n <li><a class=\"button pagination-link\" aria-label=\"Goto page 1\" data-action=\"page-goto\" data-goto=\"0\">1</a></li>\n <li data-action=\"page-ellipsis\"><span class=\"pagination-ellipsis\">…</span></li>\n `\n },\n endDots () {\n template += `\n <li data-action=\"page-ellipsis\"><span class=\"pagination-ellipsis\">…</span></li>\n <li><a class=\"button pagination-link\" aria-label=\"Goto page ${numPages}\" data-action=\"page-goto\" data-goto=\"${numPages - 1}\">${numPages}</a></li>\n `\n }\n }\n\n if (elementsToShow + 1 >= numPages) {\n add.pageNum(1, numPages)\n } else if (currentPage < elementsToShow) {\n add.pageNum(1, elementsToShow)\n add.endDots()\n } else if (currentPage > numPages - elementsToShow + 1) {\n add.startDots()\n add.pageNum(numPages - elementsToShow + 1, numPages)\n } else {\n add.startDots()\n add.pageNum(currentPage - step + 1, currentPage + step - 1)\n add.endDots()\n }\n\n return `\n <nav class=\"pagination is-centered is-small\">\n <a class=\"button pagination-previous\" data-action=\"page-prev\">Previous</a>\n <a class=\"button pagination-next\" data-action=\"page-next\">Next page</a>\n <ul class=\"pagination-list\">${template}</ul>\n </nav>\n `\n}\n\npage.getStatistics = (params = {}) => {\n if (!page.permissions.admin)\n return swal('An error occurred!', 'You can not do this!', 'error')\n\n page.updateTrigger(params.trigger, 'loading')\n const url = 'api/stats'\n axios.get(url).then(response => {\n if (response.data.success === false)\n if (response.data.description === 'No token provided') {\n return page.verifyToken(page.token)\n } else {\n page.updateTrigger(params.trigger)\n return swal('An error occurred!', response.data.description, 'error')\n }\n\n let content = ''\n const keys = Object.keys(response.data.stats)\n for (let i = 0; i < keys.length; i++) {\n let rows = ''\n if (!response.data.stats[keys[i]])\n rows += `\n <tr>\n <td>Generating, please try again later\\u2026</td>\n <td></td>\n </tr>\n `\n else\n try {\n const types = response.data.stats[keys[i]]._types || {}\n const valKeys = Object.keys(response.data.stats[keys[i]])\n for (let j = 0; j < valKeys.length; j++) {\n // Skip keys that starts with an underscore\n if (/^_/.test(valKeys[j]))\n continue\n\n const value = response.data.stats[keys[i]][valKeys[j]]\n let parsed = value\n\n // Parse values with some preset formatting\n if ((types.number || []).includes(valKeys[j]))\n parsed = value.toLocaleString()\n if ((types.byte || []).includes(valKeys[j]))\n parsed = page.getPrettyBytes(value)\n if ((types.byteUsage || []).includes(valKeys[j]))\n parsed = `${page.getPrettyBytes(value.used)} / ${page.getPrettyBytes(value.total)} (${Math.round(value.used / value.total * 100)}%)`\n\n const string = valKeys[j]\n .replace(/([A-Z])/g, ' $1')\n .toUpperCase()\n rows += `\n <tr>\n <th>${string}</th>\n <td>${parsed}</td>\n </tr>\n `\n }\n } catch (error) {\n console.error(error)\n rows = `\n <tr>\n <td>Error parsing response. Try again?</td>\n <td></td>\n </tr>\n `\n }\n\n content += `\n <div class=\"table-container\">\n <table id=\"statistics\" class=\"table is-fullwidth is-hoverable\">\n <thead>\n <tr>\n <th>${keys[i].toUpperCase()}</th>\n <td></td>\n </tr>\n </thead>\n <tbody>\n ${rows}\n </tbody>\n </table>\n </div>\n `\n }\n\n page.dom.innerHTML = content\n page.fadeAndScroll()\n page.updateTrigger(params.trigger, 'active')\n }).catch(error => {\n console.error(error)\n page.updateTrigger(params.trigger)\n const description = error.response.data && error.response.data.description\n ? error.response.data && error.response.data.description\n : 'There was an error with the request, please check the console for more information.'\n return swal('An error occurred!', description, 'error')\n })\n}\n\nwindow.onload = () => {\n // eslint-disable-next-line compat/compat\n if (typeof Object.assign !== 'function')\n // Must be writable: true, enumerable: false, configurable: true\n Object.defineProperty(Object, 'assign', {\n value: function assign (target, varArgs) { // .length of function is 2\n 'use strict'\n if (target === null || target === undefined)\n throw new TypeError('Cannot convert undefined or null to object')\n const to = Object(target)\n for (let i = 1; i < arguments.length; i++) {\n const nextSource = arguments[i]\n if (nextSource !== null && nextSource !== undefined)\n for (const nextKey in nextSource)\n // Avoid bugs when hasOwnProperty is shadowed\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey))\n to[nextKey] = nextSource[nextKey]\n }\n return to\n },\n writable: true,\n configurable: true\n })\n\n // Add 'no-touch' class to non-touch devices\n if (!('ontouchstart' in document.documentElement))\n document.documentElement.classList.add('no-touch')\n\n const selectedKeys = ['uploads', 'uploadsAll', 'users']\n for (let i = 0; i < selectedKeys.length; i++) {\n const ls = localStorage[lsKeys.selected[selectedKeys[i]]]\n if (ls) page.selected[selectedKeys[i]] = JSON.parse(ls)\n }\n\n page.preparePage()\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', event => {\n console.error(event)\n return swal('An error occurred!', 'There was an error when trying to copy the link to clipboard, please check the console for more information.', 'error')\n })\n\n page.lazyLoad = new LazyLoad()\n}\n"]} |