/** * Static shell read-more — preview/rest split; full HTML always in DOM for SEO. * Preview: first N plain-text words. Rest: complete original HTML (collapsed until toggle). * Override per host: data-read-more-words="55" on .nse-read-more-host */ (function () { 'use strict'; var READ_MORE_WORD_LIMIT = 110; function extractPlainText(html) { return String(html) .replace(/<[^>]+>/g, ' ') .replace(/\s+/g, ' ') .trim(); } function countWords(text) { if (!text) return 0; return text.split(/\s+/).filter(Boolean).length; } function truncateToWords(text, limit) { var words = text.split(/\s+/).filter(Boolean); if (words.length <= limit) { return null; } return words.slice(0, limit).join(' ') + '…'; } function escapeHtml(text) { return String(text) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } function uniqueId() { return 'nse-rm-' + Math.random().toString(36).slice(2, 9); } function resolveWordLimit(host) { if (host) { var attr = host.getAttribute('data-read-more-words'); if (attr !== null && attr !== '') { var parsed = parseInt(attr, 10); if (!isNaN(parsed) && parsed > 0) { return Math.min(Math.max(parsed, 10), 200); } } } return READ_MORE_WORD_LIMIT; } /** Split single

with
breaks into multiple paragraphs (mirrors NSE PHP). */ function normalizeParagraphMarkup(html) { html = String(html).trim(); if (!html) return html; var pCount = (html.match(/<\/p>/gi) || []).length; if (pCount >= 2) return html; var pClose = html.toLowerCase().split('

').length - 1; var pm = html.match(/]*>([\s\S]*)<\/p>/i); if (pClose === 1 && pm) { var inner = pm[1]; if (/\s*/i.test(inner)) { var chunks = inner.split(/\s*/i).map(function (c) { return c.trim(); }).filter(Boolean); if (chunks.length >= 2) { return chunks.map(function (c) { return '

' + c + '

'; }).join(''); } } else if ((inner.match(//gi) || []).length >= 2) { var lines = inner.split(/\s*/i).map(function (c) { return c.trim(); }).filter(Boolean); if (lines.length >= 2) { return lines.map(function (c) { return '

' + c + '

'; }).join(''); } } else { var plain = inner.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim(); if (plain.length > 360) { var cut = plain.search(/[.!?]\s+\S/); if (cut > 99 && cut < plain.length - 40) { var a = plain.slice(0, cut + 1).trim(); var b = plain.slice(cut + 1).trim(); if (a && b) { return '

' + escapeHtml(a) + '

' + escapeHtml(b) + '

'; } } } } } return html; } function buildWrappedMarkup(excerpt, fullHtml) { fullHtml = String(fullHtml).trim(); if (!fullHtml) return ''; var uid = uniqueId(); var iconPlus = ''; var iconMinus = ''; var out = '
'; out += excerpt; out += ''; out += '
'; return out; } /** Word-count cutoff — plain-text teaser, full HTML in expandable block (mirrors NSE PHP). */ function wrapReadMoreHtml(html, wordLimit) { html = String(html).trim(); if (!html || html.indexOf('nse-field-read-more') !== -1) return null; html = normalizeParagraphMarkup(html); var plain = extractPlainText(html); if (countWords(plain) <= wordLimit) return null; var teaserText = truncateToWords(plain, wordLimit); if (!teaserText) return null; var excerpt = '

' + escapeHtml(teaserText) + '

'; return buildWrappedMarkup(excerpt, html); } function syncCollapsedState(wrap) { if (!wrap) return; var btn = wrap.querySelector('.nse-field-read-more__btn'); var more = wrap.querySelector('.nse-field-read-more__more'); var label = btn && btn.querySelector('.nse-field-read-more__label'); if (!btn || !more) return; var lm = btn.getAttribute('data-nse-label-more') || 'Read more'; btn.setAttribute('aria-expanded', 'false'); if (label) label.textContent = lm; wrap.classList.remove('nse-field-read-more--expanded'); more.classList.add('nse-field-read-more__more--collapsed'); more.style.maxHeight = ''; more.setAttribute('aria-hidden', 'true'); more.removeAttribute('data-nse-rm-anim'); } function initHosts() { document.querySelectorAll('.nse-read-more-host').forEach(function (host) { if (host.querySelector('.nse-field-read-more')) { syncCollapsedState(host.querySelector('.nse-field-read-more')); return; } var originalHtml = host.innerHTML; var wrapped = wrapReadMoreHtml(originalHtml, resolveWordLimit(host)); if (wrapped) { host.innerHTML = wrapped; syncCollapsedState(host.querySelector('.nse-field-read-more')); } }); } function prefersReducedMotion() { return ( typeof window.matchMedia === 'function' && window.matchMedia('(prefers-reduced-motion: reduce)').matches ); } function onceMaxHeightEnd(el, fn) { function handler(e) { if (e.propertyName !== 'max-height') return; el.removeEventListener('transitionend', handler); fn(); } el.addEventListener('transitionend', handler); } document.addEventListener('click', function (e) { var btn = e.target.closest('.nse-field-read-more__btn'); if (!btn) return; var wrap = btn.closest('.nse-field-read-more'); if (!wrap) return; var more = wrap.querySelector('.nse-field-read-more__more'); if (!more) return; if (more.getAttribute('data-nse-rm-anim') === '1') return; var label = btn.querySelector('.nse-field-read-more__label'); var expanded = btn.getAttribute('aria-expanded') === 'true'; var lm = btn.getAttribute('data-nse-label-more') || 'Read more'; var ll = btn.getAttribute('data-nse-label-less') || 'Read less'; var reduced = prefersReducedMotion(); more.setAttribute('data-nse-rm-anim', '1'); function finish() { more.removeAttribute('data-nse-rm-anim'); } if (expanded) { btn.setAttribute('aria-expanded', 'false'); if (label) label.textContent = lm; wrap.classList.remove('nse-field-read-more--expanded'); if (reduced) { more.classList.add('nse-field-read-more__more--collapsed'); more.style.maxHeight = ''; more.setAttribute('aria-hidden', 'true'); finish(); return; } more.style.maxHeight = more.scrollHeight + 'px'; void more.offsetHeight; more.style.maxHeight = '0px'; onceMaxHeightEnd(more, function () { more.classList.add('nse-field-read-more__more--collapsed'); more.style.maxHeight = ''; more.setAttribute('aria-hidden', 'true'); finish(); }); } else { btn.setAttribute('aria-expanded', 'true'); if (label) label.textContent = ll; wrap.classList.add('nse-field-read-more--expanded'); if (reduced) { more.classList.remove('nse-field-read-more__more--collapsed'); more.style.maxHeight = 'none'; more.setAttribute('aria-hidden', 'false'); finish(); return; } var xh = more.scrollHeight; more.style.maxHeight = '0px'; more.classList.remove('nse-field-read-more__more--collapsed'); more.setAttribute('aria-hidden', 'false'); void more.offsetHeight; more.style.maxHeight = xh + 'px'; onceMaxHeightEnd(more, function () { more.style.maxHeight = 'none'; finish(); }); } }); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initHosts); } else { initHosts(); } })();