mirror of
https://github.com/lus/pasty.git
synced 2023-08-10 21:13:09 +03:00
Implement frontend
This commit is contained in:
parent
d1720c92f2
commit
bfe9c5b628
1
.gitignore
vendored
1
.gitignore
vendored
@ -115,3 +115,4 @@ modules.xml
|
|||||||
# End of https://www.toptal.com/developers/gitignore/api/jetbrains+all,go
|
# End of https://www.toptal.com/developers/gitignore/api/jetbrains+all,go
|
||||||
|
|
||||||
web/*.gz
|
web/*.gz
|
||||||
|
data/
|
@ -53,5 +53,5 @@ func (paste *Paste) HashDeletionToken() error {
|
|||||||
// CheckDeletionToken checks whether or not the given deletion token is correct
|
// CheckDeletionToken checks whether or not the given deletion token is correct
|
||||||
func (paste *Paste) CheckDeletionToken(deletionToken string) bool {
|
func (paste *Paste) CheckDeletionToken(deletionToken string) bool {
|
||||||
match, err := argon2id.ComparePasswordAndHash(deletionToken, paste.DeletionToken)
|
match, err := argon2id.ComparePasswordAndHash(deletionToken, paste.DeletionToken)
|
||||||
return err != nil && match
|
return err == nil && match
|
||||||
}
|
}
|
||||||
|
172
web/css/style.css
Normal file
172
web/css/style.css
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
@import url("https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap");
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #000000;
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: 'Source Code Pro', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes spinner {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate3d(-50%, -50%, 0) rotate(0deg);
|
||||||
|
transform: translate3d(-50%, -50%, 0) rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate3d(-50%, -50%, 0) rotate(360deg);
|
||||||
|
transform: translate3d(-50%, -50%, 0) rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spinner {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate3d(-50%, -50%, 0) rotate(0deg);
|
||||||
|
transform: translate3d(-50%, -50%, 0) rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate3d(-50%, -50%, 0) rotate(360deg);
|
||||||
|
transform: translate3d(-50%, -50%, 0) rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#spinner {
|
||||||
|
-webkit-animation: .75s linear infinite spinner;
|
||||||
|
animation: .75s linear infinite spinner;
|
||||||
|
-webkit-animation-play-state: inherit;
|
||||||
|
animation-play-state: inherit;
|
||||||
|
border: solid 5px #ffffff;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
border-radius: 50%;
|
||||||
|
height: 50px;
|
||||||
|
width: 50px;
|
||||||
|
position: fixed;
|
||||||
|
top: 130px;
|
||||||
|
right: 20px;
|
||||||
|
-webkit-transform: translate3d(-50%, -50%, 0);
|
||||||
|
transform: translate3d(-50%, -50%, 0);
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
width: calc(100vw - 80px);
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-orient: horizontal;
|
||||||
|
-webkit-box-direction: normal;
|
||||||
|
-ms-flex-direction: row;
|
||||||
|
flex-direction: row;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
-webkit-box-pack: justify;
|
||||||
|
-ms-flex-pack: justify;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 40px;
|
||||||
|
background-color: #222222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation .button {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation .button svg {
|
||||||
|
-webkit-transition: all 250ms;
|
||||||
|
transition: all 250ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation .button:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation .button:hover svg {
|
||||||
|
stroke: #2daa57;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation .button:disabled svg {
|
||||||
|
stroke: #5a5a5a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation .button:disabled:hover {
|
||||||
|
cursor: initial;
|
||||||
|
color: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation .meta {
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-orient: horizontal;
|
||||||
|
-webkit-box-direction: normal;
|
||||||
|
-ms-flex-direction: row;
|
||||||
|
flex-direction: row;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation .meta #version {
|
||||||
|
margin-right: 40px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
background-color: #000000;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
margin-top: 60px;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-orient: horizontal;
|
||||||
|
-webkit-box-direction: normal;
|
||||||
|
-ms-flex-direction: row;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container #linenos {
|
||||||
|
padding: 20px 0;
|
||||||
|
width: 50px;
|
||||||
|
min-height: calc(100vh - 100px);
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-box-direction: normal;
|
||||||
|
-ms-flex-direction: column;
|
||||||
|
flex-direction: column;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #111111;
|
||||||
|
color: #bebebe;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container #content {
|
||||||
|
padding: 20px;
|
||||||
|
width: calc(100vw - 50px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container #content #code {
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container #content #input {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
color: inherit;
|
||||||
|
resize: none;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
/*# sourceMappingURL=style.css.map */
|
9
web/css/style.css.map
Normal file
9
web/css/style.css.map
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"mappings": "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",
|
||||||
|
"sources": [
|
||||||
|
"style.scss"
|
||||||
|
],
|
||||||
|
"names": [],
|
||||||
|
"file": "style.css"
|
||||||
|
}
|
130
web/css/style.scss
Normal file
130
web/css/style.scss
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro&display=swap');
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #000000;
|
||||||
|
color: #ffffff;
|
||||||
|
font-family: 'Source Code Pro', monospace;
|
||||||
|
}
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes spinner {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate3d(-50%, -50%, 0) rotate(0deg);
|
||||||
|
transform: translate3d(-50%, -50%, 0) rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate3d(-50%, -50%, 0) rotate(360deg);
|
||||||
|
transform: translate3d(-50%, -50%, 0) rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes spinner {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: translate3d(-50%, -50%, 0) rotate(0deg);
|
||||||
|
transform: translate3d(-50%, -50%, 0) rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: translate3d(-50%, -50%, 0) rotate(360deg);
|
||||||
|
transform: translate3d(-50%, -50%, 0) rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#spinner {
|
||||||
|
-webkit-animation: .75s linear infinite spinner;
|
||||||
|
animation: .75s linear infinite spinner;
|
||||||
|
-webkit-animation-play-state: inherit;
|
||||||
|
animation-play-state: inherit;
|
||||||
|
border: solid 5px #ffffff;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
border-radius: 50%;
|
||||||
|
height: 50px;
|
||||||
|
width: 50px;
|
||||||
|
position: fixed;
|
||||||
|
top: 130px;
|
||||||
|
right: 20px;
|
||||||
|
-webkit-transform: translate3d(-50%, -50%, 0);
|
||||||
|
transform: translate3d(-50%, -50%, 0);
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
width: calc(100vw - 80px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 40px;
|
||||||
|
background-color: #222222;
|
||||||
|
& .button {
|
||||||
|
padding: 10px 20px;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
& svg {
|
||||||
|
transition: all 250ms;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
& svg {
|
||||||
|
stroke: #2daa57;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:disabled {
|
||||||
|
& svg {
|
||||||
|
stroke: #5a5a5a;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
cursor: initial;
|
||||||
|
color: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& .meta {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
& #version {
|
||||||
|
margin-right: 40px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
background-color: #000000;
|
||||||
|
border-radius: 10px;;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
margin-top: 60px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
& #linenos {
|
||||||
|
padding: 20px 0;
|
||||||
|
width: 50px;
|
||||||
|
min-height: calc(100vh - 100px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #111111;
|
||||||
|
color: #bebebe;
|
||||||
|
}
|
||||||
|
& #content {
|
||||||
|
padding: 20px;
|
||||||
|
width: calc(100vw - 50px);
|
||||||
|
& #code {
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
& #input {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
color: inherit;
|
||||||
|
resize: none;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,8 +4,67 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>pasty</title>
|
<title>pasty</title>
|
||||||
|
<link rel="stylesheet" href="css/style.css">
|
||||||
|
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.1.2/build/styles/default.min.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
frontend
|
<div id="spinner" class="hidden"></div>
|
||||||
|
<div class="navigation">
|
||||||
|
<div class="buttons">
|
||||||
|
<button class="button" id="btn_new" title="Create new paste (Ctrl + Q)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-circle-plus" width="40" height="40" viewBox="0 0 24 24" stroke-width="1.5" stroke="#bebebe" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<circle cx="12" cy="12" r="9" />
|
||||||
|
<line x1="9" y1="12" x2="15" y2="12" />
|
||||||
|
<line x1="12" y1="9" x2="12" y2="15" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button class="button" id="btn_save" title="Save paste (Ctrl + S)">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-device-floppy" width="40" height="40" viewBox="0 0 24 24" stroke-width="1.5" stroke="#bebebe" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<path d="M6 4h10l4 4v10a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2" />
|
||||||
|
<circle cx="12" cy="14" r="2" />
|
||||||
|
<polyline points="14 4 14 8 8 8 8 4" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button class="button" id="btn_delete" title="Delete paste (Ctrl + X)" disabled>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-trash" width="40" height="40" viewBox="0 0 24 24" stroke-width="1.5" stroke="#bebebe" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<line x1="4" y1="7" x2="20" y2="7" />
|
||||||
|
<line x1="10" y1="11" x2="10" y2="17" />
|
||||||
|
<line x1="14" y1="11" x2="14" y2="17" />
|
||||||
|
<path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12" />
|
||||||
|
<path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button class="button" id="btn_copy" title="Copy paste to clipboard (Ctrl + C)" disabled>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-clipboard" width="40" height="40" viewBox="0 0 24 24" stroke-width="1.5" stroke="#bebebe" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<path d="M9 5H7a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2V7a2 2 0 0 0 -2 -2h-2" />
|
||||||
|
<rect x="9" y="3" width="6" height="4" rx="2" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="meta">
|
||||||
|
<div id="version">loading...</div>
|
||||||
|
<a class="button" title="View the GitHub repository" href="https://github.com/Lukaesebrot/pasty" target="_blank">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-github" width="40" height="40" viewBox="0 0 24 24" stroke-width="1.5" stroke="#bebebe" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z"/>
|
||||||
|
<path d="M9 19c-4.286 1.35-4.286-2.55-6-3m12 5v-3.5c0-1 .099-1.405-.5-2 2.791-.3 5.5-1.366 5.5-6.04a4.567 4.567 0 0 0 -1.333 -3.21a4.192 4.192 0 0 0 -.08 -3.227s-1.05-.3-3.476 1.267a12.334 12.334 0 0 0 -6.222 0C6.462 2.723 5.413 3.023 5.413 3.023a4.192 4.192 0 0 0 -.08 3.227A4.566 4.566 0 0 0 4 9.486c0 4.64 2.709 5.68 5.5 6.014-.591.589-.56 1.183-.5 2V21" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
<div id="linenos"></div>
|
||||||
|
<div id="content">
|
||||||
|
<div id="code"></div>
|
||||||
|
<textarea id="input" class="hidden"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.1.2/build/highlight.min.js"></script>
|
||||||
|
<script src="js/rest.js"></script>
|
||||||
|
<script src="js/buttons.js"></script>
|
||||||
|
<script src="js/autoload.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
53
web/js/autoload.js
Normal file
53
web/js/autoload.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// Load the API information
|
||||||
|
loadAPIInfo();
|
||||||
|
|
||||||
|
// Set up the keybinds
|
||||||
|
setupKeybinds();
|
||||||
|
|
||||||
|
// Try to load a paste if one exists
|
||||||
|
let PASTE_ID = "";
|
||||||
|
function loadPaste() {
|
||||||
|
let split = location.pathname.split(".");
|
||||||
|
let pasteID = split[0];
|
||||||
|
let language = split[1];
|
||||||
|
getPaste(pasteID, function(success, data) {
|
||||||
|
// Return if no paste was found
|
||||||
|
if (!success) {
|
||||||
|
location.replace(location.protocol + "//" + location.host);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enable and disable the corresponding buttons
|
||||||
|
document.getElementById("btn_save").setAttribute("disabled", true);
|
||||||
|
document.getElementById("btn_delete").removeAttribute("disabled");
|
||||||
|
document.getElementById("btn_copy").removeAttribute("disabled");
|
||||||
|
|
||||||
|
// Set the paste content to the DOM and display the line numbers
|
||||||
|
document.getElementById("code").innerHTML = language
|
||||||
|
? hljs.highlight(language, data.content).value.replace("\n", "<br />")
|
||||||
|
: hljs.highlightAuto(data.content).value.replace("\n", "<br />");
|
||||||
|
for (i = 1; i <= data.content.split(/\n/).length; i++) {
|
||||||
|
document.getElementById("linenos").innerHTML += "<span>" + i + "</span>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the PASTE_ID variable
|
||||||
|
PASTE_ID = pasteID;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (location.pathname != "/") {
|
||||||
|
loadPaste();
|
||||||
|
} else {
|
||||||
|
const element = document.getElementById("input");
|
||||||
|
element.classList.remove("hidden");
|
||||||
|
element.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define a function to copy text to the clipboard
|
||||||
|
function copyToClipboard(text) {
|
||||||
|
const element = document.createElement("textarea");
|
||||||
|
element.value = text;
|
||||||
|
document.body.appendChild(element);
|
||||||
|
element.select();
|
||||||
|
document.execCommand("copy");
|
||||||
|
document.body.removeChild(element);
|
||||||
|
}
|
82
web/js/buttons.js
Normal file
82
web/js/buttons.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
// setupKeybinds initializes the keybinds for the buttons
|
||||||
|
function setupKeybinds() {
|
||||||
|
window.onkeydown = function(event) {
|
||||||
|
if (!event.ctrlKey) return;
|
||||||
|
|
||||||
|
let element = null;
|
||||||
|
switch (event.keyCode) {
|
||||||
|
case 81: {
|
||||||
|
element = document.getElementById("btn_new");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 83: {
|
||||||
|
element = document.getElementById("btn_save");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 88: {
|
||||||
|
element = document.getElementById("btn_delete");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 67: {
|
||||||
|
element = document.getElementById("btn_copy");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element) {
|
||||||
|
if (element.hasAttribute("disabled")) return;
|
||||||
|
event.preventDefault();
|
||||||
|
element.onclick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the behavior of the 'new' button
|
||||||
|
document.getElementById("btn_new").onclick = function() {
|
||||||
|
location.replace(location.protocol + "//" + location.host);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the behavior of the 'save' button
|
||||||
|
document.getElementById("btn_save").onclick = function() {
|
||||||
|
// Return if the text area is empty
|
||||||
|
if (!document.getElementById("input").value) return;
|
||||||
|
|
||||||
|
// Create the paste
|
||||||
|
createPaste(document.getElementById("input").value, function(success, data) {
|
||||||
|
// Notify the user about an error if one occurs
|
||||||
|
if (!success) {
|
||||||
|
alert("Error:\n\n" + data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect the user to the paste page
|
||||||
|
let address = location.protocol + "//" + location.host + "/" + data.id;
|
||||||
|
if (data.suggestedSyntaxType) address += "." + data.suggestedSyntaxType;
|
||||||
|
copyToClipboard(data.deletionToken);
|
||||||
|
location.replace(address);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the behavior of the 'delete' button
|
||||||
|
document.getElementById("btn_delete").onclick = function() {
|
||||||
|
// Ask the user for the deletion token
|
||||||
|
let deletionToken = window.prompt("Deletion Token:");
|
||||||
|
if (!deletionToken) return;
|
||||||
|
|
||||||
|
// Delete the paste
|
||||||
|
deletePaste(PASTE_ID, deletionToken, function(success, data) {
|
||||||
|
// Notify the user about an error if one occurs
|
||||||
|
if (!success) {
|
||||||
|
alert("Error:\n\n" + data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect the user to the default page
|
||||||
|
location.replace(location.protocol + "//" + location.host);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define the behavior of the 'copy' button
|
||||||
|
document.getElementById("btn_copy").onclick = function() {
|
||||||
|
copyToClipboard(document.getElementById("code").innerText);
|
||||||
|
}
|
56
web/js/rest.js
Normal file
56
web/js/rest.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// loadAPIInfo loads and displays the API information
|
||||||
|
function loadAPIInfo() {
|
||||||
|
fetch(location.protocol + "//" + location.host + "/api/v1/info")
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => document.getElementById("version").innerText = data.version);
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPaste retrieves a paste
|
||||||
|
function getPaste(id, callback) {
|
||||||
|
fetch(location.protocol + "//" + location.host + "/api/v1/pastes/" + id)
|
||||||
|
.then(response => {
|
||||||
|
if (response.status != 200) {
|
||||||
|
response.text().then(data => callback(false, data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.json().then(data => callback(true, data));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// createPaste creates a new paste
|
||||||
|
function createPaste(content, callback) {
|
||||||
|
fetch(location.protocol + "//" + location.host + "/api/v1/pastes", {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
content: content
|
||||||
|
})
|
||||||
|
}).then(response => {
|
||||||
|
if (response.status != 200) {
|
||||||
|
response.text().then(data => callback(false, data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.json().then(data => callback(true, data));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// deletePaste deletes a paste
|
||||||
|
function deletePaste(id, deletionToken, callback) {
|
||||||
|
fetch(location.protocol + "//" + location.host + "/api/v1/pastes/" + id, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
deletionToken: deletionToken
|
||||||
|
})
|
||||||
|
}).then(response => {
|
||||||
|
if (response.status != 200) {
|
||||||
|
response.text().then(data => callback(false, data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.text().then(data => callback(true, data));
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user