Hướng dẫn thêm mục lục tự động cho NukeViet CMS

 Mặc định NukeViet chưa có tính năng tạo mục lục tự động. Bài viết này sẽ hướng dẫn các bạn thêm Mục lục Tự động cho NukeViet CMS.

Hướng dẫn thêm mục lục tự động cho NukeViet CMS


Lưu ý: Để có thể hiển thị mục lục đúng và đẹp, chúng ta nên tạo các bài viết có cấu trúc chuẩn các thẻ heading (h1 - h6)


1. Thêm các hàm hỗ trợ

Thêm đoạn sau vào cuối file: modules/news/global.functions.php

function mb_find_replace(&$find = false, &$replace = false, &$string = '')
{
    if (is_array($find) && is_array($replace) && $string) {
        // check if multibyte strings are supported
        if (function_exists('mb_strpos')) {
            for ($i = 0; $i < count($find); $i++) {
                $string =
                    mb_substr($string, 0, mb_strpos($string, $find[$i])) .    // everything befor $find
                    $replace[$i] .                                                // its replacement
                    mb_substr($string, mb_strpos($string, $find[$i]) + mb_strlen($find[$i]))    // everything after $find
                ;
            }
        } else {
            for ($i = 0; $i < count($find); $i++) {
                $string = substr_replace(
                    $string,
                    $replace[$i],
                    strpos($string, $find[$i]),
                    strlen($find[$i])
                );
            }
        }
    }

    return $string;
}

function url_anchor_target($title, &$array_anchors = [])
{
    $title = strip_tags($title);
    $title = str_replace(array("\r", "\n", "\n\r", "\r\n"), ' ', $title);
    $title = str_replace('&amp;', '', $title);
    // remove non alphanumeric chars
    $title = preg_replace('/[^a-zA-Z0-9 \-_]*/', '', $title);
    // convert spaces to _
    $title = str_replace(
        array('  ', ' ', 'nbsp'),
        '_',
        $title
    );
    // remove trailing - and _
    $title = rtrim($title, '-_');
    $title = strtolower($title);
    $title = str_replace('_', '-', $title);
    $title = str_replace('--', '-', $title);

    if (array_key_exists($title, $array_anchors)) {
        $array_anchors[$title]++;
        $title .= '-' . $array_anchors[$title];
    } else
        $array_anchors[$title] = 1;

    return $title;
}

function get_title_target($title)
{
    $title = strip_tags($title);
    $title = str_replace(array("\r", "\n", "\n\r", "\r\n"), ' ', $title);
    $title = str_replace('&amp;', '', $title);
    return $title;
}

function build_hierarchy( &$matches )
{
    $current_depth = 100;	// headings can't be larger than h6 but 100 as a default to be sure
    $html = '';
    $numbered_items = array();
    $numbered_items_min = null;
    // reset the internal collision collection
    $array_anchors = array();
    // find the minimum heading to establish our baseline
    for ($i = 0; $i < count($matches); $i++) {
        if ( $current_depth > $matches[$i][2] )
            $current_depth = (int)$matches[$i][2];
    }
    $numbered_items[$current_depth] = 0;
    $numbered_items_min = $current_depth;

    for ($i = 0; $i < count($matches); $i++) {

        if ( $current_depth == (int)$matches[$i][2] )
            $html .= '<li>';
        // start lists
        if ( $current_depth != (int)$matches[$i][2] ) {
            for ($current_depth; $current_depth < (int)$matches[$i][2]; $current_depth++) {
                $numbered_items[$current_depth + 1] = 0;
                $html .= '<ul><li>';
            }
        }
        // list item
        $html .= '<a href="#' . url_anchor_target( $matches[$i][0] ) . '">';
        $html .= strip_tags($matches[$i][0]) . '</a>';
        // end lists
        if ( $i != count($matches) - 1 ) {
            if ( $current_depth > (int)$matches[$i + 1][2] ) {
                for ($current_depth; $current_depth > (int)$matches[$i + 1][2]; $current_depth--) {
                    $html .= '</li></ul>';
                    $numbered_items[$current_depth] = 0;
                }
            }
            if ( $current_depth == (int)@$matches[$i + 1][2] )
                $html .= '</li>';
        }
        else {
            // this is the last item, make sure we close off all tags
            for ($current_depth; $current_depth >= $numbered_items_min; $current_depth--) {
                $html .= '</li>';
                if ( $current_depth != $numbered_items_min ) $html .= '</ul>';
            }
        }
    }

    return $html;
}


2. Thêm đoạn xử lý detail

Mở file: modules/news/funcs/detail.php
Tìm đoạn (Line: 228)
$news_contents['newscheckss'] = md5($news_contents['id'] . NV_CHECK_SESSION);
Thêm vào bên dưới đoạn sau
if (preg_match_all('/(<h([1-6]{1})[^>]*>).*<\/h\2>/msuU', $news_contents['bodyhtml'], $matches, PREG_SET_ORDER)) {
    $array_anchors = [];
    for ($i = 0; $i < count($matches); $i++) {
        $anchor = url_anchor_target($matches[$i][0], $array_anchors);
        $find[] = $matches[$i][0];
        $replace[] = str_replace(
            array(
                $matches[$i][1],                // start of heading
                '</h' . $matches[$i][2] . '>'    // end of heading
            ),
            array(
                $matches[$i][1] . '<span id="' . $anchor . '">',
                '</span></h' . $matches[$i][2] . '>'
            ),
            $matches[$i][0]
        );
    }
}

$news_contents['bodyhtml'] = mb_find_replace($find, $replace, $news_contents['bodyhtml']);
$news_contents['toc'] = build_hierarchy($matches);


3. Hiển thị lên giao diện

