最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to implement a tabbed codeblock tag for Hexo - Stack Overflow

programmeradmin2浏览0评论

I am trying to create tabbed code-blocks (as a tag plugin) in hexo but I cannot figure out where to put my js function. I thought I could load the function using the js helper but I don't know where to include the helper. I tried, and failed, to add it into the tag plugin. This is the tag plugin code (saved as testtag.js):

hexo.extend.tag.register('testtag', function(args, content){
  var className =  args.join(' ');

  var result = '';
  result += "<\%- js('\\themes\\bootstrap-blog\\scripts\\tab.js') \%>"
  result += '<div class="tabs">';
  result += '<ul>';
  result += '<li class="li_tab1" onclick="tab(&apos;tab1&apos;)"><a>Tab 1</a></li>';
  result += '<li class="li_tab2" onclick="tab(&apos;tab2&apos;)"><a>Tab 2</a></li>';
  result += '</ul>';
  result += '<div class="contentarea">';
  result += '<div id="tab1">';
  result += '<p>' + content + '</p>';
  result += '</div>';
  result += '<div id="tab2" style="display: none;">'
  result += '<p>This is the text for tab 2.</p>'
  result += '</div>'
  result += '</div>'
  result += '</div>'

  return result;

}, {ends: true});

which does work. However, the onclick event of the tags just raises the error that it can't find the tab function. Note that the first line of result above was my failed attempt to use the helper.

This is my tab function, tab.js:

function tab(tab) {
document.getElementById('tab1').style.display = 'none';
document.getElementById('tab2').style.display = 'none';
document.getElementById('li_tab1').setAttribute("class", "");
document.getElementById('li_tab2').setAttribute("class", "");
document.getElementById(tab).style.display = 'block';
document.getElementById('li_'+tab).setAttribute("class", "active");
}

Both tab.js and testtag.js as saved in the *\themes\bootstrap-blog\scripts* folder.

I saw this answer which I though might help but I can't figure out what a view is. I couldn't find anything about views in the Hexo docs.

I am trying to create tabbed code-blocks (as a tag plugin) in hexo but I cannot figure out where to put my js function. I thought I could load the function using the js helper but I don't know where to include the helper. I tried, and failed, to add it into the tag plugin. This is the tag plugin code (saved as testtag.js):

hexo.extend.tag.register('testtag', function(args, content){
  var className =  args.join(' ');

  var result = '';
  result += "<\%- js('\\themes\\bootstrap-blog\\scripts\\tab.js') \%>"
  result += '<div class="tabs">';
  result += '<ul>';
  result += '<li class="li_tab1" onclick="tab(&apos;tab1&apos;)"><a>Tab 1</a></li>';
  result += '<li class="li_tab2" onclick="tab(&apos;tab2&apos;)"><a>Tab 2</a></li>';
  result += '</ul>';
  result += '<div class="contentarea">';
  result += '<div id="tab1">';
  result += '<p>' + content + '</p>';
  result += '</div>';
  result += '<div id="tab2" style="display: none;">'
  result += '<p>This is the text for tab 2.</p>'
  result += '</div>'
  result += '</div>'
  result += '</div>'

  return result;

}, {ends: true});

which does work. However, the onclick event of the tags just raises the error that it can't find the tab function. Note that the first line of result above was my failed attempt to use the helper.

This is my tab function, tab.js:

function tab(tab) {
document.getElementById('tab1').style.display = 'none';
document.getElementById('tab2').style.display = 'none';
document.getElementById('li_tab1').setAttribute("class", "");
document.getElementById('li_tab2').setAttribute("class", "");
document.getElementById(tab).style.display = 'block';
document.getElementById('li_'+tab).setAttribute("class", "active");
}

Both tab.js and testtag.js as saved in the *\themes\bootstrap-blog\scripts* folder.

I saw this answer which I though might help but I can't figure out what a view is. I couldn't find anything about views in the Hexo docs.

