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.
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.
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 thattab()
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
2 Answers
Reset to default 9 +50There 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 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.