mirror of
https://github.com/rikkaneko/paste.git
synced 2025-06-06 16:45:41 +00:00
Update path to frontend static files
Signed-off-by: Joe Ma <rikkaneko23@gmail.com>
This commit is contained in:
parent
3de4fa14ed
commit
2e9a56376d
7 changed files with 8 additions and 187 deletions
20
frontend/.eslintrc.json
Normal file
20
frontend/.eslintrc.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"extends": ["eslint:recommended", "prettier"],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020
|
||||
},
|
||||
"plugins": ["plugin"],
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"node": true
|
||||
}
|
||||
},
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"jquery": true
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off"
|
||||
}
|
||||
}
|
277
frontend/paste.html
Normal file
277
frontend/paste.html
Normal file
|
@ -0,0 +1,277 @@
|
|||
<!--
|
||||
~ This file is part of paste.
|
||||
~ Copyright (c) 2022-2023 Joe Ma <rikkaneko23@gmail.com>
|
||||
~
|
||||
~ This program is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU Lesser General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ This program is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU Lesser General Public License
|
||||
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/html">
|
||||
<head>
|
||||
<title>Paste</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width initial-scale=1 shrink-to-fit=1">
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" rel="stylesheet">
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.9.1/font/bootstrap-icons.min.css"
|
||||
rel="stylesheet">
|
||||
<link href="/static/paste.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar sticky-top navbar-expand-lg navbar-dark bg-dark" id="navbar">
|
||||
<div class="container-fluid">
|
||||
<span class="navbar-brand">Paste</span>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbar_supported_content"
|
||||
aria-controls="navbar_supported_content" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="bi bi-chevron-down"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbar_supported_content">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="https://nekoid.cc">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="https://github.com/rikkaneko/paste#api-specification">API</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://pb.nekoid.cc/v1">Switch to old version</a>
|
||||
</li>
|
||||
</ul>
|
||||
<form class="d-flex" role="search">
|
||||
<input class="form-control me-2" type="search" placeholder="Paste ID" aria-label="go" id="go_paste_id"
|
||||
maxlength="4" data-bs-toggle="tooltip" data-bs-placement="bottom"
|
||||
title="Paste ID should be in 4 characters.">
|
||||
<button class="btn btn-outline-success me-2" type="button" id="go_button">Go</button>
|
||||
<button class="btn btn-outline-success" type="button" id="view_info_button">Detail</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="position-relative mb-2" id="alert-container">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-center vh-100" style="margin-top: 130px">
|
||||
<form class="container" style="max-width: 400px;" id="upload_form">
|
||||
<div class="mb-3">
|
||||
<div><label class="form-label">Paste Type</label></div>
|
||||
<div class="btn-group w-100" role="group" aria-label="Paste type group">
|
||||
<input type="radio" class="btn-check" name="paste-type" id="paste_type_file" autocomplete="off" checked
|
||||
onclick="select_input_type('file')" value="file">
|
||||
<label class="btn btn-outline-primary" for="paste_type_file">File</label>
|
||||
<input type="radio" class="btn-check" name="paste-type" id="paste_type_text" autocomplete="off"
|
||||
onclick="select_input_type('text')" value="text">
|
||||
<label class="btn btn-outline-primary" for="paste_type_text">Text</label>
|
||||
<input type="radio" class="btn-check" name="paste-type" id="paste_type_url" autocomplete="off"
|
||||
onclick="select_input_type('url')" value="url">
|
||||
<label class="btn btn-outline-primary" for="paste_type_url">URL</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="file_upload_layout" class="collapse show">
|
||||
<div class="mb-2">
|
||||
<label for="file_upload" class="form-label">Upload File</label>
|
||||
<input class="form-control" type="file" id="file_upload" name="u">
|
||||
</div>
|
||||
<div class="text-sm-start mb-3">
|
||||
<small id="file_stats">0 bytes</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="text_input_layout" class="collapse">
|
||||
<div class="mb-2">
|
||||
<label for="text_input" class="form-label">Upload Text</label>
|
||||
<textarea class="form-control" id="text_input" rows="10" name="u" disabled></textarea>
|
||||
</div>
|
||||
<div class="text-sm-start mb-3">
|
||||
<small id="char_count">0 characters</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="url_input_layout" class="collapse">
|
||||
<div class="mb-2">
|
||||
<label for="url_input" class="form-label">URL Address</label>
|
||||
<input type="url" class="form-control" id="url_input" placeholder="https://example.com" name="u" disabled>
|
||||
</div>
|
||||
<div class="text-sm-start mb-3">
|
||||
<small id="url_validate_result"></small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="paste_title" class="form-label">Title</label>
|
||||
<input type="text" class="form-control" id="paste_title" placeholder="" name="title">
|
||||
</div>
|
||||
|
||||
<div class="card-header mb-3">
|
||||
<span data-bs-toggle="collapse" data-bs-target="#advanced_settings_layout" aria-expanded="false"
|
||||
aria-controls="advanced_settings_layout" id="advanced_settings_control"
|
||||
class="d-block collapsed">
|
||||
<i class="fa fa-chevron-down pull-right mt-1"></i>
|
||||
Advanced Settings
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="advanced_settings_layout" class="collapse">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="pass_input">Password</label>
|
||||
<div class="input-group mb-3">
|
||||
<input class="form-control password lock" id="pass_input" type="password" name="pass"/>
|
||||
<span class="input-group-text" style="cursor: pointer" id="show_pass_button">
|
||||
<i class="bi bi-eye-slash" id="show_pass_icon"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="read_limit_input" class="form-label">Read limit</label>
|
||||
<input type="number" class="form-control" id="read_limit_input" min="1" name="read-limit">
|
||||
</div>
|
||||
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input" type="checkbox" id="show_qrcode_checkbox" checked value="1">
|
||||
<label class="form-check-label" for="show_qrcode_checkbox">
|
||||
Show QR code
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-check mb-3">
|
||||
<input class="form-check-input" type="checkbox" value="" id="tos_btn" required>
|
||||
<label class="form-check-label" for="tos_btn">
|
||||
I understand <a data-bs-toggle="modal" data-bs-target="#tos_modal" role="button"><u>
|
||||
the terms of service</u></a>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 text-end">
|
||||
<button type="button" class="btn btn-secondary me-2" id="show_saved_button" disabled>Saved Paste</button>
|
||||
<button type="button" class="btn btn-primary" id="upload_button">Upload</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="tos_modal" tabindex="-1" aria-labelledby="tos_modal_label" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-scrollable">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="tos_modal_label">Terms of service</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<h3>Paste Service</h3>
|
||||
<p>
|
||||
<a href="https://pb.nekoid.cc">pb.nekoid.cc</a> is a pastebin-like service hosted on Cloudflare Worker.
|
||||
This service is primarily designed for own usage and interest only.<br>
|
||||
All data may be deleted or expired without any notification and guarantee. Please <b>DO NOT</b> abuse this
|
||||
service.
|
||||
The limit for file upload is <b>10 MB</b> and the paste will be kept for <b>28 days</b> only by default.<br>
|
||||
The source code is available in my GitHub repository <a
|
||||
href="https://github.com/rikkaneko/paste">[here]</a>.<br>
|
||||
This webpage is designed for upload files only.
|
||||
For other operations like changing paste settings and deleting paste, please make use of the
|
||||
<a href="https://github.com/rikkaneko/paste#api-specification">API call</a> with <a
|
||||
href="https://wiki.archlinux.org/title/CURL">curl</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<img src="https://files.nekoid.cc/pub/satanichia.png" class="rounded mx-auto d-block w-100" loading="lazy"
|
||||
alt="There should be a Satanichia ~" data-bs-toggle="tooltip"
|
||||
data-bs-placement="bottom" title="Satanichia is so cute >w<">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="paste_modal" tabindex="-1" aria-labelledby="paste_modal_label" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-scrollable">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="paste_modal_label">Paste</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-2 input-group justify-content-center">
|
||||
<span class="input-group-text" id="paste_uuid"></span>
|
||||
<button class="btn btn-primary" type="button" id="id_copy_button"
|
||||
data-bs-toggle="tooltip" data-bs-placement="bottom" title="Click to copy">
|
||||
<i class="bi bi-clipboard" id="id_copy_button_icon"></i>
|
||||
</button>
|
||||
</div>
|
||||
<img src="" class="mb-3 rounded mx-auto d-block w-75" alt="" id="paste_qrcode" style="max-width: 280px">
|
||||
<div class="mb-3 w-75 mx-auto">
|
||||
<table class="table table-striped table-bordered align-middle caption-top">
|
||||
<caption>Paste information</caption>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="text-center col-3 text-nowrap">Paste ID</td>
|
||||
<td class="text-center col-6" id="paste_info_uuid">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center col-3 text-nowrap">Title</td>
|
||||
<td class="text-center col-6" id="paste_info_title">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center col-3 text-nowrap">Type</td>
|
||||
<td class="text-center col-6" id="paste_info_type">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center col-3 text-nowrap">Size</td>
|
||||
<td class="text-center col-6" id="paste_info_human_readable_size">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center col-3 text-nowrap">Password</td>
|
||||
<td class="text-center col-6" id="paste_info_password">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center col-3 text-nowrap">Read limit</td>
|
||||
<td class="text-center col-6" id="paste_info_read_count_remain">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center col-3 text-nowrap">Created</td>
|
||||
<td class="text-center col-6 text-nowrap" id="paste_info_created">-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-center col-3 text-nowrap">Expired</td>
|
||||
<td class="text-center col-6 text-nowrap" id="paste_info_expired">-</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary me-2" id="forget_btn"
|
||||
data-bs-toggle="tooltip" data-bs-placement="bottom" title="Click to forget">
|
||||
Forget
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.6/umd/popper.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.min.js"></script>
|
||||
<script src="/static/paste.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
25
frontend/static/paste.css
Normal file
25
frontend/static/paste.css
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* This file is part of paste.
|
||||
* Copyright (c) 2023 Joe Ma <rikkaneko23@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.card-header .fa-chevron-down {
|
||||
transition: .3s transform ease-in-out;
|
||||
}
|
||||
|
||||
.card-header .collapsed .fa-chevron-down {
|
||||
transform: rotate(90deg);
|
||||
}
|
365
frontend/static/paste.js
Normal file
365
frontend/static/paste.js
Normal file
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* This file is part of paste.
|
||||
* Copyright (c) 2023 Joe Ma <rikkaneko23@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/// <reference path="../../node_modules/@types/bootstrap/index.d.ts" />
|
||||
|
||||
let input_div = {
|
||||
file: null,
|
||||
text: null,
|
||||
url: null,
|
||||
};
|
||||
|
||||
let inputs = {
|
||||
file: null,
|
||||
text: null,
|
||||
url: null,
|
||||
};
|
||||
|
||||
let paste_modal = {
|
||||
modal: null,
|
||||
uuid: null,
|
||||
qrcode: null,
|
||||
title: null,
|
||||
expired: null,
|
||||
id_copy_btn: null,
|
||||
id_copy_btn_icon: null,
|
||||
forget_btn: null,
|
||||
};
|
||||
|
||||
let cached_paste_info = null;
|
||||
let show_saved_btn = null;
|
||||
let show_qrcode = true;
|
||||
|
||||
function validate_url(path) {
|
||||
let url;
|
||||
try {
|
||||
url = new URL(path);
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
return url.protocol === 'http:' || url.protocol === 'https:';
|
||||
}
|
||||
|
||||
function show_pop_alert(message, alert_type = 'alert-primary', add_classes = null) {
|
||||
remove_pop_alert();
|
||||
$('#alert-container').prepend(
|
||||
jQuery.parseHTML(
|
||||
`<div class="alert ${alert_type} alert-dismissible position-absolute fade show top-0 start-50 translate-middle-x"
|
||||
style="margin-top: 30px; max-width: 500px; width: 80%" id="pop_alert" role="alert"> \
|
||||
<div>${message}</div> \
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> \
|
||||
</div>`
|
||||
)
|
||||
);
|
||||
if (add_classes) {
|
||||
$('.alert').addClass(add_classes);
|
||||
}
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
function remove_pop_alert() {
|
||||
const alert = $('#pop_alert');
|
||||
if (alert.length) alert.remove();
|
||||
}
|
||||
|
||||
function build_paste_modal(paste_info, show_qrcode = true, saved = true, build_only = false) {
|
||||
let tooltip = bootstrap.Tooltip.getInstance(paste_modal.id_copy_btn);
|
||||
|
||||
paste_modal.uuid.text(paste_info.link);
|
||||
paste_modal.qrcode.prop('src', paste_info.link_qr);
|
||||
paste_modal.qrcode.prop('alt', paste_info.link);
|
||||
paste_modal.id_copy_btn_icon.addClass('bi-clipboard');
|
||||
paste_modal.id_copy_btn_icon.removeClass('bi-check2');
|
||||
paste_modal.id_copy_btn.addClass('btn-primary');
|
||||
paste_modal.id_copy_btn.removeClass('btn-success');
|
||||
tooltip.setContent({ '.tooltip-inner': 'Click to copy' });
|
||||
|
||||
if (saved) {
|
||||
cached_paste_info = paste_info;
|
||||
localStorage.setItem('last_paste', JSON.stringify(paste_info));
|
||||
console.log('Paste saved');
|
||||
show_saved_btn.prop('disabled', false);
|
||||
}
|
||||
|
||||
// Hide/Show QRCode
|
||||
if (!show_qrcode) paste_modal.qrcode.addClass('d-none');
|
||||
else paste_modal.qrcode.removeClass('d-none');
|
||||
|
||||
// Hide/Show Forget button
|
||||
if (cached_paste_info) paste_modal.forget_btn.removeClass('d-none');
|
||||
else paste_modal.forget_btn.addClass('d-none');
|
||||
|
||||
Object.entries(paste_info).forEach(([key, val]) => {
|
||||
if (key.includes('link')) return;
|
||||
$(`#paste_info_${key}`).text(val ?? '-');
|
||||
});
|
||||
|
||||
let modal = new bootstrap.Modal(paste_modal.modal);
|
||||
if (!build_only) modal.show();
|
||||
}
|
||||
|
||||
$(function () {
|
||||
input_div.file = $('#file_upload_layout');
|
||||
input_div.text = $('#text_input_layout');
|
||||
input_div.url = $('#url_input_layout');
|
||||
inputs.file = $('#file_upload');
|
||||
inputs.text = $('#text_input');
|
||||
inputs.url = $('#url_input');
|
||||
paste_modal.modal = $('#paste_modal');
|
||||
paste_modal.uuid = $('#paste_uuid');
|
||||
paste_modal.qrcode = $('#paste_qrcode');
|
||||
paste_modal.id_copy_btn = $('#id_copy_button');
|
||||
paste_modal.id_copy_btn_icon = $('#id_copy_button_icon');
|
||||
paste_modal.forget_btn = $('#forget_btn');
|
||||
|
||||
let file_stat = $('#file_stats');
|
||||
let title = $('#paste_title');
|
||||
let char_count = $('#char_count');
|
||||
let pass_input = $('#pass_input');
|
||||
let show_pass_icon = $('#show_pass_icon');
|
||||
let upload_button = $('#upload_button');
|
||||
let url_validate_result = $('#url_validate_result');
|
||||
let tos_btn = $('#tos_btn');
|
||||
show_saved_btn = $('#show_saved_button');
|
||||
let go_btn = $('#go_button');
|
||||
let go_id = $('#go_paste_id');
|
||||
let view_btn = $('#view_info_button');
|
||||
let show_qrcode_checkbox = $('#show_qrcode_checkbox');
|
||||
|
||||
// Enable bootstrap tooltips
|
||||
const tooltip_trigger_list = [].slice.call($('[data-bs-toggle="tooltip"]'));
|
||||
const tooltip_list = tooltip_trigger_list.map(function (e) {
|
||||
return new bootstrap.Tooltip(e);
|
||||
});
|
||||
|
||||
// Restore saved paste info
|
||||
cached_paste_info = JSON.parse(localStorage.getItem('last_paste'));
|
||||
if (cached_paste_info) {
|
||||
show_saved_btn.prop('disabled', false);
|
||||
console.log('Restored cache paste');
|
||||
}
|
||||
|
||||
inputs.file.on('change', function () {
|
||||
inputs.file.removeClass('is-invalid');
|
||||
file_stat.removeClass('text-danger');
|
||||
if (this.files[0] === undefined) {
|
||||
file_stat.textContent = '0 bytes';
|
||||
return;
|
||||
}
|
||||
let bytes = this.files[0]?.size ?? 0;
|
||||
let size = bytes + ' bytes';
|
||||
const units = ['KiB', 'MiB', 'GiB', 'TiB'];
|
||||
for (let i = 0, approx = bytes / 1024; approx > 1; approx /= 1024, i++) {
|
||||
size = approx.toFixed(3) + ' ' + units[i];
|
||||
}
|
||||
title.val(this.files[0]?.name || '');
|
||||
file_stat.text(`${this.files[0]?.type || 'application/octet-stream'}, ${size}`);
|
||||
|
||||
// Check length
|
||||
if (bytes > 10485760) {
|
||||
inputs.file.addClass('is-invalid');
|
||||
file_stat.addClass('text-danger');
|
||||
file_stat.text('The uploaded file is larger than the 10 MB limit.');
|
||||
}
|
||||
});
|
||||
|
||||
inputs.text.on('input', function () {
|
||||
inputs.text.removeClass('is-invalid');
|
||||
char_count.removeClass('text-danger');
|
||||
char_count.text(`${this.value.length} characters`);
|
||||
if (this.value.length <= 0) {
|
||||
inputs.text.addClass('is-invalid');
|
||||
char_count.addClass('text-danger');
|
||||
char_count.text('Input text cannot be empty.');
|
||||
}
|
||||
});
|
||||
|
||||
$('#show_pass_button').on('click', function () {
|
||||
if (pass_input.attr('type') === 'password') {
|
||||
pass_input.attr('type', 'text');
|
||||
show_pass_icon.removeClass('bi-eye bi-eye-slash');
|
||||
show_pass_icon.addClass('bi-eye');
|
||||
} else if (pass_input.attr('type') === 'text') {
|
||||
pass_input.attr('type', 'password');
|
||||
show_pass_icon.removeClass('bi-eye bi-eye-slash');
|
||||
show_pass_icon.addClass('bi-eye-slash');
|
||||
}
|
||||
});
|
||||
|
||||
inputs.url.on('input', function () {
|
||||
inputs.url.removeClass('is-invalid');
|
||||
url_validate_result.removeClass('text-danger');
|
||||
url_validate_result.text('');
|
||||
if (!validate_url(this.value)) {
|
||||
inputs.url.addClass('is-invalid');
|
||||
url_validate_result.addClass('text-danger');
|
||||
url_validate_result.text('Invalid URL');
|
||||
}
|
||||
});
|
||||
|
||||
upload_button.on('click', async function () {
|
||||
const form = $('#upload_form')[0];
|
||||
let formdata = new FormData(form);
|
||||
const type = formdata.get('paste-type');
|
||||
const content = formdata.get('u');
|
||||
|
||||
inputs[type].trigger('input');
|
||||
if (inputs[type].hasClass('is-invalid') || !(!!content?.size || !!content?.length)) {
|
||||
show_pop_alert('Please check your upload file or content', 'alert-danger');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tos_btn.prop('checked')) {
|
||||
show_pop_alert('Please read the team and conditions before upload', 'alert-warning', 'tos-alert');
|
||||
tos_btn.addClass('is-invalid');
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'file':
|
||||
formdata.set('paste-type', 'paste');
|
||||
break;
|
||||
case 'text':
|
||||
formdata.set('paste-type', 'paste');
|
||||
break;
|
||||
case 'url':
|
||||
formdata.set('paste-type', 'link');
|
||||
}
|
||||
|
||||
// Remove empty entries
|
||||
let filtered = new FormData();
|
||||
formdata.forEach((val, key) => {
|
||||
if (val) filtered.set(key, val);
|
||||
});
|
||||
|
||||
// Request JSON response
|
||||
filtered.set('json', '1');
|
||||
upload_button.prop('disabled', true);
|
||||
upload_button.text('Uploading...');
|
||||
try {
|
||||
const res = await fetch('/', {
|
||||
method: 'POST',
|
||||
body: filtered,
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const paste_info = await res.json();
|
||||
show_pop_alert('Paste created!', 'alert-success');
|
||||
pass_input.val('');
|
||||
build_paste_modal(paste_info, show_qrcode);
|
||||
} else {
|
||||
show_pop_alert('Unable to create paste', 'alert-warning');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('error', err);
|
||||
show_pop_alert(err.message, 'alert-danger');
|
||||
}
|
||||
|
||||
upload_button.prop('disabled', false);
|
||||
upload_button.text('Upload');
|
||||
});
|
||||
|
||||
tos_btn.on('click', function () {
|
||||
tos_btn.removeClass('is-invalid');
|
||||
$('.tos-alert').remove();
|
||||
});
|
||||
|
||||
show_saved_btn.on('click', function () {
|
||||
if (!cached_paste_info) {
|
||||
show_pop_alert('No saved paste found.', 'alert-warning');
|
||||
return;
|
||||
}
|
||||
build_paste_modal(cached_paste_info, show_qrcode, false);
|
||||
});
|
||||
|
||||
go_btn.on('click', function () {
|
||||
const uuid = go_id.val();
|
||||
if (uuid.length !== 4) {
|
||||
show_pop_alert('Invalid Paste ID.', 'alert-warning');
|
||||
return;
|
||||
}
|
||||
window.open(`/${uuid}`);
|
||||
});
|
||||
|
||||
view_btn.on('click', async function () {
|
||||
const uuid = go_id.val();
|
||||
if (uuid.length !== 4) {
|
||||
show_pop_alert('Invalid Paste ID.', 'alert-warning');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`/${uuid}/settings?${new URLSearchParams({ json: '1' })}`);
|
||||
if (res.ok) {
|
||||
const paste_info = await res.json();
|
||||
build_paste_modal(paste_info, show_qrcode, false);
|
||||
} else {
|
||||
show_pop_alert('Invalid Paste ID.', 'alert-warning');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('error', err);
|
||||
show_pop_alert(err.message, 'alert-danger');
|
||||
}
|
||||
});
|
||||
|
||||
paste_modal.id_copy_btn.on('click', async function () {
|
||||
const uuid = paste_modal.uuid.text();
|
||||
let tooltip = bootstrap.Tooltip.getInstance(paste_modal.id_copy_btn);
|
||||
|
||||
if (navigator.clipboard) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(uuid);
|
||||
paste_modal.id_copy_btn_icon.removeClass('bi-clipboard');
|
||||
paste_modal.id_copy_btn_icon.addClass('bi-check2');
|
||||
paste_modal.id_copy_btn.removeClass('btn-primary');
|
||||
paste_modal.id_copy_btn.addClass('btn-success');
|
||||
tooltip.setContent({ '.tooltip-inner': 'Copied' });
|
||||
} catch (err) {
|
||||
tooltip.setContent({ '.tooltip-inner': 'Copied failed' });
|
||||
}
|
||||
} else {
|
||||
tooltip.setContent({ '.tooltip-inner': 'Copied failed' });
|
||||
}
|
||||
});
|
||||
|
||||
paste_modal.forget_btn.on('click', function () {
|
||||
let tooltip = bootstrap.Tooltip.getInstance(paste_modal.forget_btn);
|
||||
|
||||
if (cached_paste_info) {
|
||||
cached_paste_info = null;
|
||||
localStorage.removeItem('last_paste');
|
||||
console.log('Removed cached paste');
|
||||
tooltip.setContent({ '.tooltip-inner': 'Forgotten!' });
|
||||
show_saved_btn.prop('disabled', true);
|
||||
}
|
||||
});
|
||||
|
||||
show_qrcode_checkbox.on('click', function () {
|
||||
show_qrcode = show_qrcode_checkbox.prop('checked');
|
||||
});
|
||||
});
|
||||
|
||||
function select_input_type(name) {
|
||||
Object.keys(input_div).forEach((key) => {
|
||||
input_div[key].collapse('hide');
|
||||
inputs[key].prop('disabled', true);
|
||||
});
|
||||
input_div[name].collapse('show');
|
||||
inputs[name].prop('disabled', false);
|
||||
inputs[name].prop('required', true);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue