Moved to flask, added virtual databases and login

This commit is contained in:
Kenneth Jao 2020-08-06 23:03:36 -04:00
parent 107d35bea0
commit ed49d343f8
27 changed files with 1953 additions and 1086 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
bin/*
include/*
lib/*
lib64
__pycache__/*
share/*
pyvenv.cfg
key.txt
db.info
config.ini

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

461
binbin.py Normal file
View File

@ -0,0 +1,461 @@
import sys, os, time, hashlib, uuid, threading, atexit, flask, \
configparser as cp
from flask import Flask, render_template, url_for, request, session, \
send_from_directory, send_file, redirect
from flask_pymongo import PyMongo, ObjectId
FILTERS = {
'name': 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' +
'0123456789_',
'path': ['../', './']
}
def apply_config():
config = cp.ConfigParser()
config.read('config.ini')
for k,v in config['Settings'].items():
k = k.upper()
if k == 'KEY_FILE':
app.secret_key = open(v, 'rb').read()
elif k == 'DEFAULT_VIRTUAL_SIZE':
app.config[k] = int(v)
else:
app.config[k] = v
os.chdir(os.path.dirname(__file__))
app = Flask(__name__)
apply_config()
mongo = PyMongo(app)
USERS, DRIVES, LINKS = mongo.db['users'], mongo.db['drives'], \
mongo.db['links']
CHECK_PERIOD = 60
expire_thread = threading.Thread()
@app.route('/')
def index():
if 'username' in session:
return render_template('pre_main.html')
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
u, p = request.form['username'], request.form['password']
success = validate_login(u, p)
if success:
session['username'] = u
return flask.jsonify(True)
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:
return redirect(url_for('index'))
user_id = get_user(session)['_id']
owned = DRIVES.find({'owner': user_id})
shared = DRIVES.find({'shared_read': {'$in': [user_id]}})
info = {'owned': [], 'shared': []}
for drive in owned:
drive_info = {
'_id': str(drive['_id']),
'name': drive['name'],
'size': drive['size'],
'public_read': drive['public_read'],
'public_write': drive['public_write'],
'shared_read': [str(i) for i in drive['shared_read']],
'shared_write': [str(i) for i in drive['shared_write']]
}
info['owned'].append(drive_info)
for drive in shared:
drive_info = {
'_id': str(drive['_id']),
'name': drive['name'],
'size': drive['size']
}
info['shared'].append(drive_info)
return flask.jsonify(info)
@app.route('/files', methods=['POST'])
def files():
check = verify_data('files', request.form, session)
if not check[0]: return check[1]
form = check[1]
if form['is_fol']: # If request is a folder.
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)
@app.route('/d/<_id>')
def download(_id):
if 'username' not in session:
return redirect(url_for('index'))
try:
link = LINKS.find_one({'_id': ObjectId(_id)})
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'))
else:
if link['expiry'] == -1:
LINKS.delete_one({'_id': ObjectId(_id)})
return send_file(link['path'], as_attachment=True,
attachment_filename=link['name'])
@app.route('/users/<method>', methods=['POST'])
def users(method):
if 'username' not in session:
return redirect(url_for('index'))
user = USERS.find_one({'username': session['username']})
if method == 'create':
check = verify_data('users.create', request.form, session)
if not check[0]: return check[1]
form = check[1]
salt = uuid.uuid4().hex
to_hash = (form['password'] + salt).encode('utf-8')
user = USERS.insert_one({
'username': form['username'],
'password': hashlib.sha512(to_hash).digest(),
'salt': salt,
'perm_level': 1
})
create_drive('virtual', user.inserted_id)
elif method == 'delete':
check = verify_data('users.delete', request.form, session)
if not check[0]: return check[1]
form = check[1]
USERS.delete_one({'username': form['username']})
elif method == 'modify':
pass
return 'Operation completed'
@app.route('/drive/<drive_id>/<path:path>')
def drive_path():
pass
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
# Temporary for development:
@app.route('/css/<path:path>')
def css(path):
return send_from_directory('css', path)
@app.route('/js/<path:path>')
def js(path):
return send_from_directory('js', path)
@app.route('/assets/<path:path>')
def assets(path):
return send_from_directory('assets', path)
# End temporary
def get_user(sess):
return USERS.find_one({'username': session['username']})
def validate_login(u, p):
user = USERS.find_one({'username': u})
if user == None:
return False
else:
to_hash = (p + user['salt']).encode('utf-8')
return hashlib.sha512(to_hash).digest() == user['password']
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)
def dir_info(path, t, drive_id):
def info_dict(item, stats, is_fol):
if is_fol:
my_item = ({
'folder': True,
'name': item
})
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]
})
return my_item
full_items = []
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))
elif t == 'virtual':
drives = DRIVES.find_one({'_id': drive_id})
tree = drives['tree']
path = path.replace('.',':').split("/")[1:]
if path != []:
for sub in path: tree = tree[sub]
for k,v in tree.items():
is_fol = type(v).__name__ != 'str'
if is_fol:
stats = None
else:
stats = list(os.stat(drives['path'] + '/' + v))
full_items.append(info_dict(k.replace(':','.'), \
stats, is_fol))
return full_items
def exists(data, need):
try:
[i in data for i in need].index(False)
return False
except ValueError:
return True
def sanitize(d):
if 'username' in d:
s = ''
for c in d['username']: s += c if c in FILTERS['name'] else ''
d['username'] = s
if 'path' in d:
for s in FILTERS['path']:
if s in d['path']:
d['path'] = ''
def sess_is_user(sess, name):
return sess['username'] == name
def sess_is_admin(sess):
return get_user(sess)['perm_level'] == 100
def copy_dict(form):
new_form = {}
for k,v in form.items(): new_form[k] = v
return new_form
def verify_data(method, form, sess):
'''
Verifies permissions and format and sanitizes user input.
For each method, 1) Check for malformed data. 3) Check permissions
for operation based on session. 3) Sanitize data. 4) Check
operation specific requirements.
'''
err_msgs = {
'data': 'malformed data',
'permission': 'insufficient permissions',
'userexists': 'username already in use',
'driveperm': 'the drive is not shared with you',
'pathinvalid': 'not a valid path'
}
errors = []
data = copy_dict(form)
if method == 'users.create':
has_items = exists(data, ['username', 'password'])
if not has_items: errors.append('data')
if not sess_is_admin(sess): errors.append('permission')
sanitize(data)
try:
if USERS.find_one({'username': data['username']}) != None:
errors.append('userexists')
except KeyError:
pass
elif method == 'users.delete':
has_items = exists(data, ['username'])
if not has_items: errors.append('data')
if not sess_is_admin(sess) and \
not sess_is_user(sess, data['username']):
return errors.append('permission')
sanitize(data)
elif method == 'users.modify':
pass
elif method == 'files':
has_items = exists(data, ['drive_id', 'path'])
if not has_items: errors.append('data')
drive = DRIVES.find_one({'_id': ObjectId(data['drive_id'])})
if drive == None: errors.append('driveinvalid')
if not drive['public_read']:
user_id = get_user(sess)['_id']
if user_id != drive['owner'] and \
user_id not in drive['shared_read']:
errors.append('driveperm')
sanitize(data)
if drive['type'] == 'real':
if not os.path.exists(drive['path'] + data['path']):
errors.append('pathinvalid')
data['is_fol'] = os.path.isdir(drive['path'] + \
data['path'])
# For real drives, the path is kept as the full real path.
data['path'] = drive['path']+data['path']
elif drive['type'] == 'virtual':
tree = drive['tree']
path = data['path'].replace('.',':').split('/')[1:]
if path != []:
folder, f = path[:-1], path[-1]
try:
for sub in folder: tree = tree[sub]
data['is_fol'] = type(tree[f]).__name__ != 'str'
data['real_file'] = tree[f]
except KeyError:
errors.append('pathinvalid')
else:
data['is_fol'] = True
# For virtual drives, the path is just the user request.
data['drive'] = drive
else:
raise Exception('Invalid data verification method.')
if len(errors) == 0: return [True, data]
msg = 'Error: '
for i,e in enumerate(errors):
if len(errors) == 1:
msg += err_msgs[e][0].upper() + err_msgs[e][1:]
elif i == 0:
msg += err_msgs[e][0].upper() + err_msgs[e][1:] + ', '
elif i == len(errors)-1:
msg += 'and ' + err_msgs[e]
else:
msg += err_msgs[e] + ', '
msg += '.'
if len(errors) <= 2: msg = msg.replace(',', '')
return [False, msg]
def create_drive(method, owner, form=None):
if method == 'real':
DRIVES.insert_one({
'name': form['name'],
'path': form['path'],
'type': 'real',
'owner': owner,
'public_read': False,
'public_write': False,
'shared_read': [],
'shared_write': []
})
elif method == 'virtual':
vir_path = app.config['VIRTUAL_DB_PATH'] + "/" + str(owner)
name = str(uuid.uuid4())+str(uuid.uuid4())
DRIVES.insert_one({
'name': 'My Drive',
'path': vir_path,
'tree': {
'Welcome:txt': name
},
'type': 'virtual',
'size': app.config['DEFAULT_VIRTUAL_SIZE'],
'owner': owner,
'public_read': False,
'public_write': False,
'shared_read': [],
'shared_write': []
})
os.mkdir(vir_path)
file = open(vir_path+'/'+name, 'w')
file.write(app.config['WELCOME_MSG'])
file.close()
else:
raise Exception('Invalid drive creation method.')
return 'Operation completed.'
def manage_expiry():
links = LINKS.find()
#print(links)
if __name__ == '__main__':
app.run(debug=True)

1
binbin.wsgi Normal file
View File

@ -0,0 +1 @@
from binbin import app as application

View File

@ -1,22 +1,21 @@
@import url(https://fonts.googleapis.com/css?family=Abel);
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 12px; width: 12px;
} }
/* Track */ /* Track */
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
-webkit-border-radius: 5px; -webkit-border-radius: 5px;
border-radius: 5px; border-radius: 5px;
} }
/* Handle */ /* Handle */
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
-webkit-border-radius: 5px; -webkit-border-radius: 5px;
border-radius: 5px; border-radius: 5px;
background: rgba(255,255,255,0.7); background: rgba(255,255,255,0.7);
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5); -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5);
} }
::-webkit-scrollbar-thumb:window-inactive { ::-webkit-scrollbar-thumb:window-inactive {
background: rgba(255,255,255,0.4); background: rgba(255,255,255,0.4);
@ -33,23 +32,20 @@ html {
height: 100%; height: 100%;
width: 100%; width: 100%;
-webkit-touch-callout: none; -webkit-touch-callout: none;
-webkit-user-select: none; -webkit-user-select: none;
-khtml-user-select: none; -khtml-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
} }
body { body {
display: grid;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
padding: 0; padding: 0;
margin: 0; margin: 0;
color: white; color: white;
font-family: 'Open Sans Condensed', sans-serif; font-family: 'Roboto Slab', sans-serif;
grid-template-columns: 15% auto;
grid-template-rows: 8% auto;
} }
h1, h2, h3, h4, h5, p { h1, h2, h3, h4, h5, p {
@ -61,11 +57,6 @@ a {
color: #2EA8FF; color: #2EA8FF;
} }
#header1 h1 {
margin: auto;
font-size: 5vh;
}
.transition { .transition {
-webkit-transition: all 0.3s cubic-bezier(.25, .8, .25, 1); -webkit-transition: all 0.3s cubic-bezier(.25, .8, .25, 1);
transition: all 0.3s cubic-bezier(.25, .8, .25, 1); transition: all 0.3s cubic-bezier(.25, .8, .25, 1);
@ -75,56 +66,56 @@ a {
#header1 { #header1 {
display: grid; display: grid;
background-color: #292828; background-color: #1b1a1a;
text-align: center; text-align: center;
grid-column: 1;
grid-row: 1;
cursor: pointer; cursor: pointer;
height: 10vh;
} }
#header1 img { #header1 h1 {
margin: auto; margin: auto;
height: 80%; font-size: 3em;
font-family: 'Roboto Slab', sans-serif;
} }
#header2 { #header2 {
display: grid; display: grid;
grid-template-columns: repeat(8, 1fr); grid-template-rows: 1fr 1fr 1fr;
background-color: #27262b; background-color: #27262b;
grid-column: 2; height: 10vh;
}
#topNav {
display: grid;
grid-template-columns: repeat(8, 1fr);
grid-row: 1; grid-row: 1;
} background-color: rgba(255,255,255,0.01);
#header2 div {
margin: auto;
font-size: 150%;
}
#header2 p {
cursor: pointer;
border-radius: 5px;
padding: 5%;
width: 100%; width: 100%;
text-align: center;
} }
#header2 p:hover { #logout {
margin: auto;
grid-column: 8;
font-size: 1.15em;
padding: .5em 0 .5em 0;
font-weight: 300;
width: 100%;
cursor: pointer;
}
#logout:hover {
background-color: rgba(255,255,255,0.1); background-color: rgba(255,255,255,0.1);
} }
#header2 i {
margin-left: 2%;
}
#spectrum {
grid-column: 5;
grid-row: 1;
}
#sidebar { #sidebar {
position: relative; position: relative;
background-color: #27262b; background-color: #27262b;
grid-column: 1; height: 100%;
grid-row: 2; display: inline-block;
width: 30vh;
font-family: 'Saira Condensed', sans-serif;
} }
#sidebar span { #sidebar span {
@ -145,7 +136,17 @@ a {
height: 6vh; height: 6vh;
width: 100%; width: 100%;
cursor: pointer; cursor: pointer;
grid-template-columns: 1fr 3fr 7fr; grid-template-columns: 1fr 5fr 20fr;
}
.naviHead {
background-color: rgba(0,0,0,0.4);
padding: 3%;
font-weight: 300;
}
.naviHead:first-child {
margin-top: 6vh;
} }
.naviInner { .naviInner {
@ -173,22 +174,27 @@ a {
.navi p { .navi p {
margin: auto 0 auto 0; margin: auto 0 auto 0;
font-size: 2vh; font-size: 1em;
grid-column: 3; grid-column: 3;
font-weight: 300;
font-size: 1.2em;
} }
.naviInner p { .naviInner p {
margin: auto 0 auto 0; margin: auto 0 auto 0;
font-size: 2vh; font-size: 1em;
grid-column: 2; grid-column: 2;
} }
#mainContainer { #mainContainer {
overflow: hidden; position: absolute;
top: 0;
background-color: #3e505a; background-color: #3e505a;
font-family: 'Saira Condensed', sans-serif; font-family: 'Saira Condensed', sans-serif;
grid-column: 2; height: 100%;
grid-row: 2; min-width: 100vh;
width: calc(100vw - 30vh);
display: inline-block;
} }
.card { .card {
@ -206,25 +212,18 @@ a {
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
} }
#songList {
height: 100%;
color: white;
display: grid;
grid-template-columns: 100%;
grid-template-rows: 90% 10%;
}
#directory { #directory {
display: grid; display: grid;
height: 100%;
grid-column: 1; grid-column: 1;
grid-row: 1; grid-row: 1;
grid-template-columns: 100%; grid-template-columns: 100%;
grid-template-rows: 1fr 2fr 20fr 5fr; grid-template-rows: 1fr 2fr 25fr;
} }
#directory p { #directory p {
font-size: 150%; font-size: 1.2em;
padding: 1.5vh 2vh 1.5vh 2vh; padding: 0.6em;
} }
canvas { canvas {
@ -241,24 +240,31 @@ canvas {
#directoryHeader { #directoryHeader {
display: grid; display: grid;
grid-template-columns: 60% 25% 10% 5%; grid-template-columns: 60% 25% 10% 5%;
grid-template-rows: 100%;
color: white; color: white;
background-color: #1c1c1c; background-color: #3c84a7;
box-shadow: #242424 0 0 20px 0px; box-shadow: #242424 0 0 2px 1px;
} }
#directoryHeader p { #directoryHeader p {
display: grid; display: grid;
cursor: pointer; cursor: pointer;
grid-template-columns: 19fr 1fr; grid-template-columns: 19fr 1fr;
grid-template-rows: 100%; padding: .6em;
padding: 2.3vh; border-left: 1px solid #fefefe;
}
#directoryHeader p:first-child {
border-left: none;
} }
#directoryHeader p:hover { #directoryHeader p:hover {
background-color: rgba(0,0,0,0.1); background-color: rgba(0,0,0,0.1);
} }
#directoryHeader span {
margin: auto 0 auto 0;
}
#directoryHeader i { #directoryHeader i {
margin: auto; margin: auto;
display: none; display: none;
@ -282,16 +288,26 @@ canvas {
background-color: rgba(255,255,255,0.1); background-color: rgba(255,255,255,0.1);
} }
.item:first-child {
border-top: 1px solid #222;
}
.item:last-child {
margin-bottom: 25%;
}
.item .name { .item .name {
grid-column: 2; grid-column: 2;
} }
.item .modified { .item .modified {
grid-column: 3; grid-column: 3;
padding-left: 1.2em !important;
} }
.item .size: { .item .size {
grid-column: 4; grid-column: 4;
padding-left: 1.2em !important;
} }
.item p { .item p {
@ -299,9 +315,8 @@ canvas {
} }
.item div { .item div {
grid-column: 5;
margin: auto; margin: auto;
font-size: 140%; font-size: 1.2em;
color: white; color: white;
} }
@ -318,7 +333,7 @@ canvas {
} }
.fileIcon .fa { .fileIcon .fa {
padding: 1.3vh; padding: .6em;
} }
.fileIcon .fa:hover { .fileIcon .fa:hover {

103
css/index.css Normal file
View File

@ -0,0 +1,103 @@
html, body {
min-height: 100%;
height: 100%;
margin: 0;
font-family: 'Roboto Slab', sans-serif;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-tap-highlight-color: transparent;
overflow: hidden;
}
body {
display: grid;
background-color: #0e0e0e;
}
.transition {
-webkit-transition: all 0.3s cubic-bezier(.25, .8, .25, 1);
transition: all 0.3s cubic-bezier(.25, .8, .25, 1);
-moz-transition: all 0.3s cubic-bezier(.25, .8, .25, 1);
-ms-transition: all 0.3s cubic-bezier(.25, .8, .25, 1);
}
#canvas {
top: 0;
left: 0;
position: absolute;
z-index: -1;
}
#formContainer {
margin: auto;
padding: 2.5em;
background-color: #27262b;
color: #fefefe;
box-shadow: 4px 4px 3px rgba(0, 0, 0, 0.12);
border-radius: 2px;
}
#formContainer #formSizeWrapper {
height: 100%;
}
#formContainer #formSizeWrapper div {
position: relative;
}
#formContainer h1 {
margin: auto auto 10% auto;
font-size: 350%;
text-align: center;
}
#formContainer p {
margin: 0 0 2% 0;
font-size: 110%;
}
#formContainer input {
margin-bottom: 10%;
padding: 5%;
border: none;
font-size: 130%;
font-family: 'Roboto Slab', sans-serif;
display: block;
background-color: rgba(255,255,255,0.1);
color: #fefefe;
outline: none;
}
#formContainer input[type=password] {
margin-bottom: 35%;
}
#formContainer input:hover, #formContainer input:active {
background-color: rgba(255,255,255,0.15);
}
#formContainer button {
width: 100%;
font-family: 'Roboto Slab', sans-serif;
font-size: 150%;
padding: 3%;
color: white;
cursor: pointer;
border: 0;
background-color: #5fab4c;
position: absolute;
bottom: 3%;
outline: none;
}
#formContainer button:hover {
background-color: #599e48;
}
#formContainer button:active {
animation: pop 0.3s cubic-bezier(.25, .8, .25, 1) 0s 1;
}
@keyframes pop {
0% { width: 98%; margin: 1%; font-size: 140%; bottom: 2.5%;}
100% { width: 100%; margin: 0; font-size: 150%; bottom: 3%;}
}

