Updated keys for local storage. They're now using camel case.
Not sure why I didn't use camel case in the first place.

View type and selected files of Uploads and Manage uploads (your own
uploads and all uploads, respectively) are now stored separately.

Added "filter by username" in Manage uploads.

Added "jump to page" in all uploads/users view.

Updated fontello (added filter icon).

Bumped v1 and v3 version string, due to dashboard.js and fontello
respectively.

Curly rule fix for routes/nojs.js.
This commit is contained in:
Bobby Wibowo 2019-01-03 11:49:56 +07:00
parent 765f8c9880
commit 2b0969dc77
No known key found for this signature in database
GPG Key ID: 51C3A1E1E22D26CF
10 changed files with 225 additions and 104 deletions

View File

@ -691,16 +691,27 @@ uploadsController.list = async (req, res) => {
// Headers is string-only, this seem to be the safest and lightest
const all = req.headers.all === '1'
const uploader = req.headers.uploader
const ismoderator = perms.is(user, 'moderator')
if (all && !ismoderator) return res.status(403).end()
if ((all || uploader) && !ismoderator) return res.status(403).end()
let uploaderID = null
if (uploader)
uploaderID = await db.table('users')
.where('username', uploader)
.select('id')
.first()
.then(row => row ? row.id : null)
function filter () {
if (req.params.id === undefined)
this.where('id', '<>', '')
else
this.where('albumid', req.params.id)
if (!all || !ismoderator)
if (!ismoderator || !all)
this.where('userid', user.id)
else if (uploaderID)
this.where('userid', uploaderID)
}
const count = await db.table('files')

View File

@ -1,14 +1,16 @@
/* global swal, axios, ClipboardJS, LazyLoad */
// keys for localStorage
const LS_KEYS = {
const lsKeys = {
token: 'token',
viewType: {
uploads: 'UPLOADS_VIEW_TYPE'
uploads: 'viewTypeUploads',
uploadsAll: 'viewTypeUploadsAll'
},
selected: {
uploads: 'SELECTED_UPLOADS',
users: 'SELECTED_USERS'
uploads: 'selectedUploads',
uploadsAll: 'selectedUploadsAll',
users: 'selectedUsers'
}
}
@ -17,7 +19,7 @@ const page = {
dom: null,
// user token
token: localStorage[LS_KEYS.token],
token: localStorage[lsKeys.token],
// from api/tokens/verify
username: null,
@ -27,10 +29,16 @@ const page = {
views: {
// config of uploads view
uploads: {
type: localStorage[LS_KEYS.viewType.uploads],
type: localStorage[lsKeys.viewType.uploads],
album: null, // album's id
pageNum: null // page num
},
// config of uploads view (all)
uploadsAll: {
type: localStorage[lsKeys.viewType.uploadsAll],
uploader: null, // uploader's name
pageNum: null, // page num
all: null // listing all uploads or just the user's
all: true
},
// config of users view
users: {
@ -41,14 +49,17 @@ const page = {
// id of selected items (shared across pages and will be synced with localStorage)
selected: {
uploads: [],
uploadsAll: [],
users: []
},
checkboxes: {
uploads: [],
uploadsAll: [],
users: []
},
lastSelected: {
upload: null,
uploadsAll: null,
user: null
},
@ -90,12 +101,12 @@ page.verifyToken = function (token, reloadOnError) {
icon: 'error'
}).then(function () {
if (!reloadOnError) return
localStorage.removeItem(LS_KEYS.token)
localStorage.removeItem(lsKeys.token)
location.location = 'auth'
})
axios.defaults.headers.common.token = token
localStorage[LS_KEYS.token] = token
localStorage[lsKeys.token] = token
page.token = token
page.username = response.data.username
page.permissions = response.data.permissions
@ -173,7 +184,7 @@ page.prepareDashboard = function () {
}
page.logout = function () {
localStorage.removeItem(LS_KEYS.token)
localStorage.removeItem(lsKeys.token)
location.reload('.')
}
@ -203,35 +214,6 @@ page.domClick = function (event) {
const id = page.getItemID(element)
const action = element.dataset.action
// Handle pagination actions
if (['page-prev', 'page-next', 'page-goto'].includes(action)) {
const views = {}
let func = null
if (page.currentView === 'uploads') {
views.album = page.views.uploads.album
views.all = page.views.uploads.all
func = page.getUploads
} else if (page.currentView === 'users') {
func = page.getUsers
}
switch (action) {
case 'page-prev':
views.pageNum = page.views[page.currentView].pageNum - 1
if (views.pageNum < 0)
return swal('An error occurred!', 'This is already the first page.', 'error')
return func(views, element)
case 'page-next':
views.pageNum = page.views[page.currentView].pageNum + 1
return func(views, element)
case 'page-goto':
views.pageNum = parseInt(element.dataset.goto)
return func(views, element)
}
}
switch (action) {
case 'view-list':
return page.setUploadsView('list', element)
@ -267,6 +249,15 @@ page.domClick = function (event) {
return page.editUser(id)
case 'disable-user':
return page.disableUser(id)
case 'filter-by-uploader':
return page.filterByUploader(element)
case 'view-user-uploads':
return page.viewUserUploads(id)
case 'page-prev':
case 'page-next':
case 'page-goto':
case 'jump-to-page':
return page.switchPage(action, element)
}
}
@ -287,21 +278,56 @@ page.fadeIn = function (content) {
}, 500)
}
page.getUploads = function ({ album, pageNum, all } = {}, element) {
page.switchPage = function (action, element) {
const views = {}
let func = null
if (page.currentView === 'users') {
func = page.getUsers
} else {
func = page.getUploads
views.album = page.views[page.currentView].album
views.all = page.views[page.currentView].all
views.uploader = page.views[page.currentView].uploader
}
switch (action) {
case 'page-prev':
views.pageNum = page.views[page.currentView].pageNum - 1
if (views.pageNum < 0)
return swal('An error occurred!', 'This is already the first page.', 'error')
return func(views, element)
case 'page-next':
views.pageNum = page.views[page.currentView].pageNum + 1
return func(views, element)
case 'page-goto':
views.pageNum = parseInt(element.dataset.goto)
return func(views, element)
case 'jump-to-page':
const jumpToPage = parseInt(document.getElementById('jumpToPage').value)
views.pageNum = isNaN(jumpToPage) ? 0 : (jumpToPage - 1)
if (views.pageNum < 0) views.pageNum = 0
return func(views, element)
}
}
page.getUploads = function ({ pageNum, album, all, uploader } = {}, element) {
if (element) page.isLoading(element, true)
if (pageNum === undefined) pageNum = 0
let url = `api/uploads/${pageNum}`
if (album !== undefined) url = `api/album/${album}/${pageNum}`
if (all && !page.permissions.moderator)
if ((all || uploader) && !page.permissions.moderator)
return swal('An error occurred!', 'You can not do this!', 'error')
axios.get(url, {
headers: {
all: all ? '1' : '0'
}
}).then(function (response) {
if (typeof pageNum !== 'number' || pageNum < 0)
pageNum = 0
let url = `api/uploads/${pageNum}`
if (typeof album === 'string')
url = `api/album/${album}/${pageNum}`
const headers = {}
if (all) headers.all = '1'
if (uploader) headers.uploader = uploader
axios.get(url, { headers }).then(function (response) {
if (response.data.success === false)
if (response.data.description === 'No token provided') {
return page.verifyToken(page.token)
@ -315,11 +341,50 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
return swal('An error occurred!', `There are no more uploads to populate page ${pageNum + 1}.`, 'error')
}
page.currentView = 'uploads'
page.currentView = all ? 'uploadsAll' : 'uploads'
page.cache.uploads = {}
const pagination = page.paginate(response.data.count, 25, pageNum)
let filter = ''
if (all)
filter = `
<div class="column is-one-quarter">
<div class="field has-addons">
<div class="control is-expanded">
<input id="uploader" class="input is-small" type="text" placeholder="Username" value="${uploader || ''}">
</div>
<div class="control">
<a class="button is-small is-breeze" title="Filter by uploader" data-action="filter-by-uploader">
<span class="icon">
<i class="icon-filter"></i>
</span>
</a>
</div>
</div>
</div>
`
const extraControls = `
<div class="columns" style="margin-top: 10px">
${filter}
<div class="column is-hidden-mobile"></div>
<div class="column is-one-quarter">
<div class="field has-addons">
<div class="control is-expanded">
<input id="jumpToPage" class="input is-small" type="text" value="${pageNum + 1}">
</div>
<div class="control">
<a class="button is-small is-breeze" title="Jump to page" data-action="jump-to-page">
<span class="icon">
<i class="icon-paper-plane-empty"></i>
</span>
</a>
</div>
</div>
</div>
</div>
`
const controls = `
<div class="columns">
<div class="column is-hidden-mobile"></div>
@ -358,10 +423,10 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
`
let allSelected = true
if (page.views.uploads.type === 'thumbs') {
if (page.views[page.currentView].type === 'thumbs') {
page.dom.innerHTML = `
${pagination}
<hr>
${extraControls}
${controls}
<div id="table" class="columns is-multiline is-mobile is-centered">
</div>
@ -374,7 +439,7 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
for (let i = 0; i < response.data.files.length; i++) {
const upload = response.data.files[i]
const selected = page.selected.uploads.includes(upload.id)
const selected = page.selected[page.currentView].includes(upload.id)
if (!selected && allSelected) allSelected = false
page.cache.uploads[upload.id] = {
@ -429,8 +494,7 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
`
table.appendChild(div)
// page.checkboxes.uploads = Array.from(table.getElementsByClassName('checkbox'))
page.checkboxes.uploads = Array.from(table.querySelectorAll('.checkbox[data-action="select"]'))
page.checkboxes[page.currentView] = Array.from(table.querySelectorAll('.checkbox[data-action="select"]'))
page.lazyLoad.update()
}
} else {
@ -439,7 +503,7 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
page.dom.innerHTML = `
${pagination}
<hr>
${extraControls}
${controls}
<div class="table-container">
<table class="table is-narrow is-fullwidth is-hoverable">
@ -466,7 +530,7 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
for (let i = 0; i < response.data.files.length; i++) {
const upload = response.data.files[i]
const selected = page.selected.uploads.includes(upload.id)
const selected = page.selected[page.currentView].includes(upload.id)
if (!selected && allSelected) allSelected = false
page.cache.uploads[upload.id] = {
@ -516,8 +580,7 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
`
table.appendChild(tr)
// page.checkboxes.uploads = Array.from(table.getElementsByClassName('checkbox'))
page.checkboxes.uploads = Array.from(table.querySelectorAll('.checkbox[data-action="select"]'))
page.checkboxes[page.currentView] = Array.from(table.querySelectorAll('.checkbox[data-action="select"]'))
}
}
@ -526,9 +589,9 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
if (selectAll) selectAll.checked = true
}
page.views.uploads.album = album
page.views.uploads.pageNum = response.data.files.length ? pageNum : 0
page.views.uploads.all = all
if (page.currentView === 'uploads') page.views.uploads.album = album
if (page.currentView === 'uploadsAll') page.views.uploadsAll.uploader = uploader
page.views[page.currentView].pageNum = response.data.files.length ? pageNum : 0
}).catch(function (error) {
if (element) page.isLoading(element, false)
console.log(error)
@ -537,9 +600,9 @@ page.getUploads = function ({ album, pageNum, all } = {}, element) {
}
page.setUploadsView = function (view, element) {
localStorage[LS_KEYS.viewType.uploads] = view
page.views.uploads.type = view
page.getUploads(page.views.uploads, element)
localStorage[lsKeys.viewType[page.currentView]] = view
page.views[page.currentView].type = view
page.getUploads(page.views[page.currentView], element)
}
page.displayThumbnail = function (id) {
@ -626,9 +689,9 @@ page.selectAll = function (element) {
}
if (selected.length)
localStorage[LS_KEYS.selected[currentView]] = JSON.stringify(selected)
localStorage[lsKeys.selected[currentView]] = JSON.stringify(selected)
else
localStorage.removeItem(LS_KEYS.selected[currentView])
localStorage.removeItem(lsKeys.selected[currentView])
page.selected[currentView] = selected
element.title = element.checked ? 'Unselect all uploads' : 'Select all uploads'
@ -655,7 +718,7 @@ page.selectInBetween = function (element, lastElement) {
page.selected[currentView].push(page.getItemID(checkboxes[i]))
}
localStorage[LS_KEYS.selected.uploads] = JSON.stringify(page.selected[currentView])
localStorage[lsKeys.selected.uploads] = JSON.stringify(page.selected[currentView])
page.checkboxes[currentView] = checkboxes
}
@ -677,9 +740,9 @@ page.select = function (element, event) {
selected.splice(selected.indexOf(id), 1)
if (selected.length)
localStorage[LS_KEYS.selected[currentView]] = JSON.stringify(selected)
localStorage[lsKeys.selected[currentView]] = JSON.stringify(selected)
else
localStorage.removeItem(LS_KEYS.selected[currentView])
localStorage.removeItem(lsKeys.selected[currentView])
page.selected[currentView] = selected
}
@ -687,11 +750,12 @@ page.select = function (element, event) {
page.clearSelection = function () {
const currentView = page.currentView
const selected = page.selected[currentView]
const type = page.currentView === 'users' ? 'users' : 'uploads'
const count = selected.length
if (!count)
return swal('An error occurred!', `You have not selected any ${currentView}.`, 'error')
return swal('An error occurred!', `You have not selected any ${type}.`, 'error')
const suffix = count === 1 ? currentView.substring(0, currentView.length - 1) : currentView
const suffix = count === 1 ? type.substring(0, type.length - 1) : type
return swal({
title: 'Are you sure?',
text: `You are going to unselect ${count} ${suffix}.`,
@ -704,7 +768,7 @@ page.clearSelection = function () {
if (checkboxes[i].checked)
checkboxes[i].checked = false
localStorage.removeItem(LS_KEYS.selected[currentView])
localStorage.removeItem(lsKeys.selected[currentView])
page.selected[currentView] = []
const selectAll = document.getElementById('selectAll')
@ -714,6 +778,18 @@ page.clearSelection = function () {
})
}
page.filterByUploader = function (element) {
const uploader = document.getElementById('uploader').value
page.getUploads({ all: true, uploader }, element)
}
page.viewUserUploads = function (id) {
const user = page.cache.users[id]
if (!user) return
page.setActiveMenu(document.getElementById('itemManageUploads'))
page.getUploads({ all: true, uploader: user.username })
}
page.deleteFile = function (id) {
// TODO: Share function with bulk delete, just like 'add selected uploads to album' and 'add single file to album'
swal({
@ -751,14 +827,18 @@ page.deleteFile = function (id) {
}
page.deleteSelectedFiles = function () {
const count = page.selected.uploads.length
const count = page.selected[page.currentView].length
if (!count)
return swal('An error occurred!', 'You have not selected any uploads.', 'error')
const suffix = `file${count === 1 ? '' : 's'}`
const suffix = `upload${count === 1 ? '' : 's'}`
let text = `You won't be able to recover ${count} ${suffix}!`
if (page.currentView === 'uploadsAll')
text += '\nBe aware, you may be nuking uploads by other users!'
swal({
title: 'Are you sure?',
text: `You won't be able to recover ${count} ${suffix}!`,
text,
icon: 'warning',
dangerMode: true,
buttons: {
@ -773,7 +853,7 @@ page.deleteSelectedFiles = function () {
axios.post('api/upload/bulkdelete', {
field: 'id',
values: page.selected.uploads
values: page.selected[page.currentView]
}).then(function (bulkdelete) {
if (!bulkdelete) return
@ -787,14 +867,14 @@ page.deleteSelectedFiles = function () {
let deleted = count
if (bulkdelete.data.failed && bulkdelete.data.failed.length) {
deleted -= bulkdelete.data.failed.length
page.selected.uploads = page.selected.uploads.filter(function (id) {
page.selected[page.currentView] = page.selected[page.currentView].filter(function (id) {
return bulkdelete.data.failed.includes(id)
})
} else {
page.selected.uploads = []
page.selected[page.currentView] = []
}
localStorage[LS_KEYS.selected.uploads] = JSON.stringify(page.selected.uploads)
localStorage[lsKeys.selected.uploads] = JSON.stringify(page.selected[page.currentView])
swal('Deleted!', `${deleted} file${deleted === 1 ? ' has' : 's have'} been deleted.`, 'success')
return page.getUploads(page.views.uploads)
@ -882,20 +962,23 @@ page.deleteFileByNames = function () {
}
page.addSelectedFilesToAlbum = function () {
const count = page.selected.uploads.length
if (page.currentView !== 'uploads')
return
const count = page.selected[page.currentView].length
if (!count)
return swal('An error occurred!', 'You have not selected any uploads.', 'error')
page.addFilesToAlbum(page.selected.uploads, function (failed) {
page.addFilesToAlbum(page.selected[page.currentView], function (failed) {
if (!failed) return
if (failed.length)
page.selected.uploads = page.selected.uploads.filter(function (id) {
page.selected[page.currentView] = page.selected[page.currentView].filter(function (id) {
return failed.includes(id)
})
else
page.selected.uploads = []
page.selected[page.currentView] = []
localStorage[LS_KEYS.selected.uploads] = JSON.stringify(page.selected.uploads)
localStorage[lsKeys.selected.uploads] = JSON.stringify(page.selected[page.currentView])
page.getUploads(page.views.uploads)
})
}
@ -1448,7 +1531,7 @@ page.getNewToken = function (element) {
icon: 'success'
}).then(function () {
axios.defaults.headers.common.token = response.data.token
localStorage[LS_KEYS.token] = response.data.token
localStorage[lsKeys.token] = response.data.token
page.token = response.data.token
page.changeToken()
})
@ -1593,6 +1676,26 @@ page.getUsers = function ({ pageNum } = {}, element) {
const pagination = page.paginate(response.data.count, 25, pageNum)
const extraControls = `
<div class="columns" style="margin-top: 10px">
<div class="column is-hidden-mobile"></div>
<div class="column is-one-quarter">
<div class="field has-addons">
<div class="control is-expanded">
<input id="jumpToPage" class="input is-small" type="text" value="${pageNum + 1}">
</div>
<div class="control">
<a class="button is-small is-breeze" title="Jump to page" data-action="jump-to-page">
<span class="icon">
<i class="icon-paper-plane-empty"></i>
</span>
</a>
</div>
</div>
</div>
</div>
`
const controls = `
<div class="columns">
<div class="column is-hidden-mobile"></div>
@ -1622,7 +1725,7 @@ page.getUsers = function ({ pageNum } = {}, element) {
page.dom.innerHTML = `
${pagination}
<hr>
${extraControls}
${controls}
<div class="table-container">
<table class="table is-narrow is-fullwidth is-hoverable">
@ -1685,6 +1788,11 @@ page.getUsers = function ({ pageNum } = {}, element) {
<i class="icon-pencil-1"></i>
</span>
</a>
<a class="button is-small is-info" title="View uploads" data-action="view-user-uploads" ${user.uploadsCount ? '' : 'disabled'}>
<span class="icon">
<i class="icon-picture-1"></i>
</span>
</a>
<a class="button is-small is-warning" title="Disable user" data-action="disable-user" ${enabled ? '' : 'disabled'}>
<span class="icon">
<i class="icon-hammer"></i>
@ -1911,9 +2019,9 @@ window.onload = function () {
if (!('ontouchstart' in document.documentElement))
document.documentElement.classList.add('no-touch')
const selectedKeys = ['uploads', 'users']
const selectedKeys = ['uploads', 'uploadsAll', 'users']
for (const selectedKey of selectedKeys) {
const ls = localStorage[LS_KEYS.selected[selectedKey]]
const ls = localStorage[lsKeys.selected[selectedKey]]
if (ls) page.selected[selectedKey] = JSON.parse(ls)
}

View File

@ -1,11 +1,11 @@
@font-face {
font-family: 'fontello';
src: url('fontello.eot?37936592');
src: url('fontello.eot?37936592#iefix') format('embedded-opentype'),
url('fontello.woff2?37936592') format('woff2'),
url('fontello.woff?37936592') format('woff'),
url('fontello.ttf?37936592') format('truetype'),
url('fontello.svg?37936592#fontello') format('svg');
src: url('fontello.eot?27514039');
src: url('fontello.eot?27514039#iefix') format('embedded-opentype'),
url('fontello.woff2?27514039') format('woff2'),
url('fontello.woff?27514039') format('woff'),
url('fontello.ttf?27514039') format('truetype'),
url('fontello.svg?27514039#fontello') format('svg');
font-weight: normal;
font-style: normal;
}
@ -15,7 +15,7 @@
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'fontello';
src: url('fontello.svg?37936592#fontello') format('svg');
src: url('fontello.svg?27514039#fontello') format('svg');
}
}
*/
@ -79,6 +79,7 @@
.icon-hammer:before { content: '\e811'; } /* '' */
.icon-privatebin:before { content: '\e817'; } /* '' */
.icon-github-circled:before { content: '\f09b'; } /* '' */
.icon-filter:before { content: '\f0b0'; } /* '' */
.icon-gauge:before { content: '\f0e4'; } /* '' */
.icon-paper-plane-empty:before { content: '\f1d9'; } /* '' */
.icon-user-plus:before { content: '\f234'; } /* '' */

Binary file not shown.

View File

@ -1,7 +1,7 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Copyright (C) 2018 by original authors @ fontello.com</metadata>
<metadata>Copyright (C) 2019 by original authors @ fontello.com</metadata>
<defs>
<font id="fontello" horiz-adv-x="1000" >
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
@ -46,6 +46,8 @@
<glyph glyph-name="github-circled" unicode="&#xf09b;" d="M429 779q116 0 215-58t156-156 57-215q0-140-82-252t-211-155q-15-3-22 4t-7 17q0 1 0 43t0 75q0 54-29 79 32 3 57 10t53 22 45 37 30 58 11 84q0 67-44 115 21 51-4 114-16 5-46-6t-51-25l-21-13q-52 15-107 15t-108-15q-8 6-23 15t-47 22-47 7q-25-63-5-114-44-48-44-115 0-47 12-83t29-59 45-37 52-22 57-10q-21-20-27-58-12-5-25-8t-32-3-36 12-31 35q-11 18-27 29t-28 14l-11 1q-12 0-16-2t-3-7 5-8 7-6l4-3q12-6 24-21t18-29l6-13q7-21 24-34t37-17 39-3 31 1l13 3q0-22 0-50t1-30q0-10-8-17t-22-4q-129 43-211 155t-82 252q0 117 58 215t155 156 216 58z m-267-616q2 4-3 7-6 1-8-1-1-4 4-7 5-3 7 1z m18-19q4 3-1 9-6 5-9 2-4-3 1-9 5-6 9-2z m16-25q6 4 0 11-4 7-9 3-5-3 0-10t9-4z m24-23q4 4-2 10-7 7-11 2-5-5 2-11 6-6 11-1z m32-14q1 6-8 9-8 2-10-4t7-9q8-3 11 4z m35-3q0 7-10 6-9 0-9-6 0-7 10-6 9 0 9 6z m32 5q-1 7-10 5-9-1-8-8t10-4 8 7z" horiz-adv-x="857.1" />
<glyph glyph-name="filter" unicode="&#xf0b0;" d="M783 685q9-22-8-39l-275-275v-414q0-23-22-33-7-3-14-3-15 0-25 11l-143 143q-10 11-10 25v271l-275 275q-18 17-8 39 9 22 33 22h714q23 0 33-22z" horiz-adv-x="785.7" />
<glyph glyph-name="gauge" unicode="&#xf0e4;" d="M214 207q0 30-21 51t-50 21-51-21-21-51 21-50 51-21 50 21 21 50z m107 250q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m239-268l57 213q3 14-5 27t-21 16-27-3-17-22l-56-213q-33-3-60-25t-35-55q-11-43 11-81t66-50 81 11 50 66q9 33-4 65t-40 51z m369 18q0 30-21 51t-51 21-50-21-21-51 21-50 50-21 51 21 21 50z m-358 357q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m250-107q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m179-250q0-145-79-269-10-17-30-17h-782q-20 0-30 17-79 123-79 269 0 102 40 194t106 160 160 107 194 39 194-39 160-107 106-160 40-194z" horiz-adv-x="1000" />
<glyph glyph-name="paper-plane-empty" unicode="&#xf1d9;" d="M984 844q19-13 15-36l-142-857q-3-16-18-25-8-5-18-5-6 0-13 3l-294 120-166-182q-10-12-27-12-7 0-12 2-11 4-17 13t-6 21v252l-264 108q-20 8-22 30-2 22 18 33l928 536q20 12 38-1z m-190-837l123 739-800-462 187-76 482 356-267-444z" horiz-adv-x="1000" />

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -7,13 +7,12 @@ const renderOptions = {
maxFileSize: config.cloudflare.noJsMaxSize || config.uploads.maxSize
}
if (config.private) {
if (config.private)
if (config.enableUserAccounts) {
renderOptions.uploadDisabled = 'Anonymous upload is disabled.'
} else {
renderOptions.uploadDisabled = 'Running in private mode.'
}
}
routes.get('/nojs', async (req, res, next) => {
const options = { renderOptions }

View File

@ -15,9 +15,9 @@
v2: Images and config files (manifest.json, browserconfig.xml, etc).
v3: CSS and JS files (libs such as bulma, lazyload, etc).
#}
{% set v1 = "f7el9u61UI" %}
{% set v1 = "n5oBSPKUn0" %}
{% set v2 = "Ii3JYKIhb0" %}
{% set v3 = "ll7yHY3b2b" %}
{% set v3 = "n5oBSPKUn0" %}
{#
These will be the links in the homepage and the No-JS uploader.