Mở file: themes/<default>/modules/news/detail.tpl
- Tìm đoạn nội dung chi tiết bài viết, thường là:
<div id="news-bodyhtml" class="bodytext margin-bottom-lg">
   {DETAIL.bodyhtml}
</div>

- Thêm vào phía bên trên phần chi tiết đó code sau đây: 
<!-- BEGIN: show_toc -->
    <div id="toc_container">
        <p class="toc_title">Mục lục</p>
        <ul class="toc_list">
            {DETAIL.toc}
        </ul>
    </div>
<!-- END: show_toc -->

Thêm vào chỗ trước khi đóng <!-- END: main --> đoạn code script sau:

<script>

    $(document).ready(function() {

        if ($("#toc_container .toc_list").length > 0) {

            var height = ($('#toc_container .toc_list').height());

            if (height > 300) {

                $("#toc_container .toc_list").css("height", 300 + "px");

                $("#toc_container .toc_list").parent().append('<div class="vuta_toc_readmore"><a title="Mở rộng" href="javascript:void(0);">Mở rộng</a></div>');

                $("body").on("click", ".vuta_toc_readmore", function() {

                    $("#toc_container .toc_list").removeAttr("style");

                    $("body .vuta_toc_readmore").remove();

                    $("#toc_container .toc_list").parent().append('<div class="vuta_toc_expand"><a title="Thu gọn" href="javascript:void(0);">Thu gọn</a></div>');

                });

                $("body").on("click", ".vuta_toc_expand a", function() {

                    $("#toc_container .toc_list").css("height", 300 + "px");

                    $("#toc_container .toc_list").parent().append('<div class="vuta_toc_readmore"><a title="Mở rộng" href="javascript:void(0);">Mở rộng</a></div>');

                    $("body .vuta_toc_expand").remove();

                });

            }

        }


        // Add smooth scrolling to all links

        $("#toc_container a").on('click', function(event) {


            // Make sure this.hash has a value before overriding default behavior

            if (this.hash !== "") {

                // Prevent default anchor click behavior

                event.preventDefault();


                // Store hash

                var hash = this.hash;

                window.location.hash = hash;


                // Using jQuery's animate() method to add smooth page scroll

                // The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area

                var to_offset = $(hash).offset().top - 100;

                $('html, body').animate({

                    scrollTop: to_offset

                }, 500);

            } // End if

        });

    });

</script>

4. Check hiển thị

Mở file: modules/news/theme.php
Tìm đoạn này (Line: 788)
if (! empty($news_contents['post_name'])) {
    $xtpl->parse('main.post_name');
}

Thêm vào bên dưới:
if (!empty($news_contents['toc'])) {
   $xtpl->parse('main.show_toc');
}



5. Thêm CSS

Cuối cùng thêm đoạn CSS vào style.css giao diện của bạn, hoặc tại file detail.tpl mở thêm thẻ <style> rồi dán vào:

#toc_container li,
#toc_container ul {
    margin: 0;
    padding: 0
}

#toc_container.no_bullets li,
#toc_container.no_bullets ul,
#toc_container.no_bullets ul li,
.toc_widget_list.no_bullets,
.toc_widget_list.no_bullets li {
    background: 0 0;
    list-style-type: none;
    list-style: none
}

#toc_container.have_bullets li {
    padding-left: 12px
}

#toc_container ul ul {
    margin-left: 1.5em
}

#toc_container {
    background: #dff4ff;
    border-radius: 5px;
    margin-bottom: 1em;
    width: auto;
    display: table;
    position: relative;
}

#toc_container p.toc_title {
    text-align: center;
    font-weight: 900;
    margin: 0;
    padding: 10px 0 8px;
    font-family: "Roboto Slab", sans-serif;
    text-transform: uppercase;
    background: #f4f5f8;
    border-radius: 5px 5px 0 0;
}

#toc_container.toc_black p.toc_title {
    color: #aaa
}

#toc_container p.toc_title+ul.toc_list {
    padding: 10px 30px;
    overflow: hidden;
}

#toc_container a {
    text-decoration: none;
    text-shadow: none;
    color: #009ded;
    font-size: 15px;
    line-height: 15px;
}

#toc_container a:hover {
    color: #007bff;
}

.vuta_toc_readmore {
    text-align: center;
    cursor: pointer;
    position: absolute;
    z-index: 9999;
    bottom: 0;
    width: 100%;
    background: #fff;
}

.vuta_toc_readmore:before {
    height: 55px;
    margin-top: -45px;
    content: "";
    background: -moz-linear-gradient( top, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
    background: -webkit-linear-gradient( top, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
    background: linear-gradient( to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 100%);
    filter: progid: DXImageTransform.Microsoft.gradient( startColorstr='#ffffff00', endColorstr='#ffffff', GradientType=0);
    display: block;
}

.vuta_toc_readmore a {
    color: #222 !important;
    display: block;
    font-size: 13px !important;
    font-weight: 700;
}

.vuta_toc_readmore a:after {
    content: "";
    width: 0;
    right: 0;
    border-top: 4px solid #222;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    display: inline-block;
    vertical-align: middle;
    margin: -2px 0 0 5px;
}

.vuta_toc_expand {
    text-align: center;
}

.vuta_toc_expand a {
    position: relative;
    color: #222 !important;
    font-size: 13px !important;
    font-weight: 700;
}

.vuta_toc_expand a:after {
    content: "";
    width: 0;
    right: 0;
    border-bottom: 4px solid #222;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    display: inline-block;
    vertical-align: middle;
    margin: -2px 0 0 5px;
}
CHÚC CÁC BẠN THÀNH CÔNG!

Nguồn: https://vuta.vn

Post a Comment

0 Comments