Skip to content

Commit

Permalink
add: generate QR code
Browse files Browse the repository at this point in the history
- enlarge header and footer
- add global and qr code buttons
- fixed header and change footer position to relative
- change name of download filefrom sha256 code to path parameter
- move JS code to `app.js` file
  • Loading branch information
datlt4 committed Feb 20, 2024
1 parent af318b7 commit ba33b98
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 173 deletions.
2 changes: 1 addition & 1 deletion fhost.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ def get(path, secret=None):
response.headers["Content-Length"] = f.size
response.headers["X-Accel-Redirect"] = "/" + str(fpath)
else:
response = send_from_directory(app.config["FHOST_STORAGE_PATH"], f.sha256, mimetype = f.mime)
response = send_from_directory(app.config["FHOST_STORAGE_PATH"], f.sha256, mimetype = f.mime, download_name=path)

response.headers["X-Expires"] = f.expiration
return response
Expand Down
21 changes: 16 additions & 5 deletions static/app.css
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
/* Custom Styles */
.header {
background-color: #343a40; /* Dark color similar to the header */
position: fixed;
top: 0;
width: 100%;
z-index: 1000;
}

#page-container {
flex: 1;
position: relative;
}

#content-wrap {
padding-bottom: 2.5rem; /* Footer height */
}

.footer {
background-color: #343a40; /* Dark color similar to the header */
padding: 20px 0;
text-align: center;
color: #fff; /* White text color */
position: fixed;
/* position: absolute; */
bottom: 0;
width: 100%;
}
Expand All @@ -23,10 +31,13 @@

/* Ensure content is pushed down when header and footer are fixed */
body {
padding-top: 56px; /* Height of the fixed header */
padding-bottom: 60px; /* Height of the fixed footer */
padding-top: 60px;
font-family: Arial, sans-serif;
line-height: 1.6;
display: flex;
flex-direction: column;
margin: 0;
min-height: 100vh; /* Ensure the body takes up at least the full viewport height */
}

/* Add some margin to the bottom of the body content */
Expand Down Expand Up @@ -79,7 +90,7 @@ li:before {
}

.indented-content {
padding-left: 3em;
padding-left: 1em;
}

.response-code {
Expand Down
205 changes: 205 additions & 0 deletions static/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
// Function to convert date to timestamp in milliseconds
function datetimeToTimestamp(dateString) {
var date = new Date(dateString);
return date.getTime();
}

function toggleSecret() {
var secretInput = document.getElementById("secret");
var enableSecretCheckbox = document.getElementById("enableSecret");
secretInput.disabled = !enableSecretCheckbox.checked;
}

function toggleExpiration() {
var expiresInput = document.getElementById('expires');
var datetimeInput = document.getElementById('datetimepicker');
var enableExpirationCheckbox = document.getElementById("enableExpiration");
expiresInput.disabled = !enableExpirationCheckbox.checked;
datetimeInput.disabled = !enableExpirationCheckbox.checked;
}

function submitForm() {
var spinnerElement = document.getElementById("spinner-submit");
spinnerElement.style.display = "block";
var submitButton = document.getElementById("submit-btn");
submitButton.disabled = true;
clearResponseText('response');
var fileInput = document.getElementById("file");
var file = fileInput.files[0];
var secretInput = document.getElementById("secret");
var secret = secretInput.value;

var expiresInput = document.getElementById('expires');
var datetimeInput = document.getElementById('datetimepicker');
var selectedDatetime = datetimeInput.value;
var timestamp = datetimeToTimestamp(selectedDatetime);
expiresInput.value = timestamp;

var form = document.getElementById("fileUploadForm");
var formData = new FormData(form);

var xhr = new XMLHttpRequest();
xhr.open("POST", "/");
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
showResponse(xhr.responseText.trim(), xhr.status, 'response');
} else if (xhr.status === 400) {
showResponse("400 Bad request", xhr.status, 'response');
} else if (xhr.status === 401) {
showResponse("401 Unauthorized", xhr.status, 'response');
} else if (xhr.status === 404) {
showResponse("404 Not Found", xhr.status, 'response');
} else if (xhr.status === 411) {
showResponse("411 Length Required", xhr.status, 'response');
} else if (xhr.status === 413) {
showResponse("413 Payload Too Large", xhr.status, 'response');
} else if (xhr.status === 451) {
showResponse("451 Unavailable For Legal Reasons", xhr.status, 'response');
} else {
showResponse("ERROR " + xhr.status, xhr.status, 'response');
}
}
spinnerElement.style.display = "none";
submitButton.disabled = false;
};
xhr.send(formData);
}

function submitShortenUrl() {
var spinnerElement = document.getElementById("spinner-submit-shorten-url");
spinnerElement.style.display = "block";
var submitButton = document.getElementById("submit-shorten-url-btn");
submitButton.disabled = true;
clearResponseText('responseShortenUrl');
var form = document.getElementById("shortenUrlForm");
var formData = new FormData(form);

var xhr = new XMLHttpRequest();
xhr.open("POST", "/");
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
showResponse(xhr.responseText.trim(), xhr.status, 'responseShortenUrl');
} else if (xhr.status === 400) {
showResponse("400 Bad request", xhr.status, 'responseShortenUrl');
} else if (xhr.status === 401) {
showResponse("401 Unauthorized", xhr.status, 'responseShortenUrl');
} else if (xhr.status === 404) {
showResponse("404 Not Found", xhr.status, 'responseShortenUrl');
} else if (xhr.status === 411) {
showResponse("411 Length Required", xhr.status, 'responseShortenUrl');
} else if (xhr.status === 413) {
showResponse("413 Payload Too Large", xhr.status, 'responseShortenUrl');
} else if (xhr.status === 451) {
showResponse("451 Unavailable For Legal Reasons", xhr.status, 'responseShortenUrl');
} else {
showResponse("ERROR " + xhr.status, xhr.status, 'responseShortenUrl');
}
}
spinnerElement.style.display = "none";
submitButton.disabled = false;
};
xhr.send(formData);
}

