aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorkj_sh6042026-03-15 13:58:33 -0400
committerkj_sh6042026-03-15 13:58:33 -0400
commit006d7797ac27739e1adb500749e384c0006ba00a (patch)
tree1270a8de175e204012c499c7050576df825af754 /src
parent3f5a405eb8c5b4bd6eb3a118bc370f641aca8299 (diff)
refactor: multiple fixes and features
Diffstat (limited to 'src')
-rw-r--r--src/index.html293
-rw-r--r--src/main.js111
-rw-r--r--src/server.py20
3 files changed, 423 insertions, 1 deletions
diff --git a/src/index.html b/src/index.html
index 6e166fd..e906dd3 100644
--- a/src/index.html
+++ b/src/index.html
@@ -1 +1,292 @@
-<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="color-scheme" content="light dark"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"><meta http-equiv="pragma" content="no-cache"><title>kj-clipboard</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kj-sh604/noir.css@latest/out/noir.min.css"><style>textarea{ font-family: monospace; font-size: 0.95rem; padding: 0.75rem; resize: vertical; box-sizing: border-box; tab-size: 4;} textarea:not([rows]){ width: 100%; min-height: 30rem;} .controls{ display: flex; gap: 0.5rem; margin-top: 0.75rem; flex-wrap: wrap; align-items: center;} button:disabled{ opacity: 0.5; cursor: not-allowed;} input[type="password"]{ font-family: inherit; font-size: 0.9rem;} input[type="password"]:focus{ outline: none;} label{ font-size: 0.9rem; cursor: pointer; display: flex; align-items: center; gap: 0.3rem;} .result{ margin-top: 1rem; padding: 0.75rem; border: 1px solid #444; border-radius: 4px; display: none;} .result a{ word-break: break-all;} .spacer{ flex-grow: 1;} #lang-select{ display: none;} .status{ font-size: 0.85rem; margin-top: 0.5rem;} </style></head><body><h1>kj-clipboard</h1><p>no frills, just a public clipboard on the internet that you can use to share snippets around... that's it.</p><textarea id="content" placeholder="paste or type something here..." autofocus spellcheck="false"></textarea><div class="controls"><button id="get-link-btn" onclick="createPaste()" title="generate snippet link">generate link</button><span class="spacer"></span><label><input type="checkbox" id="is-code" onchange="toggleLang()">is this code? </label><select id="lang-select"><option value="">auto-detect</option><option value="1c">.bsl</option><option value="abnf">.abnf</option><option value="accesslog">access log</option><option value="ada">.adb/.ads</option><option value="arduino">.ino</option><option value="armasm">.s/.S</option><option value="asciidoc">.adoc</option><option value="aspectj">.aj</option><option value="autohotkey">.ahk</option><option value="autoit">.au3</option><option value="avrasm">.s</option><option value="awk">.awk</option><option value="bash">.sh</option><option value="basic">.bas</option><option value="bnf">.bnf</option><option value="brainfuck">.bf</option><option value="c">.c/.h</option><option value="cal">cal</option><option value="capnproto">.capnp</option><option value="ceylon">.ceylon</option><option value="clean">.icl/.dcl</option><option value="clojure">.clj</option><option value="clojure-repl">clojure repl</option><option value="cmake">.cmake</option><option value="coffeescript">.coffee</option><option value="coq">.v</option><option value="cos">.mac</option><option value="cpp">.cpp/.hpp</option><option value="crmsh">crmsh</option><option value="crystal">.cr</option><option value="csharp">.cs</option><option value="csp">csp</option><option value="css">.css</option><option value="d">.d</option><option value="dart">.dart</option><option value="delphi">.pas</option><option value="diff">.patch</option><option value="django">django</option><option value="dns">.zone</option><option value="dockerfile">dockerfile</option><option value="dos">.bat/.cmd</option><option value="dsconfig">dsconfig</option><option value="dts">.dts</option><option value="dust">dust</option><option value="ebnf">.ebnf</option><option value="elixir">.ex/.exs</option><option value="elm">.elm</option><option value="erb">.erb</option><option value="erlang">.erl</option><option value="excel">excel formula</option><option value="fix">fix</option><option value="flix">.flix</option><option value="fortran">.f90</option><option value="fsharp">.fs</option><option value="gams">.gms</option><option value="gauss">.gss</option><option value="gcode">.gcode</option><option value="gherkin">.feature</option><option value="glsl">.glsl</option><option value="gml">gml</option><option value="go">.go</option><option value="golo">.golo</option><option value="gradle">.gradle</option><option value="graphql">.graphql</option><option value="groovy">.groovy</option><option value="haml">.haml</option><option value="handlebars">.hbs</option><option value="haskell">.hs</option><option value="haxe">.hx</option><option value="hsp">hsp</option><option value="http">.http</option><option value="hy">.hy</option><option value="inform7">.ni</option><option value="ini">.ini</option><option value="irpf90">irpf90</option><option value="isbl">isbl</option><option value="java">.java</option><option value="javascript">.js</option><option value="jboss-cli">jboss cli</option><option value="json">.json</option><option value="julia">.jl</option><option value="kotlin">.kt</option><option value="lasso">.lasso</option><option value="latex">.tex</option><option value="ldif">.ldif</option><option value="leaf">leaf</option><option value="less">.less</option><option value="lisp">.lisp</option><option value="livecodeserver">livecodeserver</option><option value="livescript">.ls</option><option value="llvm">.ll</option><option value="lsl">lsl</option><option value="lua">.lua</option><option value="makefile">makefile</option><option value="markdown">.md</option><option value="mathematica">.nb</option><option value="matlab">.m</option><option value="maxima">.mac</option><option value="mel">.mel</option><option value="mercury">.m</option><option value="mipsasm">.s</option><option value="mizar">.miz</option><option value="mojolicious">mojolicious</option><option value="monkey">monkey</option><option value="moonscript">.moon</option><option value="n1ql">n1ql</option><option value="nestedtext">.nt</option><option value="nginx">.conf</option><option value="nim">.nim</option><option value="nix">.nix</option><option value="node-repl">node repl</option><option value="nsis">.nsi</option><option value="objectivec">.m/.mm</option><option value="ocaml">.ml/.mli</option><option value="openscad">.scad</option><option value="oxygene">.pas</option><option value="parser3">parser3</option><option value="perl">.pl</option><option value="pf">pf</option><option value="pgsql">.sql</option><option value="php">.php</option><option value="php-template">.phtml</option><option value="plaintext">.txt</option><option value="pony">.pony</option><option value="powershell">.ps1</option><option value="processing">.pde</option><option value="profile">profile</option><option value="prolog">.pl</option><option value="properties">.properties</option><option value="protobuf">.proto</option><option value="puppet">.pp</option><option value="purebasic">.pb</option><option value="python">.py</option><option value="python-repl">python repl</option><option value="q">.q</option><option value="qml">.qml</option><option value="r">.r</option><option value="reasonml">.re</option><option value="rib">rib</option><option value="roboconf">roboconf</option><option value="routeros">routeros</option><option value="rsl">rsl</option><option value="ruby">.rb</option><option value="ruleslanguage">rules language</option><option value="rust">.rs</option><option value="sas">.sas</option><option value="scala">.scala</option><option value="scheme">.scm</option><option value="scilab">.sci</option><option value="scss">.scss</option><option value="shell">.sh</option><option value="smali">.smali</option><option value="smalltalk">.st</option><option value="sml">.sml</option><option value="sqf">.sqf</option><option value="sql">.sql</option><option value="stan">.stan</option><option value="stata">.do</option><option value="step21">.p21</option><option value="stylus">.styl</option><option value="subunit">subunit</option><option value="swift">.swift</option><option value="taggerscript">taggerscript</option><option value="tap">tap</option><option value="tcl">.tcl</option><option value="thrift">.thrift</option><option value="tp">tp</option><option value="twig">.twig</option><option value="typescript">.ts</option><option value="vala">.vala</option><option value="vbnet">.vb</option><option value="vbscript">.vbs</option><option value="verilog">.v</option><option value="vhdl">.vhd</option><option value="vim">.vim</option><option value="wasm">.wat/.wasm</option><option value="wren">.wren</option><option value="x86asm">.asm</option><option value="xl">xl</option><option value="xml">.xml</option><option value="xquery">.xq</option><option value="yaml">.yml/.yaml</option><option value="zephir">.zep</option></select></div><br><input type="password" id="passphrase" placeholder="passphrase (optional)"><small>&nbsp;encrypted with <a href="https://github.com/kj-sh604/mojicrypt" target="_blank">mojicrypt</a></small><div class="result" id="result"><span>link: <a id="result-link" href="#" target="_blank"></a></span><button onclick="copyLink()" style="margin-left: 0.5rem; font-size: 0.85rem; padding: 0.25rem 0.5rem;">copy link</button></div><div class="status" id="status"></div><script>const FORM_STATE_KEY="kj-clipboard-form-state-v1"; function saveFormState(){ const state={ content: document.getElementById("content").value, isCode: document.getElementById("is-code").checked, language: document.getElementById("lang-select").value,}; sessionStorage.setItem(FORM_STATE_KEY, JSON.stringify(state));} function restoreFormState(){ const raw=sessionStorage.getItem(FORM_STATE_KEY); if (!raw){ toggleLang(); return;} try{ const state=JSON.parse(raw); document.getElementById("content").value=typeof state.content==="string" ? state.content : ""; document.getElementById("is-code").checked=!!state.isCode; const langSelect=document.getElementById("lang-select"); if (typeof state.language==="string"){ const langExists=Array.from(langSelect.options).some(opt=>opt.value===state.language); langSelect.value=langExists ? state.language : "";}} catch (_err){ sessionStorage.removeItem(FORM_STATE_KEY);} toggleLang();} function toggleLang(){ const sel=document.getElementById("lang-select"); sel.style.display=document.getElementById("is-code").checked ? "inline-block" : "none"; saveFormState();} async function createPaste(){ const content=document.getElementById("content").value.trim(); if (!content){ setStatus("nothing to paste."); return;} const btn=document.getElementById("get-link-btn"); btn.disabled=true; btn.textContent="generating..."; setStatus(""); const body={ content: content, is_code: document.getElementById("is-code").checked, language: document.getElementById("lang-select").value, passphrase: document.getElementById("passphrase").value,}; try{ const resp=await fetch("/api/paste",{ method: "POST", headers:{ "Content-Type": "application/json"}, body: JSON.stringify(body),}); const data=await resp.json(); if (data.error){ setStatus("error: " + data.error); btn.disabled=false; btn.textContent="generate link"; return;} const url=window.location.origin + data.url; const linkEl=document.getElementById("result-link"); linkEl.href=url; linkEl.textContent=url; document.getElementById("result").style.display="block"; setStatus("done.");} catch (e){ setStatus("error: " + e.message);} btn.disabled=false; btn.textContent="generate link";} function copyLink(){ const url=document.getElementById("result-link").textContent; navigator.clipboard.writeText(url);} function setStatus(msg){ document.getElementById("status").textContent=msg;} restoreFormState(); document.getElementById("content").addEventListener("input", saveFormState); document.getElementById("lang-select").addEventListener("change", saveFormState); // allow tab key in textarea document.getElementById("content").addEventListener("keydown", function(e){ if (e.key==="Tab"){ e.preventDefault(); const start=this.selectionStart; const end=this.selectionEnd; this.value=this.value.substring(0, start) + "\t" + this.value.substring(end); this.selectionStart=this.selectionEnd=start + 1; saveFormState()}}); </script></body></html> \ No newline at end of file
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="color-scheme" content="light dark">
+ <meta http-equiv="cache-control" content="no-cache">
+ <meta http-equiv="expires" content="0">
+ <meta http-equiv="pragma" content="no-cache">
+ <title>kj-clipboard</title>
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kj-sh604/noir.css@latest/out/noir.min.css">
+ <style>
+ textarea {
+ font-family: monospace;
+ font-size: 0.95rem;
+ padding: 0.75rem;
+ resize: vertical;
+ box-sizing: border-box;
+ tab-size: 4;
+ }
+
+ textarea:not([rows]) {
+ width: 100%;
+ min-height: 30rem;
+ }
+
+ .controls {
+ display: flex;
+ gap: 0.5rem;
+ margin-top: 0.75rem;
+ flex-wrap: wrap;
+ align-items: center;
+ }
+
+ button:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+
+ input[type="password"] {
+ font-family: inherit;
+ font-size: 0.9rem;
+ }
+
+ input[type="password"]:focus {
+ outline: none;
+ }
+
+ label {
+ font-size: 0.9rem;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 0.3rem;
+ }
+
+ .result {
+ margin-top: 1rem;
+ padding: 0.75rem;
+ border: 1px solid #444;
+ border-radius: 4px;
+ display: none;
+ }
+
+ .result a {
+ word-break: break-all;
+ }
+
+ .spacer {
+ flex-grow: 1;
+ }
+
+ #lang-select {
+ display: none;
+ }
+
+ .status {
+ font-size: 0.85rem;
+ margin-top: 0.5rem;
+ }
+ </style>
+</head>
+
+<body>
+ <h1>kj-clipboard</h1>
+ <p>no frills, just a public clipboard on the internet that you can use to share snippets around... that's it.</p>
+ <textarea id="content" placeholder="paste or type something here..." autofocus spellcheck="false"></textarea>
+ <div class="controls"><button id="get-link-btn" onclick="createPaste()" title="generate snippet link">generate
+ link</button><span class="spacer"></span><label><input type="checkbox" id="is-code"
+ onchange="toggleLang()">is this code? </label><select id="lang-select">
+ <option value="">auto-detect</option>
+ <option value="1c">1c</option>
+ <option value="abnf">abnf</option>
+ <option value="accesslog">accesslog</option>
+ <option value="ada">ada</option>
+ <option value="angelscript">angelscript</option>
+ <option value="apache">apache</option>
+ <option value="applescript">applescript</option>
+ <option value="arcade">arcade</option>
+ <option value="arduino">arduino</option>
+ <option value="armasm">armasm</option>
+ <option value="asciidoc">asciidoc</option>
+ <option value="aspectj">aspectj</option>
+ <option value="autohotkey">autohotkey</option>
+ <option value="autoit">autoit</option>
+ <option value="avrasm">avrasm</option>
+ <option value="awk">awk</option>
+ <option value="bash">bash</option>
+ <option value="basic">basic</option>
+ <option value="bnf">bnf</option>
+ <option value="brainfuck">brainfuck</option>
+ <option value="c">c</option>
+ <option value="cal">cal</option>
+ <option value="capnproto">capnproto</option>
+ <option value="ceylon">ceylon</option>
+ <option value="clean">clean</option>
+ <option value="clojure">clojure</option>
+ <option value="clojure-repl">clojure-repl</option>
+ <option value="cmake">cmake</option>
+ <option value="coffeescript">coffeescript</option>
+ <option value="coq">coq</option>
+ <option value="cos">cos</option>
+ <option value="cpp">cpp</option>
+ <option value="crmsh">crmsh</option>
+ <option value="crystal">crystal</option>
+ <option value="csharp">csharp</option>
+ <option value="csp">csp</option>
+ <option value="css">css</option>
+ <option value="d">d</option>
+ <option value="dart">dart</option>
+ <option value="delphi">delphi</option>
+ <option value="diff">diff</option>
+ <option value="django">django</option>
+ <option value="dns">dns</option>
+ <option value="dockerfile">dockerfile</option>
+ <option value="dos">dos</option>
+ <option value="dsconfig">dsconfig</option>
+ <option value="dts">dts</option>
+ <option value="dust">dust</option>
+ <option value="ebnf">ebnf</option>
+ <option value="elixir">elixir</option>
+ <option value="elm">elm</option>
+ <option value="erb">erb</option>
+ <option value="erlang">erlang</option>
+ <option value="excel">excel</option>
+ <option value="fix">fix</option>
+ <option value="flix">flix</option>
+ <option value="fortran">fortran</option>
+ <option value="fsharp">fsharp</option>
+ <option value="gams">gams</option>
+ <option value="gauss">gauss</option>
+ <option value="gcode">gcode</option>
+ <option value="gherkin">gherkin</option>
+ <option value="glsl">glsl</option>
+ <option value="gml">gml</option>
+ <option value="go">go</option>
+ <option value="golo">golo</option>
+ <option value="gradle">gradle</option>
+ <option value="graphql">graphql</option>
+ <option value="groovy">groovy</option>
+ <option value="haml">haml</option>
+ <option value="handlebars">handlebars</option>
+ <option value="haskell">haskell</option>
+ <option value="haxe">haxe</option>
+ <option value="hsp">hsp</option>
+ <option value="http">http</option>
+ <option value="hy">hy</option>
+ <option value="inform7">inform7</option>
+ <option value="ini">ini</option>
+ <option value="irpf90">irpf90</option>
+ <option value="isbl">isbl</option>
+ <option value="java">java</option>
+ <option value="javascript">javascript</option>
+ <option value="jboss-cli">jboss-cli</option>
+ <option value="json">json</option>
+ <option value="julia">julia</option>
+ <option value="julia-repl">julia-repl</option>
+ <option value="kotlin">kotlin</option>
+ <option value="lasso">lasso</option>
+ <option value="latex">latex</option>
+ <option value="ldif">ldif</option>
+ <option value="leaf">leaf</option>
+ <option value="less">less</option>
+ <option value="lisp">lisp</option>
+ <option value="livecodeserver">livecodeserver</option>
+ <option value="livescript">livescript</option>
+ <option value="llvm">llvm</option>
+ <option value="lsl">lsl</option>
+ <option value="lua">lua</option>
+ <option value="makefile">makefile</option>
+ <option value="markdown">markdown</option>
+ <option value="mathematica">mathematica</option>
+ <option value="matlab">matlab</option>
+ <option value="maxima">maxima</option>
+ <option value="mel">mel</option>
+ <option value="mercury">mercury</option>
+ <option value="mipsasm">mipsasm</option>
+ <option value="mizar">mizar</option>
+ <option value="mojolicious">mojolicious</option>
+ <option value="monkey">monkey</option>
+ <option value="moonscript">moonscript</option>
+ <option value="n1ql">n1ql</option>
+ <option value="nestedtext">nestedtext</option>
+ <option value="nginx">nginx</option>
+ <option value="nim">nim</option>
+ <option value="nix">nix</option>
+ <option value="node-repl">node-repl</option>
+ <option value="nsis">nsis</option>
+ <option value="objectivec">objectivec</option>
+ <option value="ocaml">ocaml</option>
+ <option value="openscad">openscad</option>
+ <option value="oxygene">oxygene</option>
+ <option value="parser3">parser3</option>
+ <option value="perl">perl</option>
+ <option value="pf">pf</option>
+ <option value="pgsql">pgsql</option>
+ <option value="php">php</option>
+ <option value="php-template">php-template</option>
+ <option value="plaintext">plaintext</option>
+ <option value="pony">pony</option>
+ <option value="powershell">powershell</option>
+ <option value="processing">processing</option>
+ <option value="profile">profile</option>
+ <option value="prolog">prolog</option>
+ <option value="properties">properties</option>
+ <option value="protobuf">protobuf</option>
+ <option value="puppet">puppet</option>
+ <option value="purebasic">purebasic</option>
+ <option value="python">python</option>
+ <option value="python-repl">python-repl</option>
+ <option value="q">q</option>
+ <option value="qml">qml</option>
+ <option value="r">r</option>
+ <option value="reasonml">reasonml</option>
+ <option value="rib">rib</option>
+ <option value="roboconf">roboconf</option>
+ <option value="routeros">routeros</option>
+ <option value="rsl">rsl</option>
+ <option value="ruby">ruby</option>
+ <option value="ruleslanguage">ruleslanguage</option>
+ <option value="rust">rust</option>
+ <option value="sas">sas</option>
+ <option value="scala">scala</option>
+ <option value="scheme">scheme</option>
+ <option value="scilab">scilab</option>
+ <option value="scss">scss</option>
+ <option value="shell">shell</option>
+ <option value="smali">smali</option>
+ <option value="smalltalk">smalltalk</option>
+ <option value="sml">sml</option>
+ <option value="sqf">sqf</option>
+ <option value="sql">sql</option>
+ <option value="stan">stan</option>
+ <option value="stata">stata</option>
+ <option value="step21">step21</option>
+ <option value="stylus">stylus</option>
+ <option value="subunit">subunit</option>
+ <option value="swift">swift</option>
+ <option value="taggerscript">taggerscript</option>
+ <option value="tap">tap</option>
+ <option value="tcl">tcl</option>
+ <option value="thrift">thrift</option>
+ <option value="tp">tp</option>
+ <option value="twig">twig</option>
+ <option value="typescript">typescript</option>
+ <option value="vala">vala</option>
+ <option value="vbnet">vbnet</option>
+ <option value="vbscript">vbscript</option>
+ <option value="vbscript-html">vbscript-html</option>
+ <option value="verilog">verilog</option>
+ <option value="vhdl">vhdl</option>
+ <option value="vim">vim</option>
+ <option value="wasm">wasm</option>
+ <option value="wren">wren</option>
+ <option value="x86asm">x86asm</option>
+ <option value="xl">xl</option>
+ <option value="xml">xml</option>
+ <option value="xquery">xquery</option>
+ <option value="yaml">yaml</option>
+ <option value="zephir">zephir</option>
+ </select></div><br><input type="password" id="passphrase"
+ placeholder="passphrase (optional)"><small>&nbsp;encrypted with <a href="https://github.com/kj-sh604/mojicrypt"
+ target="_blank">mojicrypt</a></small>
+ <div class="result" id="result"><span>link: <a id="result-link" href="#" target="_blank"></a></span><button
+ onclick="copyLink()" style="margin-left: 0.5rem; font-size: 0.85rem; padding: 0.25rem 0.5rem;">copy
+ link</button></div>
+ <div class="status" id="status"></div>
+ <script src="main.js" defer></script>
+</body>
+
+</html> \ No newline at end of file
diff --git a/src/main.js b/src/main.js
new file mode 100644
index 0000000..9b33dca
--- /dev/null
+++ b/src/main.js
@@ -0,0 +1,111 @@
+const FORM_STATE_KEY = "kj-clipboard-form-state-v1";
+
+function saveFormState() {
+ const state = {
+ content: document.getElementById("content").value,
+ isCode: document.getElementById("is-code").checked,
+ language: document.getElementById("lang-select").value,
+ };
+ sessionStorage.setItem(FORM_STATE_KEY, JSON.stringify(state));
+}
+
+function restoreFormState() {
+ const raw = sessionStorage.getItem(FORM_STATE_KEY);
+ if (!raw) {
+ toggleLang();
+ return;
+ }
+ try {
+ const state = JSON.parse(raw);
+ document.getElementById("content").value =
+ typeof state.content === "string" ? state.content : "";
+ document.getElementById("is-code").checked = !!state.isCode;
+ const langSelect = document.getElementById("lang-select");
+ if (typeof state.language === "string") {
+ const langExists = Array.from(langSelect.options).some(
+ (opt) => opt.value === state.language
+ );
+ langSelect.value = langExists ? state.language : "";
+ }
+ } catch (_err) {
+ sessionStorage.removeItem(FORM_STATE_KEY);
+ }
+ toggleLang();
+}
+
+function toggleLang() {
+ const sel = document.getElementById("lang-select");
+ sel.style.display = document.getElementById("is-code").checked
+ ? "inline-block"
+ : "none";
+ saveFormState();
+}
+
+async function createPaste() {
+ const content = document.getElementById("content").value.trim();
+ if (!content) {
+ setStatus("nothing to paste.");
+ return;
+ }
+ const btn = document.getElementById("get-link-btn");
+ btn.disabled = true;
+ btn.textContent = "generating...";
+ setStatus("");
+ const body = {
+ content: content,
+ is_code: document.getElementById("is-code").checked,
+ language: document.getElementById("lang-select").value,
+ passphrase: document.getElementById("passphrase").value,
+ };
+ try {
+ const resp = await fetch("/api/paste", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(body),
+ });
+ const data = await resp.json();
+ if (data.error) {
+ setStatus("error: " + data.error);
+ btn.disabled = false;
+ btn.textContent = "generate link";
+ return;
+ }
+ const url = window.location.origin + data.url;
+ const linkEl = document.getElementById("result-link");
+ linkEl.href = url;
+ linkEl.textContent = url;
+ document.getElementById("result").style.display = "block";
+ setStatus("done.");
+ } catch (e) {
+ setStatus("error: " + e.message);
+ }
+ btn.disabled = false;
+ btn.textContent = "generate link";
+}
+
+function copyLink() {
+ const url = document.getElementById("result-link").textContent;
+ navigator.clipboard.writeText(url);
+}
+
+function setStatus(msg) {
+ document.getElementById("status").textContent = msg;
+}
+
+restoreFormState();
+
+document.getElementById("content").addEventListener("input", saveFormState);
+document.getElementById("lang-select").addEventListener("change", saveFormState);
+
+// allow tab key in textarea
+document.getElementById("content").addEventListener("keydown", function (e) {
+ if (e.key === "Tab") {
+ e.preventDefault();
+ const start = this.selectionStart;
+ const end = this.selectionEnd;
+ this.value =
+ this.value.substring(0, start) + "\t" + this.value.substring(end);
+ this.selectionStart = this.selectionEnd = start + 1;
+ saveFormState();
+ }
+});
diff --git a/src/server.py b/src/server.py
index fe4537b..4653af4 100644
--- a/src/server.py
+++ b/src/server.py
@@ -41,6 +41,10 @@ ALLOWED_LANGUAGES = {
"abnf",
"accesslog",
"ada",
+ "angelscript",
+ "apache",
+ "applescript",
+ "arcade",
"arduino",
"armasm",
"asciidoc",
@@ -118,6 +122,7 @@ ALLOWED_LANGUAGES = {
"jboss-cli",
"json",
"julia",
+ "julia-repl",
"kotlin",
"lasso",
"latex",
@@ -209,6 +214,7 @@ ALLOWED_LANGUAGES = {
"vala",
"vbnet",
"vbscript",
+ "vbscript-html",
"verilog",
"vhdl",
"vim",
@@ -653,6 +659,20 @@ class ClipboardHandler(http.server.BaseHTTPRequestHandler):
self.send_html(200, landing_page())
return
+ if path == "/main.js":
+ js_path = BASE_DIR / "main.js"
+ if not js_path.exists():
+ self.send_plain(404, "not found")
+ return
+ data = js_path.read_bytes()
+ self.send_response(200)
+ self.send_header("Content-Type", "application/javascript; charset=utf-8")
+ self.send_header("Content-Length", str(len(data)))
+ self.add_security_headers()
+ self.end_headers()
+ self.wfile.write(data)
+ return
+
if path.startswith("/raw/"):
paste_id = path[5:]
if not is_valid_paste_id(paste_id):