merge time
This commit is contained in:
parent
6a7edd84a7
commit
00eeba9c30
5 changed files with 461 additions and 138 deletions
|
@ -119,6 +119,10 @@
|
|||
font: 12px/20px @mio-font-regular;
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
&--deleted {
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
&__user {
|
||||
|
|
|
@ -3,8 +3,14 @@
|
|||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
|
||||
&__listing {
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
&__input,
|
||||
&__javascript {
|
||||
&__javascript,
|
||||
&__notice--staff {
|
||||
border-bottom: 1px solid #9475b2;
|
||||
padding-bottom: 1px;
|
||||
margin-bottom: 1px;
|
||||
|
|
|
@ -15,6 +15,11 @@ if ($isXHR) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!tmp_csrf_verify($_REQUEST['csrf'] ?? '')) {
|
||||
echo render_info_or_json("Couldn't verify this request, please refresh the page and try again.", 403);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($app->getUserId() < 1) {
|
||||
echo render_info_or_json($isXHR, 'You must be logged in to manage comments.', 401);
|
||||
return;
|
||||
|
@ -50,11 +55,13 @@ switch ($_GET['m'] ?? null) {
|
|||
break;
|
||||
}
|
||||
|
||||
echo '[]'; // we don't really need a answer for this, the client implicitly does all
|
||||
echo json_encode(comments_votes_get($comment));
|
||||
break;
|
||||
/*
|
||||
|
||||
case 'delete':
|
||||
if ($commentId < 1) {
|
||||
$comment = (int)($_GET['c'] ?? 0);
|
||||
|
||||
if ($comment < 1) {
|
||||
echo render_info_or_json($isXHR, 'Missing data.', 400);
|
||||
break;
|
||||
}
|
||||
|
@ -65,12 +72,12 @@ switch ($_GET['m'] ?? null) {
|
|||
}
|
||||
|
||||
if (!$commentPerms['can_delete_any']
|
||||
&& !comments_post_check_ownership($commentId, $app->getUserId())) {
|
||||
&& !comments_post_check_ownership($comment, $app->getUserId())) {
|
||||
echo render_info_or_json($isXHR, "You're not allowed to delete comments made by others.", 403);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!comments_post_delete($commentId)) {
|
||||
if (!comments_post_delete($comment)) {
|
||||
echo render_info_or_json($isXHR, 'Failed to delete comment.', 500);
|
||||
break;
|
||||
}
|
||||
|
@ -80,34 +87,11 @@ switch ($_GET['m'] ?? null) {
|
|||
break;
|
||||
}
|
||||
|
||||
echo render_info_or_json($isXHR, 'Comment deleted.');
|
||||
echo json_encode([
|
||||
'comment_id' => (int)$comment,
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'edit':
|
||||
if ($commentId < 1) {
|
||||
echo render_info_or_json($isXHR, 'Missing data.', 400);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$commentPerms['can_edit']) {
|
||||
echo render_info_or_json($isXHR, "You're not allowed to edit comments.", 403);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$commentPerms['can_edit_any']
|
||||
&& !comments_post_check_ownership($commentId, $app->getUserId())) {
|
||||
echo render_info_or_json($isXHR, "You're not allowed to delete comments made by others.", 403);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($redirect) {
|
||||
header('Location: ' . $redirect . '#comment-' . $commentId);
|
||||
break;
|
||||
}
|
||||
|
||||
var_dump($_POST);
|
||||
break;
|
||||
*/
|
||||
case 'create':
|
||||
if (!$commentPerms['can_comment']) {
|
||||
echo render_info_or_json($isXHR, "You're not allowed to post comments.", 403);
|
||||
|
@ -124,10 +108,12 @@ switch ($_GET['m'] ?? null) {
|
|||
|
||||
if (!$category) {
|
||||
echo render_info_or_json($isXHR, 'This comment category doesn\'t exist.', 404);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_null($category['category_locked']) || !$commentPerms['can_lock']) {
|
||||
if (!is_null($category['category_locked']) && !$commentPerms['can_lock']) {
|
||||
echo render_info_or_json($isXHR, 'This comment category has been locked.', 403);
|
||||
break;
|
||||
}
|
||||
|
||||
$commentText = $_POST['comment']['text'] ?? '';
|
||||
|
|
|
@ -55,6 +55,28 @@ function comments_vote_add(int $comment, int $user, ?string $vote): bool
|
|||
return $setVote->execute();
|
||||
}
|
||||
|
||||
function comments_votes_get(int $commentId): array
|
||||
{
|
||||
$getVotes = Database::prepare('
|
||||
SELECT :id as `id`,
|
||||
(
|
||||
SELECT COUNT(`user_id`)
|
||||
FROM `msz_comments_votes`
|
||||
WHERE `comment_id` = `id`
|
||||
AND `comment_vote` = \'Like\'
|
||||
) as `likes`,
|
||||
(
|
||||
SELECT COUNT(`user_id`)
|
||||
FROM `msz_comments_votes`
|
||||
WHERE `comment_id` = `id`
|
||||
AND `comment_vote` = \'Dislike\'
|
||||
) as `dislikes`
|
||||
');
|
||||
$getVotes->bindValue('id', $commentId);
|
||||
$votes = $getVotes->execute() ? $getVotes->fetch(PDO::FETCH_ASSOC) : false;
|
||||
return $votes ? $votes : [];
|
||||
}
|
||||
|
||||
function comments_category_create(string $name): array
|
||||
{
|
||||
$create = Database::prepare('
|
||||
|
@ -71,14 +93,14 @@ function comments_category_create(string $name): array
|
|||
|
||||
function comments_category_lock(int $category, bool $lock): void
|
||||
{
|
||||
$lock = Database::prepare('
|
||||
$setLock = Database::prepare('
|
||||
UPDATE `msz_comments_categories`
|
||||
SET `category_locked` = IF(:lock, NOW(), NULL)
|
||||
WHERE `category_id` = :category
|
||||
');
|
||||
$lock->bindValue('category', $category);
|
||||
$lock->bindValue('lock', $lock ? 1 : 0);
|
||||
$lock->execute();
|
||||
$setLock->bindValue('category', $category);
|
||||
$setLock->bindValue('lock', $lock);
|
||||
$setLock->execute();
|
||||
}
|
||||
|
||||
define('MSZ_COMMENTS_CATEGORY_INFO_QUERY', '
|
||||
|
@ -123,7 +145,7 @@ function comments_category_info($category, bool $createIfNone = false): array
|
|||
define('MSZ_COMMENTS_CATEGORY_QUERY', '
|
||||
SELECT
|
||||
p.`comment_id`, p.`comment_text`, p.`comment_reply_to`,
|
||||
p.`comment_created`, p.`comment_pinned`,
|
||||
p.`comment_created`, p.`comment_pinned`, p.`comment_deleted`,
|
||||
u.`user_id`, u.`username`,
|
||||
COALESCE(u.`user_colour`, r.`role_colour`) as `user_colour`,
|
||||
(
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
method="post" action="/comments.php?m=create"
|
||||
id="comment-{{ reply_mode ? 'reply-' ~ reply_to.comment_id : 'create-' ~ category.category_id }}">
|
||||
<input type="hidden" name="comment[category]" value="{{ category.category_id }}">
|
||||
<input type="hidden" name="csrf" value="{{ csrf_token() }}">
|
||||
|
||||
{% if reply_mode %}
|
||||
<input type="hidden" name="comment[reply]" value="{{ reply_to.comment_id }}">
|
||||
|
@ -21,7 +22,7 @@
|
|||
</div>
|
||||
<textarea
|
||||
class="comment__text input__textarea comment__text--input"
|
||||
name="comment[text]" placeholder="Share your extensive insight..."></textarea>
|
||||
name="comment[text]" placeholder="Share your extensive insights..."></textarea>
|
||||
<div class="comment__actions">
|
||||
{% if not reply_mode %}
|
||||
{% if perms.can_pin %}
|
||||
|
@ -37,163 +38,17 @@
|
|||
</label>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<button class="comment__action comment__action--button comment__action--post">{{ reply_mode ? 'Reply' : 'Post' }}</button>
|
||||
<button class="comment__action comment__action--button comment__action--post">
|
||||
{{ reply_mode ? 'Reply' : 'Post' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro comments_section(comments, category, user, perms) %}
|
||||
<div class="comments">
|
||||
<div class="comments__input">
|
||||
{% if user|default(null) is null %}
|
||||
<div class="comments__notice">
|
||||
Please <a href="/auth.php?m=login" class="comments__notice__link">login</a> to comment.
|
||||
</div>
|
||||
{% elseif category|default(null) is null or perms|default(null) is null %}
|
||||
<div class="comments__notice">
|
||||
Posting new comments here is disabled.
|
||||
</div>
|
||||
{% elseif not perms.can_comment %}
|
||||
<div class="comments__notice">
|
||||
You are not allowed to post comments.
|
||||
</div>
|
||||
{% else %}
|
||||
{% from _self import comments_input %}
|
||||
{{ comments_input(category, user, perms) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<noscript>
|
||||
<div class="comments__javascript">
|
||||
The comments need Javascript to be enabled to function properly, without it functionality is limited.
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
{% if comments|length > 0 %}
|
||||
<div class="comments__listing">
|
||||
{% from _self import comments_entry %}
|
||||
{% for comment in comments %}
|
||||
{{ comments_entry(comment, 1, category, user, perms) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="comments__none">
|
||||
There are no comments yet.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.addEventListener('load', function () {
|
||||
if (typeof commentVote === 'function') { // if this exists, the user is allowed to vote
|
||||
var likeButtons = document.getElementsByClassName('comment__action--like'),
|
||||
dislikeButtons = document.getElementsByClassName('comment__action--dislike');
|
||||
|
||||
for (var i = 0; i < likeButtons.length; i++) // there's gonna be an equal amount of like and dislike buttons
|
||||
{
|
||||
likeButtons[i].href = 'javascript:void(0);';
|
||||
likeButtons[i].onclick = commentVote;
|
||||
dislikeButtons[i].href = 'javascript:void(0);';
|
||||
dislikeButtons[i].onclick = commentVote;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% if perms.can_comment %}
|
||||
<script>
|
||||
var commentPostLock = false;
|
||||
|
||||
function commentPost(form)
|
||||
{
|
||||
console.log(form);
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% if perms.can_vote %}
|
||||
<script>
|
||||
var commentVoteLock = false,
|
||||
commentLikeClass = 'comment__action--like',
|
||||
commentDislikeClass = 'comment__action--dislike',
|
||||
commentVotedClass = 'comment__action--voted';
|
||||
|
||||
// DEBUG THIS IF YOU MAKE MAJOR DOM CHANGES TO COMMENTS
|
||||
function commentVote(ev)
|
||||
{
|
||||
var elem = ev.target,
|
||||
id = elem.parentNode.parentNode.parentNode.parentNode.id.substr(8); // STACK UP
|
||||
|
||||
// the moment we find the id we engage vote lock
|
||||
if (id < 1 || commentVoteLock)
|
||||
return;
|
||||
commentVoteLock = true;
|
||||
|
||||
var originalText = elem.textContent;
|
||||
elem.textContent = '.';
|
||||
|
||||
var isLike = elem.classList.contains(commentLikeClass),
|
||||
isDislike = elem.classList.contains(commentDislikeClass),
|
||||
isIndifferent = elem.classList.contains(commentVotedClass),
|
||||
vote = isIndifferent ? 0 : (isLike ? 1 : -1);
|
||||
|
||||
elem.textContent += '.';
|
||||
|
||||
// find friendo (the other vote button), this'll fuck up if the parent element is fucked with
|
||||
for (var i = 0; i < elem.parentNode.childNodes.length; i++) {
|
||||
var current = elem.parentNode.childNodes[i];
|
||||
if (current.nodeName.toLowerCase() === 'a' && current !== elem) {
|
||||
var friend = current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof friend !== 'object') {
|
||||
console.error('something happened');
|
||||
return;
|
||||
}
|
||||
|
||||
friend.classList.remove(commentVotedClass);
|
||||
|
||||
var friendText = friend.textContent;
|
||||
friend.textContent = '';
|
||||
|
||||
elem.textContent += '.';
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function() {
|
||||
//console.log(this.readyState + ' ' + this.status + ': ' + this.responseText);
|
||||
if (this.readyState !== 4)
|
||||
return;
|
||||
|
||||
elem.textContent = originalText;
|
||||
friend.textContent = friendText;
|
||||
commentVoteLock = false;
|
||||
|
||||
if (vote)
|
||||
elem.classList.add(commentVotedClass);
|
||||
else
|
||||
elem.classList.remove(commentVotedClass);
|
||||
|
||||
var json = JSON.parse(this.responseText),
|
||||
message = json.error || json.message;
|
||||
|
||||
if (message)
|
||||
alert(message);
|
||||
|
||||
console.log(json);
|
||||
};
|
||||
xhr.open('GET', '/comments.php?m=vote&c={0}&v={1}&h={{ csrf_token() }}'.replace('{0}', id).replace('{1}', vote));
|
||||
xhr.setRequestHeader('X-Misuzu-XHR', 'comments');
|
||||
xhr.send();
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro comments_entry(comment, indent, category, user, perms) %}
|
||||
{% if comment.comment_deleted is null or comment.comment_replies|length > 0 %}
|
||||
<div class="comment" id="comment-{{ comment.comment_id }}">
|
||||
<div class="comment__container">
|
||||
<a class="avatar comment__avatar"
|
||||
|
@ -224,20 +79,21 @@
|
|||
{% endspaceless %}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="comment__text">
|
||||
{{ comment.comment_text|nl2br }}
|
||||
<div class="comment__text{{ comment.comment_deleted is null ? '' : ' comment__text--deleted' }}">
|
||||
{{ comment.comment_deleted is null ? comment.comment_text|nl2br : 'deleted' }}
|
||||
</div>
|
||||
{% if comment.comment_deleted is null %}
|
||||
<div class="comment__actions">
|
||||
{% if perms.can_vote %}
|
||||
<a class="comment__action comment__action--link comment__action--like{% if comment.comment_user_vote == 'Like' %} comment__action--voted{% endif %}"
|
||||
href="/comments.php?m=vote&c={{ comment.comment_id }}&v={{ comment.comment_user_vote ? '0' : '1' }}">
|
||||
href="/comments.php?m=vote&c={{ comment.comment_id }}&v={{ comment.comment_user_vote == 'Like' ? '0' : '1' }}&csrf={{ csrf_token() }}">
|
||||
Like
|
||||
{% if comment.comment_likes > 0 %}
|
||||
({{ comment.comment_likes|number_format }})
|
||||
{% endif %}
|
||||
</a>
|
||||
<a class="comment__action comment__action--link comment__action--dislike{% if comment.comment_user_vote == 'Dislike' %} comment__action--voted{% endif %}"
|
||||
href="/comments.php?m=vote&c={{ comment.comment_id }}&v={{ comment.comment_user_vote ? '0' : '-1' }}">
|
||||
href="/comments.php?m=vote&c={{ comment.comment_id }}&v={{ comment.comment_user_vote == 'Dislike' ? '0' : '-1' }}&csrf={{ csrf_token() }}">
|
||||
Dislike
|
||||
{% if comment.comment_dislikes > 0 %}
|
||||
({{ comment.comment_dislikes|number_format }})
|
||||
|
@ -247,10 +103,15 @@
|
|||
{% if perms.can_comment %}
|
||||
<label class="comment__action comment__action--link" for="comment-reply-toggle-{{ comment.comment_id }}">Reply</label>
|
||||
{% endif %}
|
||||
{% if perms.can_delete_any or (comment.user_id == user.user_id and perms.can_delete) %}
|
||||
<a class="comment__action comment__action--link comment__action--hide comment__action--delete"
|
||||
href="/comments.php?m=delete&c={{ comment.comment_id }}&csrf={{ csrf_token() }}">Delete</a>
|
||||
{% endif %}
|
||||
{# if user is not null %}
|
||||
<a class="comment__action comment__action--link comment__action--hide" href="#">Report</a>
|
||||
{% endif #}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -267,4 +128,448 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro comments_section(comments, category, user, perms) %}
|
||||
<div class="comments">
|
||||
<div class="comments__input">
|
||||
{% if user|default(null) is null %}
|
||||
<div class="comments__notice">
|
||||
Please <a href="/auth.php?m=login" class="comments__notice__link">login</a> to comment.
|
||||
</div>
|
||||
{% elseif category|default(null) is null or perms|default(null) is null %}
|
||||
<div class="comments__notice">
|
||||
Posting new comments here is disabled.
|
||||
</div>
|
||||
{% elseif not perms.can_lock and category.category_locked is not null %}
|
||||
<div class="comments__notice">
|
||||
This comment section was locked, <time datetime="{{ category.category_locked|date('c') }}" title="{{ category.category_locked|date('r') }}">{{ category.category_locked|time_diff }}</time>.
|
||||
</div>
|
||||
{% elseif not perms.can_comment %}
|
||||
<div class="comments__notice">
|
||||
You are not allowed to post comments.
|
||||
</div>
|
||||
{% else %}
|
||||
{% from _self import comments_input %}
|
||||
{{ comments_input(category, user, perms) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if perms.can_lock and category.category_locked is not null %}
|
||||
<div class="comments__notice comments__notice--staff">
|
||||
This comment section was locked, <time datetime="{{ category.category_locked|date('c') }}" title="{{ category.category_locked|date('r') }}">{{ category.category_locked|time_diff }}</time>.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<noscript>
|
||||
<div class="comments__javascript">
|
||||
While the comments work fine without Javascript, it is recommended you enable it as it has a lower bandwidth overhead.
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
<div class="comments__listing">
|
||||
{% if comments|length > 0 %}
|
||||
{% from _self import comments_entry %}
|
||||
{% for comment in comments %}
|
||||
{{ comments_entry(comment, 1, category, user, perms) }}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="comments__none">
|
||||
There are no comments yet.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.addEventListener('load', function () {
|
||||
if (typeof commentVote === 'function') { // if this exists, the user is allowed to vote
|
||||
var likeButtons = document.getElementsByClassName('comment__action--like'),
|
||||
dislikeButtons = document.getElementsByClassName('comment__action--dislike');
|
||||
|
||||
for (var i = 0; i < likeButtons.length; i++) // there's gonna be an equal amount of like and dislike buttons
|
||||
{
|
||||
likeButtons[i].href = 'javascript:void(0);';
|
||||
likeButtons[i].onclick = commentVote;
|
||||
dislikeButtons[i].href = 'javascript:void(0);';
|
||||
dislikeButtons[i].onclick = commentVote;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof commentPost === 'function') { // can comment
|
||||
var commentForms = document.getElementsByClassName('comment--input');
|
||||
|
||||
for (var i = 0; i < commentForms.length; i++) {
|
||||
commentForms[i].action = 'javascript:void(0);';
|
||||
commentForms[i].onsubmit = commentPost;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof commentDelete === 'function') { // can delete
|
||||
var commentDeletes = document.getElementsByClassName('comment__action--delete');
|
||||
|
||||
for (var i = 0; i < commentDeletes.length; i++) {
|
||||
commentDeletes[i].onclick = commentDelete;
|
||||
commentDeletes[i].dataset.href = commentDeletes[i].href;
|
||||
commentDeletes[i].href = 'javascript:void(0);';
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% if perms.can_delete %}
|
||||
<script>
|
||||
var commentDeleteLock = false;
|
||||
|
||||
function commentDelete(ev)
|
||||
{
|
||||
if (commentDeleteLock)
|
||||
return;
|
||||
commentDeleteLock = true;
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function () {
|
||||
if (this.readyState !== 4)
|
||||
return;
|
||||
commentDeleteLock = false;
|
||||
|
||||
var json = JSON.parse(this.responseText),
|
||||
message = json.error || json.message;
|
||||
|
||||
if (message)
|
||||
alert(message);
|
||||
else {
|
||||
var elem = document.getElementById('comment-' + json.comment_id);
|
||||
|
||||
if (elem)
|
||||
elem.parentNode.removeChild(elem);
|
||||
}
|
||||
};
|
||||
xhr.open('GET', ev.target.dataset.href);
|
||||
xhr.setRequestHeader('X-Misuzu-XHR', 'comments');
|
||||
xhr.send();
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% if perms.can_comment %}
|
||||
<script>
|
||||
var commentPostLock = false;
|
||||
|
||||
function commentPost(ev)
|
||||
{
|
||||
// the moment we find the id we engage vote lock
|
||||
if (commentPostLock)
|
||||
return;
|
||||
commentPostLock = true;
|
||||
|
||||
var form = ev.target,
|
||||
formData = new FormData;
|
||||
|
||||
for (var i = 0; i < form.length; i++) {
|
||||
var isCheckbox = form[i].type === 'checkbox';
|
||||
if (isCheckbox && !form[i].checked)
|
||||
continue;
|
||||
formData.append(form[i].name, form[i].value || '');
|
||||
|
||||
if (isCheckbox)
|
||||
form[i].checked = false;
|
||||
else if (form[i].type !== 'hidden')
|
||||
form[i].value = '';
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function () {
|
||||
if (this.readyState !== 4)
|
||||
return;
|
||||
|
||||
var json = JSON.parse(this.responseText),
|
||||
message = json.error || json.message;
|
||||
|
||||
if (message)
|
||||
alert(message);
|
||||
else {
|
||||
if (form.classList.contains('comment--reply'))
|
||||
form.parentNode.parentNode.querySelector('label.comment__action').click();
|
||||
commentInsert(json, form);
|
||||
}
|
||||
|
||||
commentPostLock = false;
|
||||
};
|
||||
|
||||
xhr.open('POST', '/comments.php?m=create');
|
||||
xhr.setRequestHeader('X-Misuzu-XHR', 'comments');
|
||||
xhr.send(formData);
|
||||
}
|
||||
|
||||
// this is the biggest doozy of them all, this should create an element identical to comments_entry
|
||||
function commentInsert(comment, form)
|
||||
{
|
||||
var isReply = form.classList.contains('comment--reply'),
|
||||
parent = isReply
|
||||
? form.parentNode
|
||||
: form.parentNode.parentNode.getElementsByClassName('comments__listing')[0],
|
||||
repliesIndent = isReply
|
||||
? (parseInt(parent.classList[1].substr(25)) + 1)
|
||||
: 1;
|
||||
|
||||
// layer 1
|
||||
var commentElement = document.createElement('div');
|
||||
commentElement.className = 'comment';
|
||||
commentElement.id = 'comment-' + comment.comment_id;
|
||||
|
||||
// layer 2
|
||||
var commentContainer = document.createElement('div');
|
||||
commentContainer.className = 'comment__container';
|
||||
commentElement.appendChild(commentContainer);
|
||||
|
||||
var commentReplies = document.createElement('div');
|
||||
commentReplies.className = 'comment__replies comment__replies--indent-' + repliesIndent;
|
||||
commentReplies.id = commentElement.id + '-replies';
|
||||
commentElement.appendChild(commentReplies);
|
||||
|
||||
// container
|
||||
var commentAvatar = document.createElement('a');
|
||||
commentAvatar.className = 'avatar comment__avatar';
|
||||
commentAvatar.href = '/profile.php?u=' + comment.user_id;
|
||||
commentAvatar.style.backgroundImage = 'url(\'/profile.php?m=avatar&u={0}\')'.replace('{0}', comment.user_id);
|
||||
commentContainer.appendChild(commentAvatar);
|
||||
|
||||
var commentContent = document.createElement('div');
|
||||
commentContent.className = 'comment__content';
|
||||
commentContainer.appendChild(commentContent);
|
||||
|
||||
// content
|
||||
var commentInfo = document.createElement('div');
|
||||
commentInfo.className = 'comment__info';
|
||||
commentContent.appendChild(commentInfo);
|
||||
|
||||
var commentText = document.createElement('div');
|
||||
commentText.className = 'comment__text';
|
||||
commentText.textContent = comment.comment_text;
|
||||
commentContent.appendChild(commentText);
|
||||
|
||||
var commentActions = document.createElement('div');
|
||||
commentActions.className = 'comment__actions';
|
||||
commentContent.appendChild(commentActions);
|
||||
|
||||
// info
|
||||
var commentUser = document.createElement('a');
|
||||
commentUser.className = 'comment__user comment__user--link';
|
||||
commentUser.textContent = comment.username;
|
||||
commentUser.href = '/profile?u=' + comment.user_id;
|
||||
commentUser.style.color = comment.user_colour == null || (comment.user_colour & 0x40000000) > 0
|
||||
? 'inherit'
|
||||
: '#' + (comment.user_colour & 0xFFFFFF).toString(16);
|
||||
commentInfo.appendChild(commentUser);
|
||||
|
||||
var commentLink = document.createElement('a');
|
||||
commentLink.className = 'comment__link';
|
||||
commentLink.href = '#' + commentElement.id;
|
||||
commentInfo.appendChild(commentLink);
|
||||
|
||||
var commentTime = document.createElement('time'),
|
||||
commentDate = new Date(comment.comment_created + 'Z');
|
||||
commentTime.className = 'comment__date';
|
||||
commentTime.title = commentDate.toLocaleString();
|
||||
commentTime.dateTime = commentDate.toISOString();
|
||||
commentTime.textContent = timeago().format(commentDate);
|
||||
commentLink.appendChild(commentTime);
|
||||
|
||||
// actions
|
||||
if (typeof commentVote === 'function') {
|
||||
var commentLike = document.createElement('a');
|
||||
commentLike.className = 'comment__action comment__action--link comment__action--like';
|
||||
commentLike.href = 'javascript:void(0);';
|
||||
commentLike.textContent = 'Like';
|
||||
commentLike.onclick = commentVote;
|
||||
commentActions.appendChild(commentLike);
|
||||
|
||||
var commentDislike = document.createElement('a');
|
||||
commentDislike.className = 'comment__action comment__action--link comment__action--dislike';
|
||||
commentDislike.href = 'javascript:void(0);';
|
||||
commentDislike.textContent = 'Dislike';
|
||||
commentDislike.onclick = commentVote;
|
||||
commentActions.appendChild(commentDislike);
|
||||
}
|
||||
|
||||
// if we're executing this it's fairly obvious that we can reply,
|
||||
// so no need to have a permission check on it here
|
||||
var commentReply = document.createElement('label');
|
||||
commentReply.className = 'comment__action comment__action--link';
|
||||
commentReply.htmlFor = 'comment-reply-toggle-' + comment.comment_id;
|
||||
commentReply.textContent = 'Reply';
|
||||
commentActions.appendChild(commentReply);
|
||||
|
||||
// reply section
|
||||
var commentReplyState = document.createElement('input');
|
||||
commentReplyState.id = commentReply.htmlFor;
|
||||
commentReplyState.type = 'checkbox';
|
||||
commentReplyState.className = 'comment__reply-toggle';
|
||||
commentReplies.appendChild(commentReplyState);
|
||||
|
||||
var commentReplyInput = document.createElement('form');
|
||||
commentReplyInput.id = 'comment-reply-' + comment.comment_id;
|
||||
commentReplyInput.className = 'comment comment--input comment--reply';
|
||||
commentReplyInput.method = 'post';
|
||||
commentReplyInput.action = 'javascript:void(0);';
|
||||
commentReplyInput.onsubmit = commentPost;
|
||||
commentReplies.appendChild(commentReplyInput);
|
||||
|
||||
// reply attributes
|
||||
var replyCategory = document.createElement('input');
|
||||
replyCategory.name = 'comment[category]';
|
||||
replyCategory.value = comment.category_id;
|
||||
replyCategory.type = 'hidden';
|
||||
commentReplyInput.appendChild(replyCategory);
|
||||
|
||||
var replyCsrf = document.createElement('input');
|
||||
replyCsrf.name = 'csrf';
|
||||
replyCsrf.value = '{{ csrf_token() }}';
|
||||
replyCsrf.type = 'hidden';
|
||||
commentReplyInput.appendChild(replyCsrf);
|
||||
|
||||
var replyId = document.createElement('input');
|
||||
replyId.name = 'comment[reply]';
|
||||
replyId.value = comment.comment_id;
|
||||
replyId.type = 'hidden';
|
||||
commentReplyInput.appendChild(replyId);
|
||||
|
||||
var replyContainer = document.createElement('div');
|
||||
replyContainer.className = 'comment__container';
|
||||
commentReplyInput.appendChild(replyContainer);
|
||||
|
||||
// reply container
|
||||
var replyAvatar = document.createElement('div');
|
||||
replyAvatar.className = 'avatar comment__avatar';
|
||||
replyAvatar.style.backgroundImage = 'url(\'/profile.php?m=avatar&u={0}\')'.replace('{0}', comment.user_id);
|
||||
replyContainer.appendChild(replyAvatar);
|
||||
|
||||
var replyContent = document.createElement('div');
|
||||
replyContent.className = 'comment__content';
|
||||
replyContainer.appendChild(replyContent);
|
||||
|
||||
// reply content
|
||||
var replyInfo = document.createElement('div');
|
||||
replyInfo.className = 'comment__info';
|
||||
replyContent.appendChild(replyInfo);
|
||||
|
||||
var replyUser = document.createElement('div');
|
||||
replyUser.className = 'comment__user';
|
||||
replyUser.textContent = comment.username;
|
||||
replyUser.style.color = comment.user_colour == null || (comment.user_colour & 0x40000000) > 0
|
||||
? 'inherit'
|
||||
: '#' + (comment.user_colour & 0xFFFFFF).toString(16);
|
||||
replyInfo.appendChild(replyUser);
|
||||
|
||||
var replyText = document.createElement('textarea');
|
||||
replyText.className = 'comment__text input__textarea comment__text--input';
|
||||
replyText.name = 'comment[text]';
|
||||
replyText.placeholder = 'Share your extensive insights...';
|
||||
replyContent.appendChild(replyText);
|
||||
|
||||
var replyActions = document.createElement('div');
|
||||
replyActions.className = 'comment__actions';
|
||||
replyContent.appendChild(replyActions);
|
||||
|
||||
var replyButton = document.createElement('button');
|
||||
replyButton.className = 'comment__action comment__action--button comment__action--post';
|
||||
replyButton.textContent = 'Reply';
|
||||
replyActions.appendChild(replyButton);
|
||||
|
||||
if (isReply)
|
||||
parent.appendChild(commentElement);
|
||||
else
|
||||
parent.insertBefore(commentElement, parent.firstElementChild);
|
||||
|
||||
timeago().render(commentTime);
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% if perms.can_vote %}
|
||||
<script>
|
||||
var commentVoteLock = false,
|
||||
commentLikeClass = 'comment__action--like',
|
||||
commentDislikeClass = 'comment__action--dislike',
|
||||
commentVotedClass = 'comment__action--voted',
|
||||
commentLikeText = 'Like',
|
||||
commentDislikeText = 'Dislike',
|
||||
commentVoteCountSuffix = ' ({0})';
|
||||
|
||||
// DEBUG THIS IF YOU MAKE MAJOR DOM CHANGES TO COMMENTS
|
||||
function commentVote(ev)
|
||||
{
|
||||
var elem = ev.target,
|
||||
id = elem.parentNode.parentNode.parentNode.parentNode.id.substr(8); // STACK UP
|
||||
|
||||
// the moment we find the id we engage vote lock
|
||||
if (id < 1 || commentVoteLock)
|
||||
return;
|
||||
commentVoteLock = true;
|
||||
elem.textContent = '.';
|
||||
|
||||
var isLike = elem.classList.contains(commentLikeClass),
|
||||
isDislike = elem.classList.contains(commentDislikeClass),
|
||||
isIndifferent = elem.classList.contains(commentVotedClass),
|
||||
vote = isIndifferent ? 0 : (isLike ? 1 : -1);
|
||||
|
||||
elem.textContent += '.';
|
||||
|
||||
// find friendo (the other vote button), this'll fuck up if the parent element is fucked with
|
||||
for (var i = 0; i < elem.parentNode.childNodes.length; i++) {
|
||||
var current = elem.parentNode.childNodes[i];
|
||||
if (current.nodeName.toLowerCase() === 'a' && current !== elem) {
|
||||
var friend = current;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof friend !== 'object') {
|
||||
console.error('something happened');
|
||||
return;
|
||||
}
|
||||
|
||||
friend.classList.remove(commentVotedClass);
|
||||
|
||||
friend.textContent = '';
|
||||
|
||||
elem.textContent += '.';
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function () {
|
||||
if (this.readyState !== 4)
|
||||
return;
|
||||
|
||||
if (vote)
|
||||
elem.classList.add(commentVotedClass);
|
||||
else
|
||||
elem.classList.remove(commentVotedClass);
|
||||
|
||||
var json = JSON.parse(this.responseText),
|
||||
message = json.error || json.message;
|
||||
|
||||
if (message)
|
||||
alert(message);
|
||||
|
||||
var likes = json.likes || 0,
|
||||
dislikes = json.dislikes || 0;
|
||||
|
||||
if (isLike) { // somewhat implicitly defined, like will always come before dislike
|
||||
elem.textContent = commentLikeText + (likes > 0 ? commentVoteCountSuffix.replace('{0}', likes.toLocaleString()) : '');
|
||||
friend.textContent = commentDislikeText + (dislikes > 0 ? commentVoteCountSuffix.replace('{0}', dislikes.toLocaleString()) : '');
|
||||
} else {
|
||||
elem.textContent = commentDislikeText + (dislikes > 0 ? commentVoteCountSuffix.replace('{0}', dislikes.toLocaleString()) : '');
|
||||
friend.textContent = commentLikeText + (likes > 0 ? commentVoteCountSuffix.replace('{0}', likes.toLocaleString()) : '');
|
||||
}
|
||||
|
||||
commentVoteLock = false;
|
||||
};
|
||||
xhr.open('GET', '/comments.php?m=vote&c={0}&v={1}&h={{ csrf_token() }}'.replace('{0}', id).replace('{1}', vote));
|
||||
xhr.setRequestHeader('X-Misuzu-XHR', 'comments');
|
||||
xhr.send();
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
|
Loading…
Add table
Reference in a new issue