diff --git a/assets/simpletoc-autoscope.js b/assets/simpletoc-autoscope.js new file mode 100644 index 0000000..a99b6df --- /dev/null +++ b/assets/simpletoc-autoscope.js @@ -0,0 +1,135 @@ +(function(){ + function pickContainer(){ + var candidates = []; + function pushAll(sel){ document.querySelectorAll(sel).forEach(function(el){ candidates.push(el); }); } + + pushAll('[role="main"]'); + pushAll('.wp-block-post-content'); + pushAll('article .entry-content'); + pushAll('.entry-content'); + pushAll('main'); + pushAll('.content-area'); + pushAll('#content'); + + var blacklist = ['header','footer','nav','aside','.widget','[aria-hidden="true"]']; + function isBlacklisted(el){ + return blacklist.some(function(sel){ return el.closest(sel); }); + } + function countHeadings(root){ + if(!root || isBlacklisted(root)) return 0; + return root.querySelectorAll('h1,h2,h3,h4,h5,h6').length; + } + + var best = null, bestCount = 0; + candidates.forEach(function(c){ + var n = countHeadings(c); + if(n > bestCount){ best = c; bestCount = n; } + }); + if(!best && countHeadings(document.body) > 0) return document.body; + return best; + } + + function slugify(t){ + return t.trim().toLowerCase() + .replace(/[^\w\s-]/g,'') + .replace(/\s+/g,'-') + .replace(/-+/g,'-') + .slice(0,80); + } + + function buildTOC(container, title){ + var hs = container.querySelectorAll('h1,h2,h3,h4,h5,h6'); + if(!hs.length) return null; + + var current = parseInt(hs[0].tagName.substring(1),10); + var frag = document.createDocumentFragment(); + + if(title){ + var tt = document.createElement('div'); + tt.className = 'simpletoc-title'; + tt.textContent = title; + frag.appendChild(tt); + } + + var root = document.createElement('ul'); + root.className = 'simpletoc-list'; + var stack = [root]; + + hs.forEach(function(h){ + var level = parseInt(h.tagName.substring(1),10); + if(!h.id){ + var id = slugify(h.textContent || 'section'); + var u = id, n = 2; + while(document.getElementById(u)) u = id + '-' + n++; + h.id = u; + } + + if(level > current){ + for(var up=current; uplevel; down--){ + stack.pop(); + } + } + current = level; + + var li = document.createElement('li'); + var a = document.createElement('a'); + a.href = '#' + encodeURIComponent(h.id); + a.textContent = (h.textContent || '').trim(); + li.appendChild(a); + stack[stack.length-1].appendChild(li); + }); + + frag.appendChild(root); + return frag; + } + + function enableSmooth(){ + if(document.getElementById('simpletoc-smooth-style')) return; + var s = document.createElement('style'); + s.id = 'simpletoc-smooth-style'; + s.textContent = 'html{scroll-behavior:smooth}'; + document.head.appendChild(s); + } + + function init(){ + document.querySelectorAll('.simpletoc.simpletoc-autoscope[data-simpletoc-autoscope="1"]').forEach(function(nav){ + var title = nav.getAttribute('data-simpletoc-title') || ''; + var smooth = nav.getAttribute('data-simpletoc-smooth') === '1'; + + var container = pickContainer(); + if(!container){ nav.remove(); return; } + + var built = buildTOC(container, title); + if(!built){ nav.remove(); return; } + + nav.appendChild(built); + + if(smooth){ + enableSmooth(); + nav.addEventListener('click', function(e){ + var a = e.target.closest('a[href^="#"]'); + if(!a) return; + var id = decodeURIComponent(a.getAttribute('href').slice(1)); + var target = document.getElementById(id); + if(target){ + e.preventDefault(); + try{ target.scrollIntoView({behavior:'smooth', block:'start'}); } + catch(err){ window.location.hash = id; } + } + }); + } + }); + } + + if(document.readyState === 'loading'){ + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})(); diff --git a/plugin.php b/plugin.php index 452a0cc..ed9b1b5 100644 --- a/plugin.php +++ b/plugin.php @@ -178,6 +178,26 @@ function add_ids_to_blocks_recursive($blocks) */ function render_callback_simpletoc($attributes) { + // Clientseitiges Auto Scope auf Nicht-Singular Seiten + if ( ! is_singular() ) { + $class = 'wp-block-simpletoc-toc simpletoc simpletoc-autoscope'; + if ( ! empty( $attributes['className'] ) ) { + $class .= ' ' . sanitize_html_class( $attributes['className'] ); + } + $title = ! empty( $attributes['title_text'] ) ? esc_html( trim( $attributes['title_text'] ) ) : ''; + $smooth = ( ! empty( $attributes['add_smooth'] ) || get_option( 'simpletoc_smooth_enabled' ) == 1 ) ? '1' : '0'; + + wp_enqueue_script( + 'simpletoc-autoscope', + plugins_url( 'assets/simpletoc-autoscope.js', __FILE__ ), + array(), + '1.0', + true + ); + + return ''; + } + $is_backend = defined('REST_REQUEST') && REST_REQUEST && 'edit' === filter_input(INPUT_GET, 'context'); $title_text = $attributes['title_text'] ? esc_html(trim($attributes['title_text'])) : __('Table of Contents', 'simpletoc'); $alignclass = !empty($attributes['align']) ? 'align' . $attributes['align'] : '';