Add initial frontend
This commit is contained in:
parent
68c2f8f676
commit
bd8cdc8509
8 changed files with 334 additions and 0 deletions
29
client/css/banned-posts.styl
Normal file
29
client/css/banned-posts.styl
Normal file
|
@ -0,0 +1,29 @@
|
|||
@import colors
|
||||
|
||||
.content-wrapper.banned-posts
|
||||
width: 100%
|
||||
max-width: 45em
|
||||
table
|
||||
border-spacing: 0
|
||||
width: 100%
|
||||
tr.default td
|
||||
background: $default-banned-post-background-color
|
||||
td, th
|
||||
padding: .4em
|
||||
&.color
|
||||
input[type=text]
|
||||
width: 8em
|
||||
&.usages
|
||||
text-align: center
|
||||
&.remove, &.set-default
|
||||
white-space: pre
|
||||
th
|
||||
white-space: nowrap
|
||||
&:first-child
|
||||
padding-left: 0
|
||||
&:last-child
|
||||
padding-right: 0
|
||||
tfoot
|
||||
display: none
|
||||
form
|
||||
width: auto
|
13
client/html/banned_post_entry.tpl
Normal file
13
client/html/banned_post_entry.tpl
Normal file
|
@ -0,0 +1,13 @@
|
|||
<tr data-category='<%- ctx.postBan.checksum %>'><%
|
||||
<td class='name'>
|
||||
<%- ctx.postBan.checksum %>
|
||||
</td>
|
||||
<td class='time'>
|
||||
<%- ctx.makeRelativeTime(ctx.postBan.time) %>
|
||||
</td>
|
||||
<% if (ctx.canDelete) { %>
|
||||
<td class='remove'>
|
||||
<a href>Unban</a>
|
||||
</td>
|
||||
<% } %>
|
||||
</tr>
|
25
client/html/banned_post_list.tpl
Normal file
25
client/html/banned_post_list.tpl
Normal file
|
@ -0,0 +1,25 @@
|
|||
<div class='content-wrapper banned-posts'>
|
||||
<form>
|
||||
<h1>Banned posts</h1>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class='checksum'>Checksum</th>
|
||||
<th class='time'>Time of ban</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class='messages'></div>
|
||||
|
||||
<% if (ctx.canDelete) { %>
|
||||
<div class='buttons'>
|
||||
<input type='submit' class='save' value='Save changes'>
|
||||
</div>
|
||||
<% } %>
|
||||
</form>
|
||||
</div>
|
59
client/js/controllers/banned_post_controller.js
Normal file
59
client/js/controllers/banned_post_controller.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
"use strict";
|
||||
|
||||
const api = require("../api.js");
|
||||
const BannedPostList = require("../models/banned_post_list.js");
|
||||
const topNavigation = require("../models/top_navigation.js");
|
||||
const BannedPostsView = require("../views/banned_posts_view.js");
|
||||
const EmptyView = require("../views/empty_view.js");
|
||||
|
||||
class BannedPostController {
|
||||
constructor() {
|
||||
if (!api.hasPrivilege("posts:ban:list")) {
|
||||
this._view = new EmptyView();
|
||||
this._view.showError(
|
||||
"You don't have privileges to view banned posts."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
topNavigation.activate("banned-posts");
|
||||
topNavigation.setTitle("Listing banned posts");
|
||||
BannedPostList.get().then(
|
||||
(response) => {
|
||||
this._bannedPosts = response.results;
|
||||
this._view = new BannedPostsView({
|
||||
bannedPosts: this._bannedPosts,
|
||||
canDelete: api.hasPrivilege("poolCategories:delete")
|
||||
});
|
||||
this._view.addEventListener("submit", (e) =>
|
||||
this._evtSubmit(e)
|
||||
);
|
||||
},
|
||||
(error) => {
|
||||
this._view = new EmptyView();
|
||||
this._view.showError(error.message);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
_evtSubmit(e) {
|
||||
this._view.clearMessages();
|
||||
this._view.disableForm();
|
||||
this._bannedPosts.save().then(
|
||||
() => {
|
||||
this._view.enableForm();
|
||||
this._view.showSuccess("Changes saved.");
|
||||
},
|
||||
(error) => {
|
||||
this._view.enableForm();
|
||||
this._view.showError(error.message);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = (router) => {
|
||||
router.enter(["banned-posts"], (ctx, next) => {
|
||||
ctx.controller = new BannedPostController(ctx, next);
|
||||
});
|
||||
};
|
|
@ -83,6 +83,7 @@ Promise.resolve()
|
|||
controllers.push(
|
||||
require("./controllers/user_registration_controller.js")
|
||||
);
|
||||
controllers.push(require("./controllers/banned_post_controller.js"));
|
||||
|
||||
// 404 controller needs to be registered last
|
||||
controllers.push(require("./controllers/not_found_controller.js"));
|
||||
|
|
57
client/js/models/banned_post.js
Normal file
57
client/js/models/banned_post.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
"use strict";
|
||||
|
||||
const api = require("../api.js");
|
||||
const uri = require("../util/uri.js");
|
||||
const events = require("../events.js");
|
||||
|
||||
class BannedPost extends events.EventTarget {
|
||||
constructor() {
|
||||
super();
|
||||
this._checksum = "";
|
||||
this._time = new Date();
|
||||
}
|
||||
|
||||
get checksum() {
|
||||
return this._checksum;
|
||||
}
|
||||
|
||||
get time() {
|
||||
return this._time;
|
||||
}
|
||||
|
||||
set checksum(value) {
|
||||
this._checksum = value;
|
||||
}
|
||||
|
||||
set time(value) {
|
||||
this._time = value;
|
||||
}
|
||||
|
||||
static fromResponse(response) {
|
||||
const ret = new BannedPost();
|
||||
ret._updateFromResponse(response);
|
||||
return ret;
|
||||
}
|
||||
|
||||
delete() {
|
||||
return api
|
||||
.delete(uri.formatApiLink("post-ban", this._checksum))
|
||||
.then((response) => {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("delete", {
|
||||
detail: {
|
||||
bannedPost: this,
|
||||
},
|
||||
})
|
||||
);
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
_updateFromResponse(response) {
|
||||
this._checksum = response.checksum;
|
||||
this.time = response.time;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BannedPost;
|
47
client/js/models/banned_post_list.js
Normal file
47
client/js/models/banned_post_list.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
const api = require("../api.js");
|
||||
const uri = require("../util/uri.js");
|
||||
const AbstractList = require("./abstract_list.js");
|
||||
const BannedPost = require("./banned_post.js");
|
||||
|
||||
class BannedPostList extends AbstractList {
|
||||
constructor() {
|
||||
super();
|
||||
this._deletedBans = [];
|
||||
this.addEventListener("remove", (e) => this._evtBannedPostDeleted(e));
|
||||
}
|
||||
|
||||
static get() {
|
||||
return api
|
||||
.get(uri.formatApiLink("post-ban"))
|
||||
.then((response) => {
|
||||
return Promise.resolve(
|
||||
Object.assign({}, response, {
|
||||
results: BannedPostList.fromResponse(
|
||||
response.results
|
||||
),
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
let promises = [];
|
||||
for (let BannedPost of this._deletedBans) {
|
||||
promises.push(BannedPost.delete());
|
||||
}
|
||||
|
||||
return Promise.all(promises).then((response) => {
|
||||
this._deletedBans = [];
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
_evtBannedPostDeleted(e) {
|
||||
this._deletedBans.push(e.detail.BannedPost);
|
||||
}
|
||||
}
|
||||
|
||||
BannedPostList._itemClass = BannedPost;
|
||||
BannedPostList._itemName = "bannedPost";
|
||||
|
||||
module.exports = BannedPostList;
|
103
client/js/views/banned_posts_view.js
Normal file
103
client/js/views/banned_posts_view.js
Normal file
|
@ -0,0 +1,103 @@
|
|||
"use strict";
|
||||
|
||||
const events = require("../events.js");
|
||||
const views = require("../util/views.js");
|
||||
const BannedPost = require("../models/banned_post.js");
|
||||
|
||||
const template = views.getTemplate("banned-post-list");
|
||||
const rowTemplate = views.getTemplate("banned-post-entry");
|
||||
|
||||
class BannedPostsView extends events.EventTarget {
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this._ctx = ctx;
|
||||
this._hostNode = document.getElementById("content-holder");
|
||||
|
||||
views.replaceContent(this._hostNode, template(ctx));
|
||||
views.syncScrollPosition();
|
||||
views.decorateValidator(this._formNode);
|
||||
|
||||
const bannedPostsToAdd = Array.from(ctx.bannedPosts);
|
||||
for (let bannedPost of bannedPostsToAdd) {
|
||||
this._addBannedPostRowNode(bannedPost);
|
||||
}
|
||||
|
||||
ctx.bannedPosts.addEventListener("remove", (e) =>
|
||||
this._evtBannedPostDeleted(e)
|
||||
);
|
||||
|
||||
this._formNode.addEventListener("submit", (e) =>
|
||||
this._evtSaveButtonClick(e, ctx)
|
||||
);
|
||||
}
|
||||
|
||||
enableForm() {
|
||||
views.enableForm(this._formNode);
|
||||
}
|
||||
|
||||
disableForm() {
|
||||
views.disableForm(this._formNode);
|
||||
}
|
||||
|
||||
clearMessages() {
|
||||
views.clearMessages(this._hostNode);
|
||||
}
|
||||
|
||||
showSuccess(message) {
|
||||
views.showSuccess(this._hostNode, message);
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
views.showError(this._hostNode, message);
|
||||
}
|
||||
|
||||
get _formNode() {
|
||||
return this._hostNode.querySelector("form");
|
||||
}
|
||||
|
||||
get _tableBodyNode() {
|
||||
return this._hostNode.querySelector("tbody");
|
||||
}
|
||||
|
||||
_addBannedPostRowNode(bannedPost) {
|
||||
const rowNode = rowTemplate(
|
||||
Object.assign({}, this._ctx, { postBan: bannedPost })
|
||||
);
|
||||
|
||||
const removeLinkNode = rowNode.querySelector(".remove a");
|
||||
if (removeLinkNode) {
|
||||
removeLinkNode.addEventListener("click", (e) =>
|
||||
this._evtDeleteButtonClick(e, rowNode)
|
||||
);
|
||||
}
|
||||
|
||||
this._tableBodyNode.appendChild(rowNode);
|
||||
|
||||
rowNode._bannedPost = bannedPost;
|
||||
bannedPost._rowNode = rowNode;
|
||||
}
|
||||
|
||||
_removeBannedPostRowNode(bannedPost) {
|
||||
const rowNode = bannedPost._rowNode;
|
||||
rowNode.parentNode.removeChild(rowNode);
|
||||
}
|
||||
|
||||
_evtBannedPostDeleted(e) {
|
||||
this._removeBannedPostRowNode(e.detail.poolCategory);
|
||||
}
|
||||
|
||||
_evtDeleteButtonClick(e, rowNode, link) {
|
||||
e.preventDefault();
|
||||
if (e.target.classList.contains("inactive")) {
|
||||
return;
|
||||
}
|
||||
this._ctx.bannedPosts.remove(rowNode._bannedPost);
|
||||
}
|
||||
|
||||
_evtSaveButtonClick(e, ctx) {
|
||||
e.preventDefault();
|
||||
this.dispatchEvent(new CustomEvent("submit"));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BannedPostsView;
|
Loading…
Reference in a new issue