Share Improve this question edited May 23, 2017 at 12:01 CommunityBot 11 silver badge asked Feb 1, 2016 at 21:04 DanDan 45.8k20 gold badges97 silver badges165 bronze badges 6
  • Hey man. I'm trying to understand your problem. There is multiple issue in your code. What are you trying to do? I need to know that, to give you an answer that make sens. views/templates are stored in theme/theme_name/layout – Louis Barranqueiro Commented Feb 5, 2016 at 14:00
  • I want to make a tag plugin that is a tabbed codeblock. e.g I want to post the same code in a few languages and be able to switch between the languages with tabs For example, something like this but with code colouring as well. Note that I just found that link right now and since it has no js it might be a good way forward for me. But I'm still interested in the answer to the question as it stands. My list elements are rendered with onclick="tab('tab2') so I need to write that tab() function but I'm not sure where to put the code for it. – Dan Commented Feb 5, 2016 at 14:43
  • I'd rather do this in a theme. – Leo Commented Feb 25, 2016 at 15:11
  • @Leo Can you explain how to do this in a theme? I have found the docs severely lacking... – Dan Commented Feb 25, 2016 at 15:21
  • @Leo Hey men, I just posted a plete example explaining the process. – Louis Barranqueiro Commented Mar 2, 2016 at 14:20
 |  Show 1 more ment

2 Answers 2

Reset to default 9 +50

There are too many mistake in your code so I prefer to give you a full example with explanations.

Here is what we need :

  1. A custom tag to build the HTML structure of this multiple codeblock
  2. A CSS file to stylize the code block and code coloration
  3. A JS script to animate the codeblock (tabs)

Custom tag : m_codeblock (JS server side)

We need to allow user to define :

  • a name or a link
  • multiple codeblock in this tab, so we defined a tag to separate and list each tab

Here is the syntax :

{% m_codeblock [name] [link] %}
    <!-- tab [lang] -->
        source_code
    <!-- endtab -->
{% endm_codeblock %}

and an example :

