├── index.js ├── .npmignore ├── .babelrc ├── RELEASE.md ├── src ├── string-builder.js ├── constants.js ├── config.js ├── content.js └── index.js ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── test ├── fixtures │ ├── terminal.default.js │ ├── terminal.multiple-command.js │ └── editor.default.js ├── content.test.js ├── index.test.js ├── config.test.js └── string-builder.test.js ├── LICENSE ├── package.json ├── .gitignore └── README.md /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var hexoTagGdemo = require('./lib'); 4 | 5 | hexoTagGdemo(hexo); -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | tmp/ 3 | coverage/ 4 | *.log 5 | .jshintrc 6 | .travis.yml 7 | gulpfile.js 8 | .idea/ 9 | appveyor.yml 10 | .github 11 | src/ 12 | .babelrc -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/env", 5 | { 6 | "useBuiltIns": "entry", 7 | "corejs": "3", 8 | "targets": "> 0.25%, not dead" 9 | } 10 | ] 11 | ], 12 | "plugins": [ 13 | "@babel/plugin-proposal-class-properties" 14 | ] 15 | } -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | 1. default `publishConfig` is `https://www.npmjs.com/` 2 | 2. `npm login` 3 | 3. `npm publish` 4 | 4. second `publishConfig` is `https://npm.pkg.github.com` 5 | 6 | ```json 7 | "publishConfig": { 8 | "registry":"https://npm.pkg.github.com" 9 | }, 10 | ``` 11 | 12 | 5. `npm login --scope=@heowc --registry=https://npm.pkg.github.com` 13 | 6. `npm publish` -------------------------------------------------------------------------------- /src/string-builder.js: -------------------------------------------------------------------------------- 1 | export default class StringBuilder { 2 | constructor(value) { 3 | this._array = []; 4 | this.append(value); 5 | } 6 | 7 | append(value) { 8 | if (value) { 9 | this._array.push(value); 10 | } 11 | } 12 | 13 | toString() { 14 | return this._array.join(''); 15 | } 16 | 17 | clear() { 18 | this._array.length = 0; 19 | } 20 | } -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | export const DEFAULT_GDEMO_VERSION = '0.11.12'; 2 | export const DEFAULT_GDEMO_STYLE_URL = `//cdn.jsdelivr.net/npm/@glorious/demo@${DEFAULT_GDEMO_VERSION}/dist/gdemo.min.css`; 3 | export const DEFAULT_GDEMO_SCRIPT_URL = `//cdn.jsdelivr.net/npm/@glorious/demo@${DEFAULT_GDEMO_VERSION}/dist/gdemo.min.js`; 4 | export const DEFAULT_PRISMJS_THEME = 'tomorrow'; 5 | 6 | export const PRISMJS_THEME_STYLE_URL = '//cdn.jsdelivr.net/npm/prismjs/themes/prism-%s.css'; 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | timezone: "Asia/Seoul" 13 | time: "10:00" 14 | - package-ecosystem: "github-actions" 15 | directory: "/" 16 | schedule: 17 | interval: "weekly" 18 | timezone: "Asia/Seoul" 19 | time: "10:00" 20 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v4 8 | - name: Set up Node 9 | uses: actions/setup-node@v4 10 | with: 11 | node-version: '16' 12 | cache: 'npm' 13 | - name: Get npm cache directory 14 | id: npm-cache 15 | run: | 16 | echo "::set-output name=dir::$(npm config get cache)" 17 | - uses: actions/cache@v4 18 | with: 19 | path: ${{ steps.npm-cache.outputs.dir }} 20 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 21 | restore-keys: | 22 | ${{ runner.os }}-node- 23 | - run: npm install 24 | - run: npm run test 25 | -------------------------------------------------------------------------------- /test/fixtures/terminal.default.js: -------------------------------------------------------------------------------- 1 | exports.content = [ 2 | '{% gdemo_terminal \'node ./demo\' %}', 3 | 'hello, hexo-tag-gdemo', 4 | '{% endgdemo_terminal %}', 5 | ].join('\n'); 6 | 7 | exports.actual = 8 | ` 9 | 10 | 11 |
12 | `; 19 | -------------------------------------------------------------------------------- /test/fixtures/terminal.multiple-command.js: -------------------------------------------------------------------------------- 1 | exports.content = [ 2 | '{% gdemo_terminal \'cd /usr/bin;node ./demo\'%}', 3 | 'hello, hexo-tag-gdemo', 4 | '{% endgdemo_terminal %}', 5 | ].join('\n'); 6 | 7 | exports.actual = 8 | ` 9 | 10 | 11 | 12 | `; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Heo Won Chul 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@heowc/hexo-tag-gdemo", 3 | "version": "0.15.0", 4 | "description": "glorious-demo tag plugin for Hexo", 5 | "main": "./index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/heowc/hexo-tag-gdemo.git" 9 | }, 10 | "keywords": [ 11 | "hexo", 12 | "tag", 13 | "demo", 14 | "glorious-demo" 15 | ], 16 | "author": { 17 | "name": "heowc", 18 | "email": "heowc1992@gmail.com" 19 | }, 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/heowc/hexo-tag-gdemo/issues" 23 | }, 24 | "homepage": "https://github.com/heowc/hexo-tag-gdemo#readme", 25 | "dependencies": { 26 | "prismjs": "^1.21.0" 27 | }, 28 | "devDependencies": { 29 | "@babel/cli": "^7.12.8", 30 | "@babel/core": "^7.12.9", 31 | "@babel/plugin-proposal-class-properties": "^7.10.4", 32 | "@babel/polyfill": "^7.11.5", 33 | "@babel/preset-env": "^7.11.5", 34 | "@babel/register": "^7.11.5", 35 | "ansi-regex": "^6.0.1", 36 | "hexo": "^6.0.0", 37 | "hexo-renderer-marked": "^7.0.0", 38 | "mocha": "^11.0.1" 39 | }, 40 | "scripts": { 41 | "build:lib": "npx babel src --out-dir lib", 42 | "test": "mocha -r @babel/register ./test/*.test.js" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_GDEMO_SCRIPT_URL, 3 | DEFAULT_GDEMO_STYLE_URL, 4 | DEFAULT_PRISMJS_THEME, 5 | PRISMJS_THEME_STYLE_URL 6 | } from './constants'; 7 | 8 | export default class Config { 9 | constructor(hexo) { 10 | if (hexo.config.gdemo) { 11 | this._customize(hexo.config.gdemo); 12 | } else { 13 | this._default(); 14 | } 15 | } 16 | 17 | _customize(gdemoConfig) { 18 | this._styleUrl = gdemoConfig.style_url || DEFAULT_GDEMO_STYLE_URL; 19 | this._scriptUrl = gdemoConfig.script_url || DEFAULT_GDEMO_SCRIPT_URL; 20 | this._prismjsThemeStyleUrl = 21 | String(PRISMJS_THEME_STYLE_URL).replace('%s', gdemoConfig.prismjs_theme || DEFAULT_PRISMJS_THEME); 22 | } 23 | 24 | _default() { 25 | this._styleUrl = DEFAULT_GDEMO_STYLE_URL; 26 | this._scriptUrl = DEFAULT_GDEMO_SCRIPT_URL; 27 | this._prismjsThemeStyleUrl = String(PRISMJS_THEME_STYLE_URL).replace('%s', DEFAULT_PRISMJS_THEME); 28 | } 29 | 30 | getStyleUrl() { 31 | return this._styleUrl; 32 | } 33 | 34 | getScriptUrl() { 35 | return this._scriptUrl; 36 | } 37 | 38 | getPrismjsThemeStyleUrl() { 39 | return this._prismjsThemeStyleUrl; 40 | } 41 | } -------------------------------------------------------------------------------- /test/content.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import Content from '../src/content'; 3 | 4 | describe('Test Content API', () => { 5 | 6 | it('default', () => { 7 | const str = 'test'; 8 | assert.equal(Content.default(str), str); 9 | }); 10 | 11 | it('simple', () => { 12 | const str = '\\test\`'; 13 | assert.equal(Content.simple(str), '\\\\test\\`'); 14 | }); 15 | 16 | it('highlight for javascript', () => { 17 | const code = 'let code = "test"'; 18 | assert.equal(Content.highlight(code, 'javascript'), 19 | 'let code = "test"'); 20 | }); 21 | 22 | /* 23 | Requiring prismjs will load the default languages: `markup`, `css`, `clike` and `javascript`. 24 | You can load more languages with the `loadLanguages()` utility, which will automatically handle any required 25 | dependencies. (https://prismjs.com/) 26 | */ 27 | it('highlight for java', () => { 28 | const code = 'String code = "test"'; 29 | assert.equal(Content.highlight(code, 'java'), 30 | 'String code = "test"'); 31 | }); 32 | }); -------------------------------------------------------------------------------- /test/fixtures/editor.default.js: -------------------------------------------------------------------------------- 1 | exports.content = [ 2 | '{% gdemo_editor %}', 3 | 'function greet(){', 4 | ' console.log("Hello World!");', 5 | '}', 6 | '', 7 | 'greet();', 8 | '{% endgdemo_editor %}', 9 | ].join('\n'); 10 | 11 | exports.actual = 12 | ` 13 | 14 | 15 | 16 | `; 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # parcel-bundler cache (https://parceljs.org/) 63 | .cache 64 | 65 | # next.js build output 66 | .next 67 | 68 | # nuxt.js build output 69 | .nuxt 70 | 71 | # vuepress build output 72 | .vuepress/dist 73 | 74 | # Serverless directories 75 | .serverless 76 | 77 | # Intellij 78 | .idea 79 | 80 | # etc 81 | lib -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | 3 | describe('Test Tag API', () => { 4 | 5 | const Hexo = require('hexo'); 6 | const hexo = new Hexo(); 7 | const Post = hexo.model('Post'); 8 | const renderPost = require('hexo/lib/plugins/filter/before_generate/render_post').bind(hexo); 9 | const plugin = require('../src'); 10 | 11 | before(() => hexo.init().then(() => { 12 | hexo.loadPlugin(require.resolve('hexo-renderer-marked')); 13 | plugin(hexo); 14 | })); 15 | 16 | it('render post with tag plugins by gdemo_terminal [default]', () => { 17 | const fixture = require('./fixtures/terminal.default'); 18 | assertSameContent(fixture['content'], fixture['actual']); 19 | }); 20 | 21 | it('render post with tag plugins by gdemo_terminal [multiple command]', () => { 22 | const fixture = require('./fixtures/terminal.multiple-command'); 23 | assertSameContent(fixture.content, fixture.actual); 24 | }); 25 | 26 | it('render post with tag plugins by gdemo_editor [default]', () => { 27 | const fixture = require('./fixtures/editor.default'); 28 | assertSameContent(fixture.content, fixture.actual); 29 | }); 30 | 31 | function assertSameContent(content, actual) { 32 | let id; 33 | Post.insert({ 34 | source: 'foo.md', 35 | slug: 'foo', 36 | _content: content 37 | }).then(post => { 38 | id = post._id; 39 | return renderPost(); 40 | }).then(() => { 41 | const post = Post.findById(id); 42 | console.log(post.content); 43 | assert.equal(post.content, actual); 44 | return post.remove(); 45 | }); 46 | } 47 | }); -------------------------------------------------------------------------------- /test/config.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import Config from '../src/config'; 3 | import { 4 | DEFAULT_GDEMO_SCRIPT_URL, 5 | DEFAULT_GDEMO_STYLE_URL, 6 | DEFAULT_PRISMJS_THEME, 7 | PRISMJS_THEME_STYLE_URL 8 | } from '../src/constants'; 9 | 10 | describe('Test Config API', () => { 11 | 12 | let testHexoConfig = {}; 13 | 14 | beforeEach(() => { 15 | testHexoConfig.config = {}; 16 | }); 17 | 18 | it('create `Config` as constructor with default option', () => { 19 | const config = new Config(testHexoConfig); 20 | 21 | assert.equal(config.getStyleUrl(), DEFAULT_GDEMO_STYLE_URL); 22 | assert.equal(config.getScriptUrl(), DEFAULT_GDEMO_SCRIPT_URL); 23 | assert.equal(config.getPrismjsThemeStyleUrl(), 24 | String(PRISMJS_THEME_STYLE_URL).replace('%s', DEFAULT_PRISMJS_THEME)); 25 | }); 26 | 27 | it('create `Config` as constructor with empty option', () => { 28 | testHexoConfig.config.gdemo = {}; 29 | 30 | const config = new Config(testHexoConfig); 31 | 32 | assert.equal(config.getStyleUrl(), DEFAULT_GDEMO_STYLE_URL); 33 | assert.equal(config.getScriptUrl(), DEFAULT_GDEMO_SCRIPT_URL); 34 | assert.equal(config.getPrismjsThemeStyleUrl(), 35 | String(PRISMJS_THEME_STYLE_URL).replace('%s', DEFAULT_PRISMJS_THEME)); 36 | }); 37 | 38 | it('create `Config` as constructor with custom option', () => { 39 | testHexoConfig.config.gdemo = { 40 | style_url: 'test_style_url', 41 | script_url: 'test_script_url', 42 | prismjs_theme: 'test_theme' 43 | }; 44 | 45 | const config = new Config(testHexoConfig); 46 | 47 | assert.equal(config.getStyleUrl(), 'test_style_url'); 48 | assert.equal(config.getScriptUrl(), 'test_script_url'); 49 | assert.equal(config.getPrismjsThemeStyleUrl(), 50 | String(PRISMJS_THEME_STYLE_URL).replace('%s', 'test_theme')); 51 | }); 52 | 53 | afterEach(() => { 54 | testHexoConfig.config = {}; 55 | }); 56 | }); -------------------------------------------------------------------------------- /src/content.js: -------------------------------------------------------------------------------- 1 | export default class Contents { 2 | 3 | static default(value) { 4 | return new DefaultContentDecorator(value).decorate(); 5 | } 6 | 7 | static simple(value) { 8 | return new SimpleContentDecorator(new DefaultContentDecorator(value)).decorate(); 9 | } 10 | 11 | static highlight(value, language) { 12 | return new HighlightContentDecorator(new SimpleContentDecorator(new DefaultContentDecorator(value)), language).decorate(); 13 | } 14 | } 15 | 16 | class ContentDecorator { 17 | 18 | decorate() { 19 | 20 | } 21 | } 22 | 23 | class DefaultContentDecorator extends ContentDecorator { 24 | 25 | constructor(value) { 26 | super(); 27 | this._value = value; 28 | } 29 | 30 | decorate() { 31 | return this._value; 32 | } 33 | } 34 | 35 | class SimpleContentDecorator extends ContentDecorator { 36 | 37 | constructor(contentDecorator) { 38 | super(); 39 | this._contentDecorator = contentDecorator; 40 | } 41 | 42 | decorate() { 43 | let tempValue = this._contentDecorator.decorate(); 44 | tempValue = tempValue.replaceAll('\\', '\\\\'); 45 | tempValue = tempValue.replaceAll('\`', '\\`'); 46 | return tempValue; 47 | } 48 | } 49 | 50 | class HighlightContentDecorator extends ContentDecorator { 51 | 52 | constructor(contentDecorator, language) { 53 | super(); 54 | this._contentDecorator = contentDecorator; 55 | this._language = language; 56 | } 57 | 58 | decorate() { 59 | const tempValue = this._contentDecorator.decorate(); 60 | 61 | const Prism = require('prismjs'); 62 | const loadLanguages = require('prismjs/components/'); 63 | loadLanguages([this._language]); 64 | 65 | return Prism.highlight( 66 | tempValue, 67 | Prism.languages[this._language], 68 | this._language 69 | ); 70 | } 71 | } 72 | 73 | String.prototype.replaceAll = function (target, replace) { 74 | return this.split(target).join(replace); 75 | }; -------------------------------------------------------------------------------- /test/string-builder.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import StringBuilder from '../src/string-builder'; 3 | 4 | const TEST_STRING = 'test'; 5 | const EMPTY_STRING = ''; 6 | 7 | describe('Test StringBuilder API', () => { 8 | 9 | describe('constructor', () => { 10 | it('create `StringBuilder` as constructor with no-argument', () => { 11 | const stringBuilder = new StringBuilder(); 12 | assert.equal(stringBuilder.toString(), EMPTY_STRING); 13 | }); 14 | 15 | it('create `StringBuilder` as constructor with argument', () => { 16 | const stringBuilder = new StringBuilder(TEST_STRING); 17 | assert.equal(stringBuilder.toString(), TEST_STRING); 18 | }); 19 | }); 20 | 21 | describe('append', () => { 22 | it('after create `StringBuilder` as constructor with no-argument, append string', () => { 23 | const stringBuilder = new StringBuilder(); 24 | 25 | stringBuilder.append(TEST_STRING); 26 | 27 | assert.equal(stringBuilder.toString(), TEST_STRING); 28 | }); 29 | 30 | it('after create `StringBuilder` as constructor with argument, append string', () => { 31 | const stringBuilder = new StringBuilder(TEST_STRING); 32 | 33 | stringBuilder.append(TEST_STRING); 34 | 35 | assert.equal(stringBuilder.toString(), TEST_STRING.repeat(2)); 36 | }); 37 | }); 38 | 39 | describe('clear', () => { 40 | it('after clear, append string', () => { 41 | const stringBuilder = new StringBuilder(); 42 | stringBuilder.clear(); 43 | 44 | stringBuilder.append(TEST_STRING); 45 | 46 | assert.equal(stringBuilder.toString(), TEST_STRING); 47 | }); 48 | 49 | it('after append string, clear', () => { 50 | const stringBuilder = new StringBuilder(); 51 | stringBuilder.append(TEST_STRING); 52 | 53 | stringBuilder.clear(); 54 | 55 | assert.equal(stringBuilder.toString(), EMPTY_STRING); 56 | }); 57 | }); 58 | 59 | }); -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import Config from './config'; 4 | import StringBuilder from './string-builder'; 5 | import Contents from './content'; 6 | 7 | module.exports = function (hexo) { 8 | 9 | const config = new Config(hexo); 10 | 11 | hexo.extend.tag.register('gdemo_terminal', function (args, content) { 12 | 13 | if (!args[0]) { 14 | console.error('command is empty'); 15 | return; 16 | } 17 | 18 | const command = args[0]; 19 | const minHeight = args[1] || '0px'; 20 | const windowTitle = args[2] || 'bash'; 21 | const onCompleteDelay = args[3] || 0; 22 | const promptString = args[4] || '$'; 23 | const id = args[5] || 'demo-terminal'; 24 | const highlightLang = args[6] || 'javascript'; 25 | 26 | const commands = command.split(';'); 27 | 28 | let sb = new StringBuilder(); 29 | sb.append(` 30 | new GDemo('#${id}') 31 | .openApp('terminal', {minHeight: '${minHeight}', windowTitle: '${windowTitle}', promptString: '${promptString}'})\n`); 32 | 33 | for (let i = 0; i < commands.length; i++) { 34 | let highlightedCode = Contents.highlight(commands[i], highlightLang); 35 | sb.append(` .command(\`${highlightedCode}\`, {onCompleteDelay: ${onCompleteDelay}})\n`); 36 | } 37 | 38 | sb.append(` .respond(\`${content}\`) 39 | .end(); 40 | `); 41 | 42 | return ` 43 | 44 | 45 | 46 | `; 47 | }, {ends: true}); 48 | 49 | hexo.extend.tag.register('gdemo_editor', function (args, content) { 50 | 51 | if (!content) { 52 | console.error('content is empty'); 53 | return; 54 | } 55 | 56 | const minHeight = args[0] || '0px'; 57 | const windowTitle = args[1] || 'bash'; 58 | const onCompleteDelay = args[2] || 0; 59 | const id = args[3] || 'demo-editor'; 60 | const highlightLang = args[4] || 'javascript'; 61 | 62 | let highlightedCode = Contents.highlight(content, highlightLang); 63 | 64 | const demo = ` 65 | new GDemo('#${id}') 66 | .openApp('editor', {minHeight: '${minHeight}', windowTitle: '${windowTitle}'}) 67 | .write(\`${highlightedCode}\`, {onCompleteDelay: ${onCompleteDelay}}) 68 | .end(); 69 | `; 70 | 71 | return ` 72 | 73 | 74 | 75 | `; 76 | }, {ends: true}); 77 | }; 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |  2 | 3 | # hexo-tag-gdemo 4 | 5 | [glorious-demo](https://github.com/glorious-codes/glorious-demo) tag plugin for Hexo (Based on version `0.11.12`) 6 | 7 | # Introduction 8 | 9 | This is a Hexo tag plugin which allow you to glorious-demo on your blog posts. 10 | 11 | # DEMO 12 | 13 | [Demo Link](https://heowc.github.io/2018/11/14/introduction-hexo-tag-gdemo/) 14 | 15 | # Installation 16 | 17 | ```text 18 | npm install @heowc/hexo-tag-gdemo 19 | ``` 20 | 21 | ※ Deprecated `npm install hexo-tag-gdemo` 22 | 23 | # Usage 24 | 25 | ```text 26 | {% gdemo_terminal command [minHeight] [windowTitle] [onCompleteDelay] [promptString] [id] [highlightingLang] %} 27 | content 28 | {% endgdemo_terminal %} 29 | ``` 30 | 31 | or 32 | 33 | ```text 34 | {% gdemo_editor [minHeight] [windowTitle] [onCompleteDelay] [id] [highlightingLang] %} 35 | content 36 | {% endgdemo_editor %} 37 | ``` 38 | 39 | ## command 40 | 41 | command represents one or more commands separated by ';'. Be ware that the commands can not contain ' as hexo would assume that the argument is finished and the next will follow what will lead to the object not beeing rendered. 42 | 43 | ## minHeight 44 | 45 | minHeight defines the minimal hight of the editor/terminal window. Beware that it can grow depending on the content you provide. 46 | 47 | ## windowTitle 48 | 49 | windowTitle will be displayed as title of the editor/terminal window. Use whatever you like. 50 | 51 | ## onCompleteDelay 52 | 53 | onCompleteDelay defines the wait delay, after a line of commands/code was typed. This does not affect the content in gdemo_terminal. Content will instantly appear after all commands are typed. 54 | 55 | ## promptString 56 | 57 | The promptString defines, which character or character sequence will be displayed in front of the typed commands. You can use '>' or 'root@local:/$ ' or anything else you like to display. 58 | 59 | ## id 60 | 61 | The id parameter sets a unique id for the instance of editor/terminal. The IDs have to be different for multiple instances inside of the same post. 62 | 63 | ## highlightingLang 64 | 65 | highlightingLang defines the designated highlighting language. If not specified, javascript will be used. You can find a list of supported languages at the [prismjs homepage](https://prismjs.com/#supported-languages). 66 | 67 | # `_config.yml` 68 | 69 | If you do not want to use the CDN, fill in the following: 70 | 71 | ```yml 72 | gdemo: 73 | style_url: 74 | script_url: 75 | prismjs_theme: 76 | ``` 77 | 78 | # FAQ 79 | 80 | Please read here if you can not display gdemo well. 81 | 82 | [hexo-tag-gdemo/issues/](https://github.com/heowc/hexo-tag-gdemo/issues) 83 | 84 | # Example 85 | 86 | ### 1. When using `gdemo_terminal` 87 | 88 | ```text 89 | {% gdemo_terminal 'node ./demo' '250px' 'bash' '500' '$' 'demo-teriminal' %} 90 | Hello World! 91 | {% endgdemo_terminal %} 92 | ``` 93 | 94 | ### 2. When using `gdemo_terminal` [multiple commands] 95 | 96 | - command can be divided into multiple commands based on `;`. 97 | 98 | ```text 99 | {% gdemo_terminal 'cd /usr/bin;./node ./demo' '250px' 'bash' '500' '$' 'demo-teriminal' %} 100 | Hello World! 101 | {% endgdemo_terminal %} 102 | ``` 103 | 104 | ### 3. When using `gdemo_editor` 105 | 106 | ```text 107 | {% gdemo_editor '250px' 'bash' '500' 'demo-editor' %} 108 | function greet(){ 109 | console.log("Hello World!"); 110 | } 111 | 112 | greet(); 113 | {% endgdemo_editor %} 114 | ``` 115 | 116 | > See more [here](https://github.com/glorious-codes/glorious-demo). 117 | 118 | # License 119 | 120 | MIT 121 | 122 | # Thanks 123 | 124 | - [@rafaelcamargo](https://github.com/rafaelcamargo) 125 | --------------------------------------------------------------------------------