mirror of
https://github.com/lus/pasty.git
synced 2023-08-10 21:13:09 +03:00
Improve the web frontend (#9)
* Fix line flowing out of div * Revert line highlighting * Fix tab key behaviour * Move links and version information to a footer * Fix footer hiding last code line * Calculate line number offset based on line overflow * Refactor some code
This commit is contained in:
committed by
GitHub
parent
8cbb62070e
commit
90f25ec220
@@ -8,6 +8,12 @@ import * as notifications from "./notifications.js";
|
||||
buttons.setupButtons();
|
||||
buttons.setupKeybinds();
|
||||
|
||||
// Define element handles
|
||||
const versionElement = document.getElementById("version");
|
||||
const lineNOsElement = document.getElementById("linenos");
|
||||
const codeElement = document.getElementById("code");
|
||||
const inputElement = document.getElementById("input");
|
||||
|
||||
// Load the API information
|
||||
async function loadAPIInformation() {
|
||||
const response = await api.getAPIInformation();
|
||||
@@ -17,87 +23,91 @@ async function loadAPIInformation() {
|
||||
return;
|
||||
}
|
||||
const data = await response.json();
|
||||
document.getElementById("version").innerText = data.version;
|
||||
versionElement.innerText = data.version;
|
||||
}
|
||||
loadAPIInformation();
|
||||
|
||||
// Try to load a paste if one exists
|
||||
export let PASTE_ID;
|
||||
let CODE;
|
||||
async function loadPaste() {
|
||||
if (location.pathname !== "/") {
|
||||
// Define the paste ID and language
|
||||
const split = location.pathname.replace("/", "").split(".");
|
||||
const pasteID = split[0];
|
||||
const language = split[1];
|
||||
|
||||
|
||||
// Retrieve the paste from the API and redirect the user to the main page if it could not be found
|
||||
const response = await api.getPaste(pasteID);
|
||||
if (!response.ok) {
|
||||
location.replace(location.protocol + "//" + location.host);
|
||||
return;
|
||||
}
|
||||
const data = await response.json();
|
||||
|
||||
CODE = (await response.json()).content;
|
||||
|
||||
// Adjust the button states
|
||||
document.getElementById("btn_save").setAttribute("disabled", true);
|
||||
document.getElementById("btn_delete").removeAttribute("disabled");
|
||||
document.getElementById("btn_copy").removeAttribute("disabled");
|
||||
|
||||
|
||||
// Set the paste content to the DOM
|
||||
const code = document.getElementById("code");
|
||||
code.innerHTML = language
|
||||
? hljs.highlight(language, data.content).value
|
||||
: hljs.highlightAuto(data.content).value;
|
||||
|
||||
codeElement.innerHTML = language
|
||||
? hljs.highlight(language, CODE).value
|
||||
: hljs.highlightAuto(CODE).value;
|
||||
|
||||
// Display the line numbers
|
||||
const lineNOs = document.getElementById("linenos");
|
||||
lineNOs.innerHTML = data.content.split(/\n/).map((_, index) => `<span>${index + 1}</span>`).join('');
|
||||
renderLineNumbers();
|
||||
window.addEventListener("resize", renderLineNumbers);
|
||||
|
||||
const sharedLine = parseInt(window.location.hash.toLowerCase().replace("#l", ""), 10);
|
||||
if (sharedLine) {
|
||||
lineNOs.innerHTML = data.content.split(/\n/).map((_, index) => {
|
||||
return index + 1 === sharedLine
|
||||
? `<span class="highlight">${index + 1}</span>`
|
||||
: `<span>${index + 1}</span>`;
|
||||
}).join('');
|
||||
|
||||
let html = code.innerHTML.split(/\n/);
|
||||
html[sharedLine-1] = `<span class="highlight">${html[sharedLine-1]}</span>`;
|
||||
code.innerHTML = html.join("\n");
|
||||
}
|
||||
|
||||
// TODO: Update this shitty construct
|
||||
lineNOs.childNodes.forEach(node => {
|
||||
node.addEventListener("click", function(_) {
|
||||
const address = location.protocol + "//" + location.host + location.pathname + "#L" + node.innerText;
|
||||
location.replace(address);
|
||||
location.reload();
|
||||
});
|
||||
node.addEventListener("mouseover", function(_) {
|
||||
let html = code.innerHTML.split(/\n/);
|
||||
const index = parseInt(node.innerText, 10) - 1;
|
||||
html[index] = `<span class="highlight">${html[index]}</span>`;
|
||||
code.innerHTML = html.join("\n");
|
||||
});
|
||||
node.addEventListener("mouseout", function(_) {
|
||||
let html = code.innerHTML.split(/\n/);
|
||||
const index = parseInt(node.innerText, 10) - 1;
|
||||
html[index] = html[index].substring(24, html[index].length - 7);
|
||||
code.innerHTML = html.join("\n");
|
||||
});
|
||||
});
|
||||
|
||||
// Set the PASTE_ID variable
|
||||
PASTE_ID = pasteID;
|
||||
} else {
|
||||
const input = document.getElementById("input");
|
||||
input.classList.remove("hidden");
|
||||
input.focus();
|
||||
window.addEventListener("keydown", function(event) {
|
||||
inputElement.classList.remove("hidden");
|
||||
inputElement.focus();
|
||||
window.addEventListener("keydown", function (event) {
|
||||
if (event.keyCode != 9) return;
|
||||
event.preventDefault();
|
||||
input.value += " ";
|
||||
|
||||
insertTextAtCursor(inputElement, " ");
|
||||
});
|
||||
}
|
||||
}
|
||||
spinner.surround(loadPaste);
|
||||
spinner.surround(loadPaste);
|
||||
|
||||
function renderLineNumbers() {
|
||||
lineNOsElement.innerHTML = CODE.split(/\n/).map((line, index) => {
|
||||
let lineWidth = getTextWidth(line, "16px Source Code Pro");
|
||||
let linesSpace = Math.ceil(lineWidth / codeElement.offsetWidth);
|
||||
|
||||
let result = `<span>${index+1}</span>`;
|
||||
if (linesSpace > 1) {
|
||||
result += "<span></span>".repeat(linesSpace - 1);
|
||||
}
|
||||
return result;
|
||||
}).join("");
|
||||
}
|
||||
|
||||
// 1:1 skid from https://stackoverflow.com/questions/7404366/how-do-i-insert-some-text-where-the-cursor-is
|
||||
function insertTextAtCursor(element, text) {
|
||||
let value = element.value, endIndex, range, doc = element.ownerDocument;
|
||||
if (typeof element.selectionStart == "number"
|
||||
&& typeof element.selectionEnd == "number") {
|
||||
endIndex = element.selectionEnd;
|
||||
element.value = value.slice(0, endIndex) + text + value.slice(endIndex);
|
||||
element.selectionStart = element.selectionEnd = endIndex + text.length;
|
||||
} else if (doc.selection != "undefined" && doc.selection.createRange) {
|
||||
element.focus();
|
||||
range = doc.selection.createRange();
|
||||
range.collapse(false);
|
||||
range.text = text;
|
||||
range.select();
|
||||
}
|
||||
}
|
||||
|
||||
// Also a kind of skid
|
||||
function getTextWidth(text, font) {
|
||||
let canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
|
||||
let context = canvas.getContext("2d");
|
||||
context.font = font;
|
||||
return context.measureText(text).width;
|
||||
}
|
||||
@@ -6,10 +6,10 @@ import * as notifications from "./notifications.js";
|
||||
|
||||
// setupKeybinds initializes the keybinds for the buttons
|
||||
export function setupKeybinds() {
|
||||
window.addEventListener("keydown", function(event) {
|
||||
window.addEventListener("keydown", function (event) {
|
||||
// Return if the CTRL key was not pressed
|
||||
if (!event.ctrlKey) return;
|
||||
|
||||
|
||||
// Define the DOM element of the pressed button
|
||||
let element = null;
|
||||
switch (event.keyCode) {
|
||||
@@ -30,7 +30,7 @@ export function setupKeybinds() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Call the onClick function of the button
|
||||
if (element) {
|
||||
if (element.hasAttribute("disabled")) return;
|
||||
@@ -43,13 +43,13 @@ export function setupKeybinds() {
|
||||
// setupButtons configures the click listeners of the buttons
|
||||
export function setupButtons() {
|
||||
// Define the behavior of the 'new' button
|
||||
document.getElementById("btn_new").addEventListener("click", function() {
|
||||
document.getElementById("btn_new").addEventListener("click", function () {
|
||||
location.replace(location.protocol + "//" + location.host);
|
||||
});
|
||||
|
||||
// Define the behavior of the 'save' button
|
||||
document.getElementById("btn_save").addEventListener("click", function() {
|
||||
spinner.surround(async function() {
|
||||
document.getElementById("btn_save").addEventListener("click", function () {
|
||||
spinner.surround(async function () {
|
||||
// Return if the text area is empty
|
||||
const input = document.getElementById("input");
|
||||
if (!input.value) return;
|
||||
@@ -75,8 +75,8 @@ export function setupButtons() {
|
||||
});
|
||||
|
||||
// Define the behavior of the 'delete' button
|
||||
document.getElementById("btn_delete").addEventListener("click", function() {
|
||||
spinner.surround(async function() {
|
||||
document.getElementById("btn_delete").addEventListener("click", function () {
|
||||
spinner.surround(async function () {
|
||||
// Ask the user for the deletion token
|
||||
const deletionToken = prompt("Deletion Token:");
|
||||
if (!deletionToken) return;
|
||||
@@ -95,11 +95,11 @@ export function setupButtons() {
|
||||
});
|
||||
|
||||
// Define the behavior of the 'copy' button
|
||||
document.getElementById("btn_copy").addEventListener("click", function() {
|
||||
spinner.surround(async function() {
|
||||
document.getElementById("btn_copy").addEventListener("click", function () {
|
||||
spinner.surround(async function () {
|
||||
// Ask for the clipboard permissions
|
||||
askClipboardPermissions();
|
||||
|
||||
|
||||
// Copy the code
|
||||
await navigator.clipboard.writeText(document.getElementById("code").innerText);
|
||||
notifications.success("Copied the code!");
|
||||
|
||||
@@ -18,7 +18,5 @@ function create(type, message, duration) {
|
||||
node.innerHTML = message;
|
||||
|
||||
element.appendChild(node);
|
||||
setTimeout(function() {
|
||||
element.removeChild(node);
|
||||
}, duration);
|
||||
setTimeout(() => element.removeChild(node), duration);
|
||||
}
|
||||
Reference in New Issue
Block a user