website/web/templates/forum/new_post.html
Noah 47f898561c Forum Photo Attachments
* Add support to upload a picture to forum posts and replies, in forums that
  have the PermitPhotos setting enabled.
* New DB table: CommentPhoto holds the association between a photo and a
  forum ID. Photos can be uploaded at preview time (before a CommentID is
  available) and get associated to the CommentID on save.
* Cron endpoint /v1/comment-photos/remove-orphaned can clean up orphaned
  photos without a CommentID older than 24 hours.
* Add "Photo Boards" as a default forum category for new boards.
2022-10-20 21:02:30 -07:00

280 lines
13 KiB
HTML

{{define "title"}}
{{if .EditCommentID}}
Edit Comment
{{else if .Thread}}
Reply to Thread
{{else}}
New Forum Post
{{end}}
{{end}}
{{define "content"}}
<div class="container">
<section class="hero is-info is-bold">
<div class="hero-body">
<div class="container">
<h1 class="title">
{{if .EditCommentID}}
Edit comment on: {{or .Thread.Title "Untitled Thread"}}
{{else if .Thread}}
Reply to: {{or .Thread.Title "Untitled Thread"}}
{{else}}
Post to: {{.Forum.Title}}
{{end}}
</h1>
<h2 class="subtitle">
/f/{{.Forum.Fragment}}
</h2>
</div>
</div>
</section>
<div class="block p-4">
<div class="columns is-centered">
<div class="column is-half">
<div class="card" style="width: 100%; max-width: 640px">
<header class="card-header has-background-link">
<p class="card-header-title has-text-light">
<span class="icon"><i class="fa fa-message"></i></span>
{{if .EditCommentID}}
Edit Comment
{{else if .Thread}}
Reply to Thread
{{else}}
New Thread
{{end}}
</p>
</header>
<div class="card-content">
{{if and (eq .Request.Method "POST") (ne .Message "")}}
<label class="label">Preview:</label>
<div class="box content has-background-warning-light">
{{ToMarkdown .Message}}
</div>
{{end}}
<form action="/forum/post?to={{.Forum.Fragment}}{{if .Thread}}&thread={{.Thread.ID}}{{end}}{{if .EditCommentID}}&edit={{.EditCommentID}}{{end}}" method="POST" enctype="multipart/form-data">
{{InputCSRF}}
{{if not .Thread}}
<div class="field block">
<label for="title" class="label">Title</label>
<input type="text" class="input"
name="title" id="title"
placeholder="A title for your post"
value="{{.PostTitle}}"
required>
<p class="help">Required.</p>
</div>
{{end}}
<div class="field block">
<label for="message" class="label">Message</label>
<textarea class="textarea" cols="80" rows="8"
name="message"
id="message"
{{if not .Forum.PermitPhotos}}required{{end}}
placeholder="Message">{{.Message}}</textarea>
<p class="help">
Markdown formatting supported.
</p>
</div>
<!-- Photo attachment widget -->
{{if .Forum.PermitPhotos}}
<!-- Intent: upload, remove, or replace -->
<input type="hidden" name="photo_intent" id="photoIntent">
<input type="hidden" name="photo_id" value="{{if .CommentPhoto}}{{.CommentPhoto.ID}}{{end}}">
<!-- Drag/Drop Modal -->
<div class="modal" id="drop-modal">
<div class="modal-background"></div>
<div class="modal-content">
<div class="box content has-text-centered">
<h1><i class="fa fa-upload mr-2"></i> Drop image to select it for upload</h1>
</div>
</div>
</div>
<div class="field block">
<label class="label">Photo Attachment</label>
<div class="file has-name is-fullwidth">
<label class="file-label">
<input class="file-input" type="file"
name="file"
id="file"
accept=".jpg,.jpeg,.jpe,.png">
<span class="file-cta">
<span class="file-icon">
<i class="fas fa-upload"></i>
</span>
<span class="file-label">
Choose a file…
</span>
</span>
<span class="file-name" id="fileName">
Select a file
</span>
</label>
</div>
</div>
<div class="box" id="imagePreview" {{if not .CommentPhoto}}style="display: none"{{end}}>
<h3 class="subtitle">
Selected image:
<button type="button" class="button is-danger is-small ml-4" id="removePhoto">
<i class="fa fa-trash"></i>
</button>
</h3>
<!-- Container of img tags for the selected photo preview. -->
<img id="previewImage"{{if .CommentPhoto}} src="{{PhotoURL .CommentPhoto.Filename}}"{{end}}>
</div>
{{end}}
{{if or (not .Thread) .EditThreadSettings}}
<div class="field block">
{{if or .CurrentUser.IsAdmin (and .Forum (eq .Forum.OwnerID .CurrentUser.ID))}}
<div class="mb-1">
<label class="checkbox">
<input type="checkbox"
name="pinned"
value="true"
{{if .IsPinned}}checked{{end}}>
Pinned to top
</label>
</div>
{{end}}
{{if or .CurrentUser.Explicit .IsExplicit}}
<div class="mb-1">
<label class="checkbox">
<input type="checkbox"
name="explicit"
value="true"
{{if .IsExplicit}}checked{{end}}>
Mark as Explicit (NSFW)
</label>
</div>
{{end}}
{{if .CurrentUser.IsAdmin}}
<div>
<label class="checkbox has-text-danger">
<input type="checkbox"
name="noreply"
value="true"
{{if .IsNoReply}}checked{{end}}>
No replies allowed <i class="fa fa-gavel ml-1"></i>
</label>
</div>
{{end}}
</div>
{{end}}
<div class="field has-text-centered">
<button type="submit"
name="intent"
value="preview"
class="button is-link">
Preview
</button>
<button type="submit"
name="intent"
value="submit"
class="button is-success">
Post Message
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- Script for photo upload on photo boards -->
{{if .Forum.PermitPhotos}}
<script type="text/javascript">
window.addEventListener("DOMContentLoaded", (event) => {
let $file = document.querySelector("#file"),
$fileName = document.querySelector("#fileName"),
$hiddenPreview = document.querySelector("#imagePreview"),
$previewImage = document.querySelector("#previewImage"),
$dropArea = document.querySelector("#drop-modal"),
$removePhoto = document.querySelector("#removePhoto"),
$photoIntent = document.querySelector("#photoIntent"),
$body = document.querySelector("body");
// Common handler for file selection (file input or drag/drop)
let onFile = (file) => {
$photoIntent.value = "{{if .CommentPhoto}}replace{{else}}upload{{end}}";
$fileName.innerHTML = file.name;
// Read the image to show the preview on-page.
const reader = new FileReader();
reader.addEventListener("load", () => {
const uploadedImg = reader.result;
$hiddenPreview.style.display = "block";
$previewImage.src = uploadedImg;
$previewImage.style.display = "block";
$previewImage.style.maxWidth = "100%";
$previewImage.style.height = "auto";
});
reader.readAsDataURL(file);
};
// Set up drag/drop file upload events.
$body.addEventListener("dragenter", function(e) {
e.preventDefault();
e.stopPropagation();
$dropArea.classList.add("is-active");
});
$body.addEventListener("dragover", function(e) {
e.preventDefault();
e.stopPropagation();
$dropArea.classList.add("is-active");
});
$body.addEventListener("dragleave", function(e) {
e.preventDefault();
e.stopPropagation();
$dropArea.classList.remove("is-active");
});
$body.addEventListener("drop", function(e) {
e.preventDefault();
e.stopPropagation();
$dropArea.classList.remove("is-active");
// Grab the file.
let dt = e.dataTransfer;
let file = dt.files[0];
// Set the file on the input field too.
$file.files = dt.files;
onFile(file);
});
// File input handler.
$file.addEventListener("change", function() {
let file = this.files[0];
onFile(file);
});
// Removal button.
$removePhoto.addEventListener("click", function() {
$photoIntent.value = "remove";
$fileName.innerHTML = "Select a file";
$file.value = '';
$hiddenPreview.style.display = 'none';
});
});
</script>
{{end}}
</div>
{{end}}