Added link expiry timer, file icons, and in-site file viewing

This commit is contained in:
Kenneth Jao 2020-08-06 23:03:36 -04:00
parent ed49d343f8
commit 6acada7c75
12 changed files with 464 additions and 350 deletions

View File

@ -1,2 +1,4 @@
# BinBin
Simple Database Website
Personal Drive Web App
This web application acts as a web interface for a cloud storage service. Users are assigned drives with permissions to read and/or write. There are two types of drives: real and virtual. A real drive is a physical folder on the host, with all subdirectories of the drive correlating to real subdirectories. A virtual drive is an emulated storage space, with all files being stored under a single directory, and a directory layout is mapped internally in the database.

171
binbin.py
View File

@ -1,8 +1,10 @@
import sys, os, time, hashlib, uuid, threading, atexit, flask, \
configparser as cp
configparser as cp, magic
from flask import Flask, render_template, url_for, request, session, \
send_from_directory, send_file, redirect
send_from_directory, send_file, redirect, abort, Response
from flask_pymongo import PyMongo, ObjectId
from apscheduler.schedulers.background import BackgroundScheduler
from pytz import utc
FILTERS = {
'name': 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' +
@ -22,17 +24,31 @@ def apply_config():
else:
app.config[k] = v
def expire():
links = LINKS.find()
for l in links:
if l['expiry'] < time.time():
print(l['expiry'])
print(time.time())
print("deleted")
LINKS.delete_one({'_id': l['_id']})
os.chdir(os.path.dirname(__file__))
app = Flask(__name__)
apply_config()
mongo = PyMongo(app)
scheduler = BackgroundScheduler(timezone=utc)
scheduler.add_job(expire, 'interval', seconds=20)
scheduler.start()
atexit.register(lambda: scheduler.shutdown())
USERS, DRIVES, LINKS = mongo.db['users'], mongo.db['drives'], \
mongo.db['links']
CHECK_PERIOD = 60
expire_thread = threading.Thread()
@app.route('/')
def index():
@ -41,10 +57,12 @@ def index():
else:
return render_template('index.html')
@app.route('/main/<method>')
def main(method):
return render_template(method+'.html')
@app.route('/login', methods=['POST'])
def login():
error = None
@ -56,11 +74,13 @@ def login():
else:
return flask.jsonify(False)
@app.route('/logout')
def logout():
session.pop('username', None)
return redirect(url_for('index'))
@app.route('/mydrives')
def mydrives():
if 'username' not in session:
@ -94,56 +114,89 @@ def mydrives():
return flask.jsonify(info)
@app.route('/files', methods=['POST'])
def files():
@app.route('/files/<method>', methods=['POST'])
def files(method):
err_msgs = {
'list': 'Error: This directory does not exist.',
'zip': 'Error: Folder downloading not supported.'
}
check = verify_data('files', request.form, session)
if not check[0]: return check[1]
if not check[0]: return check[1], 400
form = check[1]
if form['is_fol']: # If request is a folder.
if method == 'list':
if not form['is_fol']: return err_msgs['list']
info = dir_info(form['path'], form['drive']['type'], \
form['drive']['_id'])
return flask.jsonify(info)
else: # If request is a file.
if form['drive']['type'] == 'real':
link = LINKS.insert_one({
'path': form['path'],
'name': form['path'].split("/")[-1],
'shared': [get_user(session)['_id']],
'expiry': -1
}).inserted_id
elif form['drive']['type'] == 'virtual':
r_path = form['drive']['path'] + '/' + form['real_file']
link = LINKS.insert_one({
'path': r_path,
'name': form['path'].split("/")[-1],
'shared': [get_user(session)['_id']],
'expiry': -1
}).inserted_id
else:
raise Exception("Invalid method for file link creation.")
### QUEUE DELETION
return str(link)
elif method == 'download' or method == 'stream':
if form['is_fol']:
return err_msgs['zip']
else:
link_uuid = str(uuid.uuid4()).replace("-","")
if method == 'download':
expire = -1
else:
expire = time.time() + 20*60 # 20 minutes
if form['drive']['type'] == 'real':
link = LINKS.insert_one({
'path': form['path'],
'uuid': link_uuid,
'name': form['path'].split("/")[-1],
'shared': [get_user(session)['_id']],\
'expiry': expire
})
elif form['drive']['type'] == 'virtual':
r_path = form['drive']['path'] + '/' \
+ form['real_file']
link = LINKS.insert_one({
'path': r_path,
'uuid': link_uuid,
'name': form['path'].split("/")[-1],
'shared': [get_user(session)['_id']],
'expiry': expire
})
else:
raise Exception('Drive not real or virtual.')
return link_uuid
else:
return redirect(url_for('index'))
@app.route('/d/<_id>')
def download(_id):
@app.route('/d/<uuid>')
def download(uuid):
if 'username' not in session:
return redirect(url_for('index'))
uuid = uuid.split('.')[0]
try:
link = LINKS.find_one({'_id': ObjectId(_id)})
link = LINKS.find_one({'uuid': uuid})
except:
return redirect(url_for('index'))
if link == None: return redirect(url_for('index'))
if get_user(session)['_id'] not in link['shared']:
return redirect(url_for('index'))
if link['expiry'] == -1:
LINKS.delete_one({'uuid': uuid})
else:
LINKS.update_one({'uuid': uuid}, {
'$set': {'expiry': time.time() + 20*60}
})
if 'pdf' in magic.from_file(link['path'], mime=True):
r = send_file(link['path'])
header = 'inline; filename=\"' + link['name'] + '\"'
r.headers['Content-Disposition'] = header
return r
else:
if link['expiry'] == -1:
LINKS.delete_one({'_id': ObjectId(_id)})
return send_file(link['path'], as_attachment=True,
attachment_filename=link['name'])
attachment_filename=link['name'],
conditional=True)
@app.route('/users/<method>', methods=['POST'])
@ -155,7 +208,7 @@ def users(method):
if method == 'create':
check = verify_data('users.create', request.form, session)
if not check[0]: return check[1]
if not check[0]: return check[1], 400
form = check[1]
salt = uuid.uuid4().hex
@ -171,7 +224,7 @@ def users(method):
elif method == 'delete':
check = verify_data('users.delete', request.form, session)
if not check[0]: return check[1]
if not check[0]: return check[1], 400
form = check[1]
USERS.delete_one({'username': form['username']})
@ -183,6 +236,7 @@ def users(method):
def drive_path():
pass
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
@ -201,6 +255,10 @@ def js(path):
def assets(path):
return send_from_directory('assets', path)
@app.route('/test/<path:path>')
def test(path):
return send_from_directory('test', path)
# End temporary
def get_user(sess):
@ -217,15 +275,15 @@ def validate_login(u, p):
def sizeof_fmt(num, suffix='B'):
for unit in ['','K','M','G','T','P','E','Z']:
if abs(num) < 1024.0:
return '%3.1f%s%s' % (num, unit, suffix)
num /= 1024.0
return '%.1f%s%s' % (num, 'Y', suffix)
for unit in ['','K','M','G','T','P','E','Z']:
if abs(num) < 1024.0:
return '%3.1f%s%s' % (num, unit, suffix)
num /= 1024.0
return '%.1f%s%s' % (num, 'Y', suffix)
def dir_info(path, t, drive_id):
def info_dict(item, stats, is_fol):
def info_dict(item, stats, is_fol, filetype):
if is_fol:
my_item = ({
'folder': True,
@ -233,12 +291,12 @@ def dir_info(path, t, drive_id):
})
else:
my_item = ({
'folder': False,
'name': item,
'date': time.strftime('%Y-%m-%d %H:%M:%S UTC', \
time.gmtime(stats[8])),
'size': sizeof_fmt(stats[6]),
'real_size': stats[6]
'real_size': stats[6],
'filetype': filetype
})
return my_item
full_items = []
@ -246,9 +304,15 @@ def dir_info(path, t, drive_id):
if t == 'real':
items = os.listdir(path)
for item in items:
stats = list(os.stat(path + '/' + item))
is_fol = os.path.isdir(path + '/' + item)
full_items.append(info_dict(item, stats, is_fol))
f_path = path + '/' + item
stats = list(os.stat(f_path))
is_fol = os.path.isdir(f_path)
if not is_fol:
kind = magic.from_file(f_path, mime=True)
else:
kind = None
full_items.append(info_dict(item, stats, is_fol, kind))
elif t == 'virtual':
drives = DRIVES.find_one({'_id': drive_id})
@ -260,11 +324,14 @@ def dir_info(path, t, drive_id):
for k,v in tree.items():
is_fol = type(v).__name__ != 'str'
if is_fol:
stats = None
stats, kind = None, None
else:
stats = list(os.stat(drives['path'] + '/' + v))
kind = magic.from_file(drives['path'] + '/' + v,
mime=True)
full_items.append(info_dict(k.replace(':','.'), \
stats, is_fol))
stats, is_fol, kind))
return full_items
@ -451,11 +518,5 @@ def create_drive(method, owner, form=None):
return 'Operation completed.'
def manage_expiry():
links = LINKS.find()
#print(links)
if __name__ == '__main__':
app.run(debug=True)

