rDrama/files/templates/submit.html

540 lines
18 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
{% include "bootstrap.html" %}
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
<script src="https://cdn.jsdelivr.net/remarkable/1.7.1/remarkable.min.js"></script>
<script>
$(document).ready(function() {
$('#submitform').submit(function() {
// disable button
$("#create_button").prop("disabled", true);
// add spinner to button
$("#create_button").html('<span class="spinner-border spinner-border-sm mr-2" role="status" aria-hidden="true"></span>Creating post');
});
});
// Text Formatting
// Bold Text
makeBold = function (form) {
var text = document.getElementById(form);
var startIndex = text.selectionStart,
endIndex = text.selectionEnd;
var selectedText = text.value.substring(startIndex, endIndex);
var format = '**'
if (selectedText.includes('**')) {
text.value = selectedText.replace(/\*/g, '');
}
else if (selectedText.length == 0) {
text.value = text.value.substring(0, startIndex) + selectedText + text.value.substring(endIndex);
}
else {
text.value = text.value.substring(0, startIndex) + format + selectedText + format + text.value.substring(endIndex);
}
}
// Italicize Comment Text
makeItalics = function (form) {
var text = document.getElementById(form);
var startIndex = text.selectionStart,
endIndex = text.selectionEnd;
var selectedText = text.value.substring(startIndex, endIndex);
var format = '*'
if (selectedText.includes('*')) {
text.value = selectedText.replace(/\*/g, '');
}
else if (selectedText.length == 0) {
text.value = text.value.substring(0, startIndex) + selectedText + text.value.substring(endIndex);
}
else {
text.value = text.value.substring(0, startIndex) + format + selectedText + format + text.value.substring(endIndex);
}
}
// Quote Comment Text
makeQuote = function (form) {
var text = document.getElementById(form);
var startIndex = text.selectionStart,
endIndex = text.selectionEnd;
var selectedText = text.value.substring(startIndex, endIndex);
var format = '>'
if (selectedText.includes('>')) {
text.value = text.value.substring(0, startIndex) + selectedText.replace(/\>/g, '') + text.value.substring(endIndex);
}
else if (selectedText.length == 0) {
text.value = text.value.substring(0, startIndex) + selectedText + text.value.substring(endIndex);
}
else {
text.value = text.value.substring(0, startIndex) + format + selectedText + text.value.substring(endIndex);
}
}
// Character Count
function charLimit(form, text) {
var input = document.getElementById(form);
var text = document.getElementById(text);
var length = input.value.length;
var maxLength = input.getAttribute("maxlength");
if (length >= maxLength) {
text.style.color = "#E53E3E";
}
else if (length >= maxLength * .72){
text.style.color = "#FFC107";
}
else {
text.style.color = "#A0AEC0";
}
text.innerText = maxLength - length;
}
//part of submit page js
hide_image=function(){
x=document.getElementById('image-upload-block');
url=document.getElementById('post-URL').value;
if (url.length>=1){
x.classList.add('d-none');
}
else {
x.classList.remove('d-none');
}
}
// Auto-suggest title given URL
function autoSuggestTitle() {
var urlField = document.getElementById("post-URL");
var titleField = document.getElementById("post-title");
var isValidURL = urlField.checkValidity();
if (isValidURL && urlField.value.length > 0 && titleField.value === "") {
var x = new XMLHttpRequest();
x.withCredentials=true;
x.onreadystatechange = function() {
if (x.readyState == 4 && x.status == 200) {
title=JSON.parse(x.responseText)["title"];
titleField.value=title;
checkForRequired()
}
}
x.open('get','/submit/title?url=' + urlField.value);
x.send(null);
};
};
// Run AutoSuggestTitle function on load
if (window.location.pathname=='/submit') {
window.onload = autoSuggestTitle();
}
// Paste to create submission
document.addEventListener('paste', function (event) {
var nothingFocused = document.activeElement === document.body;
if (nothingFocused) {
var clipText = event.clipboardData.getData('Text');
var url = new RegExp('^(?:[a-z]+:)?//', 'i');
if (url.test(clipText) && window.location.pathname !== '/submit') {
window.location.href = '/submit?url=' + clipText;
}
else if (url.test(clipText) && window.location.pathname == '/submit') {
document.getElementById("post-URL").value = clipText;
autoSuggestTitle()
}
}
});
// Submit Page Front-end Validation
function checkForRequired() {
// Divs
var title = document.getElementById("post-title");
var url = document.getElementById("post-URL");
var text = document.getElementById("post-text");
var button = document.getElementById("create_button");
var image = document.getElementById("file-upload");
// Toggle reuqired attribute
if (url.value.length > 0 || image.value.length > 0) {
text.required = false;
url.required=false;
} else if (text.value.length > 0 || image.value.length > 0) {
url.required = false;
} else {
text.required = true;
url.required = true;
}
// Validity check
var isValidTitle = title.checkValidity();
var isValidURL = url.checkValidity();
var isValidText = text.checkValidity();
// Disable submit button if invalid inputs
if (isValidTitle && (isValidURL || image.value.length>0)) {
button.disabled = false;
} else if (isValidTitle && isValidText) {
button.disabled = false;
} else {
button.disabled = true;
}
}
</script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" type="image/png" href="/assets/images/{{'SITE_NAME' | app_config}}/icon.gif">
{% include "emoji_modal.html" %}
{% include "gif_modal.html" %}
{% block title %}
<title>Create a post - {{'SITE_NAME' | app_config}}</title>
{% endblock %}
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600&display=swap" rel="stylesheet">
<!-- Bootstrap core CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<!-- {{'SITE_NAME' | app_config}} Board CSS -->
{% block stylesheets %}
{% if v %}
<link rel="stylesheet" href="/assets/style/{{v.theme}}_{{v.themecolor}}.css">
{% if v.agendaposter %}<link rel="stylesheet" href="/assets/style/agendaposter.css">{% elif v.css %}<link rel="stylesheet" href="/@{{v.username}}/css">{% endif %}
{% else %}
<link rel="stylesheet" href="/assets/style/{{'DEFAULT_THEME' | app_config}}.css">
{% endif %}
{% endblock %}
<!-- Font Awesome -->
<link href="/assets/style/fa.css" rel="stylesheet"> <!--load all styles -->
{% if v %}
<script>
function post(url, callback, errortext) {
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
var form = new FormData()
form.append("formkey", "{{v.formkey}}");
xhr.withCredentials=true;
xhr.onload=callback
xhr.onerror=function(){alert(errortext)}
xhr.send(form);
}
function formkey() {
return '{{v.formkey}}';
}
</script>
{% endif %}
</head>
<body id="submit" style="overflow-x: hidden; {% if v and v.background %} background:url(/assets/images/backgrounds/{{v.background}}) no-repeat center center fixed !important; background-size: cover!important; background-color: #000!important;{% endif %}display: block;">
<!-- Navigation -->
{% include "header.html" %}
{% block form %}
<!-- Page Content -->
<div id="submitapp" class="submit-grid-view">
<form id="submitform" action="/submit" method="post" enctype="multipart/form-data" style="grid-column: 2">
<div class="container">
<div class="row justify-content-center mb-5">
<div class="col p-3 py-md-0">
<h1 class="d-none d-md-block mt-3">Create a post</h1>
<h2 class="h3 d-md-none">Create a post</h2>
<div class="body">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<label for="title">Post Title</label>
<input class="form-control" id="post-title" aria-describedby="titleHelpRegister" type="text" name="title" placeholder="Required" value="{{title}}" minlength="1" maxlength="500" required oninput="checkForRequired()">
<label class="btn btn-secondary format d-inline-block m-0" for="emoji-reply-btn-2">
<div id="emoji-reply-btn-2" onclick="loadEmojis('post-title')" aria-hidden="true" data-toggle="modal" data-target="#emojiModal" data-toggle="tooltip" data-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></div>
</label>
<div id="urlblock">
<label for="URL" class="mt-3">URL</label>
<input class="form-control" id="post-URL" aria-describedby="URLHelp" type="url" name="url" placeholder="Optional if you have text." value="{{request.args.get('url','')}}" required oninput="checkForRequired();autoSuggestTitle();hide_image()">
<small class="form-text text-muted">To post an image, use a direct image link such as i.imgur.com</small>
</div>
<div id="image-upload-block">
<div><label class="mt-3">Attachment Upload</label></div>
<img loading="lazy" id="image-preview" class="w-100 d-block">
<label class="btn btn-secondary m-0" for="file-upload">
<div id="filename-show">Select File</div>
<input id="file-upload" type="file" name="file" accept="image/*, video/*" hidden>
</label>
<small class="form-text text-muted">Optional if you have text.</small>
<small class="form-text text-muted">You can upload videos up to 1 minute long if you have at least {{ 'VIDEO_COIN_REQUIREMENT' | app_config }} {{ 'COINS_NAME' | app_config }}{% if v.admin_level > 1 %} or are an admin{% endif %}.</small>
</div>
</div>
<label for="body" class="mt-3">Text<i class="fas fa-info-circle text-gray-400 ml-1" data-toggle="tooltip" data-placement="top" title="Uses markdown. Limited to 10000 characters."></i></label>
<div class="input-group">
<textarea v-model="post_body" form="submitform" id="post-text" class="form-control rounded" aria-label="With textarea" placeholder="Optional if you have a link or an image." rows="3" name="body" oninput="charLimit('post-text','character-count-submit-text-form');checkForRequired()" maxlength="10000" required>{{text}}</textarea>
<span class="position-absolute text-small font-weight-bold" id="character-count-submit-text-form" style="right: 1rem; bottom: 0.5rem; z-index: 3;"></span>
<div class="bg-light text-format d-none">
<small class="format"><i class="fas fa-bold"></i></small>
<small class="format"><i class="fas fa-italic"></i></small>
<small class="format"><i class="fas fa-quote-right"></i></small>
<small class="format"><i class="fas fa-link"></i></small>
</div>
</div>
<p></p>
<small class="btn btn-secondary format d-inline-block m-0">
<i class="fas fa-bold" aria-hidden="true" onclick="makeBold('post-text')" data-toggle="tooltip" data-placement="bottom" title="Bold"></i>
</small>
&nbsp;
<small class="btn btn-secondary format d-inline-block m-0">
<i class="fas fa-italic" aria-hidden="true" onclick="makeItalics('post-text')" data-toggle="tooltip" data-placement="bottom" title="Italicize"></i>
</small>
&nbsp;
<small class="btn btn-secondary format d-inline-block m-0">
<i class="fas fa-quote-right" aria-hidden="true" onclick="makeQuote('post-text')" data-toggle="tooltip" data-placement="bottom" title="Quote"></i>
</small>
&nbsp;
<small class="btn btn-secondary format d-inline-block m-0"><span class="font-weight-bolder text-uppercase" aria-hidden="true" onclick="getGif();commentForm('post-text')" data-toggle="modal" data-target="#gifModal" data-toggle="tooltip" data-placement="bottom" title="Add GIF">GIF</span></small>
&nbsp;
<label class="btn btn-secondary format d-inline-block m-0" for="emoji-reply-btn">
<div id="emoji-reply-btn" onclick="loadEmojis('post-text')" aria-hidden="true" data-toggle="modal" data-target="#emojiModal" data-toggle="tooltip" data-placement="bottom" title="Add Emoji"><i class="fas fa-smile-beam"></i></div>
</label>
<div class="btn btn-secondary" @click="togglePreview()" style="float: right;">
[[ show_preview ? 'Hide preview' : 'Show preview' ]]
</div>
<pre></pre>
<div class="form-text text-small"><a href="/formatting" target="_blank">Formatting help</a></div>
<pre></pre>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="nsfwCheck" name="over_18">
<label class="custom-control-label" for="nsfwCheck">+18</label>
</div>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="privateCheck" name="private">
<label class="custom-control-label" for="privateCheck">Draft</label>
</div>
<pre>
</pre>
</div>
</div>
</div>
<div class="container">
<div class="row fixed-bottom bg-white border-top p-3" id="" style="z-index: 100; bottom: 0px; transition: bottom 220ms cubic-bezier(0, 0, 0.2, 1) 0s;">
<div class="col">
<a href="/" class="btn btn-secondary">Cancel</a>
</div>
<div class="col text-right">
{% if error %}<span class="text-danger mr-2">{{error}}</span>{% endif %}
<button class="btn btn-outline-purple" id="create_button" type="submit" disabled>Post</button>
</div>
</div>
</div>
</form>
<div v-show="show_preview" class="card-blank" id="submit-page" style="height:max-content; min-height: 25rem; transition: 15s;">
<h1 class="m-3">Markdown Preview</h1>
<hr>
<div class="m-3">
<div id="post-body-markdown" v-html="post_body_markdown" style="max-height: 500px; overflow-y: scroll;"></div>
</div>
</div>
</div>
{% endblock %}
<style>
@media(min-width: 768px){
.submit-grid-view{
display: grid;
grid-template-columns: 1fr 3fr 3fr 1fr;
grid-column-gap: 1rem;
}
}
#post-body-markdown img{
max-height: 100px !important;
max-width: 100px !important;
border-radius: 0.35rem;
margin: 0.5rem 0;
}
</style>
<script>
var md = new Remarkable();
new Vue({
el: "#submitapp",
delimiters: ['[[', ']]'],
data: {
post_body: "",
post_tag: "",
show_preview: false,
},
computed: {
post_body_markdown: function(){
markdown = md.render(this.post_body)
emojis = Array.from(markdown.matchAll(/:(.{1,30}?):/gi))
if(emojis != null){
for(i = 0; i < emojis.length; i++){
markdown = markdown.replace(emojis[i][0], "<img height=30 src='/assets/images/emojis/" + emojis[i][1] + ".gif'>")
}
}
return markdown
}
},
methods: {
togglePreview() {
this.show_preview = !this.show_preview
}
}
})
</script>
<!-- {{'SITE_NAME' | app_config}} JS -->
<script src="/assets/js/general14.js"></script>
<!-- ClipboardJS -->
<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<!-- Instantiate clipboard by passing a string selector -->
<script>
var clipboard = new ClipboardJS('.copy-link');
clipboard.on('success', function(e) {
jQuery(function($) {
$('#toast-success').toast('show');
})
console.log(e);
});
clipboard.on('error', function(e) {
jQuery(function($) {
$('#toast-error').toast('show');
})
console.log(e);
});
document.onpaste = function(event) {
f=document.getElementById('file-upload');
files = event.clipboardData.files
filename = files[0].name.toLowerCase()
if (filename.endsWith(".jpg") || filename.endsWith(".jpeg") || filename.endsWith(".png") || filename.endsWith(".gif"))
{
f.files = files;
$('#filename-show').text(filename);
$('#urlblock').addClass('d-none');
var fileReader = new FileReader();
fileReader.readAsDataURL(f.files[0]);
fileReader.addEventListener("load", function () {$('#image-preview').attr('src', this.result);});
$('#file-upload').attr('required', false);
checkForRequired();
}
}
$('#file-upload').on('change', function(e){
f=document.getElementById('file-upload');
$('#urlblock').addClass('d-none');
$('#filename-show').text($('#file-upload')[0].files[0].name);
var fileReader = new FileReader();
fileReader.readAsDataURL(f.files[0]);
fileReader.addEventListener("load", function () {$('#image-preview').attr('src', this.result);});
checkForRequired();
})
</script>
</body>
</html>