From c9ba16e1d661b5754222a5ea03364c9712771288 Mon Sep 17 00:00:00 2001 From: Bobby Wibowo Date: Sun, 15 Sep 2019 13:20:11 +0700 Subject: [PATCH] Updates (very important to read) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Client-side CSS & JS files will now be processed with Gulp. Gulp tasks are configured in gulpfile.js file. CSS files will be optimized with postcss-preset-env, which will auto-add vendor prefixes and convert any parts necessary for browsers compatibility. Afterwards they will be minified with cssnano. JS files will be optimized with bublé, likewise for browsers compatibility. Afterwards they will be minified with terser. Unprocessed CSS & JS files will now be located at src directory, while the processed results will be located at dist directory. Due to bublé, the JS files should now be compatible up to IE 11 at the minimum. Previously the safe would not work in IE 11 due to extensive usage of template literals. Due to that as well, JS files in src directory will now extensively use arrow functions for my personal comfort (as they will be converted too). The server will use the processed files at dist directory by default. If you want to rebuild the files by your own, you can run "yarn build". Gulp is a development dependency, so make sure you have installed all development dependencies (e.i. NOT using "yarn install --production"). --- yarn lint -> gulp lint yarn build -> gulp default yarn watch -> gulp watch yarn develop -> env NODE_ENV=development yarn watch --- Fixed not being able to demote staff into normal users. /api/token/verify will no longer respond with 401 HTTP error code, unless an error occurred (which will be 500 HTTP error code). Fixed /nojs route not displaying file's original name when a duplicate is found on the server. Removed is-breeze CSS class name, in favor of Bulma's is-info. Removed custom styling from auth page, in favor of global styling. Removed all usage of style HTML attribute in favor of CSS classes. Renamed js/s/ to js/misc/. Use loading spinners on dashboard's sidebar menus. Disable all other sidebar menus when something is loading. Changed title HTML attribute of disabled control buttons in uploads & users list. Hid checkboxes and WIP controls from users list. Better error messages handling. Especially homepage will now support CF's HTTP error codes. Updated various icons. Also, added fontello config file at public/libs/fontello/config.json. This should let you edit them more easily with fontello. Use Gatsby icon for my blog's link in homepage's footer. A bunch of other improvements here & there. --- .browserslistrc | 7 + .eslintignore | 2 + .gitignore | 74 +- .stylelintignore | 2 + .stylelintrc => .stylelintrc.json | 0 controllers/albumsController.js | 10 +- controllers/authController.js | 10 +- controllers/pathsController.js | 48 +- controllers/tokenController.js | 12 +- controllers/uploadController.js | 17 +- controllers/utilsController.js | 22 +- database/db.js | 4 +- database/migration.js | 2 +- dist/css/album.css | 2 + dist/css/album.css.map | 1 + dist/css/dashboard.css | 2 + dist/css/dashboard.css.map | 1 + dist/css/home.css | 2 + dist/css/home.css.map | 1 + dist/css/style.css | 2 + dist/css/style.css.map | 1 + dist/css/sweetalert.css | 2 + dist/css/sweetalert.css.map | 1 + dist/css/thumbs.css | 2 + dist/css/thumbs.css.map | 1 + dist/js/album.js | 2 + dist/js/album.js.map | 1 + dist/js/auth.js | 2 + dist/js/auth.js.map | 1 + dist/js/dashboard.js | 2 + dist/js/dashboard.js.map | 1 + dist/js/home.js | 2 + dist/js/home.js.map | 1 + dist/js/misc/render.js | 2 + dist/js/misc/render.js.map | 1 + dist/js/misc/utils.js | 2 + dist/js/misc/utils.js.map | 1 + gulpfile.js | 106 + lolisafe.js | 35 +- package.json | 24 +- public/css/auth.css | 31 - public/libs/fontello/LICENSE | 9 - public/libs/fontello/config.json | 240 ++ public/libs/fontello/fontello.css | 53 +- public/libs/fontello/fontello.eot | Bin 15196 -> 15208 bytes public/libs/fontello/fontello.svg | 46 +- public/libs/fontello/fontello.ttf | Bin 15028 -> 15040 bytes public/libs/fontello/fontello.woff | Bin 9768 -> 9812 bytes public/libs/fontello/fontello.woff2 | Bin 8304 -> 8352 bytes routes/album.js | 6 +- routes/api.js | 6 +- routes/nojs.js | 2 +- scripts/_utils.js | 13 - scripts/cf-purge.js | 3 +- scripts/clean-up.js | 8 +- scripts/delete-expired.js | 5 +- scripts/thumbs.js | 7 +- {public => src}/css/album.css | 0 {public => src}/css/dashboard.css | 27 +- {public => src}/css/home.css | 33 +- {public => src}/css/style.css | 51 +- {public => src}/css/sweetalert.css | 9 - {public => src}/css/thumbs.css | 14 - {public => src}/js/.eslintrc.json | 6 +- {public => src}/js/album.js | 2 +- {public => src}/js/auth.js | 30 +- {public => src}/js/dashboard.js | 802 ++++--- {public => src}/js/home.js | 329 +-- {public/js/s => src/js/misc}/render.js | 12 +- {public/js/s => src/js/misc}/utils.js | 10 +- todo.md | 9 +- views/_globals.njk | 12 +- views/album.njk | 4 +- views/auth.njk | 3 +- views/dashboard.njk | 32 +- views/home.njk | 22 +- views/nojs.njk | 20 +- yarn.lock | 2820 +++++++++++++++++++++++- 78 files changed, 4112 insertions(+), 975 deletions(-) create mode 100644 .browserslistrc create mode 100644 .stylelintignore rename .stylelintrc => .stylelintrc.json (100%) create mode 100644 dist/css/album.css create mode 100644 dist/css/album.css.map create mode 100644 dist/css/dashboard.css create mode 100644 dist/css/dashboard.css.map create mode 100644 dist/css/home.css create mode 100644 dist/css/home.css.map create mode 100644 dist/css/style.css create mode 100644 dist/css/style.css.map create mode 100644 dist/css/sweetalert.css create mode 100644 dist/css/sweetalert.css.map create mode 100644 dist/css/thumbs.css create mode 100644 dist/css/thumbs.css.map create mode 100644 dist/js/album.js create mode 100644 dist/js/album.js.map create mode 100644 dist/js/auth.js create mode 100644 dist/js/auth.js.map create mode 100644 dist/js/dashboard.js create mode 100644 dist/js/dashboard.js.map create mode 100644 dist/js/home.js create mode 100644 dist/js/home.js.map create mode 100644 dist/js/misc/render.js create mode 100644 dist/js/misc/render.js.map create mode 100644 dist/js/misc/utils.js create mode 100644 dist/js/misc/utils.js.map create mode 100644 gulpfile.js delete mode 100644 public/css/auth.css create mode 100644 public/libs/fontello/config.json delete mode 100644 scripts/_utils.js rename {public => src}/css/album.css (100%) rename {public => src}/css/dashboard.css (86%) rename {public => src}/css/home.css (68%) rename {public => src}/css/style.css (63%) rename {public => src}/css/sweetalert.css (85%) rename {public => src}/css/thumbs.css (73%) rename {public => src}/js/.eslintrc.json (81%) rename {public => src}/js/album.js (92%) rename {public => src}/js/auth.js (79%) rename {public => src}/js/dashboard.js (75%) rename {public => src}/js/home.js (74%) rename {public/js/s => src/js/misc}/render.js (93%) rename {public/js/s => src/js/misc}/utils.js (89%) diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 0000000..eeeb5d8 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,7 @@ +# Browserslist's defaults (supports IE 11 at the minimum) +# https://github.com/browserslist/browserslist#queries + +> 0.5% +last 2 versions +Firefox ESR +not dead diff --git a/.eslintignore b/.eslintignore index db181dd..2552e3d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,3 @@ **/*.min.js +dist/js/* +public/libs/* diff --git a/.gitignore b/.gitignore index d2b8673..99c5c60 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,63 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Dependency directories +node_modules/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# npm's package-lock (if npm is accidentally used) +package-lock.json + +# vscode's workspace settings +/.vscode + +# Configuration file +/config.js + +# Database +/database/db + +# Uploads directory +/uploads + +# Custom pages directory +/pages/custom + +# User files .DS_Store .nvmrc -.vscode !.gitkeep -node_modules -uploads -logs -database/db -config.js -start.json -npm-debug.log -pages/custom/** -migrate.js -yarn-error.log -package-lock.json -public/render/**/original -public/render/**/wip +/start.json +/migrate.js + +# User directories (renders) +/public/render/**/original +/public/render/**/wip diff --git a/.stylelintignore b/.stylelintignore new file mode 100644 index 0000000..9ab1391 --- /dev/null +++ b/.stylelintignore @@ -0,0 +1,2 @@ +dist/css/* +public/libs/* diff --git a/.stylelintrc b/.stylelintrc.json similarity index 100% rename from .stylelintrc rename to .stylelintrc.json diff --git a/controllers/albumsController.js b/controllers/albumsController.js index dd8db8d..c42838d 100644 --- a/controllers/albumsController.js +++ b/controllers/albumsController.js @@ -1,13 +1,13 @@ -const config = require('./../config') -const db = require('knex')(config.database) const EventEmitter = require('events') const fs = require('fs') -const logger = require('./../logger') const path = require('path') -const paths = require('./pathsController') const randomstring = require('randomstring') -const utils = require('./utilsController') const Zip = require('jszip') +const paths = require('./pathsController') +const utils = require('./utilsController') +const config = require('./../config') +const logger = require('./../logger') +const db = require('knex')(config.database) const self = { onHold: new Set() diff --git a/controllers/authController.js b/controllers/authController.js index ec2dff0..0f41074 100644 --- a/controllers/authController.js +++ b/controllers/authController.js @@ -1,12 +1,12 @@ const { promisify } = require('util') const bcrypt = require('bcrypt') -const config = require('./../config') -const db = require('knex')(config.database) -const logger = require('./../logger') -const perms = require('./permissionController') const randomstring = require('randomstring') +const perms = require('./permissionController') const tokens = require('./tokenController') const utils = require('./utilsController') +const config = require('./../config') +const logger = require('./../logger') +const db = require('knex')(config.database) const self = { compare: promisify(bcrypt.compare), @@ -152,7 +152,7 @@ self.editUser = async (req, res, next) => { update.enabled = Boolean(req.body.enabled) if (req.body.group !== undefined) { - update.permission = perms.permissions[req.body.group] || target.permission + update.permission = perms.permissions[req.body.group] if (typeof update.permission !== 'number' || update.permission < 0) update.permission = target.permission } diff --git a/controllers/pathsController.js b/controllers/pathsController.js index 700e669..3b7102e 100644 --- a/controllers/pathsController.js +++ b/controllers/pathsController.js @@ -1,8 +1,8 @@ const { promisify } = require('util') -const config = require('./../config') const fs = require('fs') -const logger = require('./../logger') const path = require('path') +const config = require('./../config') +const logger = require('./../logger') const self = {} @@ -33,6 +33,7 @@ self.thumbPlaceholder = path.resolve(config.uploads.generateThumbs.placeholder | self.logs = path.resolve(config.logsFolder) self.customPages = path.resolve('pages/custom') +self.dist = path.resolve('dist') self.public = path.resolve('public') self.errorRoot = path.resolve(config.errorPages.rootDir) @@ -47,33 +48,28 @@ const verify = [ ] self.init = async () => { - try { - for (const p of verify) - try { - await self.access(p) - } catch (err) { - if (err.code !== 'ENOENT') { - logger.error(err) - } else { - const mkdir = await self.mkdir(p) - if (mkdir) - logger.log(`Created directory: ${p}`) - } + // Check & create directories + for (const p of verify) + try { + await self.access(p) + } catch (err) { + if (err.code !== 'ENOENT') { + throw err + } else { + const mkdir = await self.mkdir(p) + if (mkdir) + logger.log(`Created directory: ${p}`) } - - // Purge chunks directory - const uuidDirs = await self.readdir(self.chunks) - for (const uuid of uuidDirs) { - const root = path.join(self.chunks, uuid) - const chunks = await self.readdir(root) - for (const chunk of chunks) - await self.unlink(path.join(root, chunk)) - await self.rmdir(root) } - self.verified = true - } catch (error) { - logger.error(error) + // Purge any leftover in chunks directory + const uuidDirs = await self.readdir(self.chunks) + for (const uuid of uuidDirs) { + const root = path.join(self.chunks, uuid) + const chunks = await self.readdir(root) + for (const chunk of chunks) + await self.unlink(path.join(root, chunk)) + await self.rmdir(root) } } diff --git a/controllers/tokenController.js b/controllers/tokenController.js index cdadf5b..f72620d 100644 --- a/controllers/tokenController.js +++ b/controllers/tokenController.js @@ -1,9 +1,9 @@ -const config = require('./../config') -const db = require('knex')(config.database) -const logger = require('./../logger') -const perms = require('./permissionController') const randomstring = require('randomstring') +const perms = require('./permissionController') const utils = require('./utilsController') +const config = require('./../config') +const logger = require('./../logger') +const db = require('knex')(config.database) const self = { tokenLength: 64, @@ -41,7 +41,7 @@ self.verify = async (req, res, next) => { : '' if (!token) - return res.status(401).json({ success: false, description: 'No token provided.' }) + return res.json({ success: false, description: 'No token provided.' }) try { const user = await db.table('users') @@ -50,7 +50,7 @@ self.verify = async (req, res, next) => { .first() if (!user) - return res.status(401).json({ success: false, description: 'Invalid token.' }) + return res.json({ success: false, description: 'Invalid token.' }) return res.json({ success: true, diff --git a/controllers/uploadController.js b/controllers/uploadController.js index 9073270..5bd0949 100644 --- a/controllers/uploadController.js +++ b/controllers/uploadController.js @@ -1,15 +1,15 @@ -const config = require('./../config') const crypto = require('crypto') -const db = require('knex')(config.database) const fetch = require('node-fetch') const fs = require('fs') -const logger = require('./../logger') const multer = require('multer') const path = require('path') +const randomstring = require('randomstring') const paths = require('./pathsController') const perms = require('./permissionController') -const randomstring = require('randomstring') const utils = require('./utilsController') +const config = require('./../config') +const logger = require('./../logger') +const db = require('knex')(config.database) const self = {} @@ -563,6 +563,11 @@ self.storeFilesToDb = async (req, res, user, infoMap) => { // Continue even when encountering errors await utils.unlinkFile(info.data.filename).catch(logger.error) // logger.log(`Unlinked ${info.data.filename} since a duplicate named ${dbFile.name} exists`) + + // If on /nojs route, append original file name reported by client + if (req.path === '/nojs') + dbFile.original = info.data.originalname + exists.push(dbFile) continue } @@ -635,11 +640,11 @@ self.sendUploadResponse = async (req, res, result) => { url: `${config.domain}/${file.name}` } - // Add expiry date if a temporary upload + // If a temporary upload, add expiry date if (file.expirydate) map.expirydate = file.expirydate - // Add original name if on /nojs route + // If on /nojs route, add original name if (req.path === '/nojs') map.original = file.original diff --git a/controllers/utilsController.js b/controllers/utilsController.js index 65f6834..da2b8fc 100644 --- a/controllers/utilsController.js +++ b/controllers/utilsController.js @@ -1,15 +1,15 @@ const { promisify } = require('util') const { spawn } = require('child_process') -const config = require('./../config') -const db = require('knex')(config.database) const fetch = require('node-fetch') const ffmpeg = require('fluent-ffmpeg') -const logger = require('./../logger') const path = require('path') -const paths = require('./pathsController') -const perms = require('./permissionController') const sharp = require('sharp') const si = require('systeminformation') +const paths = require('./pathsController') +const perms = require('./permissionController') +const config = require('./../config') +const logger = require('./../logger') +const db = require('knex')(config.database) const self = { clamd: { @@ -148,6 +148,18 @@ self.escape = (string) => { : html } +self.stripIndents = string => { + if (!string) return + const result = string.replace(/^[^\S\n]+/gm, '') + const match = result.match(/^[^\S\n]*(?=\S)/gm) + const indent = match && Math.min(...match.map(el => el.length)) + if (indent) { + const regexp = new RegExp(`^.{${indent}}`, 'gm') + return result.replace(regexp, '') + } + return result +} + self.authorize = async (req, res) => { // TODO: Improve usage of this function by the other APIs const token = req.headers.token diff --git a/database/db.js b/database/db.js index 6e60d6c..d4252ba 100644 --- a/database/db.js +++ b/database/db.js @@ -1,6 +1,6 @@ -const logger = require('./../logger') -const perms = require('./../controllers/permissionController') const randomstring = require('randomstring') +const perms = require('./../controllers/permissionController') +const logger = require('./../logger') // TODO: Auto-detect missing columns here // That way we will no longer need the migration script diff --git a/database/migration.js b/database/migration.js index f9ca8e7..22a1fd5 100644 --- a/database/migration.js +++ b/database/migration.js @@ -1,6 +1,6 @@ +const perms = require('./../controllers/permissionController') const config = require('./../config') const db = require('knex')(config.database) -const perms = require('./../controllers/permissionController') const map = { files: { diff --git a/dist/css/album.css b/dist/css/album.css new file mode 100644 index 0000000..d0ffdb3 --- /dev/null +++ b/dist/css/album.css @@ -0,0 +1,2 @@ +.section{background:none}@media screen and (max-width:768px){.description{text-align:center}} +/*# sourceMappingURL=album.css.map */ diff --git a/dist/css/album.css.map b/dist/css/album.css.map new file mode 100644 index 0000000..2af7230 --- /dev/null +++ b/dist/css/album.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["album.css"],"names":[],"mappings":"AAAA,SACE,eACF,CAEA,oCACE,aACE,iBACF,CACF","file":"album.css","sourcesContent":[".section {\n background: none\n}\n\n@media screen and (max-width: 768px) {\n .description {\n text-align: center\n }\n}\n"]} \ No newline at end of file diff --git a/dist/css/dashboard.css b/dist/css/dashboard.css new file mode 100644 index 0000000..3a4cce9 --- /dev/null +++ b/dist/css/dashboard.css @@ -0,0 +1,2 @@ +body{-webkit-animation:none;animation:none}#dashboard{-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}.section{background:none}.menu-list a{color:#3794d2}.menu-list a:hover{color:#60a8dc;background-color:#4d4d4d}.menu-list a.is-active{color:#eff0f1;background-color:#3794d2}.menu-list a[disabled]{color:#7a7a7a;cursor:not-allowed}.menu-list a[disabled]:hover{background:none}ul#albumsContainer{border-left:0;padding-left:0}ul#albumsContainer li{border-left:1px solid #898b8d;padding-left:.75em}#page.fade-in,ul#albumsContainer li{-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}.pagination{margin-bottom:1.25rem}.pagination a:not([disabled]){color:#eff0f1;border-color:#4d4d4d;background-color:#31363b}a.pagination-link:not(.is-current):hover,a.pagination-next:not([disabled]):hover,a.pagination-previous:not([disabled]):hover{color:#eff0f1;border-color:#60a8dc;background-color:#31363b}a.pagination-link.is-current{background-color:#3794d2;border-color:#3794d2}a.pagination-link.is-current:hover{border-color:#60a8dc}li[data-action=page-ellipsis]{cursor:pointer}.label{color:#bdc3c7}.menu-list li ul{border-left-color:#898b8d}.image-container .checkbox{position:absolute;top:.75rem;left:.75rem}.no-touch .image-container .checkbox{opacity:.5}.no-touch .image-container .controls,.no-touch .image-container .details{opacity:0}.no-touch .image-container:hover .checkbox,.no-touch .image-container:hover .controls,.no-touch .image-container:hover .details{opacity:1}#page{min-width:0}.table{color:#bdc3c7;background-color:#31363b;font-size:.75rem}.table.is-striped tbody tr:nth-child(2n),.table tr:hover{background:none}.table.is-striped tbody tr:hover,.table.is-striped tbody tr:nth-child(2n):hover,.tag{background-color:#4d4d4d}.table td,.table th{border:0;white-space:nowrap}.table th{color:#eff0f1;height:2.25em}.table thead td,.table thead th{color:#eff0f1;background-color:#ff3860}.table .cell-indent{padding-left:2.25em}.is-linethrough{text-decoration:line-through}#menu.is-loading li a{cursor:progress}#statistics tr :nth-child(2){min-width:50%} +/*# sourceMappingURL=dashboard.css.map */ diff --git a/dist/css/dashboard.css.map b/dist/css/dashboard.css.map new file mode 100644 index 0000000..b756644 --- /dev/null +++ b/dist/css/dashboard.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["dashboard.css"],"names":[],"mappings":"AAAA,KACE,sBAAc,CAAd,cACF,CAEA,WACE,mCAA4B,CAA5B,2BACF,CAEA,SACE,eACF,CAEA,aACE,aACF,CAEA,mBACE,aAAc,CACd,wBACF,CAEA,uBACE,aAAc,CACd,wBACF,CAEA,uBACE,aAAc,CACd,kBACF,CAEA,6BACE,eACF,CAEA,mBACE,aAAc,CACd,cACF,CAEA,sBACE,6BAA8B,CAC9B,kBAEF,CAEA,oCAHE,mCAA4B,CAA5B,2BAKF,CAEA,YACE,qBACF,CAEA,8BACE,aAAc,CACd,oBAAqB,CACrB,wBACF,CAEA,6HAGE,aAAc,CACd,oBAAqB,CACrB,wBACF,CAEA,6BACE,wBAAyB,CACzB,oBACF,CAEA,mCACE,oBACF,CAEA,8BACE,cACF,CAEA,OACE,aACF,CAEA,iBACE,yBACF,CAEA,2BACE,iBAAkB,CAClB,UAAY,CACZ,WACF,CAEA,qCACE,UACF,CAEA,yEAEE,SACF,CAEA,gIAGE,SACF,CAEA,MAEE,WACF,CAEA,OACE,aAAc,CACd,wBAAyB,CACzB,gBACF,CAEA,yDAEE,eACF,CAEA,qFAGE,wBACF,CAEA,oBAEE,QAAS,CACT,kBACF,CAEA,UACE,aAAc,CACd,aACF,CAEA,gCAEE,aAAc,CACd,wBACF,CAEA,oBACE,mBACF,CAEA,gBACE,4BACF,CAEA,sBACE,eACF,CAEA,6BACE,aACF","file":"dashboard.css","sourcesContent":["body {\n animation: none\n}\n\n#dashboard {\n animation: fadeInOpacity 0.5s\n}\n\n.section {\n background: none\n}\n\n.menu-list a {\n color: #3794d2\n}\n\n.menu-list a:hover {\n color: #60a8dc;\n background-color: #4d4d4d\n}\n\n.menu-list a.is-active {\n color: #eff0f1;\n background-color: #3794d2\n}\n\n.menu-list a[disabled] {\n color: #7a7a7a;\n cursor: not-allowed\n}\n\n.menu-list a[disabled]:hover {\n background: none\n}\n\nul#albumsContainer {\n border-left: 0;\n padding-left: 0\n}\n\nul#albumsContainer li {\n border-left: 1px solid #898b8d;\n padding-left: 0.75em;\n animation: fadeInOpacity 0.5s\n}\n\n#page.fade-in {\n animation: fadeInOpacity 0.5s\n}\n\n.pagination {\n margin-bottom: 1.25rem\n}\n\n.pagination a:not([disabled]) {\n color: #eff0f1;\n border-color: #4d4d4d;\n background-color: #31363b\n}\n\na.pagination-link:not(.is-current):hover,\na.pagination-next:not([disabled]):hover,\na.pagination-previous:not([disabled]):hover {\n color: #eff0f1;\n border-color: #60a8dc;\n background-color: #31363b\n}\n\na.pagination-link.is-current {\n background-color: #3794d2;\n border-color: #3794d2\n}\n\na.pagination-link.is-current:hover {\n border-color: #60a8dc\n}\n\nli[data-action=\"page-ellipsis\"] {\n cursor: pointer\n}\n\n.label {\n color: #bdc3c7\n}\n\n.menu-list li ul {\n border-left-color: #898b8d\n}\n\n.image-container .checkbox {\n position: absolute;\n top: 0.75rem;\n left: 0.75rem\n}\n\n.no-touch .image-container .checkbox {\n opacity: 0.5\n}\n\n.no-touch .image-container .controls,\n.no-touch .image-container .details {\n opacity: 0\n}\n\n.no-touch .image-container:hover .checkbox,\n.no-touch .image-container:hover .controls,\n.no-touch .image-container:hover .details {\n opacity: 1\n}\n\n#page {\n /* fix overflow issue with flex */\n min-width: 0\n}\n\n.table {\n color: #bdc3c7;\n background-color: #31363b;\n font-size: 0.75rem\n}\n\n.table tr:hover,\n.table.is-striped tbody tr:nth-child(2n) {\n background: none\n}\n\n.table.is-striped tbody tr:hover,\n.table.is-striped tbody tr:nth-child(2n):hover,\n.tag {\n background-color: #4d4d4d\n}\n\n.table td,\n.table th {\n border: 0;\n white-space: nowrap\n}\n\n.table th {\n color: #eff0f1;\n height: 2.25em\n}\n\n.table thead td,\n.table thead th {\n color: #eff0f1;\n background-color: #ff3860\n}\n\n.table .cell-indent {\n padding-left: 2.25em\n}\n\n.is-linethrough {\n text-decoration: line-through\n}\n\n#menu.is-loading li a {\n cursor: progress\n}\n\n#statistics tr *:nth-child(2) {\n min-width: 50%\n}\n"]} \ No newline at end of file diff --git a/dist/css/home.css b/dist/css/home.css new file mode 100644 index 0000000..8e4c595 --- /dev/null +++ b/dist/css/home.css @@ -0,0 +1,2 @@ +#b{width:200px;height:200px;border-radius:100%;display:inline-block;margin-bottom:40px;vertical-align:top;-webkit-animation-delay:.5s;animation-delay:.5s;-webkit-animation-duration:1.5s;animation-duration:1.5s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-name:floatUp;animation-name:floatUp;-webkit-animation-timing-function:cubic-bezier(0,.71,.29,1);animation-timing-function:cubic-bezier(0,.71,.29,1);box-shadow:0 20px 60px rgba(10,10,10,.05),0 5px 10px rgba(10,10,10,.1),0 1px 1px rgba(10,10,10,.2)}#b img.logo{max-height:200px}#dropzone *{pointer-events:none}#panel,#tokenContainer{display:none}#maxSize{font-size:1rem}.dz-preview .dz-details{display:flex}.dz-preview .dz-details .dz-filename,.dz-preview .dz-details .dz-size{flex:1}.dz-preview .dz-error-mark,.dz-preview .dz-success-mark,.dz-preview img{display:none}@-webkit-keyframes floatUp{0%{opacity:0;box-shadow:0 0 0 rgba(10,10,10,0),0 0 0 rgba(10,10,10,0),0 0 0 rgba(10,10,10,0);transform:scale(.86)}25%{opacity:1}67%{box-shadow:0 0 0 rgba(10,10,10,0),0 5px 10px rgba(10,10,10,.1),0 1px 1px rgba(10,10,10,.2);transform:scale(1)}to{box-shadow:0 20px 60px rgba(10,10,10,.05),0 5px 10px rgba(10,10,10,.1),0 1px 1px rgba(10,10,10,.2);transform:scale(1)}}@keyframes floatUp{0%{opacity:0;box-shadow:0 0 0 rgba(10,10,10,0),0 0 0 rgba(10,10,10,0),0 0 0 rgba(10,10,10,0);transform:scale(.86)}25%{opacity:1}67%{box-shadow:0 0 0 rgba(10,10,10,0),0 5px 10px rgba(10,10,10,.1),0 1px 1px rgba(10,10,10,.2);transform:scale(1)}to{box-shadow:0 20px 60px rgba(10,10,10,.05),0 5px 10px rgba(10,10,10,.1),0 1px 1px rgba(10,10,10,.2);transform:scale(1)}}.uploads>div{-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s;margin:1rem}.uploads>div:first-child{margin-top:1.5rem}.uploads.nojs{margin-bottom:0}.uploads .field>.icon:not(.icon-block){color:#3794d2}.uploads .field>.icon.icon-block{color:#da4453}.uploads progress{margin-top:.5rem;margin-bottom:1rem}.uploads img{max-width:200px}.name{font-size:1rem;color:#bdc3c7}.link>a,.name{word-break:break-all}.clipboard-mobile{margin-top:5px}#albumDiv{-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}#albumDiv .control{text-align:inherit}#linksColumn{margin-top:-.25rem;margin-left:-.25rem;margin-right:-.25rem;-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}#linksColumn .column{padding:.25rem}#linksColumn>span{padding:0 .3rem;color:#7f8c8d}.git-commit a{display:inline-block;word-break:break-all}#tabs{margin-bottom:1rem;-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}#tabs ul{border-bottom:1px solid #898b8d}#tabs li a{color:#bdc3c7;border-bottom-color:#898b8d}#tabs.is-boxed li.is-active a{color:#3794d2;background:#232629;border-color:#898b8d #898b8d #232629}#tabs.is-boxed li:not(.is-active) a:hover{background:#4d4d4d}.tab-content{margin-bottom:-.75rem;-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}.tab-content .label{color:#bdc3c7;font-weight:400}#tab-config.tab-content form{margin-bottom:.75rem}#urlMaxSize{font-weight:700}.render{position:fixed;right:0;bottom:0;font-size:1rem;color:#bdc3c7;cursor:pointer}.render.button{border-bottom-left-radius:0;border-bottom-right-radius:0;right:1%;opacity:.25;transition:opacity .25s}.render.button:hover{opacity:1} +/*# sourceMappingURL=home.css.map */ diff --git a/dist/css/home.css.map b/dist/css/home.css.map new file mode 100644 index 0000000..8803b5a --- /dev/null +++ b/dist/css/home.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["home.css"],"names":[],"mappings":"AAAA,GACE,WAAY,CACZ,YAAa,CACb,kBAAmB,CACnB,oBAAqB,CACrB,kBAAmB,CACnB,kBAAmB,CACnB,2BAAqB,CAArB,mBAAqB,CACrB,+BAAwB,CAAxB,uBAAwB,CACxB,gCAAyB,CAAzB,wBAAyB,CACzB,8BAAuB,CAAvB,sBAAuB,CACvB,2DAAyD,CAAzD,mDAAyD,CACzD,kGACF,CAEA,YACE,gBACF,CAEA,YACE,mBACF,CAEA,uBAEE,YACF,CAEA,SACE,cACF,CAEA,wBACE,YACF,CAEA,sEAEE,MACF,CAEA,wEAGE,YACF,CAEA,2BACE,GACE,SAAU,CACV,+EAA2F,CAC3F,oBACF,CAEA,IACE,SACF,CAEA,IACE,0FAAwG,CACxG,kBACF,CAEA,GACE,kGAAiH,CACjH,kBACF,CACF,CAEA,mBACE,GACE,SAAU,CACV,+EAA2F,CAC3F,oBACF,CAEA,IACE,SACF,CAEA,IACE,0FAAwG,CACxG,kBACF,CAEA,GACE,kGAAiH,CACjH,kBACF,CACF,CAEA,aACE,mCAA6B,CAA7B,2BAA6B,CAC7B,WACF,CAEA,yBACE,iBACF,CAEA,cACE,eACF,CAEA,uCACE,aACF,CAEA,iCACE,aACF,CAEA,kBACE,gBAAkB,CAClB,kBACF,CAEA,aACE,eACF,CAEA,MACE,cAAe,CACf,aAEF,CAEA,cAHE,oBAKF,CAEA,kBACE,cACF,CAEA,UACE,mCAA4B,CAA5B,2BACF,CAEA,mBACE,kBACF,CAEA,aACE,kBAAoB,CACpB,mBAAqB,CACrB,oBAAsB,CACtB,mCAA4B,CAA5B,2BACF,CAEA,qBACE,cACF,CAEA,kBACE,eAAiB,CACjB,aACF,CAEA,cACE,oBAAqB,CACrB,oBACF,CAEA,MACE,kBAAmB,CACnB,mCAA4B,CAA5B,2BACF,CAEA,SACE,+BACF,CAEA,WACE,aAAc,CACd,2BACF,CAEA,8BACE,aAAc,CACd,kBAAmB,CAEnB,oCACF,CAEA,0CACE,kBACF,CAEA,aACE,qBAAuB,CACvB,mCAA4B,CAA5B,2BACF,CAEA,oBACE,aAAc,CACd,eACF,CAEA,6BACE,oBACF,CAEA,YACE,eACF,CAEA,QACE,cAAe,CACf,OAAQ,CACR,QAAS,CACT,cAAe,CACf,aAAc,CACd,cACF,CAEA,eACE,2BAA4B,CAC5B,4BAA6B,CAC7B,QAAS,CACT,WAAa,CACb,uBACF,CAEA,qBACE,SACF","file":"home.css","sourcesContent":["#b {\n width: 200px;\n height: 200px;\n border-radius: 100%;\n display: inline-block;\n margin-bottom: 40px;\n vertical-align: top;\n animation-delay: 0.5s;\n animation-duration: 1.5s;\n animation-fill-mode: both;\n animation-name: floatUp;\n animation-timing-function: cubic-bezier(0, 0.71, 0.29, 1);\n box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2)\n}\n\n#b img.logo {\n max-height: 200px\n}\n\n#dropzone * {\n pointer-events: none\n}\n\n#tokenContainer,\n#panel {\n display: none\n}\n\n#maxSize {\n font-size: 1rem\n}\n\n.dz-preview .dz-details {\n display: flex\n}\n\n.dz-preview .dz-details .dz-size,\n.dz-preview .dz-details .dz-filename {\n flex: 1\n}\n\n.dz-preview img,\n.dz-preview .dz-success-mark,\n.dz-preview .dz-error-mark {\n display: none\n}\n\n@-webkit-keyframes floatUp {\n 0% {\n opacity: 0;\n box-shadow: 0 0 0 rgba(10, 10, 10, 0), 0 0 0 rgba(10, 10, 10, 0), 0 0 0 rgba(10, 10, 10, 0);\n transform: scale(0.86)\n }\n\n 25% {\n opacity: 100\n }\n\n 67% {\n box-shadow: 0 0 0 rgba(10, 10, 10, 0), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2);\n transform: scale(1)\n }\n\n 100% {\n box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2);\n transform: scale(1)\n }\n}\n\n@keyframes floatUp {\n 0% {\n opacity: 0;\n box-shadow: 0 0 0 rgba(10, 10, 10, 0), 0 0 0 rgba(10, 10, 10, 0), 0 0 0 rgba(10, 10, 10, 0);\n transform: scale(0.86)\n }\n\n 25% {\n opacity: 100\n }\n\n 67% {\n box-shadow: 0 0 0 rgba(10, 10, 10, 0), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2);\n transform: scale(1)\n }\n\n 100% {\n box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2);\n transform: scale(1)\n }\n}\n\n.uploads > div {\n animation: fadeInOpacity 0.5s;\n margin: 1rem\n}\n\n.uploads > div:first-child {\n margin-top: 1.5rem\n}\n\n.uploads.nojs {\n margin-bottom: 0\n}\n\n.uploads .field > .icon:not(.icon-block) {\n color: #3794d2\n}\n\n.uploads .field > .icon.icon-block {\n color: #da4453\n}\n\n.uploads progress {\n margin-top: 0.5rem;\n margin-bottom: 1rem\n}\n\n.uploads img {\n max-width: 200px\n}\n\n.name {\n font-size: 1rem;\n color: #bdc3c7;\n word-break: break-all\n}\n\n.link > a {\n word-break: break-all\n}\n\n.clipboard-mobile {\n margin-top: 5px\n}\n\n#albumDiv {\n animation: fadeInOpacity 0.5s\n}\n\n#albumDiv .control {\n text-align: inherit\n}\n\n#linksColumn {\n margin-top: -0.25rem;\n margin-left: -0.25rem;\n margin-right: -0.25rem;\n animation: fadeInOpacity 0.5s\n}\n\n#linksColumn .column {\n padding: 0.25rem\n}\n\n#linksColumn > span {\n padding: 0 0.3rem;\n color: #7f8c8d\n}\n\n.git-commit a {\n display: inline-block;\n word-break: break-all\n}\n\n#tabs {\n margin-bottom: 1rem;\n animation: fadeInOpacity 0.5s\n}\n\n#tabs ul {\n border-bottom: 1px solid #898b8d\n}\n\n#tabs li a {\n color: #bdc3c7;\n border-bottom-color: #898b8d\n}\n\n#tabs.is-boxed li.is-active a {\n color: #3794d2;\n background: #232629;\n border-color: #898b8d;\n border-bottom-color: #232629\n}\n\n#tabs.is-boxed li:not(.is-active) a:hover {\n background: #4d4d4d\n}\n\n.tab-content {\n margin-bottom: -0.75rem;\n animation: fadeInOpacity 0.5s\n}\n\n.tab-content .label {\n color: #bdc3c7;\n font-weight: normal\n}\n\n#tab-config.tab-content form {\n margin-bottom: 0.75rem\n}\n\n#urlMaxSize {\n font-weight: bold\n}\n\n.render {\n position: fixed;\n right: 0;\n bottom: 0;\n font-size: 1rem;\n color: #bdc3c7;\n cursor: pointer\n}\n\n.render.button {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n right: 1%;\n opacity: 0.25;\n transition: opacity 0.25s\n}\n\n.render.button:hover {\n opacity: 1\n}\n"]} \ No newline at end of file diff --git a/dist/css/style.css b/dist/css/style.css new file mode 100644 index 0000000..951d26e --- /dev/null +++ b/dist/css/style.css @@ -0,0 +1,2 @@ +html{background-color:#232629;overflow-y:auto}body{color:#eff0f1;-webkit-animation:fadeInOpacity .5s;animation:fadeInOpacity .5s}@-webkit-keyframes fadeInOpacity{0%{opacity:0}to{opacity:1}}@keyframes fadeInOpacity{0%{opacity:0}to{opacity:1}}a{color:#3794d2}a:hover{color:#60a8dc}hr{background-color:#898b8d}.message-body code,code{background-color:#222528;border-radius:5px}.title{color:#eff0f1}.subtitle,.subtitle strong{color:#bdc3c7}.input::-moz-placeholder,.textarea::-moz-placeholder{color:#7f8c8d}.input::-webkit-input-placeholder,.textarea::-webkit-input-placeholder{color:#7f8c8d}.input:-moz-placeholder,.textarea:-moz-placeholder{color:#7f8c8d}.input:-ms-input-placeholder,.textarea:-ms-input-placeholder{color:#7f8c8d}.input.is-active,.input.is-focused,.input:active,.input:focus,.textarea.is-active,.textarea.is-focused,.textarea:active,.textarea:focus{border-color:#3794d2}.table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#4d4d4d}.table td,.table th{vertical-align:middle}.help{color:#7f8c8d}.button.is-info.is-hovered [class*=" icon-"]:before,.button.is-info.is-hovered [class^=icon-]:before,.button.is-info:hover [class*=" icon-"]:before,.button.is-info:hover [class^=icon-]:before{fill:#fff}.checkbox:hover,.radio:hover{color:#7f8c8d}.message{background-color:#31363b}.message-body{color:#eff0f1;border:0;box-shadow:0 20px 60px rgba(10,10,10,.05),0 5px 10px rgba(10,10,10,.1),0 1px 1px rgba(10,10,10,.2)}.menu-list a.is-loading:after{-webkit-animation:spinAround .5s linear infinite;animation:spinAround .5s linear infinite;border-radius:290486px;border-color:transparent transparent #dbdbdb #dbdbdb;border-style:solid;border-width:2px;content:"";display:block;height:1em;width:1em;right:.5em;top:calc(50% - .5em);position:absolute!important} +/*# sourceMappingURL=style.css.map */ diff --git a/dist/css/style.css.map b/dist/css/style.css.map new file mode 100644 index 0000000..e9bfe13 --- /dev/null +++ b/dist/css/style.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["style.css"],"names":[],"mappings":"AAAA,KACE,wBAAyB,CACzB,eACF,CAEA,KACE,aAAc,CACd,mCAA4B,CAA5B,2BACF,CAEA,iCACE,GACE,SACF,CAEA,GACE,SACF,CACF,CAEA,yBACE,GACE,SACF,CAEA,GACE,SACF,CACF,CAEA,EACE,aACF,CAEA,QACE,aACF,CAEA,GACE,wBACF,CAEA,wBAEE,wBAAyB,CACzB,iBACF,CAEA,OACE,aACF,CAMA,2BACE,aACF,CAEA,qDAEE,aACF,CAEA,uEAEE,aACF,CAEA,mDAEE,aACF,CAEA,6DAEE,aACF,CAEA,wIAQE,oBACF,CAEA,qDACE,wBACF,CAEA,oBAEE,qBACF,CAEA,MACE,aACF,CAEA,gMAIE,SACF,CAEA,6BAEE,aACF,CAEA,SACE,wBACF,CAEA,cACE,aAAc,CACd,QAAS,CACT,kGACF,CAEA,8BACE,gDAA0C,CAA1C,wCAA0C,CAE1C,sBAAuB,CAEvB,oDAA6B,CAA7B,kBAA6B,CAA7B,gBAA6B,CAC7B,UAAW,CACX,aAAc,CACd,UAAW,CACX,SAAU,CACV,UAA2B,CAC3B,oBAA0B,CAC1B,2BACF","file":"style.css","sourcesContent":["html {\n background-color: #232629;\n overflow-y: auto\n}\n\nbody {\n color: #eff0f1;\n animation: fadeInOpacity 0.5s\n}\n\n@-webkit-keyframes fadeInOpacity {\n 0% {\n opacity: 0\n }\n\n 100% {\n opacity: 1\n }\n}\n\n@keyframes fadeInOpacity {\n 0% {\n opacity: 0\n }\n\n 100% {\n opacity: 1\n }\n}\n\na {\n color: #3794d2\n}\n\na:hover {\n color: #60a8dc\n}\n\nhr {\n background-color: #898b8d\n}\n\ncode,\n.message-body code {\n background-color: #222528;\n border-radius: 5px\n}\n\n.title {\n color: #eff0f1\n}\n\n.subtitle {\n color: #bdc3c7\n}\n\n.subtitle strong {\n color: #bdc3c7\n}\n\n.input::-moz-placeholder,\n.textarea::-moz-placeholder {\n color: #7f8c8d\n}\n\n.input::-webkit-input-placeholder,\n.textarea::-webkit-input-placeholder {\n color: #7f8c8d\n}\n\n.input:-moz-placeholder,\n.textarea:-moz-placeholder {\n color: #7f8c8d\n}\n\n.input:-ms-input-placeholder,\n.textarea:-ms-input-placeholder {\n color: #7f8c8d\n}\n\n.input.is-active,\n.input.is-focused,\n.input:active,\n.input:focus,\n.textarea.is-active,\n.textarea.is-focused,\n.textarea:active,\n.textarea:focus {\n border-color: #3794d2\n}\n\n.table.is-hoverable tbody tr:not(.is-selected):hover {\n background-color: #4d4d4d\n}\n\n.table td,\n.table th {\n vertical-align: middle\n}\n\n.help {\n color: #7f8c8d\n}\n\n.button.is-info.is-hovered [class^=\"icon-\"]::before,\n.button.is-info.is-hovered [class*=\" icon-\"]::before,\n.button.is-info:hover [class^=\"icon-\"]::before,\n.button.is-info:hover [class*=\" icon-\"]::before {\n fill: #fff\n}\n\n.checkbox:hover,\n.radio:hover {\n color: #7f8c8d\n}\n\n.message {\n background-color: #31363b\n}\n\n.message-body {\n color: #eff0f1;\n border: 0;\n box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2)\n}\n\n.menu-list a.is-loading::after {\n animation: spinAround 0.5s infinite linear;\n border: 2px solid #dbdbdb;\n border-radius: 290486px;\n border-right-color: transparent;\n border-top-color: transparent;\n content: \"\";\n display: block;\n height: 1em;\n width: 1em;\n right: calc(0% + (1em / 2));\n top: calc(50% - (1em / 2));\n position: absolute !important\n}\n"]} \ No newline at end of file diff --git a/dist/css/sweetalert.css b/dist/css/sweetalert.css new file mode 100644 index 0000000..4aed0f0 --- /dev/null +++ b/dist/css/sweetalert.css @@ -0,0 +1,2 @@ +.swal-modal{background-color:#31363b}.swal-modal .field{text-align:left;text-align:initial}.swal-modal.is-expanded{width:auto;max-width:90%}.swal-text,.swal-title{color:#eff0f1}.swal-text{text-align:center}.swal-content .checkbox,.swal-content .label,.swal-content .radio{color:#eff0f1}.swal-content .checkbox:hover,.swal-content .radio:hover{color:#bdc3c7}.swal-button{background-color:#3794d2;color:#eff0f1}.swal-button:hover{background-color:#60a8dc}.swal-button:focus{box-shadow:0 0 0 1px #31363b,0 0 0 3px rgba(55,148,210,.29)}.swal-button--loading{color:transparent}.swal-button--danger{background-color:#da4453}.swal-icon--info{border-color:#3794d2}.swal-icon--info:after,.swal-icon--info:before{background-color:#3794d2}.swal-icon--error{border-color:#da4453}.swal-icon--error__line{background-color:#da4453}.swal-icon--warning{border-color:#f67400;-webkit-animation:pulseWarning .5s infinite alternate;animation:pulseWarning .5s infinite alternate}.swal-icon--warning__body,.swal-icon--warning__dot{background-color:#f67400;-webkit-animation:pulseWarningBody .5s infinite alternate;animation:pulseWarningBody .5s infinite alternate}@-webkit-keyframes pulseWarning{0%{border-color:#ffaa60}to{border-color:#f67400}}@keyframes pulseWarning{0%{border-color:#ffaa60}to{border-color:#f67400}}@-webkit-keyframes pulseWarningBody{0%{background-color:#ffaa60}to{background-color:#f67400}}@keyframes pulseWarningBody{0%{background-color:#ffaa60}to{background-color:#f67400}}.swal-icon--success{border-color:#27ae60}.swal-icon--success__line{background-color:#27ae60}.swal-icon--success__hide-corners{background-color:#31363b}.swal-icon--success:after,.swal-icon--success:before{background:#31363b}.swal-display-thumb-container{min-width:200px;min-height:200px;display:flex;align-items:center;justify-content:center} +/*# sourceMappingURL=sweetalert.css.map */ diff --git a/dist/css/sweetalert.css.map b/dist/css/sweetalert.css.map new file mode 100644 index 0000000..140afb0 --- /dev/null +++ b/dist/css/sweetalert.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["sweetalert.css"],"names":[],"mappings":"AAAA,YACE,wBACF,CAEA,mBACE,eAAkB,CAAlB,kBACF,CAEA,wBACE,UAAW,CACX,aACF,CAEA,uBAEE,aACF,CAEA,WACE,iBACF,CAEA,kEAGE,aACF,CAEA,yDAEE,aACF,CAEA,aACE,wBAAyB,CACzB,aACF,CAEA,mBACE,wBACF,CAEA,mBACE,2DACF,CAEA,sBACE,iBACF,CAEA,qBACE,wBACF,CAEA,iBACE,oBACF,CAEA,+CAEE,wBACF,CAEA,kBACE,oBACF,CAEA,wBACE,wBACF,CAEA,oBACE,oBAAqB,CACrB,qDAA8C,CAA9C,6CACF,CAEA,mDAEE,wBAAyB,CACzB,yDAAkD,CAAlD,iDACF,CAEA,gCACE,GACE,oBACF,CAEA,GACE,oBACF,CACF,CAEA,wBACE,GACE,oBACF,CAEA,GACE,oBACF,CACF,CAEA,oCACE,GACE,wBACF,CAEA,GACE,wBACF,CACF,CAEA,4BACE,GACE,wBACF,CAEA,GACE,wBACF,CACF,CAEA,oBACE,oBACF,CAEA,0BACE,wBACF,CAEA,kCACE,wBACF,CAEA,qDAEE,kBACF,CAEA,8BACE,eAAgB,CAChB,gBAAiB,CACjB,YAAa,CACb,kBAAmB,CACnB,sBACF","file":"sweetalert.css","sourcesContent":[".swal-modal {\n background-color: #31363b\n}\n\n.swal-modal .field {\n text-align: initial\n}\n\n.swal-modal.is-expanded {\n width: auto;\n max-width: 90%\n}\n\n.swal-title,\n.swal-text {\n color: #eff0f1\n}\n\n.swal-text {\n text-align: center\n}\n\n.swal-content .label,\n.swal-content .checkbox,\n.swal-content .radio {\n color: #eff0f1\n}\n\n.swal-content .checkbox:hover,\n.swal-content .radio:hover {\n color: #bdc3c7\n}\n\n.swal-button {\n background-color: #3794d2;\n color: #eff0f1\n}\n\n.swal-button:hover {\n background-color: #60a8dc\n}\n\n.swal-button:focus {\n box-shadow: 0 0 0 1px #31363b, 0 0 0 3px rgba(55, 148, 210, 0.29)\n}\n\n.swal-button--loading {\n color: transparent\n}\n\n.swal-button--danger {\n background-color: #da4453\n}\n\n.swal-icon--info {\n border-color: #3794d2\n}\n\n.swal-icon--info::after,\n.swal-icon--info::before {\n background-color: #3794d2\n}\n\n.swal-icon--error {\n border-color: #da4453\n}\n\n.swal-icon--error__line {\n background-color: #da4453\n}\n\n.swal-icon--warning {\n border-color: #f67400;\n animation: pulseWarning 0.5s infinite alternate\n}\n\n.swal-icon--warning__body,\n.swal-icon--warning__dot {\n background-color: #f67400;\n animation: pulseWarningBody 0.5s infinite alternate\n}\n\n@-webkit-keyframes pulseWarning {\n 0% {\n border-color: #ffaa60\n }\n\n to {\n border-color: #f67400\n }\n}\n\n@keyframes pulseWarning {\n 0% {\n border-color: #ffaa60\n }\n\n to {\n border-color: #f67400\n }\n}\n\n@-webkit-keyframes pulseWarningBody {\n 0% {\n background-color: #ffaa60\n }\n\n to {\n background-color: #f67400\n }\n}\n\n@keyframes pulseWarningBody {\n 0% {\n background-color: #ffaa60\n }\n\n to {\n background-color: #f67400\n }\n}\n\n.swal-icon--success {\n border-color: #27ae60\n}\n\n.swal-icon--success__line {\n background-color: #27ae60\n}\n\n.swal-icon--success__hide-corners {\n background-color: #31363b\n}\n\n.swal-icon--success::after,\n.swal-icon--success::before {\n background: #31363b\n}\n\n.swal-display-thumb-container {\n min-width: 200px;\n min-height: 200px;\n display: flex;\n align-items: center;\n justify-content: center\n}\n"]} \ No newline at end of file diff --git a/dist/css/thumbs.css b/dist/css/thumbs.css new file mode 100644 index 0000000..f898a0f --- /dev/null +++ b/dist/css/thumbs.css @@ -0,0 +1,2 @@ +.image-container{display:flex;width:200px;height:200px;margin:9px;background-color:#31363b;overflow:hidden;align-items:center;box-shadow:0 20px 60px rgba(10,10,10,.05),0 5px 10px rgba(10,10,10,.1),0 1px 1px rgba(10,10,10,.2)}.image-container .title{font-weight:400;word-break:break-all}.image-container .image{display:flex;height:100%;width:100%;align-items:center;justify-content:center}.image-container .image img{max-height:100%;max-width:100%;height:auto;width:auto}.image-container .controls{display:flex;position:absolute;top:.75rem;right:.75rem}.image-container .controls .button{border-radius:0}.image-container .controls .button:not(:active):not(:hover){color:#fff;background-color:rgba(49,54,59,.75)}.image-container .details{position:absolute;left:.75rem;bottom:.75rem;right:.75rem;background-color:rgba(49,54,59,.75);color:#eff0f1;padding:.25rem;font-size:.75rem}.image-container .details p{display:block;text-overflow:ellipsis;overflow:hidden}.image-container .details p span{font-weight:700} +/*# sourceMappingURL=thumbs.css.map */ diff --git a/dist/css/thumbs.css.map b/dist/css/thumbs.css.map new file mode 100644 index 0000000..d782592 --- /dev/null +++ b/dist/css/thumbs.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["thumbs.css"],"names":[],"mappings":"AAAA,iBACE,YAAa,CACb,WAAY,CACZ,YAAa,CACb,UAAW,CACX,wBAAyB,CACzB,eAAgB,CAChB,kBAAmB,CACnB,kGACF,CAEA,wBACE,eAAmB,CACnB,oBACF,CAEA,wBACE,YAAa,CACb,WAAY,CACZ,UAAW,CACX,kBAAmB,CACnB,sBACF,CAEA,4BACE,eAAgB,CAChB,cAAe,CACf,WAAY,CACZ,UACF,CAEA,2BACE,YAAa,CACb,iBAAkB,CAClB,UAAY,CACZ,YACF,CAEA,mCACE,eACF,CAEA,4DACE,UAAW,CACX,mCACF,CAEA,0BACE,iBAAkB,CAClB,WAAa,CACb,aAAe,CACf,YAAc,CACd,mCAAwC,CACxC,aAAc,CACd,cAAgB,CAChB,gBACF,CAEA,4BACE,aAAc,CACd,sBAAuB,CACvB,eACF,CAEA,iCACE,eACF","file":"thumbs.css","sourcesContent":[".image-container {\n display: flex;\n width: 200px;\n height: 200px;\n margin: 9px;\n background-color: #31363b;\n overflow: hidden;\n align-items: center;\n box-shadow: 0 20px 60px rgba(10, 10, 10, 0.05), 0 5px 10px rgba(10, 10, 10, 0.1), 0 1px 1px rgba(10, 10, 10, 0.2)\n}\n\n.image-container .title {\n font-weight: normal;\n word-break: break-all\n}\n\n.image-container .image {\n display: flex;\n height: 100%;\n width: 100%;\n align-items: center;\n justify-content: center\n}\n\n.image-container .image img {\n max-height: 100%;\n max-width: 100%;\n height: auto;\n width: auto\n}\n\n.image-container .controls {\n display: flex;\n position: absolute;\n top: 0.75rem;\n right: 0.75rem\n}\n\n.image-container .controls .button {\n border-radius: 0\n}\n\n.image-container .controls .button:not(:active):not(:hover) {\n color: #fff;\n background-color: rgba(49, 54, 59, 0.75)\n}\n\n.image-container .details {\n position: absolute;\n left: 0.75rem;\n bottom: 0.75rem;\n right: 0.75rem;\n background-color: rgba(49, 54, 59, 0.75);\n color: #eff0f1;\n padding: 0.25rem;\n font-size: 0.75rem\n}\n\n.image-container .details p {\n display: block;\n text-overflow: ellipsis;\n overflow: hidden\n}\n\n.image-container .details p span {\n font-weight: bold\n}\n"]} \ No newline at end of file diff --git a/dist/js/album.js b/dist/js/album.js new file mode 100644 index 0000000..3b104f2 --- /dev/null +++ b/dist/js/album.js @@ -0,0 +1,2 @@ +var lsKeys={},page={lazyLoad:null};window.onload=function(){for(var e=document.querySelectorAll(".file-size"),a=0;a {\n const elements = document.querySelectorAll('.file-size')\n for (let i = 0; i < elements.length; i++)\n elements[i].innerHTML = page.getPrettyBytes(parseInt(elements[i].innerHTML.replace(/\\s*B$/i, '')))\n\n page.lazyLoad = new LazyLoad()\n}\n"]} \ No newline at end of file diff --git a/dist/js/auth.js b/dist/js/auth.js new file mode 100644 index 0000000..755f70e --- /dev/null +++ b/dist/js/auth.js @@ -0,0 +1,2 @@ +var lsKeys={token:"token"},page={token:localStorage[lsKeys.token],user:null,pass:null,do:function(e,r){var o=page.user.value.trim();if(!o)return swal("An error occurred!","You need to specify a username.","error");var t=page.pass.value.trim();if(!t)return swal("An error occurred!","You need to specify a password.","error");r.classList.add("is-loading"),axios.post("api/"+e,{username:o,password:t}).then((function(o){if(!1===o.data.success)return r.classList.remove("is-loading"),swal("Unable to "+e+"!",o.data.description,"error");localStorage.token=o.data.token,window.location="dashboard"})).catch((function(e){return console.error(e),r.classList.remove("is-loading"),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))},verify:function(){page.token&&axios.post("api/tokens/verify",{token:page.token}).then((function(e){if(!1===e.data.success)return swal("An error occurred!",e.data.description,"error");window.location="dashboard"})).catch((function(e){console.error(e);var r=e.response.data&&e.response.data.description?e.response.data.description:"There was an error with the request, please check the console for more information.";return swal(e.response.status+" "+e.response.statusText,r,"error")}))}};window.onload=function(){page.verify(),page.user=document.querySelector("#user"),page.pass=document.querySelector("#pass"),document.querySelector("#authForm").addEventListener("submit",(function(e){e.preventDefault()})),document.querySelector("#loginBtn").addEventListener("click",(function(e){page.do("login",e.currentTarget)})),document.querySelector("#registerBtn").addEventListener("click",(function(e){page.do("register",e.currentTarget)}))}; +//# sourceMappingURL=auth.js.map diff --git a/dist/js/auth.js.map b/dist/js/auth.js.map new file mode 100644 index 0000000..c650109 --- /dev/null +++ b/dist/js/auth.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["auth.js"],"names":["const","lsKeys","token","page","localStorage","user","pass","do","dest","trigger","value","trim","swal","classList","add","axios","post","username","password","then","response","data","success","remove","description","window","location","catch","error","console","verify","onload","document","querySelector","addEventListener","event","preventDefault","currentTarget"],"mappings":"AAEAA,IAAMC,OAAS,CACbC,MAAO,SAGHC,KAAO,CAEXD,MAAOE,aAAaH,OAAOC,OAG3BG,KAAM,KACNC,KAAM,KAGRC,GAAO,SAAIC,EAAMC,GACfT,IAAMK,EAAOF,KAAKE,KAAKK,MAAMC,OAC7B,IAAKN,EACH,OAAOO,KAAK,qBAAsB,kCAAmC,SAEvEZ,IAAMM,EAAOH,KAAKG,KAAKI,MAAMC,OAC7B,IAAKL,EACH,OAAOM,KAAK,qBAAsB,kCAAmC,SAEvEH,EAAQI,UAAUC,IAAI,cACtBC,MAAMC,KAAK,OAAOR,EAAQ,CACxBS,SAAUZ,EACVa,SAAUZ,IACTa,MAAI,SAACC,GACN,IAA8B,IAA1BA,EAASC,KAAKC,QAEhB,OADAb,EAAQI,UAAUU,OAAO,cAClBX,KAAK,aAAaJ,EAAI,IAAKY,EAASC,KAAKG,YAAa,SAG/DpB,aAAaF,MAAQkB,EAASC,KAAKnB,MACnCuB,OAAOC,SAAW,eACjBC,OAAK,SAACC,GAGP,OAFAC,QAAQD,MAAMA,GACdnB,EAAQI,UAAUU,OAAO,cAClBX,KAAK,qBAAsB,sFAAuF,aAI7HkB,OAAW,WACJ3B,KAAKD,OAEVa,MAAMC,KAAK,oBAAqB,CAC9Bd,MAAOC,KAAKD,QACXiB,MAAI,SAACC,GACN,IAA8B,IAA1BA,EAASC,KAAKC,QAChB,OAAOV,KAAK,qBAAsBQ,EAASC,KAAKG,YAAa,SAE/DC,OAAOC,SAAW,eACjBC,OAAK,SAACC,GACPC,QAAQD,MAAMA,GACd5B,IAAMwB,EAAcI,EAAMR,SAASC,MAAQO,EAAMR,SAASC,KAAKG,YAC3DI,EAAMR,SAASC,KAAKG,YACpB,sFACJ,OAAOZ,KAAQgB,EAAMR,SAAS,OAAM,IAAIQ,EAAMR,SAAmB,WAAII,EAAa,cAItFC,OAAOM,OAAM,WACX5B,KAAK2B,SAEL3B,KAAKE,KAAO2B,SAASC,cAAc,SACnC9B,KAAKG,KAAO0B,SAASC,cAAc,SAGnCD,SAASC,cAAc,aAAaC,iBAAiB,UAAQ,SAAEC,GAC7DA,EAAMC,oBAGRJ,SAASC,cAAc,aAAaC,iBAAiB,SAAO,SAAEC,GAC5DhC,KAAKI,GAAG,QAAS4B,EAAME,kBAGzBL,SAASC,cAAc,gBAAgBC,iBAAiB,SAAO,SAAEC,GAC/DhC,KAAKI,GAAG,WAAY4B,EAAME","file":"auth.js","sourcesContent":["/* global swal, axios */\n\nconst lsKeys = {\n token: 'token'\n}\n\nconst page = {\n // user token\n token: localStorage[lsKeys.token],\n\n // HTML elements\n user: null,\n pass: null\n}\n\npage.do = (dest, trigger) => {\n const user = page.user.value.trim()\n if (!user)\n return swal('An error occurred!', 'You need to specify a username.', 'error')\n\n const pass = page.pass.value.trim()\n if (!pass)\n return swal('An error occurred!', 'You need to specify a password.', 'error')\n\n trigger.classList.add('is-loading')\n axios.post(`api/${dest}`, {\n username: user,\n password: pass\n }).then(response => {\n if (response.data.success === false) {\n trigger.classList.remove('is-loading')\n return swal(`Unable to ${dest}!`, response.data.description, 'error')\n }\n\n localStorage.token = response.data.token\n window.location = 'dashboard'\n }).catch(error => {\n console.error(error)\n trigger.classList.remove('is-loading')\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.verify = () => {\n if (!page.token) return\n\n axios.post('api/tokens/verify', {\n token: page.token\n }).then(response => {\n if (response.data.success === false)\n return swal('An error occurred!', response.data.description, 'error')\n\n window.location = 'dashboard'\n }).catch(error => {\n console.error(error)\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 return swal(`${error.response.status} ${error.response.statusText}`, description, 'error')\n })\n}\n\nwindow.onload = () => {\n page.verify()\n\n page.user = document.querySelector('#user')\n page.pass = document.querySelector('#pass')\n\n // Prevent default form's submit action\n document.querySelector('#authForm').addEventListener('submit', event => {\n event.preventDefault()\n })\n\n document.querySelector('#loginBtn').addEventListener('click', event => {\n page.do('login', event.currentTarget)\n })\n\n document.querySelector('#registerBtn').addEventListener('click', event => {\n page.do('register', event.currentTarget)\n })\n}\n"]} \ No newline at end of file diff --git a/dist/js/dashboard.js b/dist/js/dashboard.js new file mode 100644 index 0000000..a252db9 --- /dev/null +++ b/dist/js/dashboard.js @@ -0,0 +1,2 @@ +var lsKeys={token:"token",viewType:{uploads:"viewTypeUploads",uploadsAll:"viewTypeUploadsAll"},selected:{uploads:"selectedUploads",uploadsAll:"selectedUploadsAll",users:"selectedUsers"}},page={dom:null,token:localStorage[lsKeys.token],username:null,permissions:null,menusContainer:null,menus:[],currentView:null,views:{uploads:{type:localStorage[lsKeys.viewType.uploads],album:null,pageNum:null},uploadsAll:{type:localStorage[lsKeys.viewType.uploadsAll],filters:null,pageNum:null,all:!0},users:{pageNum:null}},selected:{uploads:[],uploadsAll:[],users:[]},checkboxes:{uploads:[],uploadsAll:[],users:[]},lastSelected:{upload:null,uploadsAll:null,user:null},selectAlbumContainer:null,cache:{uploads:{},albums:{},users:{}},clipboardJS:null,lazyLoad:null,imageExts:[".webp",".jpg",".jpeg",".gif",".png",".tiff",".tif",".svg"],videoExts:[".webm",".mp4",".wmv",".avi",".mov",".mkv"],isTriggerLoading:null,fadingIn:null,preparePage:function(){page.token?page.verifyToken(page.token,!0):window.location="auth"},verifyToken:function(e,a){axios.post("api/tokens/verify",{token:e}).then((function(n){if(!1===n.data.success)return swal({title:"An error occurred!",text:n.data.description,icon:"error"}).then((function(){a&&(localStorage.removeItem(lsKeys.token),window.location="auth")}));axios.defaults.headers.common.token=e,localStorage[lsKeys.token]=e,page.token=e,page.username=n.data.username,page.permissions=n.data.permissions,page.prepareDashboard()})).catch((function(e){return console.error(e),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))},prepareDashboard:function(){page.dom=document.querySelector("#page"),page.dom.addEventListener("click",page.domClick,!0),page.dom.addEventListener("submit",(function(e){if(e.target&&e.target.classList.contains("prevent-default"))return e.preventDefault()}),!0),page.menusContainer=document.querySelector("#menu");for(var e=[{selector:"#itemUploads",onclick:page.getUploads},{selector:"#itemDeleteUploadsByNames",onclick:page.deleteUploadsByNames},{selector:"#itemManageAlbums",onclick:page.getAlbums},{selector:"#itemManageToken",onclick:page.changeToken},{selector:"#itemChangePassword",onclick:page.changePassword},{selector:"#itemLogout",onclick:page.logout,inactive:!0},{selector:"#itemManageUploads",onclick:page.getUploads,params:{all:!0},group:"moderator"},{selector:"#itemStatistics",onclick:page.getStatistics,group:"admin"},{selector:"#itemManageUsers",onclick:page.getUsers,group:"admin"}],a=function(a){if(!e[a].group||page.permissions[e[a].group]){var n=document.querySelector(e[a].selector);n.addEventListener("click",(function(n){page.menusContainer.classList.contains("is-loading")||e[a].onclick.call(null,Object.assign({trigger:n.currentTarget},e[a].params||{}))})),n.classList.remove("is-hidden"),page.menus.push(n)}},n=0;n';e.all&&(l='\n
\n
\n
\n
\n \n
\n
\n \n
\n
\n \n
\n
\n
\n
\n ');for(var o='\n
\n '+l+'\n
\n
\n
\n
\n \n
\n
\n \n
\n
\n
\n
\n
\n ',c='\n
\n
\n \n \n
\n ',d=!1,u=n.some((function(e){return void 0!==e.expirydate})),p=0;p\n \n
\n '+i+"\n ";for(var g=document.querySelector("#table"),m=0;m'+h.name+'':b.innerHTML='

'+(h.extname||"N/A")+"

",b.innerHTML+='\n \n
\n '+(h.thumb?'\n \n \n \n \n ':"")+'\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n
\n

'+h.name+"

\n

"+(h.appendix?""+h.appendix+" – ":"")+h.prettyBytes+"

\n
\n ",g.appendChild(b),page.checkboxes[page.currentView]=g.querySelectorAll('.checkbox[data-action="select"]'),page.lazyLoad.update()}}else{page.dom.innerHTML="\n "+i+"\n "+o+"\n "+c+'\n
\n \n \n \n \n \n '+(void 0===e.album?"":"")+"\n \n "+(e.all?"":"")+"\n \n "+(u?"":"")+'\n \n \n \n \n \n
File"+(e.all?"User":"Album")+"SizeIPDateExpiry date
\n
\n
\n '+i+"\n ";for(var f=document.querySelector("#table"),v=0;v\n '+w.name+"\n "+(w.appendix?""+w.appendix+"":"")+"\n "+w.prettyBytes+"\n "+(e.all?""+(w.ip||"")+"":"")+"\n "+w.prettyDate+"\n "+(u?""+w.prettyExpiryDate+"":"")+'\n \n \n \n \n \n \n \n \n \n \n \n '+(e.all?"":'\n \n \n \n \n ')+'\n \n \n \n \n \n \n ',f.appendChild(y),page.checkboxes[page.currentView]=f.querySelectorAll('.checkbox[data-action="select"]')}}var k=document.querySelector("#selectAll");k&&!d&&(k.checked=!0,k.title="Unselect all"),page.fadeAndScroll(),page.updateTrigger(e.trigger,"active"),"uploads"===page.currentView&&(page.views.uploads.album=e.album),"uploadsAll"===page.currentView&&(page.views.uploadsAll.filters=e.filters),page.views[page.currentView].pageNum=n.length?e.pageNum:0})).catch((function(a){return console.error(a),page.updateTrigger(e.trigger),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))},setUploadsView:function(e,a){localStorage[lsKeys.viewType[page.currentView]]=e,page.views[page.currentView].type=e,page.getUploads(Object.assign({trigger:a},page.views[page.currentView]))},displayThumbnail:function(e){var a=page.cache.uploads[e];if(a.thumb){var n=document.createElement("div");if(n.innerHTML='\n
\n \n
\n \n
\n
\n ',a.original){var t=/.[\w]+(\?|$)/.exec(a.original),s=t&&t[0]?t[0].toLowerCase():null,r=page.imageExts.includes(s),i=!r&&page.videoExts.includes(s);(r||i)&&(n.innerHTML+='\n \n ',n.querySelector("#swalOriginal").addEventListener("click",(function(e){var t=e.currentTarget;if(!t.classList.contains("is-danger")){t.classList.add("is-loading");var s=n.querySelector("#swalThumb");if(r)s.src=a.original,s.onload=function(){t.classList.add("is-hidden"),document.body.querySelector(".swal-overlay .swal-modal:not(.is-expanded)").classList.add("is-expanded")},s.onerror=function(e){e.currentTarget.classList.add("is-hidden"),t.className="button is-danger is-fullwidth",t.innerHTML='\n \n \n \n Unable to load original\n '};else if(i){s.classList.add("is-hidden");var l=document.createElement("video");l.id="swalVideo",l.controls=!0,l.autoplay=!0,l.src=a.original,s.insertAdjacentElement("afterend",l),t.classList.add("is-hidden"),document.body.querySelector(".swal-overlay .swal-modal:not(.is-expanded)").classList.add("is-expanded")}}})))}return swal({content:n,buttons:!1}).then((function(){var e=n.querySelector("#swalVideo");e&&e.remove(),document.body.querySelector(".swal-overlay .swal-modal").classList.remove("is-expanded")}))}},selectAll:function(e){for(var a=0;at&&s>t&&sn&&s"),swal({content:a})},filterUploads:function(e){var a=document.querySelector("#filters").value;page.getUploads({all:!0,filters:a},e)},viewUserUploads:function(e,a){var n=page.cache.users[e];n&&(a.classList.add("is-loading"),page.getUploads({all:!0,filters:"user:"+n.username.replace(/ /g,"\\ "),trigger:document.querySelector("#itemManageUploads")}))},deleteUpload:function(e){page.postBulkDeleteUploads({all:"uploadsAll"===page.currentView,field:"id",values:[e],cb:function(a){!a.length&&page.selected[page.currentView].includes(e)&&page.selected[page.currentView].splice(page.selected[page.currentView].indexOf(e),1),page.selected[page.currentView].length?localStorage[lsKeys.selected[page.currentView]]=JSON.stringify(page.selected[page.currentView]):delete localStorage[lsKeys.selected[page.currentView]],page.getUploads(Object.assign({autoPage:!0},page.views[page.currentView]))}})},bulkDeleteUploads:function(){if(!page.selected[page.currentView].length)return swal("An error occurred!","You have not selected any uploads.","error");page.postBulkDeleteUploads({all:"uploadsAll"===page.currentView,field:"id",values:page.selected[page.currentView],cb:function(e){e.length?page.selected[page.currentView]=page.selected[page.currentView].filter((function(a){return e.includes(a)})):page.selected[page.currentView]=[],page.selected[page.currentView].length?localStorage[lsKeys.selected[page.currentView]]=JSON.stringify(page.selected[page.currentView]):delete localStorage[lsKeys.selected[page.currentView]],page.getUploads(Object.assign({autoPage:!0},page.views[page.currentView]))}})},deleteUploadsByNames:function(e){void 0===e&&(e={});var a="";page.permissions.moderator&&(a="
Hint: You can use this feature to delete uploads by other users."),page.dom.innerHTML='\n
\n
\n \n
\n \n
\n

Separate each entry with a new line.'+a+'

\n
\n
\n
\n \n
\n
\n
\n ',page.fadeAndScroll(),page.updateTrigger(e.trigger,"active"),document.querySelector("#submitBulkDelete").addEventListener("click",(function(){var e=document.querySelector("#bulkDeleteNames"),a={},n=e.value.split(/\r?\n/).map((function(e){var a=e.trim();return/^[^\s]+$/.test(a)?a:""})).filter((function(e){return!(!e||Object.prototype.hasOwnProperty.call(a,e))&&(a[e]=!0)}));if(e.value=n.join("\n"),!n.length)return swal("An error occurred!","You have not entered any upload names.","error");page.postBulkDeleteUploads({all:!0,field:"name",values:n,cb:function(a){e.value=a.join("\n")}})}))},postBulkDeleteUploads:function(e){void 0===e&&(e={});var a=e.values.length,n=e.values.length+" upload"+(1===a?"":"s"),t="

You won't be able to recover "+n.replace(/^(\d*)(.*)/,"$1$2")+"!

";e.all&&(t+="\n

Warning: You may be nuking "+(1===a?"an upload":"some uploads")+" by "+(1===a?"another user":"other users")+"!

");var s=document.createElement("div");s.innerHTML=t,swal({title:"Are you sure?",content:s,icon:"warning",dangerMode:!0,buttons:{cancel:!0,confirm:{text:"Yes, nuke "+(1===e.values.length?"it":"them")+"!",closeModal:!1}}}).then((function(t){t&&axios.post("api/upload/bulkdelete",{field:e.fields,values:e.values}).then((function(t){if(t){if(!1===t.data.success)return"No token provided"===t.data.description?page.verifyToken(page.token):swal("An error occurred!",t.data.description,"error");var s=Array.isArray(t.data.failed)?t.data.failed:[];s.length===e.values.length?swal("An error occurred!","Unable to delete any of the "+n+".","error"):s.length&&s.length\n

You are about to add '+n+" upload"+(1===n?"":"s")+' to an album.

\n

If an upload is already in an album, it will be moved.

\n \n
\n
\n
\n \n
\n
\n
\n ',swal({icon:"warning",content:t,buttons:{cancel:!0,confirm:{text:"OK",closeModal:!1}}}).then((function(n){if(n){var t=parseInt(document.querySelector("#swalAlbum").value);if(isNaN(t))return swal("An error occurred!","You did not choose an album.","error");axios.post("api/albums/addfiles",{ids:e,albumid:t}).then((function(n){if(n)if(!1!==n.data.success){var s=e.length;n.data.failed&&n.data.failed.length&&(s-=n.data.failed.length);var r="upload"+(1===e.length?"":"s");if(!s)return swal("An error occurred!","Could not add the "+r+" to the album.","error");swal("Woohoo!","Successfully "+(t<0?"removed":"added")+" "+s+" "+r+" "+(t<0?"from":"to")+" the album.","success"),a(n.data.failed)}else"No token provided"===n.data.description?page.verifyToken(page.token):swal("An error occurred!",n.data.description,"error")})).catch((function(e){return console.error(e),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))}})).catch((function(e){return console.error(e),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")})),axios.get("api/albums").then((function(e){if(!1!==e.data.success){var a=document.querySelector("#swalAlbum");a&&(a.innerHTML+=e.data.albums.map((function(e){return'"})).join("\n"),a.getElementsByTagName("option")[1].innerHTML="Choose an album",a.removeAttribute("disabled"))}else"No token provided"===e.data.description?page.verifyToken(page.token):swal("An error occurred!",e.data.description,"error")})).catch((function(e){return console.error(e),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))},getAlbums:function(e){void 0===e&&(e={}),page.updateTrigger(e.trigger,"loading"),axios.get("api/albums").then((function(a){if(a){if(!1===a.data.success)return"No token provided"===a.data.description?page.verifyToken(page.token):(page.updateTrigger(e.trigger),swal("An error occurred!",a.data.description,"error"));page.cache.albums={},page.dom.innerHTML='\n

Create new album

\n
\n
\n
\n \n
\n
\n
\n
\n \n
\n
\n
\n
\n \n
\n
\n
\n
\n

List of albums

\n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
IDNameFilesCreated atPublic link
\n
\n ';for(var n=a.data.homeDomain,t=document.querySelector("#table"),s=0;s"+r.id+"\n "+r.name+"\n "+r.files+"\n "+r.prettyDate+"\n '+i+'\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n ',t.appendChild(l)}page.fadeAndScroll(),page.updateTrigger(e.trigger,"active")}})).catch((function(a){return console.error(a),page.updateTrigger(e.trigger),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))},editAlbum:function(e){var a=page.cache.albums[e];if(a){var n=document.createElement("div");n.innerHTML='\n
\n
\n \n
\n
\n
\n
\n \n
\n
\n
\n
\n \n
\n
\n
\n
\n \n
\n
\n
\n
\n \n
\n
\n ',swal({title:"Edit album",icon:"info",content:n,buttons:{cancel:!0,confirm:{closeModal:!1}}}).then((function(n){n&&axios.post("api/albums/edit",{id:e,name:document.querySelector("#swalName").value.trim(),description:document.querySelector("#swalDescription").value.trim(),download:document.querySelector("#swalDownload").checked,public:document.querySelector("#swalPublic").checked,requestLink:document.querySelector("#swalRequestLink").checked}).then((function(e){if(e){if(!1===e.data.success)return"No token provided"===e.data.description?page.verifyToken(page.token):swal("An error occurred!",e.data.description,"error");e.data.identifier?swal("Success!","Your album's new identifier is: "+e.data.identifier+".","success"):e.data.name!==a.name?swal("Success!","Your album was renamed to: "+e.data.name+".","success"):swal("Success!","Your album was edited!","success"),page.getAlbumsSidebar(),page.getAlbums()}})).catch((function(e){return console.error(e),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))}))}},deleteAlbum:function(e){swal({title:"Are you sure?",text:"This won't delete your uploads, only the album!",icon:"warning",dangerMode:!0,buttons:{cancel:!0,confirm:{text:"Yes, delete it!",closeModal:!1},purge:{text:"Umm, delete the uploads too please?",value:"purge",className:"swal-button--danger",closeModal:!1}}}).then((function(a){a&&axios.post("api/albums/delete",{id:e,purge:"purge"===a}).then((function(e){if(!1===e.data.success)return"No token provided"===e.data.description?page.verifyToken(page.token):Array.isArray(e.data.failed)&&e.data.failed.length?swal("An error occurred!","Unable to delete ","error"):swal("An error occurred!",e.data.description,"error");swal("Deleted!","Your album has been deleted.","success"),page.getAlbumsSidebar(),page.getAlbums()})).catch((function(e){return console.error(e),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))}))},submitAlbum:function(e){page.updateTrigger(e,"loading"),axios.post("api/albums",{name:document.querySelector("#albumName").value,description:document.querySelector("#albumDescription").value}).then((function(a){if(a){if(page.updateTrigger(e),!1===a.data.success)return"No token provided"===a.data.description?page.verifyToken(page.token):swal("An error occurred!",a.data.description,"error");swal("Woohoo!","Album was created successfully.","success"),page.getAlbumsSidebar(),page.getAlbums()}})).catch((function(a){return console.error(a),page.updateTrigger(e),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))},getAlbumsSidebar:function(){axios.get("api/albums/sidebar").then((function(e){if(e){if(!1===e.data.success)return"No token provided"===e.data.description?page.verifyToken(page.token):swal("An error occurred!",e.data.description,"error");var a=document.querySelector("#albumsContainer"),n=a.querySelectorAll("li > a");if(n.length){for(var t=0;t\n \n \n \n \n ',page.fadeAndScroll(),page.updateTrigger(e.trigger,"active"),document.querySelector("#getNewToken").addEventListener("click",(function(e){var a=e.currentTarget;page.updateTrigger(a,"loading"),axios.post("api/tokens/change").then((function(e){if(!1===e.data.success)return"No token provided"===e.data.description?page.verifyToken(page.token):(page.updateTrigger(a),swal("An error occurred!",e.data.description,"error"));page.updateTrigger(a),swal({title:"Woohoo!",text:"Your token was successfully changed.",icon:"success"}).then((function(){axios.defaults.headers.common.token=e.data.token,localStorage[lsKeys.token]=e.data.token,page.token=e.data.token,page.changeToken()}))})).catch((function(e){return console.error(e),page.updateTrigger(a),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))}))})).catch((function(a){return console.error(a),page.updateTrigger(e.trigger),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))},changePassword:function(e){void 0===e&&(e={}),page.dom.innerHTML='\n
\n
\n \n
\n \n
\n
\n
\n \n
\n \n
\n
\n
\n
\n \n
\n
\n
\n ',page.fadeAndScroll(),page.updateTrigger(e.trigger,"active"),document.querySelector("#sendChangePassword").addEventListener("click",(function(e){document.querySelector("#password").value===document.querySelector("#passwordConfirm").value?page.sendNewPassword(document.querySelector("#password").value,e.currentTarget):swal({title:"Password mismatch!",text:"Your passwords do not match, please try again.",icon:"error"})}))},sendNewPassword:function(e,a){page.updateTrigger(a,"loading"),axios.post("api/password/change",{password:e}).then((function(e){if(page.updateTrigger(a),!1===e.data.success)return"No token provided"===e.data.description?page.verifyToken(page.token):swal("An error occurred!",e.data.description,"error");swal({title:"Woohoo!",text:"Your password was successfully changed.",icon:"success"}).then((function(){page.changePassword()}))})).catch((function(e){return console.error(e),page.updateTrigger(a),swal("An error occurred!","There was an error with the request, please check the console for more information.","error")}))},getUsers:function(e){if(void 0===e&&(e={}),page.updateTrigger(e.trigger,"loading"),void 0===e.pageNum&&(e.pageNum=0),!page.permissions.admin)return swal("An error occurred!","You can not do this!","error");var a="api/users/"+e.pageNum;axios.get(a).then((function(a){if(!1===a.data.success)return"No token provided"===a.data.description?page.verifyToken(page.token):(page.updateTrigger(e.trigger),swal("An error occurred!",a.data.description,"error"));if(e.pageNum&&0===a.data.users.length)return page.updateTrigger(e.trigger),swal("An error occurred!","There are no more users to populate page "+(e.pageNum+1)+".","error");page.currentView="users",page.cache.users={};var n=page.paginate(a.data.count,25,e.pageNum),t='\n
\n
\n
\n
\n
\n
\n \n
\n
\n \n
\n
\n
\n
\n
\n ',s=!1;page.dom.innerHTML="\n "+n+"\n "+t+'\n \n \n \n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
IDUsernameUploadsUsageGroup
\n
\n
\n '+n+"\n ";for(var r=document.querySelector("#table"),i=0;i