File: //var/www/viitorx.stgviitor.com/wp-content/themes/viitorx/js/blog-single.js
/**
* Blog single: TOC from H2 headings + share links + lightweight scroll spy.
*/
(function () {
'use strict';
function slugify(text) {
return text
.toString()
.trim()
.toLowerCase()
.replace(/\s+/g, '-')
.replace(/[^\w-]+/g, '')
.replace(/--+/g, '-')
.replace(/^-+/, '')
.replace(/-+$/, '');
}
function shareUrl() {
var wrap = document.querySelector('.viitorx-blog-single-page');
return wrap && wrap.getAttribute('data-share-url')
? wrap.getAttribute('data-share-url')
: window.location.href;
}
function buildToc() {
var root = document.getElementById('blog-article-body');
var tocNav = document.getElementById('blog-single-toc');
var empty = document.getElementById('blog-toc-empty');
if (!root || !tocNav) {
return;
}
var headings = root.querySelectorAll('h2, .blog-prose__heading');
if (!headings.length) {
if (empty) {
empty.hidden = false;
}
tocNav.hidden = true;
return;
}
if (empty) {
empty.hidden = true;
}
tocNav.hidden = false;
tocNav.innerHTML = '';
var list = document.createElement('ul');
list.className = 'toc__list';
headings.forEach(function (h, i) {
var id = h.id || slugify(h.textContent) || 'section-' + (i + 1);
if (!h.id) {
h.id = id;
}
var li = document.createElement('li');
li.className = 'toc__item';
var a = document.createElement('a');
a.className = 'toc__link';
a.href = '#' + id;
a.textContent = h.textContent.trim();
li.appendChild(a);
list.appendChild(li);
});
tocNav.appendChild(list);
tocSpy(headings, tocNav.querySelectorAll('.toc__link'));
}
function navOffset() {
var nav = document.getElementById('sticky-nav');
var base = nav ? nav.getBoundingClientRect().height : 88;
return base + 32;
}
function tocSpy(headings, links) {
if (!headings.length || !links.length) {
return;
}
function update() {
var offset = window.scrollY + navOffset();
var current = headings[0].id;
for (var i = headings.length - 1; i >= 0; i--) {
var top = headings[i].getBoundingClientRect().top + window.scrollY;
if (top <= offset) {
current = headings[i].id;
break;
}
}
links.forEach(function (link) {
link.classList.toggle('is-active', link.getAttribute('href') === '#' + current);
});
}
/* Smooth-scroll TOC clicks with nav offset */
links.forEach(function (link) {
link.addEventListener('click', function (e) {
var id = link.getAttribute('href').slice(1);
var target = document.getElementById(id);
if (!target) return;
e.preventDefault();
var top = target.getBoundingClientRect().top + window.scrollY - navOffset();
window.scrollTo({ top: top, behavior: 'smooth' });
history.pushState(null, '', '#' + id);
});
});
window.addEventListener('scroll', update, { passive: true });
update();
}
function wireShare() {
var wrap = document.querySelector('.viitorx-blog-single-page');
if (!wrap) {
return;
}
function copyTextFallback(text, onDone) {
var ta = document.createElement('textarea');
ta.value = text;
ta.setAttribute('readonly', '');
ta.style.position = 'fixed';
ta.style.left = '-9999px';
ta.style.top = '0';
document.body.appendChild(ta);
ta.focus();
ta.select();
try {
var ok = document.execCommand('copy');
document.body.removeChild(ta);
if (ok) {
onDone();
} else {
window.prompt('Copy link:', text);
onDone();
}
} catch (err) {
document.body.removeChild(ta);
window.prompt('Copy link:', text);
onDone();
}
}
function copyTextToClipboard(text, onDone) {
if (navigator.clipboard && window.isSecureContext && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(onDone).catch(function () {
copyTextFallback(text, onDone);
});
return;
}
copyTextFallback(text, onDone);
}
wrap.querySelectorAll('[data-share="copy"]').forEach(function (el) {
el.addEventListener('click', function (e) {
e.preventDefault();
var plain = shareUrl();
function notify() {
var prev = el.getAttribute('aria-label');
el.setAttribute('data-label-original', prev || '');
el.setAttribute('aria-label', 'Link copied');
window.setTimeout(function () {
el.setAttribute('aria-label', el.getAttribute('data-label-original') || prev || '');
}, 2000);
}
copyTextToClipboard(plain, notify);
});
});
}
function init() {
buildToc();
wireShare();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();