Optional TOC Implementation
This commit is contained in:
+21
-1
@@ -10,7 +10,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( ! defined( 'ZEITFRESSER_VERSION' ) ) {
|
if ( ! defined( 'ZEITFRESSER_VERSION' ) ) {
|
||||||
define( 'ZEITFRESSER_VERSION', '2.2.0' );
|
define( 'ZEITFRESSER_VERSION', '2.3.6' );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! defined( 'DAISY_BLOG_VERSION' ) ) {
|
if ( ! defined( 'DAISY_BLOG_VERSION' ) ) {
|
||||||
@@ -20,6 +20,7 @@ if ( ! defined( 'DAISY_BLOG_VERSION' ) ) {
|
|||||||
require get_template_directory() . '/inc/zeitfresser-helpers.php';
|
require get_template_directory() . '/inc/zeitfresser-helpers.php';
|
||||||
require get_template_directory() . '/inc/legacy-aliases.php';
|
require get_template_directory() . '/inc/legacy-aliases.php';
|
||||||
require get_template_directory() . '/inc/performance-tools.php';
|
require get_template_directory() . '/inc/performance-tools.php';
|
||||||
|
require get_template_directory() . '/inc/zeitfresser-toc.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Theme setup.
|
* Theme setup.
|
||||||
@@ -108,6 +109,25 @@ function zeitfresser_widgets_init() {
|
|||||||
}
|
}
|
||||||
add_action( 'widgets_init', 'zeitfresser_widgets_init' );
|
add_action( 'widgets_init', 'zeitfresser_widgets_init' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue floating TOC assets on single posts.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function zeitfresser_enqueue_toc_assets() {
|
||||||
|
if ( is_singular( 'post' ) && zeitfresser_has_floating_toc() ) {
|
||||||
|
wp_enqueue_script(
|
||||||
|
'zeitfresser-toc',
|
||||||
|
get_template_directory_uri() . '/js/toc.js',
|
||||||
|
array(),
|
||||||
|
ZEITFRESSER_VERSION,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
add_action( 'wp_enqueue_scripts', 'zeitfresser_enqueue_toc_assets', 20 );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return file version using filemtime in production-safe form.
|
* Return file version using filemtime in production-safe form.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -15,3 +15,11 @@ function zeitfresser_get_default_sticky_menu() {
|
|||||||
function zeitfresser_get_default_container_width() {
|
function zeitfresser_get_default_container_width() {
|
||||||
return 1400;
|
return 1400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function zeitfresser_get_default_show_article_toc() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function zeitfresser_get_default_article_toc_min_headlines() {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ function zeitfresser_register_general_customization_section( $wp_customize ) {
|
|||||||
require dirname( __FILE__ ) . '/default-general.php';
|
require dirname( __FILE__ ) . '/default-general.php';
|
||||||
require dirname( __FILE__ ) . '/container-width/container-width.php';
|
require dirname( __FILE__ ) . '/container-width/container-width.php';
|
||||||
require dirname( __FILE__ ) . '/social-links/social-links.php';
|
require dirname( __FILE__ ) . '/social-links/social-links.php';
|
||||||
|
require dirname( __FILE__ ) . '/toc-options.php';
|
||||||
|
|
||||||
require dirname( __FILE__ ) . '/../post-snippet/default-post-snippet.php';
|
require dirname( __FILE__ ) . '/../post-snippet/default-post-snippet.php';
|
||||||
require dirname( __FILE__ ) . '/../post-snippet/excerpt/excerpt.php';
|
require dirname( __FILE__ ) . '/../post-snippet/excerpt/excerpt.php';
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* TOC related general settings.
|
||||||
|
*/
|
||||||
|
|
||||||
|
add_action( 'customize_register', 'zeitfresser_register_article_toc_options' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitize the minimum heading threshold for the article TOC.
|
||||||
|
*
|
||||||
|
* @param mixed $value Submitted control value.
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
function zeitfresser_sanitize_article_toc_min_headlines( $value ) {
|
||||||
|
$value = absint( $value );
|
||||||
|
|
||||||
|
if ( $value < 1 ) {
|
||||||
|
$value = zeitfresser_get_default_article_toc_min_headlines();
|
||||||
|
}
|
||||||
|
|
||||||
|
return min( 50, $value );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register article TOC options in General Options.
|
||||||
|
*
|
||||||
|
* @param WP_Customize_Manager $wp_customize Customizer manager.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function zeitfresser_register_article_toc_options( $wp_customize ) {
|
||||||
|
$article_toc_title = '<hr/><h2>' . esc_html__( 'Article TOC:', 'zeitfresser' ) . '</h2>';
|
||||||
|
|
||||||
|
$wp_customize->add_setting(
|
||||||
|
'article_toc_options_heading',
|
||||||
|
array(
|
||||||
|
'sanitize_callback' => 'wp_kses_post',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$wp_customize->add_control(
|
||||||
|
new Daisy_Blog_Custom_Text(
|
||||||
|
$wp_customize,
|
||||||
|
'article_toc_options_heading',
|
||||||
|
array(
|
||||||
|
'section' => 'daisy_blog_general_customization_section',
|
||||||
|
'label' => $article_toc_title,
|
||||||
|
'priority' => 12,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$wp_customize->add_setting(
|
||||||
|
'show_article_toc',
|
||||||
|
array(
|
||||||
|
'sanitize_callback' => 'zeitfresser_sanitize_checkbox',
|
||||||
|
'default' => zeitfresser_get_default_show_article_toc(),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$wp_customize->add_control(
|
||||||
|
new Graphthemes_Toggle_Control(
|
||||||
|
$wp_customize,
|
||||||
|
'show_article_toc',
|
||||||
|
array(
|
||||||
|
'settings' => 'show_article_toc',
|
||||||
|
'section' => 'daisy_blog_general_customization_section',
|
||||||
|
'label' => esc_html__( 'Show Article TOC', 'zeitfresser' ),
|
||||||
|
'description' => esc_html__( 'Enable the floating article TOC on single posts. Default: enabled.', 'zeitfresser' ),
|
||||||
|
'type' => 'toggle',
|
||||||
|
'priority' => 13,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$wp_customize->add_setting(
|
||||||
|
'article_toc_min_headlines',
|
||||||
|
array(
|
||||||
|
'sanitize_callback' => 'zeitfresser_sanitize_article_toc_min_headlines',
|
||||||
|
'default' => zeitfresser_get_default_article_toc_min_headlines(),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$wp_customize->add_control(
|
||||||
|
'article_toc_min_headlines',
|
||||||
|
array(
|
||||||
|
'settings' => 'article_toc_min_headlines',
|
||||||
|
'type' => 'number',
|
||||||
|
'section' => 'daisy_blog_general_customization_section',
|
||||||
|
'label' => esc_html__( 'Number of Headlines to Start TOC', 'zeitfresser' ),
|
||||||
|
'description' => esc_html__( 'The article TOC is shown only when this number of headings or more is found. Default: 3.', 'zeitfresser' ),
|
||||||
|
'priority' => 14,
|
||||||
|
'input_attrs' => array(
|
||||||
|
'min' => 1,
|
||||||
|
'max' => 50,
|
||||||
|
'step' => 1,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,224 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Floating table of contents helpers.
|
||||||
|
*
|
||||||
|
* @package zeitfresser
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether article TOC output is enabled.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function zeitfresser_show_article_toc() {
|
||||||
|
return (bool) get_theme_mod( 'show_article_toc', zeitfresser_get_default_show_article_toc() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the minimum heading count required before showing the TOC.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
function zeitfresser_get_article_toc_min_headlines() {
|
||||||
|
$threshold = absint( get_theme_mod( 'article_toc_min_headlines', zeitfresser_get_default_article_toc_min_headlines() ) );
|
||||||
|
return max( 1, $threshold );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a processed single post content payload with TOC metadata.
|
||||||
|
*
|
||||||
|
* @param int $post_id Post ID.
|
||||||
|
* @return array{content:string,items:array<int,array<string,mixed>>}
|
||||||
|
*/
|
||||||
|
function zeitfresser_build_toc_payload( $post_id ) {
|
||||||
|
static $cache = array();
|
||||||
|
|
||||||
|
$post_id = (int) $post_id;
|
||||||
|
|
||||||
|
if ( isset( $cache[ $post_id ] ) ) {
|
||||||
|
return $cache[ $post_id ];
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = array(
|
||||||
|
'content' => apply_filters( 'the_content', get_post_field( 'post_content', $post_id ) ),
|
||||||
|
'items' => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( ! $post_id || ! is_singular( 'post' ) || ! zeitfresser_show_article_toc() ) {
|
||||||
|
$cache[ $post_id ] = $payload;
|
||||||
|
return $payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = trim( (string) $payload['content'] );
|
||||||
|
|
||||||
|
if ( '' === $content ) {
|
||||||
|
$cache[ $post_id ] = $payload;
|
||||||
|
return $payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! class_exists( 'DOMDocument' ) ) {
|
||||||
|
$cache[ $post_id ] = $payload;
|
||||||
|
return $payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
libxml_use_internal_errors( true );
|
||||||
|
|
||||||
|
$dom = new DOMDocument();
|
||||||
|
$loaded = $dom->loadHTML(
|
||||||
|
'<?xml encoding="utf-8" ?><div id="zeitfresser-toc-root">' . $content . '</div>',
|
||||||
|
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( ! $loaded ) {
|
||||||
|
libxml_clear_errors();
|
||||||
|
$cache[ $post_id ] = $payload;
|
||||||
|
return $payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
$container = $dom->getElementById( 'zeitfresser-toc-root' );
|
||||||
|
|
||||||
|
if ( ! $container ) {
|
||||||
|
libxml_clear_errors();
|
||||||
|
$cache[ $post_id ] = $payload;
|
||||||
|
return $payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
$index = 1;
|
||||||
|
$toc_items = array();
|
||||||
|
$xpath = new DOMXPath( $dom );
|
||||||
|
$headings = $xpath->query( './/h2 | .//h3 | .//h4', $container );
|
||||||
|
|
||||||
|
if ( $headings instanceof DOMNodeList ) {
|
||||||
|
foreach ( $headings as $heading ) {
|
||||||
|
$text = trim( wp_strip_all_tags( $heading->textContent ) );
|
||||||
|
|
||||||
|
if ( '' === $text ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tag_name = strtolower( $heading->nodeName );
|
||||||
|
$id = $heading->getAttribute( 'id' );
|
||||||
|
|
||||||
|
if ( '' === $id ) {
|
||||||
|
$base_id = sanitize_title( $text );
|
||||||
|
$id = $base_id ? $base_id : 'section-' . $index;
|
||||||
|
|
||||||
|
while ( $dom->getElementById( $id ) ) {
|
||||||
|
$id = $base_id . '-' . $index;
|
||||||
|
$index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$heading->setAttribute( 'id', $id );
|
||||||
|
}
|
||||||
|
|
||||||
|
$toc_items[] = array(
|
||||||
|
'id' => $id,
|
||||||
|
'text' => $text,
|
||||||
|
'level' => (int) substr( $tag_name, 1 ),
|
||||||
|
);
|
||||||
|
|
||||||
|
$index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
libxml_clear_errors();
|
||||||
|
|
||||||
|
if ( count( $toc_items ) < zeitfresser_get_article_toc_min_headlines() ) {
|
||||||
|
$cache[ $post_id ] = array(
|
||||||
|
'content' => zeitfresser_extract_toc_inner_html( $container ),
|
||||||
|
'items' => array(),
|
||||||
|
);
|
||||||
|
return $cache[ $post_id ];
|
||||||
|
}
|
||||||
|
|
||||||
|
$cache[ $post_id ] = array(
|
||||||
|
'content' => zeitfresser_extract_toc_inner_html( $container ),
|
||||||
|
'items' => $toc_items,
|
||||||
|
);
|
||||||
|
|
||||||
|
return $cache[ $post_id ];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract container inner HTML.
|
||||||
|
*
|
||||||
|
* @param DOMNode $node Source node.
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
function zeitfresser_extract_toc_inner_html( $node ) {
|
||||||
|
$html = '';
|
||||||
|
|
||||||
|
if ( ! $node || ! $node->hasChildNodes() ) {
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ( $node->childNodes as $child_node ) {
|
||||||
|
$html .= $node->ownerDocument->saveHTML( $child_node );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the current singular post has a TOC.
|
||||||
|
*
|
||||||
|
* @param int|null $post_id Optional post ID.
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function zeitfresser_has_floating_toc( $post_id = null ) {
|
||||||
|
$post_id = $post_id ? (int) $post_id : get_the_ID();
|
||||||
|
|
||||||
|
if ( ! $post_id ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = zeitfresser_build_toc_payload( $post_id );
|
||||||
|
|
||||||
|
return ! empty( $payload['items'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render floating TOC markup.
|
||||||
|
*
|
||||||
|
* @param int|null $post_id Optional post ID.
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function zeitfresser_render_floating_toc( $post_id = null ) {
|
||||||
|
$post_id = $post_id ? (int) $post_id : get_the_ID();
|
||||||
|
|
||||||
|
if ( ! $post_id ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = zeitfresser_build_toc_payload( $post_id );
|
||||||
|
|
||||||
|
if ( empty( $payload['items'] ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<aside class="zeitfresser-floating-toc" id="zeitfresser-floating-toc" aria-label="<?php echo esc_attr__( 'Table of contents', 'zeitfresser' ); ?>">
|
||||||
|
<div class="zeitfresser-floating-toc__header">
|
||||||
|
<span class="zeitfresser-floating-toc__title"><?php echo esc_html__( 'Content', 'zeitfresser' ); ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="zeitfresser-floating-toc__progress" aria-hidden="true">
|
||||||
|
<span class="zeitfresser-floating-toc__progress-bar" id="zeitfresser-floating-toc-progress"></span>
|
||||||
|
</div>
|
||||||
|
<nav class="zeitfresser-floating-toc__nav">
|
||||||
|
<ol class="zeitfresser-floating-toc__list">
|
||||||
|
<?php foreach ( $payload['items'] as $item ) : ?>
|
||||||
|
<li class="zeitfresser-floating-toc__item level-<?php echo (int) $item['level']; ?>">
|
||||||
|
<a href="#<?php echo esc_attr( $item['id'] ); ?>" data-target="<?php echo esc_attr( $item['id'] ); ?>">
|
||||||
|
<?php echo esc_html( $item['text'] ); ?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
var toc = document.getElementById('zeitfresser-floating-toc');
|
||||||
|
var title = document.querySelector('.zeitfresser-article-heading .page-title, .zeitfresser-article-heading .entry-title, .entry-header .entry-title');
|
||||||
|
var progressBar = document.getElementById('zeitfresser-floating-toc-progress');
|
||||||
|
var nav = toc.querySelector('.zeitfresser-floating-toc__nav');
|
||||||
|
|
||||||
|
if (!toc || !title) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var links = Array.prototype.slice.call(toc.querySelectorAll('a[data-target]'));
|
||||||
|
var desktopQuery = window.matchMedia('(min-width: 1500px)');
|
||||||
|
var stickyTop = 100;
|
||||||
|
var headingOffset = 88;
|
||||||
|
var ticking = false;
|
||||||
|
|
||||||
|
function isDesktop() {
|
||||||
|
return desktopQuery.matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTarget(link) {
|
||||||
|
var id = link.getAttribute('data-target');
|
||||||
|
return id ? document.getElementById(id) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHeadings() {
|
||||||
|
return links.map(function (link) {
|
||||||
|
return {
|
||||||
|
link: link,
|
||||||
|
target: getTarget(link)
|
||||||
|
};
|
||||||
|
}).filter(function (item) {
|
||||||
|
return !!item.target;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncPosition() {
|
||||||
|
if (!isDesktop()) {
|
||||||
|
document.documentElement.style.setProperty('--zeitfresser-toc-top', stickyTop + 'px');
|
||||||
|
document.documentElement.style.setProperty('--zeitfresser-toc-left', '24px');
|
||||||
|
document.documentElement.style.setProperty('--zeitfresser-toc-width', '220px');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var titleRect = title.getBoundingClientRect();
|
||||||
|
var scrollTop = window.scrollY || window.pageYOffset || 0;
|
||||||
|
var contentColumn = document.querySelector('.inside-page .main-wrapper > *:first-child, .inside-page .main-wrapper .primary-content, .inside-page .main-wrapper #primary, .inside-page .main-wrapper main');
|
||||||
|
var sidebar = document.querySelector('.inside-page .main-wrapper > aside, .inside-page .main-wrapper .widget-area, .inside-page .main-wrapper #secondary, .inside-page .main-wrapper .sidebar');
|
||||||
|
var contentRect = contentColumn ? contentColumn.getBoundingClientRect() : titleRect;
|
||||||
|
var sidebarRect = sidebar ? sidebar.getBoundingClientRect() : null;
|
||||||
|
var mirroredGap = 56;
|
||||||
|
|
||||||
|
if (sidebarRect) {
|
||||||
|
mirroredGap = Math.max(Math.round(sidebarRect.left - contentRect.right), 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxWidth = Math.max(Math.round(contentRect.left - mirroredGap - 24), 180);
|
||||||
|
var tocWidth = Math.max(190, Math.min(250, maxWidth));
|
||||||
|
var tocLeft = Math.max(24, Math.round(contentRect.left - mirroredGap - tocWidth));
|
||||||
|
var tocTop = Math.max(stickyTop, Math.round(titleRect.top + scrollTop + 14));
|
||||||
|
|
||||||
|
document.documentElement.style.setProperty('--zeitfresser-toc-top', tocTop + 'px');
|
||||||
|
document.documentElement.style.setProperty('--zeitfresser-toc-left', tocLeft + 'px');
|
||||||
|
document.documentElement.style.setProperty('--zeitfresser-toc-width', tocWidth + 'px');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setActiveLink(id) {
|
||||||
|
links.forEach(function (link) {
|
||||||
|
var active = link.getAttribute('data-target') === id;
|
||||||
|
link.classList.toggle('is-active', active);
|
||||||
|
|
||||||
|
if (active) {
|
||||||
|
link.setAttribute('aria-current', 'true');
|
||||||
|
} else {
|
||||||
|
link.removeAttribute('aria-current');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateProgress() {
|
||||||
|
if (!progressBar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var article = document.querySelector('.single-post .post-content article, .single-post .post-content, article.post, article');
|
||||||
|
if (!article) {
|
||||||
|
progressBar.style.width = '0%';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rect = article.getBoundingClientRect();
|
||||||
|
var total = Math.max(article.offsetHeight - window.innerHeight, 1);
|
||||||
|
var progress = Math.min(Math.max((-rect.top / total) * 100, 0), 100);
|
||||||
|
|
||||||
|
progressBar.style.width = progress + '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateActiveHeading() {
|
||||||
|
var headings = getHeadings();
|
||||||
|
|
||||||
|
if (!headings.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentId = headings[0].target.id;
|
||||||
|
var triggerY = headingOffset + 24;
|
||||||
|
|
||||||
|
headings.forEach(function (item) {
|
||||||
|
if (item.target.getBoundingClientRect().top <= triggerY) {
|
||||||
|
currentId = item.target.id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
setActiveLink(currentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onViewportChange() {
|
||||||
|
if (ticking) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ticking = true;
|
||||||
|
|
||||||
|
window.requestAnimationFrame(function () {
|
||||||
|
syncPosition();
|
||||||
|
updateProgress();
|
||||||
|
updateActiveHeading();
|
||||||
|
ticking = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
links.forEach(function (link) {
|
||||||
|
link.addEventListener('click', function (event) {
|
||||||
|
var target = getTarget(link);
|
||||||
|
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
var top = target.getBoundingClientRect().top + window.scrollY - headingOffset;
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top: top,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
|
||||||
|
setActiveLink(target.id);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (nav) {
|
||||||
|
nav.addEventListener('wheel', function (event) {
|
||||||
|
var canScroll = nav.scrollHeight > nav.clientHeight;
|
||||||
|
|
||||||
|
if (!canScroll) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var atTop = nav.scrollTop <= 0;
|
||||||
|
var atBottom = Math.ceil(nav.scrollTop + nav.clientHeight) >= nav.scrollHeight;
|
||||||
|
|
||||||
|
if ((event.deltaY < 0 && !atTop) || (event.deltaY > 0 && !atBottom)) {
|
||||||
|
event.preventDefault();
|
||||||
|
nav.scrollTop += event.deltaY;
|
||||||
|
}
|
||||||
|
}, { passive: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
syncPosition();
|
||||||
|
updateProgress();
|
||||||
|
updateActiveHeading();
|
||||||
|
|
||||||
|
window.addEventListener('scroll', onViewportChange, { passive: true });
|
||||||
|
window.addEventListener('resize', onViewportChange, { passive: true });
|
||||||
|
});
|
||||||
@@ -17,9 +17,18 @@
|
|||||||
$show_hide_author_block = get_theme_mod( 'post_detail_hide_show_author_block', zeitfresser_get_default_post_detail_author_block() );
|
$show_hide_author_block = get_theme_mod( 'post_detail_hide_show_author_block', zeitfresser_get_default_post_detail_author_block() );
|
||||||
$show_hide_social_share = get_theme_mod( 'post_detail_hide_show_social_share', zeitfresser_get_default_post_detail_social_share() );
|
$show_hide_social_share = get_theme_mod( 'post_detail_hide_show_social_share', zeitfresser_get_default_post_detail_social_share() );
|
||||||
$social_share = get_theme_mod( 'post_detail_social_share_options', zeitfresser_get_default_post_detail_social_share_options() );
|
$social_share = get_theme_mod( 'post_detail_social_share_options', zeitfresser_get_default_post_detail_social_share_options() );
|
||||||
|
$toc_payload = zeitfresser_build_toc_payload( get_the_ID() );
|
||||||
|
$has_floating_toc = ! empty( $toc_payload['items'] );
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<h1 class="page-title"><?php the_title(); ?></h1>
|
<div class="zeitfresser-article-heading">
|
||||||
|
<h1 class="page-title"><?php the_title(); ?></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ( $has_floating_toc ) : ?>
|
||||||
|
<?php zeitfresser_render_floating_toc( get_the_ID() ); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
|
||||||
<div class="single-post">
|
<div class="single-post">
|
||||||
|
|
||||||
@@ -110,7 +119,7 @@
|
|||||||
<article>
|
<article>
|
||||||
|
|
||||||
<div class="inner-article-content">
|
<div class="inner-article-content">
|
||||||
<?php the_content(); ?>
|
<?php echo $toc_payload['content']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
|
|||||||
Reference in New Issue
Block a user