Merge pull request #12 from JustKato/feature/syntax_highlight

Feature/syntax highlight
This commit is contained in:
Daniel Legt 2022-06-01 18:29:48 +03:00 committed by GitHub
commit 781b4bcf80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1524 additions and 55 deletions

View File

@ -1,3 +1,6 @@
# 1.4.0 🖌
Syntax highlight has been implemented, as well as a couple security concerns being patched. Thank you to everyone that has helped me out with those
# 1.3.0 👀 # 1.3.0 👀
Implemented a views system, now everyone can see how many times a pad has been accessed, an auto-save has also been added for those views to file in the `data` dir. Implemented a views system, now everyone can see how many times a pad has been accessed, an auto-save has also been added for those views to file in the `data` dir.

View File

@ -1,6 +1,6 @@
FROM alpine FROM alpine
LABEL version="1.3.0" LABEL version="1.4.0"
# Copy the distribution files # Copy the distribution files
COPY ./dist /app COPY ./dist /app

View File

@ -6,7 +6,7 @@ func ApplyHeaders(router *gin.Engine) {
router.Use(func(ctx *gin.Context) { router.Use(func(ctx *gin.Context) {
// Apply the header // Apply the header
ctx.Header("FreePad-Version", "1.3.0") ctx.Header("FreePad-Version", "1.4.0")
// Move on // Move on
ctx.Next() ctx.Next()

View File

@ -34,7 +34,7 @@ func getViewsFilePath() (string, error) {
// Check if the file exists // Check if the file exists
if _, err := os.Stat(filePath); errors.Is(err, os.ErrNotExist) { if _, err := os.Stat(filePath); errors.Is(err, os.ErrNotExist) {
// Create the file // Create the file
err := os.WriteFile(filePath, []byte(""), 0777) err := os.WriteFile(filePath, []byte(""), 0640)
if err != nil { if err != nil {
return ``, err return ``, err
} }
@ -126,7 +126,7 @@ func SavePostViewsCache() error {
return err return err
} }
f, err := os.OpenFile(viewsFilePath, os.O_WRONLY|os.O_CREATE, 0777) f, err := os.OpenFile(viewsFilePath, os.O_WRONLY|os.O_CREATE, 0640)
if err != nil { if err != nil {
return err return err
} }
@ -162,7 +162,7 @@ func getStorageDirectory() string {
// Check if the base storage path exists // Check if the base storage path exists
if _, err := os.Stat(baseStoragePath); os.IsNotExist(err) { if _, err := os.Stat(baseStoragePath); os.IsNotExist(err) {
// Looks like the base storage path was NOT set, create the dir // Looks like the base storage path was NOT set, create the dir
err = os.Mkdir(baseStoragePath, 0777) err = os.Mkdir(baseStoragePath, 0640)
// Check for errors // Check for errors
if err != nil { if err != nil {
// No way this sends an error unless it goes horribly wrong. // No way this sends an error unless it goes horribly wrong.
@ -233,8 +233,6 @@ func WritePost(p Post) error {
if err != nil { if err != nil {
return err return err
} }
// Actually close the file
defer f.Close()
// Write the contnets // Write the contnets
_, err = f.WriteString(p.Content) _, err = f.WriteString(p.Content)
@ -242,11 +240,7 @@ func WritePost(p Post) error {
return err return err
} }
if err := f.Close(); err != nil { return f.Close()
return err
}
return nil
} }
// Cleanup all of the older posts based on the environment settings // Cleanup all of the older posts based on the environment settings

View File

@ -39,7 +39,7 @@ func HomeRoutes(router *gin.Engine) {
if err == nil { if err == nil {
postName = newPostName postName = newPostName
} }
postName = sanitize.AlphaNumeric(postName, true) postName = sanitize.XSS(sanitize.SingleLine(postName))
post := objects.GetPost(postName) post := objects.GetPost(postName)
@ -63,7 +63,7 @@ func HomeRoutes(router *gin.Engine) {
if err == nil { if err == nil {
postName = newPostName postName = newPostName
} }
postName = sanitize.AlphaNumeric(postName, true) postName = sanitize.XSS(sanitize.SingleLine(postName))
p := objects.Post{ p := objects.Post{
Name: postName, Name: postName,

View File

@ -1,3 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@300&display=swap');
:root { :root {
--color-border-default: #444c56; --color-border-default: #444c56;
--color-fg-default: #adbac7; --color-fg-default: #adbac7;
@ -35,6 +37,48 @@ main#main-card {
right: .5rem; right: .5rem;
} }
.hidden {
display: none !important;
}
#pad-content, #textarea-preview {
tab-size: 2;
font-family: 'Roboto Mono', monospace !important;
}
#pad-content-area {
position: relative;
display: flex;
flex-flow: column;
}
.edit-content-text {
display: none;
}
.read-only-content .edit-content-text {
display: block !important;
}
.read-only-content .view-content-text {
display: none !important;
}
#pad-content-toggler {
position: absolute;
top: .5rem;
right: .5rem;
user-select: none;
}
#textarea-preview {
max-height: calc(17rem + 30vh);
min-height: 17rem;
overflow: auto;
}
textarea:focus, textarea:focus,
input[type="text"]:focus, input[type="text"]:focus,
@ -56,3 +100,27 @@ input[type="color"]:focus,
box-shadow: none; box-shadow: none;
outline: 0 none; outline: 0 none;
} }
/* ===== Scrollbar CSS ===== */
/* Firefox */
* {
scrollbar-width: thin;
scrollbar-color: #3b3b3b #ffffff00;
}
/* Chrome, Edge, and Safari */
*::-webkit-scrollbar {
width: 7px;
height: 7px;
}
*::-webkit-scrollbar-track {
background: #ffffff00;
}
*::-webkit-scrollbar-thumb {
background-color: #3b3b3b;
border-radius: 2px;
border: 1px solid #ffffff00;
}

View File

@ -3,12 +3,12 @@ function sendMyData(el) {
const formData = new FormData(); const formData = new FormData();
// Check if the writing watch was sending something already // Check if the writing watch was sending something already
if ( !!window.writingWatch ) { if (!!window.writingWatch) {
// Clear old timeout // Clear old timeout
clearTimeout(window.writingWatch); clearTimeout(window.writingWatch);
} }
if ( el.value.length > maximumPadSize ) { if (el.value.length > maximumPadSize) {
let err = new Error(`Your Pad is too big! Please keep it limited to ${maximumPadSize} characters!`); let err = new Error(`Your Pad is too big! Please keep it limited to ${maximumPadSize} characters!`);
alert(err); alert(err);
throw err; throw err;
@ -16,6 +16,13 @@ function sendMyData(el) {
el.setAttribute(`readonly`, `1`); el.setAttribute(`readonly`, `1`);
const textareaPreview = document.getElementById(`textarea-preview`)
if (!!textareaPreview) {
textareaPreview.textContent = el.value;
hljs.highlightElement(document.getElementById(`textarea-preview`));
}
formData.set("content", el.value); formData.set("content", el.value);
updateStatus(`Attempting to save...`, `text-warning`); updateStatus(`Attempting to save...`, `text-warning`);
@ -24,36 +31,36 @@ function sendMyData(el) {
body: formData, body: formData,
method: "post", method: "post",
}) })
.then( resp => { .then(resp => {
resp.json() resp.json()
.then( e => { .then(e => {
document.getElementById(`last_modified_`).value = e.pad.last_modified; document.getElementById(`last_modified_`).value = e.pad.last_modified;
updateStatus(`Succesfully Saved`, `text-success`); updateStatus(`Succesfully Saved`, `text-success`);
})
.catch(err => {
updateStatus(`Failed to Save`, `text-danger`);
console.error(err);
})
}) })
.catch( err => { .catch(err => {
updateStatus(`Failed to Save`, `text-danger`); updateStatus(`Failed to Save`, `text-danger`);
console.error(err); console.error(err);
}) })
}) .finally(() => {
.catch( err => { el.removeAttribute(`readonly`);
updateStatus(`Failed to Save`, `text-danger`); })
console.error(err);
})
.finally( () => {
el.removeAttribute(`readonly`);
})
} }
function toggleWritingWatch(el) { function toggleWritingWatch(el) {
// Check if the writing watch was sending something already // Check if the writing watch was sending something already
if ( !!window.writingWatch ) { if (!!window.writingWatch) {
// Clear old timeout // Clear old timeout
clearTimeout(window.writingWatch); clearTimeout(window.writingWatch);
} }
// Set a timeout for the action // Set a timeout for the action
window.writingWatch = setTimeout( () => { window.writingWatch = setTimeout(() => {
// Send out the data // Send out the data
sendMyData(el) sendMyData(el)
}, 750) }, 750)
@ -74,7 +81,7 @@ function getLocalArchives() {
let a = localStorage.getItem(`${padTitle}_archives`); let a = localStorage.getItem(`${padTitle}_archives`);
// Check if we had anything in storage for the archives // Check if we had anything in storage for the archives
if ( a == null ) { if (a == null) {
// There were nothing in storage // There were nothing in storage
return []; return [];
} }
@ -82,7 +89,7 @@ function getLocalArchives() {
try { try {
// Try and parse the json // Try and parse the json
a = JSON.parse(a); a = JSON.parse(a);
} catch ( err ) { } catch (err) {
// Return null of the fail // Return null of the fail
return []; return [];
} }
@ -93,7 +100,7 @@ function getLocalArchives() {
function storeArchives(archives) { function storeArchives(archives) {
// Check if the provided list is an array // Check if the provided list is an array
if ( !Array.isArray(archives) ) return; if (!Array.isArray(archives)) return;
// Set the current archives // Set the current archives
localStorage.setItem(`${padTitle}_archives`, JSON.stringify(archives)); localStorage.setItem(`${padTitle}_archives`, JSON.stringify(archives));
@ -105,13 +112,13 @@ function renderArchivesSelection() {
const archivesSelection = document.getElementById(`archives-selection`); const archivesSelection = document.getElementById(`archives-selection`);
const rowTemplate = document.getElementById(`archive-selection-example`); const rowTemplate = document.getElementById(`archive-selection-example`);
// Clear any old optiosn // Clear any old optiosn
archivesSelection.querySelectorAll(`.dropdown-item:not(#do-archive-button):not(#archive-selection-example)`).forEach( el => { archivesSelection.querySelectorAll(`.dropdown-item:not(#do-archive-button):not(#archive-selection-example)`).forEach(el => {
// Remove the element // Remove the element
el.remove(); el.remove();
}) })
// Get the current list of available archives // Get the current list of available archives
for ( let a of getLocalArchives() ) { for (let a of getLocalArchives()) {
// Clone the template row // Clone the template row
const row = rowTemplate.cloneNode(true); const row = rowTemplate.cloneNode(true);
@ -130,7 +137,7 @@ function renderArchivesSelection() {
let resp = confirm("Load contents of pad from memory? This will overwrite the current pad for everyone."); let resp = confirm("Load contents of pad from memory? This will overwrite the current pad for everyone.");
if ( !!resp ) { if (!!resp) {
document.getElementById(`pad-content`).value = a.content; document.getElementById(`pad-content`).value = a.content;
} }
}) })
@ -142,7 +149,7 @@ function renderArchivesSelection() {
function saveLocalArchive() { function saveLocalArchive() {
let resp = confirm("Save a local copy of the current Pad?"); let resp = confirm("Save a local copy of the current Pad?");
if ( !resp ) { if (!resp) {
// Do not // Do not
return; return;
} }
@ -173,7 +180,7 @@ function generateQRCode() {
// Add new qr // Add new qr
new QRCode(qrcodeContainer, { new QRCode(qrcodeContainer, {
text: window.location.toString(), text: window.location.toString(),
width: 256, width: 256,
height: 256, height: 256,
colorDark: "#555273", colorDark: "#555273",
colorLight: "#ffffff", colorLight: "#ffffff",
@ -184,11 +191,35 @@ function generateQRCode() {
MicroModal.show(`qrmodal`) MicroModal.show(`qrmodal`)
} }
document.addEventListener(`DOMContentLoaded`, e => { function toggleTextareaPreview() {
setTextareaPreview(!document.getElementById(`pad-content-toggler`).classList.contains(`read-only`))
}
{ // Textarea Focusing // t == true - Read Only
const textarea = document.getElementById(`pad-content`); // t == false - Edit mode
function setTextareaPreview(t = true) {
const prev = document.getElementById(`textarea-preview`)
const textarea = document.getElementById(`pad-content`);
const toggler = document.getElementById(`pad-content-toggler`);
const padContentArea = document.getElementById(`pad-content-area`);
if (t) {
// Toggle read only
prev.classList.remove(`hidden`)
toggler.classList.add(`read-only`);
padContentArea.classList.add(`read-only-content`);
textarea.classList.add(`hidden`);
} else {
// Toggle edit mode
prev.classList.add(`hidden`)
toggler.classList.remove(`read-only`);
padContentArea.classList.remove(`read-only-content`);
textarea.classList.remove(`hidden`);
// Focus // Focus
textarea.focus(); textarea.focus();
// Scroll // Scroll
@ -197,6 +228,38 @@ document.addEventListener(`DOMContentLoaded`, e => {
textarea.setSelectionRange(textarea.value.length, textarea.value.length); textarea.setSelectionRange(textarea.value.length, textarea.value.length);
} }
}
document.addEventListener(`DOMContentLoaded`, e => {
{ // Textarea Handling
const textarea = document.getElementById(`pad-content`);
setTextareaPreview(!!textarea.value);
// Make sure tabs are taken into consideration
textarea.addEventListener('keydown', function (e) {
if (e.key == 'Tab') {
e.preventDefault();
const start = this.selectionStart;
const end = this.selectionEnd;
// set textarea value to: text before caret + tab + text after caret
this.value = this.value.substring(0, start) +
"\t" + this.value.substring(end);
// put caret at right position again
this.selectionStart =
this.selectionEnd = start + 1;
}
});
}
try { // highlights
hljs.highlightElement(document.getElementById(`textarea-preview`));
} catch ( err ) {
console.err(err);
}
{ // Archives { // Archives
renderArchivesSelection() renderArchivesSelection()
} }

View File

@ -14,8 +14,14 @@ class Pad {
// Create a new blob of the contents of the pad // Create a new blob of the contents of the pad
var blob = new Blob([ document.getElementById(`pad-content`).value ], { type: "text/plain;charset=utf-8" }); var blob = new Blob([ document.getElementById(`pad-content`).value ], { type: "text/plain;charset=utf-8" });
let downloadFileName = this.title;
if ( !this.title.includes(`.`) ) {
// Append a default file format
downloadFileName += `.txt`;
}
// Save the blob as // Save the blob as
saveAs(blob, `${this.title}.txt`); saveAs(blob, `${downloadFileName}`);
} }
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,6 @@
/*!
* Bootstrap-Dark-5 v1.1.3 (https://vinorodrigues.github.io/bootstrap-dark-5/)
* Copyright 2021 Vino Rodrigues
* Licensed under MIT (https://github.com/vinorodrigues/bootstrap-dark-5/blob/main/LICENSE.md)
*/
"use strict";class DarkMode{constructor(){this._hasGDPRConsent=!1,this.cookieExpiry=365,"loading"===document.readyState?document.addEventListener("DOMContentLoaded",(function(){DarkMode.onDOMContentLoaded()})):DarkMode.onDOMContentLoaded()}get inDarkMode(){return DarkMode.getColorScheme()==DarkMode.VALUE_DARK}set inDarkMode(e){this.setDarkMode(e,!1)}get hasGDPRConsent(){return this._hasGDPRConsent}set hasGDPRConsent(e){if(this._hasGDPRConsent=e,e){const e=DarkMode.readCookie(DarkMode.DATA_KEY);e&&(DarkMode.saveCookie(DarkMode.DATA_KEY,"",-1),localStorage.setItem(DarkMode.DATA_KEY,e))}else{const e=localStorage.getItem(DarkMode.DATA_KEY);e&&(localStorage.removeItem(DarkMode.DATA_KEY),DarkMode.saveCookie(DarkMode.DATA_KEY,e))}}get documentRoot(){return document.getElementsByTagName("html")[0]}static saveCookie(e,o="",t=365){let a="";if(t){const e=new Date;e.setTime(e.getTime()+24*t*60*60*1e3),a="; expires="+e.toUTCString()}document.cookie=e+"="+o+a+"; SameSite=Strict; path=/"}saveValue(e,o,t=this.cookieExpiry){this.hasGDPRConsent?DarkMode.saveCookie(e,o,t):localStorage.setItem(e,o)}static readCookie(e){const o=e+"=",t=document.cookie.split(";");for(let e=0;e<t.length;e++){const a=t[e].trim();if(a.startsWith(o))return a.substring(o.length)}return""}readValue(e){if(this.hasGDPRConsent)return DarkMode.readCookie(e);{const o=localStorage.getItem(e);return o||""}}eraseValue(e){this.hasGDPRConsent?this.saveValue(e,"",-1):localStorage.removeItem(e)}getSavedColorScheme(){const e=this.readValue(DarkMode.DATA_KEY);return e||""}getPreferedColorScheme(){return window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?DarkMode.VALUE_DARK:window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches?DarkMode.VALUE_LIGHT:""}setDarkMode(e,o=!0){const t=document.querySelectorAll("[data-"+DarkMode.DATA_SELECTOR+"]");if(0==t.length)e?(this.documentRoot.classList.remove(DarkMode.CLASS_NAME_LIGHT),this.documentRoot.classList.add(DarkMode.CLASS_NAME_DARK)):(this.documentRoot.classList.remove(DarkMode.CLASS_NAME_DARK),this.documentRoot.classList.add(DarkMode.CLASS_NAME_LIGHT));else for(let o=0;o<t.length;o++)t[o].setAttribute("data-"+DarkMode.DATA_SELECTOR,e?DarkMode.VALUE_DARK:DarkMode.VALUE_LIGHT);o&&this.saveValue(DarkMode.DATA_KEY,e?DarkMode.VALUE_DARK:DarkMode.VALUE_LIGHT)}toggleDarkMode(e=!0){let o;const t=document.querySelector("[data-"+DarkMode.DATA_SELECTOR+"]");o=t?t.getAttribute("data-"+DarkMode.DATA_SELECTOR)==DarkMode.VALUE_DARK:this.documentRoot.classList.contains(DarkMode.CLASS_NAME_DARK),this.setDarkMode(!o,e)}resetDarkMode(){this.eraseValue(DarkMode.DATA_KEY);const e=this.getPreferedColorScheme();if(e)this.setDarkMode(e==DarkMode.VALUE_DARK,!1);else{const e=document.querySelectorAll("[data-"+DarkMode.DATA_SELECTOR+"]");if(0==e.length)this.documentRoot.classList.remove(DarkMode.CLASS_NAME_LIGHT),this.documentRoot.classList.remove(DarkMode.CLASS_NAME_DARK);else for(let o=0;o<e.length;o++)e[o].setAttribute("data-"+DarkMode.DATA_SELECTOR,"")}}static getColorScheme(){const e=document.querySelector("[data-"+DarkMode.DATA_SELECTOR+"]");if(e){const o=e.getAttribute("data-"+DarkMode.DATA_SELECTOR);return o==DarkMode.VALUE_DARK||o==DarkMode.VALUE_LIGHT?o:""}return darkmode.documentRoot.classList.contains(DarkMode.CLASS_NAME_DARK)?DarkMode.VALUE_DARK:darkmode.documentRoot.classList.contains(DarkMode.CLASS_NAME_LIGHT)?DarkMode.VALUE_LIGHT:""}static updatePreferedColorSchemeEvent(){let e=darkmode.getSavedColorScheme();e||(e=darkmode.getPreferedColorScheme(),e&&darkmode.setDarkMode(e==DarkMode.VALUE_DARK,!1))}static onDOMContentLoaded(){let e=darkmode.readValue(DarkMode.DATA_KEY);e||(e=DarkMode.getColorScheme(),e||(e=darkmode.getPreferedColorScheme()));const o=e==DarkMode.VALUE_DARK;darkmode.setDarkMode(o,!1),window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",(function(){DarkMode.updatePreferedColorSchemeEvent()}))}}DarkMode.DATA_KEY="bs.prefers-color-scheme",DarkMode.DATA_SELECTOR="bs-color-scheme",DarkMode.VALUE_LIGHT="light",DarkMode.VALUE_DARK="dark",DarkMode.CLASS_NAME_LIGHT="light",DarkMode.CLASS_NAME_DARK="dark";const darkmode=new DarkMode;

1173
static/vendor/hljs/highlight.min.js vendored Normal file

File diff suppressed because one or more lines are too long

98
static/vendor/hljs/theme.css vendored Normal file
View File

@ -0,0 +1,98 @@
/*!
Theme: a11y-dark
Author: @ericwbailey
Maintainer: @ericwbailey
Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css
*/
.hljs {
background: #2b2b2b;
color: #f8f8f2;
}
/* Comment */
.hljs-comment,
.hljs-quote {
color: #d4d0ab;
}
/* Red */
.hljs-variable,
.hljs-template-variable,
.hljs-tag,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-regexp,
.hljs-deletion {
color: #ffa07a;
}
/* Orange */
.hljs-number,
.hljs-built_in,
.hljs-literal,
.hljs-type,
.hljs-params,
.hljs-meta,
.hljs-link {
color: #f5ab35;
}
/* Yellow */
.hljs-attribute {
color: #ffd700;
}
/* Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet,
.hljs-addition {
color: #abe338;
}
/* Blue */
.hljs-title,
.hljs-section {
color: #00e0e0;
}
/* Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #dcc6e0;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
@media screen and (-ms-high-contrast: active) {
.hljs-addition,
.hljs-attribute,
.hljs-built_in,
.hljs-bullet,
.hljs-comment,
.hljs-link,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-params,
.hljs-string,
.hljs-symbol,
.hljs-type,
.hljs-quote {
color: highlight;
}
.hljs-keyword,
.hljs-selector-tag {
font-weight: bold;
}
}

File diff suppressed because one or more lines are too long

1
static/vendor/qrcodejs/qrcode.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
{{ define "inc/footer.html"}} {{ define "inc/footer.html"}}
<script src="https://cdn.jsdelivr.net/npm/bootstrap-dark-5@1.1.3/dist/js/darkmode.min.js"></script> <script src="/static/vendor/bootstrap/darkmode.min.js"></script>
<script src="/static/js/main.js"></script> <script src="/static/js/main.js"></script>
{{ end }} {{ end }}

View File

@ -14,7 +14,7 @@
<meta name="color-scheme" content="light dark"> <meta name="color-scheme" content="light dark">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-dark-5@1.1.3/dist/css/bootstrap-nightshade.min.css" rel="stylesheet"> <link href="/static/vendor/bootstrap/bootstrap-nightshade.min.css" rel="stylesheet">
<!-- Love https://vinorodrigues.github.io/bootstrap-dark-5/ --> <!-- Love https://vinorodrigues.github.io/bootstrap-dark-5/ -->
<link rel="stylesheet" href="/static/css/main.css"> <link rel="stylesheet" href="/static/css/main.css">
</head> </head>

View File

@ -46,6 +46,22 @@
just write it in the box above and get to the right page, write anything in just write it in the box above and get to the right page, write anything in
and access the same address on any other device to get your info! and access the same address on any other device to get your info!
</p> </p>
<small>A couple hints:</small>
<p>
Pads take into consideration file extensions, use <code>.json</code>,
<code>.js</code>, <code>.cpp</code>, <code>.txt</code>, etc... to help
parse your type of file
</p>
<p>
The archival feature helps you store information on your local machine! Save your
pads and you can always come back and rewrite them exactly as they have been
</p>
<p>
All pads can be publicly edited, so if you choose some common name
and someone elses accesses the link they can completely remove/edit
what you wrote, not to mention seein that information, so refrain
from sharing important data here.
</p>
</div> </div>
</div> </div>

View File

@ -21,6 +21,8 @@
var padTitle = {{.title }}; var padTitle = {{.title }};
</script> </script>
<link rel="stylesheet" href="/static/vendor/hljs/theme.css">
<body> <body>
<main id="main-card" class="container rounded mt-5 shadow-sm"> <main id="main-card" class="container rounded mt-5 shadow-sm">
@ -35,9 +37,27 @@
<h2 class="mb-4">{{.title}}</h2> <h2 class="mb-4">{{.title}}</h2>
<textarea maxlength="{{.maximumPadSize}}" name="pad-content" id="pad-content" onchange="sendMyData(this)" <div id="pad-content-area">
onkeydown="updateStatus(`Not Saved`, `text-warning`); toggleWritingWatch(this)" <div class="btn-sm btn" id="pad-content-toggler" onclick="toggleTextareaPreview()">
class="form-control">{{.post_content}}</textarea> <span class="edit-content-text" title="Edit Content">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pencil" viewBox="0 0 16 16">
<path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/>
</svg>
</span>
<span class="view-content-text" title="ReadOnly">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eyeglasses" viewBox="0 0 16 16">
<path d="M4 6a2 2 0 1 1 0 4 2 2 0 0 1 0-4zm2.625.547a3 3 0 0 0-5.584.953H.5a.5.5 0 0 0 0 1h.541A3 3 0 0 0 7 8a1 1 0 0 1 2 0 3 3 0 0 0 5.959.5h.541a.5.5 0 0 0 0-1h-.541a3 3 0 0 0-5.584-.953A1.993 1.993 0 0 0 8 6c-.532 0-1.016.208-1.375.547zM14 8a2 2 0 1 1-4 0 2 2 0 0 1 4 0z"/>
</svg>
</span>
</div>
<pre><code id="textarea-preview" class="form-control hidden">{{.post_content}}</code></pre>
<textarea maxlength="{{.maximumPadSize}}" name="pad-content" id="pad-content" onchange="sendMyData(this)"
onkeydown="updateStatus(`Not Saved`, `text-warning`); toggleWritingWatch(this)"
class="form-control hidden">{{.post_content}}</textarea>
</div>
<div id="pad-status" class="my-4 row"> <div id="pad-status" class="my-4 row">
<div class="col-md-12 col-lg-4 col-xl-4" title="Status"> <div class="col-md-12 col-lg-4 col-xl-4" title="Status">
@ -192,10 +212,11 @@
<script src="/static/js/fileSaver.js"></script> <script src="/static/js/fileSaver.js"></script>
<script src="/static/js/pad.js"></script> <script src="/static/js/pad.js"></script>
<script src="/static/js/pad-scripts.js"></script> <script src="/static/js/pad-scripts.js"></script>
<script src="/static/vendor/hljs/highlight.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> <script src="/static/vendor/bootstrap/bootstrap.bundle.min.js"></script>
<script src="https://cdn.rawgit.com/davidshimjs/qrcodejs/gh-pages/qrcode.min.js"></script> <script src="/static/vendor/qrcodejs/qrcode.min.js"></script>
<script src="https://unpkg.com/micromodal/dist/micromodal.min.js"></script> <script src="/static/vendor/micromodal/micromodal.min.js"></script>
<script> <script>
window.pad = new Pad({{.title }}, {{.last_modified }}); window.pad = new Pad({{.title }}, {{.last_modified }});