Add what you see is what you get markdown using pell

This commit is contained in:
Tracker-Friendly 2024-07-02 18:13:28 +01:00
parent 0c35db92ba
commit 5ffa65212c
11 changed files with 11067 additions and 3657 deletions

View File

@ -9,8 +9,6 @@
<link rel="stylesheet" type="text/css" href="/static/css/style.css" /> <link rel="stylesheet" type="text/css" href="/static/css/style.css" />
<script type="text/javascript" src="/static/js/hash-wasm.js"></script> <script type="text/javascript" src="/static/js/hash-wasm.js"></script>
<script type="text/javascript" src="/static/js/crypto-js.js"></script> <script type="text/javascript" src="/static/js/crypto-js.js"></script>
<script type="text/javascript" src="/static/js/marked.js"></script>
<script type="text/javascript" src="/static/js/purify.js"></script>
<link rel="icon" href="/static/svg/favicon.svg"> <link rel="icon" href="/static/svg/favicon.svg">
</head> </head>
@ -23,7 +21,6 @@
<div class="modernToolbar"> <div class="modernToolbar">
<button class="usernameBox hidden" onclick="handleGesture()" id="backButton"><div class="vcenter"><img alt="Back arrow" src="/static/svg/arrow-back.svg"></div></button> <button class="usernameBox hidden" onclick="handleGesture()" id="backButton"><div class="vcenter"><img alt="Back arrow" src="/static/svg/arrow-back.svg"></div></button>
<button class="count" id="wordCountBox">0 words</button> <button class="count" id="wordCountBox">0 words</button>
<button onclick="toggleMarkdown()" class="usernameBox"><div class="vcenter"><img alt="Enable markdown" src="/static/svg/markdown.svg"></div></button>
<button id="usernameBox" class="usernameBox"><div class="vcenter"><img alt="Account settings" src="/static/svg/acct-settings.svg"></div></button> <button id="usernameBox" class="usernameBox"><div class="vcenter"><img alt="Account settings" src="/static/svg/acct-settings.svg"></div></button>
</div> </div>
</div> </div>
@ -90,17 +87,17 @@
</div> </div>
<div class="noteBox" id="noteBoxDiv"> <div class="noteBox" id="noteBoxDiv">
<textarea id="noteBox" class="noteBoxText"></textarea> <div id="noteBox" class="noteBoxText"></div>
<iframe id="markdown" style="display: none;" sandbox=""></iframe>
</div> </div>
<script type="text/javascript" src="/static/js/main.js"></script>
<script> <script>
for (let i = 0; i < 40; i++) { for (let i = 0; i < 40; i++) {
notesDiv.appendChild(loadingStuff.cloneNode()) notesDiv.appendChild(loadingStuff.cloneNode())
} }
loadingStuff.remove() loadingStuff.remove()
</script> </script>
<script src="https://unpkg.com/pell"></script>
<script type="text/javascript" src="/static/js/main.js"></script>
</body> </body>
</html> </html>

View File

