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('tab1')"><a>Tab 1</a></li>';
result += '<li class="li_tab2" onclick="tab('tab2')"><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.
There are too many mistake in your code so I prefer to give you a full example with explanations.
Here is what we need :
- A custom tag to build the HTML structure of this multiple codeblock
- A CSS file to stylize the code block and code coloration
- 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 comment 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.