Trying out JSFrame for windows

Winbox has this annoying bug where you can't move the window below the
calculated area of the document, so you can't drag it over blank space.
JSFrame fixes this and does basically what we want as well. This has
been implemented for post replies and I am going to implement it for
reports and ban creation too.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2022-06-25 20:42:10 -07:00
parent 8ab760d456
commit e596d59e82
9 changed files with 181 additions and 2 deletions

8
board/static/board/jsframe.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -16,11 +16,24 @@ function documentClick(e) {
}
function doQuote(e) {
$(window).trigger("quote", [$(e.target).text()]);
/*
return;
let idText = $("#id_text");
// Try to set ID text
if (!idText.length) {
idText = $("iframe").contents().find("#id_text");
}
// If we couldn't find an ID text, open the appropriate window
if (!idText.length) {
window.dispatchEvent(event);
}
// TODO
let caret = idText[0].selectionStart;
let text = idText.val();
let toAdd = ">>" + e.target.innerText + "\n";
idText.val(text.substring(0, caret) + toAdd + text.substring(caret));
*/
}
function closeMenu(e) {
@@ -78,6 +91,7 @@ $(document).on("click", documentClick);
$(document).on("click", ".post_id", doQuote);
$(window).on("load", () => {
window.reportWindow = null;
window.jsFrame = new JSFrame();
});
window.menuItemFactories = [];

View File

@@ -10,6 +10,7 @@
{% block extrastyle %}{% endblock %}
<script src="{% static 'board/jquery.js' %}"></script>
<script src="{% static 'board/winbox.bundle.js' %}"></script>
<script src="{% static 'board/jsframe.min.js' %}"></script>
<script src="{% static 'board/post.js' %}"></script>
{% if perms.board.create_ban %}
<script src="{% static 'board/ban_window.js' %}"></script>

View File

@@ -22,6 +22,10 @@
<div class="row">
<div class="column">&nbsp;</div>
<div class="column">
<h2>
<a id="create_reply" href="{% url 'board:reply_create' url=board.url id=post.id %}">{% translate "Reply to this thread" %}</a>
</h2>
{% comment %}
<form method="post" action="{% url 'board:post_detail' url=board.url id=post.id %}" enctype="multipart/form-data">
{% csrf_token %}
<table>
@@ -36,6 +40,7 @@
<tr><td>&nbsp;</td><td><input type="submit" value="Submit" /></td></tr>
</table>
</form>
{% endcomment %}
</div>
<div class="column">&nbsp;</div>
</div>
@@ -51,4 +56,62 @@
</div>
{% endfor %}
</div>
<script>
const REPLY_URL = "{% url 'board:reply_create' url=board.url id=post.id %}";
const replyWindowName = "reply-window";
function openReplyWindow() {
if(window.jsFrame.containsWindowName(replyWindowName)) {
// if there's already a new reply window, don't override it and just let
// it continue to exist.
return;
}
window.top.replyWindow = window.jsFrame.create({
title: "New Reply",
name: replyWindowName,
width: 385,
height: 350,
x: "center",
y: "center",
url: REPLY_URL,
});
window.top.replyWindow.show();
window.top.replyWindow.on("hid", (frame, info) => console.log("hidden"));
}
function replyTextbox() {
return $("iframe").contents().find("#id_text");
}
function replyAppend(toAdd) {
let textbox = replyTextbox();
if(textbox.length === 0) {
return;
}
let caret = textbox[0].selectionStart;
let text = textbox.val();
textbox.val(text.substring(0, caret) + toAdd + text.substring(caret));
textbox.focus();
}
$("#create_reply").on("click", (e) => {
e.preventDefault();
openReplyWindow();
});
$(window).on("load", () => { window.top.replyWindow = null; });
$(window).on("quote", (e, postId) => {
openReplyWindow();
let toAdd = ">>" + postId + "\n";
let textbox = replyTextbox();
if (typeof textbox === "undefined" || textbox.length === 0) {
$("iframe").on("load", () => {
replyAppend(toAdd);
});
} else {
replyAppend(toAdd);
}
});
</script>
{% endblock content %}

View File

@@ -0,0 +1,29 @@
{% extends "board/base.html" %}
{% load i18n %}
{% block content %}
{% blocktranslate %}
Post created. Closing window in {{window_timeout}} second(s).
{% endblocktranslate %}
<script>
function isIframe() {
try {
return window.self !== window.top;
} catch (_) {
return true;
}
}
setTimeout(function() {
if(isIframe()) {
// check for possible windows
if(typeof window.top.replyWindow !== "undefined" && window.top.replyWindow) {
window.top.replyWindow.closeFrame();
}
} else {
window.close();
}
}, 1000 * {{window_timeout}});
</script>
{% endblock content %}

View File

@@ -0,0 +1,19 @@
{% extends "board/base.html" %}
{% load i18n post_body %}
{% block content %}
<form method="post" action="{% url 'board:reply_create' url=board.url id=post.id %}" enctype="multipart/form-data">
{% csrf_token %}
<table>
{{ form.as_table }}
<tr>
<th>&nbsp;</th>
<td>
{% translate "Max image size" %}:
{{ max_upload_size|measure_bytes }}
</td>
</tr>
<tr><td>&nbsp;</td><td><input type="submit" value="Submit" /></td></tr>
</table>
</form>
{% endblock content %}

View File

@@ -10,6 +10,8 @@ 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>/reply/<int:id>/", ReplyCreateView.as_view(), name="reply_create"),
path("post/success/", PostSuccessView.as_view(), name="post_success"),
# Reports
path("report/<slug:url>/<int:id>/", ReportView.as_view(), name="report_form"),
path("report/success/", ReportSuccessView.as_view(), name="report_success"),

View File

@@ -19,6 +19,8 @@ __all__ = (
"BannedView",
"BoardView",
"PostView",
"PostSuccessView",
"ReplyCreateView",
"ReportView",
"ReportSuccessView",
)
@@ -105,6 +107,32 @@ class BoardView(CreateView):
return super(BoardView, self).get_context_data(**kwargs)
class ReplyCreateView(CreateView):
model = Post
form_class = ReplyForm
slug_field = "url"
slug_url_kwarg = "url"
template_name = "board/reply_create_view.html"
success_url = reverse_lazy("board:post_success")
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["board"] = self.board
post_id = self.kwargs["id"]
context["post"] = get_object_or_404(Post, id=post_id)
context["max_upload_size"] = settings.MAX_UPLOAD_SIZE
print(context["board"])
return context
def get_form_kwargs(self):
kwargs = super(ReplyCreateView, self).get_form_kwargs()
post_id = self.kwargs["id"]
post = get_object_or_404(Post, id=post_id)
kwargs["op"] = post
kwargs["reply"] = post
return kwargs
class PostView(CreateView):
model = Post
form_class = ReplyForm
@@ -130,6 +158,15 @@ class PostView(CreateView):
return kwargs
class PostSuccessView(TemplateView):
template_name = "board/post_success.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["window_timeout"] = settings.POST_WINDOW_CLOSE_TIMEOUT
return context
class ReportView(CreateView):
model = Report
form_class = ReportForm
@@ -160,7 +197,7 @@ class ReportSuccessView(TemplateView):
return context
class BanCreateView(PermissionRequiredMixin, CreateView):
class BanCreateView(PermissionRequiredMixin, edit.CreateView):
model = Ban
form_class = BanForm
permission_required = "ban.create"
@@ -190,7 +227,7 @@ class BanCreateView(PermissionRequiredMixin, CreateView):
return context
def get_form_kwargs(self) -> Dict[str, Any]:
kwargs = super(CreateView, self).get_form_kwargs()
kwargs = super(edit.CreateView, self).get_form_kwargs()
post_id = self.kwargs["id"]
post = get_object_or_404(Post, id=post_id)
kwargs["op"] = post

View File

@@ -160,3 +160,9 @@ REPORT_WINDOW_CLOSE_TIMEOUT = 5
# By default, wait 0 seconds and close immediately. It is assumed that the ban
# is created successfully, and if an error occurs, the window won't close anyway.
BAN_WINDOW_CLOSE_TIMEOUT = 0
# How many seconds to wait before closing the new post window after a post is
# created.
# By default, wait 0 seconds. If there is an error, the window won't close
# because it will be redirected elsewhere.
POST_WINDOW_CLOSE_TIMEOUT = 0