hexo-component-inferno 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,8 +48,7 @@ const CDNJS_FIXTURES = {
48
48
  // disqusjs is not hosted on CDN.js
49
49
  disqusjs: (ver, fname) => [],
50
50
  cookieconsent: (ver, fname) => ['cookieconsent', ver, fname.startsWith('build/') ? fname.substr(6) : fname],
51
- // waline is not hosted on CDN.js
52
- '@waline/client': (ver, fname) => []
51
+ '@waline/client': (ver, fname) => ['waline', ver, fname]
53
52
  };
54
53
  const UNPKG_FIXTURES = {
55
54
  mathjax: (ver, fname) => ['mathjax', ver, fname.indexOf('.min.') > -1 ? fname.replace(/\.min\./gi, '.') : fname],
@@ -17,59 +17,59 @@ describe('Get JavaScript library URL', () => {
17
17
  let cases;
18
18
  beforeEach(async () => {
19
19
  const cdn = hexo.extend.helper.get('cdn').bind(hexo);
20
- cases = [() => cdn('jquery', '3.0.0', 'dist/jquery.min.js'), () => cdn('moment', '2.24.0', 'min/moment.min.js'), () => cdn('outdatedbrowser', '1.1.5', 'outdatedbrowser/outdatedbrowser.min.js'), () => cdn('highlight.js', '9.18.1', 'styles/a11y-dark.css'), () => cdn('mathjax', '2.7.6', 'unpacked/MathJax.min.js'), () => cdn('pace-js', '1.0.2', 'pace.min.js'), () => cdn('katex', '0.11.1', 'dist/katex.min.js'), () => cdn('clipboard', '2.0.6', 'dist/clipboard.min.js'), () => cdn('disqusjs', '1.2.6', 'dist/disqus.min.js'), () => cdn('algoliasearch', '4.0.3', 'dist/algoliasearch-lite.umd.js'), () => cdn('instantsearch.js', '4.3.1', 'dist/instantsearch.production.min.js'), () => cdn('cookieconsent', '3.1.1', 'build/cookieconsent.min.js'), () => cdn('@waline/client', '1.3.1', 'dist/Waline.min.js'), () => cdn('example', '1.0.0', 'example.js')];
20
+ cases = [() => cdn('jquery', '3.0.0', 'dist/jquery.min.js'), () => cdn('moment', '2.24.0', 'min/moment.min.js'), () => cdn('outdatedbrowser', '1.1.5', 'outdatedbrowser/outdatedbrowser.min.js'), () => cdn('highlight.js', '9.18.1', 'styles/a11y-dark.css'), () => cdn('mathjax', '2.7.6', 'unpacked/MathJax.min.js'), () => cdn('pace-js', '1.0.2', 'pace.min.js'), () => cdn('katex', '0.11.1', 'dist/katex.min.js'), () => cdn('clipboard', '2.0.6', 'dist/clipboard.min.js'), () => cdn('disqusjs', '1.2.6', 'dist/disqus.min.js'), () => cdn('algoliasearch', '4.0.3', 'dist/algoliasearch-lite.umd.js'), () => cdn('instantsearch.js', '4.3.1', 'dist/instantsearch.production.min.js'), () => cdn('cookieconsent', '3.1.1', 'build/cookieconsent.min.js'), () => cdn('@waline/client', '1.5.4', 'dist/Waline.min.js'), () => cdn('example', '1.0.0', 'example.js')];
21
21
  });
22
22
  test('jsdelivr', () => {
23
- const expected = ['https://cdn.jsdelivr.net/npm/jquery@3.0.0/dist/jquery.min.js', 'https://cdn.jsdelivr.net/npm/moment@2.24.0/min/moment.min.js', 'https://cdn.jsdelivr.net/npm/outdatedbrowser@1.1.5/outdatedbrowser/outdatedbrowser.min.js', 'https://cdn.jsdelivr.net/npm/highlight.js@9.18.1/styles/a11y-dark.css', 'https://cdn.jsdelivr.net/npm/mathjax@2.7.6/unpacked/MathJax.min.js', 'https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js', 'https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js', 'https://cdn.jsdelivr.net/npm/clipboard@2.0.6/dist/clipboard.min.js', 'https://cdn.jsdelivr.net/npm/disqusjs@1.2.6/dist/disqus.min.js', 'https://cdn.jsdelivr.net/npm/algoliasearch@4.0.3/dist/algoliasearch-lite.umd.js', 'https://cdn.jsdelivr.net/npm/instantsearch.js@4.3.1/dist/instantsearch.production.min.js', 'https://cdn.jsdelivr.net/npm/cookieconsent@3.1.1/build/cookieconsent.min.js', 'https://cdn.jsdelivr.net/npm/@waline/client@1.3.1/dist/Waline.min.js', 'https://cdn.jsdelivr.net/npm/example@1.0.0/example.js'];
23
+ const expected = ['https://cdn.jsdelivr.net/npm/jquery@3.0.0/dist/jquery.min.js', 'https://cdn.jsdelivr.net/npm/moment@2.24.0/min/moment.min.js', 'https://cdn.jsdelivr.net/npm/outdatedbrowser@1.1.5/outdatedbrowser/outdatedbrowser.min.js', 'https://cdn.jsdelivr.net/npm/highlight.js@9.18.1/styles/a11y-dark.css', 'https://cdn.jsdelivr.net/npm/mathjax@2.7.6/unpacked/MathJax.min.js', 'https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js', 'https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.js', 'https://cdn.jsdelivr.net/npm/clipboard@2.0.6/dist/clipboard.min.js', 'https://cdn.jsdelivr.net/npm/disqusjs@1.2.6/dist/disqus.min.js', 'https://cdn.jsdelivr.net/npm/algoliasearch@4.0.3/dist/algoliasearch-lite.umd.js', 'https://cdn.jsdelivr.net/npm/instantsearch.js@4.3.1/dist/instantsearch.production.min.js', 'https://cdn.jsdelivr.net/npm/cookieconsent@3.1.1/build/cookieconsent.min.js', 'https://cdn.jsdelivr.net/npm/@waline/client@1.5.4/dist/Waline.min.js', 'https://cdn.jsdelivr.net/npm/example@1.0.0/example.js'];
24
24
  cases.forEach((func, i) => expect(func()).toBe(expected[i]));
25
25
  });
26
26
  test('unpkg', () => {
27
27
  hexo.config.providers = {
28
28
  cdn: 'unpkg'
29
29
  };
30
- const expected = ['https://unpkg.com/jquery@3.0.0/dist/jquery.min.js', 'https://unpkg.com/moment@2.24.0/min/moment.min.js', 'https://unpkg.com/outdatedbrowser@1.1.5/outdatedbrowser/outdatedbrowser.min.js', 'https://unpkg.com/highlight.js@9.18.1/styles/a11y-dark.css', 'https://unpkg.com/mathjax@2.7.6/unpacked/MathJax.js', 'https://unpkg.com/pace-js@1.0.2/pace.min.js', 'https://unpkg.com/katex@0.11.1/dist/katex.min.js', 'https://unpkg.com/clipboard@2.0.6/dist/clipboard.min.js', 'https://unpkg.com/disqusjs@1.2.6/dist/disqus.js', 'https://unpkg.com/algoliasearch@4.0.3/dist/algoliasearch-lite.umd.js', 'https://unpkg.com/instantsearch.js@4.3.1/dist/instantsearch.production.min.js', 'https://unpkg.com/cookieconsent@3.1.1/build/cookieconsent.min.js', 'https://unpkg.com/@waline/client@1.3.1/dist/Waline.min.js', 'https://unpkg.com/example@1.0.0/example.js'];
30
+ const expected = ['https://unpkg.com/jquery@3.0.0/dist/jquery.min.js', 'https://unpkg.com/moment@2.24.0/min/moment.min.js', 'https://unpkg.com/outdatedbrowser@1.1.5/outdatedbrowser/outdatedbrowser.min.js', 'https://unpkg.com/highlight.js@9.18.1/styles/a11y-dark.css', 'https://unpkg.com/mathjax@2.7.6/unpacked/MathJax.js', 'https://unpkg.com/pace-js@1.0.2/pace.min.js', 'https://unpkg.com/katex@0.11.1/dist/katex.min.js', 'https://unpkg.com/clipboard@2.0.6/dist/clipboard.min.js', 'https://unpkg.com/disqusjs@1.2.6/dist/disqus.js', 'https://unpkg.com/algoliasearch@4.0.3/dist/algoliasearch-lite.umd.js', 'https://unpkg.com/instantsearch.js@4.3.1/dist/instantsearch.production.min.js', 'https://unpkg.com/cookieconsent@3.1.1/build/cookieconsent.min.js', 'https://unpkg.com/@waline/client@1.5.4/dist/Waline.min.js', 'https://unpkg.com/example@1.0.0/example.js'];
31
31
  cases.forEach((func, i) => expect(func()).toBe(expected[i]));
32
32
  });
33
33
  test('cdnjs', () => {
34
34
  hexo.config.providers = {
35
35
  cdn: 'cdnjs'
36
36
  };
37
- const expected = ['https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/outdated-browser/1.1.5/outdatedbrowser.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/a11y-dark.min.css', 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js', 'https://cdnjs.cloudflare.com/ajax/libs/pace/1.0.2/pace.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/katex.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.6/clipboard.min.js', 'https://cdn.jsdelivr.net/npm/disqusjs@1.2.6/dist/disqus.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/algoliasearch/4.0.3/algoliasearch-lite.umd.js', 'https://cdnjs.cloudflare.com/ajax/libs/instantsearch.js/4.3.1/instantsearch.production.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/cookieconsent/3.1.1/cookieconsent.min.js', 'https://cdn.jsdelivr.net/npm/@waline/client@1.3.1/dist/Waline.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/example/1.0.0/example.js'];
37
+ const expected = ['https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/outdated-browser/1.1.5/outdatedbrowser.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/a11y-dark.min.css', 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.6/MathJax.js', 'https://cdnjs.cloudflare.com/ajax/libs/pace/1.0.2/pace.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.11.1/katex.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.6/clipboard.min.js', 'https://cdn.jsdelivr.net/npm/disqusjs@1.2.6/dist/disqus.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/algoliasearch/4.0.3/algoliasearch-lite.umd.js', 'https://cdnjs.cloudflare.com/ajax/libs/instantsearch.js/4.3.1/instantsearch.production.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/cookieconsent/3.1.1/cookieconsent.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/waline/1.5.4/Waline.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/example/1.0.0/example.js'];
38
38
  cases.forEach((func, i) => expect(func()).toBe(expected[i]));
39
39
  });
40
40
  test('loli', () => {
41
41
  hexo.config.providers = {
42
42
  cdn: 'loli'
43
43
  };
44
- const expected = ['https://cdnjs.loli.net/ajax/libs/jquery/3.0.0/jquery.min.js', 'https://cdnjs.loli.net/ajax/libs/moment.js/2.24.0/moment.min.js', 'https://cdnjs.loli.net/ajax/libs/outdated-browser/1.1.5/outdatedbrowser.min.js', 'https://cdnjs.loli.net/ajax/libs/highlight.js/9.18.1/styles/a11y-dark.min.css', 'https://cdnjs.loli.net/ajax/libs/mathjax/2.7.6/MathJax.js', 'https://cdnjs.loli.net/ajax/libs/pace/1.0.2/pace.min.js', 'https://cdnjs.loli.net/ajax/libs/KaTeX/0.11.1/katex.min.js', 'https://cdnjs.loli.net/ajax/libs/clipboard.js/2.0.6/clipboard.min.js', 'https://cdn.jsdelivr.net/npm/disqusjs@1.2.6/dist/disqus.min.js', 'https://cdnjs.loli.net/ajax/libs/algoliasearch/4.0.3/algoliasearch-lite.umd.js', 'https://cdnjs.loli.net/ajax/libs/instantsearch.js/4.3.1/instantsearch.production.min.js', 'https://cdnjs.loli.net/ajax/libs/cookieconsent/3.1.1/cookieconsent.min.js', 'https://cdn.jsdelivr.net/npm/@waline/client@1.3.1/dist/Waline.min.js', 'https://cdnjs.loli.net/ajax/libs/example/1.0.0/example.js'];
44
+ const expected = ['https://cdnjs.loli.net/ajax/libs/jquery/3.0.0/jquery.min.js', 'https://cdnjs.loli.net/ajax/libs/moment.js/2.24.0/moment.min.js', 'https://cdnjs.loli.net/ajax/libs/outdated-browser/1.1.5/outdatedbrowser.min.js', 'https://cdnjs.loli.net/ajax/libs/highlight.js/9.18.1/styles/a11y-dark.min.css', 'https://cdnjs.loli.net/ajax/libs/mathjax/2.7.6/MathJax.js', 'https://cdnjs.loli.net/ajax/libs/pace/1.0.2/pace.min.js', 'https://cdnjs.loli.net/ajax/libs/KaTeX/0.11.1/katex.min.js', 'https://cdnjs.loli.net/ajax/libs/clipboard.js/2.0.6/clipboard.min.js', 'https://cdn.jsdelivr.net/npm/disqusjs@1.2.6/dist/disqus.min.js', 'https://cdnjs.loli.net/ajax/libs/algoliasearch/4.0.3/algoliasearch-lite.umd.js', 'https://cdnjs.loli.net/ajax/libs/instantsearch.js/4.3.1/instantsearch.production.min.js', 'https://cdnjs.loli.net/ajax/libs/cookieconsent/3.1.1/cookieconsent.min.js', 'https://cdnjs.loli.net/ajax/libs/waline/1.5.4/Waline.min.js', 'https://cdnjs.loli.net/ajax/libs/example/1.0.0/example.js'];
45
45
  cases.forEach((func, i) => expect(func()).toBe(expected[i]));
46
46
  });
47
47
  test('bootcdn', () => {
48
48
  hexo.config.providers = {
49
49
  cdn: 'bootcdn'
50
50
  };
51
- const expected = ['https://cdn.bootcdn.net/ajax/libs/jquery/3.0.0/jquery.min.js', 'https://cdn.bootcdn.net/ajax/libs/moment.js/2.24.0/moment.min.js', 'https://cdn.bootcdn.net/ajax/libs/outdated-browser/1.1.5/outdatedbrowser.min.js', 'https://cdn.bootcdn.net/ajax/libs/highlight.js/9.18.1/styles/a11y-dark.min.css', 'https://cdn.bootcdn.net/ajax/libs/mathjax/2.7.6/MathJax.js', 'https://cdn.bootcdn.net/ajax/libs/pace/1.0.2/pace.min.js', 'https://cdn.bootcdn.net/ajax/libs/KaTeX/0.11.1/katex.min.js', 'https://cdn.bootcdn.net/ajax/libs/clipboard.js/2.0.6/clipboard.min.js', 'https://cdn.jsdelivr.net/npm/disqusjs@1.2.6/dist/disqus.min.js', 'https://cdn.bootcdn.net/ajax/libs/algoliasearch/4.0.3/algoliasearch-lite.umd.js', 'https://cdn.bootcdn.net/ajax/libs/instantsearch.js/4.3.1/instantsearch.production.min.js', 'https://cdn.bootcdn.net/ajax/libs/cookieconsent/3.1.1/cookieconsent.min.js', 'https://cdn.jsdelivr.net/npm/@waline/client@1.3.1/dist/Waline.min.js', 'https://cdn.bootcdn.net/ajax/libs/example/1.0.0/example.js'];
51
+ const expected = ['https://cdn.bootcdn.net/ajax/libs/jquery/3.0.0/jquery.min.js', 'https://cdn.bootcdn.net/ajax/libs/moment.js/2.24.0/moment.min.js', 'https://cdn.bootcdn.net/ajax/libs/outdated-browser/1.1.5/outdatedbrowser.min.js', 'https://cdn.bootcdn.net/ajax/libs/highlight.js/9.18.1/styles/a11y-dark.min.css', 'https://cdn.bootcdn.net/ajax/libs/mathjax/2.7.6/MathJax.js', 'https://cdn.bootcdn.net/ajax/libs/pace/1.0.2/pace.min.js', 'https://cdn.bootcdn.net/ajax/libs/KaTeX/0.11.1/katex.min.js', 'https://cdn.bootcdn.net/ajax/libs/clipboard.js/2.0.6/clipboard.min.js', 'https://cdn.jsdelivr.net/npm/disqusjs@1.2.6/dist/disqus.min.js', 'https://cdn.bootcdn.net/ajax/libs/algoliasearch/4.0.3/algoliasearch-lite.umd.js', 'https://cdn.bootcdn.net/ajax/libs/instantsearch.js/4.3.1/instantsearch.production.min.js', 'https://cdn.bootcdn.net/ajax/libs/cookieconsent/3.1.1/cookieconsent.min.js', 'https://cdn.bootcdn.net/ajax/libs/waline/1.5.4/Waline.min.js', 'https://cdn.bootcdn.net/ajax/libs/example/1.0.0/example.js'];
52
52
  cases.forEach((func, i) => expect(func()).toBe(expected[i]));
53
53
  });
54
54
  test('75cdn', () => {
55
55
  hexo.config.providers = {
56
56
  cdn: '75cdn'
57
57
  };
58
- const expected = ['https://lib.baomitu.com/jquery/3.0.0/jquery.min.js', 'https://lib.baomitu.com/moment.js/2.24.0/moment.min.js', 'https://lib.baomitu.com/outdated-browser/1.1.5/outdatedbrowser.min.js', 'https://lib.baomitu.com/highlight.js/9.18.1/styles/a11y-dark.min.css', 'https://lib.baomitu.com/mathjax/2.7.6/MathJax.js', 'https://lib.baomitu.com/pace/1.0.2/pace.min.js', 'https://lib.baomitu.com/KaTeX/0.11.1/katex.min.js', 'https://lib.baomitu.com/clipboard.js/2.0.6/clipboard.min.js', 'https://cdn.jsdelivr.net/npm/disqusjs@1.2.6/dist/disqus.min.js', 'https://lib.baomitu.com/algoliasearch/4.0.3/algoliasearch-lite.umd.js', 'https://lib.baomitu.com/instantsearch.js/4.3.1/instantsearch.production.min.js', 'https://lib.baomitu.com/cookieconsent/3.1.1/cookieconsent.min.js', 'https://cdn.jsdelivr.net/npm/@waline/client@1.3.1/dist/Waline.min.js', 'https://lib.baomitu.com/example/1.0.0/example.js'];
58
+ const expected = ['https://lib.baomitu.com/jquery/3.0.0/jquery.min.js', 'https://lib.baomitu.com/moment.js/2.24.0/moment.min.js', 'https://lib.baomitu.com/outdated-browser/1.1.5/outdatedbrowser.min.js', 'https://lib.baomitu.com/highlight.js/9.18.1/styles/a11y-dark.min.css', 'https://lib.baomitu.com/mathjax/2.7.6/MathJax.js', 'https://lib.baomitu.com/pace/1.0.2/pace.min.js', 'https://lib.baomitu.com/KaTeX/0.11.1/katex.min.js', 'https://lib.baomitu.com/clipboard.js/2.0.6/clipboard.min.js', 'https://cdn.jsdelivr.net/npm/disqusjs@1.2.6/dist/disqus.min.js', 'https://lib.baomitu.com/algoliasearch/4.0.3/algoliasearch-lite.umd.js', 'https://lib.baomitu.com/instantsearch.js/4.3.1/instantsearch.production.min.js', 'https://lib.baomitu.com/cookieconsent/3.1.1/cookieconsent.min.js', 'https://lib.baomitu.com/waline/1.5.4/Waline.min.js', 'https://lib.baomitu.com/example/1.0.0/example.js'];
59
59
  cases.forEach((func, i) => expect(func()).toBe(expected[i]));
60
60
  });
61
61
  test('Custom CDN', () => {
62
62
  hexo.config.providers = {
63
63
  cdn: 'https://my.cdn/${ package }@${ version }/${ filename }'
64
64
  };
65
- const expected = ['https://my.cdn/jquery@3.0.0/dist/jquery.min.js', 'https://my.cdn/moment@2.24.0/min/moment.min.js', 'https://my.cdn/outdatedbrowser@1.1.5/outdatedbrowser/outdatedbrowser.min.js', 'https://my.cdn/highlight.js@9.18.1/styles/a11y-dark.css', 'https://my.cdn/mathjax@2.7.6/unpacked/MathJax.min.js', 'https://my.cdn/pace-js@1.0.2/pace.min.js', 'https://my.cdn/katex@0.11.1/dist/katex.min.js', 'https://my.cdn/clipboard@2.0.6/dist/clipboard.min.js', 'https://my.cdn/disqusjs@1.2.6/dist/disqus.min.js', 'https://my.cdn/algoliasearch@4.0.3/dist/algoliasearch-lite.umd.js', 'https://my.cdn/instantsearch.js@4.3.1/dist/instantsearch.production.min.js', 'https://my.cdn/cookieconsent@3.1.1/build/cookieconsent.min.js', 'https://my.cdn/@waline/client@1.3.1/dist/Waline.min.js', 'https://my.cdn/example@1.0.0/example.js'];
65
+ const expected = ['https://my.cdn/jquery@3.0.0/dist/jquery.min.js', 'https://my.cdn/moment@2.24.0/min/moment.min.js', 'https://my.cdn/outdatedbrowser@1.1.5/outdatedbrowser/outdatedbrowser.min.js', 'https://my.cdn/highlight.js@9.18.1/styles/a11y-dark.css', 'https://my.cdn/mathjax@2.7.6/unpacked/MathJax.min.js', 'https://my.cdn/pace-js@1.0.2/pace.min.js', 'https://my.cdn/katex@0.11.1/dist/katex.min.js', 'https://my.cdn/clipboard@2.0.6/dist/clipboard.min.js', 'https://my.cdn/disqusjs@1.2.6/dist/disqus.min.js', 'https://my.cdn/algoliasearch@4.0.3/dist/algoliasearch-lite.umd.js', 'https://my.cdn/instantsearch.js@4.3.1/dist/instantsearch.production.min.js', 'https://my.cdn/cookieconsent@3.1.1/build/cookieconsent.min.js', 'https://my.cdn/@waline/client@1.5.4/dist/Waline.min.js', 'https://my.cdn/example@1.0.0/example.js'];
66
66
  cases.forEach((func, i) => expect(func()).toBe(expected[i]));
67
67
  });
68
68
  test('Custom CDN.js-style CDN', () => {
69
69
  hexo.config.providers = {
70
70
  cdn: '[cdnjs]https://my.cdn/ajax/libs/${ package }/${ version }/${ filename }'
71
71
  };
72
- const expected = ['https://my.cdn/ajax/libs/jquery/3.0.0/jquery.min.js', 'https://my.cdn/ajax/libs/moment.js/2.24.0/moment.min.js', 'https://my.cdn/ajax/libs/outdated-browser/1.1.5/outdatedbrowser.min.js', 'https://my.cdn/ajax/libs/highlight.js/9.18.1/styles/a11y-dark.min.css', 'https://my.cdn/ajax/libs/mathjax/2.7.6/MathJax.js', 'https://my.cdn/ajax/libs/pace/1.0.2/pace.min.js', 'https://my.cdn/ajax/libs/KaTeX/0.11.1/katex.min.js', 'https://my.cdn/ajax/libs/clipboard.js/2.0.6/clipboard.min.js', 'https://cdn.jsdelivr.net/npm/disqusjs@1.2.6/dist/disqus.min.js', 'https://my.cdn/ajax/libs/algoliasearch/4.0.3/algoliasearch-lite.umd.js', 'https://my.cdn/ajax/libs/instantsearch.js/4.3.1/instantsearch.production.min.js', 'https://my.cdn/ajax/libs/cookieconsent/3.1.1/cookieconsent.min.js', 'https://cdn.jsdelivr.net/npm/@waline/client@1.3.1/dist/Waline.min.js', 'https://my.cdn/ajax/libs/example/1.0.0/example.js'];
72
+ const expected = ['https://my.cdn/ajax/libs/jquery/3.0.0/jquery.min.js', 'https://my.cdn/ajax/libs/moment.js/2.24.0/moment.min.js', 'https://my.cdn/ajax/libs/outdated-browser/1.1.5/outdatedbrowser.min.js', 'https://my.cdn/ajax/libs/highlight.js/9.18.1/styles/a11y-dark.min.css', 'https://my.cdn/ajax/libs/mathjax/2.7.6/MathJax.js', 'https://my.cdn/ajax/libs/pace/1.0.2/pace.min.js', 'https://my.cdn/ajax/libs/KaTeX/0.11.1/katex.min.js', 'https://my.cdn/ajax/libs/clipboard.js/2.0.6/clipboard.min.js', 'https://cdn.jsdelivr.net/npm/disqusjs@1.2.6/dist/disqus.min.js', 'https://my.cdn/ajax/libs/algoliasearch/4.0.3/algoliasearch-lite.umd.js', 'https://my.cdn/ajax/libs/instantsearch.js/4.3.1/instantsearch.production.min.js', 'https://my.cdn/ajax/libs/cookieconsent/3.1.1/cookieconsent.min.js', 'https://my.cdn/ajax/libs/waline/1.5.4/Waline.min.js', 'https://my.cdn/ajax/libs/example/1.0.0/example.js'];
73
73
  cases.forEach((func, i) => expect(func()).toBe(expected[i]));
74
74
  });
75
75
  });
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Register custom Hexo tag {% message %}.
3
+ * @module hexo/tag/message
4
+ */
5
+
6
+ /**
7
+ * Register custom Hexo tag {% message %}.
8
+ * <p>
9
+ * This tag is rendered as a Bulma message box.
10
+ *
11
+ * <h5>Tag Parameters:<h5>
12
+ * <table class="params">
13
+ * <tr>
14
+ * <th>Name</th>
15
+ * <th>Type</th>
16
+ * <th class="description">Description</th>
17
+ * </tr>
18
+ * <tr>
19
+ * <td class="name"><code>color</code></td>
20
+ * <td class="type"><span class="param-type"><code>string</code></span></td>
21
+ * <td class="description">[Optional] Color of the message. Available values are: dark, primary, link, info, success, warning, danger.</td>
22
+ * </tr>
23
+ * <tr>
24
+ * <td class="name"><code>icon</code></td>
25
+ * <td class="type"><span class="param-type"><code>string</code></span></td>
26
+ * <td class="description">[Optional] Icon shown in the message header. Use FontAwesome icon class name for this field.</td>
27
+ * </tr>
28
+ * <tr>
29
+ * <td class="name"><code>title</code></td>
30
+ * <td class="type"><span class="param-type"><code>string</code></span></td>
31
+ * <td class="description">[Optional] Message title in the message header. Markdown is supported.</td>
32
+ * </tr>
33
+ * <tr>
34
+ * <td class="name"><code>size</code></td>
35
+ * <td class="type"><span class="param-type"><code>string</code></span></td>
36
+ * <td class="description last">[Optional] Size of the message box. Available values are: small, medium, large. Default size is normal.</td>
37
+ * </tr>
38
+ * </table>
39
+ *
40
+ * @see https://bulma.io/documentation/components/message/.
41
+ *
42
+ * @param {Hexo} hexo The Hexo instance.
43
+ *
44
+ * @example
45
+ * {% message color:warning 'icon:fas fa-info-circle' 'title:*ATTENTION*' size:small %}
46
+ * **This is a warning message.**
47
+ * {% endmessage %}
48
+ */
49
+ module.exports = function (hexo) {
50
+ function processTag(options, content) {
51
+ let icon = '';
52
+ let title = '';
53
+ let classes = '';
54
+ let header = '';
55
+
56
+ for (const option of options) {
57
+ const [key, value] = option.split(':');
58
+
59
+ switch (key) {
60
+ case 'size':
61
+ classes += ` is-${value}`;
62
+ break;
63
+
64
+ case 'color':
65
+ classes += ` is-${value}`;
66
+ break;
67
+
68
+ case 'icon':
69
+ icon = `<i class="${value} mr-2"></i>`;
70
+ break;
71
+
72
+ case 'title':
73
+ title = value;
74
+ break;
75
+ }
76
+ }
77
+
78
+ if (icon !== '' || title !== '') {
79
+ const inner = hexo.render.renderSync({
80
+ text: icon + title,
81
+ engine: 'markdown'
82
+ });
83
+ header = `<div class="message-header">${inner}</div>`;
84
+ }
85
+
86
+ return `<article class="message${classes}">
87
+ ${header}
88
+ <div class="message-body">
89
+ ${hexo.render.renderSync({
90
+ text: content,
91
+ engine: 'markdown'
92
+ })}
93
+ </div>
94
+ </article>`;
95
+ }
96
+
97
+ hexo.extend.tag.register('message', processTag, {
98
+ ends: true
99
+ });
100
+ };
@@ -0,0 +1,70 @@
1
+ const {
2
+ join
3
+ } = require('path');
4
+
5
+ const Hexo = require('hexo');
6
+
7
+ const cheerio = require('cheerio');
8
+
9
+ const register = require('./message');
10
+
11
+ const rootDir = join(__dirname, '../../../fixture/site');
12
+ const hexo = new Hexo(rootDir, {
13
+ silent: true
14
+ });
15
+ const cheerioOptions = {
16
+ xml: {
17
+ normalizeWhitespace: true
18
+ }
19
+ };
20
+ beforeAll(async () => {
21
+ await hexo.init();
22
+ await hexo.load();
23
+ register(hexo);
24
+ await hexo.loadPlugin(require.resolve('hexo-renderer-markdown'));
25
+ });
26
+ test('create default message', async () => {
27
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
28
+ let source = '{% message %}**content**{% endmessage %}';
29
+ let actual = cheerio.load(await render(source), cheerioOptions, false).html();
30
+ expect(actual).toEqual('<article class="message"> <div class="message-body"> ' + '<p><strong>content</strong></p> </div> </article>');
31
+ source = '{% message %}\n# title\n{% endmessage %}';
32
+ actual = cheerio.load(await render(source), cheerioOptions, false).html();
33
+ expect(actual).toEqual('<article class="message"> <div class="message-body"> ' + '<h1 id="title"><a class="header-anchor" href="#title">&#xB6;</a> title</h1> ' + '</div> </article>');
34
+ });
35
+ test('create message with different colors', async () => {
36
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
37
+
38
+ for (const color of ['dark', 'primary', 'link', 'info', 'success', 'warning', 'danger']) {
39
+ const source = `{% message color:${color} %}content{% endmessage %}`;
40
+ const actual = cheerio.load(await render(source), cheerioOptions, false).html();
41
+ expect(actual).toEqual(`<article class="message is-${color}"> <div class="message-body"> <p>content</p> ` + '</div> </article>');
42
+ }
43
+ });
44
+ test('create message with different sizes', async () => {
45
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
46
+
47
+ for (const size of ['small', 'medium', 'large']) {
48
+ const source = `{% message size:${size} %}content{% endmessage %}`;
49
+ const actual = cheerio.load(await render(source), cheerioOptions, false).html();
50
+ expect(actual).toEqual(`<article class="message is-${size}"> <div class="message-body"> <p>content</p> ` + '</div> </article>');
51
+ }
52
+ });
53
+ test('create message with an icon', async () => {
54
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
55
+ const source = '{% message "icon:fas fas-file" %}content{% endmessage %}';
56
+ const actual = cheerio.load(await render(source), cheerioOptions, false).html();
57
+ expect(actual).toEqual('<article class="message"> <div class="message-header"><p>' + '<i class="fas fas-file mr-2"/></p> </div> <div class="message-body"> <p>content</p> ' + '</div> </article>');
58
+ });
59
+ test('create message with a title', async () => {
60
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
61
+ const source = '{% message "title:*message title*" %}content{% endmessage %}';
62
+ const actual = cheerio.load(await render(source), cheerioOptions, false).html();
63
+ expect(actual).toEqual('<article class="message"> <div class="message-header"><p>' + '<em>message title</em></p> </div> <div class="message-body"> <p>content</p> ' + '</div> </article>');
64
+ });
65
+ test('create message with all properties', async () => {
66
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
67
+ const source = '{% message color:success size:small "icon:fas fas-file" ' + '"title:*message title*" %}content{% endmessage %}';
68
+ const actual = cheerio.load(await render(source), cheerioOptions, false).html();
69
+ expect(actual).toEqual('<article class="message is-success is-small"> <div class="message-header"><p>' + '<i class="fas fas-file mr-2"/><em>message title</em></p> </div> ' + '<div class="message-body"> <p>content</p> </div> </article>');
70
+ });
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Register custom Hexo tag {% tabs %}.
3
+ * @module hexo/tag/tabs
4
+ */
5
+
6
+ /**
7
+ * Register custom Hexo tag {% tabs %}.
8
+ * <p>
9
+ * This tag is rendered as a Bulma tabs component.
10
+ * <p>
11
+ * Each individual tab must be wrapped with <code>&lt;!-- tab [...tab_param] --&gt;&lt;!-- endtab --&gt;</code>
12
+ *
13
+ * <h5>Tag Parameters:<h5>
14
+ * <table class="params">
15
+ * <tr>
16
+ * <th>Name</th>
17
+ * <th>Type</th>
18
+ * <th class="description">Description</th>
19
+ * </tr>
20
+ * <tr>
21
+ * <td class="name"><code>align</code></td>
22
+ * <td class="type"><span class="param-type"><code>string</code></span></td>
23
+ * <td class="description">[Optional] Alignment of the tabs. Available values are: left, centered, right, fullwidth. Default alignment is left.</td>
24
+ * </tr>
25
+ * <tr>
26
+ * <td class="name"><code>size</code></td>
27
+ * <td class="type"><span class="param-type"><code>string</code></span></td>
28
+ * <td class="description">[Optional] Size of the tabs. Available values are: small, medium, large. Default size is normal.</td>
29
+ * </tr>
30
+ * <tr>
31
+ * <td class="name"><code>style</code></td>
32
+ * <td class="type"><span class="param-type"><code>string</code></span></td>
33
+ * <td class="description">[Optional] Style of the tabs. Available values are: boxed, toggle, toggle-rounded. Default style is none.</td>
34
+ * </tr>
35
+ * </table>
36
+ *
37
+ * <h5>Tab Parameters:<h5>
38
+ * <table class="params">
39
+ * <tr>
40
+ * <th>Name</th>
41
+ * <th>Type</th>
42
+ * <th class="description">Description</th>
43
+ * </tr>
44
+ * <tr>
45
+ * <td class="name"><code>id</code></td>
46
+ * <td class="type"><span class="param-type"><code>string</code></span></td>
47
+ * <td class="description">[Optional] The ID of the current tab. This value must be unique on each page.</td>
48
+ * </tr>
49
+ * <tr>
50
+ * <td class="name"><code>active</code></td>
51
+ * <td class="type"><span class="param-type"><code>boolean</code></span></td>
52
+ * <td class="description">[Optional] Whether to show current tab by default. Only one of the tabs can be set to active.</td>
53
+ * </tr>
54
+ * <tr>
55
+ * <td class="name"><code>title</code></td>
56
+ * <td class="type"><span class="param-type"><code>string</code></span></td>
57
+ * <td class="description">[Optional] Title of the current tab.</td>
58
+ * </tr>
59
+ * <tr>
60
+ * <td class="name"><code>icon</code></td>
61
+ * <td class="type"><span class="param-type"><code>string</code></span></td>
62
+ * <td class="description">[Optional] Icon of the current tab. Use FontAwesome icon class name for this field.</td>
63
+ * </tr>
64
+ * </table>
65
+ *
66
+ * @see https://bulma.io/documentation/components/tabs/.
67
+ *
68
+ * @param {Hexo} hexo The Hexo instance.
69
+ *
70
+ * @example
71
+ * {% tabs align:fullwidth size:small style:toggle-rounded %}
72
+ * <!-- tab active id:tab_hello title:Hello -->
73
+ * This is hello.
74
+ * <!-- endtab -->
75
+ * <!-- tab id:tab_info 'icon:fas fa-info' 'title:Info Tab' -->This is info.<!-- endtab -->
76
+ * {% endmessage %}
77
+ */
78
+ module.exports = function (hexo) {
79
+ function splitTabOptions(s) {
80
+ const options = [];
81
+ const EOL = -1;
82
+ let i = 0;
83
+ let state = 1;
84
+ let begin = 0;
85
+
86
+ while (i <= s.length) {
87
+ const c = i < s.length ? s.charAt(i) : '';
88
+
89
+ switch (state) {
90
+ case 1:
91
+ if (c === ' ') {
92
+ state = 1;
93
+ begin = i + 1;
94
+ } else if (c === '"') {
95
+ state = 2;
96
+ begin = i + 1;
97
+ } else if (c === "'") {
98
+ state = 4;
99
+ begin = i + 1;
100
+ } else if (c === '') {
101
+ state = EOL;
102
+ } else {
103
+ state = 7;
104
+ }
105
+
106
+ break;
107
+
108
+ case 2:
109
+ if (c === '\\') {
110
+ state = 3;
111
+ } else if (c === '"') {
112
+ state = 6;
113
+ }
114
+
115
+ break;
116
+
117
+ case 3:
118
+ state = 2;
119
+ break;
120
+
121
+ case 4:
122
+ if (c === '\\') {
123
+ state = 5;
124
+ } else if (c === "'") {
125
+ state = 6;
126
+ }
127
+
128
+ break;
129
+
130
+ case 5:
131
+ state = 4;
132
+ break;
133
+
134
+ case 6:
135
+ options.push(s.substring(begin, i - 1));
136
+ begin = i + 1;
137
+
138
+ if (c === ' ') {
139
+ state = 1;
140
+ } else if (c === '') {
141
+ state = EOL;
142
+ } else {
143
+ throw new Error(`malformatted tab options: ${s}`);
144
+ }
145
+
146
+ break;
147
+
148
+ case 7:
149
+ if (c === ' ') {
150
+ options.push(s.substring(begin, i));
151
+ begin = i + 1;
152
+ state = 1;
153
+ } else if (c === '') {
154
+ options.push(s.substring(begin, i));
155
+ begin = i + 1;
156
+ state = EOL;
157
+ }
158
+
159
+ break;
160
+ }
161
+
162
+ i++;
163
+ }
164
+
165
+ if (state !== EOL) {
166
+ throw new Error(`malformatted tab options: ${s}`);
167
+ }
168
+
169
+ return options;
170
+ }
171
+
172
+ function processTag(options, content) {
173
+ let classes = '';
174
+
175
+ for (const option of options) {
176
+ const [key, value] = option.split(':');
177
+
178
+ switch (key) {
179
+ case 'align':
180
+ classes += ` is-${value}`;
181
+ break;
182
+
183
+ case 'size':
184
+ classes += ` is-${value}`;
185
+ break;
186
+
187
+ case 'style':
188
+ if (value === 'toggle-rounded') {
189
+ classes += ' is-toggle';
190
+ }
191
+
192
+ classes += ` is-${value}`;
193
+ break;
194
+ }
195
+ }
196
+
197
+ const pattern = /<!--\s*tab\s*(.*?)\s*-->([\s\S]*?)<!--\s*endtab\s*-->/g;
198
+ let match;
199
+ let tabElements = '';
200
+ let contentElements = '';
201
+
202
+ while ((match = pattern.exec(content)) !== null) {
203
+ const [, tabOptions, tabContent] = match;
204
+ let id = 'tab-' + Date.now() + (Math.random() * 1000 | 0);
205
+ let icon = '';
206
+ let title = '';
207
+ let active = false;
208
+
209
+ for (const option of splitTabOptions(tabOptions)) {
210
+ const [key, value] = option.split(':');
211
+
212
+ switch (key) {
213
+ case 'id':
214
+ id = value;
215
+ break;
216
+
217
+ case 'active':
218
+ active = true;
219
+ break;
220
+
221
+ case 'icon':
222
+ icon = `<span class="icon is-small ml-0">
223
+ <i class="${value}" aria-hidden="true"></i>
224
+ </span>`;
225
+ break;
226
+
227
+ case 'title':
228
+ title = value;
229
+ break;
230
+ }
231
+ }
232
+
233
+ tabElements += `<li${active ? ' class="is-active"' : ''}>
234
+ <a href="#${id}">
235
+ ${hexo.render.renderSync({
236
+ text: icon + title,
237
+ engine: 'markdown'
238
+ })}
239
+ </a>
240
+ </li>`;
241
+ contentElements += `<div id="${id}" class="tab-content${active ? '' : ' is-hidden'}">
242
+ ${hexo.render.renderSync({
243
+ text: tabContent,
244
+ engine: 'markdown'
245
+ })}
246
+ </div>`;
247
+ }
248
+
249
+ return `<div class="tabs my-3${classes}">
250
+ <ul class="mx-0 my-0">
251
+ ${tabElements}
252
+ </ul>
253
+ </div>
254
+ ${contentElements}`;
255
+ }
256
+
257
+ const script = `<script>
258
+ (function () {
259
+ function switchTab() {
260
+ if (!location.hash) {
261
+ return;
262
+ }
263
+ Array
264
+ .from(document.querySelectorAll('.tab-content'))
265
+ .forEach($tab => {
266
+ $tab.classList.add('is-hidden');
267
+ });
268
+ Array
269
+ .from(document.querySelectorAll('.tabs li'))
270
+ .forEach($tab => {
271
+ $tab.classList.remove('is-active');
272
+ });
273
+ const $activeTab = document.querySelector(location.hash);
274
+ if ($activeTab) {
275
+ $activeTab.classList.remove('is-hidden');
276
+ }
277
+ const $tabMenu = document.querySelector(\`a[href="\${location.hash}"]\`);
278
+ if ($tabMenu) {
279
+ $tabMenu.parentElement.classList.add('is-active');
280
+ }
281
+ }
282
+ switchTab();
283
+ window.addEventListener('hashchange', switchTab, false);
284
+ })();
285
+ </script>`;
286
+ hexo.extend.injector.register('head_end', script);
287
+ hexo.extend.tag.register('tabs', processTag, {
288
+ ends: true
289
+ });
290
+ };
@@ -0,0 +1,97 @@
1
+ const {
2
+ join
3
+ } = require('path');
4
+
5
+ const Hexo = require('hexo');
6
+
7
+ const cheerio = require('cheerio');
8
+
9
+ const register = require('./tabs');
10
+
11
+ const rootDir = join(__dirname, '../../../fixture/site');
12
+ const hexo = new Hexo(rootDir, {
13
+ silent: true
14
+ });
15
+ const cheerioOptions = {
16
+ xml: {
17
+ normalizeWhitespace: true
18
+ }
19
+ };
20
+ beforeAll(async () => {
21
+ await hexo.init();
22
+ await hexo.load();
23
+ register(hexo);
24
+ await hexo.loadPlugin(require.resolve('hexo-renderer-markdown'));
25
+ });
26
+ test('create default tabs', async () => {
27
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
28
+ let source = '{% tabs %}<!--tab id:tab1-->**content**<!--endtab-->{% endtabs %}';
29
+ let actual = cheerio.load(await render(source), cheerioOptions, false).html();
30
+ expect(actual).toEqual('<div class="tabs my-3"> <ul class="mx-0 my-0"> <li> <a href="#tab1"> </a> </li> </ul> ' + '</div> <div id="tab1" class="tab-content is-hidden"> <p><strong>content</strong></p> </div>');
31
+ source = `{% tabs %}
32
+ <!-- tab --># title 1<!-- endtab -->
33
+ <!-- tab --># title 2<!-- endtab -->
34
+ {% endtabs %}`;
35
+ const $ = cheerio.load(await render(source), cheerioOptions, false);
36
+ const [tabId1, tabId2] = $('.tab-content').get().map(element => $(element).attr('id'));
37
+ actual = $.html();
38
+ expect(actual).toEqual(`<div class="tabs my-3"> <ul class="mx-0 my-0"> <li> <a href="#${tabId1}"> </a> ` + `</li><li> <a href="#${tabId2}"> </a> </li> </ul> </div> ` + `<div id="${tabId1}" class="tab-content is-hidden"> <h1 id="title 1">` + '<a class="header-anchor" href="#title 1">&#xB6;</a> title 1</h1> </div>' + `<div id="${tabId2}" class="tab-content is-hidden"> <h1 id="title 2">` + '<a class="header-anchor" href="#title 2">&#xB6;</a> title 2</h1> </div>');
39
+ });
40
+ test('create tabs with different alignment', async () => {
41
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
42
+
43
+ for (const align of ['left', 'centered', 'right', 'fullwidth']) {
44
+ const source = `{% tabs align:${align} %}<!--tab id:tab1-->content<!--endtab-->{% endtabs %}`;
45
+ const actual = cheerio.load(await render(source), cheerioOptions, false).html();
46
+ expect(actual).toEqual(`<div class="tabs my-3 is-${align}"> <ul class="mx-0 my-0"> <li> <a href="#tab1"> </a> ` + '</li> </ul> </div> <div id="tab1" class="tab-content is-hidden"> ' + '<p>content</p> </div>');
47
+ }
48
+ });
49
+ test('create tabs with different sizes', async () => {
50
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
51
+
52
+ for (const size of ['small', 'medium', 'large']) {
53
+ const source = `{% tabs size:${size} %}<!--tab id:tab1-->content<!--endtab-->{% endtabs %}`;
54
+ const actual = cheerio.load(await render(source), cheerioOptions, false).html();
55
+ expect(actual).toEqual(`<div class="tabs my-3 is-${size}"> <ul class="mx-0 my-0"> <li> <a href="#tab1"> </a> ` + '</li> </ul> </div> <div id="tab1" class="tab-content is-hidden"> ' + '<p>content</p> </div>');
56
+ }
57
+ });
58
+ test('create tabs with different styles', async () => {
59
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
60
+
61
+ for (const style of ['boxed', 'toggle', 'toggle-rounded']) {
62
+ const source = `{% tabs style:${style} %}<!--tab id:tab1-->content<!--endtab-->{% endtabs %}`;
63
+ const actual = cheerio.load(await render(source), cheerioOptions, false).html();
64
+ const classname = style === 'toggle-rounded' ? 'toggle is-toggle-rounded' : style;
65
+ expect(actual).toEqual(`<div class="tabs my-3 is-${classname}"> <ul class="mx-0 my-0"> <li> <a href="#tab1"> </a> ` + '</li> </ul> </div> <div id="tab1" class="tab-content is-hidden"> ' + '<p>content</p> </div>');
66
+ }
67
+ });
68
+ test('create tabs with active status', async () => {
69
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
70
+ const source = `{% tabs %}
71
+ <!-- tab id:tab1 -->tab 1<!-- endtab -->
72
+ <!-- tab id:tab2 active -->tab 2<!-- endtab -->
73
+ {% endtabs %}`;
74
+ const actual = cheerio.load(await render(source), cheerioOptions, false).html();
75
+ expect(actual).toEqual('<div class="tabs my-3"> <ul class="mx-0 my-0"> <li> <a href="#tab1"> </a> ' + '</li><li class="is-active"> <a href="#tab2"> </a> </li> </ul> </div> ' + '<div id="tab1" class="tab-content is-hidden"> <p>tab 1</p> </div>' + '<div id="tab2" class="tab-content"> <p>tab 2</p> </div>');
76
+ });
77
+ test('create tabs with a title', async () => {
78
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
79
+ const source = '{% tabs %}<!--tab id:tab1 "title:Tab Title"-->tab<!--endtab-->{% endtabs %}';
80
+ const actual = cheerio.load(await render(source), cheerioOptions, false).html();
81
+ expect(actual).toEqual('<div class="tabs my-3"> <ul class="mx-0 my-0"> <li> <a href="#tab1"> <p>Tab Title</p> </a> ' + '</li> </ul> </div> <div id="tab1" class="tab-content is-hidden"> <p>tab</p> </div>');
82
+ });
83
+ test('create tabs with an icon', async () => {
84
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
85
+ const source = '{% tabs %}<!--tab id:tab1 "icon:fab fa-github"-->tab<!--endtab-->{% endtabs %}';
86
+ const actual = cheerio.load(await render(source), cheerioOptions, false).html();
87
+ expect(actual).toEqual('<div class="tabs my-3"> <ul class="mx-0 my-0"> <li> <a href="#tab1"> ' + '<span class="icon is-small ml-0"> <i class="fab fa-github" aria-hidden="true"/> ' + '</span> </a> </li> </ul> </div> <div id="tab1" class="tab-content is-hidden"> ' + '<p>tab</p> </div>');
88
+ });
89
+ test('create tabs with all properties', async () => {
90
+ const render = hexo.extend.tag.render.bind(hexo.extend.tag);
91
+ const source = `{% tabs align:fullwidth 'size:large' style:boxed %}
92
+ <!-- tab id:tab1 "icon:fas\\ fa-file" -->tab 1<!-- endtab -->
93
+ <!-- tab id:tab2 active 'title:Tim\\'s Tab' -->tab 2<!-- endtab -->
94
+ {% endtabs %}`;
95
+ const actual = cheerio.load(await render(source), cheerioOptions, false).html();
96
+ expect(actual).toEqual('<div class="tabs my-3 is-fullwidth is-large is-boxed"> <ul class="mx-0 my-0"> <li> ' + '<a href="#tab1"> <span class="icon is-small ml-0"> ' + '<i class="fas\\ fa-file" aria-hidden="true"/> </span> </a> </li><li class="is-active"> ' + '<a href="#tab2"> <p>Tim&#x2019;s Tab</p> </a> </li> </ul> </div> ' + '<div id="tab1" class="tab-content is-hidden"> <p>tab 1</p> </div>' + '<div id="tab2" class="tab-content"> <p>tab 2</p> </div>');
97
+ });
@@ -12,6 +12,10 @@
12
12
  "type": "string",
13
13
  "description": "Waline server address url."
14
14
  },
15
+ "path": {
16
+ "type": "string",
17
+ "description": "Article path id. Used to distinguish different article pages to ensure loading the correct comment list under the article page."
18
+ },
15
19
  "lang": {
16
20
  "type": "string",
17
21
  "description": "Display language.",
@@ -34,31 +38,31 @@
34
38
  },
35
39
  {
36
40
  "type": "object",
37
- "description": "Emoji set configuration",
41
+ "description": "Emoji set configuration.",
38
42
  "properties": {
39
43
  "name": {
40
44
  "type": "string",
41
- "description": "Emoji name on the tab"
45
+ "description": "Emoji name on the tab."
42
46
  },
43
47
  "folder": {
44
48
  "type": "string",
45
- "description": "Image folder link"
49
+ "description": "Image folder link."
46
50
  },
47
51
  "prefix": {
48
52
  "type": "string",
49
- "description": "The general prefix of images' filename"
53
+ "description": "The general prefix of images' filename."
50
54
  },
51
55
  "type": {
52
56
  "type": "string",
53
- "description": "Type of the picture, which will be used as file extension"
57
+ "description": "Type of the picture, which will be used as file extension."
54
58
  },
55
59
  "icon": {
56
60
  "type": "string",
57
- "description": "Filename of the icon image used in tab (requirement is the same as items)"
61
+ "description": "Filename of the icon image used in tab (requirement is the same as items)."
58
62
  },
59
63
  "items": {
60
64
  "type": "array",
61
- "description": "Each item is the picture filename without common prefix (do not include file extension)",
65
+ "description": "Each item is the picture filename without common prefix (do not include file extension).",
62
66
  "items": {
63
67
  "type": "string"
64
68
  }
@@ -68,18 +72,18 @@
68
72
  }
69
73
  ]
70
74
  },
71
- "description": "Emoji settings",
75
+ "description": "Emoji settings.",
72
76
  "default": ["https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo"],
73
77
  "nullable": true
74
78
  },
75
79
  "dark": {
76
80
  "type": "string",
77
- "description": "Darkmode support",
81
+ "description": "Darkmode support.",
78
82
  "nullable": true
79
83
  },
80
84
  "meta": {
81
85
  "type": "array",
82
- "description": "Reviewer attributes",
86
+ "description": "Reviewer attributes.",
83
87
  "items": {
84
88
  "type": "string"
85
89
  },
@@ -88,24 +92,17 @@
88
92
  },
89
93
  "required_meta": {
90
94
  "type": "array",
91
- "description": "Required commenter information fields",
95
+ "description": "Required commenter information fields.",
92
96
  "default": [],
93
97
  "nullable": true
94
98
  },
95
99
  "login": {
96
100
  "type": "string",
97
- "description": "Login mode status",
101
+ "description": "Login mode status.",
98
102
  "enum": ["enable", "disable", "force"],
99
103
  "default": "enable",
100
104
  "nullable": true
101
105
  },
102
- "avatar": {
103
- "type": "string",
104
- "description": "Gravatar type",
105
- "enum": ["", "mp", "identicon", "monsterid", "wavatar", "robohash", "retro", "hide", "mm"],
106
- "default": "mp",
107
- "nullable": true
108
- },
109
106
  "word_limit": {
110
107
  "oneOf": [
111
108
  {
@@ -133,16 +130,10 @@
133
130
  "default": 10,
134
131
  "nullable": true
135
132
  },
136
- "avatar_cdn": {
137
- "type": "string",
138
- "description": "Gravatar CDN baseURL.",
139
- "default": "https://sdn.geekzu.org/avatar/",
140
- "nullable": true
141
- },
142
- "avatar_force": {
133
+ "upload_image": {
143
134
  "type": "boolean",
144
- "description": "Whether force pulling the latest avatar each time.",
145
- "default": false,
135
+ "description": "If you set it to false, image upload feature will be disabled.",
136
+ "default": true,
146
137
  "nullable": true
147
138
  },
148
139
  "highlight": {
@@ -151,9 +142,9 @@
151
142
  "default": true,
152
143
  "nullable": true
153
144
  },
154
- "math_tag_support": {
145
+ "math": {
155
146
  "type": "boolean",
156
- "description": "Whether inject extra styles to display <math> block",
147
+ "description": "If you set it to 'false', math preview feature will be disabled.",
157
148
  "default": false,
158
149
  "nullable": true
159
150
  },
@@ -40,6 +40,7 @@ var _require2 = require('../../util/cache'),
40
40
  * @example
41
41
  * <Waline
42
42
  * serverURL="https://path/to/waline/server"
43
+ * path="window.location.pathname"
43
44
  * lang="zh-CN"
44
45
  * visitor={false}
45
46
  * emoji={['https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo']}
@@ -47,13 +48,11 @@ var _require2 = require('../../util/cache'),
47
48
  * meta={['nick', 'mail', 'link']}
48
49
  * requiredMeta={[]}
49
50
  * login="enable"
50
- * avatar="mp"
51
51
  * wordLimit={0},
52
52
  * pageSize={10}
53
- * avatarCDN = "https://sdn.geekzu.org/avatar/"
54
- * avatarForce={false}
53
+ * uploadImage={true}
55
54
  * highlight={true}
56
- * mathTagSupport={false}
55
+ * math={false}
57
56
  * copyright={true}
58
57
  * locale={{placeholder: '', ...}}
59
58
  * jsUrl="/path/to/Waline.js" />
@@ -76,6 +75,8 @@ var Waline = /*#__PURE__*/function (_Component) {
76
75
  value: function render() {
77
76
  var _this$props = this.props,
78
77
  serverURL = _this$props.serverURL,
78
+ _this$props$path = _this$props.path,
79
+ path = _this$props$path === void 0 ? 'window.location.pathname' : _this$props$path,
79
80
  _this$props$lang = _this$props.lang,
80
81
  lang = _this$props$lang === void 0 ? 'zh-CN' : _this$props$lang,
81
82
  _this$props$visitor = _this$props.visitor,
@@ -90,20 +91,16 @@ var Waline = /*#__PURE__*/function (_Component) {
90
91
  requiredMeta = _this$props$requiredM === void 0 ? [] : _this$props$requiredM,
91
92
  _this$props$login = _this$props.login,
92
93
  login = _this$props$login === void 0 ? 'enable' : _this$props$login,
93
- _this$props$avatar = _this$props.avatar,
94
- avatar = _this$props$avatar === void 0 ? 'mp' : _this$props$avatar,
95
94
  _this$props$wordLimit = _this$props.wordLimit,
96
95
  wordLimit = _this$props$wordLimit === void 0 ? 0 : _this$props$wordLimit,
97
96
  _this$props$pageSize = _this$props.pageSize,
98
97
  pageSize = _this$props$pageSize === void 0 ? 10 : _this$props$pageSize,
99
- _this$props$avatarCDN = _this$props.avatarCDN,
100
- avatarCDN = _this$props$avatarCDN === void 0 ? 'https://sdn.geekzu.org/avatar/' : _this$props$avatarCDN,
101
- _this$props$avatarFor = _this$props.avatarForce,
102
- avatarForce = _this$props$avatarFor === void 0 ? false : _this$props$avatarFor,
98
+ _this$props$uploadIma = _this$props.uploadImage,
99
+ uploadImage = _this$props$uploadIma === void 0 ? true : _this$props$uploadIma,
103
100
  _this$props$highlight = _this$props.highlight,
104
101
  highlight = _this$props$highlight === void 0 ? true : _this$props$highlight,
105
- _this$props$mathTagSu = _this$props.mathTagSupport,
106
- mathTagSupport = _this$props$mathTagSu === void 0 ? false : _this$props$mathTagSu,
102
+ _this$props$math = _this$props.math,
103
+ math = _this$props$math === void 0 ? false : _this$props$math,
107
104
  _this$props$copyright = _this$props.copyright,
108
105
  copyright = _this$props$copyright === void 0 ? true : _this$props$copyright,
109
106
  locale = _this$props.locale,
@@ -113,7 +110,7 @@ var Waline = /*#__PURE__*/function (_Component) {
113
110
  return (0, _inferno.createVNode)(1, "div", "notification is-danger", [(0, _inferno.createTextVNode)("You forgot to set the "), (0, _inferno.createVNode)(1, "code", null, "server_url", 16), (0, _inferno.createTextVNode)(" for Waline. Please set it in"), (0, _inferno.createTextVNode)(' '), (0, _inferno.createVNode)(1, "code", null, "_config.yml", 16), (0, _inferno.createTextVNode)(".")], 0);
114
111
  }
115
112
 
116
- var js = "Waline({\n el: '#waline-thread',\n serverURL: ".concat(JSON.stringify(serverURL), ",\n ").concat(lang ? "lang: ".concat(JSON.stringify(lang), ",") : '', "\n ", "visitor: ".concat(JSON.stringify(visitor), ","), "\n ").concat(emoji ? "emoji: ".concat(JSON.stringify(emoji), ",") : '', "\n ").concat(dark ? "dark: ".concat(JSON.stringify(dark), ",") : '', "\n ").concat(meta ? "meta: ".concat(JSON.stringify(meta), ",") : '', "\n ").concat(Array.isArray(requiredMeta) ? "requiredMeta: ".concat(JSON.stringify(requiredMeta), ",") : '', "\n ").concat(login ? "login: ".concat(JSON.stringify(login), ",") : '', "\n ").concat(avatar ? "avatar: ".concat(JSON.stringify(avatar), ",") : '', "\n ").concat(wordLimit ? "wordLimit: ".concat(JSON.stringify(wordLimit), ",") : '', "\n ").concat(pageSize ? "pageSize: ".concat(JSON.stringify(pageSize), ",") : '', "\n ").concat(avatarCDN ? "avatarCDN: ".concat(JSON.stringify(avatarCDN), ",") : '', "\n ", "avatarForce: ".concat(JSON.stringify(avatarForce), ","), "\n ", "highlight: ".concat(JSON.stringify(highlight), ","), "\n ", "mathTagSupport: ".concat(JSON.stringify(mathTagSupport), ","), "\n ", "copyright: ".concat(JSON.stringify(copyright), ","), "\n ").concat(locale ? "locale: ".concat(JSON.stringify(locale), ",") : '', "\n });");
113
+ var js = "Waline({\n el: '#waline-thread',\n serverURL: ".concat(JSON.stringify(serverURL), ",\n path: ").concat(path, ",\n ").concat(lang ? "lang: ".concat(JSON.stringify(lang), ",") : '', "\n ", "visitor: ".concat(JSON.stringify(visitor), ","), "\n ").concat(emoji ? "emoji: ".concat(JSON.stringify(emoji), ",") : '', "\n ").concat(dark ? "dark: ".concat(JSON.stringify(dark), ",") : '', "\n ").concat(meta ? "meta: ".concat(JSON.stringify(meta), ",") : '', "\n ").concat(Array.isArray(requiredMeta) ? "requiredMeta: ".concat(JSON.stringify(requiredMeta), ",") : '', "\n ").concat(login ? "login: ".concat(JSON.stringify(login), ",") : '', "\n ").concat(wordLimit ? "wordLimit: ".concat(JSON.stringify(wordLimit), ",") : '', "\n ").concat(pageSize ? "pageSize: ".concat(JSON.stringify(pageSize), ",") : '', "\n ").concat(uploadImage === false ? "uploadImage: false," : '', "\n ").concat(highlight === false ? "highlight: false," : '', "\n ").concat(math === false ? "math: false," : '', "\n ", "copyright: ".concat(JSON.stringify(copyright), ","), "\n ").concat(locale ? "locale: ".concat(JSON.stringify(locale), ",") : '', "\n });");
117
114
  return (0, _inferno.createFragment)([(0, _inferno.createVNode)(1, "div", "content", null, 1, {
118
115
  "id": "waline-thread"
119
116
  }), (0, _inferno.createVNode)(1, "script", null, null, 1, {
@@ -138,22 +135,21 @@ var Waline = /*#__PURE__*/function (_Component) {
138
135
  * @example
139
136
  * <Waline.Cacheable
140
137
  * comment={{
141
- * server_url: "https://path/to/waline/server"
142
- * lang: "zh-CN"
143
- * visitor: false
144
- * emoji: "https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo"
145
- * dark: ""
146
- * meta: ['nick', 'mail', 'link']
147
- * required_meta: []
148
- * login: false
149
- * avatar: "mp"
150
- * word_limit: 0
151
- * page_size: 10
152
- * avatar_cdn: "https://sdn.geekzu.org/avatar/"
153
- * avatar_force: false
154
- * highlight: true
155
- * math_tag_support: false
156
- * copyright: true
138
+ * server_url: "https://path/to/waline/server",
139
+ * path: "window.location.pathname",
140
+ * lang: "zh-CN",
141
+ * visitor: false,
142
+ * emoji: "https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo",
143
+ * dark: "",
144
+ * meta: ['nick', 'mail', 'link'],
145
+ * required_meta: [],
146
+ * login: false,
147
+ * word_limit: 0,
148
+ * page_size: 10,
149
+ * upload_image: true,
150
+ * highlight: true,
151
+ * math: false,
152
+ * copyright: true,
157
153
  * locale: {placeholder: '', ...}
158
154
  * }}
159
155
  * helper={{ cdn: function() {...} }} />
@@ -167,6 +163,7 @@ Waline.Cacheable = cacheComponent(Waline, 'comment.waline', function (props) {
167
163
  config = props.config;
168
164
  return {
169
165
  serverURL: comment.server_url,
166
+ path: comment.path,
170
167
  lang: comment.lang || page.lang || page.language || config.language || 'zh-CN',
171
168
  visitor: comment.visitor,
172
169
  emoji: comment.emoji,
@@ -174,16 +171,14 @@ Waline.Cacheable = cacheComponent(Waline, 'comment.waline', function (props) {
174
171
  meta: comment.meta,
175
172
  requiredMeta: comment.required_meta,
176
173
  login: comment.login,
177
- avatar: comment.avatar,
178
174
  wordLimit: comment.word_limit,
179
175
  pageSize: comment.page_size,
180
- avatarCDN: comment.avatar_cdn,
181
- avatarForce: comment.avatar_force,
176
+ uploadImage: comment.upload_image,
182
177
  highlight: comment.highlight,
183
- mathTagSupport: comment.math_tag_support,
178
+ math: comment.math,
184
179
  copyright: comment.copyright,
185
180
  locale: comment.locale,
186
- jsUrl: helper.cdn('@waline/client', '1.3.11', 'dist/Waline.min.js')
181
+ jsUrl: helper.cdn('@waline/client', '1.5.4', 'dist/Waline.min.js')
187
182
  };
188
183
  });
189
184
  module.exports = Waline;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-component-inferno",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "A collection of Inferno.js layout components and utility scripts for Hexo",
5
5
  "main": "lib/index.js",
6
6
  "repository": "https://github.com/ppoffice/hexo-component-inferno",
@@ -34,6 +34,7 @@
34
34
  "@types/hexo": "^3.8.5",
35
35
  "@types/hexo-util": "^0.6.2",
36
36
  "babel-plugin-inferno": "^6.1.0",
37
+ "cheerio": "^1.0.0-rc.10",
37
38
  "deepmerge": "^4.2.2",
38
39
  "eslint": "^8.6.0",
39
40
  "eslint-config-hexo": "^5.0.0",
@@ -43,6 +44,7 @@
43
44
  "eslint-plugin-react": "^7.18.0",
44
45
  "hexo": "^6.0.0",
45
46
  "hexo-pagination": "^2.0.0",
47
+ "hexo-renderer-markdown": "^1.3.0",
46
48
  "hexo-util": "^2.2.0",
47
49
  "inferno-server": "^7.4.1",
48
50
  "jest": "^27.4.7",