mirror of
https://github.com/BobbyWibowo/lolisafe.git
synced 2024-12-13 16:06:21 +00:00
Updated
Upgraded dependencies. Stop adding cache-control header to album zip files unless config.cacheControl is enabled. Updated CSS files. Moved thumbnail-related styling to thumbs.css. Various other fixes & improvements. Moved render.js from public/js to public/js/s. Removed sharex.js in favor of public/js/s/utils.js. Moved getPrettyDate() & getPrettyBytes() to that JS file as well. Added lsKeys global variable wherever applicable. Previously the idea was only used in dashboard.js. Added No-JS version of album public pages. You'll only have to add ?nojs to the URL. Viewing the regular version with JS disabled will show a notice with a link to the No-JS version of the particular album. Overall page size of the regular version will now be lower as well, since there'll be no need to add noscript tag for each thumbs. No longer show Administrator section to non-admin in the dashboard. Moderators will ONLY be able to see manage users menu as well. Simplified FAQ wherever applicable. Added a new FAQ about bug report or feature request. Updated link for Firefox extension. Also pushed Firefox link before Chrome, cause I like it more. Added browser settings menu to dashboard. This allows you to choose file size unit (kilobyte vs kibibyte) for that specific browser. The preference will be used on homepage, dashboard and album pages. This also allows you to set chunk size and maximum parallel uploads for the homepage uploader. All menu links in the dashboard will now scroll to the content once loaded. Previously it would only do so with manage uploads/users when switching pages. Refactored all instances of for-in & for-of loop from browser JS files. For the sake of uniformity, for now.
This commit is contained in:
parent
b77d4b7c65
commit
05b905bc9b
@ -321,11 +321,11 @@ albumsController.get = async (req, res, next) => {
|
||||
albumsController.generateZip = async (req, res, next) => {
|
||||
const versionString = parseInt(req.query.v)
|
||||
const download = (filePath, fileName) => {
|
||||
const headers = { 'Access-Control-Allow-Origin': '*' }
|
||||
if (versionString > 0)
|
||||
// Cache-Control header is useful when using CDN (max-age: 30 days)
|
||||
const headers = {}
|
||||
if (config.cacheControl && versionString > 0) {
|
||||
headers['Access-Control-Allow-Origin'] = '*'
|
||||
headers['Cache-Control'] = 'public, max-age=2592000, must-revalidate, proxy-revalidate, immutable, stale-while-revalidate=86400, stale-if-error=604800'
|
||||
|
||||
}
|
||||
return res.download(filePath, fileName, { headers })
|
||||
}
|
||||
|
||||
@ -351,7 +351,7 @@ albumsController.generateZip = async (req, res, next) => {
|
||||
else if (album.download === 0)
|
||||
return res.json({ success: false, description: 'Download for this album is disabled.' })
|
||||
|
||||
if ((!versionString || versionString <= 0) && album.editedAt)
|
||||
if ((isNaN(versionString) || versionString <= 0) && album.editedAt)
|
||||
return res.redirect(`${album.identifier}?v=${album.editedAt}`)
|
||||
|
||||
if (album.zipGeneratedAt > album.editedAt) {
|
||||
|
10
package.json
10
package.json
@ -29,9 +29,9 @@
|
||||
"express": "^4.17.1",
|
||||
"express-rate-limit": "^5.0.0",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
"helmet": "^3.20.0",
|
||||
"helmet": "^3.20.1",
|
||||
"jszip": "^3.2.2",
|
||||
"knex": "^0.19.2",
|
||||
"knex": "^0.19.3",
|
||||
"multer": "^1.4.2",
|
||||
"node-fetch": "^2.6.0",
|
||||
"nunjucks": "^3.2.0",
|
||||
@ -42,10 +42,10 @@
|
||||
"sqlite3": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^6.2.2",
|
||||
"eslint-config-standard": "^14.0.1",
|
||||
"eslint": "^6.3.0",
|
||||
"eslint-config-standard": "^14.1.0",
|
||||
"eslint-plugin-import": "^2.18.2",
|
||||
"eslint-plugin-node": "^9.1.0",
|
||||
"eslint-plugin-node": "^9.2.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.1"
|
||||
}
|
||||
|
@ -2,99 +2,8 @@
|
||||
background: none;
|
||||
}
|
||||
|
||||
.message {
|
||||
background-color: #31363b;
|
||||
}
|
||||
|
||||
.message-body {
|
||||
color: #eff0f1;
|
||||
border: 0;
|
||||
-webkit-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);
|
||||
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);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.description {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This is the same sheets used in dashboard.css, minus the on-hover ones.
|
||||
I should probably put this in a file named _thumbs.css, remove the ones in dashboard.css,
|
||||
and use it for both album and dashboard (which means dashboard will have to load an extra css).
|
||||
But oh well, that's something for the future me to think further about.
|
||||
*/
|
||||
|
||||
.image-container {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
margin: 9px;
|
||||
background-color: #31363b;
|
||||
overflow: hidden;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
-webkit-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);
|
||||
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);
|
||||
}
|
||||
|
||||
.image-container .title {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.image-container .image {
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.image-container .file-checkbox {
|
||||
position: absolute;
|
||||
top: .75rem;
|
||||
left: .75rem;
|
||||
}
|
||||
|
||||
.image-container .controls {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
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: 800;
|
||||
}
|
||||
|
@ -94,96 +94,12 @@ li[data-action="page-ellipsis"] {
|
||||
border-left-color: #898b8d;
|
||||
}
|
||||
|
||||
.image-container {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
margin: 9px;
|
||||
background-color: #31363b;
|
||||
overflow: hidden;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
-webkit-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);
|
||||
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);
|
||||
}
|
||||
|
||||
.image-container .title {
|
||||
font-weight: normal;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.image-container .image {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.image-container .image img {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.image-container .checkbox {
|
||||
position: absolute;
|
||||
top: .75rem;
|
||||
left: .75rem;
|
||||
}
|
||||
|
||||
.image-container .controls {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
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: 800;
|
||||
}
|
||||
|
||||
/* Make extra info appear on hover only on non-touch devices */
|
||||
|
||||
.no-touch .image-container .checkbox {
|
||||
opacity: .5;
|
||||
-webkit-transition: opacity .25s;
|
||||
|
@ -106,14 +106,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
.uploads {
|
||||
padding-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.uploads>div {
|
||||
-webkit-animation: fadeInOpacity .5s;
|
||||
animation: fadeInOpacity .5s;
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
.uploads>div:first-child {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.uploads.nojs {
|
||||
@ -211,3 +211,29 @@
|
||||
display: inline-block;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
#urlMaxSize {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.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;
|
||||
-webkit-transition: opacity .25s;
|
||||
transition: opacity .25s;
|
||||
}
|
||||
|
||||
.render.button:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
@ -103,30 +103,24 @@ hr {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.checkbox:hover,
|
||||
.radio:hover {
|
||||
color: #7f8c8d;
|
||||
}
|
||||
|
||||
.progress.is-breeze:indeterminate {
|
||||
background-image: linear-gradient(to right,#60a8dc 30%,#eff0f1 30%);
|
||||
}
|
||||
|
||||
.render {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
font-size: 1rem;
|
||||
color: #bdc3c7;
|
||||
cursor: pointer;
|
||||
.message {
|
||||
background-color: #31363b;
|
||||
}
|
||||
|
||||
.render.button {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
right: 1%;
|
||||
opacity: .25;
|
||||
-webkit-transition: opacity .25s;
|
||||
transition: opacity .25s;
|
||||
}
|
||||
|
||||
.render.button:hover {
|
||||
opacity: 1;
|
||||
.message-body {
|
||||
color: #eff0f1;
|
||||
border: 0;
|
||||
-webkit-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);
|
||||
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);
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeInOpacity {
|
||||
|
81
public/css/thumbs.css
Normal file
81
public/css/thumbs.css
Normal file
@ -0,0 +1,81 @@
|
||||
.image-container {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
margin: 9px;
|
||||
background-color: #31363b;
|
||||
overflow: hidden;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
-webkit-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);
|
||||
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);
|
||||
}
|
||||
|
||||
.image-container .title {
|
||||
font-weight: normal;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.image-container .image {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.image-container .image img {
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.image-container .controls {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
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: bold;
|
||||
}
|
@ -1,25 +1,12 @@
|
||||
/* global LazyLoad */
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const lsKeys = {}
|
||||
|
||||
const page = {
|
||||
lazyLoad: null
|
||||
}
|
||||
|
||||
page.getPrettyBytes = function (num, si) {
|
||||
// MIT License
|
||||
// Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||
if (!Number.isFinite(num)) return num
|
||||
|
||||
const neg = num < 0 ? '-' : ''
|
||||
const scale = si ? 1000 : 1024
|
||||
if (neg) num = -num
|
||||
if (num < scale) return `${neg}${num} B`
|
||||
|
||||
const exponent = Math.min(Math.floor(Math.log10(num) / 3), 8) // 8 is count of KMGTPEZY
|
||||
const numStr = Number((num / Math.pow(scale, exponent)).toPrecision(3))
|
||||
const pre = (si ? 'kMGTPEZY' : 'KMGTPEZY').charAt(exponent - 1) + (si ? '' : 'i')
|
||||
return `${neg}${numStr} ${pre}B`
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
const elements = document.querySelectorAll('.file-size')
|
||||
for (let i = 0; i < elements.length; i++)
|
||||
|
@ -1,8 +1,12 @@
|
||||
/* global swal, axios */
|
||||
|
||||
const lsKeys = {
|
||||
token: 'token'
|
||||
}
|
||||
|
||||
const page = {
|
||||
// user token
|
||||
token: localStorage.token,
|
||||
token: localStorage[lsKeys.token],
|
||||
|
||||
// HTML elements
|
||||
user: null,
|
||||
|
@ -1,6 +1,5 @@
|
||||
/* global swal, axios, ClipboardJS, LazyLoad */
|
||||
|
||||
// keys for localStorage
|
||||
const lsKeys = {
|
||||
token: 'token',
|
||||
viewType: {
|
||||
@ -11,7 +10,9 @@ const lsKeys = {
|
||||
uploads: 'selectedUploads',
|
||||
uploadsAll: 'selectedUploadsAll',
|
||||
users: 'selectedUsers'
|
||||
}
|
||||
},
|
||||
chunkSize: 'chunkSize',
|
||||
parallelUploads: 'parallelUploads'
|
||||
}
|
||||
|
||||
const page = {
|
||||
@ -127,8 +128,9 @@ page.prepareDashboard = function () {
|
||||
document.querySelector('#dashboard').style.display = 'block'
|
||||
|
||||
if (page.permissions.moderator) {
|
||||
document.querySelector('#itemLabelAdmin').style.display = 'block'
|
||||
document.querySelector('#itemListAdmin').style.display = 'block'
|
||||
const itemManageUploads = document.querySelector('#itemManageUploads')
|
||||
itemManageUploads.removeAttribute('disabled')
|
||||
itemManageUploads.addEventListener('click', function () {
|
||||
page.setActiveMenu(this)
|
||||
page.getUploads({ all: true })
|
||||
@ -137,18 +139,19 @@ page.prepareDashboard = function () {
|
||||
|
||||
if (page.permissions.admin) {
|
||||
const itemServerStats = document.querySelector('#itemServerStats')
|
||||
itemServerStats.removeAttribute('disabled')
|
||||
itemServerStats.addEventListener('click', function () {
|
||||
page.setActiveMenu(this)
|
||||
page.getServerStats()
|
||||
})
|
||||
|
||||
const itemManageUsers = document.querySelector('#itemManageUsers')
|
||||
itemManageUsers.removeAttribute('disabled')
|
||||
itemManageUsers.addEventListener('click', function () {
|
||||
page.setActiveMenu(this)
|
||||
page.getUsers()
|
||||
})
|
||||
} else {
|
||||
document.querySelector('#itemServerStats').style.display = 'none'
|
||||
document.querySelector('#itemManageUsers').style.display = 'none'
|
||||
}
|
||||
|
||||
document.querySelector('#itemUploads').addEventListener('click', function () {
|
||||
@ -166,6 +169,11 @@ page.prepareDashboard = function () {
|
||||
page.getAlbums()
|
||||
})
|
||||
|
||||
document.querySelector('#itemBrowserSettings').addEventListener('click', function () {
|
||||
page.setActiveMenu(this)
|
||||
page.browserSettings()
|
||||
})
|
||||
|
||||
document.querySelector('#itemFileLength').addEventListener('click', function () {
|
||||
page.setActiveMenu(this)
|
||||
page.changeFileLength()
|
||||
@ -286,7 +294,7 @@ page.isLoading = function (element, state) {
|
||||
element.classList.remove('is-loading')
|
||||
}
|
||||
|
||||
page.fadeIn = function (content) {
|
||||
page.fadeAndScroll = function (content) {
|
||||
if (page.fadingIn) {
|
||||
clearTimeout(page.fadingIn)
|
||||
page.dom.classList.remove('fade-in')
|
||||
@ -295,10 +303,11 @@ page.fadeIn = function (content) {
|
||||
page.fadingIn = setTimeout(function () {
|
||||
page.dom.classList.remove('fade-in')
|
||||
}, 500)
|
||||
page.dom.scrollIntoView(true)
|
||||
}
|
||||
|
||||
page.switchPage = function (action, element) {
|
||||
const views = { scroll: true }
|
||||
const views = {}
|
||||
let func = null
|
||||
|
||||
if (page.currentView === 'users') {
|
||||
@ -338,7 +347,7 @@ page.focusJumpToPage = function () {
|
||||
element.select()
|
||||
}
|
||||
|
||||
page.getUploads = function ({ pageNum, album, all, filters, scroll } = {}, element) {
|
||||
page.getUploads = function ({ pageNum, album, all, filters } = {}, element) {
|
||||
if (element) page.isLoading(element, true)
|
||||
|
||||
if ((all || filters) && !page.permissions.moderator)
|
||||
@ -497,7 +506,7 @@ page.getUploads = function ({ pageNum, album, all, filters, scroll } = {}, eleme
|
||||
<hr>
|
||||
${pagination}
|
||||
`
|
||||
page.fadeIn()
|
||||
page.fadeAndScroll()
|
||||
|
||||
const table = document.querySelector('#table')
|
||||
|
||||
@ -570,7 +579,7 @@ page.getUploads = function ({ pageNum, album, all, filters, scroll } = {}, eleme
|
||||
<hr>
|
||||
${pagination}
|
||||
`
|
||||
page.fadeIn()
|
||||
page.fadeAndScroll()
|
||||
|
||||
const table = document.querySelector('#table')
|
||||
|
||||
@ -615,8 +624,6 @@ page.getUploads = function ({ pageNum, album, all, filters, scroll } = {}, eleme
|
||||
}
|
||||
}
|
||||
|
||||
if (scroll) page.dom.scrollIntoView(true)
|
||||
|
||||
if (allSelected && files.length) {
|
||||
const selectAll = document.querySelector('#selectAll')
|
||||
if (selectAll) selectAll.checked = true
|
||||
@ -961,7 +968,7 @@ page.deleteByNames = function () {
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
page.fadeIn()
|
||||
page.fadeAndScroll()
|
||||
}
|
||||
|
||||
page.deleteFileByNames = function () {
|
||||
@ -1200,7 +1207,7 @@ page.getAlbums = function () {
|
||||
</table>
|
||||
</div>
|
||||
`
|
||||
page.fadeIn()
|
||||
page.fadeAndScroll()
|
||||
|
||||
const homeDomain = response.data.homeDomain
|
||||
const table = document.querySelector('#table')
|
||||
@ -1458,6 +1465,111 @@ page.getAlbum = function (album) {
|
||||
page.getUploads({ album: album.id })
|
||||
}
|
||||
|
||||
page.browserSettings = function () {
|
||||
const selectionMap = { uploads: 'Selected uploads' }
|
||||
|
||||
if (page.permissions.moderator)
|
||||
selectionMap.uploadsAll = 'Selected uploads (manager)'
|
||||
|
||||
if (page.permissions.admin)
|
||||
selectionMap.users = 'Selected users'
|
||||
|
||||
let selectionSection = ''
|
||||
const keys = Object.keys(selectionMap)
|
||||
for (let i = 0; i < keys.length; i++)
|
||||
selectionSection += `
|
||||
<p>${selectionMap[keys[i]]}: ${page.selected[keys[i]].length}
|
||||
`
|
||||
|
||||
const maxChunkSize = 95
|
||||
const siBytes = localStorage[lsKeys.siBytes] !== '0'
|
||||
|
||||
page.dom.innerHTML = `
|
||||
<h2 class="subtitle">Browser settings</h2>
|
||||
<article class="message has-text-left">
|
||||
<div class="message-body">
|
||||
${selectionSection}
|
||||
</div>
|
||||
</article>
|
||||
<article class="message has-text-left">
|
||||
<div class="message-body">
|
||||
<form class="prevent-default" id="browserSettingsForm">
|
||||
<div class="field">
|
||||
<label class="label">File size unit</label>
|
||||
<div class="control">
|
||||
<label class="radio">
|
||||
<input type="radio" name="siBytes" value="default"${siBytes ? ' checked' : ''}>
|
||||
1 Kilobyte = 1 kB = 1000 B (default)
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label class="radio">
|
||||
<input type="radio" name="siBytes" value="0"${siBytes ? '' : ' checked'}>
|
||||
1 Kibibyte = 1 KiB = 1024 B
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Upload chunk size (MB)</label>
|
||||
<div class="control">
|
||||
<input class="input" type="number" name="chunkSize" min="0" max="${maxChunkSize}" step="5" value="${localStorage[lsKeys.chunkSize] || '0'}">
|
||||
</div>
|
||||
<p class="help">Default is 0, which means to use server's setting. Max is ${maxChunkSize} MB.</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="label">Parallel uploads</label>
|
||||
<div class="control">
|
||||
<input class="input" type="number" name="parallelUploads" min="0" value="${localStorage[lsKeys.parallelUploads] || '0'}">
|
||||
</div>
|
||||
<p class="help">Default is 0, which means to use hard-coded Dropzone setting.</p>
|
||||
</div>
|
||||
<div class="field is-grouped">
|
||||
<p class="control">
|
||||
<button type="submit" id="saveBrowserSettings" class="button is-breeze">
|
||||
Save
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</article>
|
||||
`
|
||||
page.fadeAndScroll()
|
||||
|
||||
document.querySelector('#saveBrowserSettings').addEventListener('click', function () {
|
||||
const form = document.querySelector('#browserSettingsForm')
|
||||
|
||||
const prefKeys = ['siBytes']
|
||||
for (let i = 0; i < prefKeys.length; i++) {
|
||||
const value = form.elements[prefKeys[i]].value
|
||||
if (value !== '0')
|
||||
localStorage.removeItem(lsKeys[prefKeys[i]])
|
||||
else
|
||||
localStorage[lsKeys[prefKeys[i]]] = value
|
||||
}
|
||||
|
||||
const numKeys = ['chunkSize', 'parallelUploads']
|
||||
for (let i = 0; i < numKeys.length; i++) {
|
||||
const parsed = parseInt(form.elements[numKeys[i]].value)
|
||||
let value = isNaN(parsed) ? 0 : Math.max(parsed, 0)
|
||||
if (numKeys[i] === 'chunkSize') value = Math.min(value, maxChunkSize)
|
||||
value = Math.min(value, Number.MAX_SAFE_INTEGER)
|
||||
if (value > 0)
|
||||
localStorage[lsKeys[numKeys[i]]] = value
|
||||
else
|
||||
localStorage.removeItem(lsKeys[numKeys[i]])
|
||||
}
|
||||
|
||||
swal({
|
||||
title: 'Woohoo!',
|
||||
text: 'Browser settings saved.',
|
||||
icon: 'success'
|
||||
}).then(function () {
|
||||
page.browserSettings()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
page.changeFileLength = function () {
|
||||
axios.get('api/filelength/config').then(function (response) {
|
||||
if (response.data.success === false)
|
||||
@ -1496,7 +1608,7 @@ page.changeFileLength = function () {
|
||||
</div>
|
||||
</form>
|
||||
`
|
||||
page.fadeIn()
|
||||
page.fadeAndScroll()
|
||||
|
||||
document.querySelector('#setFileLength').addEventListener('click', function () {
|
||||
page.setFileLength(document.querySelector('#fileLength').value, this)
|
||||
@ -1564,7 +1676,7 @@ page.changeToken = function () {
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
page.fadeIn()
|
||||
page.fadeAndScroll()
|
||||
}).catch(function (error) {
|
||||
console.log(error)
|
||||
return swal('An error occurred!', 'There was an error with the request, please check the console for more information.', 'error')
|
||||
@ -1629,7 +1741,7 @@ page.changePassword = function () {
|
||||
</div>
|
||||
</form>
|
||||
`
|
||||
page.fadeIn()
|
||||
page.fadeAndScroll()
|
||||
|
||||
document.querySelector('#sendChangePassword').addEventListener('click', function () {
|
||||
if (document.querySelector('#password').value === document.querySelector('#passwordConfirm').value)
|
||||
@ -1679,7 +1791,7 @@ page.setActiveMenu = function (activeItem) {
|
||||
activeItem.classList.add('is-active')
|
||||
}
|
||||
|
||||
page.getUsers = function ({ pageNum, scroll } = {}, element) {
|
||||
page.getUsers = function ({ pageNum } = {}, element) {
|
||||
if (element) page.isLoading(element, true)
|
||||
if (pageNum === undefined) pageNum = 0
|
||||
|
||||
@ -1780,7 +1892,7 @@ page.getUsers = function ({ pageNum, scroll } = {}, element) {
|
||||
<hr>
|
||||
${pagination}
|
||||
`
|
||||
page.fadeIn()
|
||||
page.fadeAndScroll()
|
||||
|
||||
const table = document.querySelector('#table')
|
||||
|
||||
@ -1790,9 +1902,10 @@ page.getUsers = function ({ pageNum, scroll } = {}, element) {
|
||||
if (!selected && allSelected) allSelected = false
|
||||
|
||||
let displayGroup = null
|
||||
for (const group of Object.keys(user.groups)) {
|
||||
if (!user.groups[group]) break
|
||||
displayGroup = group
|
||||
const groups = Object.keys(user.groups)
|
||||
for (let i = 0; i < groups.length; i++) {
|
||||
if (!user.groups[groups[i]]) break
|
||||
displayGroup = groups[i]
|
||||
}
|
||||
|
||||
// Server-side explicitly expects either of these two values to consider a user as disabled
|
||||
@ -1842,8 +1955,6 @@ page.getUsers = function ({ pageNum, scroll } = {}, element) {
|
||||
page.checkboxes.users = Array.from(table.querySelectorAll('.checkbox[data-action="select"]'))
|
||||
}
|
||||
|
||||
if (scroll) page.dom.scrollIntoView(true)
|
||||
|
||||
if (allSelected && response.data.users.length) {
|
||||
const selectAll = document.querySelector('#selectAll')
|
||||
if (selectAll) selectAll.checked = true
|
||||
@ -2055,7 +2166,7 @@ page.getServerStats = function (element) {
|
||||
Please wait, this may take a while\u2026
|
||||
<progress class="progress is-breeze" max="100" style="margin-top: 10px"></progress>
|
||||
`
|
||||
page.fadeIn()
|
||||
page.fadeAndScroll()
|
||||
|
||||
const url = 'api/stats'
|
||||
axios.get(url).then(function (response) {
|
||||
@ -2067,39 +2178,42 @@ page.getServerStats = function (element) {
|
||||
}
|
||||
|
||||
let content = ''
|
||||
for (const key of Object.keys(response.data.stats)) {
|
||||
const keys = Object.keys(response.data.stats)
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let rows = ''
|
||||
if (!response.data.stats[key])
|
||||
if (!response.data.stats[keys[i]]) {
|
||||
rows += `
|
||||
<tr>
|
||||
<td>Generating, please try again later\u2026</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
`
|
||||
else
|
||||
for (const valKey of Object.keys(response.data.stats[key])) {
|
||||
const _value = response.data.stats[key][valKey]
|
||||
} else {
|
||||
const valKeys = Object.keys(response.data.stats[keys[i]])
|
||||
for (let j = 0; j < valKeys.length; j++) {
|
||||
const _value = response.data.stats[keys[i]][valKeys[j]]
|
||||
let value = _value
|
||||
if (['albums', 'users', 'uploads'].includes(key))
|
||||
if (['albums', 'users', 'uploads'].includes(keys[i]))
|
||||
value = _value.toLocaleString()
|
||||
if (['memoryUsage', 'size'].includes(valKey))
|
||||
if (['memoryUsage', 'size'].includes(valKeys[j]))
|
||||
value = page.getPrettyBytes(_value)
|
||||
if (valKey === 'systemMemory')
|
||||
if (valKeys[j] === 'systemMemory')
|
||||
value = `${page.getPrettyBytes(_value.used)} / ${page.getPrettyBytes(_value.total)} (${Math.round(_value.used / _value.total * 100)}%)`
|
||||
rows += `
|
||||
<tr>
|
||||
<th>${valKey.replace(/([A-Z])/g, ' $1').toUpperCase()}</th>
|
||||
<th>${valKeys[j].replace(/([A-Z])/g, ' $1').toUpperCase()}</th>
|
||||
<td>${value}</td>
|
||||
</tr>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
content += `
|
||||
<div class="table-container">
|
||||
<table class="table is-fullwidth is-hoverable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>${key.toUpperCase()}</th>
|
||||
<th>${keys[i].toUpperCase()}</th>
|
||||
<td style="width: 50%"></td>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -2116,49 +2230,19 @@ page.getServerStats = function (element) {
|
||||
${content}
|
||||
`
|
||||
|
||||
page.fadeIn()
|
||||
page.fadeAndScroll()
|
||||
})
|
||||
}
|
||||
|
||||
page.getPrettyDate = function (date) {
|
||||
return date.getFullYear() + '-' +
|
||||
(date.getMonth() < 9 ? '0' : '') + // month's index starts from zero
|
||||
(date.getMonth() + 1) + '-' +
|
||||
(date.getDate() < 10 ? '0' : '') +
|
||||
date.getDate() + ' ' +
|
||||
(date.getHours() < 10 ? '0' : '') +
|
||||
date.getHours() + ':' +
|
||||
(date.getMinutes() < 10 ? '0' : '') +
|
||||
date.getMinutes() + ':' +
|
||||
(date.getSeconds() < 10 ? '0' : '') +
|
||||
date.getSeconds()
|
||||
}
|
||||
|
||||
page.getPrettyBytes = function (num, si) {
|
||||
// MIT License
|
||||
// Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||
if (!Number.isFinite(num)) return num
|
||||
|
||||
const neg = num < 0 ? '-' : ''
|
||||
const scale = si ? 1000 : 1024
|
||||
if (neg) num = -num
|
||||
if (num < scale) return `${neg}${num} B`
|
||||
|
||||
const exponent = Math.min(Math.floor(Math.log10(num) / 3), 8) // 8 is count of KMGTPEZY
|
||||
const numStr = Number((num / Math.pow(scale, exponent)).toPrecision(3))
|
||||
const pre = (si ? 'kMGTPEZY' : 'KMGTPEZY').charAt(exponent - 1) + (si ? '' : 'i')
|
||||
return `${neg}${numStr} ${pre}B`
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
// Add 'no-touch' class to non-touch devices
|
||||
if (!('ontouchstart' in document.documentElement))
|
||||
document.documentElement.classList.add('no-touch')
|
||||
|
||||
const selectedKeys = ['uploads', 'uploadsAll', 'users']
|
||||
for (const selectedKey of selectedKeys) {
|
||||
const ls = localStorage[lsKeys.selected[selectedKey]]
|
||||
if (ls) page.selected[selectedKey] = JSON.parse(ls)
|
||||
for (let i = 0; i < selectedKeys.length; i++) {
|
||||
const ls = localStorage[lsKeys.selected[selectedKeys[i]]]
|
||||
if (ls) page.selected[selectedKeys[i]] = JSON.parse(ls)
|
||||
}
|
||||
|
||||
page.preparePage()
|
||||
|
@ -1,8 +1,15 @@
|
||||
/* global swal, axios, Dropzone, ClipboardJS, LazyLoad */
|
||||
|
||||
const lsKeys = {
|
||||
token: 'token',
|
||||
chunkSize: 'chunkSize',
|
||||
parallelUploads: 'parallelUploads',
|
||||
ufBehavior: 'ufBehavior'
|
||||
}
|
||||
|
||||
const page = {
|
||||
// user token
|
||||
token: localStorage.token,
|
||||
token: localStorage[lsKeys.token],
|
||||
|
||||
// configs from api/check
|
||||
private: null,
|
||||
@ -13,6 +20,10 @@ const page = {
|
||||
// store album id that will be used with upload requests
|
||||
album: null,
|
||||
|
||||
maxSizeBytes: null,
|
||||
urlMaxSize: null,
|
||||
urlMaxSizeBytes: null,
|
||||
|
||||
albumSelect: null,
|
||||
previewTemplate: null,
|
||||
|
||||
@ -27,7 +38,8 @@ page.checkIfPublic = function () {
|
||||
axios.get('api/check').then(function (response) {
|
||||
page.private = response.data.private
|
||||
page.enableUserAccounts = response.data.enableUserAccounts
|
||||
page.maxSize = response.data.maxSize
|
||||
page.maxSize = parseInt(response.data.maxSize)
|
||||
page.maxSizeBytes = page.maxSize * 1e6
|
||||
page.chunkSize = response.data.chunkSize
|
||||
page.preparePage()
|
||||
}).catch(function (error) {
|
||||
@ -96,9 +108,14 @@ page.prepareUpload = function () {
|
||||
document.querySelector('#albumDiv').style.display = 'flex'
|
||||
}
|
||||
|
||||
document.querySelector('#maxSize').innerHTML = `Maximum upload size per file is ${page.maxSize}`
|
||||
document.querySelector('#maxSize').innerHTML = `Maximum upload size per file is ${page.getPrettyBytes(page.maxSizeBytes)}`
|
||||
document.querySelector('#loginToUpload').style.display = 'none'
|
||||
|
||||
const urlMaxSize = document.querySelector('#urlMaxSize')
|
||||
page.urlMaxSize = parseInt(urlMaxSize.innerHTML)
|
||||
page.urlMaxSizeBytes = page.urlMaxSize * 1e6
|
||||
urlMaxSize.innerHTML = page.getPrettyBytes(page.urlMaxSizeBytes)
|
||||
|
||||
if (!page.token && page.enableUserAccounts)
|
||||
document.querySelector('#loginLinkText').innerHTML = 'Create an account and keep track of your uploads'
|
||||
|
||||
@ -190,16 +207,16 @@ page.prepareDropzone = function () {
|
||||
`
|
||||
tabDiv.querySelector('.dz-container').appendChild(div)
|
||||
|
||||
const maxSize = parseInt(page.maxSize)
|
||||
const maxSizeBytes = maxSize * 1e6
|
||||
|
||||
const previewsContainer = tabDiv.querySelector('#tab-files .field.uploads')
|
||||
|
||||
const chunkSize = (localStorage[lsKeys.chunkSize] || parseInt(page.chunkSize)) * 1e6
|
||||
const parallelUploads = localStorage[lsKeys.parallelUploads] || 2
|
||||
|
||||
page.dropzone = new Dropzone('#dropzone', {
|
||||
url: 'api/upload',
|
||||
paramName: 'files[]',
|
||||
maxFilesize: maxSizeBytes / 1024 / 1024, // this option expects MiB
|
||||
parallelUploads: 2,
|
||||
maxFilesize: page.maxSizeBytes / 1024 / 1024, // this option expects MiB
|
||||
parallelUploads,
|
||||
uploadMultiple: false,
|
||||
previewsContainer,
|
||||
previewTemplate: page.previewTemplate,
|
||||
@ -207,7 +224,7 @@ page.prepareDropzone = function () {
|
||||
autoProcessQueue: true,
|
||||
headers: { token: page.token },
|
||||
chunking: Boolean(page.chunkSize),
|
||||
chunkSize: (parseInt(page.chunkSize) * 1e6), // the option below expects Bytes
|
||||
chunkSize, // the option below expects Bytes
|
||||
parallelChunkUploads: false, // when set to true, it often hangs with hundreds of parallel uploads
|
||||
chunksUploaded (file, done) {
|
||||
file.previewElement.querySelector('.progress').setAttribute('value', 100)
|
||||
@ -280,7 +297,7 @@ page.prepareDropzone = function () {
|
||||
page.dropzone.on('error', function (file, error) {
|
||||
if ((typeof error === 'string' && /^File is too big/.test(error)) ||
|
||||
error.description === 'MulterError: File too large')
|
||||
error = `File too large (${(file.size / 1e6).toFixed(2)}MB).`
|
||||
error = `File too large (${page.getPrettyBytes(file.size)}).`
|
||||
page.updateTemplateIcon(file.previewElement, 'icon-block')
|
||||
file.previewElement.querySelector('.progress').style.display = 'none'
|
||||
file.previewElement.querySelector('.name').innerHTML = file.name
|
||||
@ -475,8 +492,9 @@ page.createAlbum = function () {
|
||||
// Handle image paste event
|
||||
window.addEventListener('paste', function (event) {
|
||||
const items = (event.clipboardData || event.originalEvent.clipboardData).items
|
||||
for (const index in items) {
|
||||
const item = items[index]
|
||||
const index = Object.keys(items)
|
||||
for (let i = 0; i < index.length; i++) {
|
||||
const item = items[index[i]]
|
||||
if (item.kind === 'file') {
|
||||
const blob = item.getAsFile()
|
||||
const file = new File([blob], `pasted-image.${blob.type.match(/(?:[^/]*\/)([^;]*)/)[1]}`)
|
||||
|
@ -1,4 +1,7 @@
|
||||
/* global page, swal */
|
||||
/* global lsKeys, page, swal */
|
||||
|
||||
// keys for localStorage
|
||||
lsKeys.render = 'render'
|
||||
|
||||
page.renderType = 'miku'
|
||||
page.renderConfig = {
|
||||
@ -66,7 +69,7 @@ page.doRenderSwal = function () {
|
||||
<div class="field">
|
||||
<div class="control">
|
||||
<label class="checkbox">
|
||||
<input id="swalRender" type="checkbox" ${localStorage.render === '0' ? '' : 'checked'}>
|
||||
<input id="swalRender" type="checkbox" ${localStorage[lsKeys.render] === '0' ? '' : 'checked'}>
|
||||
Enable random render of ${page.config.name}
|
||||
</label>
|
||||
</div>
|
||||
@ -82,8 +85,11 @@ page.doRenderSwal = function () {
|
||||
}).then(function (value) {
|
||||
if (!value) return
|
||||
const newValue = div.querySelector('#swalRender').checked ? undefined : '0'
|
||||
if (newValue !== localStorage.render) {
|
||||
newValue ? localStorage.render = newValue : localStorage.removeItem('render')
|
||||
if (newValue !== localStorage[lsKeys.render]) {
|
||||
if (newValue)
|
||||
localStorage[lsKeys.render] = newValue
|
||||
else
|
||||
localStorage.removeItem(lsKeys.render)
|
||||
swal('Success!', `Random render is now ${newValue ? 'disabled' : 'enabled'}.`, 'success')
|
||||
const element = document.querySelector('body > .render')
|
||||
element.remove()
|
||||
@ -104,7 +110,7 @@ page.doRender = function () {
|
||||
if (!page.config || !page.config.array.length) return
|
||||
|
||||
let element
|
||||
if (localStorage.render === '0') {
|
||||
if (localStorage[lsKeys.render] === '0') {
|
||||
element = document.createElement('a')
|
||||
element.className = 'button is-breeze is-hidden-mobile'
|
||||
element.title = page.config.name
|
58
public/js/s/utils.js
Normal file
58
public/js/s/utils.js
Normal file
@ -0,0 +1,58 @@
|
||||
/* global lsKeys, page */
|
||||
|
||||
// keys for localStorage
|
||||
lsKeys.siBytes = 'siBytes'
|
||||
|
||||
page.prepareShareX = function () {
|
||||
if (!page.token) return
|
||||
const origin = (location.hostname + location.pathname).replace(/\/(dashboard)?$/, '')
|
||||
const originClean = origin.replace(/\//g, '_')
|
||||
const sharexElement = document.querySelector('#ShareX')
|
||||
const sharexFile = `{
|
||||
"Name": "${originClean}",
|
||||
"DestinationType": "ImageUploader, FileUploader",
|
||||
"RequestType": "POST",
|
||||
"RequestURL": "${location.protocol}//${origin}/api/upload",
|
||||
"FileFormName": "files[]",
|
||||
"Headers": {
|
||||
"token": "${page.token}"
|
||||
},
|
||||
"ResponseType": "Text",
|
||||
"URL": "$json:files[0].url$",
|
||||
"ThumbnailURL": "$json:files[0].url$"
|
||||
}\n`
|
||||
const sharexBlob = new Blob([sharexFile], { type: 'application/octet-binary' })
|
||||
sharexElement.setAttribute('href', URL.createObjectURL(sharexBlob))
|
||||
sharexElement.setAttribute('download', `${originClean}.sxcu`)
|
||||
}
|
||||
|
||||
page.getPrettyDate = function (date) {
|
||||
return date.getFullYear() + '-' +
|
||||
(date.getMonth() < 9 ? '0' : '') + // month's index starts from zero
|
||||
(date.getMonth() + 1) + '-' +
|
||||
(date.getDate() < 10 ? '0' : '') +
|
||||
date.getDate() + ' ' +
|
||||
(date.getHours() < 10 ? '0' : '') +
|
||||
date.getHours() + ':' +
|
||||
(date.getMinutes() < 10 ? '0' : '') +
|
||||
date.getMinutes() + ':' +
|
||||
(date.getSeconds() < 10 ? '0' : '') +
|
||||
date.getSeconds()
|
||||
}
|
||||
|
||||
page.getPrettyBytes = function (num) {
|
||||
// MIT License
|
||||
// Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||
if (!Number.isFinite(num)) return num
|
||||
|
||||
const si = localStorage[lsKeys.siBytes] !== '0'
|
||||
const neg = num < 0 ? '-' : ''
|
||||
const scale = si ? 1000 : 1024
|
||||
if (neg) num = -num
|
||||
if (num < scale) return `${neg}${num} B`
|
||||
|
||||
const exponent = Math.min(Math.floor(Math.log10(num) / 3), 8) // 8 is count of KMGTPEZY
|
||||
const numStr = Number((num / Math.pow(scale, exponent)).toPrecision(3))
|
||||
const pre = (si ? 'kMGTPEZY' : 'KMGTPEZY').charAt(exponent - 1) + (si ? '' : 'i')
|
||||
return `${neg}${numStr} ${pre}B`
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
/* global page */
|
||||
|
||||
page.prepareShareX = function () {
|
||||
if (!page.token) return
|
||||
const origin = (location.hostname + location.pathname).replace(/\/(dashboard)?$/, '')
|
||||
const originClean = origin.replace(/\//g, '_')
|
||||
const sharexElement = document.querySelector('#ShareX')
|
||||
const sharexFile = `{
|
||||
"Name": "${originClean}",
|
||||
"DestinationType": "ImageUploader, FileUploader",
|
||||
"RequestType": "POST",
|
||||
"RequestURL": "${location.protocol}//${origin}/api/upload",
|
||||
"FileFormName": "files[]",
|
||||
"Headers": {
|
||||
"token": "${page.token}"
|
||||
},
|
||||
"ResponseType": "Text",
|
||||
"URL": "$json:files[0].url$",
|
||||
"ThumbnailURL": "$json:files[0].url$"
|
||||
}\n`
|
||||
const sharexBlob = new Blob([sharexFile], { type: 'application/octet-binary' })
|
||||
sharexElement.setAttribute('href', URL.createObjectURL(sharexBlob))
|
||||
sharexElement.setAttribute('download', `${originClean}.sxcu`)
|
||||
}
|
@ -64,7 +64,8 @@ routes.get('/a/:identifier', async (req, res, next) => {
|
||||
downloadLink: album.download === 0 ? null : `../api/album/zip/${album.identifier}?v=${album.editedAt}`,
|
||||
editedAt: album.editedAt,
|
||||
url: `${homeDomain}/a/${album.identifier}`,
|
||||
totalSize
|
||||
totalSize,
|
||||
nojs: req.query.nojs !== undefined
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
v3: CSS and JS files (libs such as bulma, lazyload, etc).
|
||||
v4: Renders in /public/render/* directories (to be used by render.js).
|
||||
#}
|
||||
{% set v1 = "UOoSqCmggh" %}
|
||||
{% set v1 = "Jlu03caLZN" %}
|
||||
{% set v2 = "hiboQUzAzp" %}
|
||||
{% set v3 = "f0nYw5J15T" %}
|
||||
{% set v4 = "S3TAWpPeFS" %}
|
||||
@ -58,6 +58,15 @@
|
||||
},
|
||||
icon: 'icon-sharex icon-2x'
|
||||
},
|
||||
{
|
||||
attrs: {
|
||||
title: 'Firefox extension',
|
||||
href: 'https://addons.mozilla.org/en-US/firefox/addon/lolisafe/',
|
||||
target: '_blank',
|
||||
rel: 'noopener'
|
||||
},
|
||||
icon: 'icon-firefox icon-2x'
|
||||
},
|
||||
{
|
||||
attrs: {
|
||||
title: 'Chrome extension',
|
||||
@ -67,15 +76,6 @@
|
||||
},
|
||||
icon: 'icon-chrome icon-2x'
|
||||
},
|
||||
{
|
||||
attrs: {
|
||||
title: 'Firefox extension',
|
||||
href: 'https://github.com/BobbyWibowo/loli-safe-extension/releases',
|
||||
target: '_blank',
|
||||
rel: 'noopener'
|
||||
},
|
||||
icon: 'icon-firefox icon-2x'
|
||||
},
|
||||
{
|
||||
attrs: {
|
||||
title: 'Bash uploader',
|
||||
|
@ -4,13 +4,17 @@
|
||||
<!-- Stylesheets -->
|
||||
<link rel="stylesheet" href="../libs/bulma/bulma.min.css?v={{ globals.v3 }}">
|
||||
<link rel="stylesheet" href="../css/style.css?v={{ globals.v1 }}">
|
||||
<link rel="stylesheet" href="../css/thumbs.css?v={{ globals.v1 }}">
|
||||
<link rel="stylesheet" href="../css/album.css?v={{ globals.v1 }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{% if not nojs -%}
|
||||
<!-- Scripts -->
|
||||
<script src="../libs/lazyload/lazyload.min.js?v={{ globals.v3 }}"></script>
|
||||
<script src="../js/album.js?v={{ globals.v1 }}"></script>
|
||||
<script src="../js/s/utils.js?v={{ globals.v1 }}"></script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block opengraph %}
|
||||
@ -59,25 +63,34 @@
|
||||
</div>
|
||||
{%- endif %}
|
||||
</nav>
|
||||
|
||||
{% if description -%}
|
||||
<h2 class="subtitle description">
|
||||
{{ description | safe }}
|
||||
</h2>
|
||||
{%- endif %}
|
||||
<hr>
|
||||
|
||||
{% if nojs -%}
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
<p>You are viewing No-JS version of this album, so file size will be displayed in bytes.</p>
|
||||
<p>Please <a href="{{ url }}">click here</a> if you want to its regular version.</p>
|
||||
</div>
|
||||
</article>
|
||||
{%- endif %}
|
||||
|
||||
{% if files.length -%}
|
||||
<div id="table" class="columns is-multiline is-mobile is-centered has-text-centered">
|
||||
{% for file in files %}
|
||||
<div class="image-container column is-narrow">
|
||||
<a class="image" href="{{ file.file }}" target="_blank" rel="noopener">
|
||||
{% if file.thumb -%}
|
||||
<img alt="{{ file.name }}" data-src="{{ file.thumb }}">
|
||||
{#-
|
||||
This will kinda increase the overall page size,
|
||||
but this will still benefit users with JavaScript enabled by lazyloading images,
|
||||
and not causing those who have JavaScript disabled be unable to view the images.
|
||||
#}
|
||||
<noscript><img alt="{{ file.name }}" src="{{ file.thumb }}" style="display: none"></noscript>
|
||||
{% if nojs -%}
|
||||
<img alt="{{ file.name }}" src="{{ file.thumb }}">
|
||||
{%- else -%}
|
||||
<img alt="{{ file.name }}" data-src="{{ file.thumb }}">
|
||||
{%- endif %}
|
||||
{%- else -%}
|
||||
<h1 class="title">{{ file.extname | default('N/A') }}</h1>
|
||||
{%- endif %}
|
||||
@ -99,11 +112,17 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# Hide lazyload img tags and show noscript img tags #}
|
||||
{% if not nojs -%}
|
||||
<noscript>
|
||||
<style>
|
||||
img[data-src] { display: none; }
|
||||
img[src] { display: block !important; }
|
||||
</style>
|
||||
<style>body > section:not(#noscript) { display: none !important; }</style>
|
||||
<section id="noscript" class="hero is-fullheight">
|
||||
<div class="hero-body">
|
||||
<div class="container has-text-centered">
|
||||
<p>You have JavaScript disabled, but this page requires JavaScript to function.</p>
|
||||
<p>Please <a href="{{ url }}?nojs">click here</a> if you want to view its No-JS version.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</noscript>
|
||||
{%- endif %}
|
||||
{% endblock %}
|
||||
|
@ -4,6 +4,7 @@
|
||||
{{ super() }}
|
||||
<link rel="stylesheet" href="libs/fontello/fontello.css?v={{ globals.v3 }}">
|
||||
<link rel="stylesheet" href="css/sweetalert.css?v={{ globals.v1 }}">
|
||||
<link rel="stylesheet" href="css/thumbs.css?v={{ globals.v1 }}">
|
||||
<link rel="stylesheet" href="css/dashboard.css?v={{ globals.v1 }}">
|
||||
{% endblock %}
|
||||
|
||||
@ -14,7 +15,7 @@
|
||||
<script src="libs/clipboard.js/clipboard.min.js?v={{ globals.v3 }}"></script>
|
||||
<script src="libs/lazyload/lazyload.min.js?v={{ globals.v3 }}"></script>
|
||||
<script src="js/dashboard.js?v={{ globals.v1 }}"></script>
|
||||
<script src="js/sharex.js?v={{ globals.v1 }}"></script>
|
||||
<script src="js/s/utils.js?v={{ globals.v1 }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@ -53,16 +54,16 @@
|
||||
<ul id="albumsContainer"></ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="menu-label">Administration</p>
|
||||
<ul class="menu-list">
|
||||
<p id="itemLabelAdmin" class="menu-label" style="display: none">Administration</p>
|
||||
<ul id="itemListAdmin" class="menu-list" style="display: none">
|
||||
<li>
|
||||
<a id="itemServerStats" disabled>Statistics</a>
|
||||
<a id="itemServerStats">Statistics</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="itemManageUploads" disabled>Manage uploads</a>
|
||||
<a id="itemManageUploads">Manage uploads</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="itemManageUsers" disabled>Manage users</a>
|
||||
<a id="itemManageUsers">Manage users</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="menu-label">Configuration</p>
|
||||
@ -70,6 +71,9 @@
|
||||
<li>
|
||||
<a id="ShareX">ShareX user profile</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="itemBrowserSettings">Browser settings</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="itemFileLength">File name length</a>
|
||||
</li>
|
||||
|
@ -1,21 +1,5 @@
|
||||
{% extends "_layout.njk" %}
|
||||
|
||||
{% block stylesheets %}
|
||||
{{ super() }}
|
||||
<style>
|
||||
.message {
|
||||
background-color: #31363b;
|
||||
}
|
||||
|
||||
.message-body {
|
||||
color: #eff0f1;
|
||||
border: 0;
|
||||
-webkit-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);
|
||||
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);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{{ super() }}
|
||||
<section class="section">
|
||||
@ -23,7 +7,7 @@
|
||||
<h2 class='subtitle'>What is safe.fiery.me?</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
safe.fiery.me is a fork of <a href="https://github.com/WeebDev/lolisafe" target="_blank" rel="noopener">lolisafe</a>. You can check out the fork <a href="https://github.com/BobbyWibowo/lolisafe" target="_blank" rel="noopener">here</a>.
|
||||
This is a fork of <a href="https://github.com/WeebDev/lolisafe" target="_blank" rel="noopener">lolisafe</a>. GitHub repository of the fork is located <a href="https://github.com/BobbyWibowo/lolisafe" target="_blank" rel="noopener">here</a>.
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@ -45,9 +29,9 @@
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
Albums are a simple way of sorting uploads together.<br>
|
||||
Right now you can create albums through the dashboard (and the homepage if you are logged in),<br>
|
||||
then afterwards you can use them with our <a href="https://chrome.google.com/webstore/detail/loli-safe-uploader/enkkmplljfjppcdaancckgilmgoiofnj" target="_blank" rel="noopener">Chrome extension</a> or <a href="https://github.com/BobbyWibowo/loli-safe-extension/releases" target="_blank" rel="noopener">Firefox extension</a>,<br>
|
||||
which will enable you to <strong>right click -> send to safe</strong> or to a desired album if you have any.<br>
|
||||
As long as you are logged in, you can create albums through the homepage or the dashboard,<br>
|
||||
then afterwards you can use them with our <a href="https://addons.mozilla.org/en-US/firefox/addon/lolisafe/" target="_blank" rel="noopener">Firefox extension</a> or <a href="https://chrome.google.com/webstore/detail/loli-safe-uploader/enkkmplljfjppcdaancckgilmgoiofnj" target="_blank" rel="noopener">Chrome extension</a>,<br>
|
||||
which will enable you to <strong>right click -> send file to safe</strong> or to a desired album if you have any.<br>
|
||||
You will have to set the domain in the extension's settings to <strong>https://safe.fiery.me</strong> though.
|
||||
</div>
|
||||
</article>
|
||||
@ -66,39 +50,53 @@
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<h2 class='subtitle'>I found a bug! -or- I want to request a feature!</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
Feel free to create a GitHub issue <a href="https://github.com/BobbyWibowo/lolisafe/issues/new/choose" target="_blank" rel="noopener">here</a>.</br>
|
||||
Or if you don't want to use GitHub, then you can also contact me through my email above.
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<h2 class='subtitle'>Where is the server located at?</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
Paris, France.<br>
|
||||
Expect high First Time Byte (FTB) everywhere else, especially anywhere on the other side of the planet Earth (generally can be over 1000ms).<br>
|
||||
I believe it is mostly due to the fact that we are using Cloudflare, since your requests have to go through them first.<br>
|
||||
However, since Cloudflare will cache your uploads too, the uploads should have much better FTB afterwards (and generally faster download speed too).
|
||||
We are using Cloudflare though, so you can expect your uploads to be delivered quickly all over the world after they have been cached.
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<h2 class='subtitle'>Since my uploads are being cached, what about after I delete them from the dashboard?</h2>
|
||||
<h2 class='subtitle'>Since my uploads are cached, what about after I delete them from the dashboard?</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
No need to worry.<br>
|
||||
We will send API requests to Cloudflare to purge their cache immediately after you delete your uploads from the dashboard.<br>
|
||||
Cache of thumbnails will also be purged, so no need to worry about them either.
|
||||
Cache of their thumbnails will also be purged, if applicable.
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<h2 class='subtitle'>Do you have a No-JS uploader form?</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
Yes, check out <a href="nojs" target="_blank" rel="noopener">this page</a>.<br>
|
||||
Unfortunately you will not be able to associate your uploads to your account, if you have any.
|
||||
Yes, check out <a href="nojs" target="_blank" rel="noopener">this page</a>.
|
||||
</div>
|
||||
</article>
|
||||
|
||||
{% if noJsMaxSize and chunkSize -%}
|
||||
<h2 class='subtitle'>Why is the maximum file size in the No-JS uploader form smaller?</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
This site is using Cloudflare, which limits the maximum upload size.<br>
|
||||
Since the homepage uploader chunks your uploads through JS magic, it is possible to increase the maximum file size there.
|
||||
</div>
|
||||
</article>
|
||||
{%- endif %}
|
||||
|
||||
{% if chunkSize -%}
|
||||
<h2 class='subtitle'>Does your API support chunked uploads?</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
Yes, the homepage uploader will chunk your uploads into {{ chunkSize }} pieces by default.<br>
|
||||
If you want to utilize chunked uploads with the API, then feel free to inspect the HTTP requests.
|
||||
Yes, the homepage uploader is hard-coded to chunk uploads into {{ chunkSize }} pieces by default.<br>
|
||||
If you want to chunk your API uploads, feel free to read the source code to see how it works.
|
||||
</div>
|
||||
</article>
|
||||
{%- endif %}
|
||||
@ -116,26 +114,16 @@
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<h2 class='subtitle'>How are the file URLs going to be determined?</h2>
|
||||
<h2 class='subtitle'>How are the file URLs be determined?</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
Random {{ fileLength.default }}-letter strings will automatically be generated for your uploads.
|
||||
The safe will generate random {{ fileLength.default }}-letter identifiers.
|
||||
{% if fileLength.userChangeable %}<br>
|
||||
If you think that is too {{ "short" if tooShort else "long" }}, you can create an account, which will let you to set a preferred length.<br>
|
||||
At the moment you can choose from {{ fileLength.min }} to {{ fileLength.max }} letters.
|
||||
If you find that too {{ "short" if tooShort else "long" }}, you can create an account which will let you to set your preferred length.<br>
|
||||
You can choose from {{ fileLength.min }} to {{ fileLength.max }} letters.
|
||||
{%- endif %}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
{% if noJsMaxSize and chunkSize -%}
|
||||
<h2 class='subtitle'>Why is the maximum file size in the No-JS uploader form smaller?</h2>
|
||||
<article class="message">
|
||||
<div class="message-body">
|
||||
This site is using Cloudflare, which limits the maximum upload size.<br>
|
||||
The homepage uploader will automatically chunk your uploads into {{ chunkSize }} pieces, so it is possible to increase the maximum file size there, but not in the No-JS uploader form.
|
||||
</div>
|
||||
</article>
|
||||
{%- endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
@ -22,9 +22,9 @@
|
||||
<script src="libs/clipboard.js/clipboard.min.js?v={{ globals.v3 }}"></script>
|
||||
<script src="libs/lazyload/lazyload.min.js?v={{ globals.v3 }}"></script>
|
||||
<script src="js/home.js?v={{ globals.v1 }}"></script>
|
||||
<script src="js/sharex.js?v={{ globals.v1 }}"></script>
|
||||
<script src="js/s/utils.js?v={{ globals.v1 }}"></script>
|
||||
<!-- We assign an ID for this so that the script can find out version string for render images -->
|
||||
<script id="renderScript" data-version="{{ globals.v4 }}" src="js/render.js?v={{ globals.v1 }}"></script>
|
||||
<script id="renderScript" data-version="{{ globals.v4 }}" src="js/s/render.js?v={{ globals.v1 }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@ -66,7 +66,7 @@
|
||||
{%- endif %}
|
||||
<div id="tab-files" class="tab-content" style="display: none">
|
||||
<div class="field dz-container"></div>
|
||||
<div class="field uploads" style="display: none"></div>
|
||||
<div class="field uploads"></div>
|
||||
</div>
|
||||
{% if urlMaxSize -%}
|
||||
<div id="tab-urls" class="tab-content" style="display: none">
|
||||
@ -76,7 +76,7 @@
|
||||
</div>
|
||||
<p class="help">
|
||||
{% if urlMaxSize !== maxSize -%}
|
||||
Maximum file size for URL upload is <span style="font-weight: bold">{{ urlMaxSize }}</span>.
|
||||
Maximum file size for URL upload is <span id="urlMaxSize">{{ urlMaxSize }}</span>.
|
||||
{%- endif %}
|
||||
|
||||
{% if urlExtensionsFilter.length and (urlExtensionsFilterMode === 'blacklist') -%}
|
||||
@ -100,7 +100,7 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field uploads" style="display: none"></div>
|
||||
<div class="field uploads"></div>
|
||||
</div>
|
||||
{%- endif %}
|
||||
</div>
|
||||
@ -112,7 +112,7 @@
|
||||
<i class="icon" style="display: none"></i>
|
||||
<img class="is-unselectable" style="display: none">
|
||||
<p class="name is-unselectable"></p>
|
||||
<progress class="progress is-small is-danger" value="0" max="100">0%</progress>
|
||||
<progress class="progress is-small is-danger" max="100"></progress>
|
||||
<p class="error"></p>
|
||||
<p class="link">
|
||||
<a target="_blank" rel="noopener"></a>
|
||||
|
118
yarn.lock
118
yarn.lock
@ -288,6 +288,11 @@ body-parser@1.19.0, body-parser@^1.19.0:
|
||||
raw-body "2.4.0"
|
||||
type-is "~1.6.17"
|
||||
|
||||
bowser@2.5.3:
|
||||
version "2.5.3"
|
||||
resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.5.3.tgz#811b0a24219c566c9a6ab3402bc8a13f35a18a96"
|
||||
integrity sha512-aWCA+CKfKNL/WGzNgjmK+Whp57JMzboZMwJ5gy2jDj2bEIjbMCb3ImGX+V++5wsJftyFiDIbOjRXl60ycniVqg==
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
@ -503,10 +508,10 @@ color@^3.1.2:
|
||||
color-convert "^1.9.1"
|
||||
color-string "^1.5.2"
|
||||
|
||||
colorette@1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.0.8.tgz#421ff11c80b7414027ebed922396bc1833d1903c"
|
||||
integrity sha512-X6Ck90ReaF+EfKdVGB7vdIQ3dr651BbIrBwY5YBKg13fjH+940sTtp7/Pkx33C6ntYfQcRumOs/aUQhaRPpbTQ==
|
||||
colorette@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.1.0.tgz#1f943e5a357fac10b4e0f5aaef3b14cdc1af6ec7"
|
||||
integrity sha512-6S062WDQUXi6hOfkO/sBPVwE5ASXY4G2+b4atvhJfSsuUUhIaUKlkjLe9692Ipyt5/a+IPF5aVTu3V5gvXq5cg==
|
||||
|
||||
combined-stream@^1.0.6, combined-stream@~1.0.6:
|
||||
version "1.0.8"
|
||||
@ -823,10 +828,10 @@ escape-string-regexp@^1.0.5:
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
|
||||
|
||||
eslint-config-standard@^14.0.1:
|
||||
version "14.0.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.0.1.tgz#375c3636fb4bd453cb95321d873de12e4eef790b"
|
||||
integrity sha512-1RWsAKTDTZgA8bIM6PSC9aTGDAUlKqNkYNJlTZ5xYD/HYkIM6GlcefFvgcJ8xi0SWG5203rttKYX28zW+rKNOg==
|
||||
eslint-config-standard@^14.1.0:
|
||||
version "14.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.0.tgz#b23da2b76fe5a2eba668374f246454e7058f15d4"
|
||||
integrity sha512-EF6XkrrGVbvv8hL/kYa/m6vnvmUT+K82pJJc4JJVMM6+Qgqh0pnwprSxdduDLB9p/7bIxD+YV5O0wfb8lmcPbA==
|
||||
|
||||
eslint-import-resolver-node@^0.3.2:
|
||||
version "0.3.2"
|
||||
@ -844,12 +849,12 @@ eslint-module-utils@^2.4.0:
|
||||
debug "^2.6.8"
|
||||
pkg-dir "^2.0.0"
|
||||
|
||||
eslint-plugin-es@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-1.4.0.tgz#475f65bb20c993fc10e8c8fe77d1d60068072da6"
|
||||
integrity sha512-XfFmgFdIUDgvaRAlaXUkxrRg5JSADoRC8IkKLc/cISeR3yHVMefFHQZpcyXXEUUPHfy5DwviBcrfqlyqEwlQVw==
|
||||
eslint-plugin-es@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-1.4.1.tgz#12acae0f4953e76ba444bfd1b2271081ac620998"
|
||||
integrity sha512-5fa/gR2yR3NxQf+UXkeLeP8FBBl6tSgdrAz1+cF84v1FMM4twGwQoqTnn+QxFLcPOrF4pdKEJKDB/q9GoyJrCA==
|
||||
dependencies:
|
||||
eslint-utils "^1.3.0"
|
||||
eslint-utils "^1.4.2"
|
||||
regexpp "^2.0.1"
|
||||
|
||||
eslint-plugin-import@^2.18.2:
|
||||
@ -869,13 +874,13 @@ eslint-plugin-import@^2.18.2:
|
||||
read-pkg-up "^2.0.0"
|
||||
resolve "^1.11.0"
|
||||
|
||||
eslint-plugin-node@^9.1.0:
|
||||
version "9.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-9.1.0.tgz#f2fd88509a31ec69db6e9606d76dabc5adc1b91a"
|
||||
integrity sha512-ZwQYGm6EoV2cfLpE1wxJWsfnKUIXfM/KM09/TlorkukgCAwmkgajEJnPCmyzoFPQQkmvo5DrW/nyKutNIw36Mw==
|
||||
eslint-plugin-node@^9.2.0:
|
||||
version "9.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-9.2.0.tgz#b1911f111002d366c5954a6d96d3cd5bf2a3036a"
|
||||
integrity sha512-2abNmzAH/JpxI4gEOwd6K8wZIodK3BmHbTxz4s79OIYwwIt2gkpEXlAouJXu4H1c9ySTnRso0tsuthSOZbUMlA==
|
||||
dependencies:
|
||||
eslint-plugin-es "^1.4.0"
|
||||
eslint-utils "^1.3.1"
|
||||
eslint-plugin-es "^1.4.1"
|
||||
eslint-utils "^1.4.2"
|
||||
ignore "^5.1.1"
|
||||
minimatch "^3.0.4"
|
||||
resolve "^1.10.1"
|
||||
@ -899,7 +904,7 @@ eslint-scope@^5.0.0:
|
||||
esrecurse "^4.1.0"
|
||||
estraverse "^4.1.1"
|
||||
|
||||
eslint-utils@^1.3.0, eslint-utils@^1.3.1, eslint-utils@^1.4.2:
|
||||
eslint-utils@^1.4.2:
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab"
|
||||
integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==
|
||||
@ -911,10 +916,10 @@ eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
|
||||
integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
|
||||
|
||||
eslint@^6.2.2:
|
||||
version "6.2.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.2.2.tgz#03298280e7750d81fcd31431f3d333e43d93f24f"
|
||||
integrity sha512-mf0elOkxHbdyGX1IJEUsNBzCDdyoUgljF3rRlgfyYh0pwGnreLc0jjD6ZuleOibjmnUWZLY2eXwSooeOgGJ2jw==
|
||||
eslint@^6.3.0:
|
||||
version "6.3.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.3.0.tgz#1f1a902f67bfd4c354e7288b81e40654d927eb6a"
|
||||
integrity sha512-ZvZTKaqDue+N8Y9g0kp6UPZtS4FSY3qARxBs7p4f0H0iof381XHduqVerFWtK8DPtKmemqbqCFENWSQgPR/Gow==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
ajv "^6.10.0"
|
||||
@ -1335,10 +1340,10 @@ get-value@^2.0.3, get-value@^2.0.6:
|
||||
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
|
||||
integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
|
||||
|
||||
getopts@2.2.4:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.4.tgz#3137fe8a5fddf304904059a851bdc1c22f0f54fb"
|
||||
integrity sha512-Rz7DGyomZjrenu9Jx4qmzdlvJgvrEFHXHvjK0FcZtcTC1U5FmES7OdZHUwMuSnEE6QvBvwse1JODKj7TgbSEjQ==
|
||||
getopts@2.2.5:
|
||||
version "2.2.5"
|
||||
resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.5.tgz#67a0fe471cacb9c687d817cab6450b96dde8313b"
|
||||
integrity sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA==
|
||||
|
||||
getpass@^0.1.1:
|
||||
version "0.1.7"
|
||||
@ -1480,20 +1485,20 @@ helmet-crossdomain@0.4.0:
|
||||
resolved "https://registry.yarnpkg.com/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz#5f1fe5a836d0325f1da0a78eaa5fd8429078894e"
|
||||
integrity sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA==
|
||||
|
||||
helmet-csp@2.8.0:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.8.0.tgz#746d329e24ef39c4ebc00278a48abd3c209e0378"
|
||||
integrity sha512-MlCPeM0Sm3pS9RACRihx70VeTHmkQwa7sum9EK1tfw1VZyvFU0dBWym9nHh3CRkTRNlyNm/WFCMvuh9zXkOjNw==
|
||||
helmet-csp@2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.9.0.tgz#8524886b08c7f7d611cb5f36eae453dd604efd4c"
|
||||
integrity sha512-DGGOQtOLM7ZQpjbf/uvUonq1yG/rFgsBuK10ZJt2AtxUJxqfkPvfmP9aLUmgH9IactiRiYoiFY72YYSPl1TLTQ==
|
||||
dependencies:
|
||||
bowser "2.5.3"
|
||||
camelize "1.0.0"
|
||||
content-security-policy-builder "2.1.0"
|
||||
dasherize "2.0.0"
|
||||
platform "1.3.5"
|
||||
|
||||
helmet@^3.20.0:
|
||||
version "3.20.0"
|
||||
resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.20.0.tgz#8a9383bf8230a461cafe8bc763423fbde110d2fc"
|
||||
integrity sha512-Ob+TqmQFZ5f7WgP8kBbAzNPsbf6p1lOj5r+327/ymw/IILWih3wcx9u/u/S8Mwv5wbBkO7Li6x5s23t3COhUKw==
|
||||
helmet@^3.20.1:
|
||||
version "3.20.1"
|
||||
resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.20.1.tgz#802fcb39ac6865208cbc6879d3502e582c6f777e"
|
||||
integrity sha512-em+X5Wz/f0yqoRsBnpnVy3wJHSiIeskX3FQn30szBh1tILaOeSRRLkShuUVFlk/o4qTYjWxdHg4FrRe45iBWHg==
|
||||
dependencies:
|
||||
depd "2.0.0"
|
||||
dns-prefetch-control "0.2.0"
|
||||
@ -1502,7 +1507,7 @@ helmet@^3.20.0:
|
||||
feature-policy "0.3.0"
|
||||
frameguard "3.1.0"
|
||||
helmet-crossdomain "0.4.0"
|
||||
helmet-csp "2.8.0"
|
||||
helmet-csp "2.9.0"
|
||||
hide-powered-by "1.1.0"
|
||||
hpkp "2.0.0"
|
||||
hsts "2.2.0"
|
||||
@ -1975,25 +1980,25 @@ kind-of@^6.0.0, kind-of@^6.0.2:
|
||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
|
||||
integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
|
||||
|
||||
knex@^0.19.2:
|
||||
version "0.19.2"
|
||||
resolved "https://registry.yarnpkg.com/knex/-/knex-0.19.2.tgz#056efdb33fb8c77d3d76266b5d1d12dc483c21b5"
|
||||
integrity sha512-TVYvlp2esS4LjjJSz8XuE48bPJq4N3lWnETQVgJ3hXPEqjiDjxcTa3bCn6F5ipQuBaMAAaFHNrqsZm7BttogdA==
|
||||
knex@^0.19.3:
|
||||
version "0.19.3"
|
||||
resolved "https://registry.yarnpkg.com/knex/-/knex-0.19.3.tgz#b5d85b29a127f631a6924e8727c76e53e26cc713"
|
||||
integrity sha512-HN32QB5PVkUYfvE4UoK/Tbf6UQ7CLEgS0PL8EP6xfonsP0IPZr2M84dy1dIy2KnB5dx+XO6NNEPgfzo8Y8BYzA==
|
||||
dependencies:
|
||||
bluebird "^3.5.5"
|
||||
colorette "1.0.8"
|
||||
colorette "1.1.0"
|
||||
commander "^2.20.0"
|
||||
debug "4.1.1"
|
||||
getopts "2.2.4"
|
||||
getopts "2.2.5"
|
||||
inherits "~2.0.4"
|
||||
interpret "^1.2.0"
|
||||
liftoff "3.1.0"
|
||||
lodash "^4.17.15"
|
||||
mkdirp "^0.5.1"
|
||||
pg-connection-string "2.0.0"
|
||||
pg-connection-string "2.1.0"
|
||||
tarn "^2.0.0"
|
||||
tildify "2.0.0"
|
||||
uuid "^3.3.2"
|
||||
uuid "^3.3.3"
|
||||
v8flags "^3.1.3"
|
||||
|
||||
lcid@^1.0.0:
|
||||
@ -2153,9 +2158,9 @@ minimist@^1.2.0:
|
||||
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
||||
|
||||
minipass@^2.2.1, minipass@^2.3.5:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.4.0.tgz#38f0af94f42fb6f34d3d7d82a90e2c99cd3ff485"
|
||||
integrity sha512-6PmOuSP4NnZXzs2z6rbwzLJu/c5gdzYg1mRI/WIYdx45iiX7T+a4esOzavD6V/KmBzAaopFSTZPZcUx73bqKWA==
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.5.0.tgz#dddb1d001976978158a05badfcbef4a771612857"
|
||||
integrity sha512-9FwMVYhn6ERvMR8XFdOavRz4QK/VJV8elU1x50vYexf9lslDcWe/f4HBRxCPd185ekRSjU6CfYyJCECa/CQy7Q==
|
||||
dependencies:
|
||||
safe-buffer "^5.1.2"
|
||||
yallist "^3.0.0"
|
||||
@ -2640,10 +2645,10 @@ performance-now@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||
|
||||
pg-connection-string@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.0.0.tgz#3eefe5997e06d94821e4d502e42b6a1c73f8df82"
|
||||
integrity sha1-Pu/lmX4G2Ugh5NUC5CtqHHP434I=
|
||||
pg-connection-string@2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.1.0.tgz#e07258f280476540b24818ebb5dca29e101ca502"
|
||||
integrity sha512-bhlV7Eq09JrRIvo1eKngpwuqKtJnNhZdpdOlvrPrA4dxqXPjxSrbNrfnIDmTpwMyRszrcV4kU5ZA4mMsQUrjdg==
|
||||
|
||||
pify@^2.0.0:
|
||||
version "2.3.0"
|
||||
@ -2657,11 +2662,6 @@ pkg-dir@^2.0.0:
|
||||
dependencies:
|
||||
find-up "^2.1.0"
|
||||
|
||||
platform@1.3.5:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.5.tgz#fb6958c696e07e2918d2eeda0f0bc9448d733444"
|
||||
integrity sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q==
|
||||
|
||||
posix-character-classes@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
|
||||
@ -3558,7 +3558,7 @@ utils-merge@1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
||||
|
||||
uuid@^3.3.2:
|
||||
uuid@^3.3.2, uuid@^3.3.3:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
|
||||
integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==
|
||||
|
Loading…
Reference in New Issue
Block a user