summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.vscode/launch.json26
-rw-r--r--.vscode/simple-comments.code-workspace39
-rw-r--r--src/controllers/replies_controller.py6
-rw-r--r--src/lib/blacklist_matcher.py3
-rw-r--r--static/js/controllers/base_controller.js66
-rw-r--r--static/js/controllers/comments_controller.js72
-rw-r--r--static/js/controllers/replies_controller.js84
-rw-r--r--templates/replies/form.jinja16
-rw-r--r--templates/replies/index.jinja4
9 files changed, 199 insertions, 117 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..90ecc77
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,26 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+
+ {
+ "name": "Python Debugger: Flask",
+ "type": "debugpy",
+ "request": "launch",
+ "module": "flask",
+ "env": {
+ "FLASK_APP": "main.py",
+ "FLASK_DEBUG": "1"
+ },
+ "args": [
+ "run",
+ "--debug",
+ "--no-debugger",
+ "--no-reload"
+ ],
+ "jinja": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/.vscode/simple-comments.code-workspace b/.vscode/simple-comments.code-workspace
new file mode 100644
index 0000000..db16e41
--- /dev/null
+++ b/.vscode/simple-comments.code-workspace
@@ -0,0 +1,39 @@
+{
+ "folders": [
+ {
+ "path": ".."
+ },
+ {
+ "path": "../../../../Jekyll Pages/russian-lessons"
+ }
+ ],
+ "settings": {},
+ "launch": {
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "firefox",
+ "request": "launch",
+ "reAttach": true,
+ "name": "Launch localhost",
+ "url": "http://127.0.0.1:4000",
+ "webRoot": "${workspaceFolder:russian-lessons}/_site",
+ "pathMappings": [
+ { "url": "http://127.0.0.1:5000/static/js", "path": "${workspaceFolder:simple-comments}/static/js" }
+ ]
+ },
+ {
+ "name": "Attach",
+ "type": "firefox",
+ "request": "attach"
+ },
+ {
+ "name": "Launch WebExtension",
+ "type": "firefox",
+ "request": "launch",
+ "reAttach": true,
+ "addonPath": "${workspaceFolder:russian-lessons}/_site"
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/src/controllers/replies_controller.py b/src/controllers/replies_controller.py
index bd47a44..6713e26 100644
--- a/src/controllers/replies_controller.py
+++ b/src/controllers/replies_controller.py
@@ -12,7 +12,9 @@ comments_query = CommentsQuery()
@replies_blueprint.get('/api/comments/<int:comment_id>/replies')
def index(comment_id):
- return render_template('replies/index.jinja', page=comments_query.replies_of(comment_id))
+ comment = db.get_or_404(Comment, comment_id)
+
+ return render_template('replies/index.jinja', page=comments_query.replies_of(comment.id), comment=comment)
@replies_blueprint.get('/api/replies/new')
@@ -28,4 +30,4 @@ def create(comment_id):
if status_code != 200:
abort(status_code)
- return render_template('comments/index.jinja')
+ return render_template('comments/index.jinja', page=comments_query.replies_of(comment_id))
diff --git a/src/lib/blacklist_matcher.py b/src/lib/blacklist_matcher.py
index 0f28953..4618792 100644
--- a/src/lib/blacklist_matcher.py
+++ b/src/lib/blacklist_matcher.py
@@ -6,6 +6,9 @@ from config import user_config
def contains_forbidden_term(comment):
matcher = build_matcher()
+ if comment is None:
+ return False
+
return matcher.search(comment) is not None
diff --git a/static/js/controllers/base_controller.js b/static/js/controllers/base_controller.js
index fc05e29..6caa9dd 100644
--- a/static/js/controllers/base_controller.js
+++ b/static/js/controllers/base_controller.js
@@ -1,46 +1,46 @@
export class BaseController {
- constructor() {
- this.comments_server_url = document.getElementById('comments-client').src;
- this.origin = window.location.origin;
- this.protocol = this.getProtocol();
- this.domain = this.getDomain();
- this.post = window.location.pathname;
- this.comments_server_host = `${this.protocol}//${this.domain}`;
- this.parser = new DOMParser();
- }
-
- async submit(event, route) {
- event.preventDefault();
- const form = new FormData(event.target);
-
- try {
+ constructor() {
+ this.comments_server_url = document.getElementById('comments-client').src;
+ this.origin = window.location.origin;
+ this.protocol = this.getProtocol();
+ this.domain = this.getDomain();
+ this.post = window.location.pathname;
+ this.comments_server_host = `${this.protocol}//${this.domain}`;
+ this.parser = new DOMParser();
+ }
+
+ async submit(event, route) {
+ event.preventDefault();
+ const form = new FormData(event.target);
+
+ try {
const response = await fetch(route, { method: "POST", body: form });
response.text().then((response_document) => {
- this.renderSubmitResponse(response_document);
+ this.renderSubmitResponse(response_document);
});
- } catch(error) {}
- }
+ } catch(error) {}
+ }
- getDomain() {
- return this.comments_server_url.split('/')[2];
- }
+ getDomain() {
+ return this.comments_server_url.split('/')[2];
+ }
- getProtocol() {
- return this.comments_server_url.split('/')[0];
- }
+ getProtocol() {
+ return this.comments_server_url.split('/')[0];
+ }
- htmlFromResponse(body) {
- return this.parser.parseFromString(body, "text/html");
- }
+ htmlFromResponse(body) {
+ return this.parser.parseFromString(body, "text/html");
+ }
- async get(route) {
- try {
+ async get(route) {
+ try {
const response = await fetch(`${this.comments_server_host}${route}`);
return response.text().then(this.htmlFromResponse.bind(this));
- } catch(error) {
- return null;
- }
- }
+ } catch(error) {
+ return null;
+ }
+ }
}
diff --git a/static/js/controllers/comments_controller.js b/static/js/controllers/comments_controller.js
index 8989c5a..a21bd05 100644
--- a/static/js/controllers/comments_controller.js
+++ b/static/js/controllers/comments_controller.js
@@ -1,45 +1,45 @@
import { BaseController } from "./base_controller.js";
export class CommentsController extends BaseController {
- constructor(replies_controller) {
- super();
- this.replies_controller = replies_controller;
- this.comments_node = document.getElementById("comments-thread");
- this.renderForm();
- this.renderComments();
- }
-
- renderForm() {
- this.get("/api/comments/new").then((value) => {
+ constructor(replies_controller) {
+ super();
+ this.replies_controller = replies_controller;
+ this.comments_node = document.getElementById("comments-thread");
+ this.renderForm();
+ this.renderComments();
+ }
+
+ renderForm() {
+ this.get("/api/comments/new").then((value) => {
const form = value?.getElementById("comment-form");
if(form != null) {
- this.comments_node.appendChild(form);
- this.form_element = document.getElementById("comment-form");
- this.form_element.addEventListener("submit", this.submit.bind(this));
+ this.comments_node.appendChild(form);
+ this.form_element = document.getElementById("comment-form");
+ this.form_element.addEventListener("submit", this.submit.bind(this));
}
- });
- }
-
- renderComments() {
- this.get(`/api/comments?path=${this.post}`).then((value) => {
- const comments = value?.getElementById("comment-section");
-
- if(comments != null) {
- this.comments_node.appendChild(comments);
- this.replies_controller.init();
- }
- });
- }
-
- renderSubmitResponse(response_document) {
- const new_comments = this.htmlFromResponse(response_document).getElementById("comment-section");
- const comments = document.getElementById("comment-section");
- comments.replaceWith(new_comments);
- }
-
- async submit(event) {
- super.submit(event, `${this.comments_server_host}/api/comments?path=${this.post}`);
- }
+ });
+ }
+
+ renderComments() {
+ this.get(`/api/comments?path=${this.post}`).then((value) => {
+ const comments = value?.getElementById("comment-section");
+
+ if(comments != null) {
+ this.comments_node.appendChild(comments);
+ this.replies_controller.init();
+ }
+ });
+ }
+
+ renderSubmitResponse(response_document) {
+ const new_comments = this.htmlFromResponse(response_document).getElementById("comment-section");
+ const comments = document.getElementById("comment-section");
+ comments.replaceWith(new_comments);
+ }
+
+ async submit(event) {
+ super.submit(event, `${this.comments_server_host}/api/comments?path=${this.post}`);
+ }
}
diff --git a/static/js/controllers/replies_controller.js b/static/js/controllers/replies_controller.js
index 5d638a5..5f767be 100644
--- a/static/js/controllers/replies_controller.js
+++ b/static/js/controllers/replies_controller.js
@@ -1,58 +1,70 @@
import { BaseController } from "./base_controller.js";
export class RepliesController extends BaseController {
- constructor() {
- super();
- }
+ constructor() {
+ super();
+ }
- async init() {
- this.comment_id = 0;
- this.reply_form = await this.getReplyForm();
- this.listenButtons("replies-button", this.showReplies.bind(this));
- this.listenButtons("new-reply-button", this.showReplyForm.bind(this));
- }
+ async init() {
+ this.comment_id = 0;
+ this.reply_form = await this.getReplyForm();
+ this.listenButtons("replies-button", this.renderReplies.bind(this));
+ this.listenButtons("new-reply-button", this.showReplyForm.bind(this));
+ }
- async submit(event) {
- await super.submit(event, `${this.comments_server_host}/api/comments/${this.comment_id}/replies`);
- }
+ async submit(event) {
+ await super.submit(event, `${this.comments_server_host}/api/comments/${this.comment_id}/replies`);
+ }
- listenButtons(class_name, func) {
- const buttons = document.getElementsByClassName(class_name);
+ listenButtons(class_name, func) {
+ const buttons = document.getElementsByClassName(class_name);
- if(buttons) {
+ if(buttons) {
for(let button of buttons)
- button.addEventListener("click", func);
- }
- }
+ button.addEventListener("click", func);
+ }
+ }
- showReplyForm(event) {
- const replies_section = event.target.parentElement.parentElement.childNodes[3];
- const form = replies_section.querySelector(".reply-form");
+ showReplyForm(event) {
+ const replies_section = event.target.parentElement.parentElement.childNodes[3];
+ const form = replies_section.querySelector(".reply-form");
- if(form == null) {
+ if(form == null) {
replies_section.appendChild(this.reply_form);
this.setCommentId(replies_section);
this.reply_form.addEventListener("submit", this.submit.bind(this));
- } else
- form.remove();
- }
+ } else
+ form.remove();
+ }
- showReplies(event) {
- /* The div to contain the comment's replies. From the element id
- we can get the comment's id. */
- this.setCommentId(event.target);
- console.log("You're in showReplies()");
- }
+ renderReplies(event) {
+ /* The div to contain the comment's replies. From the element id
+ we can get the comment's id. */
+ const comment_replies_section = event.target.parentElement.parentElement.parentElement;
+ const replies = comment_replies_section.querySelector(".replies-section");
+ this.setCommentId(comment_replies_section);
+
+ if( replies != null) {
+ replies.remove();
- setCommentId(parent) {
- const replies_section = parent.parentElement.parentElement.childNodes[3];
+ return;
+ }
+
+ this.get(`/api/comments/${this.comment_id}/replies`).then((value) => {
+ const replies = value?.getElementById(`replies-section-${this.comment_id}`);
+
+ if(replies != null)
+ comment_replies_section.appendChild(replies);
+ });
+ }
- this.comment_id = /\d/.exec(replies_section.id)[0];
+ setCommentId(replies_section) {
+ this.comment_id = /\d/.exec(replies_section.id)[0];
}
async getReplyForm() {
- var form = await this.get("/api/replies/new");
+ var form = await this.get("/api/replies/new");
- return form.getElementsByClassName("reply-form")[0];
+ return form.getElementsByClassName("reply-form")[0];
}
}
diff --git a/templates/replies/form.jinja b/templates/replies/form.jinja
index f585d4e..e65e244 100644
--- a/templates/replies/form.jinja
+++ b/templates/replies/form.jinja
@@ -1,17 +1,17 @@
-<form action="" class="reply-form" method="post">
+<form action="" class="reply-form" id="reply-form" method="post">
<div>
- <label for="author"> Name: </label>
- <input type="text" name="author" id="author" />
+ <label for="author"> Name: </label>
+ <input type="text" name="author" id="author" />
</div>
<div>
- <label for="email"> Email: </label>
- <input type="text" name="email" id="email" />
+ <label for="email"> Email: </label>
+ <input type="text" name="email" id="email" />
</div>
<div>
- <textarea rows="4" cols="40" form="reply-form" name="content" id="content" />
- </textarea>
+ <textarea rows="4" cols="40" form="reply-form" name="content" id="content" />
+ </textarea>
</div>
<div>
- <input type="submit" value="Submit" />
+ <input type="submit" value="Submit" />
</div>
</form>
diff --git a/templates/replies/index.jinja b/templates/replies/index.jinja
index df0705a..c1fc6ea 100644
--- a/templates/replies/index.jinja
+++ b/templates/replies/index.jinja
@@ -1,4 +1,4 @@
-<div id="comment-section" class="comment-section">
+<div id="replies-section-{{comment.id}}" class="replies-section">
{% for reply in page.items %}
<div id="reply-{{reply.id}}" class="comment">
<section class="comment-meta">
@@ -6,7 +6,7 @@
{% if reply.author is eq('') %}
Anonymous said:
{% else %}
- {{ reply.author }} said:
+ {{ reply.author }} replied:
{% endif %}
</div>
<div class="date">