{% m_codeblock stack overflow https://example.fr %}
    <!-- tab html -->
        <html>
            <body>
                <h1>Hey dan</h1>
            </body>
        </html>
    <!-- endtab -->
    <!-- tab css -->
        h1 {
            color:red;
        }
    <!-- endtab -->
{% endm_codeblock %}        

Install these dependencies in your blog folder (not theme folder):

  • run npm install jsdom --save
  • run npm install jquery --save

and here is the source code of this custom tag put in themes/theme_name/scripts/m_codeblock.js:

'use strict';

var util = require('hexo-util');
var highlight = util.highlight;
var stripIndent = require('strip-indent');
var rCaptionUrl = /(\S[\S\s]*)\s+(https?:\/\/)(\S+)/i;
var rCaption = /(\S[\S\s]*)/;
var rTab = /<!--\s*tab (\w*)\s*-->\n([\w\W\s\S]*?)<!--\s*endtab\s*-->/g;

// create a window with a document to use jQuery library
require("jsdom").env("", function(err, window) {
    if (err) {
        console.error(err);
        return;
    }

    var $ = require("jquery")(window);

    /**
     * Multi code block
     * @param args
     * @param content
     * @returns {string}
     */
    function multiCodeBlock(args, content) {
        var arg = args.join(' ');
        // get blog config
        var config = hexo.config.highlight || {};

        if (!config.enable) {
            return '<pre><code>' + content + '</code></pre>';
        }

        var html;
        var matches = [];
        var match;
        var caption = '';
        var codes = '';

        // extract languages and source codes
        while (match = rTab.exec(content)) {
            matches.push(match[1]);
            matches.push(match[2]);
        }
        // create tabs and tabs content
        for (var i = 0; i < matches.length; i += 2) {
            var lang = matches[i];
            var code = matches[i + 1];
            var $code;
            // trim code
            code = stripIndent(code).trim();
            // add tab
            // active the first tab
            if (i == 0) {
                caption += '<li class="tab active">' + lang + '</li>';
            }
            else {
                caption += '<li class="tab">' + lang + '</li>';
            }
            // highlight code
            code = highlight(code, {
                lang: lang,
                gutter: config.line_number,
                tab: config.tab_replace,
                autoDetect: config.auto_detect
            });
            // used to parse HTML code and ease DOM manipulation
            // display the first code block
            $code = $('<div>').append(code).find('>:first-child');
            if (i == 0) {
                $code.css('display', 'block');
            }
            else {
                $code.css('display', 'none');
            }

            codes += $code.prop('outerHTML');
        }
        // build caption
        caption = '<ul class="tabs">' + caption + '</ul>';
        // add caption title
        if (rCaptionUrl.test(arg)) {
            match = arg.match(rCaptionUrl);
            caption = '<a href="' + match[2] + match[3] + '">' + match[1] + '</a>' + caption;
        }
        else if (rCaption.test(arg)) {
            match = arg.match(rCaption);
            caption = '<span>' + match[1] + '</span>' + caption;
        }
        codes = '<div class="tabs-content">' + codes + '</div>';
        // wrap caption
        caption = '<figcaption>' + caption + '</figcaption>';
        html = '<figure class="highlight multi">' + caption + codes + '</figure>';
        return html;
    }

    /**
     * Multi code block tag
     *
     * Syntax:
     *   {% m_codeblock %}
     *   <!-- tab [lang] -->
     *       content
     *   <!-- endtab -->
     *   {% endm_codeblock %}
     * E.g:
     *   {% m_codeblock %}
     *   <!-- tab js -->
     *       var test = 'test';
     *   <!-- endtab -->
     *   <!-- tab css -->
     *       .btn {
     *           color: red;
     *       }
     *   <!-- endtab -->
     *   {% endm_codeblock %}
     */
    hexo.extend.tag.register('m_codeblock', multiCodeBlock, {ends: true});
});

Read the ment to understand the code.

All you need to do is put your JavaScript files in the scripts folder and Hexo will load them during initialization.

Stylize the code block

By default, only the first tab is displayed and others hidden and we did that in the custom tag source code here :

$code = $('<div>').append(code).find('>:first-child');
if (i == 0) {
  $code.css('display', 'block');
}
else {
  $code.css('display', 'none');
}

So you just need more css to improve user interface and code coloration. Put this file in theme/theme_name/assets/css/style.css and link it to a layout.

Animate the code block (JS client side)

We need some javascript to animate the tab. When we click on a tab, all tab contents must be hidden and only the right tab displayed. Put this script in theme/theme_name/assets/js/script.js and link it to a layout.

$(document).ready(function() {
  $('.highlight.multi').find('.tab').click(function() {
    var $codeblock = $(this).parent().parent().parent();
    var $tab = $(this);
    // remove `active` css class on all tabs
    $tab.siblings().removeClass('active');
    // add `active` css class on the clicked tab
    $tab.addClass('active');
    // hide all tab contents
    $codeblock.find('.highlight').hide();
    // show only the right one
    $codeblock.find('.highlight.' + $tab.text()).show();
  });  
});

Your issue was the opportunity to build this custom tag and I'm gonna integrate it in the next release of a hexo theme (Tranquilpeak) that I developed.

Here is the result :

Check it live on JSFiddle

You can also create inner tags that are read by the parent one.

{% code_with_tabs %}
  {% code js title="something" class_name="info" %}
    1. aosjaojsdoajsdoajsd
  {% endcode %}
  {% code js title="something" class_name="info" %}
    2. aosjaojsdoajsdoajsd
  {% endcode %}
{% endcode_with_tabs %}

And use a parser to read the generated inner HTML.

发布评论

评论列表(0)

  1. 暂无评论