mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-23 20:18:00 +01:00
183 lines
5.7 KiB
JavaScript
183 lines
5.7 KiB
JavaScript
/**
|
|
* Comments.
|
|
*/
|
|
|
|
import { $ } from './utils/dom';
|
|
import { filterNode } from './imagesclientside';
|
|
import { fetchHtml } from './utils/requests';
|
|
import { timeAgo } from './timeago';
|
|
|
|
function handleError(response) {
|
|
const errorMessage = '<div>Comment failed to load!</div>';
|
|
|
|
if (!response.ok) {
|
|
return errorMessage;
|
|
}
|
|
return response.text();
|
|
}
|
|
|
|
function commentPosted(response) {
|
|
const commentEditTab = $('#js-comment-form a[data-click-tab="write"]'),
|
|
commentEditForm = $('#js-comment-form'),
|
|
container = document.getElementById('comments'),
|
|
requestOk = response.ok;
|
|
|
|
commentEditTab.click();
|
|
commentEditForm.reset();
|
|
|
|
if (requestOk) {
|
|
response.text().then(text => {
|
|
if (text.includes('<div class="flash flash--warning">')) {
|
|
window.location.reload();
|
|
} else {
|
|
displayComments(container, text);
|
|
}
|
|
});
|
|
} else {
|
|
window.location.reload();
|
|
window.scrollTo(0, 0); // Error message is displayed at the top of the page (flash)
|
|
}
|
|
}
|
|
|
|
function loadParentPost(event) {
|
|
const clickedLink = event.target,
|
|
// Find the comment containing the link that was clicked
|
|
fullComment = clickedLink.closest('article.block'),
|
|
// Look for a potential image and comment ID
|
|
commentMatches = /(\w+)#comment_(\w+)$/.exec(clickedLink.getAttribute('href'));
|
|
|
|
// If the clicked link is already active, just clear the parent comments
|
|
if (clickedLink.classList.contains('active_reply_link')) {
|
|
clearParentPost(clickedLink, fullComment);
|
|
|
|
return true;
|
|
}
|
|
|
|
if (commentMatches) {
|
|
// If the regex matched, get the image and comment ID
|
|
const [, imageId, commentId] = commentMatches;
|
|
|
|
fetchHtml(`/images/${imageId}/comments/${commentId}`)
|
|
.then(handleError)
|
|
.then(data => {
|
|
clearParentPost(clickedLink, fullComment);
|
|
insertParentPost(data, clickedLink, fullComment);
|
|
});
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
function insertParentPost(data, clickedLink, fullComment) {
|
|
// Add the 'subthread' class to the comment with the clicked link
|
|
fullComment.classList.add('subthread');
|
|
|
|
// Insert parent comment
|
|
fullComment.insertAdjacentHTML('beforebegin', data);
|
|
|
|
// Add class subthread and fetched-comment - use separate add()-methods to support IE11
|
|
fullComment.previousSibling.classList.add('subthread');
|
|
fullComment.previousSibling.classList.add('fetched-comment');
|
|
|
|
// Execute timeago on the new comment - it was not present when first run
|
|
timeAgo(fullComment.previousSibling.getElementsByTagName('time'));
|
|
|
|
// Add class active_reply_link to the clicked link
|
|
clickedLink.classList.add('active_reply_link');
|
|
|
|
// Filter images (if any) in the loaded comment
|
|
filterNode(fullComment.previousSibling);
|
|
}
|
|
|
|
function clearParentPost(clickedLink, fullComment) {
|
|
// Remove any previous siblings with the class fetched-comment
|
|
while (fullComment.previousSibling && fullComment.previousSibling.classList.contains('fetched-comment')) {
|
|
fullComment.previousSibling.parentNode.removeChild(fullComment.previousSibling);
|
|
}
|
|
|
|
// Remove class active_reply_link from all links in the comment
|
|
[].slice.call(fullComment.getElementsByClassName('active_reply_link')).forEach(link => {
|
|
link.classList.remove('active_reply_link');
|
|
});
|
|
|
|
// If this full comment isn't a fetched comment, remove the subthread class.
|
|
if (!fullComment.classList.contains('fetched-comment')) {
|
|
fullComment.classList.remove('subthread');
|
|
}
|
|
}
|
|
|
|
function displayComments(container, commentsHtml) {
|
|
container.innerHTML = commentsHtml;
|
|
|
|
// Execute timeago on comments
|
|
timeAgo(document.getElementsByTagName('time'));
|
|
|
|
// Filter images in the comments
|
|
filterNode(container);
|
|
}
|
|
|
|
function loadComments(event) {
|
|
const container = document.getElementById('comments'),
|
|
hasHref = event.target && event.target.getAttribute('href'),
|
|
hasHash = window.location.hash && window.location.hash.match(/#comment_([a-f0-9]+)/),
|
|
getURL =
|
|
hasHref ||
|
|
(hasHash
|
|
? `${container.dataset.currentUrl}?comment_id=${window.location.hash.substring(9, window.location.hash.length)}`
|
|
: container.dataset.currentUrl);
|
|
|
|
fetchHtml(getURL)
|
|
.then(handleError)
|
|
.then(data => {
|
|
displayComments(container, data);
|
|
|
|
// Make sure the :target CSS selector applies to the inserted content
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=98561
|
|
if (hasHash) {
|
|
// eslint-disable-next-line
|
|
window.location = window.location;
|
|
}
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
function setupComments() {
|
|
const comments = document.getElementById('comments'),
|
|
hasHash = window.location.hash && window.location.hash.match(/^#comment_([a-f0-9]+)$/),
|
|
targetOnPage = hasHash ? Boolean($(window.location.hash)) : true;
|
|
|
|
// Load comments over AJAX if we are on a page with element #comments
|
|
if (comments) {
|
|
if (!comments.dataset.loaded || !targetOnPage) {
|
|
// There is no event associated with the initial load, so use false
|
|
loadComments(false);
|
|
} else {
|
|
filterNode(comments);
|
|
}
|
|
}
|
|
|
|
// Define clickable elements and the function to execute on click
|
|
const targets = {
|
|
'article[id*="comment"] .communication__body__text a[href]': loadParentPost,
|
|
'#comments .pagination a[href]': loadComments,
|
|
'#js-refresh-comments': loadComments,
|
|
};
|
|
|
|
document.addEventListener('click', event => {
|
|
if (event.button === 0) {
|
|
// Left-click only
|
|
for (const target in targets) {
|
|
if (event.target && event.target.closest(target)) {
|
|
targets[target](event) && event.preventDefault();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
document.addEventListener('fetchcomplete', event => {
|
|
if (event.target.id === 'js-comment-form') commentPosted(event.detail);
|
|
});
|
|
}
|
|
|
|
export { setupComments };
|