redzuurdesem/themes/desem-swift-theme/assets/js/index.js

637 lines
18 KiB
JavaScript

function fileClosure(){
// everything in this file should be declared within this closure (function).
// global variables
let hidden;
hidden = 'hidden';
const doc = document.documentElement;
const parentURL = '{{ .Site.BaseURL }}';
const staticman = Object.create(null);
{{ with .Site.Params.staticman -}}
const endpoint = '{{ .endpoint | default "https://staticman3.herokuapp.com" }}';
const gitProvider = '{{ .gitprovider }}';
const username = '{{ .username }}';
const repository = '{{ .repository }}';
const branch = '{{ .branch }}';
// store reCAPTCHA v2 site key and secret
{{ with .recaptcha -}}
staticman.siteKey = '{{ .sitekey }}';
staticman.secret = '{{ .secret }}';
{{ end -}}
{{ end -}}
const translations = {
success: {
title: '{{ i18n "successTitle" }}',
text: '{{ i18n "successMsg" }}',
close: '{{ i18n "close" }}'
},
error: {
title: '{{ i18n "errTitle" }}',
text: '{{ i18n "errMsg" }}',
close: '{{ i18n "close" }}'
},
discard: {
title: '{{ i18n "discardComment" }}',
button: '{{ i18n "discard" }}'
},
submit: '{{ i18n "btnSubmit" }}',
submitted: '{{ i18n "btnSubmitted" }}'
};
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 isMatch(element, selectors) {
if(isObj(element)) {
if(selectors.isArray) {
let matching = selectors.map(function(selector){
return element.matches(selector)
})
return matching.includes(true);
}
return element.matches(selectors)
}
}
(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')) && !url.startsWith(parentURL) ? 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 = '{{ absURL "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');
}
});
let inlineListItems = elems('ol li');
if(inlineListItems) {
inlineListItems.forEach(function(listItem){
let firstChild = listItem.children[0]
let containsHeading = isMatch(firstChild, tags);
containsHeading ? pushClass(listItem, 'align') : false;
})
}
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, 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);
let isWithinCopyIcon = target.closest(`.${copy}`);
if (isCopyIcon || isWithinCopyIcon) {
let icon = isCopyIcon ? isCopyIcon : isWithinCopyIcon;
isInExcerpt = containsClass(icon, postCopy);
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(icon, 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();
});
}
})();
(function postsPager(){
const pager = elem('.pagination');
if (pager) {
pushClass(pager, 'pager');
const pagerItems = elems('li', pager);
const pagerLinks = Array.from(pagerItems).map(function(item){
return item.firstElementChild;
});
pagerLinks.forEach(function(link){
pushClass(link, 'pager_link')
});
pagerItems.forEach(function(item){
pushClass(item, 'pager_item')
});
}
})();
// add new code above this line
}
window.addEventListener('load', fileClosure());