View File

@ -16,7 +16,7 @@ body {
padding: 0; padding: 0;
margin: 0; margin: 0;
color: white; color: white;
font-family: 'Open Sans Condensed', sans-serif; font-family: 'Saira Condensed', sans-serif;
grid-template-columns: 100%; grid-template-columns: 100%;
grid-template-rows: 8% 6% auto; grid-template-rows: 8% 6% auto;
} }
@ -72,10 +72,6 @@ a {
box-shadow: 1px 0px 12px 1px black; box-shadow: 1px 0px 12px 1px black;
} }
#sidebar div:nth-child(2) {
margin-top: 20%;
}
#sidebar span { #sidebar span {
font-size: 110%; font-size: 110%;
padding: 5%; padding: 5%;
@ -97,6 +93,16 @@ a {
grid-template-columns: 1fr 3fr 7fr; grid-template-columns: 1fr 3fr 7fr;
} }
.naviHead {
background-color: rgba(0,0,0,0.4);
padding: 3%;
font-weight: 300;
}
.naviHead:first-child {
margin-top: 6vh;
}
.naviInner { .naviInner {
background-color: rgba(0,0,0,0.15); background-color: rgba(0,0,0,0.15);
} }
@ -123,6 +129,7 @@ a {
.navi p { .navi p {
margin: auto 0 auto 0; margin: auto 0 auto 0;
font-size: 2vh; font-size: 2vh;
font-weight: 300;
grid-column: 3; grid-column: 3;
} }
@ -168,9 +175,10 @@ a {
grid-row: 1; grid-row: 1;
grid-column: 2; grid-column: 2;
font-size: 120%; font-size: 120%;
font-weight: 300;
} }
.item .modified { .item .otherInfo {
grid-row: 2; grid-row: 2;
grid-column: 2; grid-column: 2;
font-size: 80%; font-size: 80%;

View File

@ -1,74 +0,0 @@
<body>
<div id="header1" class="transition">
<h1>BinBin</h1>
</div>
<div id="header2">
<div id="spectrum">
<p class="transition">Spectrum <i class="fa fa-times-circle" aria-hidden="true"></i></p>
</div>
</div>
<div id="sidebar">
<span>Developed by <p onclick="window.open('https://github.com/ksjdragon/binbin.git','_blank')">ksjdragon</p></span>
</div>
<div id="mainContainer">
<div id="songList">
<div id="directory">
<div id="directoryLocation" class="transition">
<p>a</p>
</div>
<div id="directoryHeader">
<p class="name transition">Name
<i class="fa fa-chevron-down transition"></i>
<i class="fa fa-chevron-up transition"></i>
</p>
<p class="date transition">Date Modified
<i class="fa fa-chevron-down transition"></i>
<i class="fa fa-chevron-up transition"></i>
</p>
<p class="size transition">Size
<i class="fa fa-chevron-down transition"></i>
<i class="fa fa-chevron-up transition"></i>
</p>
</div>
<div id="directoryCont">
</div>
<canvas id="visualize" width="1200" height="250"></canvas>
</div>
<div id="playback">
<div id="info">
<div>
<h2></h2>
</div>
<div>
<a download><i class="fa fa-download transition"></i></a>
</div>
</div>
<div id="tracker">
<div>
<i id="prev" class="fa fa-step-backward" aria-hidden="true"></i>
<i id="pause" class="fa fa-pause-circle transition"></i>
<i id="next" class="fa fa-step-forward" aria-hidden="true"></i>
</div>
<div id="bar">
<p>-:--</p>
<input type="range" min="0", max="100000" value="0">
<p>-:--</p>
</div>
</div>
<div id="speed">
<i class="fa fa-fast-forward transition"></i>
<input type="range" min="0", max="100" value="25">
</div>
<div id="volume">
<i class="fa fa-volume-up transition"></i>
<input type="range" min="0", max="100" value="100">
</div>
<audio controls>
<source src="">
</audio>
</div>
</div>
</div>
<input id="copy" readonly>
</body>

View File

@ -1,123 +0,0 @@
var Visualizer = function() {
this.file = null, //the current file
this.fileName = null, //the current file name
this.audioContext = null,
this.source = null, //the audio source
this.info = document.getElementById('info').innerHTML, //this used to upgrade the UI information
this.infoUpdateId = null, //to sotore the setTimeout ID and clear the interval
this.animationId = null,
this.status = 0, //flag for sound is playing 1 or stopped 0
this.forceStop = false,
this.allCapsReachBottom = false
};
Visualizer.prototype = {
ini: function() {
this._prepareAPI();
},
_prepareAPI: function() {
//fix browser vender for AudioContext and requestAnimationFrame
window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;
window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame;
window.cancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.msCancelAnimationFrame;
try {
this.audioContext = new AudioContext();
} catch (e) {
alert('!Your browser does not support AudioContext', false);
console.log(e);
}
},
_visualize: function(url, canvas, audio) {
var audioContext = this.audioContext,
audioBufferSouceNode = audioContext.createMediaElementSource(audio),
analyser = audioContext.createAnalyser(),
that = this;
this.analyser = analyser;
this.canvas = canvas;
//connect the source to the analyser
audioBufferSouceNode.connect(analyser);
//connect the analyser to the destination(the speaker), or we won't hear the sound
analyser.connect(audioContext.destination);
//then assign the buffer to the buffer source node
//play the source
if (!audioBufferSouceNode.start) {
audioBufferSouceNode.start = audioBufferSouceNode.noteOn //in old browsers use noteOn method
audioBufferSouceNode.stop = audioBufferSouceNode.noteOff //in old browsers use noteOn method
};
//stop the previous sound if any
if (this.animationId !== null) {
cancelAnimationFrame(this.animationId);
}
if (this.source !== null) {
this.source.stop(0);
}
//audioBufferSouceNode.start(0);
this.status = 1;
this.source = audioBufferSouceNode;
this._drawSpectrum(analyser, canvas);
},
_restart: function() {
this._drawSpectrum(this.analyser, this.canvas);
},
_stop: function() {
cancelAnimationFrame(this.animationId);
},
_drawSpectrum: function(analyser, canvas) {
var that = this,
monoL = canvas,
//monoR = document.getElementById('mono-R'),
cwidth = monoL.width,
cheight = monoL.height - 3,
meterWidth = 1, //width of the meters in the spectrum
gap = 0.01, //gap between meters
capHeight = 2,
capStyle = '#fff',
meterNum = 20 * (2 + 2), //count of the meters
capYPositionArray = []; ////store the vertical position of hte caps for the preivous frame
ctx = monoL.getContext('2d'),
gradient = ctx.createLinearGradient(0, 0, 0, 300);
gradient.addColorStop(1, themeColors.highlight);
gradient.addColorStop(0, '#fff');
var drawMeter = function() {
var array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(array);
if (that.status === 0) {
//fix when some sounds end the value still not back to zero
for (var i = array.length - 1; i >= 0; i--) {
array[i] = 0;
};
allCapsReachBottom = true;
for (var i = capYPositionArray.length - 1; i >= 0; i--) {
allCapsReachBottom = allCapsReachBottom && (capYPositionArray[i] === 0);
};
if (allCapsReachBottom) {
cancelAnimationFrame(that.animationId); //since the sound is top and animation finished, stop the requestAnimation to prevent potential memory leak,THIS IS VERY IMPORTANT!
return;
};
};
var step = Math.round(array.length / meterNum); //sample limited data from the total array
ctx.clearRect(0, 0, cwidth, cheight);
for (var i = 0; i < meterNum; i++) {
var value = array[i * step];
if (capYPositionArray.length < Math.round(meterNum)) {
capYPositionArray.push(value);
};
ctx.fillStyle = capStyle;
//draw the cap, with transition effect
if (value < capYPositionArray[i]) {
ctx.fillRect(i * 12, cheight - (--capYPositionArray[i]), meterWidth, capHeight);
} else {
ctx.fillRect(i * 12, cheight - value, meterWidth, capHeight);
capYPositionArray[i] = value;
};
ctx.fillStyle = gradient; //set the filllStyle to gradient for a better look
ctx.fillRect(i * 12 /*meterWidth+gap*/ , cheight - value + capHeight, meterWidth, cheight); //the meter
}
that.animationId = requestAnimationFrame(drawMeter);
}
this.animationId = requestAnimationFrame(drawMeter);
}
}

View File

@ -1,33 +0,0 @@
<?php
$dir = $_GET['name'];
$unlnk = $_GET['u'];
$file_url = getcwd().$dir;
$type = mime_content_type($dir);
header('Content-Description: File Transfer');
header('Content-Type: '.$type);
header("Content-Disposition: attachment; filename=\"" . basename($file_url) . "\"");
header('Content-Transfer-Encoding: Binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($file_url));
ob_clean();
ob_end_flush();
$handle = fopen($file_url, "rb");
if($unlnk === "y") {
ignore_user_abort(true);
while (!feof($handle)) {
echo fread($handle, 1000);
}
unlink($file_url);
} else {
while (!feof($handle)) {
echo fread($handle, 1000);
}
}
?>

View File

@ -1,39 +0,0 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>BinBin</title>
<link rel="icon" href="favicon.ico?v=2">
<link href="https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Saira+Condensed:300,400" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script></script>
<script src="https://use.fontawesome.com/c8d5486cd8.js"></script>
</head>
<body>
</body>
<script>
var prefix = (screen.width <= 699) ? "mobile" : "desktop";
var scripts = {
"desktop": ["visualizer", "desktop"],
"mobile": ["mobile"]
};
var l = document.createElement("link");
l.rel = "stylesheet";
l.href = "./"+prefix+"/"+prefix+".css";
document.getElementsByTagName("head")[0].appendChild(l);
$.ajax({
type:"GET",
url:window.location.origin + "/"+prefix+"/"+prefix+".html",
success: function(d){
document.getElementsByTagName("body")[0].outerHTML = d;
for(var i = 0; i < scripts[prefix].length; i++) {
var s = document.createElement("script");
s.src = "./"+prefix+"/"+scripts[prefix][i]+".js";
document.getElementsByTagName("html")[0].appendChild(s);
}
}
});
</script>
</html>

38
js/alert.js Normal file
View File

@ -0,0 +1,38 @@
// Loads alert box into HTML first.
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.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";
box.appendChild(p);
get("body").appendChild(box);
function alertBox(s, type) {
colors = {
"error": "#d24242",
"msg": "#4d9e53"
};
box.childNodes[0].textContent = s;
box.childNodes[0].style.backgroundColor = colors[type];
box.style.top = "2em";
setTimeout(function() {
box.style.top = "-4em";
}, 1000);
}

234
js/desktop.js Normal file
View File

@ -0,0 +1,234 @@
var data = [[],[]] // Stores file directory data.
var navi = { // Stores data for sidebar navigation.
'owned': [],
'shared': []
};
var drives = {}; // Stores drive names.
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.
// FIX THE DATE
function sortFiles(type, direction) {
if(type === 'name') data[0] = sortSection(type, direction, data[0]);
data[1] = sortSection(type, direction, data[1]);
ico = get('#directoryHeader i');
ico.forEach(function(ele) {
ele.style.opacity = '0';
});
setTimeout(function() {
ico.forEach(function(ele) {
ele.style.display = 'none';
});
var arrow = (direction < 0) ? 'up' : 'down';
arrow = get(`#directoryHeader .${type} i.fa-chevron-${arrow}`);
animFade('open', arrow);
}, 300);
try {
clearTbl();
setTimeout(function() {
get('#directory').removeChild(get('#directoryCont'));
dispDir();
}, 300);
} catch(err) {
dispDir();
}
};
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);
loc.style.opacity = '1';
var subdir = currDir.split('/');
for(var i = 0; i < subdir.length; i++) {
var p = element('p', {
text: (i === 0) ? drives[navSelect] : subdir[i],
class: 'subdir transition',
style: 'cursor:pointer',
onclick: function() {
clickable = false;
clearTbl();
subdirNum = subdir.indexOf(this.innerText);
if(subdirNum === -1) {
currDir = '';
} else {
currDir = subdir.slice(0, subdirNum+1)
.reduce(function(a,b) { return a + '/' + b; }) + '/';
}
listDir(currDir, 0);
}
});
if(i > 0) {
loc.appendChild(element('i', {
class: 'fa fa-angle-right'
}));
}
loc.appendChild(p);
}
};
function sortButtons() {
get('#directoryHeader .name').onclick = function() {
sort.name = sort.name * -1;
sortFiles('name', sort.name);
};
get('#directoryHeader .date').onclick = function() {
sort.date = sort.date * -1;
sortFiles('date', sort.date);
};
get('#directoryHeader .size').onclick = function() {
sort.size = sort.size * -1;
sortFiles('size', sort.size);
};
};
document.addEventListener('keydown', function(event) {
try {
switch((event || window.event).keyCode) {
case 13:
selectDiv.click();
break;
case 38:
selectDiv.previousElementSibling.click();
break;
case 40:
if(selectDiv == undefined) {
document.getElementById('directoryCont').childNodes[0].click();
} else {
selectDiv.nextElementSibling.click();
}
break;
case 8:
var subdirs = document.getElementsByClassName('subdir');
subdirs[subdirs.length-1].click();
break;
}
} catch(err) {}
});
getDrives();
sortButtons();

0
js/drive.js Normal file
View File

98
js/index.js Normal file
View File

@ -0,0 +1,98 @@
var t = 0;
function login(form) {
u = form.username.value;
p = form.password.value;
uEmpty = u === "", pEmpty = p === "";
if(uEmpty && pEmpty) {
alertBox("Please enter a username and password!", "error");
return;
} else if (uEmpty && !pEmpty) {
alertBox("Please enter a username!", "error");
return;
} else if (!uEmpty && pEmpty) {
alertBox("Please enter a password!", "error");
return;
}
data = {username: u, password: p}
$.post("./login", data).done(function(data) {
if(data) {
location.reload(true);
} else {
alertBox("Wrong username or password!");
}
});
}
function drawCanvas() {
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;
var col = randColor();
var dir = randDir();
function animCanvas(t, col) {
// To update when window changes.
var w = window.innerWidth, h = window.innerHeight;
var x = w/size, y = h/size;
var offX = -(w-Math.floor(x)*size)/2, offY = -(h-Math.floor(y)*size)/2;
el.width = w, el.height = h;
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++) {
var intes = Math.round(step*Math.cos((i+j*dir[0]+t*dir[1])*freq)+step)*0.2/step+base
c.fillStyle = `rgba(${col[0]},${col[1]},${col[2]},${intes})`;
c.fillRect(i*size+offX, j*size+offY, block, block);
}
}
return 1
}
function randColor() {
var arr = [
128*Math.round(2*Math.random())-1,
128*Math.round(2*Math.random())-1,
128*Math.round(2*Math.random())-1
];
while(arr[0]+arr[1]+arr[2] < 382) arr = randColor();
return arr;
}
function randDir() {
return [
(Math.round(Math.random())) ? -1 : 1,
(Math.round(Math.random())) ? -1 : 1
];
}
setInterval(function() {
t += animCanvas(t, col);
if(t == period) {
t = 0;
newCol = randColor();
while(newCol === col) newCol == randColor();
col = newCol;
}
}, 80);
}
drawCanvas();
inputs = get("input"), button = get("button")
inputs[0].addEventListener("keyup", function(e) {
if(e.keyCode === 13) button.click();
});
inputs[1].addEventListener("keyup", function(e) {
if(e.keyCode === 13) button.click();
});

