import "no-darkreader" import { marked } from "marked" import JSConfetti from "js-confetti" import Scrollbar from "smooth-scrollbar" import "./icons" import hljs from "highlight.js/lib/common" // import hljs from "../min/highlight.min" import "../min/rosepine.min.css" import { toggleHiddenIcon } from "./icons" let rawContent = "" let buttonPaneHidden = false let isMarkdown = false let singleView = false const jsConfetti = new JSConfetti() const lineNumbers = document.querySelector(".line-numbers") const wrapper = document.querySelector(".wrapper") const buttonWrapper = document.querySelector(".button-wrapper") const editor = document.getElementById("text-area") const codeViewPre = document.getElementById("code-view-pre") const codeView = document.getElementById("code-view") const messages = document.getElementById("messages") const viewCounterLabel = ( document.getElementById("viewcounter-label") ) const viewCounter = ( document.getElementById("viewcounter-count") ) const saveButton = document.getElementById("save-button") const newButton = document.getElementById("new-button") const copyButton = document.getElementById("copy-button") const hideButton = document.getElementById("hide-button") const shareButton = document.getElementById("share-button") const markdownButton = ( document.getElementById("markdown-button") ) const singleViewButton = ( document.getElementById("single-view-button") ) function hide(element: HTMLElement) { element.style.visibility = "hidden" element.style.opacity = "0" } function show(element: HTMLElement) { element.style.visibility = "visible" element.style.opacity = "1" } function disable(element: HTMLButtonElement) { element.disabled = true } function enable(element: HTMLButtonElement) { element.disabled = false } async function postPaste(content: string, callback: Function) { const payload = { content, single_view: singleView } await fetch(`${API_URL}/p/n`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(payload), }) .then((response) => response.json()) .then((data) => { if (data["success"]) { callback(null, data) return } callback(data || { data: { message: "An unkown error occured!" } }) }) .catch(() => { callback({ data: { message: "An API error occurred, please try again." }, }) }) } async function getPaste(id: string, callback: Function) { await fetch(`${API_URL}/p/${id}`, { method: "GET", headers: { "Content-Type": "application/json", }, referrerPolicy: "no-referrer", }) .then((response) => response.json()) .then((data) => { if (data["success"]) { callback(null, data) return } callback(data || { data: { message: "An unkown error occured!" } }) }) .catch(() => { callback({ data: { message: "An API error occurred, please try again." }, }) }) } function newPaste() { Scrollbar.destroyAll() lineNumbers.innerHTML = ">" enable(saveButton) disable(newButton) disable(copyButton) disable(shareButton) enable(singleViewButton) editor.value = "" rawContent = "" wrapper.classList.add("text-area-proper") show(editor) editor.disabled = false hide(codeViewPre) hide(viewCounterLabel) hide(viewCounter) viewCounterLabel.style.display = "none" viewCounter.style.display = "none" } function addMessage(message: string) { let msg = document.createElement("li") msg.innerHTML = message messages.insertBefore(msg, messages.firstChild) setTimeout(function () { msg.classList.add("fadeOut"), function () { msg.remove() } }, 3000) } function viewPaste(content: string, views: string, singleView: boolean) { lineNumbers.innerHTML = "" if ( content.startsWith("---") || content.startsWith("md ") || content.startsWith("md\n") ) { codeView.innerHTML = marked.parse(content.substring(3)) } else { for (let i = 1; i <= content.split("\n").length; i++) { lineNumbers.innerHTML = lineNumbers.innerHTML + `${i}
` } codeView.innerHTML = hljs.highlightAuto(content).value } if (singleView) { show(singleViewButton.firstElementChild as HTMLElement) singleViewButton.lastElementChild.classList.add("fire") addMessage("This is a single-view paste!") } enable(shareButton) shareButton.addEventListener("click", function () { const url = window.location.toString() if (navigator.canShare) { navigator.share({ title: "zer0bin paste", url: url, }) } else { navigator.clipboard.writeText(url) addMessage("Copied URL to clipboard!") } }) disable(saveButton) disable(markdownButton) enable(newButton) enable(copyButton) disable(singleViewButton) hide(editor) show(codeViewPre) show(viewCounterLabel) show(viewCounter) viewCounterLabel.style.display = null viewCounter.style.display = null viewCounter.textContent = views try { wrapper.classList.remove("text-area-proper") } catch (error) {} Scrollbar.init(document.querySelector(".scrollbar-container")) } async function savePaste() { if (editor.value === "") { return } const val: string = editor.value?.toString()! await postPaste(val, function (err, res) { if (err) { addMessage(err["data"]["message"]) } else { window.history.pushState(null, "", `/${res["data"]["id"]}`) rawContent = res["data"]["content"] viewPaste(rawContent, "0", res["data"]["single_view"]) const rand = Math.floor( Math.random() * parseInt(CONFETTI_CHANCE ?? "10") * 6 ) if (rand < 5) { jsConfetti.addConfetti({ confettiColors: [ "#eb6f92", "#f6c177", "#ebbcba", "#31748f", "#9ccfd8", "#c4a7e7", ], }) } else if (rand === 5) { jsConfetti.addConfetti({ emojis: ["๐Ÿฆ€"], }) } else if (rand === 6) { jsConfetti.addConfetti({ emojis: ["๐Ÿˆ", "๐Ÿงถ", "๐Ÿ“ฆ"], }) } } }) } async function duplicatePaste() { const content = rawContent window.history.pushState(null, "", "/") newPaste() rawContent = content editor.value = content } function toggleMarkdown() { let val = editor.value markdownButton.lastElementChild.classList.toggle("markdown") if (isMarkdown) { isMarkdown = false val = val.substring(val.indexOf("\n") + 1) } else { isMarkdown = true val = `---\n${val}` } } saveButton.addEventListener("click", async function () { await savePaste() }) document.addEventListener("keydown", (e) => { if (e.ctrlKey && e.code === "KeyS") { e.preventDefault() savePaste() } else if (e.ctrlKey && e.code === "KeyN") { e.preventDefault() newPaste() } else if (e.ctrlKey && e.code === "KeyD") { e.preventDefault() duplicatePaste() } else if (e.ctrlKey && e.code === "KeyM") { e.preventDefault() toggleMarkdown() } }) editor.addEventListener( "keydown", function (e: KeyboardEvent) { if (e.code == "Tab") { e.preventDefault() let start: number = this.selectionStart let end: number = this.selectionEnd this.value = this.value.substring(0, start) + "\t" + this.value.substring(end) this.selectionStart = this.selectionEnd = start + 1 } }, false ) copyButton.addEventListener("click", async function () { await duplicatePaste() }) newButton.addEventListener("click", function () { window.location.href = "/" }) hideButton.addEventListener("click", function () { if (!buttonPaneHidden) { buttonPaneHidden = true hide(buttonWrapper) } else { buttonPaneHidden = false show(buttonWrapper) } toggleHiddenIcon(buttonPaneHidden) }) markdownButton.addEventListener("click", function () { toggleMarkdown() }) singleViewButton.addEventListener("click", function () { singleViewButton.lastElementChild.classList.toggle("fire") if (singleView) { singleView = false hide(singleViewButton.firstElementChild as HTMLElement) } else { singleView = true show(singleViewButton.firstElementChild as HTMLElement) } }) async function handlePopstate() { const path = window.location.pathname if (path == "/") { newPaste() } else { const split = path.split("/") const id = split[split.length - 1] await getPaste(id, function (err, res) { if (err) { window.history.pushState(null, "", `/`) newPaste() } else { rawContent = res["data"]["content"] viewPaste( rawContent, res["data"]["views"].toString(), res["data"]["single_view"] ) } }) } } window.addEventListener("popstate", async () => { await handlePopstate() }) document.addEventListener( "DOMContentLoaded", async () => { await handlePopstate() }, false )