diff options
Diffstat (limited to 'templates')
-rw-r--r-- | templates/index.html.j2 | 83 | ||||
-rw-r--r-- | templates/upload.html.j2 | 53 | ||||
-rw-r--r-- | templates/upload.js.j2 | 139 |
3 files changed, 275 insertions, 0 deletions
diff --git a/templates/index.html.j2 b/templates/index.html.j2 new file mode 100644 index 0000000..75f97ee --- /dev/null +++ b/templates/index.html.j2 @@ -0,0 +1,83 @@ +{% set prefix_s = prefix | trim('/') ~ '/' %}{% set s_prefix_s = ( '/' ~ prefix | trim('/') ~ '/' ) | replace ("//","/") %}{% set ulp_s = ulp | trim('/') ~ '/' %}{% set server_prefix = ( server | replace("//","##") ~ '/' ~ prefix ~ '/' ) | replace("///","/") | replace("//", "/") | replace("##","//") %}{% set prefix_ulp = ( '/' ~ prefix ~ '/' ~ ulp ~ '/' ) | replace("///","/") | replace("//", "/") %}{% set server_prefix_ulp = ( server | replace("//","##") ~ '/' ~ prefix ~ '/' ~ ulp ~ '/' ) | replace("///","/") | replace("//", "/") | replace("##","//") %}<!DOCTYPE html> +<html> +<head> +<title>FUSS: File Upload and Storage Service</title> +<link rel="stylesheet" href="{{ s_prefix_s }}static/index.css"/> +<meta name="viewport" content="width=device-width, initial-scale=1"> +</head> +<!-- +server = "{{ server }}" +prefix = "{{ prefix }}" +ulp = "{{ ulp }}" +file_count = "{{ file_count }}" +max_size = "{{ max_size }}" +mimetype_blacklist = "{{ mimetype_blacklist }}" +meta = "{{ meta }}" +meta_visible = "{{ meta_visible }}" +meta_headers = "{{ meta_headers }}" +icons = "{{ icons }}" +--> +<body> +<h1>FUSS</h1> +<input id="intro" class="toggle" type="checkbox" checked><label for="intro" class="lbl-toggle" tabindex="0">Introduction</label> +<div id="intro" class="content"> +<div class="content-inner"> +<a href="{{ server_prefix }}">FUSS</a> is a simple file upload and storage web app. +Features include: +<ul> +<li>Maximum upload size</li> +<li>Accept original file modification timestamp</li> +<li>Filter out mimetypes</li> +<li>Handle duplicate files gracefully</li> +<li>Handle up to so many dissimilar files with same name</li> +<li>Drag and drop upload</li> +<li>Display mimetype icons</li> +</ul> +<p style="font-size: 66%;"><a href="https://gitlab.com/bgstack15/fuss/">source</a> (GPL-3.0)</p> +</div> <!-- content-inner --> +</div> <!-- content --> +<input id="use" class="toggle" type="checkbox" checked><label for="use" class="lbl-toggle" tabindex="0">How to use</label> +<div id="use" class="content"> +<div class="content-inner"> +{% if ulp != "" %}Visit the upload form at <a href="{{ prefix_ulp }}">{{ ulp_s }}</a>. +Or f{% else %}F{% endif %}rom the command line: +<pre> +curl -F 'file=@/path/to/file' {{ server_prefix_ulp }} +</pre> +To save the original last modified timestamp from the command line, use script <a href="{{ s_prefix_s }}fuss-upload">fuss-upload</a>. +<pre> +./fuss-upload /path/to/file {{ server_prefix_ulp }} +</pre> +</div> <!-- content-inner --> +</div> <!-- content --> +<input id="stats" class="toggle" type="checkbox" checked><label for="stats" class="lbl-toggle" tabindex="0">Current status for this instance</label> +<div id="stats" class="content"> +<div class="content-inner"> +<ul> +<li>Max file size: {{ max_size }}</li> +<li>Files stored: <a href="{{ s_prefix_s }}dump_files/">{{ file_count }}</a> +(<a href="{{ s_prefix_s }}dump_files/json">json</a> +<a href="{{ s_prefix_s }}dump_files/html">html</a> +<a href="{{ s_prefix_s }}dump_files/html-long">html details</a>) +</li> +<li>Mimetype blacklist +{% if mimetype_blacklist %} +<ul>{% endif %} +{% for m in mimetype_blacklist %}<li>{{ m }}</li>{% endfor %} +{% if mimetype_blacklist %}</ul>{% endif %} +<li>Max duplicate filenames: {{ max_dupe }}</li> +<li>Metadata{% if not meta %} is disabled{% endif %} +{% if meta %} +<ul> +<li>User queriable: {% if meta_visible %}yes{% else %}no{% endif %}</li> +<li>Add to headers: {% if meta_visible and (meta_headers|length) > 0 %}yes{% else %}no{% endif %}</li> +<li>Mimetype icons: {% if icons %}yes{% else %}no{% endif %}</li> +{% endif %} +</ul> <!-- metadata sublist --> +</ul> +<p style="font-size: 66%;"><a href="{{ s_prefix_s }}dump_config/">dump config</a> (<a href="{{ s_prefix_s }}dump_config/json">json</a>) +</div> <!-- content-inner --> +</div> <!-- content --> +<script src="{{ s_prefix_s }}static/index.js"></script> +</body> +</html> diff --git a/templates/upload.html.j2 b/templates/upload.html.j2 new file mode 100644 index 0000000..35673b7 --- /dev/null +++ b/templates/upload.html.j2 @@ -0,0 +1,53 @@ +{% set prefix_s = prefix | trim('/') ~ '/' %}{% set s_prefix_s = ( '/' ~ prefix | trim('/') ~ '/' ) | replace ("//","/") %}{% set ulp_s = ulp | trim('/') ~ '/' %}{% set server_prefix = ( server | replace("//","##") ~ '/' ~ prefix ~ '/' ) | replace("///","/") | replace("//", "/") | replace("##","//") %}{% set prefix_ulp = ( '/' ~ prefix ~ '/' ~ ulp ~ '/' ) | replace("///","/") | replace("//", "/") %}{% set server_prefix_ulp = ( server | replace("//","##") ~ '/' ~ prefix ~ '/' ~ ulp ~ '/' ) | replace("///","/") | replace("//", "/") | replace("##","//") %}<!DOCTYPE html> +<html> + <head> + <title> + FUSS upload page + </title> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <!-- (A) CSS + JS --> + <link rel="stylesheet" href="{{ s_prefix_s }}static/upload.css"/> + <link rel="stylesheet" href="{{ s_prefix_s }}static/index.css"/> + <script src="{{ s_prefix_s }}template/upload.js"></script> + <script> + function lastmod(elem){ + tc = "lastmod="; + for (var x=0; x < elem.files.length; x++) { + tc += `${Math.trunc(elem.files[x].lastModified / 1000)},` + } + document.cookie = tc; + // For a single file: + //document.cookie = `lastmod=${elem.files[0].lastModified}` + } + </script> + </head> +<!-- +server = "{{ server }}" +prefix = "{{ prefix }}" +ulp = "{{ ulp }}" +--> + <body> + <!-- (B) FILE DROP ZONE --> + <div id="upzone"> + Drop Files Here + </div> + + <!-- (D) FALLBACK --> + <form id="upform" action="{{ server_prefix_ulp }}" method="post" enctype="multipart/form-data"> + <br/> + <input type="file" name="file" multiple accept="*" oninput="lastmod(this);" required> + <input type="submit" value="Upload File"> + </form> + + <!-- (C) UPLOAD STATUS --> + <div id="hiddenfirst"> + <input id="upstatus" class="toggle" type="checkbox" checked><label for="upstatus" class="lbl-toggle" tabindex="0">Upload status</label> + <div id="upstatus" class="content"> + <div class="content-inner" id="upstat"> + </div> <!-- content-inner --> + </div> <!-- content --> + </div> + <script src="{{ s_prefix_s }}static/index.js"></script> + </body> +</html> diff --git a/templates/upload.js.j2 b/templates/upload.js.j2 new file mode 100644 index 0000000..28fe892 --- /dev/null +++ b/templates/upload.js.j2 @@ -0,0 +1,139 @@ +{% set prefix_s = prefix | trim('/') ~ '/' %}{% set s_prefix_s = ( '/' ~ prefix | trim('/') ~ '/' ) | replace ("//","/") %}{% set ulp_s = ulp | trim('/') ~ '/' %}{% set server_prefix = ( server | replace("//","##") ~ '/' ~ prefix ~ '/' ) | replace("///","/") | replace("//", "/") | replace("##","//") %}{% set prefix_ulp = ( '/' ~ prefix ~ '/' ~ ulp ~ '/' ) | replace("///","/") | replace("//", "/") %}{% set server_prefix_ulp = ( server | replace("//","##") ~ '/' ~ prefix ~ '/' ~ ulp ~ '/' ) | replace("///","/") | replace("//", "/") | replace("##","//") %} +/* vim:set syntax=javascript ts=2 sw=2 sts=2 et: */ +var ddup = { + // (A) ON PAGE LOAD + hzone: null, // HTML upload zone + hstat: null, // HTML upload status + hform: null, // HTML upload form + hiddenfirst: null, + init : function () { + // (A1) GET HTML ELEMENTS + ddup.hzone = document.getElementById("upzone"); + ddup.hstat = document.getElementById("upstat"); + ddup.hform = document.getElementById("upform"); + ddup.hiddenfirst = document.getElementById("hiddenfirst"); + + // (A2) DRAG-DROP SUPPORTED + if (window.File && window.FileReader && window.FileList && window.Blob) { + // HIGHLIGHT DROPZONE ON FILE HOVER + ddup.hzone.addEventListener("dragenter", function (e) { + e.preventDefault(); + e.stopPropagation(); + ddup.hzone.classList.add('highlight'); + ddup.hzone.innerHTML = "Release to upload"; + }); + ddup.hzone.addEventListener("dragleave", function (e) { + e.preventDefault(); + e.stopPropagation(); + ddup.hzone.classList.remove('highlight'); + ddup.hzone.innerHTML = "Drop Files Here"; + }); + + // DROP TO UPLOAD FILE + ddup.hzone.addEventListener("dragover", function (e) { + e.preventDefault(); + e.stopPropagation(); + }); + ddup.hzone.addEventListener("drop", function (e) { + e.preventDefault(); + e.stopPropagation(); + ddup.hzone.classList.remove('highlight'); + ddup.hiddenfirst.style.display = "block" ; + if (e.dataTransfer.files.length > 0) { + ddup.hzone.classList.add('processing'); + ddup.hzone.innerHTML = "Uploading..."; + ddup.queue(e.dataTransfer.files); + } else { + ddup.hzone.classList.add('invalid'); + ddup.hzone.innerHTML = "Input is not recognized!"; + ddup.reset_text_timer(1500); + } + }); + } + + // (A3) DRAG-DROP UPLOAD NOT SUPPORTED + else { + ddup.hzone.style.display = "none"; + ddup.hform.style.display = "block"; + } + }, + + // (B) UPLOAD QUEUE + HANDLER + // NOTE: AJAX IS ASYNCHRONOUS + // A QUEUE IS REQUIRED TO STOP SERVER FLOOD + upqueue : [], // upload queue + uplock : false, // currently uploading a file + queue : function (files) { + // FILE LIST INTO QUEUE + for (let f of files) { + // OPTIONAL - SHOW UPLOAD STATUS + ddup.thisdiv = document.getElementById(f.name); + if (!ddup.thisdiv) { + // add new div with filename as id + ddup.hstat.innerHTML += `<div id="${f.name}">${f.name} - Added to queue</div>`; + } else { + // change contents of existing div + ddup.thisdiv.innerHTML = `${f.name} - Added to queue`; + } + // ADD TO QUEUE + ddup.upqueue.push(f); + } + // GO! + ddup.go(); + }, + + // (C) AJAX UPLOAD + go : function () { if (!ddup.uplock && ddup.upqueue.length!=0) { + // (C1) QUEUE STATUS UPDATE + ddup.uplock = true; + + // (C2) PLUCK OUT FIRST FILE IN QUEUE + let thisfile = ddup.upqueue[0]; + ddup.upqueue.shift(); + + // OPTIONAL - SHOW UPLOAD STATUS + ddup.thisdiv = document.getElementById(thisfile.name); + ddup.thisdiv.innerHTML = `${thisfile.name} - Upload started`; + // at start of queue, change color + ddup.hzone.classList.add('processing'); + ddup.hzone.innerHTML = "Uploading..."; + + // (C3) UPLOAD DATA + let data = new FormData(); + data.append('file', thisfile); + // ADD MORE POST DATA IF YOU WANT + // data.append("KEY", "VALUE"); + + // (C4) AJAX REQUEST + let xhr = new XMLHttpRequest(); + xhr.open("POST", "{{ server_prefix_ulp }}"); + xhr.setRequestHeader("lastModified", thisfile.lastModified/1000); + xhr.onload = function () { + // OPTIONAL - SHOW UPLOAD STATUS + ddup.thisdiv.innerHTML = `${thisfile.name} - ${this.response}`; + // NEXT BETTER PLAYER! + ddup.hzone.classList.remove('processing'); + ddup.hzone.innerHTML = "Drop Files Here"; + ddup.uplock = false; + ddup.go(); + }; + xhr.onerror = function(evt){ + // OPTIONAL - SHOW UPLOAD STATUS + ddup.thisdiv.innerHTML = `${thisfile.name} - AJAX ERROR`; + // NEXT BETTER PLAYER! + ddup.hzone.classList.remove('processing'); + ddup.hzone.innerHTML = "Drop Files Here"; + ddup.uplock = false; + ddup.go(); + }; + xhr.send(data); + } }, + + reset_text_timer : function (delay_ms) { + setTimeout(function (){ + ddup.hzone.classList.remove('invalid'); + ddup.hzone.innerHTML = "Drop Files Here"; + }, delay_ms); + } +}; +window.addEventListener("DOMContentLoaded", ddup.init); |