(function fileClosure(){ // everything in this file should be declared within this closure (function). // global variables let hidden; hidden = 'hidden'; const doc = document.documentElement; const staticman = Object.create(null); const translations = { success: { title: 'Review submitted', text: 'Thanks for your review! It will be shown on the site once it has been approved.', close: 'Close' }, error: { title: 'Error', text: 'Sorry, there was an error with the submission!', close: 'Close' }, discard: { title: 'Discard Comment', button: 'discard' }, submit: 'Submit', submitted: 'Submitted' }; function isObj(obj) { return (obj && typeof obj === 'object' && obj !== null) ? true : false; } function createEl(element = 'div') { return document.createElement(element); } function elem(selector, parent = document){ let elem = parent.querySelector(selector); return elem != false ? elem : false; } function elems(selector, parent = document) { let elems = parent.querySelectorAll(selector); return elems.length ? elems : false; } function pushClass(el, targetClass) { if (isObj(el) && targetClass) { elClass = el.classList; elClass.contains(targetClass) ? false : elClass.add(targetClass); } } function deleteClass(el, targetClass) { if (isObj(el) && targetClass) { elClass = el.classList; elClass.contains(targetClass) ? elClass.remove(targetClass) : false; } } function modifyClass(el, targetClass) { if (isObj(el) && targetClass) { elClass = el.classList; elClass.contains(targetClass) ? elClass.remove(targetClass) : elClass.add(targetClass); } } function containsClass(el, targetClass) { if (isObj(el) && targetClass && el !== document ) { return el.classList.contains(targetClass) ? true : false; } } function isChild(node, parentClass) { let objectsAreValid = isObj(node) && parentClass && typeof parentClass == 'string'; return (objectsAreValid && node.closest(parentClass)) ? true : false; } function elemAttribute(elem, attr, value = null) { if (value) { elem.setAttribute(attr, value); } else { value = elem.getAttribute(attr); return value ? value : false; } } function deleteChars(str, subs) { let newStr = str; if (Array.isArray(subs)) { for (let i = 0; i < subs.length; i++) { newStr = newStr.replace(subs[i], ''); } } else { newStr = newStr.replace(subs, ''); } return newStr; } function isBlank(str) { return (!str || str.trim().length === 0); } (function updateDate() { var date = new Date(); var year = date.getFullYear(); elem('.year').innerHTML = year; })(); (function() { let bar = 'nav_bar-wrap'; let navBar = elem(`.${bar}`); let nav = elem('.nav-body'); let open = 'nav-open'; let exit = 'nav-exit'; let drop = 'nav-drop'; let pop = 'nav-pop'; let navDrop = elem(`.${drop}`); function toggleMenu(){ let menuOpen, menuPulled, status; modifyClass(navDrop, pop); modifyClass(navBar, hidden); menuOpen = containsClass(nav, open); menuPulled = containsClass(nav, exit); status = menuOpen || menuPulled ? true : false; status ? modifyClass(nav, exit) : modifyClass(nav, open); status ? modifyClass(nav, open) : modifyClass(nav, exit); } navBar.addEventListener('click', function() { toggleMenu(); }); elem('.nav-close').addEventListener('click', function() { toggleMenu(); }); elem('.nav-drop').addEventListener('click', function(e) { e.target === this ? toggleMenu() : false; }); })(); function convertToUnderScoreCase(str) { let char, newChar, newStr; newStr = ''; if (typeof str == 'string') { for (let x = 0; x < str.length; x++) { char = str.charAt(x); if (char.match(/^[A-Z]*$/)) { char = char.toLowerCase(); newChar = `_${char}` newStr += newChar; } else { newStr += char; } } return newStr; } } function createModal(children, parent) { let body, modal, title; modal = createEl(); pushClass(modal, 'modal'); body = createEl(); pushClass(body, 'modal_inner'); title = createEl('h3'); pushClass(title, 'modal_title'); body.appendChild(title); // add html specific to modal if (isObj(children)) { if (Array.isArray(children)) { children.map(function(child){ body.appendChild(child); }); } else { body.appendChild(children); } } modal.appendChild(body); parent.append(modal); pushClass(doc, 'modal_show'); } function fillModal(obj) { let el, targetClass, modal; modal = elem('.modal'); const entries = Object.entries(obj) for (const [element, content] of entries) { targetClass = `.${convertToUnderScoreCase(element)}`; el = elem(targetClass, modal); el.innerHTML = content; } } (function comments(){ let comments, form, replyNotice, open; comments = elem('.comments'); form = elem('.form'); button = elem('.form_toggle'); replyNotice = elem('.reply_notice') open = 'form_open'; let successOutput, errorOutput; successOutput = { modalTitle: translations.success.title, modalText: translations.success.text, modalClose: translations.success.close }; errorOutput = { modalTitle: translations.error.title, modalText: translations.error.text, modalClose: translations.error.close }; function feedbackModal() { let body, button, children; body = createEl(); pushClass(body, 'modal_text'); button = createEl(); pushClass(button, 'btn'); pushClass(button, 'modal_close'); children = [ body, button ]; return children; } function confirmModal() { // confirm if you want to exit form let group, button, cancel; group = createEl(); pushClass(group, 'btn_group'); button = createEl(); pushClass(button, 'btn'); pushClass(button, 'modal_close') pushClass(button, 'form_close') cancel = createEl(); pushClass(cancel, 'modal_close') pushClass(cancel, 'btn_close'); pushClass(cancel, 'icon'); group.appendChild(button); group.appendChild(cancel); return group; } function handleForm(form) { function formValues() { // returns an object with form field values let deadWeight, fields, fieldAreas, obj; fieldAreas = elems('.form_input', form); fields = Array.from(fieldAreas); obj = Object.create(null); deadWeight = ['fields', 'options', '[' , ']', 'undefined']; fields.map(function(field) { let key, value; key = deleteChars(field.name, deadWeight); key = convertToUnderScoreCase(key); value = field.value; obj[key] = value; }); return obj; } (function submitForm() { form.addEventListener('submit', function (event) { event.preventDefault(); let fields, recaptchaResponse, submit, url; url = [endpoint, 'v3/entry', gitProvider, username, repository, branch, 'comments'].join('/'); fields = formValues(); submit = elem('.form_submit', form); recaptchaResponse = elem('[name="g-recaptcha-response"]', form); submit.value = translations.submitted; function formActions(info) { showModal(info); submit.value = translations.submit; } let data = { fields: { name: fields.name, email: fields.email, comment: fields.comment, replyID: fields.reply_id, replyName: fields.reply_name, replyThread: fields.reply_thread }, options: { slug: fields.slug } }; if (staticman.secret){ data.options.reCaptcha = {}; data.options.reCaptcha.siteKey = staticman.siteKey; data.options.reCaptcha.secret = staticman.secret; data["g-recaptcha-response"] = recaptchaResponse.value; } fetch(url, { method: "POST", body: JSON.stringify(data), headers: { "Content-Type": "application/json" } }).then(function(res) { if(res.ok) { formActions(successOutput); } else { formActions(errorOutput); } }).catch(function(error) { formActions(errorOutput); console.error('Error:', error); }); }); })(); function getHiddenFields() { let reply_id, reply_name, reply_thread, reply_to, obj; reply_id = elem('.reply_id', form); reply_name = elem('.reply_name', form); reply_thread = elem('.reply_thread', form); reply_to = elem('.reply_to', form); obj = { id: reply_id, name: reply_name, thread: reply_thread, to: reply_to } return obj; } function setReplyValues(trigger) { let comment, id, name, thread; let reply_fields = getHiddenFields(); comment = trigger.parentNode; id = comment.id; name = elem('.comment_name_span', comment); thread = elem('.comment_thread', comment); reply_fields.thread.value = thread.textContent; reply_fields.id.value = id; reply_fields.name.value = name.textContent; reply_fields.to.textContent = name.textContent; } function resetReplyValues() { let reply_fields; reply_fields = getHiddenFields(); const values = Object.entries(reply_fields); for (const [key, element] of values) { if (key == 'to') { element.textContent = ''; } else { element.value = ''; } } } function toggleForm(action = true) { let reply_to, toggle_btn; action = action ? pushClass : deleteClass; toggle_btn = elem('.form_toggle'); action(form, open); action(toggle_btn, hidden); reply_to = getHiddenFields().to.textContent; isBlank(reply_to) ? pushClass(replyNotice, hidden) : deleteClass(replyNotice, hidden) ; } comments.addEventListener('click', function (event){ let confirm, fields, modal, target, obj, formIsEmpty, hiddenValuesEmpty; // buttons let isFormCloseBtn, isFormToggleBtn, isModalCloseBtn, isResetFormBtn, isReplyBt; target = event.target; fields = formValues(); formIsEmpty = isBlank(fields.name) && isBlank(fields.comment) && isBlank(fields.email) ? true : false; hiddenValuesEmpty = isBlank(fields.reply_id) ? true : false; isFormCloseBtn = containsClass(target, 'form_close'); isFormToggleBtn = containsClass(target, 'form_toggle'); isModalCloseBtn = containsClass(target, 'modal_close'); isResetFormBtn = containsClass(target, 'form_reset'); isReplyBtn = containsClass(target, 'reply_btn'); isReplyBtn ? setReplyValues(target) : false; isReplyBtn || isFormToggleBtn ? toggleForm() : false; isFormCloseBtn ? toggleForm(false) : false; if (isFormCloseBtn) { form.reset(); } if (isResetFormBtn) { if (formIsEmpty) { hiddenValuesEmpty ? false : resetReplyValues(); toggleForm(false); } else { obj = { modalTitle: translations.discard.title, modalClose: translations.discard.button } confirm = confirmModal(); createModal(confirm, comments); fillModal(obj); } } if (isModalCloseBtn) { modal = target.closest('.modal'); modal.remove(); deleteClass(doc, 'modal_show'); } }); } form ? handleForm(form) : false; function showModal(obj) { let feedbackBody; feedback = feedbackModal(); createModal(feedback, comments); fillModal(obj); } })(); (function makeExternalLinks(){ let links = elems('a'); if(links) { Array.from(links).forEach(function(link){ let target, rel, blank, noopener, attr1, attr2, url, isExternal; url = elemAttribute(link, 'href'); isExternal = (url && typeof url == 'string' && url.startsWith('http')) && !containsClass(link, 'nav_item') && !isChild(link, '.post_item') && !isChild(link, '.pager') ? true : false; if(isExternal) { target = 'target'; rel = 'rel'; blank = '_blank'; noopener = 'noopener'; attr1 = elemAttribute(link, target); attr2 = elemAttribute(link, noopener); attr1 ? false : elemAttribute(link, target, blank); attr2 ? false : elemAttribute(link, rel, noopener); } }); } })(); let headingNodes = [], results, link, icon, current, id, tags = ['h2', 'h3', 'h4', 'h5', 'h6']; current = document.URL; tags.forEach(function(tag){ results = document.getElementsByTagName(tag); Array.prototype.push.apply(headingNodes, results); }); headingNodes.forEach(function(node){ link = createEl('a'); icon = createEl('img'); icon.src = 'https://h.cowbay.org/images/icons/link.svg'; link.className = 'link'; link.appendChild(icon); id = node.getAttribute('id'); if(id) { link.href = `${current}#${id}`; node.appendChild(link); pushClass(node, 'link_owner'); } }); const copyToClipboard = str => { let copy, selection, selected; copy = createEl('textarea'); copy.value = str; copy.setAttribute('readonly', ''); copy.style.position = 'absolute'; copy.style.left = '-9999px'; selection = document.getSelection(); doc.appendChild(copy); // check if there is any selected content selected = selection.rangeCount > 0 ? selection.getRangeAt(0) : false; copy.select(); document.execCommand('copy'); doc.removeChild(copy); if (selected) { // if a selection existed before copying selection.removeAllRanges(); // unselect existing selection selection.addRange(selected); // restore the original selection } } (function copyHeadingLink() { let deeplink, deeplinks, newLink, parent, target; deeplink = 'link'; deeplinks = elems(`.${deeplink}`); if(deeplinks) { document.addEventListener('click', function(event) { target = event.target; parent = target.parentNode; if (target && containsClass(target, deeplink) || containsClass(parent, deeplink)) { event.preventDefault(); newLink = target.href != undefined ? target.href : target.parentNode.href; copyToClipboard(newLink); } }); } })(); (function copyLinkToShare() { let copy, copied, excerpt, isCopyIcon, isInExcerpt, link, page, postCopy, postLink, target; copy = 'copy'; copied = 'copy_done'; excerpt = 'excerpt'; postCopy = 'post_copy'; postLink = 'post_card'; doc.addEventListener('click', function(event) { target = event.target; isCopyIcon = containsClass(target, copy); isInExcerpt = containsClass(target, postCopy); if (isCopyIcon) { if (isInExcerpt) { link = target.closest(`.${excerpt}`).previousElementSibling; link = containsClass(link, postLink)? elemAttribute(link, 'href') : false; } else { link = window.location.href; } if(link) { copyToClipboard(link); pushClass(target, copied); } } }); })(); (function hideAside(){ let aside, title, posts; aside = elem('.aside'); title = aside ? aside.previousElementSibling : null; if(aside && title.nodeName.toLowerCase() === 'h3') { posts = Array.from(aside.children); posts.length < 1 ? title.remove() : false; } })(); (function goBack() { let backBtn = elem('.btn_back'); let history = window.history; if (backBtn) { backBtn.addEventListener('click', function(){ history.back(); }); } })(); // add new code above this line })();