Merge branch 'feature-preview'
This commit is contained in:
@@ -36,14 +36,27 @@
|
|||||||
td(style='width: 60px')
|
td(style='width: 60px')
|
||||||
file-icon(:file='file')
|
file-icon(:file='file')
|
||||||
td
|
td
|
||||||
p
|
div.pull-right
|
||||||
clipboard.pull-right(:value='host + file.url', @change='copied(file, $event)', title='Copy to clipboard', style='margin-left: 5px')
|
i.fa.fa-check.text-success(v-show='file.downloaded')
|
||||||
|
clipboard.btn.btn-sm.btn-default(:value='host + file.url', @change='copied(file, $event)', title='Copy to clipboard', style='margin: 0 5px')
|
||||||
a
|
a
|
||||||
i.fa.fa-fw.fa-copy
|
i.fa.fa-fw.fa-copy
|
||||||
i.fa.fa-check.text-success.pull-right(v-show='file.downloaded')
|
a.btn.btn-sm.btn-default(title="preview", @click.prevent.stop="preview=file", v-if="getPreviewType(file)")
|
||||||
strong {{ file.metadata.name }}
|
i.fa.fa-fw.fa-eye
|
||||||
small(v-if="Number.isFinite(file.size)") ({{ humanFileSize(file.size) }})
|
p
|
||||||
|
strong {{ file.metadata.name }}
|
||||||
|
small(v-if="Number.isFinite(file.size)", style="margin-left:15px") ({{ humanFileSize(file.size) }})
|
||||||
p {{ file.metadata.comment }}
|
p {{ file.metadata.comment }}
|
||||||
|
|
||||||
|
modal(v-if="preview", @close="preview=false", :has-header="true")
|
||||||
|
h4(slot="header") {{preview.metadata.name}}
|
||||||
|
div(slot="body")
|
||||||
|
div(v-if="getPreviewType(preview) === 'image'", style="text-align:center")
|
||||||
|
img(:src="preview.url", style="max-width: 100%; height:auto")
|
||||||
|
div(v-if="getPreviewType(preview) === 'text'")
|
||||||
|
pre {{ previewText }}
|
||||||
|
p(v-if="getPreviewType(preview) === false", style="text-align:center")
|
||||||
|
strong.text-danger No preview available
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
@@ -55,11 +68,11 @@
|
|||||||
|
|
||||||
import FileIcon from './common/FileIcon.vue';
|
import FileIcon from './common/FileIcon.vue';
|
||||||
import Clipboard from './common/Clipboard.vue';
|
import Clipboard from './common/Clipboard.vue';
|
||||||
|
import Modal from './common/Modal.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
components: { FileIcon, Clipboard },
|
components: { FileIcon, Clipboard, Modal },
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
files: [],
|
files: [],
|
||||||
@@ -69,7 +82,17 @@
|
|||||||
password: '',
|
password: '',
|
||||||
content: '',
|
content: '',
|
||||||
error: '',
|
error: '',
|
||||||
host: document.location.protocol + '//' + document.location.host
|
host: document.location.protocol + '//' + document.location.host,
|
||||||
|
config: {},
|
||||||
|
preview: false,
|
||||||
|
previewText: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
preview: function(preview, old) {
|
||||||
|
if(this.getPreviewType(preview) !== 'text' || preview === old) return;
|
||||||
|
this.getPreviewText();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -80,6 +103,29 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
getPreviewType(file) {
|
||||||
|
if(!file || !file.metadata.type) return false;
|
||||||
|
if(file.metadata.retention === 'one-time') return false;
|
||||||
|
// no preview for files size > 2MB
|
||||||
|
if(file.size > this.config.maxPreviewSize) return false;
|
||||||
|
if(file.metadata.type.startsWith('image/')) return 'image';
|
||||||
|
else if(file.metadata.type.startsWith('text/')) return 'text';
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
getPreviewText() {
|
||||||
|
this.previewText = '';
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', '//' + document.location.host + this.preview.url);
|
||||||
|
xhr.onload = () => {
|
||||||
|
if(xhr.status === 200) {
|
||||||
|
this.previewText = xhr.responseText
|
||||||
|
} else {
|
||||||
|
this.previewText = `${xhr.status} ${xhr.statusText}: ${xhr.responseText}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
},
|
||||||
|
|
||||||
download(file) {
|
download(file) {
|
||||||
if(file.downloaded && file.metadata.retention === 'one-time') {
|
if(file.downloaded && file.metadata.retention === 'one-time') {
|
||||||
alert('One-Time Download: File is not available anymore.');
|
alert('One-Time Download: File is not available anymore.');
|
||||||
@@ -150,7 +196,9 @@
|
|||||||
xhr.onload = () => {
|
xhr.onload = () => {
|
||||||
if(xhr.status === 200) {
|
if(xhr.status === 200) {
|
||||||
try {
|
try {
|
||||||
this.files = JSON.parse(xhr.responseText).map(f => {
|
let data = JSON.parse(xhr.responseText);
|
||||||
|
this.config = data.config;
|
||||||
|
this.files = data.items.map(f => {
|
||||||
if(typeof f !== 'object') {
|
if(typeof f !== 'object') {
|
||||||
this.needsPassword = true;
|
this.needsPassword = true;
|
||||||
return f;
|
return f;
|
||||||
|
|||||||
56
app/src/common/Modal.vue
Normal file
56
app/src/common/Modal.vue
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<template lang="pug">
|
||||||
|
.modal.fade.in.background-darken(ref='modal', style="display:block", tabindex='-1', role='dialog', @click.self='close()', @keyup.esc='close()')
|
||||||
|
.modal-dialog.modal-lg(role='document')
|
||||||
|
.modal-content
|
||||||
|
.modal-header(v-if='hasHeader')
|
||||||
|
button.close(type='button', data-dismiss='modal', aria-label='Close', @click='close()')
|
||||||
|
span(aria-hidden='true') ×
|
||||||
|
h4.modal-title
|
||||||
|
slot(name='header') Modal
|
||||||
|
.modal-body
|
||||||
|
slot(name='body') Body
|
||||||
|
.modal-footer(v-if='hasFooter')
|
||||||
|
slot(name='footer')
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
hasHeader: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hasFooter: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.$nextTick(function() {
|
||||||
|
this.$refs.modal.focus();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
close() {
|
||||||
|
this.$emit('close');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.background-darken {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
.modal.in {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -22,6 +22,8 @@ const config = {
|
|||||||
4838400: "8 Weeks"
|
4838400: "8 Weeks"
|
||||||
},
|
},
|
||||||
defaultRetention: 604800,
|
defaultRetention: 604800,
|
||||||
|
// maximum file-size for previews in byte
|
||||||
|
maxPreviewSize: Math.pow(2,20) * 2, // 2MB
|
||||||
mailTemplate: 'mailto:?subject=File Transfer&body=You can download the files here: %%URL%%',
|
mailTemplate: 'mailto:?subject=File Transfer&body=You can download the files here: %%URL%%',
|
||||||
// see https://github.com/expressjs/morgan
|
// see https://github.com/expressjs/morgan
|
||||||
// set to false to disable logging
|
// set to false to disable logging
|
||||||
|
|||||||
@@ -60,14 +60,19 @@ app.get('/:sid', (req, res, next) => {
|
|||||||
const sid = req.params.sid.substr(0, req.params.sid.length-5);
|
const sid = req.params.sid.substr(0, req.params.sid.length-5);
|
||||||
if(!db.get(sid)) return res.status(404).end();
|
if(!db.get(sid)) return res.status(404).end();
|
||||||
|
|
||||||
res.json(db.get(sid).map(data => {
|
res.json({
|
||||||
const item = Object.assign(data, {url: `/files/${sid}++${data.key}`});
|
items: db.get(sid).map(data => {
|
||||||
if(item.metadata.password) {
|
const item = Object.assign(data, {url: `/files/${sid}++${data.key}`});
|
||||||
return AES.encrypt(JSON.stringify(data), item.metadata.password).toString();
|
if(item.metadata.password) {
|
||||||
} else {
|
return AES.encrypt(JSON.stringify(data), item.metadata.password).toString();
|
||||||
return item;
|
} else {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
config: {
|
||||||
|
maxPreviewSize: config.maxPreviewSize
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
} else {
|
} else {
|
||||||
if(!db.get(req.params.sid)) return next();
|
if(!db.get(req.params.sid)) return next();
|
||||||
res.sendFile(path.join(__dirname, '../public/html/download.html'));
|
res.sendFile(path.join(__dirname, '../public/html/download.html'));
|
||||||
|
|||||||
Reference in New Issue
Block a user