client/general: remove api calls from controls
Introduce some missing models along the way
This commit is contained in:
parent
54e3099c56
commit
a697aba1b0
15 changed files with 769 additions and 312 deletions
|
@ -1,6 +1,4 @@
|
|||
<div class='comments'>
|
||||
<% if (ctx.canListComments && ctx.comments.length) { %>
|
||||
<ul>
|
||||
</ul>
|
||||
<% } %>
|
||||
<ul>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
const api = require('../api.js');
|
||||
const misc = require('../util/misc.js');
|
||||
const PostList = require('../models/post_list.js');
|
||||
const topNavigation = require('../models/top_navigation.js');
|
||||
const PageController = require('../controllers/page_controller.js');
|
||||
const CommentsPageView = require('../views/comments_page_view.js');
|
||||
|
@ -10,25 +11,62 @@ class CommentsController {
|
|||
constructor(ctx) {
|
||||
topNavigation.activate('comments');
|
||||
|
||||
const proxy = PageController.createHistoryCacheProxy(
|
||||
ctx, page => {
|
||||
const url =
|
||||
'/posts/?query=sort:comment-date+comment-count-min:1' +
|
||||
`&page=${page}&pageSize=10&fields=` +
|
||||
'id,comments,commentCount,thumbnailUrl';
|
||||
return api.get(url);
|
||||
});
|
||||
|
||||
this._pageController = new PageController({
|
||||
searchQuery: ctx.searchQuery,
|
||||
clientUrl: '/comments/' + misc.formatSearchQuery({page: '{page}'}),
|
||||
requestPage: PageController.createHistoryCacheProxy(
|
||||
ctx,
|
||||
page => {
|
||||
return api.get(
|
||||
'/posts/?query=sort:comment-date+comment-count-min:1' +
|
||||
`&page=${page}&pageSize=10&fields=` +
|
||||
'id,comments,commentCount,thumbnailUrl');
|
||||
}),
|
||||
requestPage: page => {
|
||||
return proxy(page).then(response => {
|
||||
return Promise.resolve(Object.assign(
|
||||
{},
|
||||
response,
|
||||
{results: PostList.fromResponse(response.results)}));
|
||||
});
|
||||
},
|
||||
pageRenderer: pageCtx => {
|
||||
Object.assign(pageCtx, {
|
||||
canViewPosts: api.hasPrivilege('posts:view'),
|
||||
});
|
||||
return new CommentsPageView(pageCtx);
|
||||
const view = new CommentsPageView(pageCtx);
|
||||
view.addEventListener('change', e => this._evtChange(e));
|
||||
view.addEventListener('score', e => this._evtScore(e));
|
||||
view.addEventListener('delete', e => this._evtDelete(e));
|
||||
return view;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
_evtChange(e) {
|
||||
// TODO: disable form
|
||||
e.detail.comment.text = e.detail.text;
|
||||
e.detail.comment.save()
|
||||
.catch(errorMessage => {
|
||||
e.detail.target.showError(errorMessage);
|
||||
// TODO: enable form
|
||||
});
|
||||
}
|
||||
|
||||
_evtScore(e) {
|
||||
e.detail.comment.setScore(e.detail.score)
|
||||
.catch(errorMessage => {
|
||||
window.alert(errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
_evtDelete(e) {
|
||||
e.detail.comment.delete()
|
||||
.catch(errorMessage => {
|
||||
window.alert(errorMessage);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = router => {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
'use strict';
|
||||
|
||||
const api = require('../api.js');
|
||||
const misc = require('../util/misc.js');
|
||||
const settings = require('../models/settings.js');
|
||||
const Comment = require('../models/comment.js');
|
||||
const Post = require('../models/post.js');
|
||||
const topNavigation = require('../models/top_navigation.js');
|
||||
const PostView = require('../views/post_view.js');
|
||||
|
@ -17,6 +19,7 @@ class PostController {
|
|||
this._decorateSearchQuery('')),
|
||||
]).then(responses => {
|
||||
const [post, aroundResponse] = responses;
|
||||
this._post = post;
|
||||
this._view = new PostView({
|
||||
post: post,
|
||||
editMode: editMode,
|
||||
|
@ -26,6 +29,28 @@ class PostController {
|
|||
canListComments: api.hasPrivilege('comments:list'),
|
||||
canCreateComments: api.hasPrivilege('comments:create'),
|
||||
});
|
||||
if (this._view.sidebarControl) {
|
||||
this._view.sidebarControl.addEventListener(
|
||||
'favorite', e => this._evtFavoritePost(e));
|
||||
this._view.sidebarControl.addEventListener(
|
||||
'unfavorite', e => this._evtUnfavoritePost(e));
|
||||
this._view.sidebarControl.addEventListener(
|
||||
'score', e => this._evtScorePost(e));
|
||||
}
|
||||
if (this._view.commentFormControl) {
|
||||
this._view.commentFormControl.addEventListener(
|
||||
'change', e => this._evtCommentChange(e));
|
||||
this._view.commentFormControl.addEventListener(
|
||||
'submit', e => this._evtCreateComment(e));
|
||||
}
|
||||
if (this._view.commentListControl) {
|
||||
this._view.commentListControl.addEventListener(
|
||||
'change', e => this._evtUpdateComment(e));
|
||||
this._view.commentListControl.addEventListener(
|
||||
'score', e => this._evtScoreComment(e));
|
||||
this._view.commentListControl.addEventListener(
|
||||
'delete', e => this._evtDeleteComment(e));
|
||||
}
|
||||
}, response => {
|
||||
this._view = new EmptyView();
|
||||
this._view.showError(response.description);
|
||||
|
@ -45,6 +70,71 @@ class PostController {
|
|||
}
|
||||
return text.trim();
|
||||
}
|
||||
|
||||
_evtCommentChange(e) {
|
||||
misc.enableExitConfirmation();
|
||||
}
|
||||
|
||||
_evtCreateComment(e) {
|
||||
// TODO: disable form
|
||||
const comment = Comment.create(this._post.id);
|
||||
comment.text = e.detail.text;
|
||||
comment.save()
|
||||
.then(() => {
|
||||
this._post.comments.add(comment);
|
||||
this._view.commentFormControl.setText('');
|
||||
// TODO: enable form
|
||||
misc.disableExitConfirmation();
|
||||
}, errorMessage => {
|
||||
this._view.commentFormControl.showError(errorMessage);
|
||||
// TODO: enable form
|
||||
});
|
||||
}
|
||||
|
||||
_evtUpdateComment(e) {
|
||||
// TODO: disable form
|
||||
e.detail.comment.text = e.detail.text;
|
||||
e.detail.comment.save()
|
||||
.catch(errorMessage => {
|
||||
e.detail.target.showError(errorMessage);
|
||||
// TODO: enable form
|
||||
});
|
||||
}
|
||||
|
||||
_evtScoreComment(e) {
|
||||
e.detail.comment.setScore(e.detail.score)
|
||||
.catch(errorMessage => {
|
||||
window.alert(errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
_evtDeleteComment(e) {
|
||||
e.detail.comment.delete()
|
||||
.catch(errorMessage => {
|
||||
window.alert(errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
_evtScorePost(e) {
|
||||
e.detail.post.setScore(e.detail.score)
|
||||
.catch(errorMessage => {
|
||||
window.alert(errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
_evtFavoritePost(e) {
|
||||
e.detail.post.addToFavorites()
|
||||
.catch(errorMessage => {
|
||||
window.alert(errorMessage);
|
||||
});
|
||||
}
|
||||
|
||||
_evtUnfavoritePost(e) {
|
||||
e.detail.post.removeFromFavorites()
|
||||
.catch(errorMessage => {
|
||||
window.alert(errorMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = router => {
|
||||
|
|
|
@ -1,98 +1,86 @@
|
|||
'use strict';
|
||||
|
||||
const api = require('../api.js');
|
||||
const events = require('../events.js');
|
||||
const views = require('../util/views.js');
|
||||
const CommentFormControl = require('../controls/comment_form_control.js');
|
||||
|
||||
class CommentControl {
|
||||
constructor(hostNode, comment, settings) {
|
||||
const template = views.getTemplate('comment');
|
||||
const scoreTemplate = views.getTemplate('score');
|
||||
|
||||
class CommentControl extends events.EventTarget {
|
||||
constructor(hostNode, comment) {
|
||||
super();
|
||||
this._hostNode = hostNode;
|
||||
this._comment = comment;
|
||||
this._template = views.getTemplate('comment');
|
||||
this._scoreTemplate = views.getTemplate('score');
|
||||
this._settings = settings;
|
||||
|
||||
this.install();
|
||||
}
|
||||
comment.addEventListener('change', e => this._evtChange(e));
|
||||
comment.addEventListener('changeScore', e => this._evtChangeScore(e));
|
||||
|
||||
install() {
|
||||
const isLoggedIn = api.isLoggedIn(this._comment.user);
|
||||
const infix = isLoggedIn ? 'own' : 'any';
|
||||
const sourceNode = this._template({
|
||||
views.replaceContent(this._hostNode, template({
|
||||
comment: this._comment,
|
||||
canViewUsers: api.hasPrivilege('users:view'),
|
||||
canEditComment: api.hasPrivilege(`comments:edit:${infix}`),
|
||||
canDeleteComment: api.hasPrivilege(`comments:delete:${infix}`),
|
||||
});
|
||||
}));
|
||||
|
||||
if (this._editButtonNode) {
|
||||
this._editButtonNode.addEventListener(
|
||||
'click', e => this._evtEditClick(e));
|
||||
}
|
||||
if (this._deleteButtonNode) {
|
||||
this._deleteButtonNode.addEventListener(
|
||||
'click', e => this._evtDeleteClick(e));
|
||||
}
|
||||
|
||||
this._formControl = new CommentFormControl(
|
||||
this._hostNode.querySelector('.comment-form-container'),
|
||||
this._comment,
|
||||
true);
|
||||
events.proxyEvent(this._formControl, this, 'submit', 'change');
|
||||
|
||||
this._installScore();
|
||||
}
|
||||
|
||||
get _scoreContainerNode() {
|
||||
return this._hostNode.querySelector('.score-container');
|
||||
}
|
||||
|
||||
get _editButtonNode() {
|
||||
return this._hostNode.querySelector('.edit');
|
||||
}
|
||||
|
||||
get _deleteButtonNode() {
|
||||
return this._hostNode.querySelector('.delete');
|
||||
}
|
||||
|
||||
get _upvoteButtonNode() {
|
||||
return this._hostNode.querySelector('.upvote');
|
||||
}
|
||||
|
||||
get _downvoteButtonNode() {
|
||||
return this._hostNode.querySelector('.downvote');
|
||||
}
|
||||
|
||||
_installScore() {
|
||||
views.replaceContent(
|
||||
sourceNode.querySelector('.score-container'),
|
||||
this._scoreTemplate({
|
||||
this._scoreContainerNode,
|
||||
scoreTemplate({
|
||||
score: this._comment.score,
|
||||
ownScore: this._comment.ownScore,
|
||||
canScore: api.hasPrivilege('comments:score'),
|
||||
}));
|
||||
|
||||
const editButton = sourceNode.querySelector('.edit');
|
||||
const deleteButton = sourceNode.querySelector('.delete');
|
||||
const upvoteButton = sourceNode.querySelector('.upvote');
|
||||
const downvoteButton = sourceNode.querySelector('.downvote');
|
||||
|
||||
if (editButton) {
|
||||
editButton.addEventListener(
|
||||
'click', e => this._evtEditClick(e));
|
||||
if (this._upvoteButtonNode) {
|
||||
this._upvoteButtonNode.addEventListener(
|
||||
'click', e => this._evtScoreClick(e, 1));
|
||||
}
|
||||
if (deleteButton) {
|
||||
deleteButton.addEventListener(
|
||||
'click', e => this._evtDeleteClick(e));
|
||||
if (this._downvoteButtonNode) {
|
||||
this._downvoteButtonNode.addEventListener(
|
||||
'click', e => this._evtScoreClick(e, -1));
|
||||
}
|
||||
|
||||
if (upvoteButton) {
|
||||
upvoteButton.addEventListener(
|
||||
'click',
|
||||
e => this._evtScoreClick(
|
||||
e, () => this._comment.ownScore === 1 ? 0 : 1));
|
||||
}
|
||||
if (downvoteButton) {
|
||||
downvoteButton.addEventListener(
|
||||
'click',
|
||||
e => this._evtScoreClick(
|
||||
e, () => this._comment.ownScore === -1 ? 0 : -1));
|
||||
}
|
||||
|
||||
this._formControl = new CommentFormControl(
|
||||
sourceNode.querySelector('.comment-form-container'),
|
||||
this._comment,
|
||||
{
|
||||
onSave: text => {
|
||||
return api.put('/comment/' + this._comment.id, {
|
||||
text: text,
|
||||
}).then(response => {
|
||||
this._comment = response;
|
||||
this.install();
|
||||
}, response => {
|
||||
this._formControl.showError(response.description);
|
||||
});
|
||||
},
|
||||
canCancel: true
|
||||
});
|
||||
|
||||
views.replaceContent(this._hostNode, sourceNode);
|
||||
}
|
||||
|
||||
_evtScoreClick(e, scoreGetter) {
|
||||
e.preventDefault();
|
||||
api.put(
|
||||
'/comment/' + this._comment.id + '/score',
|
||||
{score: scoreGetter()})
|
||||
.then(
|
||||
response => {
|
||||
this._comment.score = parseInt(response.score);
|
||||
this._comment.ownScore = parseInt(response.ownScore);
|
||||
this.install();
|
||||
}, response => {
|
||||
window.alert(response.description);
|
||||
});
|
||||
}
|
||||
|
||||
_evtEditClick(e) {
|
||||
|
@ -100,20 +88,34 @@ class CommentControl {
|
|||
this._formControl.enterEditMode();
|
||||
}
|
||||
|
||||
_evtScoreClick(e, score) {
|
||||
e.preventDefault();
|
||||
this.dispatchEvent(new CustomEvent('score', {
|
||||
detail: {
|
||||
comment: this._comment,
|
||||
score: this._comment.ownScore === score ? 0 : score,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
_evtDeleteClick(e) {
|
||||
e.preventDefault();
|
||||
if (!window.confirm('Are you sure you want to delete this comment?')) {
|
||||
return;
|
||||
}
|
||||
api.delete('/comment/' + this._comment.id)
|
||||
.then(response => {
|
||||
if (this._settings.onDelete) {
|
||||
this._settings.onDelete(this._comment);
|
||||
}
|
||||
this._hostNode.parentNode.removeChild(this._hostNode);
|
||||
}, response => {
|
||||
window.alert(response.description);
|
||||
});
|
||||
this.dispatchEvent(new CustomEvent('delete', {
|
||||
detail: {
|
||||
comment: this._comment,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
_evtChange(e) {
|
||||
this._formControl.exitEditMode();
|
||||
}
|
||||
|
||||
_evtChangeScore(e) {
|
||||
this._installScore();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
const events = require('../events.js');
|
||||
const misc = require('../util/misc.js');
|
||||
const views = require('../util/views.js');
|
||||
|
||||
class CommentFormControl {
|
||||
constructor(hostNode, comment, settings) {
|
||||
const template = views.getTemplate('comment-form');
|
||||
|
||||
class CommentFormControl extends events.EventTarget {
|
||||
constructor(hostNode, comment, canCancel, minHeight) {
|
||||
super();
|
||||
this._hostNode = hostNode;
|
||||
this._comment = comment || {text: ''};
|
||||
this._template = views.getTemplate('comment-form');
|
||||
this._settings = settings;
|
||||
this.install();
|
||||
}
|
||||
this._canCancel = canCancel;
|
||||
this._minHeight = minHeight || 150;
|
||||
|
||||
install() {
|
||||
const sourceNode = this._template({
|
||||
const sourceNode = template({
|
||||
comment: this._comment,
|
||||
});
|
||||
|
||||
|
@ -30,7 +31,7 @@ class CommentFormControl {
|
|||
|
||||
formNode.addEventListener('submit', e => this._evtSaveClick(e));
|
||||
|
||||
if (this._settings.canCancel) {
|
||||
if (this._canCancel) {
|
||||
cancelButton
|
||||
.addEventListener('click', e => this._evtCancelClick(e));
|
||||
} else {
|
||||
|
@ -43,7 +44,11 @@ class CommentFormControl {
|
|||
});
|
||||
}
|
||||
textareaNode.addEventListener('change', e => {
|
||||
misc.enableExitConfirmation();
|
||||
this.dispatchEvent(new CustomEvent('change', {
|
||||
detail: {
|
||||
target: this,
|
||||
},
|
||||
}));
|
||||
this._growTextArea();
|
||||
});
|
||||
|
||||
|
@ -60,7 +65,6 @@ class CommentFormControl {
|
|||
exitEditMode() {
|
||||
this._hostNode.classList.remove('editing');
|
||||
this._hostNode.querySelector('.tabs-wrapper').style.minHeight = null;
|
||||
misc.disableExitConfirmation();
|
||||
views.clearMessages(this._hostNode);
|
||||
this.setText(this._comment.text);
|
||||
}
|
||||
|
@ -97,11 +101,13 @@ class CommentFormControl {
|
|||
|
||||
_evtSaveClick(e) {
|
||||
e.preventDefault();
|
||||
if (!this._settings.onSave) {
|
||||
throw 'No save handler';
|
||||
}
|
||||
this._settings.onSave(this._textareaNode.value)
|
||||
.then(() => { misc.disableExitConfirmation(); });
|
||||
this.dispatchEvent(new CustomEvent('submit', {
|
||||
detail: {
|
||||
target: this,
|
||||
comment: this._comment,
|
||||
text: this._textareaNode.value,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
_evtCancelClick(e) {
|
||||
|
@ -125,7 +131,7 @@ class CommentFormControl {
|
|||
_growTextArea() {
|
||||
this._textareaNode.style.height =
|
||||
Math.max(
|
||||
this._settings.minHeight || 0,
|
||||
this._minHeight || 0,
|
||||
this._textareaNode.scrollHeight) + 'px';
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,48 +1,58 @@
|
|||
'use strict';
|
||||
|
||||
const api = require('../api.js');
|
||||
const events = require('../events.js');
|
||||
const views = require('../util/views.js');
|
||||
const CommentControl = require('../controls/comment_control.js');
|
||||
|
||||
class CommentListControl {
|
||||
constructor(hostNode, comments) {
|
||||
const template = views.getTemplate('comment-list');
|
||||
|
||||
class CommentListControl extends events.EventTarget {
|
||||
constructor(hostNode, comments, reversed) {
|
||||
super();
|
||||
this._hostNode = hostNode;
|
||||
this._comments = comments;
|
||||
this._template = views.getTemplate('comment-list');
|
||||
this._commentIdToNode = {};
|
||||
|
||||
this.install();
|
||||
comments.addEventListener('add', e => this._evtAdd(e));
|
||||
comments.addEventListener('remove', e => this._evtRemove(e));
|
||||
|
||||
views.replaceContent(this._hostNode, template());
|
||||
|
||||
const commentList = Array.from(comments);
|
||||
if (reversed) {
|
||||
commentList.reverse();
|
||||
}
|
||||
for (let comment of commentList) {
|
||||
this._installCommentNode(comment);
|
||||
}
|
||||
}
|
||||
|
||||
install() {
|
||||
const sourceNode = this._template({
|
||||
comments: this._comments,
|
||||
canListComments: api.hasPrivilege('comments:list'),
|
||||
});
|
||||
|
||||
views.replaceContent(this._hostNode, sourceNode);
|
||||
|
||||
this._renderComments();
|
||||
get _commentListNode() {
|
||||
return this._hostNode.querySelector('ul');
|
||||
}
|
||||
|
||||
_renderComments() {
|
||||
if (!this._comments.length) {
|
||||
return;
|
||||
}
|
||||
const commentList = new DocumentFragment();
|
||||
for (let comment of this._comments) {
|
||||
const commentListItemNode = document.createElement('li');
|
||||
new CommentControl(commentListItemNode, comment, {
|
||||
onDelete: removedComment => {
|
||||
for (let [index, comment] of this._comments.entries()) {
|
||||
if (comment.id === removedComment.id) {
|
||||
this._comments.splice(index, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
commentList.appendChild(commentListItemNode);
|
||||
}
|
||||
views.replaceContent(this._hostNode.querySelector('ul'), commentList);
|
||||
_installCommentNode(comment) {
|
||||
const commentListItemNode = document.createElement('li');
|
||||
const commentControl = new CommentControl(
|
||||
commentListItemNode, comment);
|
||||
events.proxyEvent(commentControl, this, 'change');
|
||||
events.proxyEvent(commentControl, this, 'score');
|
||||
events.proxyEvent(commentControl, this, 'delete');
|
||||
this._commentIdToNode[comment.id] = commentListItemNode;
|
||||
this._commentListNode.appendChild(commentListItemNode);
|
||||
}
|
||||
|
||||
_uninstallCommentNode(comment) {
|
||||
const commentListItemNode = this._commentIdToNode[comment.id];
|
||||
commentListItemNode.parentNode.removeChild(commentListItemNode);
|
||||
}
|
||||
|
||||
_evtAdd(e) {
|
||||
this._installCommentNode(e.detail.comment);
|
||||
}
|
||||
|
||||
_evtRemove(e) {
|
||||
this._uninstallCommentNode(e.detail.comment);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,22 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
const events = require('../events.js');
|
||||
const views = require('../util/views.js');
|
||||
|
||||
class PostEditSidebarControl {
|
||||
const template = views.getTemplate('post-edit-sidebar');
|
||||
|
||||
class PostEditSidebarControl extends events.EventTarget {
|
||||
constructor(hostNode, post, postContentControl) {
|
||||
super();
|
||||
this._hostNode = hostNode;
|
||||
this._post = post;
|
||||
this._postContentControl = postContentControl;
|
||||
this._template = views.getTemplate('post-edit-sidebar');
|
||||
|
||||
this.install();
|
||||
}
|
||||
|
||||
install() {
|
||||
const sourceNode = this._template({
|
||||
views.replaceContent(this._hostNode, template({
|
||||
post: this._post,
|
||||
});
|
||||
views.replaceContent(this._hostNode, sourceNode);
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,93 +1,128 @@
|
|||
'use strict';
|
||||
|
||||
const api = require('../api.js');
|
||||
const events = require('../events.js');
|
||||
const tags = require('../tags.js');
|
||||
const views = require('../util/views.js');
|
||||
|
||||
class PostReadonlySidebarControl {
|
||||
const template = views.getTemplate('post-readonly-sidebar');
|
||||
const scoreTemplate = views.getTemplate('score');
|
||||
const favTemplate = views.getTemplate('fav');
|
||||
|
||||
class PostReadonlySidebarControl extends events.EventTarget {
|
||||
constructor(hostNode, post, postContentControl) {
|
||||
super();
|
||||
this._hostNode = hostNode;
|
||||
this._post = post;
|
||||
this._postContentControl = postContentControl;
|
||||
this._template = views.getTemplate('post-readonly-sidebar');
|
||||
this._scoreTemplate = views.getTemplate('score');
|
||||
this._favTemplate = views.getTemplate('fav');
|
||||
|
||||
this.install();
|
||||
}
|
||||
post.addEventListener('changeFavorite', e => this._evtChangeFav(e));
|
||||
post.addEventListener('changeScore', e => this._evtChangeScore(e));
|
||||
|
||||
install() {
|
||||
const sourceNode = this._template({
|
||||
views.replaceContent(this._hostNode, template({
|
||||
post: this._post,
|
||||
getTagCategory: this._getTagCategory,
|
||||
getTagUsages: this._getTagUsages,
|
||||
canListPosts: api.hasPrivilege('posts:list'),
|
||||
canViewTags: api.hasPrivilege('tags:view'),
|
||||
});
|
||||
}));
|
||||
|
||||
views.replaceContent(
|
||||
sourceNode.querySelector('.score-container'),
|
||||
this._scoreTemplate({
|
||||
score: this._post.score,
|
||||
ownScore: this._post.ownScore,
|
||||
canScore: api.hasPrivilege('posts:score'),
|
||||
}));
|
||||
this._installFav();
|
||||
this._installScore();
|
||||
this._installFitButtons();
|
||||
this._syncFitButton();
|
||||
}
|
||||
|
||||
get _scoreContainerNode() {
|
||||
return this._hostNode.querySelector('.score-container');
|
||||
}
|
||||
|
||||
get _favContainerNode() {
|
||||
return this._hostNode.querySelector('.fav-container');
|
||||
}
|
||||
|
||||
get _upvoteButtonNode() {
|
||||
return this._hostNode.querySelector('.upvote');
|
||||
}
|
||||
|
||||
get _downvoteButtonNode() {
|
||||
return this._hostNode.querySelector('.downvote');
|
||||
}
|
||||
|
||||
get _addFavButtonNode() {
|
||||
return this._hostNode.querySelector('.add-favorite');
|
||||
}
|
||||
|
||||
get _remFavButtonNode() {
|
||||
return this._hostNode.querySelector('.remove-favorite');
|
||||
}
|
||||
|
||||
get _fitBothButtonNode() {
|
||||
return this._hostNode.querySelector('.fit-both');
|
||||
}
|
||||
|
||||
get _fitOriginalButtonNode() {
|
||||
return this._hostNode.querySelector('.fit-original');
|
||||
}
|
||||
|
||||
get _fitWidthButtonNode() {
|
||||
return this._hostNode.querySelector('.fit-width');
|
||||
}
|
||||
|
||||
get _fitHeightButtonNode() {
|
||||
return this._hostNode.querySelector('.fit-height');
|
||||
}
|
||||
|
||||
_installFitButtons() {
|
||||
this._fitBothButtonNode.addEventListener(
|
||||
'click', this._eventZoomProxy(
|
||||
() => this._postContentControl.fitBoth()));
|
||||
this._fitOriginalButtonNode.addEventListener(
|
||||
'click', this._eventZoomProxy(
|
||||
() => this._postContentControl.fitOriginal()));
|
||||
this._fitWidthButtonNode.addEventListener(
|
||||
'click', this._eventZoomProxy(
|
||||
() => this._postContentControl.fitWidth()));
|
||||
this._fitHeightButtonNode.addEventListener(
|
||||
'click', this._eventZoomProxy(
|
||||
() => this._postContentControl.fitHeight()));
|
||||
}
|
||||
|
||||
_installFav() {
|
||||
views.replaceContent(
|
||||
sourceNode.querySelector('.fav-container'),
|
||||
this._favTemplate({
|
||||
this._favContainerNode,
|
||||
favTemplate({
|
||||
favoriteCount: this._post.favoriteCount,
|
||||
ownFavorite: this._post.ownFavorite,
|
||||
canFavorite: api.hasPrivilege('posts:favorite'),
|
||||
}));
|
||||
|
||||
const upvoteButton = sourceNode.querySelector('.upvote');
|
||||
const downvoteButton = sourceNode.querySelector('.downvote');
|
||||
const addFavButton = sourceNode.querySelector('.add-favorite');
|
||||
const remFavButton = sourceNode.querySelector('.remove-favorite');
|
||||
const fitBothButton = sourceNode.querySelector('.fit-both');
|
||||
const fitOriginalButton = sourceNode.querySelector('.fit-original');
|
||||
const fitWidthButton = sourceNode.querySelector('.fit-width');
|
||||
const fitHeightButton = sourceNode.querySelector('.fit-height');
|
||||
|
||||
if (upvoteButton) {
|
||||
upvoteButton.addEventListener(
|
||||
'click', this._eventRequestProxy(
|
||||
() => this._setScore(this._post.ownScore === 1 ? 0 : 1)));
|
||||
if (this._addFavButtonNode) {
|
||||
this._addFavButtonNode.addEventListener(
|
||||
'click', e => this._evtAddToFavoritesClick(e));
|
||||
}
|
||||
if (downvoteButton) {
|
||||
downvoteButton.addEventListener(
|
||||
'click', this._eventRequestProxy(
|
||||
() => this._setScore(this._post.ownScore === -1 ? 0 : -1)));
|
||||
if (this._remFavButtonNode) {
|
||||
this._remFavButtonNode.addEventListener(
|
||||
'click', e => this._evtRemoveFromFavoritesClick(e));
|
||||
}
|
||||
}
|
||||
|
||||
if (addFavButton) {
|
||||
addFavButton.addEventListener(
|
||||
'click', this._eventRequestProxy(
|
||||
() => this._addToFavorites()));
|
||||
_installScore() {
|
||||
views.replaceContent(
|
||||
this._scoreContainerNode,
|
||||
scoreTemplate({
|
||||
score: this._post.score,
|
||||
ownScore: this._post.ownScore,
|
||||
canScore: api.hasPrivilege('posts:score'),
|
||||
}));
|
||||
if (this._upvoteButtonNode) {
|
||||
this._upvoteButtonNode.addEventListener(
|
||||
'click', e => this._evtScoreClick(e, 1));
|
||||
}
|
||||
if (remFavButton) {
|
||||
remFavButton.addEventListener(
|
||||
'click', this._eventRequestProxy(
|
||||
() => this._removeFromFavorites()));
|
||||
if (this._downvoteButtonNode) {
|
||||
this._downvoteButtonNode.addEventListener(
|
||||
'click', e => this._evtScoreClick(e, -1));
|
||||
}
|
||||
|
||||
fitBothButton.addEventListener(
|
||||
'click', this._eventZoomProxy(
|
||||
() => this._postContentControl.fitBoth()));
|
||||
fitOriginalButton.addEventListener(
|
||||
'click', this._eventZoomProxy(
|
||||
() => this._postContentControl.fitOriginal()));
|
||||
fitWidthButton.addEventListener(
|
||||
'click', this._eventZoomProxy(
|
||||
() => this._postContentControl.fitWidth()));
|
||||
fitHeightButton.addEventListener(
|
||||
'click', this._eventZoomProxy(
|
||||
() => this._postContentControl.fitHeight()));
|
||||
|
||||
views.replaceContent(this._hostNode, sourceNode);
|
||||
|
||||
this._syncFitButton();
|
||||
}
|
||||
|
||||
_eventZoomProxy(func) {
|
||||
|
@ -99,15 +134,6 @@ class PostReadonlySidebarControl {
|
|||
};
|
||||
}
|
||||
|
||||
_eventRequestProxy(promise) {
|
||||
return e => {
|
||||
e.preventDefault();
|
||||
promise().then(() => {
|
||||
this.install();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
_syncFitButton() {
|
||||
const funcToClassName = {};
|
||||
funcToClassName[this._postContentControl.fitBoth] = 'fit-both';
|
||||
|
@ -134,37 +160,40 @@ class PostReadonlySidebarControl {
|
|||
return tag ? tag.category : 'unknown';
|
||||
}
|
||||
|
||||
_setScore(score) {
|
||||
return this._requestAndRefresh(
|
||||
() => api.put('/post/' + this._post.id + '/score', {score: score}));
|
||||
_evtAddToFavoritesClick(e) {
|
||||
e.preventDefault();
|
||||
this.dispatchEvent(new CustomEvent('favorite', {
|
||||
detail: {
|
||||
post: this._post,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
_addToFavorites() {
|
||||
return this._requestAndRefresh(
|
||||
() => api.post('/post/' + this._post.id + '/favorite'));
|
||||
_evtRemoveFromFavoritesClick(e) {
|
||||
e.preventDefault();
|
||||
this.dispatchEvent(new CustomEvent('unfavorite', {
|
||||
detail: {
|
||||
post: this._post,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
_removeFromFavorites() {
|
||||
return this._requestAndRefresh(
|
||||
() => api.delete('/post/' + this._post.id + '/favorite'));
|
||||
_evtScoreClick(e, score) {
|
||||
e.preventDefault();
|
||||
this.dispatchEvent(new CustomEvent('score', {
|
||||
detail: {
|
||||
post: this._post,
|
||||
score: this._post.ownScore === score ? 0 : score,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
_requestAndRefresh(requestPromise) {
|
||||
return new Promise((resolve, reject) => {
|
||||
requestPromise()
|
||||
.then(
|
||||
response => { return api.get('/post/' + this._post.id); },
|
||||
response => { return Promise.reject(response); })
|
||||
.then(
|
||||
response => {
|
||||
this._post = response;
|
||||
resolve();
|
||||
},
|
||||
response => {
|
||||
reject();
|
||||
window.alert(response.description);
|
||||
});
|
||||
});
|
||||
_evtChangeFav(e) {
|
||||
this._installFav();
|
||||
}
|
||||
|
||||
_evtChangeScore(e) {
|
||||
this._installScore();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -13,10 +13,22 @@ class EventTarget {
|
|||
}
|
||||
};
|
||||
|
||||
function proxyEvent(source, target, sourceEventType, targetEventType) {
|
||||
if (!targetEventType) {
|
||||
targetEventType = sourceEventType;
|
||||
}
|
||||
source.addEventListener(sourceEventType, e => {
|
||||
target.dispatchEvent(new CustomEvent(targetEventType, {
|
||||
detail: e.detail,
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
Success: 'success',
|
||||
Error: 'error',
|
||||
Info: 'info',
|
||||
|
||||
proxyEvent: proxyEvent,
|
||||
EventTarget: EventTarget,
|
||||
};
|
||||
|
|
118
client/js/models/comment.js
Normal file
118
client/js/models/comment.js
Normal file
|
@ -0,0 +1,118 @@
|
|||
'use strict';
|
||||
|
||||
const api = require('../api.js');
|
||||
const events = require('../events.js');
|
||||
|
||||
class Comment extends events.EventTarget {
|
||||
constructor() {
|
||||
super();
|
||||
this.commentList = null;
|
||||
|
||||
this._id = null;
|
||||
this._postId = null;
|
||||
this._text = null;
|
||||
this._user = null;
|
||||
this._creationTime = null;
|
||||
this._lastEditTime = null;
|
||||
this._score = null;
|
||||
this._ownScore = null;
|
||||
}
|
||||
|
||||
static create(postId) {
|
||||
const comment = new Comment();
|
||||
comment._postId = postId;
|
||||
return comment;
|
||||
}
|
||||
|
||||
static fromResponse(response) {
|
||||
const comment = new Comment();
|
||||
comment._updateFromResponse(response);
|
||||
return comment;
|
||||
}
|
||||
|
||||
get id() { return this._id; }
|
||||
get postId() { return this._postId; }
|
||||
get text() { return this._text; }
|
||||
get user() { return this._user; }
|
||||
get creationTime() { return this._creationTime; }
|
||||
get lastEditTime() { return this._lastEditTime; }
|
||||
get score() { return this._score; }
|
||||
get ownScore() { return this._ownScore; }
|
||||
|
||||
set text(value) { this._text = value; }
|
||||
|
||||
save() {
|
||||
let promise = null;
|
||||
if (this._id) {
|
||||
promise = api.put(
|
||||
'/comment/' + this._id,
|
||||
{
|
||||
text: this._text,
|
||||
});
|
||||
} else {
|
||||
promise = api.post(
|
||||
'/comments',
|
||||
{
|
||||
text: this._text,
|
||||
postId: this._postId,
|
||||
});
|
||||
}
|
||||
|
||||
return promise.then(response => {
|
||||
this._updateFromResponse(response);
|
||||
this.dispatchEvent(new CustomEvent('change', {
|
||||
details: {
|
||||
comment: this,
|
||||
},
|
||||
}));
|
||||
return Promise.resolve();
|
||||
}, response => {
|
||||
return Promise.reject(response.description);
|
||||
});
|
||||
}
|
||||
|
||||
delete() {
|
||||
return api.delete('/comment/' + this._id)
|
||||
.then(response => {
|
||||
if (this.commentList) {
|
||||
this.commentList.remove(this);
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent('delete', {
|
||||
details: {
|
||||
comment: this,
|
||||
},
|
||||
}));
|
||||
return Promise.resolve();
|
||||
}, response => {
|
||||
return Promise.reject(response.description);
|
||||
});
|
||||
}
|
||||
|
||||
setScore(score) {
|
||||
return api.put('/comment/' + this._id + '/score', {score: score})
|
||||
.then(response => {
|
||||
this._updateFromResponse(response);
|
||||
this.dispatchEvent(new CustomEvent('changeScore', {
|
||||
details: {
|
||||
comment: this,
|
||||
},
|
||||
}));
|
||||
return Promise.resolve();
|
||||
}, response => {
|
||||
return Promise.reject(response.description);
|
||||
});
|
||||
}
|
||||
|
||||
_updateFromResponse(response) {
|
||||
this._id = response.id;
|
||||
this._postId = response.postId;
|
||||
this._text = response.text;
|
||||
this._user = response.user;
|
||||
this._creationTime = response.creationTime;
|
||||
this._lastEditTime = response.lastEditTime;
|
||||
this._score = parseInt(response.score);
|
||||
this._ownScore = parseInt(response.ownScore);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Comment;
|
59
client/js/models/comment_list.js
Normal file
59
client/js/models/comment_list.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
'use strict';
|
||||
|
||||
const events = require('../events.js');
|
||||
const Comment = require('./comment.js');
|
||||
|
||||
class CommentList extends events.EventTarget {
|
||||
constructor(comments) {
|
||||
super();
|
||||
this._list = [];
|
||||
}
|
||||
|
||||
static fromResponse(commentsResponse) {
|
||||
const commentList = new CommentList();
|
||||
for (let commentResponse of commentsResponse) {
|
||||
const comment = Comment.fromResponse(commentResponse);
|
||||
comment.commentList = commentList;
|
||||
commentList._list.push(comment);
|
||||
}
|
||||
return commentList;
|
||||
}
|
||||
|
||||
get comments() {
|
||||
return [...this._list];
|
||||
}
|
||||
|
||||
add(comment) {
|
||||
comment.commentList = this;
|
||||
this._list.push(comment);
|
||||
this.dispatchEvent(new CustomEvent('add', {
|
||||
detail: {
|
||||
comment: comment,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
remove(commentToRemove) {
|
||||
for (let [index, comment] of this._list.entries()) {
|
||||
if (comment.id === commentToRemove.id) {
|
||||
this._list.splice(index, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent('remove', {
|
||||
detail: {
|
||||
comment: commentToRemove,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
get length() {
|
||||
return this._list.length;
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this._list[Symbol.iterator]();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CommentList;
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
const api = require('../api.js');
|
||||
const events = require('../events.js');
|
||||
const CommentList = require('./comment_list.js');
|
||||
|
||||
class Post extends events.EventTarget {
|
||||
constructor() {
|
||||
|
@ -29,7 +30,22 @@ class Post extends events.EventTarget {
|
|||
this._ownFavorite = null;
|
||||
}
|
||||
|
||||
// encapsulation - don't let set these casually
|
||||
static fromResponse(response) {
|
||||
const post = new Post();
|
||||
post._updateFromResponse(response);
|
||||
return post;
|
||||
}
|
||||
|
||||
static get(id) {
|
||||
return api.get('/post/' + id)
|
||||
.then(response => {
|
||||
const post = Post.fromResponse(response);
|
||||
return Promise.resolve(post);
|
||||
}, response => {
|
||||
return Promise.reject(response);
|
||||
});
|
||||
}
|
||||
|
||||
get id() { return this._id; }
|
||||
get type() { return this._type; }
|
||||
get mimeType() { return this._mimeType; }
|
||||
|
@ -52,37 +68,97 @@ class Post extends events.EventTarget {
|
|||
get ownFavorite() { return this._ownFavorite; }
|
||||
get ownScore() { return this._ownScore; }
|
||||
|
||||
static get(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
api.get('/post/' + id)
|
||||
.then(response => {
|
||||
const post = new Post();
|
||||
post._id = response.id;
|
||||
post._type = response.type;
|
||||
post._mimeType = response.mimeType;
|
||||
post._creationTime = response.creationTime;
|
||||
post._user = response.user;
|
||||
post._safety = response.safety;
|
||||
post._contentUrl = response.contentUrl;
|
||||
post._thumbnailUrl = response.thumbnailUrl;
|
||||
post._canvasWidth = response.canvasWidth;
|
||||
post._canvasHeight = response.canvasHeight;
|
||||
post._fileSize = response.fileSize;
|
||||
setScore(score) {
|
||||
return api.put('/post/' + this._id + '/score', {score: score})
|
||||
.then(response => {
|
||||
const prevFavorite = this._ownFavorite;
|
||||
this._updateFromResponse(response);
|
||||
if (this._ownFavorite !== prevFavorite) {
|
||||
this.dispatchEvent(new CustomEvent('changeFavorite', {
|
||||
details: {
|
||||
post: this,
|
||||
},
|
||||
}));
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent('changeScore', {
|
||||
details: {
|
||||
post: this,
|
||||
},
|
||||
}));
|
||||
return Promise.resolve();
|
||||
}, response => {
|
||||
return Promise.reject(response.description);
|
||||
});
|
||||
}
|
||||
|
||||
post._tags = response.tags;
|
||||
post._notes = response.notes;
|
||||
post._comments = response.comments;
|
||||
post._relations = response.relations;
|
||||
addToFavorites() {
|
||||
return api.post('/post/' + this.id + '/favorite')
|
||||
.then(response => {
|
||||
const prevScore = this._ownScore;
|
||||
this._updateFromResponse(response);
|
||||
if (this._ownScore !== prevScore) {
|
||||
this.dispatchEvent(new CustomEvent('changeScore', {
|
||||
details: {
|
||||
post: this,
|
||||
},
|
||||
}));
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent('changeFavorite', {
|
||||
details: {
|
||||
post: this,
|
||||
},
|
||||
}));
|
||||
return Promise.resolve();
|
||||
}, response => {
|
||||
return Promise.reject(response.description);
|
||||
});
|
||||
}
|
||||
|
||||
post._score = response.score;
|
||||
post._favoriteCount = response.favoriteCount;
|
||||
post._ownScore = response.ownScore;
|
||||
post._ownFavorite = response.ownFavorite;
|
||||
resolve(post);
|
||||
}, response => {
|
||||
reject(response);
|
||||
});
|
||||
});
|
||||
removeFromFavorites() {
|
||||
return api.delete('/post/' + this.id + '/favorite')
|
||||
.then(response => {
|
||||
const prevScore = this._ownScore;
|
||||
this._updateFromResponse(response);
|
||||
if (this._ownScore !== prevScore) {
|
||||
this.dispatchEvent(new CustomEvent('changeScore', {
|
||||
details: {
|
||||
post: this,
|
||||
},
|
||||
}));
|
||||
}
|
||||
this.dispatchEvent(new CustomEvent('changeFavorite', {
|
||||
details: {
|
||||
post: this,
|
||||
},
|
||||
}));
|
||||
return Promise.resolve();
|
||||
}, response => {
|
||||
return Promise.reject(response.description);
|
||||
});
|
||||
}
|
||||
|
||||
_updateFromResponse(response) {
|
||||
this._id = response.id;
|
||||
this._type = response.type;
|
||||
this._mimeType = response.mimeType;
|
||||
this._creationTime = response.creationTime;
|
||||
this._user = response.user;
|
||||
this._safety = response.safety;
|
||||
this._contentUrl = response.contentUrl;
|
||||
this._thumbnailUrl = response.thumbnailUrl;
|
||||
this._canvasWidth = response.canvasWidth;
|
||||
this._canvasHeight = response.canvasHeight;
|
||||
this._fileSize = response.fileSize;
|
||||
|
||||
this._tags = response.tags;
|
||||
this._notes = response.notes;
|
||||
this._comments = CommentList.fromResponse(response.comments);
|
||||
this._relations = response.relations;
|
||||
|
||||
this._score = response.score;
|
||||
this._favoriteCount = response.favoriteCount;
|
||||
this._ownScore = response.ownScore;
|
||||
this._ownFavorite = response.ownFavorite;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
33
client/js/models/post_list.js
Normal file
33
client/js/models/post_list.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
'use strict';
|
||||
|
||||
const events = require('../events.js');
|
||||
const Post = require('./post.js');
|
||||
|
||||
class PostList extends events.EventTarget {
|
||||
constructor(posts) {
|
||||
super();
|
||||
this._list = [];
|
||||
}
|
||||
|
||||
static fromResponse(postsResponse) {
|
||||
const postList = new PostList();
|
||||
for (let postResponse of postsResponse) {
|
||||
postList._list.push(Post.fromResponse(postResponse));
|
||||
}
|
||||
return postList;
|
||||
}
|
||||
|
||||
get posts() {
|
||||
return [...this._list];
|
||||
}
|
||||
|
||||
get length() {
|
||||
return this._list.length;
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this._list[Symbol.iterator]();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PostList;
|
|
@ -1,24 +1,27 @@
|
|||
'use strict';
|
||||
|
||||
const events = require('../events.js');
|
||||
const views = require('../util/views.js');
|
||||
const CommentListControl = require('../controls/comment_list_control.js');
|
||||
|
||||
const template = views.getTemplate('comments-page');
|
||||
|
||||
class CommentsPageView {
|
||||
class CommentsPageView extends events.EventTarget {
|
||||
constructor(ctx) {
|
||||
super();
|
||||
this._hostNode = ctx.hostNode;
|
||||
this._controls = [];
|
||||
|
||||
const sourceNode = template(ctx);
|
||||
|
||||
for (let post of ctx.results) {
|
||||
post.comments.sort((a, b) => { return b.id - a.id; });
|
||||
this._controls.push(
|
||||
new CommentListControl(
|
||||
sourceNode.querySelector(
|
||||
`.comments-container[data-for="${post.id}"]`),
|
||||
post.comments));
|
||||
const commentListControl = new CommentListControl(
|
||||
sourceNode.querySelector(
|
||||
`.comments-container[data-for="${post.id}"]`),
|
||||
post.comments,
|
||||
true);
|
||||
events.proxyEvent(commentListControl, this, 'change');
|
||||
events.proxyEvent(commentListControl, this, 'score');
|
||||
events.proxyEvent(commentListControl, this, 'delete');
|
||||
}
|
||||
|
||||
views.replaceContent(this._hostNode, sourceNode);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
const api = require('../api.js');
|
||||
const router = require('../router.js');
|
||||
const views = require('../util/views.js');
|
||||
const keyboard = require('../util/keyboard.js');
|
||||
|
@ -52,8 +51,8 @@ class PostView {
|
|||
ctx.post);
|
||||
|
||||
this._installSidebar(ctx);
|
||||
this._installCommentForm(ctx);
|
||||
this._installComments(ctx);
|
||||
this._installCommentForm();
|
||||
this._installComments(ctx.post.comments);
|
||||
|
||||
keyboard.bind('e', () => {
|
||||
if (ctx.editMode) {
|
||||
|
@ -79,49 +78,35 @@ class PostView {
|
|||
'#content-holder .sidebar-container');
|
||||
|
||||
if (ctx.editMode) {
|
||||
new PostEditSidebarControl(
|
||||
this.sidebarControl = new PostEditSidebarControl(
|
||||
sidebarContainerNode, ctx.post, this._postContentControl);
|
||||
} else {
|
||||
new PostReadonlySidebarControl(
|
||||
this.sidebarControl = new PostReadonlySidebarControl(
|
||||
sidebarContainerNode, ctx.post, this._postContentControl);
|
||||
}
|
||||
}
|
||||
|
||||
_installCommentForm(ctx) {
|
||||
_installCommentForm() {
|
||||
const commentFormContainer = document.querySelector(
|
||||
'#content-holder .comment-form-container');
|
||||
if (!commentFormContainer) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._formControl = new CommentFormControl(
|
||||
commentFormContainer,
|
||||
null,
|
||||
{
|
||||
onSave: text => {
|
||||
return api.post('/comments', {
|
||||
postId: ctx.post.id,
|
||||
text: text,
|
||||
}).then(response => {
|
||||
ctx.post.comments.push(response);
|
||||
this._formControl.setText('');
|
||||
this._installComments(ctx);
|
||||
}, response => {
|
||||
this._formControl.showError(response.description);
|
||||
});
|
||||
},
|
||||
canCancel: false,
|
||||
minHeight: 150,
|
||||
});
|
||||
this._formControl.enterEditMode();
|
||||
this.commentFormControl = new CommentFormControl(
|
||||
commentFormContainer, null, false, 150);
|
||||
this.commentFormControl.enterEditMode();
|
||||
}
|
||||
|
||||
_installComments(ctx) {
|
||||
_installComments(comments) {
|
||||
const commentsContainerNode = document.querySelector(
|
||||
'#content-holder .comments-container');
|
||||
if (commentsContainerNode) {
|
||||
new CommentListControl(commentsContainerNode, ctx.post.comments);
|
||||
if (!commentsContainerNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.commentListControl = new CommentListControl(
|
||||
commentsContainerNode, comments);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue