client/comments: rework comments appearance and UX
This commit is contained in:
parent
f0573be715
commit
fe0ba63f19
11 changed files with 311 additions and 308 deletions
|
@ -1,51 +1,8 @@
|
|||
@import colors
|
||||
$comment-header-background-color = $top-navigation-color
|
||||
$comment-border-color = #DDD
|
||||
|
||||
.comment-form-container
|
||||
&:not(.editing)
|
||||
.tabs nav
|
||||
display: none
|
||||
.tabs .edit.tab
|
||||
display: none
|
||||
.comment-content
|
||||
margin-left: 0.5em
|
||||
&.editing
|
||||
.tab:not(.active)
|
||||
display: none
|
||||
.tabs-wrapper
|
||||
background: $active-tab-background-color
|
||||
padding: 0.3em
|
||||
.tab-wrapper[data-tab='preview']
|
||||
background: $window-color
|
||||
.tab.preview
|
||||
padding: 1em
|
||||
.tab.edit
|
||||
textarea
|
||||
resize: vertical
|
||||
width: 100%
|
||||
max-height: 80vh
|
||||
box-sizing: padding-box
|
||||
vertical-align: top /* ghost margin on chrome */
|
||||
|
||||
form
|
||||
width: auto
|
||||
margin: 0
|
||||
&:after
|
||||
display: block
|
||||
height: 1px
|
||||
content: ' '
|
||||
clear: both
|
||||
|
||||
nav
|
||||
vertical-align: middle !important
|
||||
&.buttons
|
||||
margin: 0 0.3em 0.5em 0 !important
|
||||
float: left
|
||||
&.actions
|
||||
float: left
|
||||
margin: 0.3em 0 0.5em 0 !important
|
||||
|
||||
|
||||
.comment
|
||||
.comment-container
|
||||
margin: 0 0 1em 0
|
||||
padding: 0
|
||||
display: -webkit-flex
|
||||
|
@ -63,25 +20,67 @@
|
|||
a
|
||||
display: inline-block
|
||||
|
||||
.body
|
||||
nav:not(.active), .tab:not(.active)
|
||||
display: none
|
||||
|
||||
.comment
|
||||
border: 1px solid $comment-border-color
|
||||
flex-grow: 1
|
||||
|
||||
header
|
||||
white-space: nowrap
|
||||
line-height: 16pt
|
||||
vertical-align: middle
|
||||
margin-bottom: 0.5em
|
||||
background: $top-navigation-color
|
||||
padding: 0.2em 0.5em
|
||||
|
||||
.nickname, .date, .score-container, .edit
|
||||
margin-right: 2em
|
||||
.date, .score-container, .edit, .delete
|
||||
font-size: 95%
|
||||
vertical-align: middle
|
||||
position: relative
|
||||
background: $comment-header-background-color
|
||||
border-bottom: 1px solid $comment-border-color
|
||||
|
||||
nav.edit
|
||||
padding: 0.33em 1em 0 1em
|
||||
ul
|
||||
list-style-type: none
|
||||
margin: 0
|
||||
padding: 0
|
||||
li
|
||||
display: inline-block
|
||||
margin: 0 0 -1px 0
|
||||
a
|
||||
padding: 0.25em 1em
|
||||
&.active
|
||||
background: $window-color
|
||||
border: 1px solid $comment-border-color
|
||||
border-bottom: none
|
||||
|
||||
nav.readonly
|
||||
padding: 0.33em 1em
|
||||
|
||||
&:before
|
||||
position: absolute
|
||||
display: block
|
||||
content: ' '
|
||||
width: 0
|
||||
height: 0
|
||||
left: -1.5em
|
||||
top: calc(50% - 0.75em)
|
||||
border: 0.75em solid transparent
|
||||
border-right: 0.75em solid darken($comment-border-color, 10%)
|
||||
|
||||
&:after
|
||||
position: absolute
|
||||
display: block
|
||||
content: ' '
|
||||
width: 0
|
||||
height: 0
|
||||
left: calc(-1.5em + 1px)
|
||||
top: calc(50% - 0.75em)
|
||||
border: 0.75em solid transparent
|
||||
border-right: 0.75em solid $comment-header-background-color
|
||||
|
||||
.date, .score-container, .edit
|
||||
margin-right: 2em
|
||||
.edit, .delete, .score-container a, .nickname a
|
||||
&:not(.inactive)
|
||||
color: mix($main-color, $inactive-tab-text-color)
|
||||
.edit, .delete
|
||||
font-size: 80%
|
||||
|
||||
i
|
||||
margin-right: 0.3em
|
||||
|
@ -96,6 +95,19 @@
|
|||
display: inline-block
|
||||
width: 2em
|
||||
|
||||
.body
|
||||
width: auto
|
||||
margin: 1em
|
||||
|
||||
.keep-height
|
||||
position: relative
|
||||
textarea
|
||||
position: absolute
|
||||
width: 100%
|
||||
height: 100%
|
||||
.tab.edit
|
||||
min-height: 150px
|
||||
|
||||
.messages
|
||||
margin: 1em 0
|
||||
|
||||
|
@ -118,9 +130,6 @@
|
|||
white-space: pre
|
||||
word-wrap: normal
|
||||
|
||||
p:first-child
|
||||
margin-top: 0
|
||||
|
||||
.spoiler
|
||||
background: #eee
|
||||
color: #eee
|
||||
|
@ -140,5 +149,5 @@
|
|||
background: #fafafa
|
||||
color: #444
|
||||
|
||||
blockquote :last-child
|
||||
:last-child
|
||||
margin-bottom: 0
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.comments>ul
|
||||
list-style-type: none
|
||||
margin: 0 0 2em 0
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
|
|
@ -1,34 +1,40 @@
|
|||
<div class='comment'>
|
||||
<div class='comment-container'>
|
||||
<div class='avatar'>
|
||||
<% if (ctx.comment.user && ctx.comment.user.name && ctx.canViewUsers) { %>
|
||||
<a href='/user/<%- encodeURIComponent(ctx.comment.user.name) %>'>
|
||||
<% if (ctx.user && ctx.user.name && ctx.canViewUsers) { %>
|
||||
<a href='/user/<%- encodeURIComponent(ctx.user.name) %>'>
|
||||
<% } %>
|
||||
|
||||
<%= ctx.makeThumbnail(ctx.comment.user ? ctx.comment.user.avatarUrl : null) %>
|
||||
<%= ctx.makeThumbnail(ctx.user ? ctx.user.avatarUrl : null) %>
|
||||
|
||||
<% if (ctx.comment.user && ctx.comment.user.name && ctx.canViewUsers) { %>
|
||||
<% if (ctx.user && ctx.user.name && ctx.canViewUsers) { %>
|
||||
</a>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
<div class='body'>
|
||||
<header><%
|
||||
%><span class='nickname'><%
|
||||
%><% if (ctx.comment.user && ctx.comment.user.name && ctx.canViewUsers) { %><%
|
||||
%><a href='/user/<%- encodeURIComponent(ctx.comment.user.name) %>'><%
|
||||
<div class='comment'>
|
||||
<header>
|
||||
<nav class='edit tabs'>
|
||||
<ul>
|
||||
<li class='edit'><a href>Write</a></li>
|
||||
<li class='preview'><a href>Preview</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<nav class='readonly'><%
|
||||
%><strong><span class='nickname'><%
|
||||
%><% if (ctx.user && ctx.user.name && ctx.canViewUsers) { %><%
|
||||
%><a href='/user/<%- encodeURIComponent(ctx.user.name) %>'><%
|
||||
%><% } %><%
|
||||
|
||||
%><%- ctx.comment.user ? ctx.comment.user.name : 'Deleted user' %><%
|
||||
%><%- ctx.user ? ctx.user.name : 'Deleted user' %><%
|
||||
|
||||
%><% if (ctx.comment.user && ctx.comment.user.name && ctx.canViewUsers) { %><%
|
||||
%><% if (ctx.user && ctx.user.name && ctx.canViewUsers) { %><%
|
||||
%></a><%
|
||||
%><% } %><%
|
||||
%></span><%
|
||||
%></span></strong>
|
||||
|
||||
%><wbr><%
|
||||
|
||||
%><span class='date'><%
|
||||
%><%= ctx.makeRelativeTime(ctx.comment.creationTime) %><%
|
||||
<span class='date'><%
|
||||
%>commented <%= ctx.makeRelativeTime(ctx.comment ? ctx.comment.creationTime : null) %><%
|
||||
%></span><%
|
||||
|
||||
%><wbr><%
|
||||
|
@ -50,8 +56,30 @@
|
|||
%><i class='fa fa-remove'></i> delete<%
|
||||
%></a><%
|
||||
%><% } %><%
|
||||
%></nav><%
|
||||
%></header>
|
||||
|
||||
<div class='comment-form-container'></div>
|
||||
<form class='body'>
|
||||
<div class='keep-height'>
|
||||
<div class='tab preview'>
|
||||
<div class='comment-content'>
|
||||
<%= ctx.makeMarkdown(ctx.comment ? ctx.comment.text : '') %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='tab edit'>
|
||||
<textarea required minlength=1><%- ctx.comment ? ctx.comment.text : '' %></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class='edit'>
|
||||
<div class='messages'></div>
|
||||
|
||||
<input type='submit' class='save-changes' value='Save'/>
|
||||
<% if (!ctx.onlyEditing) { %>
|
||||
<input type='button' class='cancel-editing discourage' value='Cancel'/>
|
||||
<% } %>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
<div class='tabs'>
|
||||
<form>
|
||||
<div class='tabs-wrapper'><%
|
||||
%><div class='tab-wrapper'><%
|
||||
%><div class='preview tab'><%
|
||||
%><div class='comment-content'><%
|
||||
%><%= ctx.makeMarkdown(ctx.comment.text) %><%
|
||||
%></div><%
|
||||
%></div><%
|
||||
|
||||
%><div class='edit tab'><%
|
||||
%><textarea required minlength=1><%- ctx.comment.text %></textarea><%
|
||||
%></div><%
|
||||
%></div><%
|
||||
%></div>
|
||||
|
||||
<nav class='buttons'>
|
||||
<ul>
|
||||
<li class='preview'><a href>Preview</a></li>
|
||||
<li class='edit'><a href>Edit</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<nav class='actions'>
|
||||
<input type='submit' class='save' value='Save'/>
|
||||
<input type='button' class='cancel discourage' value='Cancel'/>
|
||||
</nav>
|
||||
</form>
|
||||
|
||||
<div class='messages'></div>
|
||||
</div>
|
|
@ -4,7 +4,6 @@ const router = require('../router.js');
|
|||
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 PostList = require('../models/post_list.js');
|
||||
const PostDetailView = require('../views/post_detail_view.js');
|
||||
|
|
|
@ -69,10 +69,10 @@ class PostMainController extends BasePostController {
|
|||
'merge', e => this._evtMergePost(e));
|
||||
}
|
||||
|
||||
if (this._view.commentFormControl) {
|
||||
this._view.commentFormControl.addEventListener(
|
||||
if (this._view.commentControl) {
|
||||
this._view.commentControl.addEventListener(
|
||||
'change', e => this._evtCommentChange(e));
|
||||
this._view.commentFormControl.addEventListener(
|
||||
this._view.commentControl.addEventListener(
|
||||
'submit', e => this._evtCreateComment(e));
|
||||
}
|
||||
|
||||
|
@ -183,18 +183,18 @@ class PostMainController extends BasePostController {
|
|||
}
|
||||
|
||||
_evtCreateComment(e) {
|
||||
// TODO: disable form
|
||||
this._view.commentControl.disableForm();
|
||||
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
|
||||
this._view.commentControl.exitEditMode();
|
||||
this._view.commentControl.enableForm();
|
||||
misc.disableExitConfirmation();
|
||||
}, errorMessage => {
|
||||
this._view.commentFormControl.showError(errorMessage);
|
||||
// TODO: enable form
|
||||
this._view.commentControl.showError(errorMessage);
|
||||
this._view.commentControl.enableForm();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,55 +1,87 @@
|
|||
'use strict';
|
||||
|
||||
const api = require('../api.js');
|
||||
const misc = require('../util/misc.js');
|
||||
const events = require('../events.js');
|
||||
const views = require('../util/views.js');
|
||||
const CommentFormControl = require('../controls/comment_form_control.js');
|
||||
|
||||
const template = views.getTemplate('comment');
|
||||
const scoreTemplate = views.getTemplate('score');
|
||||
|
||||
class CommentControl extends events.EventTarget {
|
||||
constructor(hostNode, comment) {
|
||||
constructor(hostNode, comment, onlyEditing) {
|
||||
super();
|
||||
this._hostNode = hostNode;
|
||||
this._comment = comment;
|
||||
this._onlyEditing = onlyEditing;
|
||||
|
||||
comment.addEventListener('change', e => this._evtChange(e));
|
||||
comment.addEventListener('changeScore', e => this._evtChangeScore(e));
|
||||
if (comment) {
|
||||
comment.addEventListener(
|
||||
'change', e => this._evtChange(e));
|
||||
comment.addEventListener(
|
||||
'changeScore', e => this._evtChangeScore(e));
|
||||
}
|
||||
|
||||
const isLoggedIn = api.isLoggedIn(this._comment.user);
|
||||
const isLoggedIn = comment && api.isLoggedIn(comment.user);
|
||||
const infix = isLoggedIn ? 'own' : 'any';
|
||||
views.replaceContent(this._hostNode, template({
|
||||
comment: this._comment,
|
||||
comment: comment,
|
||||
user: comment ? comment.user : api.user,
|
||||
canViewUsers: api.hasPrivilege('users:view'),
|
||||
canEditComment: api.hasPrivilege(`comments:edit:${infix}`),
|
||||
canDeleteComment: api.hasPrivilege(`comments:delete:${infix}`),
|
||||
onlyEditing: onlyEditing,
|
||||
}));
|
||||
|
||||
if (this._editButtonNode) {
|
||||
this._editButtonNode.addEventListener(
|
||||
'click', e => this._evtEditClick(e));
|
||||
if (this._editButtonNodes) {
|
||||
for (let node of this._editButtonNodes) {
|
||||
node.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');
|
||||
if (this._previewEditingButtonNode) {
|
||||
this._previewEditingButtonNode.addEventListener(
|
||||
'click', e => this._evtPreviewEditingClick(e));
|
||||
}
|
||||
|
||||
if (this._saveChangesButtonNode) {
|
||||
this._saveChangesButtonNode.addEventListener(
|
||||
'click', e => this._evtSaveChangesClick(e));
|
||||
}
|
||||
|
||||
if (this._cancelEditingButtonNode) {
|
||||
this._cancelEditingButtonNode.addEventListener(
|
||||
'click', e => this._evtCancelEditingClick(e));
|
||||
}
|
||||
|
||||
this._installScore();
|
||||
if (onlyEditing) {
|
||||
this._selectNav('edit');
|
||||
this._selectTab('edit');
|
||||
} else {
|
||||
this._selectNav('readonly');
|
||||
this._selectTab('preview');
|
||||
}
|
||||
}
|
||||
|
||||
get _formNode() {
|
||||
return this._hostNode.querySelector('form');
|
||||
}
|
||||
|
||||
get _scoreContainerNode() {
|
||||
return this._hostNode.querySelector('.score-container');
|
||||
}
|
||||
|
||||
get _editButtonNode() {
|
||||
return this._hostNode.querySelector('.edit');
|
||||
get _editButtonNodes() {
|
||||
return this._hostNode.querySelectorAll('li.edit>a, a.edit');
|
||||
}
|
||||
|
||||
get _previewEditingButtonNode() {
|
||||
return this._hostNode.querySelector('li.preview>a');
|
||||
}
|
||||
|
||||
get _deleteButtonNode() {
|
||||
|
@ -64,12 +96,32 @@ class CommentControl extends events.EventTarget {
|
|||
return this._hostNode.querySelector('.downvote');
|
||||
}
|
||||
|
||||
get _saveChangesButtonNode() {
|
||||
return this._hostNode.querySelector('.save-changes');
|
||||
}
|
||||
|
||||
get _cancelEditingButtonNode() {
|
||||
return this._hostNode.querySelector('.cancel-editing');
|
||||
}
|
||||
|
||||
get _textareaNode() {
|
||||
return this._hostNode.querySelector('.tab.edit textarea');
|
||||
}
|
||||
|
||||
get _contentNode() {
|
||||
return this._hostNode.querySelector('.tab.preview .comment-content');
|
||||
}
|
||||
|
||||
get _heightKeeperNode() {
|
||||
return this._hostNode.querySelector('.keep-height');
|
||||
}
|
||||
|
||||
_installScore() {
|
||||
views.replaceContent(
|
||||
this._scoreContainerNode,
|
||||
scoreTemplate({
|
||||
score: this._comment.score,
|
||||
ownScore: this._comment.ownScore,
|
||||
score: this._comment ? this._comment.score : 0,
|
||||
ownScore: this._comment ? this._comment.ownScore : 0,
|
||||
canScore: api.hasPrivilege('comments:score'),
|
||||
}));
|
||||
|
||||
|
@ -83,9 +135,40 @@ class CommentControl extends events.EventTarget {
|
|||
}
|
||||
}
|
||||
|
||||
enterEditMode() {
|
||||
this._selectNav('edit');
|
||||
this._selectTab('edit');
|
||||
}
|
||||
|
||||
exitEditMode() {
|
||||
if (this._onlyEditing) {
|
||||
this._selectNav('edit');
|
||||
this._selectTab('edit');
|
||||
this._setText('');
|
||||
} else {
|
||||
this._selectNav('readonly');
|
||||
this._selectTab('preview');
|
||||
this._setText(this._comment.text);
|
||||
}
|
||||
this._forgetHeight();
|
||||
views.clearMessages(this._hostNode);
|
||||
}
|
||||
|
||||
enableForm() {
|
||||
views.enableForm(this._formNode);
|
||||
}
|
||||
|
||||
disableForm() {
|
||||
views.disableForm(this._formNode);
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
views.showError(this._hostNode, message);
|
||||
}
|
||||
|
||||
_evtEditClick(e) {
|
||||
e.preventDefault();
|
||||
this._formControl.enterEditMode();
|
||||
this.enterEditMode();
|
||||
}
|
||||
|
||||
_evtScoreClick(e, score) {
|
||||
|
@ -114,12 +197,69 @@ class CommentControl extends events.EventTarget {
|
|||
}
|
||||
|
||||
_evtChange(e) {
|
||||
this._formControl.exitEditMode();
|
||||
this.exitEditMode();
|
||||
}
|
||||
|
||||
_evtChangeScore(e) {
|
||||
this._installScore();
|
||||
}
|
||||
|
||||
_evtPreviewEditingClick(e) {
|
||||
e.preventDefault();
|
||||
this._contentNode.innerHTML =
|
||||
misc.formatMarkdown(this._textareaNode.value);
|
||||
this._selectTab('edit');
|
||||
this._selectTab('preview');
|
||||
}
|
||||
|
||||
_evtEditClick(e) {
|
||||
e.preventDefault();
|
||||
this.enterEditMode();
|
||||
}
|
||||
|
||||
_evtSaveChangesClick(e) {
|
||||
e.preventDefault();
|
||||
this.dispatchEvent(new CustomEvent('submit', {
|
||||
detail: {
|
||||
target: this,
|
||||
comment: this._comment,
|
||||
text: this._textareaNode.value,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
_evtCancelEditingClick(e) {
|
||||
e.preventDefault();
|
||||
this.exitEditMode();
|
||||
}
|
||||
|
||||
_setText(text) {
|
||||
this._textareaNode.value = text;
|
||||
this._contentNode.innerHTML = misc.formatMarkdown(text);
|
||||
}
|
||||
|
||||
_selectNav(modeName) {
|
||||
for (let node of this._hostNode.querySelectorAll('nav')) {
|
||||
node.classList.toggle('active', node.classList.contains(modeName));
|
||||
}
|
||||
}
|
||||
|
||||
_selectTab(tabName) {
|
||||
this._ensureHeight();
|
||||
|
||||
for (let node of this._hostNode.querySelectorAll('.tab, .tabs li')) {
|
||||
node.classList.toggle('active', node.classList.contains(tabName));
|
||||
}
|
||||
}
|
||||
|
||||
_ensureHeight() {
|
||||
this._heightKeeperNode.style.minHeight =
|
||||
this._heightKeeperNode.getBoundingClientRect().height + 'px';
|
||||
}
|
||||
|
||||
_forgetHeight() {
|
||||
this._heightKeeperNode.style.minHeight = null;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = CommentControl;
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const events = require('../events.js');
|
||||
const misc = require('../util/misc.js');
|
||||
const views = require('../util/views.js');
|
||||
|
||||
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._canCancel = canCancel;
|
||||
this._minHeight = minHeight || 150;
|
||||
|
||||
const sourceNode = template({
|
||||
comment: this._comment,
|
||||
});
|
||||
|
||||
const previewTabButton = sourceNode.querySelector('.buttons .preview');
|
||||
const editTabButton = sourceNode.querySelector('.buttons .edit');
|
||||
const formNode = sourceNode.querySelector('form');
|
||||
const cancelButton = sourceNode.querySelector('.cancel');
|
||||
const textareaNode = sourceNode.querySelector('form textarea');
|
||||
|
||||
previewTabButton.addEventListener(
|
||||
'click', e => this._evtPreviewClick(e));
|
||||
editTabButton.addEventListener(
|
||||
'click', e => this._evtEditClick(e));
|
||||
|
||||
formNode.addEventListener('submit', e => this._evtSaveClick(e));
|
||||
|
||||
if (this._canCancel) {
|
||||
cancelButton
|
||||
.addEventListener('click', e => this._evtCancelClick(e));
|
||||
} else {
|
||||
cancelButton.style.display = 'none';
|
||||
}
|
||||
|
||||
for (let event of ['cut', 'paste', 'drop', 'keydown']) {
|
||||
textareaNode.addEventListener(event, e => {
|
||||
window.setTimeout(() => this._growTextArea(), 0);
|
||||
});
|
||||
}
|
||||
textareaNode.addEventListener('change', e => {
|
||||
this.dispatchEvent(new CustomEvent('change', {
|
||||
detail: {
|
||||
target: this,
|
||||
},
|
||||
}));
|
||||
this._growTextArea();
|
||||
});
|
||||
|
||||
views.replaceContent(this._hostNode, sourceNode);
|
||||
}
|
||||
|
||||
enterEditMode() {
|
||||
this._freezeTabHeights();
|
||||
this._hostNode.classList.add('editing');
|
||||
this._selectTab('edit');
|
||||
this._growTextArea();
|
||||
}
|
||||
|
||||
exitEditMode() {
|
||||
this._hostNode.classList.remove('editing');
|
||||
this._hostNode.querySelector('.tab-wrapper').style.minHeight = null;
|
||||
views.clearMessages(this._hostNode);
|
||||
this.setText(this._comment.text);
|
||||
}
|
||||
|
||||
get _textareaNode() {
|
||||
return this._hostNode.querySelector('.edit.tab textarea');
|
||||
}
|
||||
|
||||
get _contentNode() {
|
||||
return this._hostNode.querySelector('.preview.tab .comment-content');
|
||||
}
|
||||
|
||||
setText(text) {
|
||||
this._textareaNode.value = text;
|
||||
this._contentNode.innerHTML = misc.formatMarkdown(text);
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
views.showError(this._hostNode, message);
|
||||
}
|
||||
|
||||
_evtPreviewClick(e) {
|
||||
e.preventDefault();
|
||||
this._contentNode.innerHTML =
|
||||
misc.formatMarkdown(this._textareaNode.value);
|
||||
this._freezeTabHeights();
|
||||
this._selectTab('preview');
|
||||
}
|
||||
|
||||
_evtEditClick(e) {
|
||||
e.preventDefault();
|
||||
this.enterEditMode();
|
||||
}
|
||||
|
||||
_evtSaveClick(e) {
|
||||
e.preventDefault();
|
||||
this.dispatchEvent(new CustomEvent('submit', {
|
||||
detail: {
|
||||
target: this,
|
||||
comment: this._comment,
|
||||
text: this._textareaNode.value,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
_evtCancelClick(e) {
|
||||
e.preventDefault();
|
||||
this.exitEditMode();
|
||||
}
|
||||
|
||||
_selectTab(tabName) {
|
||||
this._freezeTabHeights();
|
||||
const tabWrapperNode = this._hostNode.querySelector('.tab-wrapper');
|
||||
tabWrapperNode.setAttribute('data-tab', tabName);
|
||||
for (let tab of this._hostNode.querySelectorAll('.tab, .buttons li')) {
|
||||
tab.classList.toggle('active', tab.classList.contains(tabName));
|
||||
}
|
||||
}
|
||||
|
||||
_freezeTabHeights() {
|
||||
const tabsNode = this._hostNode.querySelector('.tab-wrapper');
|
||||
const tabsHeight = tabsNode.getBoundingClientRect().height;
|
||||
tabsNode.style.minHeight = tabsHeight + 'px';
|
||||
}
|
||||
|
||||
_growTextArea() {
|
||||
this._textareaNode.style.height =
|
||||
Math.max(
|
||||
this._minHeight || 0,
|
||||
this._textareaNode.scrollHeight) + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = CommentFormControl;
|
|
@ -34,7 +34,7 @@ class CommentListControl extends events.EventTarget {
|
|||
_installCommentNode(comment) {
|
||||
const commentListItemNode = document.createElement('li');
|
||||
const commentControl = new CommentControl(
|
||||
commentListItemNode, comment);
|
||||
commentListItemNode, comment, false);
|
||||
events.proxyEvent(commentControl, this, 'submit');
|
||||
events.proxyEvent(commentControl, this, 'score');
|
||||
events.proxyEvent(commentControl, this, 'delete');
|
||||
|
|
|
@ -23,7 +23,7 @@ class Comment extends events.EventTarget {
|
|||
|
||||
get id() { return this._id; }
|
||||
get postId() { return this._postId; }
|
||||
get text() { return this._text; }
|
||||
get text() { return this._text || ''; }
|
||||
get user() { return this._user; }
|
||||
get creationTime() { return this._creationTime; }
|
||||
get lastEditTime() { return this._lastEditTime; }
|
||||
|
|
|
@ -10,8 +10,8 @@ const PostReadonlySidebarControl =
|
|||
require('../controls/post_readonly_sidebar_control.js');
|
||||
const PostEditSidebarControl =
|
||||
require('../controls/post_edit_sidebar_control.js');
|
||||
const CommentControl = require('../controls/comment_control.js');
|
||||
const CommentListControl = require('../controls/comment_list_control.js');
|
||||
const CommentFormControl = require('../controls/comment_form_control.js');
|
||||
|
||||
const template = views.getTemplate('post-main');
|
||||
|
||||
|
@ -101,9 +101,8 @@ class PostMainView {
|
|||
return;
|
||||
}
|
||||
|
||||
this.commentFormControl = new CommentFormControl(
|
||||
commentFormContainer, null, false, 150);
|
||||
this.commentFormControl.enterEditMode();
|
||||
this.commentControl = new CommentControl(
|
||||
commentFormContainer, null, true);
|
||||
}
|
||||
|
||||
_installComments(comments) {
|
||||
|
|
Loading…
Reference in a new issue