Add floating window for new threads
New threads get a floating window just like new replies have. This only pops up on the board detail view. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -22,8 +22,9 @@ class PostForm(ModelForm):
|
||||
model = Post
|
||||
fields = ["subject", "name", "text", "image"]
|
||||
|
||||
def __init__(self, *args, board, ip, **kwargs):
|
||||
def __init__(self, *args, user, board, ip, **kwargs):
|
||||
super(PostForm, self).__init__(*args, **kwargs)
|
||||
self.user = user
|
||||
self.instance.board = board
|
||||
self.instance.ip = ip
|
||||
|
||||
@@ -42,10 +43,9 @@ class ReplyForm(PostForm):
|
||||
model = Post
|
||||
fields = ["name", "text", "bump", "capcode", "image"]
|
||||
|
||||
def __init__(self, *args, user, op, **kwargs):
|
||||
def __init__(self, *args, op, **kwargs):
|
||||
super(ReplyForm, self).__init__(*args, **kwargs)
|
||||
self.instance.op = op
|
||||
self.user = user
|
||||
|
||||
def clean(self):
|
||||
super().clean()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const OPEN = "open";
|
||||
const CLOSED = "closed";
|
||||
const replyWindowName = "reply-window";
|
||||
const postWindowName = "post-window";
|
||||
|
||||
function documentClick(e) {
|
||||
let sender = e.target;
|
||||
@@ -59,7 +60,7 @@ function openReplyWindow(replyUrl) {
|
||||
if (window.top.jsFrame.containsWindowName(replyWindowName)) {
|
||||
// if there's already a new reply window, don't override it and just let
|
||||
// it continue to exist.
|
||||
return;
|
||||
return getReplyWindow();
|
||||
}
|
||||
|
||||
let replyWindow = window.top.jsFrame.create({
|
||||
@@ -70,6 +71,7 @@ function openReplyWindow(replyUrl) {
|
||||
url: replyUrl
|
||||
});
|
||||
replyWindow.show();
|
||||
return replyWindow;
|
||||
}
|
||||
|
||||
function getReplyWindow() {
|
||||
@@ -77,18 +79,49 @@ function getReplyWindow() {
|
||||
}
|
||||
|
||||
function replyTextbox() {
|
||||
return $("iframe").contents().find("#id_text");
|
||||
replyWindow = getReplyWindow();
|
||||
if (!replyWindow) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return replyWindow.$("#id_text")
|
||||
}
|
||||
|
||||
function replyAppend(toAdd) {
|
||||
let replyWindow = getReplyWindow();
|
||||
let textbox = replyTextbox();
|
||||
if (textbox.length === 0) {
|
||||
if (!textbox) {
|
||||
$(replyWindow.iframe, "#id_text").on("load", (e) => {
|
||||
replyAppend(toAdd);
|
||||
})
|
||||
} else {
|
||||
let caret = textbox.selectionStart;
|
||||
textbox = $(textbox);
|
||||
let text = textbox.val();
|
||||
textbox.val(text.substring(0, caret) + toAdd + text.substring(caret));
|
||||
textbox.focus();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Reply window
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
function openPostWindow(postUrl) {
|
||||
if (window.top.jsFrame.containsWindowName(postWindowName)) {
|
||||
return;
|
||||
}
|
||||
let caret = textbox[0].selectionStart;
|
||||
let text = textbox.val();
|
||||
textbox.val(text.substring(0, caret) + toAdd + text.substring(caret));
|
||||
textbox.focus();
|
||||
let postWindow = window.top.jsFrame.create({
|
||||
title: "New Thread",
|
||||
name: postWindowName,
|
||||
width: 385,
|
||||
height: 350,
|
||||
url: postUrl,
|
||||
});
|
||||
postWindow.show();
|
||||
}
|
||||
|
||||
function getPostWindow() {
|
||||
return window.top.jsFrame.getWindowByName(postWindowName);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -23,23 +23,9 @@
|
||||
<div class="column"> </div>
|
||||
<div class="column">
|
||||
<div class="row">
|
||||
<h2>{% translate "Create a new thread" %}</h2>
|
||||
</div>
|
||||
<div class="row">
|
||||
<form method="post" action="{% url 'board:board_detail' url=board.url %}" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
<tr>
|
||||
<th> </th>
|
||||
<td>
|
||||
{% translate "Max image size" %}:
|
||||
{{ max_upload_size|measure_bytes }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr><th> </th><td><input type="submit" value="Submit" /></td></tr>
|
||||
</table>
|
||||
</form>
|
||||
<h2>
|
||||
<a id="create_post" href="{% url 'board:post_create' url=board.url %}">{% translate "Create a new thread" %}</a>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column"> </div>
|
||||
@@ -85,4 +71,12 @@
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const POST_URL = "{% url 'board:post_create' url=board.url %}";
|
||||
$("#create_post").on("click", (e) => {
|
||||
e.preventDefault();
|
||||
openPostWindow(POST_URL);
|
||||
});
|
||||
</script>
|
||||
{% endblock content %}
|
||||
34
board/templates/board/post_create_view.html
Normal file
34
board/templates/board/post_create_view.html
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends "board/base.html" %}
|
||||
{% load i18n post_body %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post" action="{% url 'board:post_create' url=board.url %}" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<table>
|
||||
{% for field in form %}
|
||||
{% if field.name != "capcode" %}
|
||||
<tr>
|
||||
<th>{{field.label_tag}}</th>
|
||||
<td>{{field}}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if capcodes %}
|
||||
<tr>
|
||||
<th>{{form.capcode.label_tag}}</th>
|
||||
<td>
|
||||
{{form.capcode}}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<th> </th>
|
||||
<td>
|
||||
{% translate "Max image size" %}:
|
||||
{{ max_upload_size|measure_bytes }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr><td> </td><td><input type="submit" value="Submit" /></td></tr>
|
||||
</table>
|
||||
</form>
|
||||
{% endblock content %}
|
||||
@@ -54,14 +54,7 @@ $("#create_reply").on("click", (e) => {
|
||||
$(window).on("quote", (e, postId) => {
|
||||
openReplyWindow(REPLY_URL);
|
||||
let toAdd = ">>" + postId + "\n";
|
||||
let textbox = replyTextbox();
|
||||
if (typeof textbox === "undefined" || textbox.length === 0) {
|
||||
$("iframe").on("load", () => {
|
||||
replyAppend(toAdd);
|
||||
});
|
||||
} else {
|
||||
replyAppend(toAdd);
|
||||
}
|
||||
replyAppend(toAdd);
|
||||
});
|
||||
</script>
|
||||
{% endblock content %}
|
||||
@@ -15,16 +15,22 @@ function isIframe() {
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
if(isIframe()) {
|
||||
// check for possible windows
|
||||
let replyWindow = getReplyWindow();
|
||||
if(replyWindow) {
|
||||
replyWindow.closeFrame();
|
||||
$(window).on("load", () => {
|
||||
setTimeout(function() {
|
||||
let params = new URLSearchParams(window.location.search);
|
||||
let next = params.get("next");
|
||||
let target = isIframe()
|
||||
? window.top
|
||||
: window;
|
||||
if(next) {
|
||||
target.location = next;
|
||||
if(next.includes("#")) {
|
||||
target.location.reload();
|
||||
}
|
||||
} else {
|
||||
target.close();
|
||||
}
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
}, 1000 * {{window_timeout}});
|
||||
}, 1000 * {{window_timeout}});
|
||||
});
|
||||
</script>
|
||||
{% endblock content %}
|
||||
@@ -10,6 +10,7 @@ urlpatterns = [
|
||||
path("<slug:url>/", BoardView.as_view(), name="board_detail"),
|
||||
path("<slug:url>/page/<int:page>/", BoardView.as_view(), name="board_detail"),
|
||||
path("<slug:url>/post/<int:id>/", PostView.as_view(), name="post_detail"),
|
||||
path("<slug:url>/post/create/", PostCreateView.as_view(), name="post_create"),
|
||||
path("<slug:url>/reply/<int:id>/", ReplyCreateView.as_view(), name="reply_create"),
|
||||
path("post/success/", PostSuccessView.as_view(), name="post_success"),
|
||||
# Reports
|
||||
|
||||
@@ -2,9 +2,9 @@ from typing import Any, Dict
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model, get_user
|
||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.db.models import Q
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.http.request import QueryDict
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.views.generic.base import TemplateView
|
||||
from django.views.generic import edit
|
||||
@@ -22,6 +22,7 @@ __all__ = (
|
||||
"BanSuccessView",
|
||||
"BannedView",
|
||||
"BoardView",
|
||||
"PostCreateView",
|
||||
"PostView",
|
||||
"PostSuccessView",
|
||||
"ReplyCreateView",
|
||||
@@ -77,9 +78,8 @@ class CreateView(edit.CreateView):
|
||||
return super(CreateView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class BoardView(CreateView):
|
||||
model = Post
|
||||
form_class = PostForm
|
||||
class BoardView(TemplateView):
|
||||
model = Board
|
||||
slug_field = "url"
|
||||
slug_url_kwarg = "url"
|
||||
template_name = "board/board_detail.html"
|
||||
@@ -92,6 +92,10 @@ class BoardView(CreateView):
|
||||
)
|
||||
return super(BoardView, self).get(request, *args, **kwargs)
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.board = get_object_or_404(Board, url=kwargs["url"])
|
||||
return super(BoardView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
page = self.kwargs["page"]
|
||||
|
||||
@@ -114,6 +118,33 @@ class BoardView(CreateView):
|
||||
return super(BoardView, self).get_context_data(**kwargs)
|
||||
|
||||
|
||||
class PostCreateView(CreateView):
|
||||
model = Post
|
||||
form_class = PostForm
|
||||
slug_field = "url"
|
||||
slug_url_kwarg = "url"
|
||||
template_name = "board/post_create_view.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["board"] = self.board
|
||||
context["max_upload_size"] = settings.MAX_UPLOAD_SIZE
|
||||
context["capcodes"] = get_objects_for_user(
|
||||
get_user(self.request), "board.use_capcode"
|
||||
)
|
||||
return context
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(PostCreateView, self).get_form_kwargs()
|
||||
kwargs["user"] = self.request.user
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
query = QueryDict(mutable=True)
|
||||
query["next"] = self.get_form().instance.get_absolute_url()
|
||||
return reverse("board:post_success") + "?" + query.urlencode()
|
||||
|
||||
|
||||
class ReplyCreateView(CreateView):
|
||||
model = Post
|
||||
form_class = ReplyForm
|
||||
@@ -141,10 +172,14 @@ class ReplyCreateView(CreateView):
|
||||
kwargs["user"] = self.request.user
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
query = QueryDict(mutable=True)
|
||||
query["next"] = self.get_form().instance.get_absolute_url()
|
||||
return reverse("board:post_success") + "?" + query.urlencode()
|
||||
|
||||
class PostView(CreateView):
|
||||
|
||||
class PostView(TemplateView):
|
||||
model = Post
|
||||
form_class = ReplyForm
|
||||
slug_field = "url"
|
||||
slug_url_kwarg = "url"
|
||||
|
||||
@@ -158,13 +193,10 @@ class PostView(CreateView):
|
||||
|
||||
return super(PostView, self).get_context_data(**kwargs)
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(PostView, self).get_form_kwargs()
|
||||
post_id = self.kwargs["id"]
|
||||
post = get_object_or_404(Post, id=post_id)
|
||||
kwargs["op"] = post
|
||||
kwargs["user"] = self.request.user
|
||||
return kwargs
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
# Set the board on this object
|
||||
self.board = get_object_or_404(Board, url=kwargs["url"])
|
||||
return super(PostView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class PostSuccessView(TemplateView):
|
||||
|
||||
Reference in New Issue
Block a user