* Admin-configurable display locale * Add i18n-js and namespacing * Basic tests and clean up * A few test adjustments * Update vendor cache * Fix a few tests * Fix a few tests * Update app/views/articles/_actions.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update app/views/articles/_comments_actions.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update app/views/articles/_single_story.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update app/views/articles/_single_story.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update app/views/comments/_comment_header.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update app/views/layouts/_sidebar_tags.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update app/views/listings/index.html.erb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update spec/system/homepage/user_visits_homepage_articles_spec.rb Co-authored-by: Michael Kohl <citizen428@dev.to> * Update spec/system/user/view_user_index_spec.rb Co-authored-by: Michael Kohl <citizen428@dev.to> * Alphabetical locale page * Add activerecord custom validation error translations * Add i18n to webpacker * Fix a few tests * Adjust error messages * Add i18n-tasks * Adjust JS to get working with jest * Adjust the way translations are pulled in * Adjust jest tests * Remove time localization * Remove superfluous public js * Add basic tests for i18n application controller * Remove unnecessary content Co-authored-by: Michael Kohl <citizen428@dev.to>
591 lines
23 KiB
Text
591 lines
23 KiB
Text
var iconSmallThread = `<svg width="24" height="24" class="crayons-icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M17 13l-5 6-5-6h3.125c0-3.314 2.798-6 6.25-6 .17 0 .34.006.506.02-1.787.904-3.006 2.705-3.006 4.78V13H17z" /></svg>`;
|
|
|
|
/**
|
|
*
|
|
* A function that triggers all the interactivity when a page with comments are loaded.
|
|
* It calls sub-functions to define functionality for fetching async info, and attaching
|
|
* event listeners related to rich UI interaction and form submission.
|
|
*
|
|
* When comment reaction data needs to be fetched and how we make those choices:
|
|
* When no logged in user only need to fetch reaction numbers if there has been recent comment activity.
|
|
* If no recent comments, we do not need the precision of fetching latest counts async. Static value is almost certainly good enough.
|
|
* Always fetch when user is logged in because we need state of whether the user has reacted.
|
|
*
|
|
* @function initializeCommentsPage
|
|
*/
|
|
|
|
function initializeCommentsPage() {
|
|
if (document.getElementById('comments-container')) {
|
|
toggleCodeOfConduct();
|
|
var userStatus = document.body.getAttribute('data-user-status');
|
|
var commentableId = document.getElementById('comments-container').dataset.commentableId;
|
|
var commentableType = document.getElementById('comments-container').dataset.commentableType;
|
|
var hasRecentCommentActivity = document.getElementById('comments-container').dataset.hasRecentCommentActivity;
|
|
commentableIdList = commentableId.split(",");
|
|
|
|
if (userStatus === 'logged-in' || hasRecentCommentActivity !== 'false') {
|
|
var f = (function() {
|
|
for (var i = 0; i < commentableIdList.length; i++) {
|
|
(function(i){
|
|
var ajaxReq;
|
|
if (window.XMLHttpRequest) {
|
|
ajaxReq = new XMLHttpRequest();
|
|
} else {
|
|
ajaxReq = new ActiveXObject('Microsoft.XMLHTTP');
|
|
}
|
|
ajaxReq.onreadystatechange = function () {
|
|
if (ajaxReq.readyState === XMLHttpRequest.DONE) {
|
|
var responseObj = JSON.parse(ajaxReq.response);
|
|
var reactions = responseObj.reactions;
|
|
var allNodes = document.getElementsByClassName('single-comment-node');
|
|
var publicReactionCounts = responseObj.public_reaction_counts;
|
|
for (var i = 0; i < reactions.length; i++) {
|
|
var buttForComment = document.getElementById('button-for-comment-' + reactions[i].reactable_id);
|
|
if (buttForComment) {
|
|
buttForComment.classList.add('reacted');
|
|
buttForComment.setAttribute('aria-pressed', 'true')
|
|
}
|
|
}
|
|
for (var i = 0; i < publicReactionCounts.length; i++) {
|
|
var buttForComment = document.getElementById('button-for-comment-' + publicReactionCounts[i].id);
|
|
if (buttForComment) {
|
|
var reactionsCountWrapper = buttForComment.querySelector('.reactions-count');
|
|
var reactionsLabelWrapper = buttForComment.querySelector('.reactions-label');
|
|
if (publicReactionCounts[i].count > 0) {
|
|
|
|
if (publicReactionCounts[i].count > 1) {
|
|
reactionsLabelWrapper.innerHTML = ` ${I18n.t('core.like').toLowerCase()}s`;
|
|
} else {
|
|
reactionsLabelWrapper.innerHTML = ` ${I18n.t('core.like').toLowerCase()}`;
|
|
}
|
|
|
|
reactionsCountWrapper.id = 'reactions-count-' + publicReactionCounts[i].id;
|
|
reactionsCountWrapper.innerHTML = publicReactionCounts[i].count;
|
|
reactionsCountWrapper.classList.remove("hidden");
|
|
} else {
|
|
reactionsCountWrapper.classList.add("hidden");
|
|
reactionsCountWrapper.innerHTML = '0';
|
|
}
|
|
|
|
if (!buttForComment.classList.contains("reacted")) {
|
|
buttForComment.setAttribute('aria-pressed', 'false')
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < allNodes.length; i++) {
|
|
if (allNodes[i].dataset.commentAuthorId == responseObj.current_user.id) {
|
|
allNodes[i].dataset.currentUserComment = "true";
|
|
var path = allNodes[i].dataset.path;
|
|
var userActionsEl = allNodes[i].querySelector('.current-user-actions');
|
|
var buttEl = document.getElementById('button-for-comment-' + allNodes[i].dataset.commentId);
|
|
if (userActionsEl && buttEl) {
|
|
userActionsEl.innerHTML = `<li><a href="${ path }/edit" class="crayons-link crayons-link--block" aria-label="Edit this comment">Edit</a></li>
|
|
<li><a data-no-instant href="${ path }/delete_confirm" class="edit-butt crayons-link crayons-link--block" aria-label="Delete this comment">Delete</a></li>`
|
|
userActionsEl.classList.remove('hidden');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
ajaxReq.open("GET", "/reactions?commentable_id=" + commentableIdList[i] + "&commentable_type=" + commentableType, true);
|
|
ajaxReq.send();
|
|
})(i);
|
|
}
|
|
})();
|
|
}
|
|
|
|
var butts = document.getElementsByClassName('reaction-button');
|
|
for (var i = 0; i < butts.length; i++) {
|
|
var butt = butts[i];
|
|
butt.onclick = function (event) {
|
|
var thisButt = this;
|
|
event.preventDefault();
|
|
sendHapticMessage('medium');
|
|
var userStatus = document.body.getAttribute('data-user-status');
|
|
if (userStatus === 'logged-out') {
|
|
showLoginModal();
|
|
return;
|
|
}
|
|
|
|
thisButt.classList.add('reacted');
|
|
thisButt.disabled = true;
|
|
|
|
function successCb(response) {
|
|
var reactionCount = thisButt.querySelector('.reactions-count');
|
|
var reactionLabel = thisButt.querySelector('.reactions-label');
|
|
if (response.result === 'create') {
|
|
thisButt.classList.add('reacted');
|
|
thisButt.setAttribute('aria-pressed', 'true');
|
|
if (reactionCount) {
|
|
reactionCount.innerHTML = parseInt(reactionCount.innerHTML) + 1;
|
|
reactionCount.classList.remove("hidden");
|
|
if(parseInt(reactionCount.innerHTML) == 1) {
|
|
reactionLabel.innerHTML = " like"
|
|
} else if(parseInt(reactionCount.innerHTML) > 1) {
|
|
reactionLabel.innerHTML = " likes"
|
|
}
|
|
}
|
|
} else {
|
|
thisButt.classList.remove('reacted');
|
|
thisButt.setAttribute('aria-pressed', 'false');
|
|
if (reactionCount) {
|
|
reactionCount.innerHTML = parseInt(reactionCount.innerHTML) - 1;
|
|
if(parseInt(reactionCount.innerHTML) == 0) {
|
|
reactionCount.classList.add("hidden");
|
|
reactionLabel.innerHTML = "Like"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var formData = new FormData();
|
|
formData.append('reactable_type', 'Comment');
|
|
formData.append('reactable_id', thisButt.dataset.commentId);
|
|
getCsrfToken()
|
|
.then(sendFetch('reaction-creation', formData))
|
|
.then(function (response) {
|
|
thisButt.disabled = false;
|
|
if (response.status === 200) {
|
|
response.json().then(successCb);
|
|
} else {
|
|
showModalAfterError({
|
|
response,
|
|
element: 'reaction',
|
|
action_ing: 'making',
|
|
action_past: 'made',
|
|
});
|
|
}
|
|
});
|
|
};
|
|
}
|
|
var replyButts = document.getElementsByClassName('toggle-reply-form');
|
|
for (var i = 0; i < replyButts.length; i++) {
|
|
var butt = replyButts[i];
|
|
butt.onclick = function (event) {
|
|
event.preventDefault();
|
|
if (event.target.classList.contains("thread-indication")) {
|
|
return false;
|
|
} else {
|
|
var userStatus = document.body.getAttribute('data-user-status');
|
|
if (userStatus == 'logged-out') {
|
|
showLoginModal();
|
|
return;
|
|
}
|
|
var parentId = event.target.closest('.comment').dataset.commentId;
|
|
var waitingOnCSRF = setInterval(function () {
|
|
var metaTag = document.querySelector("meta[name='csrf-token']");
|
|
if (metaTag) {
|
|
clearInterval(waitingOnCSRF);
|
|
commentWrapper = event.target.closest('.comment__details');
|
|
commentWrapper.classList.add("replying");
|
|
commentWrapper.innerHTML += buildCommentFormHTML(commentableId, commentableType, parentId);
|
|
initializeCommentsPage();
|
|
|
|
setTimeout(function () {
|
|
commentWrapper.getElementsByTagName('textarea')[0].focus();
|
|
}, 30);
|
|
}
|
|
}, 1);
|
|
};
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (document.getElementById('new_comment')) {
|
|
document.getElementById('new_comment').addEventListener('submit', handleCommentSubmit);
|
|
}
|
|
}
|
|
listenForDetailsToggle();
|
|
}
|
|
|
|
function toggleCodeOfConduct() {
|
|
var user = userData();
|
|
if (!user) {
|
|
return;
|
|
}
|
|
var codeOfConduct = user.checked_code_of_conduct
|
|
var checkboxWrapper = document.getElementById('toggle-code-of-conduct-checkbox');
|
|
if (checkboxWrapper && !codeOfConduct) {
|
|
checkboxWrapper.innerHTML = '<input type="checkbox" name="checked_code_of_conduct" class="checkbox" required/>\
|
|
<label for="checked_code_of_conduct">I\'ve read the <a href="/code-of-conduct">code of conduct</a></label>'
|
|
}
|
|
}
|
|
|
|
function handleCommentSubmit(event) {
|
|
event.preventDefault();
|
|
var form = event.target;
|
|
form.classList.add('submitting');
|
|
var textarea = form.getElementsByClassName('comment-textarea')[0];
|
|
if (textarea) {
|
|
textarea.style.height = null;
|
|
textarea.blur();
|
|
}
|
|
var parentComment = document.getElementById("comment-node-" + event.target.dataset.commentId);
|
|
|
|
// as there can be multiple forms rendered in the comments, we need to use querySelector to find descendants
|
|
var commentParentId = form.querySelector("#comment_parent_id");
|
|
var body = JSON.stringify({
|
|
comment: {
|
|
body_markdown: form.getElementsByTagName("textarea")[0].value,
|
|
commentable_id: form.querySelector("#comment_commentable_id").value,
|
|
commentable_type: form.querySelector("#comment_commentable_type").value,
|
|
parent_id: commentParentId ? commentParentId.value : null,
|
|
}
|
|
});
|
|
|
|
getCsrfToken()
|
|
.then(sendFetch('comment-creation', body))
|
|
.then(function (response) {
|
|
if (response.status === 200) {
|
|
response.json().then(function (newComment) {
|
|
var newNode = document.createElement('div');
|
|
newNode.innerHTML = buildCommentHTML(newComment);
|
|
var docBody = document.body
|
|
|
|
var userData = JSON.parse(docBody.getAttribute('data-user'))
|
|
userData.checked_code_of_conduct = true;
|
|
|
|
docBody.dataset.user = JSON.stringify(userData);
|
|
|
|
var checkbox = form.getElementsByClassName('code-of-conduct')[0]
|
|
if (checkbox) {
|
|
checkbox.innerHTML = ""
|
|
}
|
|
|
|
var mainCommentsForm = document.getElementById("new_comment");
|
|
if (parentComment) {
|
|
handleFormClose(event);
|
|
if (newComment.depth > 3) {
|
|
var replyTrigger = parentComment.getElementsByClassName("toggle-reply-form")[0];
|
|
var threadIndicator = `<span class="fs-s inline-flex items-center fs-italic color-base-50 pl-1">${ iconSmallThread }Thread</span>`;
|
|
replyTrigger.classList.replace("inline-flex", "hidden");
|
|
replyTrigger.parentNode.innerHTML += threadIndicator;
|
|
}
|
|
var actionsNode = parentComment.getElementsByClassName("comment__inner")[0];
|
|
actionsNode.parentNode.insertBefore(newNode, actionsNode.nextSibling);
|
|
}
|
|
|
|
else if (mainCommentsForm) {
|
|
var mainCommentsForm = document.getElementById("new_comment");
|
|
mainCommentsForm.classList.remove("submitting");
|
|
mainCommentsForm.classList.remove('preview-open');
|
|
|
|
const commentInputs = [...form.getElementsByClassName("comment-textarea")]
|
|
commentInputs[0].closest('.comment-form').classList.remove('comment-form--initiated');
|
|
|
|
// Clearing out all comment textboxes and resetting their height because
|
|
// there is an additional one generated by the comment
|
|
// mention auto-complete component
|
|
commentInputs.forEach(input => {
|
|
input.value = newComment.comment_template || "";
|
|
input.style.height = null;
|
|
});
|
|
|
|
const preview = document.getElementById("preview-div");
|
|
const togglePreview = document.querySelector('.preview-toggle');
|
|
preview.innerHTML = "";
|
|
togglePreview.innerHTML = "Preview";
|
|
const container = document.getElementById("comment-trees-container");
|
|
container.insertBefore(newNode, container.firstChild);
|
|
}
|
|
else if (document.getElementById("notifications-container")) {
|
|
var newDiv = document.createElement("span")
|
|
newDiv.innerHTML = '<div class="crayons-notice align-center p-2 m-2 crayons-notice--success reply-sent-notice reply-sent-notice" aria-live="polite">Reply sent — <a href="' + newComment.url + '">Check it out</a></div>'
|
|
form.replaceWith(newDiv);
|
|
}
|
|
else {
|
|
window.location.replace(newComment.url)
|
|
}
|
|
updateCommentsCount();
|
|
initializeCommentsPage();
|
|
initializeCommentDate();
|
|
activateRunkitTags();
|
|
})
|
|
} else {
|
|
form.classList.remove('submitting');
|
|
showModalAfterError({
|
|
response,
|
|
element: 'comment',
|
|
action_ing: 'posting',
|
|
action_past: 'posted',
|
|
});
|
|
return false;
|
|
}
|
|
return false;
|
|
});
|
|
return false;
|
|
}
|
|
|
|
function handleFocus(event) {
|
|
handleButtonsActivation(event);
|
|
var userStatus = document.body.getAttribute('data-user-status');
|
|
var area = event.target;
|
|
if (userStatus == 'logged-out') {
|
|
event.preventDefault();
|
|
showLoginModal();
|
|
area.blur();
|
|
} else {
|
|
var form = event.target.closest(".comment-form");
|
|
if (form) {
|
|
form.classList.add("comment-form--initiated");
|
|
}
|
|
handleSizeChange(event);
|
|
window.Forem.initializeMentionAutocompleteTextArea(area);
|
|
}
|
|
}
|
|
|
|
function handleKeyUp(event) {
|
|
handleSizeChange(event);
|
|
handleButtonsActivation(event);
|
|
}
|
|
|
|
// Handler for when Ctrl+Enter OR Command+Enter is pressed
|
|
function handleSubmit(event) {
|
|
// Get user details and extract code of conduct & comment count
|
|
var user = userData();
|
|
if (!user) {
|
|
return;
|
|
}
|
|
|
|
var codeOfConduct = user.checked_code_of_conduct;
|
|
if (codeOfConduct && event.target.value.trim() !== '') {
|
|
event.target.closest('form').querySelector('button[type="submit"]').click();
|
|
}
|
|
}
|
|
|
|
// Handler when Ctrl+B/I OR Command+B/I is pressed
|
|
function handleBoldAndItalic(event) {
|
|
var textArea = event.target;
|
|
|
|
var selection = textArea.value.substring(textArea.selectionStart, textArea.selectionEnd);
|
|
var selectionStart = textArea.selectionStart;
|
|
var surroundingStr = event.keyCode === KEY_CODE_B ? "**" : "_";
|
|
|
|
replaceSelectedText(textArea, `${surroundingStr}${selection}${surroundingStr}`);
|
|
|
|
var selectionStartWithOffset = selectionStart + surroundingStr.length;
|
|
textArea.setSelectionRange(selectionStartWithOffset, selectionStartWithOffset + selection.length);
|
|
}
|
|
|
|
// Handler when Ctrl+K OR Command+K is pressed
|
|
function handleLink(event) {
|
|
var textArea = event.target;
|
|
|
|
var selection = textArea.value.substring(textArea.selectionStart, textArea.selectionEnd);
|
|
var selectionStart = textArea.selectionStart;
|
|
|
|
replaceSelectedText(textArea, `[${selection}](url)`);
|
|
|
|
// start position + length of selection + [](
|
|
var startOffset = selectionStart + selection.length + 3;
|
|
|
|
// start offset + 'url'.length
|
|
var endOffset = startOffset + 3;
|
|
|
|
textArea.setSelectionRange(startOffset, endOffset);
|
|
}
|
|
|
|
function replaceSelectedText(textArea, text) {
|
|
// Chrome and other modern browsers (except FF and IE 8,9,10,11)
|
|
if (document.execCommand('insertText', false, text)) {
|
|
}
|
|
// Firefox (non-standard method)
|
|
else if (typeof textArea.setRangeText === "function") {
|
|
textArea.setRangeText(text);
|
|
}
|
|
|
|
/*
|
|
Disabling IE 8-11 for now as there's no easy way to verify all this
|
|
We can revisit this if it's really needed and find a jQuery plugin to use
|
|
|
|
// IE 8-10
|
|
else if(document.selection) {
|
|
const ieRange = document.selection.createRange();
|
|
ieRange.text = text;
|
|
|
|
// Move cursor after the inserted text
|
|
ieRange.collapse(false); // to the end
|
|
ieRange.select();
|
|
}
|
|
else {
|
|
// Does not support IE 11 yet
|
|
}
|
|
*/
|
|
}
|
|
|
|
var KEY_CODE_B = 66;
|
|
var KEY_CODE_I = 73;
|
|
var KEY_CODE_K = 75;
|
|
var ENTER_KEY_CODE = 13;
|
|
|
|
function handleKeyDown(event) {
|
|
if (Runtime.hasOSSpecificModifier(event)) {
|
|
switch (event.keyCode) {
|
|
case KEY_CODE_B:
|
|
event.preventDefault();
|
|
handleBoldAndItalic(event);
|
|
break;
|
|
case KEY_CODE_I:
|
|
event.preventDefault();
|
|
handleBoldAndItalic(event);
|
|
break;
|
|
case KEY_CODE_K:
|
|
event.preventDefault();
|
|
handleLink(event);
|
|
break;
|
|
case ENTER_KEY_CODE:
|
|
event.preventDefault();
|
|
handleSubmit(event);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
function handleFormClose(event) {
|
|
event.target.closest('.inner-comment').classList.remove("replying");
|
|
event.target.closest('.comment-form').remove();
|
|
initializeCommentsPage();
|
|
}
|
|
|
|
function handleSizeChange(event) {
|
|
var textarea = event.target;
|
|
var oldHeight = parseInt(textarea.style.height.replace('px',''));
|
|
textarea.style.height = textarea.scrollHeight + (textarea.scrollHeight > oldHeight ? 15 : 0) + "px";
|
|
}
|
|
|
|
function handleButtonsActivation(event) {
|
|
var textarea = event.target;
|
|
var commentForm = textarea.closest('.comment-form');
|
|
if (commentForm) {
|
|
var buttons = textarea.closest('.comment-form').getElementsByClassName('js-btn-enable');
|
|
Array.from(buttons).forEach(function(button) {
|
|
button.disabled = textarea.value.length === 0;
|
|
});
|
|
};
|
|
}
|
|
|
|
function validateField(event) {
|
|
// We only need to validate the textarea that is not the comment mention auto-complete component
|
|
const textArea = event.target.form.querySelector('.comment-textarea:not([role=combobox])');
|
|
|
|
if (textArea.value === '') {
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
|
|
function handleChange(event) {
|
|
handleButtonsActivation(event);
|
|
}
|
|
|
|
function generateUploadFormdata(image) {
|
|
var token = document.querySelector("meta[name='csrf-token']").content;
|
|
var formData = new FormData();
|
|
formData.append('authenticity_token', token);
|
|
formData.append('image', image[0]);
|
|
return formData;
|
|
}
|
|
|
|
function handleImageUpload(event, randomIdNumber) {
|
|
var commentableId = document.getElementById('comments-container').dataset.commentableId;
|
|
event.preventDefault();
|
|
document.getElementById('image-upload-' + randomIdNumber).click();
|
|
document.getElementById('image-upload-' + randomIdNumber).onchange = function (e) {
|
|
var image = document.getElementById('image-upload-' + randomIdNumber).files;
|
|
if (image.length > 0) {
|
|
document.getElementById("image-upload-file-label-" + randomIdNumber).style.color = '#888888';
|
|
document.getElementById("image-upload-file-label-" + randomIdNumber).innerHTML = "Uploading...";
|
|
document.getElementById("image-upload-submit-" + randomIdNumber).value = "uploading";
|
|
setTimeout(function () {
|
|
document.getElementById("image-upload-submit-" + randomIdNumber).click(function () { });
|
|
}, 50)
|
|
}
|
|
}
|
|
|
|
document.getElementById("image-upload-submit-" + randomIdNumber).onclick = function (e) {
|
|
e.preventDefault();
|
|
var image = document.getElementById('image-upload-' + randomIdNumber).files;
|
|
if (image.length > 0) {
|
|
getCsrfToken()
|
|
.then(sendFetch("image-upload", generateUploadFormdata(image)))
|
|
.then(function (response) {
|
|
if (response.status === 200) {
|
|
response.json().then(
|
|
function uploadImageCb(json) {
|
|
var address = document.getElementById("uploaded-image-" + randomIdNumber);
|
|
var button = document.getElementById("image-upload-button-" + randomIdNumber);
|
|
var messageContainer = document.getElementById("image-upload-file-label-" + randomIdNumber)
|
|
// button.style.display = "none";
|
|
messageContainer.style.display = "none";
|
|
address.value = json.links[0];
|
|
address.classList.remove("hidden");;
|
|
address.select();
|
|
|
|
var uploadedMessage = 'Uploaded! Paste into editor';
|
|
messageContainer.innerHTML = uploadedMessage;
|
|
messageContainer.style.color = '#00c673';
|
|
messageContainer.style.position = "relative";
|
|
messageContainer.style.top = "5px";
|
|
}
|
|
);
|
|
} else if (response.status === 429) {
|
|
showRateLimitModal({
|
|
response,
|
|
element: 'image',
|
|
action_ing: 'uploading',
|
|
action_past: 'uploaded',
|
|
});
|
|
} else {
|
|
response.json().then(function(responseBody) {
|
|
var errorMessage = responseBody.error || 'Invalid file!';
|
|
document.getElementById("image-upload-file-label-" + randomIdNumber).innerHTML = errorMessage;
|
|
document.getElementById("image-upload-file-label-" + randomIdNumber).style.color = '#e05252';
|
|
document.getElementById("image-upload-submit-" + randomIdNumber).style.display = 'none';
|
|
});
|
|
}
|
|
})
|
|
.catch(function (err) {
|
|
// there's currently no error handling
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
function listenForDetailsToggle() {
|
|
var detailItems = document.querySelectorAll(".js-comment-wrapper");
|
|
for (var i = 0; i < detailItems.length; i++) {
|
|
detailItems[i].addEventListener("toggle", event => {
|
|
var item = event.target;
|
|
var itemSummaryContent = item.getElementsByClassName("js-collapse-comment-content")[0];
|
|
var usernames = item.getElementsByClassName("js-comment-username");
|
|
var number = "";
|
|
if (usernames.length > 1) {
|
|
number = " + " + (usernames.length - 1) + " replies"
|
|
}
|
|
var itemUsername = usernames[0].textContent + number
|
|
if (item.open) {
|
|
itemSummaryContent.innerHTML = "";
|
|
} else {
|
|
itemSummaryContent.innerHTML = itemUsername;
|
|
}
|
|
item.getElementsByTagName("SUMMARY")[0].blur();
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Increment comment, stored in `.js-comments-count`, count by one.
|
|
*/
|
|
function updateCommentsCount() {
|
|
const commentsCountDiv = document.querySelector(".js-comments-count");
|
|
|
|
// if there's nowhere to put the count return early.
|
|
if(!commentsCountDiv) return;
|
|
|
|
const commentsCountData = parseInt(commentsCountDiv.dataset.commentsCount, 10) + 1;
|
|
commentsCountDiv.dataset.commentsCount = commentsCountData;
|
|
commentsCountDiv.innerHTML = `(${commentsCountData})`
|
|
}
|