290
js/mobile.js Normal file
View File

@ -0,0 +1,290 @@
var data = [[],[]] // Stores file directory data.
var navi = { // Stores data for sidebar navigation.
'owned': [],
'shared': []
};
var drives = {}; // Stores drive names.
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.
function sortFiles(type, direction) {
if(type === 'name') data[0] = sortSection(type, direction, data[0]);
data[1] = sortSection(type, direction, data[1]);
var p = get('#sortType');
var i = get('#sortDirection');
p.style.opacity = '0';
i.style.opacity = '0';
p.innerText = type[0].toUpperCase() + type.substring(1, type.length);
setTimeout(function() {
var arrow = (direction < 0) ? 'up' : 'down';
i.className = `fa fa-arrow-${arrow} transition`;
p.style.opacity = '1';
i.style.opacity = '1';
}, 300);
try {
clearTbl();
setTimeout(function() {
get('#directory').removeChild(get('#directoryCont'));
dispDir();
}, 300);
} catch(err) {
dispDir();
}
};
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: '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: `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 i = get('#barOpen i');
if(currDir === '') {
get('#location').textContent = drives[navSelect];
if(i.className.includes('fa-bars')) return;
i.style.opacity = '0';
setTimeout(function() {
i.className = 'fa fa-bars transition';
i.style.opacity = '1'
}, 300);
} else {
get('#location').textContent = currDir.split('/').slice(-1);
if(i.className.includes('fa-arrow-left')) return;
i.style.opacity = '0';
setTimeout(function() {
i.className = 'fa fa-arrow-left transition';
i.style.opacity = '1';
}, 300);
}
};
function sortButtons() {
get('#sortText').onclick = function() {
event.stopPropagation();
};
get('#sortName').onclick = function() {
event.stopPropagation();
animMenu('close');
sort.name = sort.name * -1;
sortFiles('name', sort.name);
};
get('#sortDate').onclick = function() {
event.stopPropagation();
animMenu('close');
sort.date = sort.date * -1;
sortFiles('date', sort.date);
};
get('#sortSize').onclick = function() {
event.stopPropagation();
animMenu('close');
sort.size = sort.size * -1;
sortFiles('size', sort.size);
};
get('#sortType').onclick = function() {
var type = this.innerText.toLowerCase();
sort[type] = sort[type] * -1;
sortFiles(type, sort[type]);
};
};
get('#barOpen').onclick = function() {
animIcon(this);
if(currDir === '') {
setTimeout(function() {
moveSidebar('open');
}, 10);
} else {
var arr = currDir.split('/');
if(arr.length === 2) {
currDir = '';
} else {
currDir = arr.slice(0, -1).reduce((a,b) => a + '/' + b);
}
listDir(currDir, 0);
}
};
function animMenu(type) {
if(type === 'open') {
animFade('open', get('#menuOverlay'));
setTimeout(function() {
get('#optionContainer').style.bottom = '0';
}, 150);
} else if(type === 'close') {
animFade('close', get('#menuOverlay'));
get('#optionContainer').style.bottom = '-60%';
}
};
function moveSidebar(type) {
if(type === 'open') {
get('#sidebar').style.left = '0';
} else if(type === 'close') {
get('#sidebar').style.left = '-80%';
}
};
function animIcon(div) {
div.children[0].style.backgroundColor = 'rgba(0,0,0,0.2)';
setTimeout(function() {
div.children[0].style.backgroundColor = 'rgba(0,0,0,0)';
}, 300);
};
function darkenTap(div) {
div.style.backgroundColor = 'rgba(0,0,0,0.2)';
that = this;
setTimeout(function() {
div.style.backgroundColor = 'rgba(0,0,0,0)';
}, 300);
};
get('#sidebar').onclick = function() {
event.stopPropagation();
};
get('#dotOpen').onclick = function(event) {
event.stopPropagation();
animIcon(this);
animFade('open', get('#dotMenu'));
};
get('#openSort').onclick = function() {
event.stopPropagation();
darkenTap(this);
animFade('close', get('#dotMenu'));
animMenu('open');
};
document.getElementById('download').onclick = function() {
event.stopPropagation();
darkenTap(this);
};
document.onclick = function(event) {
animFade('close', get('#dotMenu'));
animMenu('close');
moveSidebar('close');
};
getDrives();
sortButtons();