function clearResponseText(responseElementName) {
var responseDiv = document.getElementById(responseElementName);
responseDiv.style.display = "none";
responseDiv.textContent = ""; // Clear the response text
responseDiv.className = "";
}

function showResponse(text, statusCode, responseElementName) {
// Request successful
var responseDiv = document.getElementById(responseElementName);
responseDiv.style.display = "block";
var codeElement = document.createElement('code');
// Set its text content to the trimmed response
codeElement.textContent = text
codeElement.className = "response-code";// + responseElementName;
responseDiv.appendChild(codeElement);
responseDiv.role = "alert";
if (statusCode === 200) {
responseDiv.className = "mt-3 alert alert-success d-flex justify-content-between align-items-center";
codeElement.style.color = "#1c8556";
addButtons(text, responseElementName);
} else {
responseDiv.className = "mt-3 alert alert-danger d-flex justify-content-between align-items-center";
codeElement.style.color = "#dc3545";
}
}

// Function to add buttons
function addButtons(text, responseElementName) {
var buttonContainer = document.createElement("div");
buttonContainer.className = "button-container";
buttonContainer.id = "button-container-" + responseElementName
var responseDiv = document.getElementById(responseElementName);
responseDiv.appendChild(buttonContainer);
addCopyButton(text, responseElementName);
addUrlInNewTabButton(text, responseElementName);
addScanQrCodeButton(text, responseElementName);
}

// Function to add a copy button
function addCopyButton(text, responseElementName) {
var button = document.createElement("button");
button.className = "btn btn-success ms-2";
button.innerHTML = '<i class="bi bi-copy"></i>';
button.onclick = function () {copyToClipboard(text);};
var buttonContainer = document.getElementById("button-container-" + responseElementName);
buttonContainer.appendChild(button);
}

// Function to copy text to clipboard
function copyToClipboard(text) {
var textarea = document.createElement("textarea");
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand("copy");
document.body.removeChild(textarea);
alert("Copied to clipboard: " + text);
}

// Function to add a button access url in new tab
function addUrlInNewTabButton(url, responseElementName) {
var button = document.createElement("button");
button.className = "btn btn-info ms-2";
button.innerHTML = '<i class="bi bi-globe2"></i>';
button.onclick = function () {openUrlInNewTab(url);};
var buttonContainer = document.getElementById("button-container-" + responseElementName);
buttonContainer.appendChild(button);
}

// Open the URL in a new tab
function openUrlInNewTab(url) {
window.open(url, '_blank');
}

// Function to add a copy button
function addScanQrCodeButton(text, responseElementName) {
var button = document.createElement("button");
button.className = "btn btn-warning ms-2";
button.innerHTML = '<i class="bi bi-qr-code-scan"></i>';
button.setAttribute("data-bs-toggle", "modal");
button.setAttribute("data-bs-target", "#qrCodeModal-" + responseElementName);
var buttonContainer = document.getElementById("button-container-" + responseElementName);
buttonContainer.appendChild(button);
generateQrCode(text, responseElementName);
}

function generateQrCode(text, id) {
var qrCodeContainer = document.getElementById("qrCodeContainer-" + id);
qrCodeContainer.innerHTML = ""; // Clear previous QR code
// Generate QR code
var qr = new QRCode(qrCodeContainer, {
text: text,
width: 256,
height: 256,
colorDark: "#000000",
colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.H
});
}
2 changes: 1 addition & 1 deletion templates/footer.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!-- Footer -->
<footer class="footer">
<div class="container-md">
<div class="container-xxxl flex-md-nowrap">
<p>If you would like to request deletion, please contact Mia via IRC on Libera Chat, or send an email to [email protected] (do not copy and paste).</p>
<p>Please allow up to 24 hours for a response.</p>
</div>
Expand Down
13 changes: 6 additions & 7 deletions templates/header.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<nav class="navbar navbar-expand-lg navbar-dark bg-dark header">
<div class="container-md">
<!-- Logo and Service Name -->
<a class="navbar-brand" href="{{ url_for("fhost", _external=True).rstrip("/") }}">
<header class="navbar navbar-expand-md navbar-dark bd-navbar bg-dark header">
<nav class="container-xxxl flex-md-nowrap" aria-label="Main navigation">
<a class="navbar-brand d-flex align-items-center" href="{{ url_for('fhost', _external=True).rstrip('/') }}">
<img src="{{ url_for('static', filename='favicon.ico') }}" width="50" height="50" class="d-inline-block align-top" alt="ZXZ Logo">
<span class="mx-auto">ZXZ</span>
<span class="mx-auto" style="padding-left: 10px;">ZXZ</span>
</a>
</div>
</nav>
</nav>
</header>
Loading

0 comments on commit ba33b98

Please sign in to comment.