@ -385,21 +385,17 @@ body {
width: calc(100% - 200px); width: calc(100% - 200px);
height: calc(100% - 50px - 30px); height: calc(100% - 50px - 30px);
font-family: "Inter", sans-serif; font-family: "Inter", sans-serif;
display: flex;
flex-direction: row;
margin: 10px; margin: 10px;
outline: none; outline: none;
z-index: -1; z-index: -1;
} }
.noteBox.mobile { .noteBox.mobile {
flex-direction: column-reverse;
margin: 15px 0 0; margin: 15px 0 0;
height: calc(100% - 50px); height: calc(100% - 50px);
} }
.noteBoxText { .noteBoxText {
resize: none;
background-color: var(--editor); background-color: var(--editor);
color: var(--text-color); color: var(--text-color);
border: none; border: none;
@ -407,13 +403,29 @@ body {
height: 100%; height: 100%;
font-family: "Inter", sans-serif; font-family: "Inter", sans-serif;
outline: none; outline: none;
margin-top: 5px;
} }
iframe#markdown { .pell-content {
width: 100%; width: 100%;
height: 100%; height: calc(100% - 20px);
border: none; overflow-y: scroll;
border-left: solid var(--bar) 1px; }
.pell-button {
background-color: var(--button);
border: 1px var(--border-color) solid;
width: 35px;
height: 35px;
margin-left: 1px;
margin-right: 1px;
border-radius: 10px;
}
.pell-actionbar {
display: flex;
justify-content: space-evenly;
margin-bottom: 5px;
} }
.noteBox:focus { .noteBox:focus {

View File

@ -1,9 +1,11 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat // @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat
/* /*
Beautified version of crypto-js, to maintain compatibility with uMatrix * Beautified version of:
Beautified from https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js * crypto-js (https://www.npmjs.com/package/crypto-js)
*/ * (c) Crypto-JS
* @license MIT
*/
! function(t, e) { ! function(t, e) {
"object" == typeof exports ? module.exports = exports = e() : "function" == typeof define && define.amd ? define([], e) : t.CryptoJS = e() "object" == typeof exports ? module.exports = exports = e() : "function" == typeof define && define.amd ? define([], e) : t.CryptoJS = e()

View File

@ -26,11 +26,11 @@ function showElements(yesorno) {
} }
} }
changeButton.addEventListener("click", (event) => { changeButton.addEventListener("click", () => {
async function doStuff() { async function doStuff() {
let remote = homeserverBox.value let remote = homeserverBox.value
if (remote == "") { if (remote === "") {
statusBox.innerText = "A homeserver is required!" statusBox.innerText = "A homeserver is required!"
return return
} }
@ -38,11 +38,16 @@ changeButton.addEventListener("click", (event) => {
showElements(false) showElements(false)
statusBox.innerText = "Connecting to homeserver..." statusBox.innerText = "Connecting to homeserver..."
fetch(remote + "/api/version") fetch(remote + "/api/versionjson")
.then((response) => response) .then((response) => response)
.then((response) => { .then((response) => {
async function doStuff() { async function doStuff() {
if (response.status == 200) { if (response.status === 200) {
let version = await response.json()
let fetchClientVersion = await (await fetch("/static/version.txt")).text()
if (parseInt(version["versionnum"]) < parseInt(fetchClientVersion)) {
localStorage.setItem("legacy", "true")
}
localStorage.setItem("homeserverURL", remote) localStorage.setItem("homeserverURL", remote)
if (document.referrer !== "") { if (document.referrer !== "") {
@ -51,12 +56,44 @@ changeButton.addEventListener("click", (event) => {
else { else {
window.location.href = "/login"; window.location.href = "/login";
} }
} else if (response.status === 404) {
let legacyHomeserverCheck = await fetch(remote + "/api/version")
if (legacyHomeserverCheck.status === 200) {
let homeserverText = await legacyHomeserverCheck.text()
let homeserverFloat = homeserverText.split(" ")[2]
let homeserverNameCheck = homeserverText.split(" ")[0]
if (homeserverNameCheck !== "Burgernotes") {
statusBox.innerText = "This homeserver is not compatible with Burgernotes!"
showElements(true)
return
} }
else if (response.status == 404) { let homeserverInt = parseFloat(homeserverFloat) * 100
statusBox.innerText = "Not a valid homeserver!" if (homeserverInt < 200) {
localStorage.setItem("legacy", "true")
localStorage.setItem("homeserverURL", remote)
if (document.referrer !== "") {
window.location.href = document.referrer;
} }
else { else {
statusBox.innerText = "Something went wrong!" window.location.href = "/login";
}
} else if (homeserverInt > 200) {
localStorage.setItem("legacy", "false")
localStorage.setItem("homeserverURL", remote)
if (document.referrer !== "") {
window.location.href = document.referrer;
}
else {
window.location.href = "/login";
}
} else {
statusBox.innerText = "This homeserver is not compatible with Burgernotes!"
showElements(true)
}
}
}
else {
statusBox.innerText = "This homeserver is not compatible with Burgernotes!"
showElements(true) showElements(true)
} }
} }
@ -66,7 +103,7 @@ changeButton.addEventListener("click", (event) => {
doStuff() doStuff()
}); });
backButton.addEventListener("click", (event) => { backButton.addEventListener("click", () => {
history.back() history.back()
}); });

View File

@ -20,7 +20,8 @@ let inputNameBox = document.getElementById("inputNameBox")
let backButton = document.getElementById("backButton") let backButton = document.getElementById("backButton")
let opButton = document.getElementById("opButton") let opButton = document.getElementById("opButton")
async function loginFetch(username, password) { async function loginFetch(username, password, changePass, newPass) {
if (localStorage.getItem("legacy") !== true) {
return await fetch(remote + "/api/login", { return await fetch(remote + "/api/login", {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
@ -32,6 +33,28 @@ async function loginFetch(username, password) {
"X-Burgernotes-Version": "200" "X-Burgernotes-Version": "200"
} }
}) })
} else {
let passwordChange, newPassChecked
if (changePass) {
passwordChange = "yes"
newPassChecked = newPass
} else {
passwordChange = "no"
newPassChecked = password
}
return await fetch(remote + "/api/login", {
method: "POST",
body: JSON.stringify({
username: username,
password: password,
passwordchange: passwordChange,
newpass: newPassChecked
}),
headers: {
"Content-Type": "application/json; charset=UTF-8",
}
})
}
} }
async function addLegacyPassword(secretKey, password) { async function addLegacyPassword(secretKey, password) {
@ -165,11 +188,12 @@ signupButton.addEventListener("click", () => {
showElements(true) showElements(true)
statusBox.innerText = "Signing in..." statusBox.innerText = "Signing in..."
const login = await loginFetch(username, await hashpass(password)) const hashedPass = await hashpass(password)
const login = await loginFetch(username, hashedPass, false, "")
const loginData = await login.json() const loginData = await login.json()
if (login.status === 401) { if (login.status === 401) {
// Trying hashpassold // Trying hashpassold
const loginOld = await loginFetch(username, await hashpassold(password)) const loginOld = await loginFetch(username, await hashpassold(password), true, hashedPass)
const loginDataOld = await loginOld.json() const loginDataOld = await loginOld.json()
if (loginOld.status === 401) { if (loginOld.status === 401) {
statusBox.innerText = "Username or password incorrect!" statusBox.innerText = "Username or password incorrect!"
@ -181,7 +205,7 @@ signupButton.addEventListener("click", () => {
if (loginDataOld["legacyPasswordNeeded"] === true) { if (loginDataOld["legacyPasswordNeeded"] === true) {
await addLegacyPassword(username, await hashpass(await hashpassold(password))) await addLegacyPassword(username, await hashpass(await hashpassold(password)))
} }
await migrateLegacyPassword(loginDataOld["key"], await hashpass(password)) await migrateLegacyPassword(loginDataOld["key"], hashedPass)
window.location.replace("/app/") window.location.replace("/app/")
} else { } else {
statusBox.innerText = loginDataOld["error"] statusBox.innerText = loginDataOld["error"]
@ -211,4 +235,4 @@ backButton.addEventListener("click", () => {
showInput(0) showInput(0)
// @license-endc // @license-end

View File

@ -22,7 +22,6 @@ function formatBytes(a, b = 2) { if (!+a) return "0 Bytes"; const c = 0 > b ? 0
let secretkey = localStorage.getItem("DONOTSHARE-secretkey") let secretkey = localStorage.getItem("DONOTSHARE-secretkey")
let password = localStorage.getItem("DONOTSHARE-password") let password = localStorage.getItem("DONOTSHARE-password")
let currentFontSize = 16 let currentFontSize = 16
let markdowntoggle = false
let backButton = document.getElementById("backButton") let backButton = document.getElementById("backButton")
let usernameBox = document.getElementById("usernameBox") let usernameBox = document.getElementById("usernameBox")
@ -51,11 +50,10 @@ let notesBar = document.getElementById("notesBar")
let topBar = document.getElementById("topBar") let topBar = document.getElementById("topBar")
let notesDiv = document.getElementById("notesDiv") let notesDiv = document.getElementById("notesDiv")
let newNote = document.getElementById("newNote") let newNote = document.getElementById("newNote")
let noteBox = document.getElementById("noteBox")
let noteBoxDiv = document.getElementById("noteBoxDiv") let noteBoxDiv = document.getElementById("noteBoxDiv")
let pellAttacher = document.getElementById("noteBox")
let loadingStuff = document.getElementById("loadingStuff") let loadingStuff = document.getElementById("loadingStuff")
let exportNotesButton = document.getElementById("exportNotesButton") let exportNotesButton = document.getElementById("exportNotesButton")
let markdown = document.getElementById('markdown');
let textSizeBox = document.getElementById('textSizeBox'); let textSizeBox = document.getElementById('textSizeBox');
let textPlusBox = document.getElementById('textPlusBox'); let textPlusBox = document.getElementById('textPlusBox');
let textMinusBox = document.getElementById('textMinusBox'); let textMinusBox = document.getElementById('textMinusBox');
@ -70,9 +68,25 @@ let indiv = false
let mobile = false let mobile = false
let selectLatestNote = false let selectLatestNote = false
if (/Android|iPhone|iPod/i.test(navigator.userAgent)) { // Init the note box
document.addEventListener("DOMContentLoaded", function() {
pell.init({
element: pellAttacher,
onChange: html => console.log(html),
defaultParagraphSeparator: 'br',
styleWithCSS: false,
classes: {
actionbar: 'pell-actionbar',
button: 'pell-button',
content: 'pell-content',
selected: 'pell-button-selected'
}
})
let noteBox = document.getElementsByClassName("pell-content")[0]
if (/Android|iPhone|iPod/i.test(navigator.userAgent)) {
mobile = true mobile = true
noteBoxDiv.classList.add("mobile"); noteBoxDiv.classList.add("mobile")
noteBoxDiv.style.width = "0px"; noteBoxDiv.style.width = "0px";
notesBar.style.width = "100%" notesBar.style.width = "100%"
topBar.style.width = "100%" topBar.style.width = "100%"
@ -104,33 +118,11 @@ if (/Android|iPhone|iPod/i.test(navigator.userAgent)) {
touchendY = event.changedTouches[0].screenY; touchendY = event.changedTouches[0].screenY;
if (touchendX > touchstartX + 75) { if (touchendX > touchstartX + 75) {
handleGesture(); handleGesture();
} else if (touchendX < touchstartX - 75) {
enableMarkdown();
} }
}, false); }, false);
markdown.addEventListener("touchstart", function (event) {
touchstartX = event.changedTouches[0].screenX;
touchstartY = event.changedTouches[0].screenY;
}, false);
markdown.addEventListener("touchstart", function (event) {
touchstartX = event.changedTouches[0].screenX;
touchstartY = event.changedTouches[0].screenY;
}, false);
markdown.addEventListener("touchend", function (event) {
touchendX = event.changedTouches[0].screenX;
touchendY = event.changedTouches[0].screenY;
if (touchendX > touchstartX + 75) {
disableMarkdown();
} else if (touchendX < touchstartX - 75) {
disableMarkdown();
} }
}, false);
}
function handleGesture() { function handleGesture() {
if (indiv) { if (indiv) {
indiv = false indiv = false
notesBar.style.width = "100%"; notesBar.style.width = "100%";
@ -154,42 +146,45 @@ function handleGesture() {
backButton.classList.remove("hidden") backButton.classList.remove("hidden")
newNote.classList.add("hidden") newNote.classList.add("hidden")
} }
} }
noteBox.value = "" noteBox.innerText = ""
noteBox.readOnly = true noteBox.readOnly = true
let noteCount = 0 let noteCount = 0
function displayError(message) { function displayError(message) {
errorDiv.classList.remove("hidden") errorDiv.classList.remove("hidden")
optionsCoverDiv.classList.remove("hidden") optionsCoverDiv.classList.remove("hidden")
errorMessageThing.innerHTML = message errorMessageThing.innerHTML = message
} }
closeErrorButton.addEventListener("click", () => { closeErrorButton.addEventListener("click", () => {
errorDiv.classList.add("hidden") errorDiv.classList.add("hidden")
optionsCoverDiv.classList.add("hidden") optionsCoverDiv.classList.add("hidden")
}); });
closeErrorButton.addEventListener("click", () => { closeErrorButton.addEventListener("click", () => {
errorDiv.classList.add("hidden") errorDiv.classList.add("hidden")
optionsCoverDiv.classList.add("hidden") optionsCoverDiv.classList.add("hidden")
errorInput.classList.add("hidden") errorInput.classList.add("hidden")
cancelErrorButton.classList.add("hidden") cancelErrorButton.classList.add("hidden")
}); });
function updateFont() { function updateFont() {
currentFontSize = localStorage.getItem("SETTING-fontsize") currentFontSize = localStorage.getItem("SETTING-fontsize")
noteBox.style.fontSize = currentFontSize + "px" noteBox.style.fontSize = currentFontSize + "px"
textSizeBox.innerText = currentFontSize + "px" textSizeBox.innerText = currentFontSize + "px"
if (markdowntoggle) {
markdown.srcdoc = "<!DOCTYPE html><html lang='en'><style>html { height: 100% } pre { white-space: pre-wrap; overflow-wrap: break-word; } body { white-space: pre-wrap; overflow-wrap: break-word; font-family: 'Inter', sans-serif; height: 100%; color: " + getComputedStyle(document.documentElement).getPropertyValue('--text-color') + "; font-size: " + currentFontSize + "px; }</style>" + marked.parse(DOMPurify.sanitize(noteBox.value)) + "</html>";
} }
}
async function checknetwork() { async function checknetwork() {
fetch(remote + "/api/loggedin", { let loggedInEndpoint
if (localStorage.getItem("legacy") === "true") {
loggedInEndpoint = "userinfo"
} else {
loggedInEndpoint = "loggedin"
}
fetch(remote + "/api/" + loggedInEndpoint, {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
secretKey: localStorage.getItem("DONOTSHARE-secretkey"), secretKey: localStorage.getItem("DONOTSHARE-secretkey"),
@ -199,9 +194,8 @@ async function checknetwork() {
} }
}) })
.catch(() => { .catch(() => {
noteBox.readOnly = true noteBox.contentEditable = false
noteBox.value = "" noteBox.innerHTML = "<h1>You are currently offline.</h1>"
noteBox.placeholder = "You are currently offline."
displayError("Failed to connect to the server.\nPlease check your internet connection.") displayError("Failed to connect to the server.\nPlease check your internet connection.")
}) })
.then((response) => response) .then((response) => response)
@ -217,40 +211,39 @@ async function checknetwork() {
updateUserInfo() updateUserInfo()
} else { } else {
noteBox.readOnly = true noteBox.readOnly = true
noteBox.value = "" noteBox.innerHTML = "<h1>You are currently offline.</h1>"
noteBox.placeholder = "You are currently offline."
displayError("Failed to connect to the server.\nPlease check your internet connection.") displayError("Failed to connect to the server.\nPlease check your internet connection.")
} }
}); });
} }
if (localStorage.getItem("SETTING-fontsize") === null) { if (localStorage.getItem("SETTING-fontsize") === null) {
localStorage.setItem("SETTING-fontsize", "16") localStorage.setItem("SETTING-fontsize", "16")
updateFont() updateFont()
} else { } else {
updateFont() updateFont()
} }
textPlusBox.addEventListener("click", () => { textPlusBox.addEventListener("click", () => {
localStorage.setItem("SETTING-fontsize", String(Number(localStorage.getItem("SETTING-fontsize")) + Number(1))) localStorage.setItem("SETTING-fontsize", String(Number(localStorage.getItem("SETTING-fontsize")) + Number(1)))
updateFont() updateFont()
}); });
textMinusBox.addEventListener("click", () => { textMinusBox.addEventListener("click", () => {
localStorage.setItem("SETTING-fontsize", String(Number(localStorage.getItem("SETTING-fontsize")) - Number(1))) localStorage.setItem("SETTING-fontsize", String(Number(localStorage.getItem("SETTING-fontsize")) - Number(1)))
updateFont() updateFont()
}); });
function truncateString(str, num) { function truncateString(str, num) {
if (str.length > num) { if (str.length > num) {
return str.slice(0, num) + ".."; return str.slice(0, num) + "..";
} else { } else {
return str; return str;
} }
} }
function updateUserInfo() { function updateUserInfo() {
fetch(remote + "/api/userinfo", { fetch(remote + "/api/userinfo", {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
@ -277,22 +270,24 @@ function updateUserInfo() {
noteCount = responseData["notecount"] noteCount = responseData["notecount"]
} }
} }
doStuff() doStuff()
}); });
} }
usernameBox.addEventListener("click", () => {
usernameBox.addEventListener("click", () => {
optionsCoverDiv.classList.remove("hidden") optionsCoverDiv.classList.remove("hidden")
optionsDiv.classList.remove("hidden") optionsDiv.classList.remove("hidden")
updateUserInfo() updateUserInfo()
}); });
logOutButton.addEventListener("click", () => { logOutButton.addEventListener("click", () => {
window.location.replace("/logout") window.location.replace("/logout")
}); });
exitThing.addEventListener("click", () => { exitThing.addEventListener("click", () => {
optionsDiv.classList.add("hidden") optionsDiv.classList.add("hidden")
optionsCoverDiv.classList.add("hidden") optionsCoverDiv.classList.add("hidden")
}); });
deleteMyAccountButton.addEventListener("click", () => { deleteMyAccountButton.addEventListener("click", () => {
if (confirm("Are you REALLY sure that you want to delete your account? There's no going back!") === true) { if (confirm("Are you REALLY sure that you want to delete your account? There's no going back!") === true) {
fetch(remote + "/api/deleteaccount", { fetch(remote + "/api/deleteaccount", {
method: "POST", method: "POST",
@ -311,26 +306,28 @@ deleteMyAccountButton.addEventListener("click", () => {
} }
}) })
} }
}); });
async function waitForConfirm() {
async function waitForConfirm() {
let resolvePromise; let resolvePromise;
const promise = new Promise(resolve => resolvePromise = resolve); const promise = new Promise(resolve => resolvePromise = resolve);
closeErrorButton.addEventListener("click", () => { closeErrorButton.addEventListener("click", () => {
resolvePromise(); resolvePromise();
}); });
await promise; await promise;
} }
async function hashpass(pass) { async function hashpass(pass) {
let key = pass let key = pass
for (let i = 0; i < 128; i++) { for (let i = 0; i < 128; i++) {
key = await hashwasm.sha3(key) key = await hashwasm.sha3(key)
} }
return key return key
} }
changePasswordButton.addEventListener("click", () => { changePasswordButton.addEventListener("click", () => {
optionsDiv.classList.add("hidden") optionsDiv.classList.add("hidden")
async function doStuff() { async function doStuff() {
async function fatalError(notes, passwordBackup) { async function fatalError(notes, passwordBackup) {
displayError("Something went wrong! Your password change has failed. Attempting to revert changes...") displayError("Something went wrong! Your password change has failed. Attempting to revert changes...")
@ -364,6 +361,7 @@ changePasswordButton.addEventListener("click", () => {
downloadObjectAsJson(notes, "data") downloadObjectAsJson(notes, "data")
} }
} }
displayError("Confirm your current password to change it") displayError("Confirm your current password to change it")
errorInput.type = "password" errorInput.type = "password"
errorInput.classList.remove("hidden") errorInput.classList.remove("hidden")
@ -433,13 +431,14 @@ changePasswordButton.addEventListener("click", () => {
} }
} }
} }
doStuff() doStuff()
}) })
importNotesButton.addEventListener("click", () => { importNotesButton.addEventListener("click", () => {
optionsDiv.classList.add("hidden") optionsDiv.classList.add("hidden")
importNotesDiv.classList.remove("hidden") importNotesDiv.classList.remove("hidden")
}); });
sessionManagerButton.addEventListener("click", () => { sessionManagerButton.addEventListener("click", () => {
optionsDiv.classList.add("hidden") optionsDiv.classList.add("hidden")
sessionManagerDiv.classList.remove("hidden") sessionManagerDiv.classList.remove("hidden")
@ -510,33 +509,28 @@ sessionManagerButton.addEventListener("click", () => {
sessionDiv.append(sessionElement) sessionDiv.append(sessionElement)
} }
} }
doStuff() doStuff()
}); });
}); });
exitImportThing.addEventListener("click", () => { exitImportThing.addEventListener("click", () => {
optionsDiv.classList.remove("hidden") optionsDiv.classList.remove("hidden")
importNotesDiv.classList.add("hidden") importNotesDiv.classList.add("hidden")
}); });
exitSessionsThing.addEventListener("click", () => { exitSessionsThing.addEventListener("click", () => {
optionsDiv.classList.remove("hidden") optionsDiv.classList.remove("hidden")
sessionManagerDiv.classList.add("hidden") sessionManagerDiv.classList.add("hidden")
}); });
function updateWordCount() { function updateWordCount() {
let wordCount = noteBox.value.split(" ").length let wordCount = noteBox.innerText.split(" ").length
if (wordCount === 1) { if (wordCount === 1) {
wordCount = 0 wordCount = 0
} }
wordCountBox.innerText = wordCount + " words" wordCountBox.innerText = wordCount + " words"
}
function renderMarkDown() {
if (markdowntoggle) {
markdown.srcdoc = "<!DOCTYPE html><html lang='en'><style>html { height: 100% } pre { white-space: pre-wrap; overflow-wrap: break-word; } body { white-space: pre-wrap; overflow-wrap: break-word; font-family: 'Inter', sans-serif; height: 100%; color: " + getComputedStyle(document.documentElement).getPropertyValue('--text-color') + "; font-size: " + currentFontSize + "px; }</style>" + marked.parse(DOMPurify.sanitize(noteBox.value)) + "</html>"
} }
}
function selectNote(nameithink) { function selectNote(nameithink) {
document.querySelectorAll(".noteButton").forEach((el) => el.classList.remove("selected")); document.querySelectorAll(".noteButton").forEach((el) => el.classList.remove("selected"));
let thingArray = Array.from(document.querySelectorAll(".noteButton")).find(el => String(nameithink) === String(el.id)); let thingArray = Array.from(document.querySelectorAll(".noteButton")).find(el => String(nameithink) === String(el.id));
thingArray.classList.add("selected") thingArray.classList.add("selected")
@ -552,9 +546,8 @@ function selectNote(nameithink) {
} }
}) })
.catch(() => { .catch(() => {
noteBox.readOnly = true noteBox.contentEditable = false
noteBox.value = "" noteBox.innerHTML = ""
noteBox.placeholder = ""
displayError("Something went wrong... Please try again later!") displayError("Something went wrong... Please try again later!")
}) })
.then((response) => { .then((response) => {
@ -562,33 +555,32 @@ function selectNote(nameithink) {
if (mobile) { if (mobile) {
handleGesture() handleGesture()
} }
noteBox.readOnly = false noteBox.contentEditable = true
noteBox.placeholder = "Type something!" noteBox.click()
async function doStuff() { async function doStuff() {
let responseData = await response.json() let responseData = await response.json()
let bytes = CryptoJS.AES.decrypt(responseData["content"], password); let bytes = CryptoJS.AES.decrypt(responseData["content"], password);
noteBox.value = bytes.toString(CryptoJS.enc.Utf8) let cleanedHTML = bytes.toString(CryptoJS.enc.Utf8).replace(/<(?!\/?(h1|h2|br)\b)[^>]*>/gi, '')
noteBox.innerHTML = cleanedHTML.replace("\n", "<br>")
updateWordCount() updateWordCount()
renderMarkDown()
noteBox.addEventListener("input", () => { noteBox.addEventListener("input", () => {
updateWordCount() updateWordCount()
renderMarkDown()
clearTimeout(timer); clearTimeout(timer);
timer = setTimeout(() => { timer = setTimeout(() => {
let preEncryptedTitle = noteBox.value let preEncryptedTitle = noteBox.innerText
if (noteBox.value.substring(0, noteBox.value.indexOf("\n")) !== "") { if (noteBox.innerText.substring(0, noteBox.innerText.indexOf("\n")) !== "") {
preEncryptedTitle = noteBox.value.substring(0, noteBox.value.indexOf("\n")); preEncryptedTitle = noteBox.innerText.substring(0, noteBox.innerText.indexOf("\n"));
} }
preEncryptedTitle = truncateString(preEncryptedTitle, 15) preEncryptedTitle = truncateString(preEncryptedTitle, 15)
document.getElementById(nameithink).innerText = preEncryptedTitle document.getElementById(nameithink).innerText = preEncryptedTitle
let encryptedText = CryptoJS.AES.encrypt(noteBox.value, password).toString(); let encryptedText = CryptoJS.AES.encrypt(noteBox.innerHTML, password).toString();
let encryptedTitle = CryptoJS.AES.encrypt(preEncryptedTitle, password).toString(); let encryptedTitle = CryptoJS.AES.encrypt(preEncryptedTitle, password).toString();
console.log(encryptedTitle) console.log(encryptedTitle)
@ -619,12 +611,13 @@ function selectNote(nameithink) {
}, waitTime); }, waitTime);
}); });
} }
doStuff() doStuff()
}); });
} }
function updateNotes() { function updateNotes() {
console.log("notes updated") console.log("Notes updated")
fetch(remote + "/api/listnotes", { fetch(remote + "/api/listnotes", {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
@ -636,23 +629,16 @@ function updateNotes() {
}) })
.then((response) => { .then((response) => {
async function doStuff() { async function doStuff() {
noteBox.readOnly = true noteBox.contentEditable = false
selectedNote = 0 selectedNote = 0
if (selectLatestNote === false) { noteBox.innerHTML = ""
noteBox.placeholder = ""
}
noteBox.value = ""
clearTimeout(timer) clearTimeout(timer)
updateWordCount() updateWordCount()
renderMarkDown()
let responseData = await response.json() let responseData = await response.json()
let decryptedResponseData = [] let decryptedResponseData = []
let highestID = 0 let highestID = 0
// First decrypt note data, then render
let noteData; let noteData;
for (let i in responseData) { for (let i in responseData) {
noteData = responseData[i] noteData = responseData[i]
@ -717,19 +703,19 @@ function updateNotes() {
selectLatestNote = false selectLatestNote = false
} }
} }
doStuff() doStuff()
}); });
} }
updateNotes() updateNotes()
newNote.addEventListener("click", () => { newNote.addEventListener("click", () => {
let noteName = "New note" let noteName = "New note"
selectLatestNote = true selectLatestNote = true
console.log(selectLatestNote) console.log(selectLatestNote)
// create fake item // create fake item
document.querySelectorAll(".noteButton").forEach((el) => el.classList.remove("selected")); document.querySelectorAll(".noteButton").forEach((el) => el.classList.remove("selected"));
let noteButton = document.createElement("button"); let noteButton = document.createElement("button");
noteButton.classList.add("noteButton") noteButton.classList.add("noteButton")
@ -737,7 +723,7 @@ newNote.addEventListener("click", () => {
noteButton.innerText = "New note" noteButton.innerText = "New note"
noteButton.style.order = "-1" noteButton.style.order = "-1"
noteButton.classList.add("selected") noteButton.classList.add("selected")
noteBox.placeholder = "Type something!" noteBox.click()
let encryptedName = CryptoJS.AES.encrypt(noteName, password).toString(CryptoJS.enc.Utf8); let encryptedName = CryptoJS.AES.encrypt(noteName, password).toString(CryptoJS.enc.Utf8);
@ -762,8 +748,9 @@ newNote.addEventListener("click", () => {
updateNotes() updateNotes()
} }
}); });
}); });
function downloadObjectAsJson(exportObj, exportName) {
function downloadObjectAsJson(exportObj, exportName) {
let dataStr = "data:text/json;charset=utf-8," + JSON.stringify(exportObj); let dataStr = "data:text/json;charset=utf-8," + JSON.stringify(exportObj);
let downloadAnchorNode = document.createElement("a"); let downloadAnchorNode = document.createElement("a");
downloadAnchorNode.setAttribute("href", dataStr); downloadAnchorNode.setAttribute("href", dataStr);
@ -771,9 +758,9 @@ function downloadObjectAsJson(exportObj, exportName) {
document.body.appendChild(downloadAnchorNode); document.body.appendChild(downloadAnchorNode);
downloadAnchorNode.click(); downloadAnchorNode.click();
downloadAnchorNode.remove(); downloadAnchorNode.remove();
} }
async function exportNotes() { async function exportNotes() {
let exportNotesFetch = await fetch(remote + "/api/exportnotes", { let exportNotesFetch = await fetch(remote + "/api/exportnotes", {
method: "POST", method: "POST",
body: JSON.stringify({ body: JSON.stringify({
@ -794,9 +781,9 @@ async function exportNotes() {
responseData[i]["content"] = bytesd.toString(CryptoJS.enc.Utf8) responseData[i]["content"] = bytesd.toString(CryptoJS.enc.Utf8)
} }
return responseData return responseData
} }
async function importNotes(plaintextNotes) { async function importNotes(plaintextNotes) {
for (let i in plaintextNotes) { for (let i in plaintextNotes) {
let originalTitle = plaintextNotes[i]["title"]; let originalTitle = plaintextNotes[i]["title"];
plaintextNotes[i]["title"] = CryptoJS.AES.encrypt(originalTitle, password).toString(); plaintextNotes[i]["title"] = CryptoJS.AES.encrypt(originalTitle, password).toString();
@ -815,45 +802,25 @@ async function importNotes(plaintextNotes) {
} }
}) })
return importNotesFetch.status return importNotesFetch.status
} }
function firstNewVersion() { function firstNewVersion() {
if (localStorage.getItem("NEWVERSION") === "1.2") { if (localStorage.getItem("NEWVERSION") === "1.2") {
return false; return false;
} else { } else {
localStorage.setItem("NEWVERSION", "1.2") localStorage.setItem("NEWVERSION", "1.2")
return true; return true;
} }
}
function toggleMarkdown() {
if (markdown.style.display === 'none') {
enableMarkdown()
} else {
disableMarkdown()
} }
}
function enableMarkdown() { exportNotesButton.addEventListener("click", () => {
markdown.style.display = 'inherit';
markdowntoggle = true
renderMarkDown()
}
function disableMarkdown() {
markdown.style.display = 'none';
markdowntoggle = false
markdown.srcdoc = ""
}
exportNotesButton.addEventListener("click", () => {
let responseData = exportNotes() let responseData = exportNotes()
downloadObjectAsJson(responseData, "data") downloadObjectAsJson(responseData, "data")
optionsDiv.classList.add("hidden") optionsDiv.classList.add("hidden")
displayError("Exported notes!") displayError("Exported notes!")
}); });
importFile.addEventListener('change', function() { importFile.addEventListener('change', function () {
let fileread = new FileReader() let fileread = new FileReader()
fileread.addEventListener( fileread.addEventListener(
"load", "load",
@ -877,9 +844,9 @@ importFile.addEventListener('change', function() {
); );
fileread.readAsText(importFile.files[0]) fileread.readAsText(importFile.files[0])
}) })
removeBox.addEventListener("click", () => { removeBox.addEventListener("click", () => {
if (selectedNote === 0) { if (selectedNote === 0) {
displayError("You need to select a note first!") displayError("You need to select a note first!")
} else { } else {
@ -901,16 +868,12 @@ removeBox.addEventListener("click", () => {
displayError("Something went wrong! Please try again later...") displayError("Something went wrong! Please try again later...")
}) })
} }
}); });
document.addEventListener("DOMContentLoaded", function() { if (firstNewVersion()) {
markdown.srcdoc = "<!DOCTYPE html><html lang='en'><style>html { height: 100% } pre { white-space: pre-wrap; overflow-wrap: break-word; } body { white-space: pre-wrap; overflow-wrap: break-word; font-family: 'Inter', sans-serif; height: 100%; color: " + getComputedStyle(document.documentElement).getPropertyValue('--text-color') + "; font-size: " + currentFontSize + "px; }</style>" + marked.parse(DOMPurify.sanitize(noteBox.value)) + "</html>" displayError("What's new in Burgernotes 2.0?\nRestyled client\nAdded changing passwords\nAdded importing notes")
}); }
if (firstNewVersion()) {
displayError("What's new in Burgernotes 2.0?\nRestyled client\nAdded changing passwords\nMigrated to OAuth2\nAdded importing notes")
}
checknetwork()
checknetwork()
})
// @license-end // @license-end

File diff suppressed because it is too large Load Diff

200
static/js/pell.js Normal file
View File

@ -0,0 +1,200 @@
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat
/*
* Beautified version of:
* pell (https://github.com/jaredreich/pell)
* (c) Jared Reich
* @license MIT
*/
! function(t, e) {
"object" == typeof exports && "undefined" != typeof module ? e(exports) : "function" == typeof define && define.amd ? define(["exports"], e) : e(t.pell = {})
}(this, function(t) {
"use strict";
var e = Object.assign || function(t) {
for (var e = 1; e < arguments.length; e++) {
var n = arguments[e];
for (var r in n) Object.prototype.hasOwnProperty.call(n, r) && (t[r] = n[r])
}
return t
},
c = "defaultParagraphSeparator",
l = "formatBlock",
a = function(t, e, n) {
return t.addEventListener(e, n)
},
s = function(t, e) {
return t.appendChild(e)
},
d = function(t) {
return document.createElement(t)
},
n = function(t) {
return document.queryCommandState(t)
},
f = function(t) {
var e = 1 < arguments.length && void 0 !== arguments[1] ? arguments[1] : null;
return document.execCommand(t, !1, e)
},
p = {
bold: {
icon: "<b>B</b>",
title: "Bold",
state: function() {
return n("bold")
},
result: function() {
return f("bold")
}
},
italic: {
icon: "<i>I</i>",
title: "Italic",
state: function() {
return n("italic")
},
result: function() {
return f("italic")
}
},
underline: {
icon: "<u>U</u>",
title: "Underline",
state: function() {
return n("underline")
},
result: function() {
return f("underline")
}
},
strikethrough: {
icon: "<strike>S</strike>",
title: "Strike-through",
state: function() {
return n("strikeThrough")
},
result: function() {
return f("strikeThrough")
}
},
heading1: {
icon: "<b>H<sub>1</sub></b>",
title: "Heading 1",
result: function() {
return f(l, "<h1>")
}
},
heading2: {
icon: "<b>H<sub>2</sub></b>",
title: "Heading 2",
result: function() {
return f(l, "<h2>")
}
},
paragraph: {
icon: "&#182;",
title: "Paragraph",
result: function() {
return f(l, "<p>")
}
},
quote: {
icon: "&#8220; &#8221;",
title: "Quote",
result: function() {
return f(l, "<blockquote>")
}
},
olist: {
icon: "&#35;",
title: "Ordered List",
result: function() {
return f("insertOrderedList")
}
},
ulist: {
icon: "&#8226;",
title: "Unordered List",
result: function() {
return f("insertUnorderedList")
}
},
code: {
icon: "&lt;/&gt;",
title: "Code",
result: function() {
return f(l, "<pre>")
}
},
line: {
icon: "&#8213;",
title: "Horizontal Line",
result: function() {
return f("insertHorizontalRule")
}
},
link: {
icon: "&#128279;",
title: "Link",
result: function() {
var t = window.prompt("Enter the link URL");
t && f("createLink", t)
}
},
image: {
icon: "&#128247;",
title: "Image",
result: function() {
var t = window.prompt("Enter the image URL");
t && f("insertImage", t)
}
}
},
m = {
actionbar: "pell-actionbar",
button: "pell-button",
content: "pell-content",
selected: "pell-button-selected"
},
r = function(n) {
var t = n.actions ? n.actions.map(function(t) {
return "string" == typeof t ? p[t] : p[t.name] ? e({}, p[t.name], t) : t
}) : Object.keys(p).map(function(t) {
return p[t]
}),
r = e({}, m, n.classes),
i = n[c] || "div",
o = d("div");
o.className = r.actionbar, s(n.element, o);
var u = n.element.content = d("div");
return u.contentEditable = !0, u.className = r.content, u.oninput = function(t) {
var e = t.target.firstChild;
e && 3 === e.nodeType ? f(l, "<" + i + ">") : "<br>" === u.innerHTML && (u.innerHTML = ""), n.onChange(u.innerHTML)
}, u.onkeydown = function(t) {
var e;
"Enter" === t.key && "blockquote" === (e = l, document.queryCommandValue(e)) && setTimeout(function() {
return f(l, "<" + i + ">")
}, 0)
}, s(n.element, u), t.forEach(function(t) {
var e = d("button");
if (e.className = r.button, e.innerHTML = t.icon, e.title = t.title, e.setAttribute("type", "button"), e.onclick = function() {
return t.result() && u.focus()
}, t.state) {
var n = function() {
return e.classList[t.state() ? "add" : "remove"](r.selected)
};
a(u, "keyup", n), a(u, "mouseup", n), a(e, "click", n)
}
s(o, e)
}), n.styleWithCSS && f("styleWithCSS"), f(c, i), n.element
},
i = {
exec: f,
init: r
};
t.exec = f, t.init = r, t.default = i, Object.defineProperty(t, "__esModule", {
value: !0
})
});
// @license-end

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
121 200