100
js/overlay.temp.js Normal file
View File

@ -0,0 +1,100 @@
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);
}

203
js/tools.js Normal file
View File

@ -0,0 +1,203 @@
var themeColors = { // For reference and for quick changing if need-be.
'main': '#3e505a',
'sidebar': '#2a2e31',
'highlight': '#fff'
};
var faIcons = {
'fol': 'folder',
'mp3': 'music',
'ogg': 'music',
'mp4': 'video-camera',
'zip': 'file-zip-o',
'other': 'file-o'
};
var sort = { // Default sorting directions.
'name': -1,
'date': 1,
'size': 1,
};
/*
var navi = [ // Necessary arguments: id, alias, fa | Optional arguments: subnav.
{
'id': 'myFiles',
'alias': 'My Files',
'fa': 'home'
},
];
*/
function get(name) {
ele = document.querySelectorAll(name)
return (ele.length === 1) ? ele[0] : ele;
};
function element(type, dict) {
ele = document.createElement(type);
for(var [k,v] of Object.entries(dict)) {
if(k === 'text') {
ele.appendChild(document.createTextNode(v));
} else if(k === 'onclick') {
ele.onclick = v;
} else {
ele.setAttribute(k, v);
}
}
return ele;
};
function getDrives() {
$.get('./mydrives').done(function(d) {
navSelect = d['owned'][0]['_id'] // ADD DEFAULT LATER
types = ['owned', 'shared']
for(var i = 0; i < types.length; i++) {
for(var j = 0; j < d[types[i]].length; j++) {
item = {
'id': d[types[i]][j]['_id'],
'alias': d[types[i]][j]['name'],
'fa': 'home',
'onclick': function() {
if(this.id === navSelect) return;
updateNav(this.id);
sidebar = get('.closeable');
if(sidebar) moveSidebar('close');
currDir = '';
listDir(currDir, 0);
}
}
drives[item['id']] = item['alias'];
navi[types[i]].push(item)
}
}
navLayout();
updateNav(navSelect);
listDir(currDir, 0);
});
};
// Directory is the sub-directory, sec is the section of data,
// if files need to be split up into sections.
function listDir(dir, sec) {
$.post('./files', {'drive_id': navSelect, 'path': currDir})
.done(function(d) {
data = [[],[]];
for(var i = 0; i < d.length; i++) {
if(d[i]['folder']) {
data[0].push(d[i]);
} else {
d[i].date = Date.parse(d[i].date);
data[1].push(d[i]);
}
}
sortFiles('name', -1);
clickable = true;
});
};
function downloadFile(path) {
alertBox('Downloading file...', 'msg');
$.post('./files', {'drive_id': navSelect, 'path': path}).done(function(d) {
window.location = './d/' + d;
});
};
function sortSection(type, direc, arr) {
var sorted = arr;
switch(type) {
case 'name':
sorted.sort(function(a, b) {
return (a.name < b.name) ? direc*1 : direc*-1;
});
break;
case 'date':
sorted.sort(function(a, b){
return (a.date < b.date) ? direc*1 : direc*-1;
});
break;
case 'size':
sorted.sort(function(a, b) {
return (a['real_size'] < b['real_size']) ? direc*1 : direc*-1;
});
break;
}
return sorted;
}
function navLayout() {
function createNavHeader(text) {
get('#sidebarItems').appendChild(element('div', {
class: 'naviHead transition',
text: text
}));
};
function createNav(navi) { // Create navigation tabs on sidebar.
var side = get('#sidebarItems');
navi.forEach(function(ele) {
var div = element('div', {
id: ele.id,
class: 'navi transition',
onclick: ele.onclick
});
div.appendChild(element('i', {
class: `fa fa-${ele.fa}`
}));
div.appendChild(element('p', {
text: ele.alias
}))
side.appendChild(div);
});
};
createNavHeader('My Drives');
createNav(navi['owned']);
createNavHeader('Shared Drives');
createNav(navi['shared']);
};
function updateNav(op) { // Updates the sidebar navigation.
var oldNav = document.getElementById(navSelect);
var newNav = document.getElementById(op);
navSelect = op;
oldNav.style.backgroundColor = 'rgba(0,0,0,0)';
oldNav.style.color = 'white';
newNav.style.backgroundColor = themeColors.main;
newNav.style.color = themeColors.highlight;
};
function clearTbl() {
selectDiv = undefined;
get('#directoryCont').style.opacity = '0';
};
function animFade(type, div) {
if(type === 'open') {
div.style.display = 'block';
setTimeout(function() {
div.style.opacity = '1';
}, 10);
} else if(type === 'close') {
div.style.opacity = '0';
setTimeout(function() {
div.style.display = 'none';
}, 300);
}
};
function dateStr(date, type) {
type = type || 'all';
var str = new Date(date).toLocaleString();
if(type === 'all') {
return str.replace(',', ' | ');
} else if(type === 'date') {
return str.substring(0, str.indexOf(','));
} else if(Type === 'time') {
return str.substring(str.indexOf(',') + 1, str.length);
}
};