View File

@ -31,12 +31,6 @@
html {
height: 100%;
width: 100%;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
body {
@ -64,6 +58,15 @@ a {
-ms-transition: all 0.3s cubic-bezier(.25, .8, .25, 1);
}
.noSelect {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#header1 {
display: grid;
background-color: #1b1a1a;
@ -332,11 +335,11 @@ canvas {
margin: auto;
}
.fileIcon .fa {
.fileIcon i {
padding: .6em;
}
.fileIcon .fa:hover {
.fileIcon i:hover {
color: #fff;
}
@ -371,10 +374,6 @@ canvas {
display: inline-block;
}
#directoryLocation i {
font-size: 150%;
}
.subdir:hover {
background-color: rgba(255,255,255, 0.1);
}
@ -386,10 +385,6 @@ canvas {
background-color: rgba(255,255,255,0.1);
}
audio {
display: none;
}
#playback div {
display: grid;
}

View File

@ -198,7 +198,7 @@ a {
margin: auto auto auto 0 !important;
}
.item div .fa {
.item div i {
padding: 1.5vh;
}

View File

@ -1,38 +1,38 @@
// Loads alert box into HTML first.
var box = document.createElement("div");
var p = document.createElement("p");
var box = document.createElement('div');
var p = document.createElement('p');
box.id = "alert";
box.style.position = "absolute";
box.style.top = "-4em";
box.style.width = "100%";
box.style.color = "#fefefe";
box.style.textAlign = "center";
box.id = 'alert';
box.style.position = 'absolute';
box.style.top = '-4em';
box.style.width = '100%';
box.style.color = '#fefefe';
box.style.textAlign = 'center';
box.style.setProperty("-webkit-transition", " top 0.3s cubic-bezier(.25, .8, .25, 1)");
box.style.setProperty("transition:", "top 0.3s cubic-bezier(.25, .8, .25, 1)");
box.style.setProperty("-moz-transition", " top 0.3s cubic-bezier(.25, .8, .25, 1)");
box.style.setProperty("-ms-transition", " top 0.3s cubic-bezier(.25, .8, .25, 1)");
box.style.setProperty('-webkit-transition', ' top 0.3s cubic-bezier(.25, .8, .25, 1)');
box.style.setProperty('transition:', 'top 0.3s cubic-bezier(.25, .8, .25, 1)');
box.style.setProperty('-moz-transition', ' top 0.3s cubic-bezier(.25, .8, .25, 1)');
box.style.setProperty('-ms-transition', ' top 0.3s cubic-bezier(.25, .8, .25, 1)');
p.style.backgroundColor = "#000";
p.style.display = "inline";
p.style.padding = "1em";
p.style.borderRadius = "4px";
p.style.backgroundColor = '#000';
p.style.display = 'inline';
p.style.padding = '1em';
p.style.borderRadius = '4px';
box.appendChild(p);
get("body").appendChild(box);
get('body').appendChild(box);
function alertBox(s, type) {
colors = {
"error": "#d24242",
"msg": "#4d9e53"
'error': '#d24242',
'msg': '#4d9e53'
};
box.childNodes[0].textContent = s;
box.childNodes[0].style.backgroundColor = colors[type];
box.style.top = "2em";
box.style.top = '2em';
setTimeout(function() {
box.style.top = "-4em";
}, 1000);
box.style.top = '-4em';
}, 2500);
}

View File

@ -8,8 +8,8 @@ var navSelect; // Stores current selected sidebar option.
var clickable = true; // Prevents actions being run more than once.
var selectDiv; // Stores selected file or folder div.
var currDir = ''; // Stores the current directory.
var version = 'desktop';
// FIX THE DATE
function sortFiles(type, direction) {
if(type === 'name') data[0] = sortSection(type, direction, data[0]);
data[1] = sortSection(type, direction, data[1]);
@ -39,124 +39,6 @@ function sortFiles(type, direction) {
}
};
function dispDir() {
updateLocation();
try {
get('#directory').removeChild(get('#directoryCont'));
} catch(err) {}
var cont = element('div', {
id: 'directoryCont',
class: 'transition',
style: 'opacity:0'
});
if(data[0].length === 0 && data[1].length === 0) {
cont.appendChild(element('p', {
text: 'Nothing here!',
style: 'font-weight: 100'
}));
}
for(var i = 0; i < data.length; i++) {
for(var j = 0; j < data[i].length; j++) {
var itemInfo = data[i][j];
var ext = (itemInfo.folder) ? "fol" :
itemInfo.name.substring(
itemInfo.name.lastIndexOf(".") + 1,
itemInfo.name.length)
.toLowerCase();
var item = element('div', {
class: 'item transition',
ext: ext,
filename: itemInfo.name
});
item.appendChild(element('p', {
class: 'name',
text: itemInfo.name
}));
item.appendChild(element('p', {
class: 'modified',
text: (itemInfo.folder) ? "----" : dateStr(itemInfo.date)
}));
item.appendChild(element('p', {
class: 'size',
text: itemInfo.size || "----"
}));
if(!itemInfo.folder) {
var a = element('div', {
onclick: function() {
console.log("generating download link");
// DO EXPIRY LINKS HERE
// update link to get('copy') and copy
}
});
a.appendChild(element('i', {
class: 'fa fa-files-o transition'
}));
item.appendChild(a);
}
var ico = element('div', {
class: 'fileIcon',
});
ico.appendChild(element('i', {
class: `fa fa-${(faIcons[ext] || faIcons["other"])}`
}));
item.appendChild(ico);
item.onclick = function() {
if(!clickable) return;
// DO WITH SHIFT AND CONTROL LATER.
if(this.className.search( 'selectedItem') === -1) {
get('.item').forEach(function(ele) {
ele.style.backgroundColor = "";
ele.className = ele.className.replace(' selectedItem',
'');
});
this.className += ' selectedItem';
this.style.backgroundColor = "rgba(255,255,255,0.2)";
return;
}
// Below executes only after user has clicked twice.
var name = this.getAttribute('filename');
var ext = this.getAttribute('ext');
clickable = false;
if(ext == 'fol') {
clearTbl();
setTimeout(function() {
currDir += '/' + name;
listDir(currDir, 0);
}, 300);
} else {
downloadFile(currDir + "/" + name);
}
clickable = true;
}
cont.appendChild(item);
}
}
get('#directory').appendChild(cont);
setTimeout(function() {
get('#directoryCont').style.opacity = "1";
}, 100);
};
function updateLocation() {
var loc = get('#directoryLocation');
while(loc.firstChild) loc.removeChild(loc.firstChild);
@ -176,7 +58,7 @@ function updateLocation() {
currDir = '';
} else {
currDir = subdir.slice(0, subdirNum+1)
.reduce(function(a,b) { return a + '/' + b; }) + '/';
.reduce(function(a,b) { return a + '/' + b; });
}
listDir(currDir, 0);
}
@ -184,7 +66,7 @@ function updateLocation() {
if(i > 0) {
loc.appendChild(element('i', {
class: 'fa fa-angle-right'
class: 'fas fa-chevron-right'
}));
}
loc.appendChild(p);

View File

@ -3,32 +3,32 @@ var t = 0;
function login(form) {
u = form.username.value;
p = form.password.value;
uEmpty = u === "", pEmpty = p === "";
uEmpty = u === '', pEmpty = p === '';
if(uEmpty && pEmpty) {
alertBox("Please enter a username and password!", "error");
alertBox('Please enter a username and password!', 'error');
return;
} else if (uEmpty && !pEmpty) {
alertBox("Please enter a username!", "error");
alertBox('Please enter a username!', 'error');
return;
} else if (!uEmpty && pEmpty) {
alertBox("Please enter a password!", "error");
alertBox('Please enter a password!', 'error');
return;
}
data = {username: u, password: p}
$.post("./login", data).done(function(data) {
$.post('./login', data).done(function(data) {
if(data) {
location.reload(true);
} else {
alertBox("Wrong username or password!");
alertBox('Wrong username or password!');
}
});
}
function drawCanvas() {
var el = get("canvas")
var c = el.getContext("2d")
var el = get('canvas')
var c = el.getContext('2d')
var block = 10, space = 2, size = block+space;
var period = 100, freq = 2*Math.PI/period, step = 1.4, base = 0.05;
@ -44,7 +44,7 @@ function drawCanvas() {
el.width = w, el.height = h;
c.fillStyle = "#0e0e0e";
c.fillStyle = '#0e0e0e';
c.fillRect(0, 0, w, h);
for(var i = 0; i < x+1; i++) {
for(var j = 0; j < y+1; j++) {
@ -87,12 +87,12 @@ function drawCanvas() {
drawCanvas();
inputs = get("input"), button = get("button")
inputs = get('input'), button = get('button')
inputs[0].addEventListener("keyup", function(e) {
inputs[0].addEventListener('keyup', function(e) {
if(e.keyCode === 13) button.click();
});
inputs[1].addEventListener("keyup", function(e) {
inputs[1].addEventListener('keyup', function(e) {
if(e.keyCode === 13) button.click();
});

View File

@ -8,6 +8,7 @@ var navSelect; // Stores current selected sidebar option.
var clickable = true; // Prevents actions being run more than once.
var selectDiv; // Stores selected file or folder div.
var currDir = ''; // Stores the current directory.
var version = 'mobile';
function sortFiles(type, direction) {
if(type === 'name') data[0] = sortSection(type, direction, data[0]);

View File

@ -1,100 +0,0 @@
function videoOverlay(url) {
var overlay = getDefaultOverlay();
var video = document.createElement("video");
video.onclick = function() {event.stopPropagation();}
video.src = url;
video.controls = true;
video.autoplay = true;
video.type = "video/mp4";
video.style.margin = "auto";
video.style.backgroundColor = "black";
video.onloadedmetadata = function() {
if((video.videoHeight/video.videoWidth) > (window.innerHeight/window.innerWidth)) {
video.style.height = (window.innerHeight * 0.9).toString() + "px";
} else {
video.style.width = (window.innerWidth * 0.9).toString() + "px";
}
}
var div = document.createElement("div");
div.style.margin = "auto";
div.style.gridRow = "1";
div.style.gridColumn = "1";
div.appendChild(video);
overlay.appendChild(div);
var close = getClose();
overlay.appendChild(close);
document.getElementsByTagName("body")[0].appendChild(overlay);
setTimeout(function() {
overlay.style.opacity = "1";
}, 10);
}
function audioOverlay(url) {
var overlay = getDefaultOverlay();
var audio = document.createElement("audio");
audio.onclick = function() {event.stopPropagation();}
audio.src = url;
audio.controls = true;
audio.autoplay = true;
audio.style.margin = "auto";
audio.style.width = (window.innerWidth * 0.9).toString() + "px";
var div = document.createElement("div");
div.style.margin = "auto";
div.style.gridRow = "1";
div.style.gridColumn = "1";
div.appendChild(audio);
overlay.appendChild(div);
var close = getClose();
overlay.appendChild(close);
document.getElementsByTagName("body")[0].appendChild(overlay);
setTimeout(function() {
overlay.style.opacity = "1";
}, 10);
}
function imageOverlay(url) {
var overlay = getDefaultOverlay();
var img = new Image();
img.src = url;
img.style.margin = "auto";
var image = document.createElement("img");
image.src = url;
img.onload = function() {
var height = img.height;
var width = img.width;
if((height/width) > (window.innerHeight/window.innerWidth)) {
image.style.height = (window.innerHeight * 0.9).toString() + "px";
} else {
image.style.width = (window.innerWidth * 0.9).toString() + "px";
}
};
var div = document.createElement("div");
div.style.margin = "auto";
div.style.gridRow = "1";
div.style.gridColumn = "1";
div.appendChild(image);
overlay.appendChild(div);
var close = getClose();
overlay.appendChild(close);
document.getElementsByTagName("body")[0].appendChild(overlay);
setTimeout(function() {
overlay.style.opacity = "1";
}, 10);
}

View File

@ -5,12 +5,13 @@ var themeColors = { // For reference and for quick changing if need-be.
};
var faIcons = {
'fol': 'folder',
'mp3': 'music',
'ogg': 'music',
'mp4': 'video-camera',
'zip': 'file-zip-o',
'other': 'file-o'
'fol': 'fas fa-folder',
'audio': 'fas fa-file-audio',
'video': 'fas fa-file-video',
'image': 'fas fa-file-image',
'zip': 'fas fa-file-archive',
'pdf': 'fas fa-file-pdf',
'other': 'fas fa-file'
};
var sort = { // Default sorting directions.
@ -30,8 +31,8 @@ var navi = [ // Necessary arguments: id, alias, fa | Optional arguments: subnav.
*/
function get(name) {
ele = document.querySelectorAll(name)
return (ele.length === 1) ? ele[0] : ele;
ele = document.querySelectorAll(name)
return (ele.length === 1) ? ele[0] : ele;
};
function element(type, dict) {
@ -61,8 +62,7 @@ function getDrives() {
'onclick': function() {
if(this.id === navSelect) return;
updateNav(this.id);
sidebar = get('.closeable');
if(sidebar) moveSidebar('close');
if(version === 'mobile') moveSidebar('close');
currDir = '';
listDir(currDir, 0);
}
@ -74,6 +74,10 @@ function getDrives() {
navLayout();
updateNav(navSelect);
listDir(currDir, 0);
})
.fail(function(e) {
alertBox(e.responseText, 'error');
console.log(e.responseText);
});
};
@ -81,7 +85,7 @@ function getDrives() {
// if files need to be split up into sections.
function listDir(dir, sec) {
$.post('./files', {'drive_id': navSelect, 'path': currDir})
$.post('./files/list', {'drive_id': navSelect, 'path': currDir})
.done(function(d) {
data = [[],[]];
for(var i = 0; i < d.length; i++) {
@ -94,13 +98,43 @@ function listDir(dir, sec) {
}
sortFiles('name', -1);
clickable = true;
})
.fail(function(e) {
alertBox(e.responseText, 'error');
console.log(e.responseText);
});
};
function downloadFile(path) {
function downloadFile(type, ext, path) {
alertBox('Downloading file...', 'msg');
$.post('./files', {'drive_id': navSelect, 'path': path}).done(function(d) {
window.location = './d/' + d;
$.post('./files/download', {'drive_id': navSelect, 'path': path})
.done(function(d) {
if(type === 'download') {
if(ext.includes('pdf')) {
window.open('./d/' + d);
} else {
window.location = './d/' + d;
}
} else if(type === 'image') {
overlay(type, './d/' + d, ext)
}
})
.fail(function(e) {
alertBox(e.responseText, 'error');
console.log(e.responseText);
});
};
function streamFile(type, ext, path) {
alertBox('Getting file...', 'msg');
$.post('./files/stream', {'drive_id': navSelect, 'path': path})
.done(function(d) {
overlay(type, './d/' + d, ext)
})
.fail(function(e) {
alertBox(e.responseText, 'error');
console.log(e.responseText);
});
};
@ -124,7 +158,135 @@ function sortSection(type, direc, arr) {
break;
}
return sorted;
}
};
function dispDir() {
updateLocation();
try {
get('#directory').removeChild(get('#directoryCont'));
} catch(err) {}
var cont = element('div', {
id: 'directoryCont',
class: 'transition',
style: 'opacity:0'
});
if(data[0].length === 0 && data[1].length === 0) {
cont.appendChild(element('p', {
text: 'Nothing here!',
style: 'font-weight: 100'
}));
}
for(var i = 0; i < data.length; i++) {
for(var j = 0; j < data[i].length; j++) {
var itemInfo = data[i][j];
var ext = (itemInfo.folder) ? 'fol' : itemInfo.filetype
var item = element('div', {
class: 'item transition',
ext: ext,
filename: itemInfo.name
});
item.appendChild(element('p', {
class: 'name',
text: itemInfo.name
}));
if(version === 'desktop') {
item.appendChild(element('p', {
class: 'modified',
text: (itemInfo.folder) ? '----' : dateStr(itemInfo.date)
}));
item.appendChild(element('p', {
class: 'size',
text: itemInfo.size || '----'
}));
} else if(version === 'mobile') {
item.appendChild(element('p', {
class: 'otherInfo',
text: (itemInfo.folder) ? '----' :
dateStr(itemInfo.date, 'date') + ' | ' + itemInfo.size
}));
}
if(!itemInfo.folder) {
var a = element('div', {
onclick: function() {
console.log('generating download link');
// DO EXPIRY LINKS HERE
// update link to get('copy') and copy
}
});
a.appendChild(element('i', {
class: 'fa fa-files-o transition'
}));
item.appendChild(a);
}
var ico = element('div', {
class: 'fileIcon',
});
ico.appendChild(element('i', {
class: faIcons[fileType(ext)]
}));
item.appendChild(ico);
item.onclick = function() {
if(!clickable) return;
// DO WITH SHIFT AND CONTROL LATER.
if(this.className.search( 'selectedItem') === -1) {
get('.item').forEach(function(ele) {
ele.style.backgroundColor = '';
ele.className = ele.className.replace(' selectedItem',
'');
});
this.className += ' selectedItem';
this.style.backgroundColor = 'rgba(255,255,255,0.2)';
return;
}
// Below executes only after user has clicked twice.
var name = this.getAttribute('filename');
var ext = this.getAttribute('ext');
clickable = false;
if(ext == 'fol') {
clearTbl();
setTimeout(function() {
currDir += '/' + name;
listDir(currDir, 0);
}, 300);
} else if(ext.includes('image')) {
downloadFile('image', ext, currDir + '/' + name);
} else if(ext.includes('audio')) {
streamFile('audio', ext, currDir + '/' + name);
} else if(ext.includes('video')) {
streamFile('video', ext, currDir + '/' + name);
} else {
downloadFile('download', ext, currDir + '/' + name);
}
clickable = true;
}
cont.appendChild(item);
}
}
get('#directory').appendChild(cont);
setTimeout(function() {
get('#directoryCont').style.opacity = '1';
}, 100);
};
function navLayout() {
function createNavHeader(text) {
@ -172,10 +334,99 @@ function updateNav(op) { // Updates the sidebar navigation.
};
function clearTbl() {
selectDiv = undefined;
get('#directoryCont').style.opacity = '0';
selectDiv = undefined;
get('#directoryCont').style.opacity = '0';
};
function overlay(type, src, mime) {
function resize(item, vH, vW) {
wH = window.innerHeight, wW = window.innerWidth;
if((vH/vW) > (wH/wW)) {
item.style.height = (wH * 0.9).toString() + "px";
} else {
item.style.width = (wW * 0.9).toString() + "px";
}
}
var div = element('div', {
id: 'overlay',
class: 'transition',
style: `width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-color: rgba(0,0,0,0.7);
opacity: 0;
display: grid;`,
onclick: function() {
this.style.opacity = '0';
that = this;
setTimeout(function() {
that.parentNode.removeChild(that);
}, 300);
}
});
var inner;
if(type === 'image') {
var img = element('img', {
style: 'margin: auto;',
src: src,
onclick: function(event) {
event.stopPropagation();
}
});
img.onload = function() {
resize(this, this.height, this.width);
};
inner = img;
} else if (type === 'audio') {
var audio = element('audio', {
class: 'noSelect',
style: 'margin: auto; outline: none',
controls: true,
autoplay: true,
src: src,
type: mime,
onclick: function(event) {
event.stopPropagation();
}
});
inner = audio;
} else if (type === 'video') {
var vid = element('video', {
style: 'margin: auto; background-color: black;',
controls: true,
autoplay: true,
src: src,
type: mime,
onclick: function(event) {
event.stopPropagation();
}
});
vid.onloadedmetadata = function() {
resize(this, this.videoHeight, this.videoWidth);
};
inner = vid;
}
div.appendChild(inner);
get('body').appendChild(div);
setTimeout(function() {
div.style.opacity = '1';
}, 10);
}
function animFade(type, div) {
if(type === 'open') {
div.style.display = 'block';
@ -200,4 +451,24 @@ function dateStr(date, type) {
} else if(Type === 'time') {
return str.substring(str.indexOf(',') + 1, str.length);
}
};
};
function fileType(ext) {
if(ext === 'fol') return 'fol';
if(ext.includes('image')) {
return 'image';
} else if(ext.includes('video')) {
return 'video';
} else if(ext.includes('pdf')) {
return 'pdf';
} else if(ext.includes('audio')) {
return 'audio';
} else if(ext.includes('zip') ||
ext.includes('x-rar') ||
ext.includes('x-7z-compressed') ||
ext.includes('gzip')) {
return 'zip';
} else {
return 'other'
}
}

View File

@ -19,9 +19,9 @@
<h1>BinBin</h1>
<form id="login" onsubmit="login(form);">
<p>Username:</p>
<input class="transition" type="text" name="username">
<input class="transition noSelect" type="text" name="username">
<p>Password:</p>
<input class="transition" type="password" name="password">
<input class="transition noSelect" type="password" name="password">
</form>
<div>
<button class="transition" onclick="login(get('#login'));" >Login</button>

View File

@ -9,7 +9,7 @@
<link href="https://fonts.googleapis.com/css?family=Roboto+Slab:100,300" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://use.fontawesome.com/c8d5486cd8.js"></script>
<script src="https://kit.fontawesome.com/54cafaf1a9.js"></script>
<script src="./js/tools.js"></script>
<script id="version">
scripts = {
@ -18,7 +18,8 @@
};
function isMobileDevice() {
return (typeof window.orientation !== "undefined") || (navigator.userAgent.indexOf('IEMobile') !== -1);
return (typeof window.orientation !== "undefined") ||
(navigator.userAgent.indexOf('IEMobile') !== -1);
};
function setPage(method, html) {
@ -34,6 +35,7 @@
};
var method = (isMobileDevice()) ? "mobile" : "desktop";
console.log(method)
get('head').appendChild(element('link', {
rel: 'stylesheet',
href: `./css/${method}.css`