function initializeCommentsPage() { if (document.getElementById('comments-container')) { toggleCodeOfConduct(); var commentableId = document.getElementById('comments-container').dataset.commentableId; var commentableType = document.getElementById('comments-container').dataset.commentableType; commentableIdList = commentableId.split(","); 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 positiveReactionCounts = responseObj.positive_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'); } } for (var i = 0; i < positiveReactionCounts.length; i++) { var buttForComment = document.getElementById('button-for-comment-' + positiveReactionCounts[i].id); if (buttForComment) { if (positiveReactionCounts[i].count > 0) { if (!document.getElementById('reactions-count-' + positiveReactionCounts[i].id)) { buttForComment.innerHTML = buttForComment.innerHTML + "" + positiveReactionCounts[i].count + ''; } else { document.getElementById('reactions-count-' + positiveReactionCounts[i].id).innerHTML = positiveReactionCounts[i].count; } } } } for (var i = 0; i < allNodes.length; i++) { if (allNodes[i].dataset.commentAuthorId == responseObj.current_user.id) { allNodes[i].dataset.currentUserComment = "true"; var userActionsEl = allNodes[i].children[0].children[2].children[0]; var buttEl = document.getElementById('button-for-comment-' + allNodes[i].dataset.commentId); if (userActionsEl && buttEl) { userActionsEl.className = 'current-user-actions'; userActionsEl.style.display = 'inline-block'; document.getElementById('button-for-comment-' + allNodes[i].dataset.commentId).classList.add('reacted'); } } } } }; 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.getElementsByTagName('body')[0].getAttribute('data-user-status'); if (userStatus === 'logged-out') { showModal('react-to-comment'); return; } thisButt.classList.add('reacted'); thisButt.disabled = true; function successCb(response) { var reactionCountSpan = thisButt.children[2]; if (response.result === 'create') { thisButt.classList.add('reacted'); if (reactionCountSpan) { reactionCountSpan.innerHTML = parseInt(reactionCountSpan.innerHTML) + 1; } } else { thisButt.classList.remove('reacted'); if (reactionCountSpan) { reactionCountSpan.innerHTML = parseInt(reactionCountSpan.innerHTML) - 1; } } } 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); } }); }; } 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.getElementsByTagName('body')[0].getAttribute('data-user-status'); if (userStatus == 'logged-out') { showModal('reply-to-comment'); return; } var actionNode = event.target.parentNode; var parentId = actionNode.dataset.commentId; document.getElementById("button-for-comment-" + actionNode.dataset.commentId).style.zIndex = "5"; var waitingOnCSRF = setInterval(function () { var metaTag = document.querySelector("meta[name='csrf-token']"); if (metaTag) { clearInterval(waitingOnCSRF); actionNode.innerHTML = buildCommentFormHTML(commentableId, commentableType, parentId); setTimeout(function () { actionNode.getElementsByTagName('textarea')[0].focus(); }, 30); } }, 1); // document.getElementById('textarea-for-'+parentId).focus(); }; return false; } } var editButts = document.getElementsByClassName('edit-butt'); for (var i = 0; i < editButts.length; i++) { var butt = editButts[i]; butt.onclick = function () { // event.preventDefault(); // alert("edit clicked!") }; } 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 commentCount = user.number_of_comments var checkboxWrapper = document.getElementById('toggle-code-of-conduct-checkbox') if (checkboxWrapper && !codeOfConduct && commentCount < 1) { checkboxWrapper.innerHTML = '\ ' } } function replaceActionButts(el) { var loggedInActionButts = ""; var wrapper = el.getElementsByClassName("actions")[0] if (el.dataset.currentUserComment == "true") { loggedInActionButts = 'DELETE\ EDIT' } wrapper.innerHTML = '' + loggedInActionButts + 'REPLY'; } function warmNewCommentsArea() { var path = '/stories/warm_comments'+ window.location.pathname window.fetch(path) } function handleCommentSubmit(event) { event.preventDefault(); var form = event.target; form.classList.add('submitting'); var parentComment = document.getElementById("comment-node-" + event.target.dataset.commentId); 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: form.querySelector("#comment_parent_id") ? form.querySelector("#comment_parent_id").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'); if (newComment.status == "comment already exists") { return false; } if (newComment.status == "errors") { alert("There was a problem submitting this comment.") return false; } newNode.innerHTML = buildCommentHTML(newComment); var docBody = document.getElementsByTagName('body')[0] 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) { replaceActionButts(parentComment); if (newComment.depth > 2) { parentComment.getElementsByClassName("toggle-reply-form")[0].innerHTML = "" } var actionsNode = parentComment.getElementsByClassName("inner-comment")[0]; actionsNode.parentNode.insertBefore(newNode, actionsNode.nextSibling); } else if (mainCommentsForm) { var mainCommentsForm = document.getElementById("new_comment"); mainCommentsForm.classList.remove("submitting"); const textArea = document.getElementById("text-area"); textArea.classList = ""; textArea.value = newComment.comment_template || ""; var preview = document.getElementById("preview-div"); preview.classList.add("preview-toggle"); preview.innerHTML = ""; var container = document.getElementById("comment-trees-container"); container.insertBefore(newNode, container.firstChild); } else if (document.getElementById("notifications-container")) { var newDiv = document.createElement("span") newDiv.innerHTML = '
Reply sent — Check it out
' form.replaceWith(newDiv); } else { window.location.replace(newComment.url) } warmNewCommentsArea(); initializeCommentsPage(); initializeCommentDate(); initializeCommentDropdown(); }) } else { response.json().then(function parseError(errorReponse) { form.classList.remove('submitting'); window.alert(errorReponse.error); // eslint-disable-line no-alert return false; }); } return false; }); return false; } function handleFocus(event) { var userStatus = document.getElementsByTagName('body')[0].getAttribute('data-user-status'); var area = event.target; if (userStatus == 'logged-out') { event.preventDefault(); showModal('reply-to-comment'); area.blur(); setTimeout(function () { area.blur(); showModal('reply-to-comment'); }, 100); } else { handleSizeChange(event); } } function handleBlur(event) { setTimeout(function () { var el = document.getElementById('text-area'); if (el.value.length == 0) { el.className = ''; } }, 100); } function handleKeyUp(event) { handleSizeChange(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 commentCount = user.number_of_comments; // var codeOfConduct = user.checked_code_of_conduct; // Code of conduct is false the first time even if the user has accepted it // so we are not using it in the check below // It also seems unnecessary if comment count >= 1 indicates that // it was previously accepted // Ensure that user has commented at least once // and we have a non-empty comment to post if (commentCount >= 1 && event.target.value.trim() !== '') { // get a reference to the submit button for the text area (first level comment vs. reply comment) var parentFormId = event.target.parentElement.parentElement.id || event.target.parentElement.id; var submitButton = document.querySelector('#' + parentFormId + ' input[type="submit"].comment-action-button'); submitButton.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 (event.ctrlKey || event.metaKey) { 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 handleSizeChange(event) { var lines = event.target.value.split(/\r*\n/); var lineCount = lines.length; if (lineCount > 11) { document.getElementById('text-area').className = 'embiggened-max'; } else if (lineCount > 6) { document.getElementById('text-area').className = 'embiggened-more'; } else { document.getElementById('text-area').className = 'embiggened'; } } function validateField(event) { if (document.getElementById('text-area')) { var commentField = document.getElementById('text-area').value; if (commentField == '') { event.preventDefault(); } } } 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.add("showing"); address.select(); var uploadedMessage = 'Uploaded! Paste into editor'; messageContainer.innerHTML = uploadedMessage; messageContainer.style.color = '#00c673'; messageContainer.style.position = "relative" messageContainer.style.top = "5px"; } ); } 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.getElementsByTagName("DETAILS"); for (var i = 0; i < detailItems.length; i++) { detailItems[i].addEventListener("toggle", event => { var item = event.target var itemSummaryContent = item.getElementsByTagName("SPAN")[0] var usernames = item.getElementsByClassName("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(); }); } }