View File

@ -1,91 +0,0 @@
<?php
if(isset($_POST['getdir']) && !empty($_POST['getdir'])) {
$dir = $_POST['getdir'];
echo json_encode((listDir($dir[0],$dir[1])));
}
if(isset($_POST['rootdir']) && !empty($_POST['rootdir'])) {
echo json_encode('/Database'.'/');
}
if(isset($_POST['zip']) && !empty($_POST['zip'])) {
$info = $_POST['zip'];
zip($info[0],$info[1]);
}
function listDir($relroot,$section) {
$folder = getcwd().$relroot;
$paths = scandir($folder);
$ext = array("ext");
$mod = array("mod");
$size = array("size");
$paths = array_slice($paths,$section*100,100);
foreach ($paths as $dir) {
$realdir = $folder.'/'.$dir;
if(is_dir($realdir)) {
$ext[] = 'true';
$size[] = "- - - -";
} else {
$ext[] = 'false';
$size[] = human_filesize(filesize($realdir));
}
$mod[] = date ("F d, Y | H:i:s", filemtime($realdir));
}
$results[] = $paths;
$results[] = $ext;
$results[] = $mod;
$results[] = $size;
return $results;
}
function human_filesize($bytes, $decimals = 2) {
$sz = 'BKMGTP';
$factor = floor((strlen($bytes) - 1) / 3);
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor].'B';
}
function zip($path,$title) {
$root = getcwd();
// Get real path for our folder
$rootPath = $root.$path;
// Initialize archive object
$zip = new ZipArchive();
$ziploc = $root.'/zip'.'/'.$title;
$zip->open($ziploc, ZipArchive::CREATE | ZipArchive::OVERWRITE);
// Create recursive directory iterator
/* @var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($rootPath),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $name => $file)
{
// Skip directories (they would be added automatically)
if (!$file->isDir())
{
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath) + 1);
// Add current file to archive
$zip->addFile($filePath, $relativePath);
}
}
// Zip archive will be created only after closing object
$zip->close();
return '/zip'.'/'.$title;
}
?>

View File

@ -1,36 +0,0 @@
<body>
<div id="header">
<div class="transition">
<i class="fa fa-bars transition"></i>
</div>
<h1>BinBin</h1>
<div class="transition">
<i class="fa fa-ellipsis-v"></i>
</div>
</div>
<div id="directoryHeader">
<p id="location" class="transition">BinBin</p>
<p class="transition">Name</p>
<i class="fa fa-arrow-up transition"></i>
</div>
<div id="sidebar" class="transition">
<span>Developed by <p onclick="window.open('https://github.com/ksjdragon/binbin.git','_blank')">ksjdragon</p></span>
</div>
<div id="mainContainer">
<div id="directory">
</div>
</div>
<div id="dotMenu" class="card">
<p id="openSort" class="transition">Sort by...</p>
<a id="download" class="transition" download>Download</a>
</div>
<div id="menuOverlay" class="transition">
<div id="optionContainer" class="transition">
<p>Sort by</p>
<p>Name</p>
<p>Date</p>
<p>Size</p>
</div>
</div>
<input id="copy" readonly>
</body>

View File

@ -1,606 +0,0 @@
var data, // Stores data from PHP.
section = 0,
clickable = true,
selectName, // Stores name of folder in selected div
selectDiv, // Stores actual selected div.
currDir = "";
var sort = {
"name": -1,
"date": 1,
"size": 1,
};
var faIcons = {
"fol": "folder",
"mp3": "music",
"wav": "music",
"ogg": "music",
"mp4": "video-camera",
"zip": "file-zip-o",
"other": "file-o"
};
var navi = [ // Necessary arguments: id, alias, fa | Optional arguments: subnav.
{
"id": "myFiles",
"alias": "My Files",
"fa": "home"
},
];
var navSelect = "myFiles";
var themeColors = { // For reference and for quick changing if need-be.
"main": "#3e505a",
"sidebar": "#2a2e31",
"highlight": "#fff"
};
function getData() {
$.when($.ajax({
type : 'POST',
url: 'main.php',
data: {rootdir: 'rootdir'}
})).done(function(d) {
rootDir = JSON.parse(d);
checkHash();
});
}
function listDir(dir, sec) { // Directory is the sub-directory, sec is the section of data, if files need to be split up into sections.
var real = rootDir+dir;
$.when($.ajax({
type : 'POST',
url: 'main.php',
data: {getdir : [real, sec]},
})).done(function(d) {
data = JSON.parse(d);
if(data[0] === null) {
currDir = "";
listDir(currDir, 0);
return;
}
if(sec == 0) {
data[0].splice(0,2);
data[1].splice(0,3);
data[2].splice(0,3);
data[3].splice(0,3);
} else {
data[1].splice(0,1);
data[2].splice(0,1);
data[3].splice(0,1);
}
var toObj = [];
for(var i = 0; i < data[0].length; i++) {
toObj.push({
name: data[0][i],
folder: data[1][i],
date: data[2][i],
size: data[3][i]
});
}
data = toObj;
sortFiles("name", -1);
clickable = true;
});
}
function sortFiles(type, direction) {
switch(type) {
case "name":
data.sort(function(a, b){ return (a.name < b.name) ? direction*1 : direction*-1;});
break;
case "date":
data.sort(function(a, b){
a = a.date.replace(",","").split(" ");
b = b.date.replace(",","").split(" ");
a = Date.parse(a[1] + " " + a[0] + " " + a[2]);
b = Date.parse(b[1] + " " + b[0] + " " + b[2]);
return (a < b) ? direction*1 : direction*-1;
});
break;
case "size":
data.sort(function(a, b){ return (a.size.replace("B","").substring(0, a.size.length-1) < b.size.replace("B","").substring(0, b.size.length-1)) ? direction*1 : direction*-1;});
}
var p = document.querySelectorAll("#directoryHeader p:nth-child(2)")[0];
var i = document.querySelectorAll("#directoryHeader i")[0];
p.style.opacity = "0";
i.style.opacity = "0";
setTimeout(function() {
p.innerText = type[0].toUpperCase() + type.substring(1,type.length);
i.className = "fa fa-arrow-" + ((direction < 0) ? "up" : "down") + " transition";
p.style.opacity = "1";
i.style.opacity = "1";
}, 300);
try {
clearTbl();
setTimeout(function() {
document.getElementById("directory").removeChild(document.getElementById("directoryCont"));
dispDir();
}, 300);
} catch(err) {
dispDir();
}
}
function dispDir() {
updateLocation();
try {
document.getElementById("directory").removeChild(document.getElementById("directoryCont"));
} catch(err) {}
var cont = document.createElement("div");
cont.id = "directoryCont";
cont.style.opacity = "0";
cont.className = "transition";
selectName = "";
var item;
if(data.length === 0) {
var p = document.createElement("p");
p.appendChild(document.createTextNode("Nothing here!"));
p.style.fontWeight = "100";
cont.appendChild(p);
}
for(var i = 0; i < data.length; i++) {
item = createRow();
var curr = data[i];
var name = document.createTextNode(curr.name);
var otherInfo = document.createTextNode(curr.date.split(" | ")[0] + " | " + curr.size);
item.childNodes[0].appendChild(name);
item.childNodes[1].appendChild(otherInfo);
var ext = document.createAttribute("ext");
if(curr.folder == "true") {
ext.value = "fol";
} else {
ext.value = curr.name.substring(curr.name.lastIndexOf(".")+1,curr.name.length).toLowerCase();
url = getURI(curr.name);
var f = document.createElement("i");
var a = document.createElement("div");
a.setAttribute("url", url);
f.className = "fa fa-files-o transition";
a.appendChild(f);
a.onclick = function() {
this.style.backgroundColor = "rgba(0,0,0,0.4)";
that = this;
setTimeout(function() {
that.style.backgroundColor = "rgba(0,0,0,0)";
}, 300);
document.getElementById("copy").value = this.getAttribute("url");
document.getElementById("copy").select();
document.execCommand("copy");
}
item.appendChild(a);
}
item.setAttributeNode(ext);
var ico = document.createElement("div");
ico.className = "fileIcon";
var faico = document.createElement("i");
faico.className = "fa fa-" + (faIcons[item.getAttribute("ext")] || faIcons["other"]);
ico.appendChild(faico);
item.appendChild(ico);
item.onclick = function() {
if(clickable == true) {
var name = this.childNodes[0].innerText;
url = getURI(name);
attr = this.getAttribute("ext");
var download = document.querySelectorAll("#dotMenu a")[0]
if(attr == "fol") {
download.href = ""
download.style.color = "rgba(0,0,0,0.5)";
} else {
download.href = url;
download.style.color = "rgba(0,0,0,1)";
}
if(selectName == name) {
clickable = false;
if(attr == "fol") {
clearTbl();
setTimeout(function() {
currDir += name+"/";
listDir(currDir,0);
}, 300)
return;
} else if (attr == "mkv" || attr == "mp4") {
videoOverlay(url);
} else if (attr == "png" || attr == "jpg" || attr == "gif") {
imageOverlay(url);
} else if (attr == "mp3" || attr == "ogg") {
audioOverlay(url);
clickable = true;
} else {
downloadFile(rootDir + currDir + name, 'n');
clickable = true;
}
}
selectName = name;
selectDiv = this;
for(var i =0; i < document.getElementsByClassName("item").length;i++){
document.getElementsByClassName("item")[i].style.backgroundColor = "";
}
this.style.backgroundColor = "rgba(255,255,255,0.2)";
}
}
cont.appendChild(item);
item = null;
}
document.getElementById("directory").appendChild(cont);
setTimeout(function() {
document.getElementById("directoryCont").style.opacity = "1";
}, 100);
}
function getClose() {
var close = document.createElement("i");
close.className = "fa fa-times transition";
var attr = document.createAttribute("aria-hidden");
attr.value = "true";
close.setAttributeNode(attr);
close.onclick = function() {
this.style.color = "#f13838";
that = this;
document.getElementsByClassName("overlay")[0].opacity = "0";
setTimeout(function() {
that.style.color = "white";
document.getElementsByTagName("body")[0].removeChild(document.getElementsByClassName("overlay")[0]);
clickable = true;
}, 300);
};
return close;
}
function createRow() {
var item = document.createElement("div");
item.className = "item transition";
var name = document.createElement("p");
name.className = "name";
item.appendChild(name);
var modified = document.createElement("p");
modified.className = "modified";
item.appendChild(modified);
return item;
}
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);
}
function getDefaultOverlay() {
var overlay = document.createElement("div");
overlay.className = "overlay transition";
overlay.style.position = "absolute";
overlay.style.top = "0";
overlay.style.left = "0";
overlay.style.minHeight = "100%";
overlay.style.minWidth = "100%";
overlay.style.background = 'rgba(0,0,0,0.8)';
overlay.style.zIndex = "50";
overlay.style.display = "grid";
overlay.style.gridTemplateColumns = "1fr";
overlay.style.gridTemplateRows = "1fr";
overlay.style.opacity = "0";
return overlay;
}
function clearTbl() {
selected = undefined;
selectDiv = undefined;
document.getElementById("directoryCont").style.opacity = "0";
}
function getURI(name) {
var dirs = (rootDir+currDir+name).split("/");
var uri = window.location.origin;
for(var i = 1; i < dirs.length; i++) uri+="/"+encodeURIComponent(dirs[i]);
return uri;
}
function createNav() {
for (var i = 0; i < navi.length; i++) { // Create navigation tabs.
var side = document.getElementById("sidebar");
var div = document.createElement("div");
div.className = "navi transition";
div.setAttribute("option", navi[i].id);
var ic = document.createElement("i");
ic.className = "fa fa-" + navi[i].fa;
ic["aria-hidden"] = true;
var p = document.createElement("p");
p.appendChild(document.createTextNode(navi[i].alias));
div.appendChild(ic);
div.appendChild(p);
side.appendChild(div);
var subNav = navi[i].subNav;
if(!subNav) continue;
var subNavCont = document.createElement("div");
subNavCont.className = "naviInner";
subNavCont.setAttribute("option", navi[i].id);
for(var j = 0; j < subNav.length; j++) {
var eachSubNav = document.createElement("div");
eachSubNav.className = "transition";
eachSubNav.setAttribute("option", navi[i].id+"&"+subNav[j].id);
eachSubNav.onclick = function() {
var op = this.getAttribute("option");
if(subNavSelect === op) return;
//updateMain(op);
}
var p2 = document.createElement("p");
p2.appendChild(document.createTextNode(subNav[j].alias));
eachSubNav.appendChild(p2);
subNavCont.appendChild(eachSubNav);
}
side.appendChild(subNavCont);
}
}
function updateNav(op) { // Updates the sidebar navigation (if naviagation tabs are ever dynamically implemented).
var oldNav = document.querySelectorAll("[option=" + navSelect + "]")[0];
var newNav = document.querySelectorAll("[option=" + op + "]")[0];
oldNav.style.backgroundColor = "rgba(0,0,0,0)";
oldNav.style.color = "white";
newNav.style.backgroundColor = themeColors.main;
newNav.style.color = themeColors.highlight;
}
function updateLocation() {
window.location.hash = currDir.replace(/[\/]+/g,"*").replace(/ /g, "_");
var i = document.querySelectorAll("#header div:first-child i")[0];
document.getElementById("location").innerText = (currDir === "") ? "BinBin" : currDir.split("/").slice(-2)[0];
if(currDir === "" && !i.className.includes("fa-bars")) {
i.style.opacity = "0";
setTimeout(function() {
i.className = "fa fa-bars transition";
i.style.opacity = "1"
}, 300);
} else if(currDir !== "" && !i.className.includes("fa-arrow-left")) {
i.style.opacity = "0";
setTimeout(function() {
i.className = "fa fa-arrow-left transition";
i.style.opacity = "1";
}, 300);
}
}
function checkHash() {
if(window.location.hash) {
currDir = window.location.hash.replace(/[_]+/g, " ").replace(/[\*]+/g,"/").replace("#","");
}
listDir(currDir,0);
window.location.hash = "";
}
function closeMenuOverlay() {
var overlay = document.getElementById("menuOverlay");
overlay.style.opacity = "0";
setTimeout(function() {
overlay.style.display = "none";
}, 300);
document.getElementById("optionContainer").style.bottom = "-60%";
}
function sortButtons() {
document.querySelectorAll("#optionContainer p:first-child")[0].onclick = function() {event.stopPropagation();}
document.querySelectorAll("#optionContainer p:nth-child(2)")[0].onclick = function() {
event.stopPropagation();
closeMenuOverlay();
sort.name = sort.name * -1;
sortFiles("name", sort.name);
}
document.querySelectorAll("#optionContainer p:nth-child(3)")[0].onclick = function() {
event.stopPropagation();
closeMenuOverlay();
sort.date = sort.date * -1;
sortFiles("date", sort.date);
}
document.querySelectorAll("#optionContainer p:nth-child(4)")[0].onclick = function() {
event.stopPropagation();
closeMenuOverlay();
sort.size = sort.size * -1;
sortFiles("size", sort.size);
}
document.querySelectorAll("#directoryHeader p:nth-child(2)")[0].onclick = function() {
var type = this.innerText.toLowerCase();
sort[type] = sort[type] * -1;
sortFiles(type, sort[type]);
}
}
document.querySelectorAll("#header div:first-child i")[0].onclick = function() {
this.parentNode.style.backgroundColor = "rgba(0,0,0,0.4)";
that = this;
setTimeout(function() {
that.parentNode.style.backgroundColor = "rgba(0,0,0,0)";
}, 300);
if(currDir === "") {
setTimeout(function() {
document.getElementById("sidebar").style.left = "0";
}, 10);
} else {
var arr = currDir.split("/");
if(arr.length === 2) {
currDir = "";
} else {
currDir = arr.slice(0,arr.length-2).reduce((a,b) => a+"/"+b)+"/";
}
listDir(currDir, 0);
}
}
document.getElementById("sidebar").onclick = function() {
event.stopPropagation();
}
document.querySelectorAll("#header div:last-child i")[0].onclick = function(event) {
event.stopPropagation();
this.parentNode.style.backgroundColor = "rgba(0,0,0,0.4)";
that = this;
setTimeout(function() {
that.parentNode.style.backgroundColor = "rgba(0,0,0,0)";
}, 300);
var menu = document.getElementById("dotMenu");
menu.style.display = "block";
setTimeout(function() {
menu.style.opacity = "1";
}, 10);
}
document.getElementById("openSort").onclick = function() {
event.stopPropagation();
this.style.backgroundColor = "rgba(0,0,0,0.2)";
that = this;
setTimeout(function() {
that.style.backgroundColor = "rgba(0,0,0,0)";
}, 300);
// Close Menu
var menu = document.getElementById("dotMenu");
menu.style.opacity = "0";
setTimeout(function() {
menu.style.display = "none";
}, 300);
// Open overlay
var overlay = document.getElementById("menuOverlay");
overlay.style.display = "block";
setTimeout(function() {
overlay.style.opacity = "1";
}, 10);
setTimeout(function() {
var option = document.getElementById("optionContainer");
option.style.bottom = "0";
}, 150);
}
document.getElementById("download").onclick = function() {
event.stopPropagation();
this.style.backgroundColor = "rgba(0,0,0,0.2)";
that = this;
setTimeout(function() {
that.style.backgroundColor = "rgba(0,0,0,0)";
}, 300);
}
document.onclick = function(event) {
var menu = document.getElementById("dotMenu");
menu.style.opacity = "0";
setTimeout(function() {
menu.style.display = "none";
}, 300);
closeMenuOverlay();
document.getElementById("sidebar").style.left = "-80%";
}
getData();
sortButtons();
createNav();
updateNav(navSelect);

125
templates/404.html Normal file
View File

@ -0,0 +1,125 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>BinBin</title>
<link rel="icon" href="./assets/favicon.ico?v=2">
<link href="https://fonts.googleapis.com/css?family=Roboto+Slab:700" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
</head>
<style>
html, body {
min-height: 100%;
height: 100%;
margin: 0;
font-family: 'Roboto Slab', sans-serif;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-tap-highlight-color: transparent;
overflow: hidden;
}
body {
display: grid;
background-color: #0e0e0e;
}
h1 {
margin: auto;
font-family: 'Roboto Slab', sans-serif;
font-size: 50vh;
}
#front {
margin: 0;
width: 100%;
height: 100%;
top: 0;
left: 0;
position: absolute;
background: rgba(0,0,0,0.85);
line-height: 100vh;
text-align: center;
z-index: 5;
color: #fff;
mix-blend-mode: overlay;
}
#canvas {
top: 0;
left: 0;
position: absolute;
mix-blend-mode: screen;
}
</style>
<body>
<canvas id="canvas" width=window.innerHeight></canvas>
<h1 id='front'>404</h1>
</body>
<script src="./js/tools.js"></script>
<script>
var t = 0;
function drawCanvas() {
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;
var col = randColor();
var dir = randDir();
function animCanvas(t, col) {
// To update when window changes.
var w = window.innerWidth, h = window.innerHeight;
var x = w/size, y = h/size;
var offX = -(w-Math.floor(x)*size)/2, offY = -(h-Math.floor(y)*size)/2;
el.width = w, el.height = h;
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++) {
var intes = Math.round(step*Math.cos((i+j*dir[0]+t*dir[1])*freq)+step)*0.2/step+base
c.fillStyle = `rgba(${col[0]},${col[1]},${col[2]},${intes})`;
c.fillRect(i*size+offX, j*size+offY, block, block);
}
}
return 1;
}
function randColor() {
var arr = [
128*Math.round(2*Math.random())-1,
128*Math.round(2*Math.random())-1,
128*Math.round(2*Math.random())-1
];
while(arr[0]+arr[1]+arr[2] < 382) arr = randColor();
return arr;
}
function randDir() {
return [
(Math.round(Math.random())) ? -1 : 1,
(Math.round(Math.random())) ? -1 : 1
];
}
setInterval(function() {
t += animCanvas(t, col);
if(t == period) {
t = 0;
newCol = randColor();
while(newCol === col) newCol == randColor();
col = newCol;
}
}, 80);
}
drawCanvas();
</script>
</html>

41
templates/desktop.html Normal file
View File

@ -0,0 +1,41 @@
<div id="sidebar">
<div id="header1" class="transition">
<h1>BinBin</h1>
</div>
<div id="sidebarItems"></div>
<span>Developed by <p onclick="window.open('https://github.com/ksjdragon/binbin.git','_blank')">ksjdragon</p></span>
</div>
<div id="mainContainer">
<div id="header2">
<div id="topNav">
<div id="logout" class="transition" onclick="window.location='./logout';">Logout</div>
</div>
</div>
<div id="directory">
<div id="directoryLocation" class="transition">
<p>a</p>
</div>
<div id="directoryHeader">
<p class="name transition">
<span>Name</span>
<i class="fa fa-chevron-down transition"></i>
<i class="fa fa-chevron-up transition"></i>
</p>
<p class="date transition">
<span>Date Modified</span>
<i class="fa fa-chevron-down transition"></i>
<i class="fa fa-chevron-up transition"></i>
</p>
<p class="size transition">
<span>Size</span>
<i class="fa fa-chevron-down transition"></i>
<i class="fa fa-chevron-up transition"></i>
</p>
</div>
<div id="directoryCont">
</div>
<canvas id="visualize" width="1200" height="250"></canvas>
</div>
</div>
<input id="copy" readonly>

21
templates/drive.html Normal file
View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>BinBin</title>
<link rel="icon" href="./assets/favicon.ico?v=2">
<link rel="stylesheet" href="./css/drive.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Saira+Condensed:300,400" rel="stylesheet">
<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="./js/tools.js"></script>
</head>
<body>
</body>
</html>

35
templates/index.html Normal file
View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>BinBin</title>
<link rel="icon" href="./assets/favicon.ico?v=2">
<link rel="stylesheet" href="./css/index.css">
<link href="https://fonts.googleapis.com/css?family=Saira+Condensed:300,400" rel="stylesheet">
<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>
</head>
<body>
<canvas id="canvas" width=window.innerHeight></canvas>
<div id="formContainer">
<div id="formSizeWrapper">
<h1>BinBin</h1>
<form id="login" onsubmit="login(form);">
<p>Username:</p>
<input class="transition" type="text" name="username">
<p>Password:</p>
<input class="transition" type="password" name="password">
</form>
<div>
<button class="transition" onclick="login(get('#login'));" >Login</button>
</div>
</div>
</div>
</body>
<script src="./js/tools.js"></script>
<script src="./js/alert.js"></script>
<script src="./js/index.js"></script>
</html>

35
templates/mobile.html Normal file
View File

@ -0,0 +1,35 @@
<div id="header">
<div id="barOpen" class="transition">
<i class="fa fa-bars transition"></i>
</div>
<h1>BinBin</h1>
<div id="dotOpen" class="transition">
<i class="fa fa-ellipsis-v"></i>
</div>
</div>
<div id="directoryHeader">
<p id="location" class="transition"></p>
<p id="sortType" class="transition">Name</p>
<i id="sortDirection" class="fa fa-arrow-up transition"></i>
</div>
<div id="sidebar" class="transition closeable">
<div id="sidebarItems"></div>
<span>Developed by <p onclick="window.open('https://github.com/ksjdragon/binbin.git','_blank')">ksjdragon</p></span>
</div>
<div id="mainContainer">
<div id="directory">
</div>
</div>
<div id="dotMenu" class="card">
<p id="openSort" class="transition">Sort by...</p>
<a id="download" class="transition" download>Download</a>
</div>
<div id="menuOverlay" class="transition">
<div id="optionContainer" class="transition">
<p id='sortText'>Sort by</p>
<p id='sortName'>Name</p>
<p id='sortDate'>Date</p>
<p id='sortSize'>Size</p>
</div>
</div>
<input id="copy" readonly>

51
templates/pre_main.html Normal file
View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>BinBin</title>
<link rel="icon" href="./assets/favicon.ico?v=2">
<link href="https://fonts.googleapis.com/css?family=Saira+Condensed:300,400" rel="stylesheet">
<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="./js/tools.js"></script>
<script id="version">
scripts = {
'desktop': ['alert', 'desktop'],
'mobile': ['alert', 'mobile']
};
function isMobileDevice() {
return (typeof window.orientation !== "undefined") || (navigator.userAgent.indexOf('IEMobile') !== -1);
};
function setPage(method, html) {
body = get('body');
get('body').innerHTML = html;
scripts[method].forEach(function(ele) {
body.appendChild(element('script', {
src: `./js/${ele}.js`
}));
});
get('head').removeChild(get('#version'));
};
var method = (isMobileDevice()) ? "mobile" : "desktop";
get('head').appendChild(element('link', {
rel: 'stylesheet',
href: `./css/${method}.css`
}));
$.get(`./main/${method}`).done(function(d) {
setPage(method, d);
});
</script>
</head>
<body>
</body>
</html>