Plugin Directory

Changeset 3487767


Ignore:
Timestamp:
03/21/2026 12:39:03 PM (11 days ago)
Author:
muki
Message:

Release 1.0.7: Fix TOC overflow with scrollbar, remove console.log, scope anchor handler, consolidate settings, fix regex bug

Location:
muki-floating-toc
Files:
8 edited
14 copied

Legend:

Unmodified
Added
Removed
  • muki-floating-toc/tags/1.0.7/includes/class-muki-floating-toc.php

    r3355807 r3487767  
    1717    public static function init() {
    1818        // Load default settings
    19         self::$settings = array(
    20             'position_left' => true,
    21             'default_pin' => false,
    22             'auto_display' => true,
    23             'heading_levels' => array('h2', 'h3', 'h4', 'h5', 'h6'),
    24             'exclude_selectors' => '.single-author-box-container, .author-box, .comment-respond',
    25             'fixed_header_height' => 0,
    26             'custom_content_selector' => ''
    27         );
     19        self::$settings = muki_floating_toc_get_defaults();
    2820       
    2921        // Add settings page
     
    318310        // Further restrictive regex to allow only valid CSS selector characters
    319311        // Allows: a-z, A-Z, 0-9, #, ., ,, -, _, [, ], =, "
    320         $selectors = preg_replace('/[^\w\s#.,-_\[\]="]/', '', $selectors);
     312        $selectors = preg_replace('/[^\w\s#.,_\[\]=":-]/', '', $selectors);
    321313
    322314        return $selectors;
  • muki-floating-toc/tags/1.0.7/muki-floating-toc.php

    r3355807 r3487767  
    33 * Plugin Name: Muki Floating TOC
    44 * Description: Add a floating TOC on the left or right side of articles, following scrolling and fixed at appropriate positions.
    5  * Version: 1.0.6
     5 * Version: 1.0.7
    66 * Author: Muki Wu
    77 * Author URI: https://muki.tw
     
    2020
    2121/**
    22  * Load plugin text domain for internationalization
    23  */
    24 function muki_floating_toc_load_textdomain() {
    25     load_plugin_textdomain(
    26         'muki-floating-toc',
    27         false,
    28         dirname(plugin_basename(__FILE__)) . '/languages/'
    29     );
    30 }
    31 add_action('plugins_loaded', 'muki_floating_toc_load_textdomain');
    32 
    33 // Register scripts and styles
    34 function muki_floating_toc_scripts() {
    35     // Only load on single posts
    36     if (is_single()) {
    37         wp_enqueue_style(
    38             'muki-floating-toc-style',
    39             plugin_dir_url(__FILE__) . 'src/css/muki-floating-toc.css',
    40             array(),
    41             '1.0.6'
    42         );
    43        
    44         wp_enqueue_script(
    45             'muki-floating-toc-script',
    46             plugin_dir_url(__FILE__) . 'src/js/muki-floating-toc.js',
    47             array('jquery'),
    48             '1.0.6',
    49             true
    50         );
    51 
    52         // Get settings
    53         $settings = get_option('muki_floating_toc_settings', array(
    54             'position_left' => true,
    55             'default_pin' => false,
    56             'auto_display' => true,
    57             'heading_levels' => array('h2', 'h3', 'h4', 'h5', 'h6'),
    58             'exclude_selectors' => '.single-author-box-container, .author-box, .comment-respond',
    59             'fixed_header_height' => 0,
    60             'custom_content_selector' => ''
    61         ));
    62 
    63         $default_selector = '.entry-content, article[class*="post-"], .post, .type-post, .page, .type-page';
    64        
    65         // if custom_content_selector has value, use it first
    66         $content_selector = !empty($settings['custom_content_selector']) ? $settings['custom_content_selector'] : $default_selector;
    67 
    68         // Pass settings to JavaScript
    69         wp_localize_script(
    70             'muki-floating-toc-script',
    71             'muki_floating_toc_settings',
    72             array(
    73                 'selectorContent' => $content_selector,
    74                 'positionLeft' => isset($settings['position_left']) ? (bool)$settings['position_left'] : true,
    75                 'defaultPin' => isset($settings['default_pin']) ? (bool)$settings['default_pin'] : false,
    76                 'excludeSelectors' => isset($settings['exclude_selectors']) ? $settings['exclude_selectors'] : '.single-author-box-container',
    77                 'fixedHeaderHeight' => isset($settings['fixed_header_height']) ? intval($settings['fixed_header_height']) : 0,
    78                 'headingLevels' => isset($settings['heading_levels']) ? $settings['heading_levels'] : array('h2', 'h3', 'h4')
    79             )
    80         );
    81     }
    82 }
    83 add_action('wp_enqueue_scripts', 'muki_floating_toc_scripts');
    84 
    85 /**
    86  * Add floating TOC HTML to the footer
    87  * No longer using the_content filter to avoid content positioning issues
    88  */
    89 function muki_floating_toc_add_to_footer() {
    90     // Only add on single posts
    91     if (!is_single()) {
    92         return;
    93     }
    94    
    95     // Get settings to check if auto display is enabled
    96     $settings = get_option('muki_floating_toc_settings', array(
     22 * Get plugin default settings
     23 */
     24function muki_floating_toc_get_defaults() {
     25    return array(
    9726        'position_left' => true,
    9827        'default_pin' => false,
     
    10231        'fixed_header_height' => 0,
    10332        'custom_content_selector' => ''
    104     ));
    105    
    106     // Only auto display if setting is enabled
    107     if (!isset($settings['auto_display']) || !$settings['auto_display']) {
    108         return;
    109     }
    110    
    111     // Create floating TOC HTML
    112     $toc_html = muki_floating_toc_get_html();
    113    
    114     echo wp_kses_post($toc_html);
    115 }
    116 add_action('wp_footer', 'muki_floating_toc_add_to_footer', 999); // Increase priority to ensure it loads last
    117 
    118 /**
    119  * Add Dashicons support
    120  */
    121 function muki_floating_toc_enqueue_dashicons() {
    122     wp_enqueue_style('dashicons');
    123 }
    124 add_action('wp_enqueue_scripts', 'muki_floating_toc_enqueue_dashicons');
    125 
    126 /**
    127  * Manual TOC display function for theme developers
    128  * This allows developers to place the TOC anywhere in their template files
    129  */
    130 function muki_floating_toc_display() {
    131     static $displayed = false;
    132    
    133     // Prevent multiple displays
    134     if ($displayed) {
    135         return;
    136     }
    137    
    138     // Only work on single posts or pages
    139     if (!is_single() && !is_page()) {
    140         return;
    141     }
    142    
    143     // Ensure scripts and styles are loaded
    144     muki_floating_toc_enqueue_assets();
    145    
    146     // Mark as displayed
    147     $displayed = true;
    148    
    149     // Get the TOC HTML
    150     $toc_html = muki_floating_toc_get_html();
    151    
    152     echo wp_kses_post($toc_html);
    153 }
    154 
    155 /**
    156  * Enqueue assets for manual display
    157  */
    158 function muki_floating_toc_enqueue_assets() {
    159     if (!wp_style_is_enqueued('muki-floating-toc-style')) {
    160         wp_enqueue_style(
    161             'muki-floating-toc-style',
    162             plugin_dir_url(__FILE__) . 'src/css/muki-floating-toc.css',
    163             array(),
    164             '1.0.6'
    165         );
    166     }
    167    
    168     if (!wp_script_is_enqueued('muki-floating-toc-script')) {
    169         wp_enqueue_script(
    170             'muki-floating-toc-script',
    171             plugin_dir_url(__FILE__) . 'src/js/muki-floating-toc.js',
    172             array('jquery'),
    173             '1.0.6',
    174             true
    175         );
    176 
    177         // Get settings and localize script
    178         $settings = get_option('muki_floating_toc_settings', array(
    179             'position_left' => true,
    180             'default_pin' => false,
    181             'auto_display' => true,
    182             'heading_levels' => array('h2', 'h3', 'h4', 'h5', 'h6'),
    183             'exclude_selectors' => '.single-author-box-container, .author-box, .comment-respond',
    184             'fixed_header_height' => 0,
    185             'custom_content_selector' => ''
    186         ));
    187 
    188         $default_selector = '.entry-content, article[class*="post-"], .post, .type-post, .page, .type-page';
    189         $content_selector = !empty($settings['custom_content_selector']) ? $settings['custom_content_selector'] : $default_selector;
    190 
    191         wp_localize_script(
    192             'muki-floating-toc-script',
    193             'muki_floating_toc_settings',
    194             array(
    195                 'selectorContent' => $content_selector,
    196                 'positionLeft' => isset($settings['position_left']) ? (bool)$settings['position_left'] : true,
    197                 'defaultPin' => isset($settings['default_pin']) ? (bool)$settings['default_pin'] : false,
    198                 'excludeSelectors' => isset($settings['exclude_selectors']) ? $settings['exclude_selectors'] : '.single-author-box-container',
    199                 'fixedHeaderHeight' => isset($settings['fixed_header_height']) ? intval($settings['fixed_header_height']) : 0,
    200                 'headingLevels' => isset($settings['heading_levels']) ? $settings['heading_levels'] : array('h2', 'h3', 'h4')
    201             )
    202         );
    203     }
    204    
    205     // Ensure dashicons are loaded
    206     wp_enqueue_style('dashicons');
    207 }
    208 
    209 /**
    210  * Get TOC HTML structure
    211  */
    212 function muki_floating_toc_get_html() {
    213     $toc_html = '<div id="muki-floating-toc" class="muki-floating-toc" aria-label="Article Table of Contents">';
    214     $toc_html .= '<div class="muki-toc-toolbar">';
    215     $toc_html .= '<button class="muki-toc-pin-button" title="Pin TOC"><span class="dashicons dashicons-admin-post"></span></button>';
    216     $toc_html .= '</div>';
    217     $toc_html .= '</div>';
    218    
    219     return $toc_html;
    220 }
    221 
    222 /**
    223  * Shortcode handler for [muki_floating_toc] 
    224  * This allows users to place TOC anywhere in post content using shortcode
    225  */
    226 function muki_floating_toc_shortcode($atts = array()) {
    227     // Only work on single posts or pages
    228     if (!is_single() && !is_page()) {
    229         return '';
    230     }
    231    
    232     // Prevent multiple displays
    233     static $shortcode_used = false;
    234     if ($shortcode_used) {
    235         return '<p><em>' . esc_html__('Note: TOC shortcode can only be used once per page.', 'muki-floating-toc') . '</em></p>';
    236     }
    237     $shortcode_used = true;
    238    
    239     // Parse shortcode attributes
    240     $atts = shortcode_atts(array(), $atts, 'muki_floating_toc');
    241    
    242     // Mark that shortcode was used and enqueue assets in footer
    243     add_action('wp_footer', 'muki_floating_toc_enqueue_shortcode_assets', 5);
    244    
    245     // Return simple HTML structure - JavaScript will build the TOC
    246     return '<div id="muki-floating-toc" class="muki-floating-toc" aria-label="Article Table of Contents">
    247         <div class="muki-toc-toolbar">
    248             <button class="muki-toc-pin-button" title="Pin TOC"><span class="dashicons dashicons-admin-post"></span></button>
    249         </div>
    250     </div>';
    251 }
    252 
    253 /**
    254  * Enqueue assets specifically for shortcode usage
    255  */ 
    256 function muki_floating_toc_enqueue_shortcode_assets() {
    257     // Enqueue styles
    258     wp_enqueue_style(
    259         'muki-floating-toc-style',
    260         plugin_dir_url(__FILE__) . 'src/css/muki-floating-toc.css',
    261         array(),
    262         '1.0.6'
    263     );
    264    
    265     // Enqueue scripts
    266     wp_enqueue_script(
    267         'muki-floating-toc-script',
    268         plugin_dir_url(__FILE__) . 'src/js/muki-floating-toc.js',
    269         array('jquery'),
    270         '1.0.6',
    271         true
    272     );
    273 
    274     // Get settings
    275     $settings = get_option('muki_floating_toc_settings', array(
    276         'position_left' => true,
    277         'default_pin' => false,
    278         'auto_display' => true,
    279         'heading_levels' => array('h2', 'h3', 'h4', 'h5', 'h6'),
    280         'exclude_selectors' => '.single-author-box-container, .author-box, .comment-respond',
    281         'fixed_header_height' => 0,
    282         'custom_content_selector' => ''
    283     ));
    284 
     33    );
     34}
     35
     36/**
     37 * Get plugin settings with defaults
     38 */
     39function muki_floating_toc_get_settings() {
     40    return get_option('muki_floating_toc_settings', muki_floating_toc_get_defaults());
     41}
     42
     43/**
     44 * Localize script with plugin settings
     45 */
     46function muki_floating_toc_localize_settings() {
     47    $settings = muki_floating_toc_get_settings();
    28548    $default_selector = '.entry-content, article[class*="post-"], .post, .type-post, .page, .type-page';
    28649    $content_selector = !empty($settings['custom_content_selector']) ? $settings['custom_content_selector'] : $default_selector;
    28750
    288     // Localize script
    28951    wp_localize_script(
    29052        'muki-floating-toc-script',
     
    29961        )
    30062    );
    301    
     63}
     64
     65/**
     66 * Load plugin text domain for internationalization
     67 */
     68function muki_floating_toc_load_textdomain() {
     69    load_plugin_textdomain(
     70        'muki-floating-toc',
     71        false,
     72        dirname(plugin_basename(__FILE__)) . '/languages/'
     73    );
     74}
     75add_action('plugins_loaded', 'muki_floating_toc_load_textdomain');
     76
     77// Register scripts and styles
     78function muki_floating_toc_scripts() {
     79    // Only load on single posts
     80    if (is_single()) {
     81        wp_enqueue_style(
     82            'muki-floating-toc-style',
     83            plugin_dir_url(__FILE__) . 'src/css/muki-floating-toc.css',
     84            array(),
     85            '1.0.7'
     86        );
     87       
     88        wp_enqueue_script(
     89            'muki-floating-toc-script',
     90            plugin_dir_url(__FILE__) . 'src/js/muki-floating-toc.js',
     91            array('jquery'),
     92            '1.0.7',
     93            true
     94        );
     95
     96        // Pass settings to JavaScript
     97        muki_floating_toc_localize_settings();
     98    }
     99}
     100add_action('wp_enqueue_scripts', 'muki_floating_toc_scripts');
     101
     102/**
     103 * Add floating TOC HTML to the footer
     104 * No longer using the_content filter to avoid content positioning issues
     105 */
     106function muki_floating_toc_add_to_footer() {
     107    // Only add on single posts
     108    if (!is_single()) {
     109        return;
     110    }
     111   
     112    // Get settings to check if auto display is enabled
     113    $settings = muki_floating_toc_get_settings();
     114   
     115    // Only auto display if setting is enabled
     116    if (!isset($settings['auto_display']) || !$settings['auto_display']) {
     117        return;
     118    }
     119   
     120    // Create floating TOC HTML
     121    $toc_html = muki_floating_toc_get_html();
     122   
     123    echo wp_kses_post($toc_html);
     124}
     125add_action('wp_footer', 'muki_floating_toc_add_to_footer', 999); // Increase priority to ensure it loads last
     126
     127/**
     128 * Add Dashicons support
     129 */
     130function muki_floating_toc_enqueue_dashicons() {
     131    wp_enqueue_style('dashicons');
     132}
     133add_action('wp_enqueue_scripts', 'muki_floating_toc_enqueue_dashicons');
     134
     135/**
     136 * Manual TOC display function for theme developers
     137 * This allows developers to place the TOC anywhere in their template files
     138 */
     139function muki_floating_toc_display() {
     140    static $displayed = false;
     141   
     142    // Prevent multiple displays
     143    if ($displayed) {
     144        return;
     145    }
     146   
     147    // Only work on single posts or pages
     148    if (!is_single() && !is_page()) {
     149        return;
     150    }
     151   
     152    // Ensure scripts and styles are loaded
     153    muki_floating_toc_enqueue_assets();
     154   
     155    // Mark as displayed
     156    $displayed = true;
     157   
     158    // Get the TOC HTML
     159    $toc_html = muki_floating_toc_get_html();
     160   
     161    echo wp_kses_post($toc_html);
     162}
     163
     164/**
     165 * Enqueue assets for manual display
     166 */
     167function muki_floating_toc_enqueue_assets() {
     168    if (!wp_style_is_enqueued('muki-floating-toc-style')) {
     169        wp_enqueue_style(
     170            'muki-floating-toc-style',
     171            plugin_dir_url(__FILE__) . 'src/css/muki-floating-toc.css',
     172            array(),
     173            '1.0.7'
     174        );
     175    }
     176   
     177    if (!wp_script_is_enqueued('muki-floating-toc-script')) {
     178        wp_enqueue_script(
     179            'muki-floating-toc-script',
     180            plugin_dir_url(__FILE__) . 'src/js/muki-floating-toc.js',
     181            array('jquery'),
     182            '1.0.7',
     183            true
     184        );
     185
     186        muki_floating_toc_localize_settings();
     187    }
     188   
     189    // Ensure dashicons are loaded
     190    wp_enqueue_style('dashicons');
     191}
     192
     193/**
     194 * Get TOC HTML structure
     195 */
     196function muki_floating_toc_get_html() {
     197    $toc_html = '<div id="muki-floating-toc" class="muki-floating-toc" aria-label="Article Table of Contents">';
     198    $toc_html .= '<div class="muki-toc-toolbar">';
     199    $toc_html .= '<button class="muki-toc-pin-button" title="Pin TOC"><span class="dashicons dashicons-admin-post"></span></button>';
     200    $toc_html .= '</div>';
     201    $toc_html .= '</div>';
     202   
     203    return $toc_html;
     204}
     205
     206/**
     207 * Shortcode handler for [muki_floating_toc] 
     208 * This allows users to place TOC anywhere in post content using shortcode
     209 */
     210function muki_floating_toc_shortcode($atts = array()) {
     211    // Only work on single posts or pages
     212    if (!is_single() && !is_page()) {
     213        return '';
     214    }
     215   
     216    // Prevent multiple displays
     217    static $shortcode_used = false;
     218    if ($shortcode_used) {
     219        return '<p><em>' . esc_html__('Note: TOC shortcode can only be used once per page.', 'muki-floating-toc') . '</em></p>';
     220    }
     221    $shortcode_used = true;
     222   
     223    // Parse shortcode attributes
     224    $atts = shortcode_atts(array(), $atts, 'muki_floating_toc');
     225   
     226    // Mark that shortcode was used and enqueue assets in footer
     227    add_action('wp_footer', 'muki_floating_toc_enqueue_shortcode_assets', 5);
     228   
     229    // Return simple HTML structure - JavaScript will build the TOC
     230    return '<div id="muki-floating-toc" class="muki-floating-toc" aria-label="Article Table of Contents">
     231        <div class="muki-toc-toolbar">
     232            <button class="muki-toc-pin-button" title="Pin TOC"><span class="dashicons dashicons-admin-post"></span></button>
     233        </div>
     234    </div>';
     235}
     236
     237/**
     238 * Enqueue assets specifically for shortcode usage
     239 */ 
     240function muki_floating_toc_enqueue_shortcode_assets() {
     241    // Enqueue styles
     242    wp_enqueue_style(
     243        'muki-floating-toc-style',
     244        plugin_dir_url(__FILE__) . 'src/css/muki-floating-toc.css',
     245        array(),
     246        '1.0.7'
     247    );
     248   
     249    // Enqueue scripts
     250    wp_enqueue_script(
     251        'muki-floating-toc-script',
     252        plugin_dir_url(__FILE__) . 'src/js/muki-floating-toc.js',
     253        array('jquery'),
     254        '1.0.7',
     255        true
     256    );
     257
     258    muki_floating_toc_localize_settings();
     259
    302260    // Enqueue dashicons
    303261    wp_enqueue_style('dashicons');
  • muki-floating-toc/tags/1.0.7/readme-zh_TW.txt

    r3355807 r3487767  
    33Tags: table of contents
    44Requires at least: 6.0
    5 Tested up to: 6.8
    6 Stable tag: 1.0.6
     5Tested up to: 6.9
     6Stable tag: 1.0.7
    77Requires PHP: 7.0
    88License: GPLv2 or later
     
    4343== 更新紀錄 ==
    4444
     45= 1.0.7 =
     46* 修正:當標題數量多或標題文字過長時,目錄內容會超出容器範圍
     47* 新增:固定模式下加入垂直捲軸,並使用細窄美化樣式(支援 WebKit 及 Firefox)
     48
    4549= 1.0.6 =
    4650* 新增:「自動顯示」設定選項,可控制目錄自動顯示功能
  • muki-floating-toc/tags/1.0.7/readme.txt

    r3355807 r3487767  
    33Tags: table of contents
    44Requires at least: 6.0
    5 Tested up to: 6.8
    6 Stable tag: 1.0.6
     5Tested up to: 6.9
     6Stable tag: 1.0.7
    77Requires PHP: 7.0
    88License: GPLv2 or later
     
    4343== Changelog ==
    4444
     45= 1.0.7 =
     46* Fix: TOC content overflowing container when there are many headings or long heading text
     47* Add vertical scrollbar to pinned TOC with styled thin scrollbar (WebKit + Firefox)
     48
    4549= 1.0.6 =
    4650* New: Add "Auto Display" setting to control automatic TOC display
  • muki-floating-toc/tags/1.0.7/src/css/muki-floating-toc.css

    r3348225 r3487767  
    170170    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    171171    padding: 15px;
    172     transition: width 0.45s cubic-bezier(0.3, 0.7, 0.1, 1),
    173                 background-color 0.3s ease,
     172    overflow-y: auto;
     173    overflow-x: hidden;
     174    scrollbar-width: thin;
     175    scrollbar-color: rgba(0, 0, 0, 0.15) transparent;
     176    transition: width 0.45s cubic-bezier(0.3, 0.7, 0.1, 1),
     177                background-color 0.3s ease,
    174178                box-shadow 0.35s ease,
    175179                padding 0.4s ease,
    176180                transform 0s;
     181}
     182
     183.muki-floating-toc.pinned::-webkit-scrollbar {
     184    width: 4px;
     185}
     186
     187.muki-floating-toc.pinned::-webkit-scrollbar-track {
     188    background: transparent;
     189}
     190
     191.muki-floating-toc.pinned::-webkit-scrollbar-thumb {
     192    background-color: rgba(0, 0, 0, 0.15);
     193    border-radius: 4px;
     194}
     195
     196.muki-floating-toc.pinned::-webkit-scrollbar-thumb:hover {
     197    background-color: rgba(0, 0, 0, 0.3);
    177198}
    178199
  • muki-floating-toc/tags/1.0.7/src/js/muki-floating-toc.js

    r3348225 r3487767  
    6363    // Validate content selector for security
    6464    if (!isValidSelector(selectorContent)) {
    65       console.log('Muki Floating TOC: 無效的內容選擇器,使用默認值');
    6665      selectorContent = '.entry-content, article[class*="post-"], .post, .type-post, .page, .type-page';
    6766    }
     
    7170
    7271    if (!$content || $content.length === 0) {
    73       console.log('Muki Floating TOC: 未找到文章容器');
    7472      return;
    7573    }
    7674
    7775    if ($toc.length === 0) {
    78       console.log('Muki Floating TOC: 未找到 TOC 元素');
    7976      return;
    8077    }
    8178
    82     console.log('Muki Floating TOC: 找到文章容器', $content.prop('tagName'), $content.attr('class'));
    83 
    8479
    8580    var excludeSelectors = getSafeSetting('excludeSelectors', '.single-author-box-container', 'string');
    86     if (isValidSelector(excludeSelectors)) {
    87       console.log('Muki Floating TOC: 排除選擇器', excludeSelectors);
    88     } else {
     81    if (!isValidSelector(excludeSelectors)) {
    8982      excludeSelectors = '.single-author-box-container';
    90       console.log('Muki Floating TOC: 使用默認排除選擇器');
    9183    }
    9284
     
    9688    var $headings = $(); // Empty jQuery object to store headings
    9789    var headingsCache = []; // Cache for heading positions
    98     var contentOffset, contentTop, contentLeft, contentWidth, contentHeight, contentBottom, tocHeight;
    9990
    10091    // Generate unique ID generator for this TOC instance
     
    132123
    133124
    134     $(window).on('resize', function () {
     125    $window.on('resize', throttle(function () {
    135126
    136127      contentOffset = $content.offset();
     
    142133      tocHeight = $toc.outerHeight();
    143134
     135      // Refresh cached heading positions after layout change
     136      headingsCache = $headings.map(function () {
     137        return $(this).offset().top;
     138      }).get();
    144139
    145140      positionTOC();
    146     });
     141    }, 150));
    147142
    148143    function initToolbar($toc) {
     
    208203          if (defaultPin === true || defaultPin === 'true' || defaultPin === 1 || defaultPin === '1') {
    209204            shouldPin = true;
    210             console.log('Muki Floating TOC: 使用後台設定的預設固定狀態,設定值為:', defaultPin);
    211205          }
    212206        }
     
    228222
    229223      // Use the pre-validated excludeSelectors variable from outer scope
    230       console.log('Muki Floating TOC: 使用排除選擇器', excludeSelectors);
    231224
    232225
    233226      var allHeadings = $content.find(headingSelectors);
    234       console.log('Muki Floating TOC: 在文章容器內找到標題總數量', allHeadings.length);
    235227
    236228
     
    246238
    247239              if ($this.closest(selector).length > 0) {
    248                 console.log('Muki Floating TOC: 排除標題', $this.text(), '因為它在', selector, '內');
    249240                return false;
    250241              }
     
    256247      });
    257248
    258       console.log('Muki Floating TOC: 排除後的標題數量', $headings.length);
    259 
    260249      // Cache heading positions
    261250      headingsCache = $headings.map(function () {
     
    265254
    266255      if ($headings.length === 0) {
    267         console.log('Muki Floating TOC: 未找到標題,添加默認線段');
    268256        for (var i = 0; i < 5; i++) {
    269257          var $defaultItem = $('<div>', {
     
    457445
    458446      var positionLeft = getSafeSetting('positionLeft', true, 'boolean');
     447      var position;
    459448
    460449      if (positionLeft) {
    461 
    462         var position = contentLeft - 60;
    463 
    464 
     450        position = contentLeft - 60;
    465451        position = Math.max(10, position);
    466 
    467452
    468453        $toc.css({
     
    471456        });
    472457      } else {
    473 
    474         var position = contentLeft + contentWidth + 20;
    475 
     458        position = contentLeft + contentWidth + 20;
    476459
    477460        $toc.css({
     
    496479
    497480
    498     $(document).on('click', 'a[href^="#"]', function (e) {
     481    $toc.on('click', 'a[href^="#"]', function (e) {
    499482      var href = $(this).attr('href');
    500 
    501483
    502484      if (href === '#' || href.length <= 1) return;
     
    506488        e.preventDefault();
    507489
    508 
    509490        var fixedHeaderHeight = getSafeSetting('fixedHeaderHeight', 0, 'number');
    510 
    511 
    512491        var extraSpace = 20;
    513492        var offset = $target.offset().top - (fixedHeaderHeight + extraSpace);
  • muki-floating-toc/trunk/includes/class-muki-floating-toc.php

    r3355807 r3487767  
    1717    public static function init() {
    1818        // Load default settings
    19         self::$settings = array(
    20             'position_left' => true,
    21             'default_pin' => false,
    22             'auto_display' => true,
    23             'heading_levels' => array('h2', 'h3', 'h4', 'h5', 'h6'),
    24             'exclude_selectors' => '.single-author-box-container, .author-box, .comment-respond',
    25             'fixed_header_height' => 0,
    26             'custom_content_selector' => ''
    27         );
     19        self::$settings = muki_floating_toc_get_defaults();
    2820       
    2921        // Add settings page
     
    318310        // Further restrictive regex to allow only valid CSS selector characters
    319311        // Allows: a-z, A-Z, 0-9, #, ., ,, -, _, [, ], =, "
    320         $selectors = preg_replace('/[^\w\s#.,-_\[\]="]/', '', $selectors);
     312        $selectors = preg_replace('/[^\w\s#.,_\[\]=":-]/', '', $selectors);
    321313
    322314        return $selectors;
  • muki-floating-toc/trunk/muki-floating-toc.php

    r3355807 r3487767  
    33 * Plugin Name: Muki Floating TOC
    44 * Description: Add a floating TOC on the left or right side of articles, following scrolling and fixed at appropriate positions.
    5  * Version: 1.0.6
     5 * Version: 1.0.7
    66 * Author: Muki Wu
    77 * Author URI: https://muki.tw
     
    2020
    2121/**
    22  * Load plugin text domain for internationalization
    23  */
    24 function muki_floating_toc_load_textdomain() {
    25     load_plugin_textdomain(
    26         'muki-floating-toc',
    27         false,
    28         dirname(plugin_basename(__FILE__)) . '/languages/'
    29     );
    30 }
    31 add_action('plugins_loaded', 'muki_floating_toc_load_textdomain');
    32 
    33 // Register scripts and styles
    34 function muki_floating_toc_scripts() {
    35     // Only load on single posts
    36     if (is_single()) {
    37         wp_enqueue_style(
    38             'muki-floating-toc-style',
    39             plugin_dir_url(__FILE__) . 'src/css/muki-floating-toc.css',
    40             array(),
    41             '1.0.6'
    42         );
    43        
    44         wp_enqueue_script(
    45             'muki-floating-toc-script',
    46             plugin_dir_url(__FILE__) . 'src/js/muki-floating-toc.js',
    47             array('jquery'),
    48             '1.0.6',
    49             true
    50         );
    51 
    52         // Get settings
    53         $settings = get_option('muki_floating_toc_settings', array(
    54             'position_left' => true,
    55             'default_pin' => false,
    56             'auto_display' => true,
    57             'heading_levels' => array('h2', 'h3', 'h4', 'h5', 'h6'),
    58             'exclude_selectors' => '.single-author-box-container, .author-box, .comment-respond',
    59             'fixed_header_height' => 0,
    60             'custom_content_selector' => ''
    61         ));
    62 
    63         $default_selector = '.entry-content, article[class*="post-"], .post, .type-post, .page, .type-page';
    64        
    65         // if custom_content_selector has value, use it first
    66         $content_selector = !empty($settings['custom_content_selector']) ? $settings['custom_content_selector'] : $default_selector;
    67 
    68         // Pass settings to JavaScript
    69         wp_localize_script(
    70             'muki-floating-toc-script',
    71             'muki_floating_toc_settings',
    72             array(
    73                 'selectorContent' => $content_selector,
    74                 'positionLeft' => isset($settings['position_left']) ? (bool)$settings['position_left'] : true,
    75                 'defaultPin' => isset($settings['default_pin']) ? (bool)$settings['default_pin'] : false,
    76                 'excludeSelectors' => isset($settings['exclude_selectors']) ? $settings['exclude_selectors'] : '.single-author-box-container',
    77                 'fixedHeaderHeight' => isset($settings['fixed_header_height']) ? intval($settings['fixed_header_height']) : 0,
    78                 'headingLevels' => isset($settings['heading_levels']) ? $settings['heading_levels'] : array('h2', 'h3', 'h4')
    79             )
    80         );
    81     }
    82 }
    83 add_action('wp_enqueue_scripts', 'muki_floating_toc_scripts');
    84 
    85 /**
    86  * Add floating TOC HTML to the footer
    87  * No longer using the_content filter to avoid content positioning issues
    88  */
    89 function muki_floating_toc_add_to_footer() {
    90     // Only add on single posts
    91     if (!is_single()) {
    92         return;
    93     }
    94    
    95     // Get settings to check if auto display is enabled
    96     $settings = get_option('muki_floating_toc_settings', array(
     22 * Get plugin default settings
     23 */
     24function muki_floating_toc_get_defaults() {
     25    return array(
    9726        'position_left' => true,
    9827        'default_pin' => false,
     
    10231        'fixed_header_height' => 0,
    10332        'custom_content_selector' => ''
    104     ));
    105    
    106     // Only auto display if setting is enabled
    107     if (!isset($settings['auto_display']) || !$settings['auto_display']) {
    108         return;
    109     }
    110    
    111     // Create floating TOC HTML
    112     $toc_html = muki_floating_toc_get_html();
    113    
    114     echo wp_kses_post($toc_html);
    115 }
    116 add_action('wp_footer', 'muki_floating_toc_add_to_footer', 999); // Increase priority to ensure it loads last
    117 
    118 /**
    119  * Add Dashicons support
    120  */
    121 function muki_floating_toc_enqueue_dashicons() {
    122     wp_enqueue_style('dashicons');
    123 }
    124 add_action('wp_enqueue_scripts', 'muki_floating_toc_enqueue_dashicons');
    125 
    126 /**
    127  * Manual TOC display function for theme developers
    128  * This allows developers to place the TOC anywhere in their template files
    129  */
    130 function muki_floating_toc_display() {
    131     static $displayed = false;
    132    
    133     // Prevent multiple displays
    134     if ($displayed) {
    135         return;
    136     }
    137    
    138     // Only work on single posts or pages
    139     if (!is_single() && !is_page()) {
    140         return;
    141     }
    142    
    143     // Ensure scripts and styles are loaded
    144     muki_floating_toc_enqueue_assets();
    145    
    146     // Mark as displayed
    147     $displayed = true;
    148    
    149     // Get the TOC HTML
    150     $toc_html = muki_floating_toc_get_html();
    151    
    152     echo wp_kses_post($toc_html);
    153 }
    154 
    155 /**
    156  * Enqueue assets for manual display
    157  */
    158 function muki_floating_toc_enqueue_assets() {
    159     if (!wp_style_is_enqueued('muki-floating-toc-style')) {
    160         wp_enqueue_style(
    161             'muki-floating-toc-style',
    162             plugin_dir_url(__FILE__) . 'src/css/muki-floating-toc.css',
    163             array(),
    164             '1.0.6'
    165         );
    166     }
    167    
    168     if (!wp_script_is_enqueued('muki-floating-toc-script')) {
    169         wp_enqueue_script(
    170             'muki-floating-toc-script',
    171             plugin_dir_url(__FILE__) . 'src/js/muki-floating-toc.js',
    172             array('jquery'),
    173             '1.0.6',
    174             true
    175         );
    176 
    177         // Get settings and localize script
    178         $settings = get_option('muki_floating_toc_settings', array(
    179             'position_left' => true,
    180             'default_pin' => false,
    181             'auto_display' => true,
    182             'heading_levels' => array('h2', 'h3', 'h4', 'h5', 'h6'),
    183             'exclude_selectors' => '.single-author-box-container, .author-box, .comment-respond',
    184             'fixed_header_height' => 0,
    185             'custom_content_selector' => ''
    186         ));
    187 
    188         $default_selector = '.entry-content, article[class*="post-"], .post, .type-post, .page, .type-page';
    189         $content_selector = !empty($settings['custom_content_selector']) ? $settings['custom_content_selector'] : $default_selector;
    190 
    191         wp_localize_script(
    192             'muki-floating-toc-script',
    193             'muki_floating_toc_settings',
    194             array(
    195                 'selectorContent' => $content_selector,
    196                 'positionLeft' => isset($settings['position_left']) ? (bool)$settings['position_left'] : true,
    197                 'defaultPin' => isset($settings['default_pin']) ? (bool)$settings['default_pin'] : false,
    198                 'excludeSelectors' => isset($settings['exclude_selectors']) ? $settings['exclude_selectors'] : '.single-author-box-container',
    199                 'fixedHeaderHeight' => isset($settings['fixed_header_height']) ? intval($settings['fixed_header_height']) : 0,
    200                 'headingLevels' => isset($settings['heading_levels']) ? $settings['heading_levels'] : array('h2', 'h3', 'h4')
    201             )
    202         );
    203     }
    204    
    205     // Ensure dashicons are loaded
    206     wp_enqueue_style('dashicons');
    207 }
    208 
    209 /**
    210  * Get TOC HTML structure
    211  */
    212 function muki_floating_toc_get_html() {
    213     $toc_html = '<div id="muki-floating-toc" class="muki-floating-toc" aria-label="Article Table of Contents">';
    214     $toc_html .= '<div class="muki-toc-toolbar">';
    215     $toc_html .= '<button class="muki-toc-pin-button" title="Pin TOC"><span class="dashicons dashicons-admin-post"></span></button>';
    216     $toc_html .= '</div>';
    217     $toc_html .= '</div>';
    218    
    219     return $toc_html;
    220 }
    221 
    222 /**
    223  * Shortcode handler for [muki_floating_toc] 
    224  * This allows users to place TOC anywhere in post content using shortcode
    225  */
    226 function muki_floating_toc_shortcode($atts = array()) {
    227     // Only work on single posts or pages
    228     if (!is_single() && !is_page()) {
    229         return '';
    230     }
    231    
    232     // Prevent multiple displays
    233     static $shortcode_used = false;
    234     if ($shortcode_used) {
    235         return '<p><em>' . esc_html__('Note: TOC shortcode can only be used once per page.', 'muki-floating-toc') . '</em></p>';
    236     }
    237     $shortcode_used = true;
    238    
    239     // Parse shortcode attributes
    240     $atts = shortcode_atts(array(), $atts, 'muki_floating_toc');
    241    
    242     // Mark that shortcode was used and enqueue assets in footer
    243     add_action('wp_footer', 'muki_floating_toc_enqueue_shortcode_assets', 5);
    244    
    245     // Return simple HTML structure - JavaScript will build the TOC
    246     return '<div id="muki-floating-toc" class="muki-floating-toc" aria-label="Article Table of Contents">
    247         <div class="muki-toc-toolbar">
    248             <button class="muki-toc-pin-button" title="Pin TOC"><span class="dashicons dashicons-admin-post"></span></button>
    249         </div>
    250     </div>';
    251 }
    252 
    253 /**
    254  * Enqueue assets specifically for shortcode usage
    255  */ 
    256 function muki_floating_toc_enqueue_shortcode_assets() {
    257     // Enqueue styles
    258     wp_enqueue_style(
    259         'muki-floating-toc-style',
    260         plugin_dir_url(__FILE__) . 'src/css/muki-floating-toc.css',
    261         array(),
    262         '1.0.6'
    263     );
    264    
    265     // Enqueue scripts
    266     wp_enqueue_script(
    267         'muki-floating-toc-script',
    268         plugin_dir_url(__FILE__) . 'src/js/muki-floating-toc.js',
    269         array('jquery'),
    270         '1.0.6',
    271         true
    272     );
    273 
    274     // Get settings
    275     $settings = get_option('muki_floating_toc_settings', array(
    276         'position_left' => true,
    277         'default_pin' => false,
    278         'auto_display' => true,
    279         'heading_levels' => array('h2', 'h3', 'h4', 'h5', 'h6'),
    280         'exclude_selectors' => '.single-author-box-container, .author-box, .comment-respond',
    281         'fixed_header_height' => 0,
    282         'custom_content_selector' => ''
    283     ));
    284 
     33    );
     34}
     35
     36/**
     37 * Get plugin settings with defaults
     38 */
     39function muki_floating_toc_get_settings() {
     40    return get_option('muki_floating_toc_settings', muki_floating_toc_get_defaults());
     41}
     42
     43/**
     44 * Localize script with plugin settings
     45 */
     46function muki_floating_toc_localize_settings() {
     47    $settings = muki_floating_toc_get_settings();
    28548    $default_selector = '.entry-content, article[class*="post-"], .post, .type-post, .page, .type-page';
    28649    $content_selector = !empty($settings['custom_content_selector']) ? $settings['custom_content_selector'] : $default_selector;
    28750
    288     // Localize script
    28951    wp_localize_script(
    29052        'muki-floating-toc-script',
     
    29961        )
    30062    );
    301    
     63}
     64
     65/**
     66 * Load plugin text domain for internationalization
     67 */
     68function muki_floating_toc_load_textdomain() {
     69    load_plugin_textdomain(
     70        'muki-floating-toc',
     71        false,
     72        dirname(plugin_basename(__FILE__)) . '/languages/'
     73    );
     74}
     75add_action('plugins_loaded', 'muki_floating_toc_load_textdomain');
     76
     77// Register scripts and styles
     78function muki_floating_toc_scripts() {
     79    // Only load on single posts
     80    if (is_single()) {
     81        wp_enqueue_style(
     82            'muki-floating-toc-style',
     83            plugin_dir_url(__FILE__) . 'src/css/muki-floating-toc.css',
     84            array(),
     85            '1.0.7'
     86        );
     87       
     88        wp_enqueue_script(
     89            'muki-floating-toc-script',
     90            plugin_dir_url(__FILE__) . 'src/js/muki-floating-toc.js',
     91            array('jquery'),
     92            '1.0.7',
     93            true
     94        );
     95
     96        // Pass settings to JavaScript
     97        muki_floating_toc_localize_settings();
     98    }
     99}
     100add_action('wp_enqueue_scripts', 'muki_floating_toc_scripts');
     101
     102/**
     103 * Add floating TOC HTML to the footer
     104 * No longer using the_content filter to avoid content positioning issues
     105 */
     106function muki_floating_toc_add_to_footer() {
     107    // Only add on single posts
     108    if (!is_single()) {
     109        return;
     110    }
     111   
     112    // Get settings to check if auto display is enabled
     113    $settings = muki_floating_toc_get_settings();
     114   
     115    // Only auto display if setting is enabled
     116    if (!isset($settings['auto_display']) || !$settings['auto_display']) {
     117        return;
     118    }
     119   
     120    // Create floating TOC HTML
     121    $toc_html = muki_floating_toc_get_html();
     122   
     123    echo wp_kses_post($toc_html);
     124}
     125add_action('wp_footer', 'muki_floating_toc_add_to_footer', 999); // Increase priority to ensure it loads last
     126
     127/**
     128 * Add Dashicons support
     129 */
     130function muki_floating_toc_enqueue_dashicons() {
     131    wp_enqueue_style('dashicons');
     132}
     133add_action('wp_enqueue_scripts', 'muki_floating_toc_enqueue_dashicons');
     134
     135/**
     136 * Manual TOC display function for theme developers
     137 * This allows developers to place the TOC anywhere in their template files
     138 */
     139function muki_floating_toc_display() {
     140    static $displayed = false;
     141   
     142    // Prevent multiple displays
     143    if ($displayed) {
     144        return;
     145    }
     146   
     147    // Only work on single posts or pages
     148    if (!is_single() && !is_page()) {
     149        return;
     150    }
     151   
     152    // Ensure scripts and styles are loaded
     153    muki_floating_toc_enqueue_assets();
     154   
     155    // Mark as displayed
     156    $displayed = true;
     157   
     158    // Get the TOC HTML
     159    $toc_html = muki_floating_toc_get_html();
     160   
     161    echo wp_kses_post($toc_html);
     162}
     163
     164/**
     165 * Enqueue assets for manual display
     166 */
     167function muki_floating_toc_enqueue_assets() {
     168    if (!wp_style_is_enqueued('muki-floating-toc-style')) {
     169        wp_enqueue_style(
     170            'muki-floating-toc-style',
     171            plugin_dir_url(__FILE__) . 'src/css/muki-floating-toc.css',
     172            array(),
     173            '1.0.7'
     174        );
     175    }
     176   
     177    if (!wp_script_is_enqueued('muki-floating-toc-script')) {
     178        wp_enqueue_script(
     179            'muki-floating-toc-script',
     180            plugin_dir_url(__FILE__) . 'src/js/muki-floating-toc.js',
     181            array('jquery'),
     182            '1.0.7',
     183            true
     184        );
     185
     186        muki_floating_toc_localize_settings();
     187    }
     188   
     189    // Ensure dashicons are loaded
     190    wp_enqueue_style('dashicons');
     191}
     192
     193/**
     194 * Get TOC HTML structure
     195 */
     196function muki_floating_toc_get_html() {
     197    $toc_html = '<div id="muki-floating-toc" class="muki-floating-toc" aria-label="Article Table of Contents">';
     198    $toc_html .= '<div class="muki-toc-toolbar">';
     199    $toc_html .= '<button class="muki-toc-pin-button" title="Pin TOC"><span class="dashicons dashicons-admin-post"></span></button>';
     200    $toc_html .= '</div>';
     201    $toc_html .= '</div>';
     202   
     203    return $toc_html;
     204}
     205
     206/**
     207 * Shortcode handler for [muki_floating_toc] 
     208 * This allows users to place TOC anywhere in post content using shortcode
     209 */
     210function muki_floating_toc_shortcode($atts = array()) {
     211    // Only work on single posts or pages
     212    if (!is_single() && !is_page()) {
     213        return '';
     214    }
     215   
     216    // Prevent multiple displays
     217    static $shortcode_used = false;
     218    if ($shortcode_used) {
     219        return '<p><em>' . esc_html__('Note: TOC shortcode can only be used once per page.', 'muki-floating-toc') . '</em></p>';
     220    }
     221    $shortcode_used = true;
     222   
     223    // Parse shortcode attributes
     224    $atts = shortcode_atts(array(), $atts, 'muki_floating_toc');
     225   
     226    // Mark that shortcode was used and enqueue assets in footer
     227    add_action('wp_footer', 'muki_floating_toc_enqueue_shortcode_assets', 5);
     228   
     229    // Return simple HTML structure - JavaScript will build the TOC
     230    return '<div id="muki-floating-toc" class="muki-floating-toc" aria-label="Article Table of Contents">
     231        <div class="muki-toc-toolbar">
     232            <button class="muki-toc-pin-button" title="Pin TOC"><span class="dashicons dashicons-admin-post"></span></button>
     233        </div>
     234    </div>';
     235}
     236
     237/**
     238 * Enqueue assets specifically for shortcode usage
     239 */ 
     240function muki_floating_toc_enqueue_shortcode_assets() {
     241    // Enqueue styles
     242    wp_enqueue_style(
     243        'muki-floating-toc-style',
     244        plugin_dir_url(__FILE__) . 'src/css/muki-floating-toc.css',
     245        array(),
     246        '1.0.7'
     247    );
     248   
     249    // Enqueue scripts
     250    wp_enqueue_script(
     251        'muki-floating-toc-script',
     252        plugin_dir_url(__FILE__) . 'src/js/muki-floating-toc.js',
     253        array('jquery'),
     254        '1.0.7',
     255        true
     256    );
     257
     258    muki_floating_toc_localize_settings();
     259
    302260    // Enqueue dashicons
    303261    wp_enqueue_style('dashicons');
  • muki-floating-toc/trunk/readme-zh_TW.txt

    r3355807 r3487767  
    33Tags: table of contents
    44Requires at least: 6.0
    5 Tested up to: 6.8
    6 Stable tag: 1.0.6
     5Tested up to: 6.9
     6Stable tag: 1.0.7
    77Requires PHP: 7.0
    88License: GPLv2 or later
     
    4343== 更新紀錄 ==
    4444
     45= 1.0.7 =
     46* 修正:當標題數量多或標題文字過長時,目錄內容會超出容器範圍
     47* 新增:固定模式下加入垂直捲軸,並使用細窄美化樣式(支援 WebKit 及 Firefox)
     48
    4549= 1.0.6 =
    4650* 新增:「自動顯示」設定選項,可控制目錄自動顯示功能
  • muki-floating-toc/trunk/readme.txt

    r3355807 r3487767  
    33Tags: table of contents
    44Requires at least: 6.0
    5 Tested up to: 6.8
    6 Stable tag: 1.0.6
     5Tested up to: 6.9
     6Stable tag: 1.0.7
    77Requires PHP: 7.0
    88License: GPLv2 or later
     
    4343== Changelog ==
    4444
     45= 1.0.7 =
     46* Fix: TOC content overflowing container when there are many headings or long heading text
     47* Add vertical scrollbar to pinned TOC with styled thin scrollbar (WebKit + Firefox)
     48
    4549= 1.0.6 =
    4650* New: Add "Auto Display" setting to control automatic TOC display
  • muki-floating-toc/trunk/src/css/muki-floating-toc.css

    r3348225 r3487767  
    170170    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    171171    padding: 15px;
    172     transition: width 0.45s cubic-bezier(0.3, 0.7, 0.1, 1),
    173                 background-color 0.3s ease,
     172    overflow-y: auto;
     173    overflow-x: hidden;
     174    scrollbar-width: thin;
     175    scrollbar-color: rgba(0, 0, 0, 0.15) transparent;
     176    transition: width 0.45s cubic-bezier(0.3, 0.7, 0.1, 1),
     177                background-color 0.3s ease,
    174178                box-shadow 0.35s ease,
    175179                padding 0.4s ease,
    176180                transform 0s;
     181}
     182
     183.muki-floating-toc.pinned::-webkit-scrollbar {
     184    width: 4px;
     185}
     186
     187.muki-floating-toc.pinned::-webkit-scrollbar-track {
     188    background: transparent;
     189}
     190
     191.muki-floating-toc.pinned::-webkit-scrollbar-thumb {
     192    background-color: rgba(0, 0, 0, 0.15);
     193    border-radius: 4px;
     194}
     195
     196.muki-floating-toc.pinned::-webkit-scrollbar-thumb:hover {
     197    background-color: rgba(0, 0, 0, 0.3);
    177198}
    178199
  • muki-floating-toc/trunk/src/js/muki-floating-toc.js

    r3348225 r3487767  
    6363    // Validate content selector for security
    6464    if (!isValidSelector(selectorContent)) {
    65       console.log('Muki Floating TOC: 無效的內容選擇器,使用默認值');
    6665      selectorContent = '.entry-content, article[class*="post-"], .post, .type-post, .page, .type-page';
    6766    }
     
    7170
    7271    if (!$content || $content.length === 0) {
    73       console.log('Muki Floating TOC: 未找到文章容器');
    7472      return;
    7573    }
    7674
    7775    if ($toc.length === 0) {
    78       console.log('Muki Floating TOC: 未找到 TOC 元素');
    7976      return;
    8077    }
    8178
    82     console.log('Muki Floating TOC: 找到文章容器', $content.prop('tagName'), $content.attr('class'));
    83 
    8479
    8580    var excludeSelectors = getSafeSetting('excludeSelectors', '.single-author-box-container', 'string');
    86     if (isValidSelector(excludeSelectors)) {
    87       console.log('Muki Floating TOC: 排除選擇器', excludeSelectors);
    88     } else {
     81    if (!isValidSelector(excludeSelectors)) {
    8982      excludeSelectors = '.single-author-box-container';
    90       console.log('Muki Floating TOC: 使用默認排除選擇器');
    9183    }
    9284
     
    9688    var $headings = $(); // Empty jQuery object to store headings
    9789    var headingsCache = []; // Cache for heading positions
    98     var contentOffset, contentTop, contentLeft, contentWidth, contentHeight, contentBottom, tocHeight;
    9990
    10091    // Generate unique ID generator for this TOC instance
     
    132123
    133124
    134     $(window).on('resize', function () {
     125    $window.on('resize', throttle(function () {
    135126
    136127      contentOffset = $content.offset();
     
    142133      tocHeight = $toc.outerHeight();
    143134
     135      // Refresh cached heading positions after layout change
     136      headingsCache = $headings.map(function () {
     137        return $(this).offset().top;
     138      }).get();
    144139
    145140      positionTOC();
    146     });
     141    }, 150));
    147142
    148143    function initToolbar($toc) {
     
    208203          if (defaultPin === true || defaultPin === 'true' || defaultPin === 1 || defaultPin === '1') {
    209204            shouldPin = true;
    210             console.log('Muki Floating TOC: 使用後台設定的預設固定狀態,設定值為:', defaultPin);
    211205          }
    212206        }
     
    228222
    229223      // Use the pre-validated excludeSelectors variable from outer scope
    230       console.log('Muki Floating TOC: 使用排除選擇器', excludeSelectors);
    231224
    232225
    233226      var allHeadings = $content.find(headingSelectors);
    234       console.log('Muki Floating TOC: 在文章容器內找到標題總數量', allHeadings.length);
    235227
    236228
     
    246238
    247239              if ($this.closest(selector).length > 0) {
    248                 console.log('Muki Floating TOC: 排除標題', $this.text(), '因為它在', selector, '內');
    249240                return false;
    250241              }
     
    256247      });
    257248
    258       console.log('Muki Floating TOC: 排除後的標題數量', $headings.length);
    259 
    260249      // Cache heading positions
    261250      headingsCache = $headings.map(function () {
     
    265254
    266255      if ($headings.length === 0) {
    267         console.log('Muki Floating TOC: 未找到標題,添加默認線段');
    268256        for (var i = 0; i < 5; i++) {
    269257          var $defaultItem = $('<div>', {
     
    457445
    458446      var positionLeft = getSafeSetting('positionLeft', true, 'boolean');
     447      var position;
    459448
    460449      if (positionLeft) {
    461 
    462         var position = contentLeft - 60;
    463 
    464 
     450        position = contentLeft - 60;
    465451        position = Math.max(10, position);
    466 
    467452
    468453        $toc.css({
     
    471456        });
    472457      } else {
    473 
    474         var position = contentLeft + contentWidth + 20;
    475 
     458        position = contentLeft + contentWidth + 20;
    476459
    477460        $toc.css({
     
    496479
    497480
    498     $(document).on('click', 'a[href^="#"]', function (e) {
     481    $toc.on('click', 'a[href^="#"]', function (e) {
    499482      var href = $(this).attr('href');
    500 
    501483
    502484      if (href === '#' || href.length <= 1) return;
     
    506488        e.preventDefault();
    507489
    508 
    509490        var fixedHeaderHeight = getSafeSetting('fixedHeaderHeight', 0, 'number');
    510 
    511 
    512491        var extraSpace = 20;
    513492        var offset = $target.offset().top - (fixedHeaderHeight + extraSpace);
Note: See TracChangeset for help on using the changeset viewer.