├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmrc ├── .prettierrc ├── config.dev.js ├── manifest.json ├── markdown └── demo.md ├── package-lock.json ├── package.json ├── readme.md ├── scripts └── compile.js ├── src ├── DocBuilder.ts ├── constants.ts ├── default_index.md ├── ejs │ ├── head.ejs │ └── tpl.ejs ├── index.ts ├── resource │ ├── favicon.ico │ ├── icons │ │ ├── 128.png │ │ ├── 144.png │ │ ├── 192.png │ │ ├── 256.png │ │ ├── 512.png │ │ ├── bars.svg │ │ └── circle-xmark.svg │ ├── lib │ │ ├── github-markdown.min.css │ │ ├── highlight.default.min.css │ │ ├── jquery-viewer-1.0.1 │ │ │ ├── jquery-viewer.common.js │ │ │ ├── jquery-viewer.esm.js │ │ │ ├── jquery-viewer.js │ │ │ └── jquery-viewer.min.js │ │ ├── jquery.min.js │ │ ├── mark.js-8.11.1 │ │ │ ├── jquery.mark.es6.js │ │ │ ├── jquery.mark.es6.min.js │ │ │ ├── jquery.mark.js │ │ │ ├── jquery.mark.min.js │ │ │ ├── mark.es6.js │ │ │ ├── mark.es6.min.js │ │ │ ├── mark.js │ │ │ └── mark.min.js │ │ └── viewerjs-1.10.5 │ │ │ ├── viewer.common.js │ │ │ ├── viewer.css │ │ │ ├── viewer.esm.js │ │ │ ├── viewer.js │ │ │ ├── viewer.min.css │ │ │ └── viewer.min.js │ ├── script.js │ └── style.less ├── types.d.ts └── utils │ ├── config.ts │ ├── getTocHtmlByMd.ts │ ├── index.ts │ ├── logger.ts │ └── mdInstance.ts ├── tsconfig.json └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | src/resource/lib 2 | *.md 3 | *.less 4 | *.ejs 5 | *.ico 6 | *.png 7 | *.svg 8 | .eslintrc.js 9 | bin -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | commonjs: true, 5 | es2021: true, 6 | node: true, 7 | jquery: true, 8 | }, 9 | extends: [ 10 | 'eslint:recommended', 11 | 'plugin:@typescript-eslint/recommended', 12 | 'prettier', 13 | ], 14 | parser: '@typescript-eslint/parser', 15 | parserOptions: { 16 | ecmaVersion: 'latest', 17 | }, 18 | plugins: ['@typescript-eslint', 'prettier'], 19 | rules: { 20 | '@typescript-eslint/no-var-requires': 0, 21 | 'prettier/prettier': ['error'], 22 | }, 23 | globals: {}, 24 | }; 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | bin 4 | dist 5 | temp 6 | yarn-error.log 7 | markdown/* 8 | !markdown/demo.md -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true, 6 | "trailingComma": "all", 7 | "bracketSameLine": false, 8 | "singleAttributePerLine": true, 9 | "endOfLine": "auto" 10 | } 11 | -------------------------------------------------------------------------------- /config.dev.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | input: 'markdown', 3 | output: 'dist', 4 | port: '8989', 5 | title: 'dev' 6 | }; 7 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test name", 3 | "short_name": "test short_name", 4 | "display": "standalone", 5 | "start_url": "/", 6 | "theme_color": "#ffffff", 7 | "background_color": "#ff0000", 8 | "orientation": "any", 9 | "icons": [ 10 | { 11 | "src": "./resource/icons/128.png", 12 | "sizes": "128x128" 13 | }, 14 | { 15 | "src": "./resource/icons/144.png", 16 | "sizes": "144x144" 17 | }, 18 | { 19 | "src": "./resource/icons/192.png", 20 | "sizes": "192x192" 21 | }, 22 | { 23 | "src": "./resource/icons/256.png", 24 | "sizes": "256x256" 25 | }, 26 | { 27 | "src": "./resource/icons/512.png", 28 | "sizes": "512x512" 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /markdown/demo.md: -------------------------------------------------------------------------------- 1 | # h1 2 | 3 | ## h2 4 | 5 | ### h3 6 | 7 | [链接](https://baidu.com) 8 | 9 | 段落*斜体*段落**粗体**段落**_加粗斜体_**段落~~删除线~~段落==mark==段落`行内代码`段落段落段落段落段落段落段落段落段落段落段落 10 | 段落段落段落段落段落段落段落段落段落段落段落段落段落段落段落段落段落段落段落段落段落段落段落 11 | 12 | emoji 表情 ❤😁 13 | 14 | 脚注 1 链接[^first]。 15 | 16 | 脚注 2 链接[^second]。 17 | 18 | 行内的脚注^[行内脚注文本] 定义。 19 | 20 | 重复的页脚定义[^second]。 21 | 22 | - 列表 23 | - 列表 24 | - 列表 25 | - 列表 26 | - [ ] 任务 27 | - [x] 任务 28 | 29 | ![](https://temp.im/100/4CD964/fff '图片 title') 30 | 31 | ![](https://temp.im/100/4CD964/fff '自定义尺寸' =100x200) 32 | 33 | > 引用引用引用引用 34 | > 引用引用引用引用 35 | > 引用引用引用引用 36 | 37 | ```typescript 38 | const randomString = (len?: number): string => { 39 | len = len || 32; 40 | const t = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; 41 | const a = t.length; 42 | let n = ''; 43 | for (let i = 0; i < len; i++) { 44 | n += t.charAt(Math.floor(Math.random() * a)); 45 | } 46 | return n; 47 | }; 48 | ``` 49 | 50 | [//]: # (分割线) 51 | 52 | --- 53 | 54 | ::: info 容器 55 | 56 | ## 你好 57 | 58 | info 59 | 60 | ::: 61 | 62 | ::: info 容器 63 | 64 | - aaa 65 | - bbb 66 | 67 | ::: 68 | 69 | ::: note 容器 70 | 71 | note 72 | 73 | ::: 74 | 75 | ::: tip 容器 76 | 77 | tip 78 | 79 | ::: 80 | 81 | ::: warning 容器 82 | 83 | warning 84 | 85 | ::: 86 | 87 | ::: danger 容器 88 | 89 | danger 90 | 91 | ::: 92 | 93 | | 表头 | 表头 | 94 | |-----|-----| 95 | | 单元格 | 单元格 | 96 | | 单元格 | 单元格 | 97 | | 单元格 | 单元格 | 98 | | 单元格 | 单元格 | 99 | | 单元格 | 单元格 | 100 | 101 | [^first]: 脚注 **可以包含特殊标记** 102 | 103 | 也可以由多个段落组成 104 | 105 | [^second]: 脚注文字。 106 | 107 | 108 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@qxtang/doc-builder", 3 | "version": "1.3.5", 4 | "description": "将文件夹中的 markdown 文档翻译成 html 站点,根据文件结构自动生成菜单", 5 | "scripts": { 6 | "prepublishOnly": "npm run compile", 7 | "dev": "node ./bin/index.js start --config=config.dev.js", 8 | "compile:ts": "npx tsc", 9 | "compile:ts:watch": "npx tsc -w", 10 | "compile": "node ./scripts/compile.js", 11 | "compile:watch": "node ./scripts/compile.js -w", 12 | "eslint": "npx eslint src/**/*", 13 | "eslint:fix": "npx eslint src/**/* --fix" 14 | }, 15 | "bin": { 16 | "doc-builder": "bin/index.js" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/qxtang/doc-builder.git" 21 | }, 22 | "files": [ 23 | "readme.md", 24 | "bin", 25 | "package.json" 26 | ], 27 | "author": "qxtang", 28 | "license": "ISC", 29 | "bugs": { 30 | "url": "https://github.com/qxtang/doc-builder/issues" 31 | }, 32 | "homepage": "https://github.com/qxtang/doc-builder#readme", 33 | "devDependencies": { 34 | "@babel/cli": "^7.17.6", 35 | "@babel/core": "^7.17.7", 36 | "@babel/preset-env": "^7.16.11", 37 | "@babel/runtime": "^7.17.7", 38 | "@types/ejs": "^3.1.0", 39 | "@types/fs-extra": "^9.0.13", 40 | "@types/jquery": "^3.5.14", 41 | "@types/less": "^3.0.3", 42 | "@types/live-server": "^1.2.1", 43 | "@types/markdown-it": "^12.2.3", 44 | "@types/md5": "^2.3.2", 45 | "@types/node": "^17.0.21", 46 | "@typescript-eslint/eslint-plugin": "^5.15.0", 47 | "@typescript-eslint/parser": "^5.15.0", 48 | "eslint": "7.14.0", 49 | "eslint-config-prettier": "^8.6.0", 50 | "eslint-plugin-prettier": "^3.1.4", 51 | "less": "^4.1.2", 52 | "less-plugin-autoprefix": "^2.0.0", 53 | "prettier": "^2.8.4", 54 | "typescript": "^4.6.2" 55 | }, 56 | "dependencies": { 57 | "chalk": "^4.1.1", 58 | "chokidar": "^3.5.3", 59 | "commander": "^9.1.0", 60 | "ejs": "^3.1.6", 61 | "fs-extra": "^10.0.0", 62 | "highlight.js": "^11.5.0", 63 | "live-server": "^1.2.1", 64 | "markdown-it": "^12.3.2", 65 | "markdown-it-anchor": "^8.4.1", 66 | "markdown-it-attrs": "^4.1.3", 67 | "markdown-it-container": "^3.0.0", 68 | "markdown-it-footnote": "^3.0.3", 69 | "markdown-it-image-figures": "^2.1.1", 70 | "markdown-it-imsize": "^2.0.1", 71 | "markdown-it-mark": "^3.0.1", 72 | "markdown-it-sub": "^1.0.0", 73 | "markdown-it-sup": "^1.0.0", 74 | "markdown-it-task-lists": "^2.1.1", 75 | "markdown-toc": "^1.2.0", 76 | "md5": "^2.3.0", 77 | "ora": "^5.4.0", 78 | "tslib": "^2.3.1" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # DOC-BUILDER 2 | 3 | - 极速零配置,将 markdown 文档翻译成站点,根据文件结构生成菜单 4 | - 全站搜索、toc 目录 5 | - [Preview 示例预览](https://qxtang.github.io) 6 | 7 | ## 使用 8 | 9 | - `npm install -g @qxtang/doc-builder` 10 | - `mkdir somedir && cd somedir && echo "# hello" > hello.md` 11 | - `doc-builder start` 启动本地服务 12 | - `doc-builder build` 打包 13 | - `doc-builder -h` 查看帮助 14 | 15 | ## 使用配置文件 16 | 17 | - 创建文件 builder.config.js 18 | 19 | ```javascript 20 | module.exports = { 21 | port: 8181, 22 | host: '127.0.0.1', 23 | output: 'your dist', 24 | input: 'your input', 25 | resource: 'your resource', 26 | title: 'your title', 27 | root: 'your path', 28 | ignore: [], 29 | }; 30 | ``` 31 | 32 | - 传入 `doc-builder build --config=builder.config.js` 33 | 34 | ## 与 GitHub Actions 结合 35 | 36 | 给仓库添加一个权限点足够的 secrets,创建 `.github\workflows\CI.yml` 37 | 38 | ```yml 39 | name: CI 40 | on: 41 | push: 42 | branches: 43 | - main # 分支名 44 | 45 | jobs: 46 | main: 47 | runs-on: ubuntu-latest 48 | steps: 49 | - name: Checkout 50 | uses: actions/checkout@v2 51 | with: 52 | persist-credentials: false 53 | 54 | - name: Install and Build 55 | run: | 56 | npm install @qxtang/doc-builder@latest 57 | npx doc-builder build --title="your title" --root="your path" --ignore=node_modules,dist 58 | 59 | - name: Deploy 60 | uses: JamesIves/github-pages-deploy-action@v4.3.0 61 | with: 62 | token: ${{ secrets.ACCESS_TOKEN }} # 仓库 secrets 名称 63 | branch: gh-pages # 发布站点的分支 64 | folder: dist # 输出文件夹 65 | clean: true 66 | clean-exclude: | 67 | .nojekyll 68 | ``` 69 | 70 | -------------------------------------------------------------------------------- /scripts/compile.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | const chokidar = require('chokidar'); 3 | const fs = require('fs-extra'); 4 | const less = require('less'); 5 | const ora = require('ora'); 6 | const chalk = require('chalk'); 7 | const LessPluginAutoPrefix = require('less-plugin-autoprefix'); 8 | const path = require('path'); 9 | const babel = require('@babel/core'); 10 | 11 | const CWD = process.cwd(); 12 | const OUTPUT_PATH = path.join(CWD, 'bin'); 13 | const SRC_PATH = path.join(CWD, 'src'); 14 | 15 | const { Command } = require('commander'); 16 | const program = new Command(); 17 | 18 | program.option('-w, --watch', 'watch', false); 19 | program.parse(process.argv); 20 | const options = program.opts(); 21 | const isWatch = options.watch; 22 | 23 | let compiling = false; 24 | let requestWhileCompiling = false; 25 | 26 | const logger = { 27 | info: (...args) => { 28 | console.log(`\n\r[${new Date().toLocaleString()}]`, chalk.blueBright(...args)); 29 | }, 30 | error: (...args) => { 31 | console.log(`\n\r[${new Date().toLocaleString()}] ERROR:`, chalk.redBright(...args)); 32 | } 33 | }; 34 | 35 | const compileTs = async () => { 36 | return new Promise((resolve, reject) => { 37 | exec( 38 | 'npx tsc', 39 | { 40 | cwd: CWD 41 | }, 42 | function (err) { 43 | if (err) { 44 | reject(err); 45 | } 46 | resolve(); 47 | } 48 | ); 49 | }); 50 | }; 51 | 52 | const compileLess = async () => { 53 | return new Promise((resolve, reject) => { 54 | const autoPrefixPlugin = new LessPluginAutoPrefix({ browsers: ['cover 99.5%'] }); 55 | const lessInput = fs.readFileSync(path.join(SRC_PATH, 'resource/style.less'), { encoding: 'utf-8' }); 56 | const lessOutputPath = path.join(OUTPUT_PATH, 'resource/style.css'); 57 | 58 | less.render( 59 | lessInput, 60 | { 61 | compress: true, 62 | plugins: [autoPrefixPlugin] 63 | }, 64 | (err, output) => { 65 | if (err) { 66 | reject(err); 67 | } 68 | 69 | fs.writeFileSync(lessOutputPath, output.css, { encoding: 'utf-8' }); 70 | resolve(); 71 | } 72 | ); 73 | }); 74 | }; 75 | 76 | const compileScript = async () => { 77 | return new Promise((resolve, reject) => { 78 | const code = fs.readFileSync(path.join(SRC_PATH, 'resource/script.js'), { encoding: 'utf-8' }); 79 | const output = path.join(OUTPUT_PATH, 'resource/script.js'); 80 | 81 | babel.transform( 82 | code, 83 | { 84 | presets: [ 85 | [ 86 | '@babel/env', 87 | { 88 | targets: 'cover 99.5%' 89 | } 90 | ] 91 | ] 92 | }, 93 | function (err, result) { 94 | if (err) { 95 | reject(err); 96 | } 97 | fs.writeFileSync(output, result.code, { encoding: 'utf-8' }); 98 | resolve(); 99 | } 100 | ); 101 | }); 102 | }; 103 | 104 | const moveTpl = async () => { 105 | return new Promise((resolve) => { 106 | fs.copySync(path.join(SRC_PATH, 'ejs'), path.join(OUTPUT_PATH, 'ejs')); 107 | fs.copySync(path.join(SRC_PATH, 'resource'), path.join(OUTPUT_PATH, 'resource')); 108 | fs.copySync(path.join(SRC_PATH, 'default_index.md'), path.join(OUTPUT_PATH, 'default_index.md')); 109 | resolve(); 110 | }); 111 | }; 112 | 113 | const reset = () => { 114 | fs.removeSync(OUTPUT_PATH); 115 | fs.mkdirSync(OUTPUT_PATH); 116 | }; 117 | 118 | const doCompile = async () => { 119 | if (compiling) { 120 | requestWhileCompiling = true; 121 | } 122 | 123 | const fn = async () => { 124 | compiling = true; 125 | const spinner = ora('COMPILING\n\r').start(); 126 | 127 | if (!isWatch) { 128 | reset(); 129 | } 130 | 131 | if (!fs.existsSync(OUTPUT_PATH)) { 132 | fs.mkdirSync(OUTPUT_PATH); 133 | } 134 | 135 | try { 136 | await compileTs(); 137 | await moveTpl(); 138 | await compileLess(); 139 | await compileScript(); 140 | 141 | spinner.color = 'green'; 142 | spinner.succeed('COMPILE SUCCESS\n\r'); 143 | } catch (err) { 144 | spinner.color = 'red'; 145 | spinner.fail(`COMPILE ERROR: ${err}\n\r`); 146 | process.exit(1); 147 | } finally { 148 | compiling = false; 149 | 150 | if (requestWhileCompiling) { 151 | requestWhileCompiling = false; 152 | await fn(); 153 | } 154 | } 155 | }; 156 | 157 | if (!compiling) { 158 | await fn(); 159 | } 160 | }; 161 | 162 | (async () => { 163 | logger.info(`COMPILE START: ${isWatch ? 'dev' : 'build'}`); 164 | await doCompile(); 165 | })(); 166 | 167 | if (isWatch) { 168 | chokidar.watch(SRC_PATH, { depth: 10 }).on('change', async (filename) => { 169 | logger.info('src file change:', filename); 170 | 171 | await doCompile(); 172 | }); 173 | } 174 | -------------------------------------------------------------------------------- /src/DocBuilder.ts: -------------------------------------------------------------------------------- 1 | import { IConfig, IOption } from './types'; 2 | import chokidar from 'chokidar'; 3 | import ora from 'ora'; 4 | import chalk from 'chalk'; 5 | import fs from 'fs-extra'; 6 | import path from 'path'; 7 | import liveServer from 'live-server'; 8 | import { Command } from 'commander'; 9 | import { APP_NAME, CWD, getConfig } from './utils/config'; 10 | import logger from './utils/logger'; 11 | import { 12 | copyTplResource, 13 | copyUserResource, 14 | genDirTreeJson, 15 | genManifest, 16 | genNojekyllFile, 17 | getDirTree, 18 | printInfo, 19 | printIpAddrs, 20 | renderDirTree, 21 | } from './utils'; 22 | 23 | class DocBuilder { 24 | building: boolean; 25 | requestWhileBuilding: boolean; 26 | 27 | setCommonOptions(program: Command) { 28 | program 29 | .option('--config ', '声明配置文件', '') 30 | .option('--port ', '本地服务模式端口号', '8181') 31 | .option('--host ', '本地服务模式 host', '0.0.0.0') 32 | .option('--output ', '输出文件夹', 'dist') 33 | .option('--input ', '输入文件夹', '.') 34 | .option( 35 | '--resource ', 36 | '存放图片等资源的文件夹,路径相对于输入文件夹,打包时会一并复制,当然也可以使用自己的图床', 37 | 'resource', 38 | ) 39 | .option('--title ', '站点主标题', 'doc-builder') 40 | .option( 41 | '--root <root>', 42 | '站点根目录,例如你的站点要部署在 https://abc.com/path/,则需要设置为 "path"', 43 | '', 44 | ) 45 | .option( 46 | '--ignore <ignore>', 47 | '需要忽略的文件夹或文件列表,英文逗号分隔,在配置文件中则为数组', 48 | 'node_modules,dist', 49 | ); 50 | 51 | return program; 52 | } 53 | 54 | async doBuild(options: { 55 | inputPath: string; 56 | outputPath: string; 57 | resourcePath: string; 58 | config: IConfig; 59 | }) { 60 | if (this.building) { 61 | this.requestWhileBuilding = true; 62 | } 63 | 64 | const fn = async () => { 65 | this.building = true; 66 | const { inputPath, outputPath, config, resourcePath } = options; 67 | 68 | if (!fs.existsSync(inputPath)) { 69 | logger.error('输入文件夹不存在:', inputPath); 70 | return; 71 | } 72 | 73 | if (!fs.existsSync(outputPath)) { 74 | fs.mkdirSync(outputPath); 75 | } 76 | 77 | const spinner = ora('building...').start(); 78 | 79 | try { 80 | const dirTree = getDirTree({ 81 | inputPath: inputPath, 82 | config: config, 83 | }); 84 | await genDirTreeJson(dirTree, outputPath); 85 | await genNojekyllFile(outputPath); 86 | await copyTplResource(outputPath); 87 | await copyUserResource({ 88 | resourcePath: resourcePath, 89 | outputPath: outputPath, 90 | config: config, 91 | }); 92 | await genManifest({ 93 | config: config, 94 | outputPath: outputPath, 95 | }); 96 | await renderDirTree({ 97 | dirTree, 98 | config: config, 99 | outputPath: outputPath, 100 | }); 101 | 102 | spinner.color = 'green'; 103 | spinner.succeed(chalk.blueBright('build success')); 104 | } catch (err) { 105 | spinner.fail(chalk.redBright('build fail:', err)); 106 | process.exit(1); 107 | } finally { 108 | this.building = false; 109 | 110 | if (this.requestWhileBuilding) { 111 | this.requestWhileBuilding = false; 112 | await fn(); 113 | } 114 | } 115 | }; 116 | 117 | if (!this.building) { 118 | await fn(); 119 | } 120 | } 121 | 122 | run(): void { 123 | const program = new Command(); 124 | 125 | this.setCommonOptions(program.command('start')) 126 | .description('启动本地服务') 127 | .action((options) => { 128 | this.start(options); 129 | }); 130 | 131 | this.setCommonOptions(program.command('build')) 132 | .description('编译打包') 133 | .action((options) => { 134 | this.build(options); 135 | }); 136 | 137 | program.name(APP_NAME).usage('[command] [options]'); 138 | 139 | program.showHelpAfterError(); 140 | program.parse(process.argv); 141 | } 142 | 143 | async start(options: IOption) { 144 | const config = getConfig(options); 145 | printInfo(config); 146 | const inputPath = path.join(CWD, config.input); 147 | const outputPath = path.join(__dirname, '../temp'); 148 | const resourcePath = path.join(inputPath, config.resource); 149 | 150 | fs.removeSync(outputPath); 151 | fs.mkdirSync(outputPath); 152 | 153 | await this.doBuild({ 154 | inputPath, 155 | outputPath, 156 | resourcePath, 157 | config, 158 | }); 159 | 160 | // watch input 161 | chokidar 162 | .watch([inputPath, __dirname], { 163 | depth: 10, 164 | ignoreInitial: true, 165 | ignored: [ 166 | // eslint-disable-next-line no-useless-escape 167 | /(^|[\/\\])\../, // ignore dotfiles 168 | ...config.ignore.map((i) => path.join(inputPath, i)), 169 | ], 170 | }) 171 | .on('all', async (eventName, path) => { 172 | logger.info(`watch: ${eventName} ${path}`); 173 | 174 | await this.doBuild({ 175 | inputPath, 176 | outputPath, 177 | resourcePath, 178 | config, 179 | }); 180 | }); 181 | 182 | liveServer.start({ 183 | port: config.port, 184 | host: config.host, 185 | root: outputPath, 186 | open: false, 187 | logLevel: 0, 188 | }); 189 | printIpAddrs({ host: config.host, port: config.port }); 190 | } 191 | 192 | async build(options: IOption) { 193 | const config = getConfig(options); 194 | printInfo(config); 195 | const inputPath = path.join(CWD, config.input); 196 | const outputPath = path.join(CWD, config.output); 197 | const resourcePath = path.join(inputPath, config.resource); 198 | 199 | fs.removeSync(outputPath); 200 | fs.mkdirSync(outputPath); 201 | 202 | await this.doBuild({ 203 | inputPath, 204 | outputPath, 205 | resourcePath, 206 | config, 207 | }); 208 | } 209 | } 210 | 211 | export default DocBuilder; 212 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | export const INDEX_FILE_NAME = 'index.md'; 2 | -------------------------------------------------------------------------------- /src/default_index.md: -------------------------------------------------------------------------------- 1 | # Welcome 2 | 3 | build by [doc-builder](https://github.com/qxtang/doc-builder) 4 | -------------------------------------------------------------------------------- /src/ejs/head.ejs: -------------------------------------------------------------------------------- 1 | <head> 2 | <meta charset="UTF-8" /> 3 | <meta http-equiv="X-UA-Compatible" content="IE=edge" /> 4 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 5 | <title><%= title %> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 37 | 38 | -------------------------------------------------------------------------------- /src/ejs/tpl.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%- include('./head', { title: basename ? (title + ' - ' + basename) : title, root: root, version: version, timeString: timeString }); %> 4 | 5 | 24 |
25 |
26 |
27 |
28 |
29 |
30 | 31 |
32 |
33 | <%- html %> 34 | <% if (tocHtml) { %> 35 |
36 | <% } else { %> 37 |
38 | <% } %> 39 |
40 | <% if (tocHtml) { %> 41 |
<%- tocHtml %>
42 | <% } %> 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import DocBuilder from './DocBuilder'; 4 | 5 | new DocBuilder().run(); 6 | -------------------------------------------------------------------------------- /src/resource/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BugHunter7788/doc-builder/0fdc832c5eaaf007d9261c135442423232c0083f/src/resource/favicon.ico -------------------------------------------------------------------------------- /src/resource/icons/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BugHunter7788/doc-builder/0fdc832c5eaaf007d9261c135442423232c0083f/src/resource/icons/128.png -------------------------------------------------------------------------------- /src/resource/icons/144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BugHunter7788/doc-builder/0fdc832c5eaaf007d9261c135442423232c0083f/src/resource/icons/144.png -------------------------------------------------------------------------------- /src/resource/icons/192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BugHunter7788/doc-builder/0fdc832c5eaaf007d9261c135442423232c0083f/src/resource/icons/192.png -------------------------------------------------------------------------------- /src/resource/icons/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BugHunter7788/doc-builder/0fdc832c5eaaf007d9261c135442423232c0083f/src/resource/icons/256.png -------------------------------------------------------------------------------- /src/resource/icons/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BugHunter7788/doc-builder/0fdc832c5eaaf007d9261c135442423232c0083f/src/resource/icons/512.png -------------------------------------------------------------------------------- /src/resource/icons/bars.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/resource/icons/circle-xmark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/resource/lib/github-markdown.min.css: -------------------------------------------------------------------------------- 1 | @media (prefers-color-scheme:dark){.markdown-body{color-scheme:dark;--color-prettylights-syntax-comment:#8b949e;--color-prettylights-syntax-constant:#79c0ff;--color-prettylights-syntax-entity:#d2a8ff;--color-prettylights-syntax-storage-modifier-import:#c9d1d9;--color-prettylights-syntax-entity-tag:#7ee787;--color-prettylights-syntax-keyword:#ff7b72;--color-prettylights-syntax-string:#a5d6ff;--color-prettylights-syntax-variable:#ffa657;--color-prettylights-syntax-brackethighlighter-unmatched:#f85149;--color-prettylights-syntax-invalid-illegal-text:#f0f6fc;--color-prettylights-syntax-invalid-illegal-bg:#8e1519;--color-prettylights-syntax-carriage-return-text:#f0f6fc;--color-prettylights-syntax-carriage-return-bg:#b62324;--color-prettylights-syntax-string-regexp:#7ee787;--color-prettylights-syntax-markup-list:#f2cc60;--color-prettylights-syntax-markup-heading:#1f6feb;--color-prettylights-syntax-markup-italic:#c9d1d9;--color-prettylights-syntax-markup-bold:#c9d1d9;--color-prettylights-syntax-markup-deleted-text:#ffdcd7;--color-prettylights-syntax-markup-deleted-bg:#67060c;--color-prettylights-syntax-markup-inserted-text:#aff5b4;--color-prettylights-syntax-markup-inserted-bg:#033a16;--color-prettylights-syntax-markup-changed-text:#ffdfb6;--color-prettylights-syntax-markup-changed-bg:#5a1e02;--color-prettylights-syntax-markup-ignored-text:#c9d1d9;--color-prettylights-syntax-markup-ignored-bg:#1158c7;--color-prettylights-syntax-meta-diff-range:#d2a8ff;--color-prettylights-syntax-brackethighlighter-angle:#8b949e;--color-prettylights-syntax-sublimelinter-gutter-mark:#484f58;--color-prettylights-syntax-constant-other-reference-link:#a5d6ff;--color-fg-default:#c9d1d9;--color-fg-muted:#8b949e;--color-fg-subtle:#484f58;--color-canvas-default:#0d1117;--color-canvas-subtle:#161b22;--color-border-default:#30363d;--color-border-muted:#21262d;--color-neutral-muted:rgba(110,118,129,0.4);--color-accent-fg:#58a6ff;--color-accent-emphasis:#1f6feb;--color-attention-subtle:rgba(187,128,9,0.15);--color-danger-fg:#f85149}}@media (prefers-color-scheme:light){.markdown-body{color-scheme:light;--color-prettylights-syntax-comment:#6e7781;--color-prettylights-syntax-constant:#0550ae;--color-prettylights-syntax-entity:#8250df;--color-prettylights-syntax-storage-modifier-import:#24292f;--color-prettylights-syntax-entity-tag:#116329;--color-prettylights-syntax-keyword:#cf222e;--color-prettylights-syntax-string:#0a3069;--color-prettylights-syntax-variable:#953800;--color-prettylights-syntax-brackethighlighter-unmatched:#82071e;--color-prettylights-syntax-invalid-illegal-text:#f6f8fa;--color-prettylights-syntax-invalid-illegal-bg:#82071e;--color-prettylights-syntax-carriage-return-text:#f6f8fa;--color-prettylights-syntax-carriage-return-bg:#cf222e;--color-prettylights-syntax-string-regexp:#116329;--color-prettylights-syntax-markup-list:#3b2300;--color-prettylights-syntax-markup-heading:#0550ae;--color-prettylights-syntax-markup-italic:#24292f;--color-prettylights-syntax-markup-bold:#24292f;--color-prettylights-syntax-markup-deleted-text:#82071e;--color-prettylights-syntax-markup-deleted-bg:#FFEBE9;--color-prettylights-syntax-markup-inserted-text:#116329;--color-prettylights-syntax-markup-inserted-bg:#dafbe1;--color-prettylights-syntax-markup-changed-text:#953800;--color-prettylights-syntax-markup-changed-bg:#ffd8b5;--color-prettylights-syntax-markup-ignored-text:#eaeef2;--color-prettylights-syntax-markup-ignored-bg:#0550ae;--color-prettylights-syntax-meta-diff-range:#8250df;--color-prettylights-syntax-brackethighlighter-angle:#57606a;--color-prettylights-syntax-sublimelinter-gutter-mark:#8c959f;--color-prettylights-syntax-constant-other-reference-link:#0a3069;--color-fg-default:#24292f;--color-fg-muted:#57606a;--color-fg-subtle:#6e7781;--color-canvas-default:#ffffff;--color-canvas-subtle:#f6f8fa;--color-border-default:#d0d7de;--color-border-muted:hsla(210,18%,87%,1);--color-neutral-muted:rgba(175,184,193,0.2);--color-accent-fg:#0969da;--color-accent-emphasis:#0969da;--color-attention-subtle:#fff8c5;--color-danger-fg:#cf222e}}.markdown-body{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;margin:0;color:var(--color-fg-default);background-color:var(--color-canvas-default);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";font-size:16px;line-height:1.5;word-wrap:break-word}.markdown-body .octicon{display:inline-block;fill:currentColor;vertical-align:text-bottom}.markdown-body h1:hover .anchor .octicon-link:before,.markdown-body h2:hover .anchor .octicon-link:before,.markdown-body h3:hover .anchor .octicon-link:before,.markdown-body h4:hover .anchor .octicon-link:before,.markdown-body h5:hover .anchor .octicon-link:before,.markdown-body h6:hover .anchor .octicon-link:before{width:16px;height:16px;content:' ';display:inline-block;background-color:currentColor;-webkit-mask-image:url("data:image/svg+xml,");mask-image:url("data:image/svg+xml,")}.markdown-body details,.markdown-body figcaption,.markdown-body figure{display:block}.markdown-body summary{display:list-item}.markdown-body [hidden]{display:none!important}.markdown-body a{background-color:transparent;color:var(--color-accent-fg);text-decoration:none}.markdown-body a:active,.markdown-body a:hover{outline-width:0}.markdown-body abbr[title]{border-bottom:none;text-decoration:underline dotted}.markdown-body b,.markdown-body strong{font-weight:600}.markdown-body dfn{font-style:italic}.markdown-body h1{margin:.67em 0;font-weight:600;padding-bottom:.3em;font-size:2em;border-bottom:1px solid var(--color-border-muted)}.markdown-body mark{background-color:var(--color-attention-subtle);color:var(--color-text-primary)}.markdown-body small{font-size:90%}.markdown-body sub,.markdown-body sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}.markdown-body sub{bottom:-.25em}.markdown-body sup{top:-.5em}.markdown-body img{border-style:none;max-width:100%;box-sizing:content-box;background-color:var(--color-canvas-default)}.markdown-body code,.markdown-body kbd,.markdown-body pre,.markdown-body samp{font-family:monospace,monospace;font-size:1em}.markdown-body figure{margin:1em 40px}.markdown-body hr{box-sizing:content-box;overflow:hidden;background:0 0;border-bottom:1px solid var(--color-border-muted);height:.25em;padding:0;margin:24px 0;background-color:var(--color-border-default);border:0}.markdown-body input{font:inherit;margin:0;overflow:visible;font-family:inherit;font-size:inherit;line-height:inherit}.markdown-body [type=button],.markdown-body [type=reset],.markdown-body [type=submit]{-webkit-appearance:button}.markdown-body [type=button]::-moz-focus-inner,.markdown-body [type=reset]::-moz-focus-inner,.markdown-body [type=submit]::-moz-focus-inner{border-style:none;padding:0}.markdown-body [type=button]:-moz-focusring,.markdown-body [type=reset]:-moz-focusring,.markdown-body [type=submit]:-moz-focusring{outline:1px dotted ButtonText}.markdown-body [type=checkbox],.markdown-body [type=radio]{box-sizing:border-box;padding:0}.markdown-body [type=number]::-webkit-inner-spin-button,.markdown-body [type=number]::-webkit-outer-spin-button{height:auto}.markdown-body [type=search]{-webkit-appearance:textfield;outline-offset:-2px}.markdown-body [type=search]::-webkit-search-cancel-button,.markdown-body [type=search]::-webkit-search-decoration{-webkit-appearance:none}.markdown-body ::-webkit-input-placeholder{color:inherit;opacity:.54}.markdown-body ::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.markdown-body a:hover{text-decoration:underline}.markdown-body hr::before{display:table;content:""}.markdown-body hr::after{display:table;clear:both;content:""}.markdown-body table{border-spacing:0;border-collapse:collapse;display:block;width:max-content;max-width:100%;overflow:auto}.markdown-body td,.markdown-body th{padding:0}.markdown-body details summary{cursor:pointer}.markdown-body details:not([open])>:not(summary){display:none!important}.markdown-body kbd{display:inline-block;padding:3px 5px;font:11px ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;line-height:10px;color:var(--color-fg-default);vertical-align:middle;background-color:var(--color-canvas-subtle);border:solid 1px var(--color-neutral-muted);border-bottom-color:var(--color-neutral-muted);border-radius:6px;box-shadow:inset 0 -1px 0 var(--color-neutral-muted)}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{margin-top:24px;margin-bottom:16px;font-weight:600;line-height:1.25}.markdown-body h2{font-weight:600;padding-bottom:.3em;font-size:1.5em;border-bottom:1px solid var(--color-border-muted)}.markdown-body h3{font-weight:600;font-size:1.25em}.markdown-body h4{font-weight:600;font-size:1em}.markdown-body h5{font-weight:600;font-size:.875em}.markdown-body h6{font-weight:600;font-size:.85em;color:var(--color-fg-muted)}.markdown-body p{margin-top:0;margin-bottom:10px}.markdown-body blockquote{margin:0;padding:0 1em;color:var(--color-fg-muted);border-left:.25em solid var(--color-border-default)}.markdown-body ol,.markdown-body ul{margin-top:0;margin-bottom:0;padding-left:2em}.markdown-body ol ol,.markdown-body ul ol{list-style-type:lower-roman}.markdown-body ol ol ol,.markdown-body ol ul ol,.markdown-body ul ol ol,.markdown-body ul ul ol{list-style-type:lower-alpha}.markdown-body dd{margin-left:0}.markdown-body code,.markdown-body tt{font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:12px}.markdown-body pre{margin-top:0;margin-bottom:0;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:12px;word-wrap:normal}.markdown-body .octicon{display:inline-block;overflow:visible!important;vertical-align:text-bottom;fill:currentColor}.markdown-body ::placeholder{color:var(--color-fg-subtle);opacity:1}.markdown-body input::-webkit-inner-spin-button,.markdown-body input::-webkit-outer-spin-button{margin:0;-webkit-appearance:none;appearance:none}.markdown-body .pl-c{color:var(--color-prettylights-syntax-comment)}.markdown-body .pl-c1,.markdown-body .pl-s .pl-v{color:var(--color-prettylights-syntax-constant)}.markdown-body .pl-e,.markdown-body .pl-en{color:var(--color-prettylights-syntax-entity)}.markdown-body .pl-s .pl-s1,.markdown-body .pl-smi{color:var(--color-prettylights-syntax-storage-modifier-import)}.markdown-body .pl-ent{color:var(--color-prettylights-syntax-entity-tag)}.markdown-body .pl-k{color:var(--color-prettylights-syntax-keyword)}.markdown-body .pl-pds,.markdown-body .pl-s,.markdown-body .pl-s .pl-pse .pl-s1,.markdown-body .pl-sr,.markdown-body .pl-sr .pl-cce,.markdown-body .pl-sr .pl-sra,.markdown-body .pl-sr .pl-sre{color:var(--color-prettylights-syntax-string)}.markdown-body .pl-smw,.markdown-body .pl-v{color:var(--color-prettylights-syntax-variable)}.markdown-body .pl-bu{color:var(--color-prettylights-syntax-brackethighlighter-unmatched)}.markdown-body .pl-ii{color:var(--color-prettylights-syntax-invalid-illegal-text);background-color:var(--color-prettylights-syntax-invalid-illegal-bg)}.markdown-body .pl-c2{color:var(--color-prettylights-syntax-carriage-return-text);background-color:var(--color-prettylights-syntax-carriage-return-bg)}.markdown-body .pl-sr .pl-cce{font-weight:700;color:var(--color-prettylights-syntax-string-regexp)}.markdown-body .pl-ml{color:var(--color-prettylights-syntax-markup-list)}.markdown-body .pl-mh,.markdown-body .pl-mh .pl-en,.markdown-body .pl-ms{font-weight:700;color:var(--color-prettylights-syntax-markup-heading)}.markdown-body .pl-mi{font-style:italic;color:var(--color-prettylights-syntax-markup-italic)}.markdown-body .pl-mb{font-weight:700;color:var(--color-prettylights-syntax-markup-bold)}.markdown-body .pl-md{color:var(--color-prettylights-syntax-markup-deleted-text);background-color:var(--color-prettylights-syntax-markup-deleted-bg)}.markdown-body .pl-mi1{color:var(--color-prettylights-syntax-markup-inserted-text);background-color:var(--color-prettylights-syntax-markup-inserted-bg)}.markdown-body .pl-mc{color:var(--color-prettylights-syntax-markup-changed-text);background-color:var(--color-prettylights-syntax-markup-changed-bg)}.markdown-body .pl-mi2{color:var(--color-prettylights-syntax-markup-ignored-text);background-color:var(--color-prettylights-syntax-markup-ignored-bg)}.markdown-body .pl-mdr{font-weight:700;color:var(--color-prettylights-syntax-meta-diff-range)}.markdown-body .pl-ba{color:var(--color-prettylights-syntax-brackethighlighter-angle)}.markdown-body .pl-sg{color:var(--color-prettylights-syntax-sublimelinter-gutter-mark)}.markdown-body .pl-corl{text-decoration:underline;color:var(--color-prettylights-syntax-constant-other-reference-link)}.markdown-body [data-catalyst]{display:block}.markdown-body g-emoji{font-family:"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1em;font-style:normal!important;font-weight:400;line-height:1;vertical-align:-.075em}.markdown-body g-emoji img{width:1em;height:1em}.markdown-body::before{display:table;content:""}.markdown-body::after{display:table;clear:both;content:""}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .absent{color:var(--color-danger-fg)}.markdown-body .anchor{float:left;padding-right:4px;margin-left:-20px;line-height:1}.markdown-body .anchor:focus{outline:0}.markdown-body blockquote,.markdown-body details,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-top:0;margin-bottom:16px}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body sup>a::before{content:"["}.markdown-body sup>a::after{content:"]"}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:var(--color-fg-default);vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{padding:0 .2em;font-size:inherit}.markdown-body ol.no-list,.markdown-body ul.no-list{padding:0;list-style-type:none}.markdown-body ol[type="1"]{list-style-type:decimal}.markdown-body ol[type=a]{list-style-type:lower-alpha}.markdown-body ol[type=i]{list-style-type:lower-roman}.markdown-body div>ol:not([type]){list-style-type:decimal}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:0;margin-bottom:0}.markdown-body li>p{margin-top:16px}.markdown-body li+li{margin-top:.25em}.markdown-body dl{padding:0}.markdown-body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:600}.markdown-body dl dd{padding:0 16px;margin-bottom:16px}.markdown-body table th{font-weight:600}.markdown-body table td,.markdown-body table th{padding:6px 13px;border:1px solid var(--color-border-default)}.markdown-body table tr{background-color:var(--color-canvas-default);border-top:1px solid var(--color-border-muted)}.markdown-body table tr:nth-child(2n){background-color:var(--color-canvas-subtle)}.markdown-body table img{background-color:transparent}.markdown-body img[align=right]{padding-left:20px}.markdown-body img[align=left]{padding-right:20px}.markdown-body .emoji{max-width:none;vertical-align:text-top;background-color:transparent}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{display:block;float:left;width:auto;padding:7px;margin:13px 0 0;overflow:hidden;border:1px solid var(--color-border-default)}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{display:block;padding:5px 0 0;clear:both;color:var(--color-fg-default)}.markdown-body span.align-center{display:block;overflow:hidden;clear:both}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{display:block;overflow:hidden;clear:both}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body code,.markdown-body tt{padding:.2em .4em;margin:0;font-size:85%;background-color:var(--color-neutral-muted);border-radius:6px}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body pre code{font-size:100%}.markdown-body pre>code{padding:0;margin:0;word-break:normal;white-space:pre;background:0 0;border:0}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body .highlight pre,.markdown-body pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:var(--color-canvas-subtle);border-radius:6px}.markdown-body pre code,.markdown-body pre tt{display:inline;max-width:auto;padding:0;margin:0;overflow:visible;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown-body .csv-data td,.markdown-body .csv-data th{padding:5px;overflow:hidden;font-size:12px;line-height:1;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-num{padding:10px 8px 9px;text-align:right;background:var(--color-canvas-default);border:0}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{font-weight:600;background:var(--color-canvas-subtle);border-top:0}.markdown-body .footnotes{font-size:12px;color:var(--color-fg-muted);border-top:1px solid var(--color-border-default)}.markdown-body .footnotes ol{padding-left:16px}.markdown-body .footnotes li{position:relative}.markdown-body .footnotes li:target::before{position:absolute;top:-8px;right:-8px;bottom:-8px;left:-24px;pointer-events:none;content:"";border:2px solid var(--color-accent-emphasis);border-radius:6px}.markdown-body .footnotes li:target{color:var(--color-fg-default)}.markdown-body .footnotes .data-footnote-backref g-emoji{font-family:monospace}.markdown-body .task-list-item{list-style-type:none}.markdown-body .task-list-item label{font-weight:400}.markdown-body .task-list-item.enabled label{cursor:pointer}.markdown-body .task-list-item+.task-list-item{margin-top:3px}.markdown-body .task-list-item .handle{display:none}.markdown-body .task-list-item-checkbox{margin:0 .2em .25em -1.6em;vertical-align:middle}.markdown-body .contains-task-list:dir(rtl) .task-list-item-checkbox{margin:0 -1.6em .25em .2em}.markdown-body ::-webkit-calendar-picker-indicator{filter:invert(50%)} -------------------------------------------------------------------------------- /src/resource/lib/highlight.default.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Theme: Default 3 | Description: Original highlight.js style 4 | Author: (c) Ivan Sagalaev 5 | Maintainer: @highlightjs/core-team 6 | Website: https://highlightjs.org/ 7 | License: see project LICENSE 8 | Touched: 2021 9 | */pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#f3f3f3;color:#444}.hljs-comment{color:#697070}.hljs-punctuation,.hljs-tag{color:#444a}.hljs-tag .hljs-attr,.hljs-tag .hljs-name{color:#444}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-operator,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#ab5656}.hljs-literal{color:#695}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} -------------------------------------------------------------------------------- /src/resource/lib/jquery-viewer-1.0.1/jquery-viewer.common.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Viewer v1.0.1 3 | * https://fengyuanchen.github.io/jquery-viewer 4 | * 5 | * Copyright 2018-present Chen Fengyuan 6 | * Released under the MIT license 7 | * 8 | * Date: 2019-12-14T09:00:02.315Z 9 | */ 10 | 11 | 'use strict'; 12 | 13 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } 14 | 15 | var $ = _interopDefault(require('jquery')); 16 | var Viewer = _interopDefault(require('viewerjs')); 17 | 18 | if ($ && $.fn && Viewer) { 19 | var AnotherViewer = $.fn.viewer; 20 | var NAMESPACE = 'viewer'; 21 | 22 | $.fn.viewer = function jQueryViewer(option) { 23 | for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 24 | args[_key - 1] = arguments[_key]; 25 | } 26 | 27 | var result; 28 | this.each(function (i, element) { 29 | var $element = $(element); 30 | var isDestroy = option === 'destroy'; 31 | var viewer = $element.data(NAMESPACE); 32 | 33 | if (!viewer) { 34 | if (isDestroy) { 35 | return; 36 | } 37 | 38 | var options = $.extend({}, $element.data(), $.isPlainObject(option) && option); 39 | viewer = new Viewer(element, options); 40 | $element.data(NAMESPACE, viewer); 41 | } 42 | 43 | if (typeof option === 'string') { 44 | var fn = viewer[option]; 45 | 46 | if ($.isFunction(fn)) { 47 | result = fn.apply(viewer, args); 48 | 49 | if (result === viewer) { 50 | result = undefined; 51 | } 52 | 53 | if (isDestroy) { 54 | $element.removeData(NAMESPACE); 55 | } 56 | } 57 | } 58 | }); 59 | return result !== undefined ? result : this; 60 | }; 61 | 62 | $.fn.viewer.Constructor = Viewer; 63 | $.fn.viewer.setDefaults = Viewer.setDefaults; 64 | 65 | $.fn.viewer.noConflict = function noConflict() { 66 | $.fn.viewer = AnotherViewer; 67 | return this; 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /src/resource/lib/jquery-viewer-1.0.1/jquery-viewer.esm.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Viewer v1.0.1 3 | * https://fengyuanchen.github.io/jquery-viewer 4 | * 5 | * Copyright 2018-present Chen Fengyuan 6 | * Released under the MIT license 7 | * 8 | * Date: 2019-12-14T09:00:02.315Z 9 | */ 10 | 11 | import $ from 'jquery'; 12 | import Viewer from 'viewerjs'; 13 | 14 | if ($ && $.fn && Viewer) { 15 | var AnotherViewer = $.fn.viewer; 16 | var NAMESPACE = 'viewer'; 17 | 18 | $.fn.viewer = function jQueryViewer(option) { 19 | for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 20 | args[_key - 1] = arguments[_key]; 21 | } 22 | 23 | var result; 24 | this.each(function (i, element) { 25 | var $element = $(element); 26 | var isDestroy = option === 'destroy'; 27 | var viewer = $element.data(NAMESPACE); 28 | 29 | if (!viewer) { 30 | if (isDestroy) { 31 | return; 32 | } 33 | 34 | var options = $.extend({}, $element.data(), $.isPlainObject(option) && option); 35 | viewer = new Viewer(element, options); 36 | $element.data(NAMESPACE, viewer); 37 | } 38 | 39 | if (typeof option === 'string') { 40 | var fn = viewer[option]; 41 | 42 | if ($.isFunction(fn)) { 43 | result = fn.apply(viewer, args); 44 | 45 | if (result === viewer) { 46 | result = undefined; 47 | } 48 | 49 | if (isDestroy) { 50 | $element.removeData(NAMESPACE); 51 | } 52 | } 53 | } 54 | }); 55 | return result !== undefined ? result : this; 56 | }; 57 | 58 | $.fn.viewer.Constructor = Viewer; 59 | $.fn.viewer.setDefaults = Viewer.setDefaults; 60 | 61 | $.fn.viewer.noConflict = function noConflict() { 62 | $.fn.viewer = AnotherViewer; 63 | return this; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /src/resource/lib/jquery-viewer-1.0.1/jquery-viewer.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Viewer v1.0.1 3 | * https://fengyuanchen.github.io/jquery-viewer 4 | * 5 | * Copyright 2018-present Chen Fengyuan 6 | * Released under the MIT license 7 | * 8 | * Date: 2019-12-14T09:00:02.315Z 9 | */ 10 | 11 | (function (global, factory) { 12 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery'), require('viewerjs')) : 13 | typeof define === 'function' && define.amd ? define(['jquery', 'viewerjs'], factory) : 14 | (global = global || self, factory(global.jQuery, global.Viewer)); 15 | }(this, (function ($, Viewer) { 'use strict'; 16 | 17 | $ = $ && $.hasOwnProperty('default') ? $['default'] : $; 18 | Viewer = Viewer && Viewer.hasOwnProperty('default') ? Viewer['default'] : Viewer; 19 | 20 | if ($ && $.fn && Viewer) { 21 | var AnotherViewer = $.fn.viewer; 22 | var NAMESPACE = 'viewer'; 23 | 24 | $.fn.viewer = function jQueryViewer(option) { 25 | for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 26 | args[_key - 1] = arguments[_key]; 27 | } 28 | 29 | var result; 30 | this.each(function (i, element) { 31 | var $element = $(element); 32 | var isDestroy = option === 'destroy'; 33 | var viewer = $element.data(NAMESPACE); 34 | 35 | if (!viewer) { 36 | if (isDestroy) { 37 | return; 38 | } 39 | 40 | var options = $.extend({}, $element.data(), $.isPlainObject(option) && option); 41 | viewer = new Viewer(element, options); 42 | $element.data(NAMESPACE, viewer); 43 | } 44 | 45 | if (typeof option === 'string') { 46 | var fn = viewer[option]; 47 | 48 | if ($.isFunction(fn)) { 49 | result = fn.apply(viewer, args); 50 | 51 | if (result === viewer) { 52 | result = undefined; 53 | } 54 | 55 | if (isDestroy) { 56 | $element.removeData(NAMESPACE); 57 | } 58 | } 59 | } 60 | }); 61 | return result !== undefined ? result : this; 62 | }; 63 | 64 | $.fn.viewer.Constructor = Viewer; 65 | $.fn.viewer.setDefaults = Viewer.setDefaults; 66 | 67 | $.fn.viewer.noConflict = function noConflict() { 68 | $.fn.viewer = AnotherViewer; 69 | return this; 70 | }; 71 | } 72 | 73 | }))); 74 | -------------------------------------------------------------------------------- /src/resource/lib/jquery-viewer-1.0.1/jquery-viewer.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Viewer v1.0.1 3 | * https://fengyuanchen.github.io/jquery-viewer 4 | * 5 | * Copyright 2018-present Chen Fengyuan 6 | * Released under the MIT license 7 | * 8 | * Date: 2019-12-14T09:00:02.315Z 9 | */ 10 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("jquery"),require("viewerjs")):"function"==typeof define&&define.amd?define(["jquery","viewerjs"],t):t((e=e||self).jQuery,e.Viewer)}(this,function(d,v){"use strict";if(d=d&&d.hasOwnProperty("default")?d.default:d,v=v&&v.hasOwnProperty("default")?v.default:v,d&&d.fn&&v){var e=d.fn.viewer,w="viewer";d.fn.viewer=function(o){for(var e=arguments.length,u=new Array(1!r.call(e,s)||(t=!0,!1)),t}return!1}getContexts(){let e,t=[];return(e=void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(e=>{const s=t.filter(t=>t.contains(e)).length>0;-1!==t.indexOf(e)||s||t.push(e)}),t}getIframeContents(e,t,s=(()=>{})){let r;try{const t=e.contentWindow;if(r=t.document,!t||!r)throw new Error("iframe inaccessible")}catch(e){s()}r&&t(r)}isIframeBlank(e){const t="about:blank",s=e.getAttribute("src").trim(),r=e.contentWindow.location.href;return r===t&&s!==t&&s}observeIframeLoad(e,t,s){let r=!1,i=null;const n=()=>{if(!r){r=!0,clearTimeout(i);try{this.isIframeBlank(e)||(e.removeEventListener("load",n),this.getIframeContents(e,t,s))}catch(e){s()}}};e.addEventListener("load",n),i=setTimeout(n,this.iframesTimeout)}onIframeReady(e,t,s){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,s):this.getIframeContents(e,t,s):this.observeIframeLoad(e,t,s)}catch(e){s()}}waitForIframes(e,t){let s=0;this.forEachIframe(e,()=>!0,e=>{s++,this.waitForIframes(e.querySelector("html"),()=>{--s||t()})},e=>{e||t()})}forEachIframe(e,s,r,i=(()=>{})){let n=e.querySelectorAll("iframe"),o=n.length,a=0;n=Array.prototype.slice.call(n);const c=()=>{--o<=0&&i(a)};o||c(),n.forEach(e=>{t.matches(e,this.exclude)?c():this.onIframeReady(e,t=>{s(e)&&(a++,r(t)),c()},c)})}createIterator(e,t,s){return document.createNodeIterator(e,t,s,!1)}createInstanceOnIframe(e){return new t(e.querySelector("html"),this.iframes)}compareNodeIframe(e,t,s){const r=e.compareDocumentPosition(s),i=Node.DOCUMENT_POSITION_PRECEDING;if(r&i){if(null===t)return!0;if(t.compareDocumentPosition(s)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}getIteratorNode(e){const t=e.previousNode();let s;return{prevNode:t,node:s=null===t?e.nextNode():e.nextNode()&&e.nextNode()}}checkIframeFilter(e,t,s,r){let i=!1,n=!1;return r.forEach((e,t)=>{e.val===s&&(i=t,n=e.handled)}),this.compareNodeIframe(e,t,s)?(!1!==i||n?!1===i||n||(r[i].handled=!0):r.push({val:s,handled:!0}),!0):(!1===i&&r.push({val:s,handled:!1}),!1)}handleOpenIframes(e,t,s,r){e.forEach(e=>{e.handled||this.getIframeContents(e.val,e=>{this.createInstanceOnIframe(e).forEachNode(t,s,r)})})}iterateThroughNodes(e,t,s,r,i){const n=this.createIterator(t,e,r);let o,a,c=[],h=[],l=()=>(({prevNode:a,node:o}=this.getIteratorNode(n)),o);for(;l();)this.iframes&&this.forEachIframe(t,e=>this.checkIframeFilter(o,a,e,c),t=>{this.createInstanceOnIframe(t).forEachNode(e,e=>h.push(e),r)}),h.push(o);h.forEach(e=>{s(e)}),this.iframes&&this.handleOpenIframes(c,e,s,r),i()}forEachNode(e,t,s,r=(()=>{})){const i=this.getContexts();let n=i.length;n||r(),i.forEach(i=>{const o=()=>{this.iterateThroughNodes(e,i,t,s,()=>{--n<=0&&r()})};this.iframes?this.waitForIframes(i,o):o()})}}class s{constructor(e){this.ctx=e,this.ie=!1;const t=window.navigator.userAgent;(t.indexOf("MSIE")>-1||t.indexOf("Trident")>-1)&&(this.ie=!0)}set opt(e){this._opt=Object.assign({},{element:"",className:"",exclude:[],iframes:!1,iframesTimeout:5e3,separateWordSearch:!0,diacritics:!0,synonyms:{},accuracy:"partially",acrossElements:!1,caseSensitive:!1,ignoreJoiners:!1,ignoreGroups:0,ignorePunctuation:[],wildcards:"disabled",each:()=>{},noMatch:()=>{},filter:()=>!0,done:()=>{},debug:!1,log:window.console},e)}get opt(){return this._opt}get iterator(){return new t(this.ctx,this.opt.iframes,this.opt.exclude,this.opt.iframesTimeout)}log(e,t="debug"){const s=this.opt.log;this.opt.debug&&"object"==typeof s&&"function"==typeof s[t]&&s[t](`mark.js: ${e}`)}escapeStr(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}createRegExp(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e)}createSynonymsRegExp(e){const t=this.opt.synonyms,s=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(let i in t)if(t.hasOwnProperty(i)){const n=t[i],o="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(n):this.escapeStr(n);""!==o&&""!==a&&(e=e.replace(new RegExp(`(${this.escapeStr(o)}|${this.escapeStr(a)})`,`gm${s}`),r+`(${this.processSynomyms(o)}|`+`${this.processSynomyms(a)})`+r))}return e}processSynomyms(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}setupWildcardsRegExp(e){return(e=e.replace(/(?:\\)*\?/g,e=>"\\"===e.charAt(0)?"?":"")).replace(/(?:\\)*\*/g,e=>"\\"===e.charAt(0)?"*":"")}createWildcardsRegExp(e){let t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}setupIgnoreJoinersRegExp(e){return e.replace(/[^(|)\\]/g,(e,t,s)=>{let r=s.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}createJoinersRegExp(e){let t=[];const s=this.opt.ignorePunctuation;return Array.isArray(s)&&s.length&&t.push(this.escapeStr(s.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join(`[${t.join("")}]*`):e}createDiacriticsRegExp(e){const t=this.opt.caseSensitive?"":"i",s=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"];let r=[];return e.split("").forEach(i=>{s.every(s=>{if(-1!==s.indexOf(i)){if(r.indexOf(s)>-1)return!1;e=e.replace(new RegExp(`[${s}]`,`gm${t}`),`[${s}]`),r.push(s)}return!0})}),e}createMergedBlanksRegExp(e){return e.replace(/[\s]+/gim,"[\\s]+")}createAccuracyRegExp(e){const t="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿";let s=this.opt.accuracy,r="string"==typeof s?s:s.value,i="string"==typeof s?[]:s.limiters,n="";switch(i.forEach(e=>{n+=`|${this.escapeStr(e)}`}),r){case"partially":default:return`()(${e})`;case"complementary":return`()([^${n="\\s"+(n||this.escapeStr(t))}]*${e}[^${n}]*)`;case"exactly":return`(^|\\s${n})(${e})(?=$|\\s${n})`}}getSeparatedKeywords(e){let t=[];return e.forEach(e=>{this.opt.separateWordSearch?e.split(" ").forEach(e=>{e.trim()&&-1===t.indexOf(e)&&t.push(e)}):e.trim()&&-1===t.indexOf(e)&&t.push(e)}),{keywords:t.sort((e,t)=>t.length-e.length),length:t.length}}isNumeric(e){return Number(parseFloat(e))==e}checkRanges(e){if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];const t=[];let s=0;return e.sort((e,t)=>e.start-t.start).forEach(e=>{let{start:r,end:i,valid:n}=this.callNoMatchOnInvalidRanges(e,s);n&&(e.start=r,e.length=i-r,t.push(e),s=i)}),t}callNoMatchOnInvalidRanges(e,t){let s,r,i=!1;return e&&void 0!==e.start?(r=(s=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-s>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+`${JSON.stringify(e)}`),this.opt.noMatch(e))):(this.log(`Ignoring invalid range: ${JSON.stringify(e)}`),this.opt.noMatch(e)),{start:s,end:r,valid:i}}checkWhitespaceRanges(e,t,s){let r,i=!0,n=s.length,o=t-n,a=parseInt(e.start,10)-o;return(r=(a=a>n?n:a)+parseInt(e.length,10))>n&&(r=n,this.log(`End range automatically set to the max value of ${n}`)),a<0||r-a<0||a>n||r>n?(i=!1,this.log(`Invalid range: ${JSON.stringify(e)}`),this.opt.noMatch(e)):""===s.substring(a,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:a,end:r,valid:i}}getTextNodes(e){let t="",s=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,e=>{s.push({start:t.length,end:(t+=e.textContent).length,node:e})},e=>this.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT,()=>{e({value:t,nodes:s})})}matchesExclude(e){return t.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}wrapRangeInTextNode(e,t,s){const r=this.opt.element?this.opt.element:"mark",i=e.splitText(t),n=i.splitText(s-t);let o=document.createElement(r);return o.setAttribute("data-markjs","true"),this.opt.className&&o.setAttribute("class",this.opt.className),o.textContent=i.textContent,i.parentNode.replaceChild(o,i),n}wrapRangeInMappedTextNode(e,t,s,r,i){e.nodes.every((n,o)=>{const a=e.nodes[o+1];if(void 0===a||a.start>t){if(!r(n.node))return!1;const a=t-n.start,c=(s>n.end?n.end:s)-n.start,h=e.value.substr(0,n.start),l=e.value.substr(c+n.start);if(n.node=this.wrapRangeInTextNode(n.node,a,c),e.value=h+l,e.nodes.forEach((t,s)=>{s>=o&&(e.nodes[s].start>0&&s!==o&&(e.nodes[s].start-=c),e.nodes[s].end-=c)}),s-=c,i(n.node.previousSibling,n.start),!(s>n.end))return!1;t=n.end}return!0})}wrapMatches(e,t,s,r,i){const n=0===t?0:t+1;this.getTextNodes(t=>{t.nodes.forEach(t=>{let i;for(t=t.node;null!==(i=e.exec(t.textContent))&&""!==i[n];){if(!s(i[n],t))continue;let o=i.index;if(0!==n)for(let e=1;e{let o;for(;null!==(o=e.exec(t.value))&&""!==o[n];){let i=o.index;if(0!==n)for(let e=1;es(o[n],e),(t,s)=>{e.lastIndex=s,r(t)})}i()})}wrapRangeFromIndex(e,t,s,r){this.getTextNodes(i=>{const n=i.value.length;e.forEach((e,r)=>{let{start:o,end:a,valid:c}=this.checkWhitespaceRanges(e,n,i.value);c&&this.wrapRangeInMappedTextNode(i,o,a,s=>t(s,e,i.value.substring(o,a),r),t=>{s(t,e)})}),r()})}unwrapMatches(e){const t=e.parentNode;let s=document.createDocumentFragment();for(;e.firstChild;)s.appendChild(e.removeChild(e.firstChild));t.replaceChild(s,e),this.ie?this.normalizeTextNode(t):t.normalize()}normalizeTextNode(e){if(e){if(3===e.nodeType)for(;e.nextSibling&&3===e.nextSibling.nodeType;)e.nodeValue+=e.nextSibling.nodeValue,e.parentNode.removeChild(e.nextSibling);else this.normalizeTextNode(e.firstChild);this.normalizeTextNode(e.nextSibling)}}markRegExp(e,t){this.opt=t,this.log(`Searching with expression "${e}"`);let s=0,r="wrapMatches";const i=e=>{s++,this.opt.each(e)};this.opt.acrossElements&&(r="wrapMatchesAcrossElements"),this[r](e,this.opt.ignoreGroups,(e,t)=>this.opt.filter(t,e,s),i,()=>{0===s&&this.opt.noMatch(e),this.opt.done(s)})}mark(e,t){this.opt=t;let s=0,r="wrapMatches";const{keywords:i,length:n}=this.getSeparatedKeywords("string"==typeof e?[e]:e),o=this.opt.caseSensitive?"":"i",a=e=>{let t=new RegExp(this.createRegExp(e),`gm${o}`),c=0;this.log(`Searching with expression "${t}"`),this[r](t,1,(t,r)=>this.opt.filter(r,e,s,c),e=>{c++,s++,this.opt.each(e)},()=>{0===c&&this.opt.noMatch(e),i[n-1]===e?this.opt.done(s):a(i[i.indexOf(e)+1])})};this.opt.acrossElements&&(r="wrapMatchesAcrossElements"),0===n?this.opt.done(s):a(i[0])}markRanges(e,t){this.opt=t;let s=0,r=this.checkRanges(e);r&&r.length?(this.log("Starting to mark with the following ranges: "+JSON.stringify(r)),this.wrapRangeFromIndex(r,(e,t,s,r)=>this.opt.filter(e,t,s,r),(e,t)=>{s++,this.opt.each(e,t)},()=>{this.opt.done(s)})):this.opt.done(s)}unmark(e){this.opt=e;let s=this.opt.element?this.opt.element:"*";s+="[data-markjs]",this.opt.className&&(s+=`.${this.opt.className}`),this.log(`Removal selector "${s}"`),this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT,e=>{this.unwrapMatches(e)},e=>{const r=t.matches(e,s),i=this.matchesExclude(e);return!r||i?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},this.opt.done)}}return e.fn.mark=function(e,t){return new s(this.get()).mark(e,t),this},e.fn.markRegExp=function(e,t){return new s(this.get()).markRegExp(e,t),this},e.fn.markRanges=function(e,t){return new s(this.get()).markRanges(e,t),this},e.fn.unmark=function(e){return new s(this.get()).unmark(e),this},e}); 8 | -------------------------------------------------------------------------------- /src/resource/lib/mark.js-8.11.1/jquery.mark.min.js: -------------------------------------------------------------------------------- 1 | /*!*************************************************** 2 | * mark.js v8.11.1 3 | * https://markjs.io/ 4 | * Copyright (c) 2014–2018, Julian Kühnel 5 | * Released under the MIT license https://git.io/vwTVl 6 | *****************************************************/ 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],t):e.Mark=t(e.jQuery)}(this,function(e){"use strict";e=e&&e.hasOwnProperty("default")?e.default:e;var t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},r=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1])||arguments[1],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;n(this,e),this.ctx=t,this.iframes=r,this.exclude=i,this.iframesTimeout=o}return r(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(function(t){var n=e.filter(function(e){return e.contains(t)}).length>0;-1!==e.indexOf(t)||n||e.push(t)}),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var i=e.contentWindow;if(r=i.document,!i||!r)throw new Error("iframe inaccessible")}catch(e){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t=e.getAttribute("src").trim();return"about:blank"===e.contentWindow.location.href&&"about:blank"!==t&&t}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,i=!1,o=null,a=function a(){if(!i){i=!0,clearTimeout(o);try{r.isIframeBlank(e)||(e.removeEventListener("load",a),r.getIframeContents(e,t,n))}catch(e){n()}}};e.addEventListener("load",a),o=setTimeout(a,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(e){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,function(){return!0},function(e){r++,n.waitForIframes(e.querySelector("html"),function(){--r||t()})},function(e){e||t()})}},{key:"forEachIframe",value:function(t,n,r){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=t.querySelectorAll("iframe"),s=a.length,c=0;a=Array.prototype.slice.call(a);var u=function(){--s<=0&&o(c)};s||u(),a.forEach(function(t){e.matches(t,i.exclude)?u():i.onIframeReady(t,function(e){n(t)&&(c++,r(e)),u()},u)})}},{key:"createIterator",value:function(e,t,n){return document.createNodeIterator(e,t,n,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode();return{prevNode:t,node:null===t?e.nextNode():e.nextNode()&&e.nextNode()}}},{key:"checkIframeFilter",value:function(e,t,n,r){var i=!1,o=!1;return r.forEach(function(e,t){e.val===n&&(i=t,o=e.handled)}),this.compareNodeIframe(e,t,n)?(!1!==i||o?!1===i||o||(r[i].handled=!0):r.push({val:n,handled:!0}),!0):(!1===i&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var i=this;e.forEach(function(e){e.handled||i.getIframeContents(e.val,function(e){i.createInstanceOnIframe(e).forEachNode(t,n,r)})})}},{key:"iterateThroughNodes",value:function(e,t,n,r,i){for(var o,a=this,s=this.createIterator(t,e,r),c=[],u=[],l=void 0,h=void 0;void 0,o=a.getIteratorNode(s),h=o.prevNode,l=o.node;)this.iframes&&this.forEachIframe(t,function(e){return a.checkIframeFilter(l,h,e,c)},function(t){a.createInstanceOnIframe(t).forEachNode(e,function(e){return u.push(e)},r)}),u.push(l);u.forEach(function(e){n(e)}),this.iframes&&this.handleOpenIframes(c,e,n,r),i()}},{key:"forEachNode",value:function(e,t,n){var r=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},o=this.getContexts(),a=o.length;a||i(),o.forEach(function(o){var s=function(){r.iterateThroughNodes(e,o,t,n,function(){--a<=0&&i()})};r.iframes?r.waitForIframes(o,s):s()})}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var i=!1;return n.every(function(t){return!r.call(e,t)||(i=!0,!1)}),i}return!1}}]),e}(),a=function(){function e(t){n(this,e),this.ctx=t,this.ie=!1;var r=window.navigator.userAgent;(r.indexOf("MSIE")>-1||r.indexOf("Trident")>-1)&&(this.ie=!0)}return r(e,[{key:"log",value:function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",r=this.opt.log;this.opt.debug&&"object"===(void 0===r?"undefined":t(r))&&"function"==typeof r[n]&&r[n]("mark.js: "+e)}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createRegExp",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e)}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o);""!==a&&""!==s&&(e=e.replace(new RegExp("("+this.escapeStr(a)+"|"+this.escapeStr(s)+")","gm"+n),r+"("+this.processSynomyms(a)+"|"+this.processSynomyms(s)+")"+r))}return e}},{key:"processSynomyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,function(e){return"\\"===e.charAt(0)?"?":""})).replace(/(?:\\)*\*/g,function(e){return"\\"===e.charAt(0)?"*":""})}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"],r=[];return e.split("").forEach(function(i){n.every(function(n){if(-1!==n.indexOf(i)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0})}),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n=this.opt.accuracy,r="string"==typeof n?n:n.value,i="";switch(("string"==typeof n?[]:n.limiters).forEach(function(e){i+="|"+t.escapeStr(e)}),r){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿")))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach(function(e){t.opt.separateWordSearch?e.split(" ").forEach(function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)}):e.trim()&&-1===n.indexOf(e)&&n.push(e)}),{keywords:n.sort(function(e,t){return t.length-e.length}),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort(function(e,t){return e.start-t.start}).forEach(function(e){var i=t.callNoMatchOnInvalidRanges(e,r),o=i.start,a=i.end;i.valid&&(e.start=o,e.length=a-o,n.push(e),r=a)}),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,i=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:i}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,i=!0,o=n.length,a=t-o,s=parseInt(e.start,10)-a;return(r=(s=s>o?o:s)+parseInt(e.length,10))>o&&(r=o,this.log("End range automatically set to the max value of "+o)),s<0||r-s<0||s>o||r>o?(i=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:i}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})},function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},function(){e({value:n,nodes:r})})}},{key:"matchesExclude",value:function(e){return o.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,t,n){var r=this.opt.element?this.opt.element:"mark",i=e.splitText(t),o=i.splitText(n-t),a=document.createElement(r);return a.setAttribute("data-markjs","true"),this.opt.className&&a.setAttribute("class",this.opt.className),a.textContent=i.textContent,i.parentNode.replaceChild(a,i),o}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,i){var o=this;e.nodes.every(function(a,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(a.node))return!1;var u=t-a.start,l=(n>a.end?a.end:n)-a.start,h=e.value.substr(0,a.start),f=e.value.substr(l+a.start);if(a.node=o.wrapRangeInTextNode(a.node,u,l),e.value=h+f,e.nodes.forEach(function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=l),e.nodes[n].end-=l)}),n-=l,i(a.node.previousSibling,a.start),!(n>a.end))return!1;t=a.end}return!0})}},{key:"wrapMatches",value:function(e,t,n,r,i){var o=this,a=0===t?0:t+1;this.getTextNodes(function(t){t.nodes.forEach(function(t){t=t.node;for(var i=void 0;null!==(i=e.exec(t.textContent))&&""!==i[a];)if(n(i[a],t)){var s=i.index;if(0!==a)for(var c=1;c { 34 | if (fn.call(element, sel)) { 35 | match = true; 36 | return false; 37 | } 38 | return true; 39 | }); 40 | return match; 41 | } else { 42 | return false; 43 | } 44 | } 45 | getContexts() { 46 | let ctx, 47 | filteredCtx = []; 48 | if (typeof this.ctx === 'undefined' || !this.ctx) { 49 | ctx = []; 50 | } else if (NodeList.prototype.isPrototypeOf(this.ctx)) { 51 | ctx = Array.prototype.slice.call(this.ctx); 52 | } else if (Array.isArray(this.ctx)) { 53 | ctx = this.ctx; 54 | } else if (typeof this.ctx === 'string') { 55 | ctx = Array.prototype.slice.call( 56 | document.querySelectorAll(this.ctx) 57 | ); 58 | } else { 59 | ctx = [this.ctx]; 60 | } 61 | ctx.forEach(ctx => { 62 | const isDescendant = filteredCtx.filter(contexts => { 63 | return contexts.contains(ctx); 64 | }).length > 0; 65 | if (filteredCtx.indexOf(ctx) === -1 && !isDescendant) { 66 | filteredCtx.push(ctx); 67 | } 68 | }); 69 | return filteredCtx; 70 | } 71 | getIframeContents(ifr, successFn, errorFn = () => {}) { 72 | let doc; 73 | try { 74 | const ifrWin = ifr.contentWindow; 75 | doc = ifrWin.document; 76 | if (!ifrWin || !doc) { 77 | throw new Error('iframe inaccessible'); 78 | } 79 | } catch (e) { 80 | errorFn(); 81 | } 82 | if (doc) { 83 | successFn(doc); 84 | } 85 | } 86 | isIframeBlank(ifr) { 87 | const bl = 'about:blank', 88 | src = ifr.getAttribute('src').trim(), 89 | href = ifr.contentWindow.location.href; 90 | return href === bl && src !== bl && src; 91 | } 92 | observeIframeLoad(ifr, successFn, errorFn) { 93 | let called = false, 94 | tout = null; 95 | const listener = () => { 96 | if (called) { 97 | return; 98 | } 99 | called = true; 100 | clearTimeout(tout); 101 | try { 102 | if (!this.isIframeBlank(ifr)) { 103 | ifr.removeEventListener('load', listener); 104 | this.getIframeContents(ifr, successFn, errorFn); 105 | } 106 | } catch (e) { 107 | errorFn(); 108 | } 109 | }; 110 | ifr.addEventListener('load', listener); 111 | tout = setTimeout(listener, this.iframesTimeout); 112 | } 113 | onIframeReady(ifr, successFn, errorFn) { 114 | try { 115 | if (ifr.contentWindow.document.readyState === 'complete') { 116 | if (this.isIframeBlank(ifr)) { 117 | this.observeIframeLoad(ifr, successFn, errorFn); 118 | } else { 119 | this.getIframeContents(ifr, successFn, errorFn); 120 | } 121 | } else { 122 | this.observeIframeLoad(ifr, successFn, errorFn); 123 | } 124 | } catch (e) { 125 | errorFn(); 126 | } 127 | } 128 | waitForIframes(ctx, done) { 129 | let eachCalled = 0; 130 | this.forEachIframe(ctx, () => true, ifr => { 131 | eachCalled++; 132 | this.waitForIframes(ifr.querySelector('html'), () => { 133 | if (!(--eachCalled)) { 134 | done(); 135 | } 136 | }); 137 | }, handled => { 138 | if (!handled) { 139 | done(); 140 | } 141 | }); 142 | } 143 | forEachIframe(ctx, filter, each, end = () => {}) { 144 | let ifr = ctx.querySelectorAll('iframe'), 145 | open = ifr.length, 146 | handled = 0; 147 | ifr = Array.prototype.slice.call(ifr); 148 | const checkEnd = () => { 149 | if (--open <= 0) { 150 | end(handled); 151 | } 152 | }; 153 | if (!open) { 154 | checkEnd(); 155 | } 156 | ifr.forEach(ifr => { 157 | if (DOMIterator.matches(ifr, this.exclude)) { 158 | checkEnd(); 159 | } else { 160 | this.onIframeReady(ifr, con => { 161 | if (filter(ifr)) { 162 | handled++; 163 | each(con); 164 | } 165 | checkEnd(); 166 | }, checkEnd); 167 | } 168 | }); 169 | } 170 | createIterator(ctx, whatToShow, filter) { 171 | return document.createNodeIterator(ctx, whatToShow, filter, false); 172 | } 173 | createInstanceOnIframe(contents) { 174 | return new DOMIterator(contents.querySelector('html'), this.iframes); 175 | } 176 | compareNodeIframe(node, prevNode, ifr) { 177 | const compCurr = node.compareDocumentPosition(ifr), 178 | prev = Node.DOCUMENT_POSITION_PRECEDING; 179 | if (compCurr & prev) { 180 | if (prevNode !== null) { 181 | const compPrev = prevNode.compareDocumentPosition(ifr), 182 | after = Node.DOCUMENT_POSITION_FOLLOWING; 183 | if (compPrev & after) { 184 | return true; 185 | } 186 | } else { 187 | return true; 188 | } 189 | } 190 | return false; 191 | } 192 | getIteratorNode(itr) { 193 | const prevNode = itr.previousNode(); 194 | let node; 195 | if (prevNode === null) { 196 | node = itr.nextNode(); 197 | } else { 198 | node = itr.nextNode() && itr.nextNode(); 199 | } 200 | return { 201 | prevNode, 202 | node 203 | }; 204 | } 205 | checkIframeFilter(node, prevNode, currIfr, ifr) { 206 | let key = false, 207 | handled = false; 208 | ifr.forEach((ifrDict, i) => { 209 | if (ifrDict.val === currIfr) { 210 | key = i; 211 | handled = ifrDict.handled; 212 | } 213 | }); 214 | if (this.compareNodeIframe(node, prevNode, currIfr)) { 215 | if (key === false && !handled) { 216 | ifr.push({ 217 | val: currIfr, 218 | handled: true 219 | }); 220 | } else if (key !== false && !handled) { 221 | ifr[key].handled = true; 222 | } 223 | return true; 224 | } 225 | if (key === false) { 226 | ifr.push({ 227 | val: currIfr, 228 | handled: false 229 | }); 230 | } 231 | return false; 232 | } 233 | handleOpenIframes(ifr, whatToShow, eCb, fCb) { 234 | ifr.forEach(ifrDict => { 235 | if (!ifrDict.handled) { 236 | this.getIframeContents(ifrDict.val, con => { 237 | this.createInstanceOnIframe(con).forEachNode( 238 | whatToShow, eCb, fCb 239 | ); 240 | }); 241 | } 242 | }); 243 | } 244 | iterateThroughNodes(whatToShow, ctx, eachCb, filterCb, doneCb) { 245 | const itr = this.createIterator(ctx, whatToShow, filterCb); 246 | let ifr = [], 247 | elements = [], 248 | node, prevNode, retrieveNodes = () => { 249 | ({ 250 | prevNode, 251 | node 252 | } = this.getIteratorNode(itr)); 253 | return node; 254 | }; 255 | while (retrieveNodes()) { 256 | if (this.iframes) { 257 | this.forEachIframe(ctx, currIfr => { 258 | return this.checkIframeFilter(node, prevNode, currIfr, ifr); 259 | }, con => { 260 | this.createInstanceOnIframe(con).forEachNode( 261 | whatToShow, ifrNode => elements.push(ifrNode), filterCb 262 | ); 263 | }); 264 | } 265 | elements.push(node); 266 | } 267 | elements.forEach(node => { 268 | eachCb(node); 269 | }); 270 | if (this.iframes) { 271 | this.handleOpenIframes(ifr, whatToShow, eachCb, filterCb); 272 | } 273 | doneCb(); 274 | } 275 | forEachNode(whatToShow, each, filter, done = () => {}) { 276 | const contexts = this.getContexts(); 277 | let open = contexts.length; 278 | if (!open) { 279 | done(); 280 | } 281 | contexts.forEach(ctx => { 282 | const ready = () => { 283 | this.iterateThroughNodes(whatToShow, ctx, each, filter, () => { 284 | if (--open <= 0) { 285 | done(); 286 | } 287 | }); 288 | }; 289 | if (this.iframes) { 290 | this.waitForIframes(ctx, ready); 291 | } else { 292 | ready(); 293 | } 294 | }); 295 | } 296 | } 297 | 298 | class Mark$1 { 299 | constructor(ctx) { 300 | this.ctx = ctx; 301 | this.ie = false; 302 | const ua = window.navigator.userAgent; 303 | if (ua.indexOf('MSIE') > -1 || ua.indexOf('Trident') > -1) { 304 | this.ie = true; 305 | } 306 | } 307 | set opt(val) { 308 | this._opt = Object.assign({}, { 309 | 'element': '', 310 | 'className': '', 311 | 'exclude': [], 312 | 'iframes': false, 313 | 'iframesTimeout': 5000, 314 | 'separateWordSearch': true, 315 | 'diacritics': true, 316 | 'synonyms': {}, 317 | 'accuracy': 'partially', 318 | 'acrossElements': false, 319 | 'caseSensitive': false, 320 | 'ignoreJoiners': false, 321 | 'ignoreGroups': 0, 322 | 'ignorePunctuation': [], 323 | 'wildcards': 'disabled', 324 | 'each': () => {}, 325 | 'noMatch': () => {}, 326 | 'filter': () => true, 327 | 'done': () => {}, 328 | 'debug': false, 329 | 'log': window.console 330 | }, val); 331 | } 332 | get opt() { 333 | return this._opt; 334 | } 335 | get iterator() { 336 | return new DOMIterator( 337 | this.ctx, 338 | this.opt.iframes, 339 | this.opt.exclude, 340 | this.opt.iframesTimeout 341 | ); 342 | } 343 | log(msg, level = 'debug') { 344 | const log = this.opt.log; 345 | if (!this.opt.debug) { 346 | return; 347 | } 348 | if (typeof log === 'object' && typeof log[level] === 'function') { 349 | log[level](`mark.js: ${msg}`); 350 | } 351 | } 352 | escapeStr(str) { 353 | return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); 354 | } 355 | createRegExp(str) { 356 | if (this.opt.wildcards !== 'disabled') { 357 | str = this.setupWildcardsRegExp(str); 358 | } 359 | str = this.escapeStr(str); 360 | if (Object.keys(this.opt.synonyms).length) { 361 | str = this.createSynonymsRegExp(str); 362 | } 363 | if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) { 364 | str = this.setupIgnoreJoinersRegExp(str); 365 | } 366 | if (this.opt.diacritics) { 367 | str = this.createDiacriticsRegExp(str); 368 | } 369 | str = this.createMergedBlanksRegExp(str); 370 | if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) { 371 | str = this.createJoinersRegExp(str); 372 | } 373 | if (this.opt.wildcards !== 'disabled') { 374 | str = this.createWildcardsRegExp(str); 375 | } 376 | str = this.createAccuracyRegExp(str); 377 | return str; 378 | } 379 | createSynonymsRegExp(str) { 380 | const syn = this.opt.synonyms, 381 | sens = this.opt.caseSensitive ? '' : 'i', 382 | joinerPlaceholder = this.opt.ignoreJoiners || 383 | this.opt.ignorePunctuation.length ? '\u0000' : ''; 384 | for (let index in syn) { 385 | if (syn.hasOwnProperty(index)) { 386 | const value = syn[index], 387 | k1 = this.opt.wildcards !== 'disabled' ? 388 | this.setupWildcardsRegExp(index) : 389 | this.escapeStr(index), 390 | k2 = this.opt.wildcards !== 'disabled' ? 391 | this.setupWildcardsRegExp(value) : 392 | this.escapeStr(value); 393 | if (k1 !== '' && k2 !== '') { 394 | str = str.replace( 395 | new RegExp( 396 | `(${this.escapeStr(k1)}|${this.escapeStr(k2)})`, 397 | `gm${sens}` 398 | ), 399 | joinerPlaceholder + 400 | `(${this.processSynomyms(k1)}|` + 401 | `${this.processSynomyms(k2)})` + 402 | joinerPlaceholder 403 | ); 404 | } 405 | } 406 | } 407 | return str; 408 | } 409 | processSynomyms(str) { 410 | if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) { 411 | str = this.setupIgnoreJoinersRegExp(str); 412 | } 413 | return str; 414 | } 415 | setupWildcardsRegExp(str) { 416 | str = str.replace(/(?:\\)*\?/g, val => { 417 | return val.charAt(0) === '\\' ? '?' : '\u0001'; 418 | }); 419 | return str.replace(/(?:\\)*\*/g, val => { 420 | return val.charAt(0) === '\\' ? '*' : '\u0002'; 421 | }); 422 | } 423 | createWildcardsRegExp(str) { 424 | let spaces = this.opt.wildcards === 'withSpaces'; 425 | return str 426 | .replace(/\u0001/g, spaces ? '[\\S\\s]?' : '\\S?') 427 | .replace(/\u0002/g, spaces ? '[\\S\\s]*?' : '\\S*'); 428 | } 429 | setupIgnoreJoinersRegExp(str) { 430 | return str.replace(/[^(|)\\]/g, (val, indx, original) => { 431 | let nextChar = original.charAt(indx + 1); 432 | if (/[(|)\\]/.test(nextChar) || nextChar === '') { 433 | return val; 434 | } else { 435 | return val + '\u0000'; 436 | } 437 | }); 438 | } 439 | createJoinersRegExp(str) { 440 | let joiner = []; 441 | const ignorePunctuation = this.opt.ignorePunctuation; 442 | if (Array.isArray(ignorePunctuation) && ignorePunctuation.length) { 443 | joiner.push(this.escapeStr(ignorePunctuation.join(''))); 444 | } 445 | if (this.opt.ignoreJoiners) { 446 | joiner.push('\\u00ad\\u200b\\u200c\\u200d'); 447 | } 448 | return joiner.length ? 449 | str.split(/\u0000+/).join(`[${joiner.join('')}]*`) : 450 | str; 451 | } 452 | createDiacriticsRegExp(str) { 453 | const sens = this.opt.caseSensitive ? '' : 'i', 454 | dct = this.opt.caseSensitive ? [ 455 | 'aàáảãạăằắẳẵặâầấẩẫậäåāą', 'AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ', 456 | 'cçćč', 'CÇĆČ', 'dđď', 'DĐĎ', 457 | 'eèéẻẽẹêềếểễệëěēę', 'EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ', 458 | 'iìíỉĩịîïī', 'IÌÍỈĨỊÎÏĪ', 'lł', 'LŁ', 'nñňń', 459 | 'NÑŇŃ', 'oòóỏõọôồốổỗộơởỡớờợöøō', 'OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ', 460 | 'rř', 'RŘ', 'sšśșş', 'SŠŚȘŞ', 461 | 'tťțţ', 'TŤȚŢ', 'uùúủũụưừứửữựûüůū', 'UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ', 462 | 'yýỳỷỹỵÿ', 'YÝỲỶỸỴŸ', 'zžżź', 'ZŽŻŹ' 463 | ] : [ 464 | 'aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ', 'cçćčCÇĆČ', 465 | 'dđďDĐĎ', 'eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ', 466 | 'iìíỉĩịîïīIÌÍỈĨỊÎÏĪ', 'lłLŁ', 'nñňńNÑŇŃ', 467 | 'oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ', 'rřRŘ', 468 | 'sšśșşSŠŚȘŞ', 'tťțţTŤȚŢ', 469 | 'uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ', 'yýỳỷỹỵÿYÝỲỶỸỴŸ', 'zžżźZŽŻŹ' 470 | ]; 471 | let handled = []; 472 | str.split('').forEach(ch => { 473 | dct.every(dct => { 474 | if (dct.indexOf(ch) !== -1) { 475 | if (handled.indexOf(dct) > -1) { 476 | return false; 477 | } 478 | str = str.replace( 479 | new RegExp(`[${dct}]`, `gm${sens}`), `[${dct}]` 480 | ); 481 | handled.push(dct); 482 | } 483 | return true; 484 | }); 485 | }); 486 | return str; 487 | } 488 | createMergedBlanksRegExp(str) { 489 | return str.replace(/[\s]+/gmi, '[\\s]+'); 490 | } 491 | createAccuracyRegExp(str) { 492 | const chars = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~¡¿'; 493 | let acc = this.opt.accuracy, 494 | val = typeof acc === 'string' ? acc : acc.value, 495 | ls = typeof acc === 'string' ? [] : acc.limiters, 496 | lsJoin = ''; 497 | ls.forEach(limiter => { 498 | lsJoin += `|${this.escapeStr(limiter)}`; 499 | }); 500 | switch (val) { 501 | case 'partially': 502 | default: 503 | return `()(${str})`; 504 | case 'complementary': 505 | lsJoin = '\\s' + (lsJoin ? lsJoin : this.escapeStr(chars)); 506 | return `()([^${lsJoin}]*${str}[^${lsJoin}]*)`; 507 | case 'exactly': 508 | return `(^|\\s${lsJoin})(${str})(?=$|\\s${lsJoin})`; 509 | } 510 | } 511 | getSeparatedKeywords(sv) { 512 | let stack = []; 513 | sv.forEach(kw => { 514 | if (!this.opt.separateWordSearch) { 515 | if (kw.trim() && stack.indexOf(kw) === -1) { 516 | stack.push(kw); 517 | } 518 | } else { 519 | kw.split(' ').forEach(kwSplitted => { 520 | if (kwSplitted.trim() && stack.indexOf(kwSplitted) === -1) { 521 | stack.push(kwSplitted); 522 | } 523 | }); 524 | } 525 | }); 526 | return { 527 | 'keywords': stack.sort((a, b) => { 528 | return b.length - a.length; 529 | }), 530 | 'length': stack.length 531 | }; 532 | } 533 | isNumeric(value) { 534 | return Number(parseFloat(value)) == value; 535 | } 536 | checkRanges(array) { 537 | if ( 538 | !Array.isArray(array) || 539 | Object.prototype.toString.call( array[0] ) !== '[object Object]' 540 | ) { 541 | this.log('markRanges() will only accept an array of objects'); 542 | this.opt.noMatch(array); 543 | return []; 544 | } 545 | const stack = []; 546 | let last = 0; 547 | array 548 | .sort((a, b) => { 549 | return a.start - b.start; 550 | }) 551 | .forEach(item => { 552 | let {start, end, valid} = this.callNoMatchOnInvalidRanges(item, last); 553 | if (valid) { 554 | item.start = start; 555 | item.length = end - start; 556 | stack.push(item); 557 | last = end; 558 | } 559 | }); 560 | return stack; 561 | } 562 | callNoMatchOnInvalidRanges(range, last) { 563 | let start, end, 564 | valid = false; 565 | if (range && typeof range.start !== 'undefined') { 566 | start = parseInt(range.start, 10); 567 | end = start + parseInt(range.length, 10); 568 | if ( 569 | this.isNumeric(range.start) && 570 | this.isNumeric(range.length) && 571 | end - last > 0 && 572 | end - start > 0 573 | ) { 574 | valid = true; 575 | } else { 576 | this.log( 577 | 'Ignoring invalid or overlapping range: ' + 578 | `${JSON.stringify(range)}` 579 | ); 580 | this.opt.noMatch(range); 581 | } 582 | } else { 583 | this.log(`Ignoring invalid range: ${JSON.stringify(range)}`); 584 | this.opt.noMatch(range); 585 | } 586 | return { 587 | start: start, 588 | end: end, 589 | valid: valid 590 | }; 591 | } 592 | checkWhitespaceRanges(range, originalLength, string) { 593 | let end, 594 | valid = true, 595 | max = string.length, 596 | offset = originalLength - max, 597 | start = parseInt(range.start, 10) - offset; 598 | start = start > max ? max : start; 599 | end = start + parseInt(range.length, 10); 600 | if (end > max) { 601 | end = max; 602 | this.log(`End range automatically set to the max value of ${max}`); 603 | } 604 | if (start < 0 || end - start < 0 || start > max || end > max) { 605 | valid = false; 606 | this.log(`Invalid range: ${JSON.stringify(range)}`); 607 | this.opt.noMatch(range); 608 | } else if (string.substring(start, end).replace(/\s+/g, '') === '') { 609 | valid = false; 610 | this.log('Skipping whitespace only range: ' +JSON.stringify(range)); 611 | this.opt.noMatch(range); 612 | } 613 | return { 614 | start: start, 615 | end: end, 616 | valid: valid 617 | }; 618 | } 619 | getTextNodes(cb) { 620 | let val = '', 621 | nodes = []; 622 | this.iterator.forEachNode(NodeFilter.SHOW_TEXT, node => { 623 | nodes.push({ 624 | start: val.length, 625 | end: (val += node.textContent).length, 626 | node 627 | }); 628 | }, node => { 629 | if (this.matchesExclude(node.parentNode)) { 630 | return NodeFilter.FILTER_REJECT; 631 | } else { 632 | return NodeFilter.FILTER_ACCEPT; 633 | } 634 | }, () => { 635 | cb({ 636 | value: val, 637 | nodes: nodes 638 | }); 639 | }); 640 | } 641 | matchesExclude(el) { 642 | return DOMIterator.matches(el, this.opt.exclude.concat([ 643 | 'script', 'style', 'title', 'head', 'html' 644 | ])); 645 | } 646 | wrapRangeInTextNode(node, start, end) { 647 | const hEl = !this.opt.element ? 'mark' : this.opt.element, 648 | startNode = node.splitText(start), 649 | ret = startNode.splitText(end - start); 650 | let repl = document.createElement(hEl); 651 | repl.setAttribute('data-markjs', 'true'); 652 | if (this.opt.className) { 653 | repl.setAttribute('class', this.opt.className); 654 | } 655 | repl.textContent = startNode.textContent; 656 | startNode.parentNode.replaceChild(repl, startNode); 657 | return ret; 658 | } 659 | wrapRangeInMappedTextNode(dict, start, end, filterCb, eachCb) { 660 | dict.nodes.every((n, i) => { 661 | const sibl = dict.nodes[i + 1]; 662 | if (typeof sibl === 'undefined' || sibl.start > start) { 663 | if (!filterCb(n.node)) { 664 | return false; 665 | } 666 | const s = start - n.start, 667 | e = (end > n.end ? n.end : end) - n.start, 668 | startStr = dict.value.substr(0, n.start), 669 | endStr = dict.value.substr(e + n.start); 670 | n.node = this.wrapRangeInTextNode(n.node, s, e); 671 | dict.value = startStr + endStr; 672 | dict.nodes.forEach((k, j) => { 673 | if (j >= i) { 674 | if (dict.nodes[j].start > 0 && j !== i) { 675 | dict.nodes[j].start -= e; 676 | } 677 | dict.nodes[j].end -= e; 678 | } 679 | }); 680 | end -= e; 681 | eachCb(n.node.previousSibling, n.start); 682 | if (end > n.end) { 683 | start = n.end; 684 | } else { 685 | return false; 686 | } 687 | } 688 | return true; 689 | }); 690 | } 691 | wrapMatches(regex, ignoreGroups, filterCb, eachCb, endCb) { 692 | const matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1; 693 | this.getTextNodes(dict => { 694 | dict.nodes.forEach(node => { 695 | node = node.node; 696 | let match; 697 | while ( 698 | (match = regex.exec(node.textContent)) !== null && 699 | match[matchIdx] !== '' 700 | ) { 701 | if (!filterCb(match[matchIdx], node)) { 702 | continue; 703 | } 704 | let pos = match.index; 705 | if (matchIdx !== 0) { 706 | for (let i = 1; i < matchIdx; i++) { 707 | pos += match[i].length; 708 | } 709 | } 710 | node = this.wrapRangeInTextNode( 711 | node, 712 | pos, 713 | pos + match[matchIdx].length 714 | ); 715 | eachCb(node.previousSibling); 716 | regex.lastIndex = 0; 717 | } 718 | }); 719 | endCb(); 720 | }); 721 | } 722 | wrapMatchesAcrossElements(regex, ignoreGroups, filterCb, eachCb, endCb) { 723 | const matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1; 724 | this.getTextNodes(dict => { 725 | let match; 726 | while ( 727 | (match = regex.exec(dict.value)) !== null && 728 | match[matchIdx] !== '' 729 | ) { 730 | let start = match.index; 731 | if (matchIdx !== 0) { 732 | for (let i = 1; i < matchIdx; i++) { 733 | start += match[i].length; 734 | } 735 | } 736 | const end = start + match[matchIdx].length; 737 | this.wrapRangeInMappedTextNode(dict, start, end, node => { 738 | return filterCb(match[matchIdx], node); 739 | }, (node, lastIndex) => { 740 | regex.lastIndex = lastIndex; 741 | eachCb(node); 742 | }); 743 | } 744 | endCb(); 745 | }); 746 | } 747 | wrapRangeFromIndex(ranges, filterCb, eachCb, endCb) { 748 | this.getTextNodes(dict => { 749 | const originalLength = dict.value.length; 750 | ranges.forEach((range, counter) => { 751 | let {start, end, valid} = this.checkWhitespaceRanges( 752 | range, 753 | originalLength, 754 | dict.value 755 | ); 756 | if (valid) { 757 | this.wrapRangeInMappedTextNode(dict, start, end, node => { 758 | return filterCb( 759 | node, 760 | range, 761 | dict.value.substring(start, end), 762 | counter 763 | ); 764 | }, node => { 765 | eachCb(node, range); 766 | }); 767 | } 768 | }); 769 | endCb(); 770 | }); 771 | } 772 | unwrapMatches(node) { 773 | const parent = node.parentNode; 774 | let docFrag = document.createDocumentFragment(); 775 | while (node.firstChild) { 776 | docFrag.appendChild(node.removeChild(node.firstChild)); 777 | } 778 | parent.replaceChild(docFrag, node); 779 | if (!this.ie) { 780 | parent.normalize(); 781 | } else { 782 | this.normalizeTextNode(parent); 783 | } 784 | } 785 | normalizeTextNode(node) { 786 | if (!node) { 787 | return; 788 | } 789 | if (node.nodeType === 3) { 790 | while (node.nextSibling && node.nextSibling.nodeType === 3) { 791 | node.nodeValue += node.nextSibling.nodeValue; 792 | node.parentNode.removeChild(node.nextSibling); 793 | } 794 | } else { 795 | this.normalizeTextNode(node.firstChild); 796 | } 797 | this.normalizeTextNode(node.nextSibling); 798 | } 799 | markRegExp(regexp, opt) { 800 | this.opt = opt; 801 | this.log(`Searching with expression "${regexp}"`); 802 | let totalMatches = 0, 803 | fn = 'wrapMatches'; 804 | const eachCb = element => { 805 | totalMatches++; 806 | this.opt.each(element); 807 | }; 808 | if (this.opt.acrossElements) { 809 | fn = 'wrapMatchesAcrossElements'; 810 | } 811 | this[fn](regexp, this.opt.ignoreGroups, (match, node) => { 812 | return this.opt.filter(node, match, totalMatches); 813 | }, eachCb, () => { 814 | if (totalMatches === 0) { 815 | this.opt.noMatch(regexp); 816 | } 817 | this.opt.done(totalMatches); 818 | }); 819 | } 820 | mark(sv, opt) { 821 | this.opt = opt; 822 | let totalMatches = 0, 823 | fn = 'wrapMatches'; 824 | const { 825 | keywords: kwArr, 826 | length: kwArrLen 827 | } = this.getSeparatedKeywords(typeof sv === 'string' ? [sv] : sv), 828 | sens = this.opt.caseSensitive ? '' : 'i', 829 | handler = kw => { 830 | let regex = new RegExp(this.createRegExp(kw), `gm${sens}`), 831 | matches = 0; 832 | this.log(`Searching with expression "${regex}"`); 833 | this[fn](regex, 1, (term, node) => { 834 | return this.opt.filter(node, kw, totalMatches, matches); 835 | }, element => { 836 | matches++; 837 | totalMatches++; 838 | this.opt.each(element); 839 | }, () => { 840 | if (matches === 0) { 841 | this.opt.noMatch(kw); 842 | } 843 | if (kwArr[kwArrLen - 1] === kw) { 844 | this.opt.done(totalMatches); 845 | } else { 846 | handler(kwArr[kwArr.indexOf(kw) + 1]); 847 | } 848 | }); 849 | }; 850 | if (this.opt.acrossElements) { 851 | fn = 'wrapMatchesAcrossElements'; 852 | } 853 | if (kwArrLen === 0) { 854 | this.opt.done(totalMatches); 855 | } else { 856 | handler(kwArr[0]); 857 | } 858 | } 859 | markRanges(rawRanges, opt) { 860 | this.opt = opt; 861 | let totalMatches = 0, 862 | ranges = this.checkRanges(rawRanges); 863 | if (ranges && ranges.length) { 864 | this.log( 865 | 'Starting to mark with the following ranges: ' + 866 | JSON.stringify(ranges) 867 | ); 868 | this.wrapRangeFromIndex( 869 | ranges, (node, range, match, counter) => { 870 | return this.opt.filter(node, range, match, counter); 871 | }, (element, range) => { 872 | totalMatches++; 873 | this.opt.each(element, range); 874 | }, () => { 875 | this.opt.done(totalMatches); 876 | } 877 | ); 878 | } else { 879 | this.opt.done(totalMatches); 880 | } 881 | } 882 | unmark(opt) { 883 | this.opt = opt; 884 | let sel = this.opt.element ? this.opt.element : '*'; 885 | sel += '[data-markjs]'; 886 | if (this.opt.className) { 887 | sel += `.${this.opt.className}`; 888 | } 889 | this.log(`Removal selector "${sel}"`); 890 | this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT, node => { 891 | this.unwrapMatches(node); 892 | }, node => { 893 | const matchesSel = DOMIterator.matches(node, sel), 894 | matchesExclude = this.matchesExclude(node); 895 | if (!matchesSel || matchesExclude) { 896 | return NodeFilter.FILTER_REJECT; 897 | } else { 898 | return NodeFilter.FILTER_ACCEPT; 899 | } 900 | }, this.opt.done); 901 | } 902 | } 903 | 904 | function Mark(ctx) { 905 | const instance = new Mark$1(ctx); 906 | this.mark = (sv, opt) => { 907 | instance.mark(sv, opt); 908 | return this; 909 | }; 910 | this.markRegExp = (sv, opt) => { 911 | instance.markRegExp(sv, opt); 912 | return this; 913 | }; 914 | this.markRanges = (sv, opt) => { 915 | instance.markRanges(sv, opt); 916 | return this; 917 | }; 918 | this.unmark = (opt) => { 919 | instance.unmark(opt); 920 | return this; 921 | }; 922 | return this; 923 | } 924 | 925 | return Mark; 926 | 927 | }))); 928 | -------------------------------------------------------------------------------- /src/resource/lib/mark.js-8.11.1/mark.es6.min.js: -------------------------------------------------------------------------------- 1 | /*!*************************************************** 2 | * mark.js v8.11.1 3 | * https://markjs.io/ 4 | * Copyright (c) 2014–2018, Julian Kühnel 5 | * Released under the MIT license https://git.io/vwTVl 6 | *****************************************************/ 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Mark=t()}(this,function(){"use strict";class e{constructor(e,t=!0,s=[],r=5e3){this.ctx=e,this.iframes=t,this.exclude=s,this.iframesTimeout=r}static matches(e,t){const s="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){let t=!1;return s.every(s=>!r.call(e,s)||(t=!0,!1)),t}return!1}getContexts(){let e,t=[];return(e=void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(e=>{const s=t.filter(t=>t.contains(e)).length>0;-1!==t.indexOf(e)||s||t.push(e)}),t}getIframeContents(e,t,s=(()=>{})){let r;try{const t=e.contentWindow;if(r=t.document,!t||!r)throw new Error("iframe inaccessible")}catch(e){s()}r&&t(r)}isIframeBlank(e){const t="about:blank",s=e.getAttribute("src").trim(),r=e.contentWindow.location.href;return r===t&&s!==t&&s}observeIframeLoad(e,t,s){let r=!1,i=null;const o=()=>{if(!r){r=!0,clearTimeout(i);try{this.isIframeBlank(e)||(e.removeEventListener("load",o),this.getIframeContents(e,t,s))}catch(e){s()}}};e.addEventListener("load",o),i=setTimeout(o,this.iframesTimeout)}onIframeReady(e,t,s){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,s):this.getIframeContents(e,t,s):this.observeIframeLoad(e,t,s)}catch(e){s()}}waitForIframes(e,t){let s=0;this.forEachIframe(e,()=>!0,e=>{s++,this.waitForIframes(e.querySelector("html"),()=>{--s||t()})},e=>{e||t()})}forEachIframe(t,s,r,i=(()=>{})){let o=t.querySelectorAll("iframe"),n=o.length,a=0;o=Array.prototype.slice.call(o);const c=()=>{--n<=0&&i(a)};n||c(),o.forEach(t=>{e.matches(t,this.exclude)?c():this.onIframeReady(t,e=>{s(t)&&(a++,r(e)),c()},c)})}createIterator(e,t,s){return document.createNodeIterator(e,t,s,!1)}createInstanceOnIframe(t){return new e(t.querySelector("html"),this.iframes)}compareNodeIframe(e,t,s){const r=e.compareDocumentPosition(s),i=Node.DOCUMENT_POSITION_PRECEDING;if(r&i){if(null===t)return!0;if(t.compareDocumentPosition(s)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}getIteratorNode(e){const t=e.previousNode();let s;return{prevNode:t,node:s=null===t?e.nextNode():e.nextNode()&&e.nextNode()}}checkIframeFilter(e,t,s,r){let i=!1,o=!1;return r.forEach((e,t)=>{e.val===s&&(i=t,o=e.handled)}),this.compareNodeIframe(e,t,s)?(!1!==i||o?!1===i||o||(r[i].handled=!0):r.push({val:s,handled:!0}),!0):(!1===i&&r.push({val:s,handled:!1}),!1)}handleOpenIframes(e,t,s,r){e.forEach(e=>{e.handled||this.getIframeContents(e.val,e=>{this.createInstanceOnIframe(e).forEachNode(t,s,r)})})}iterateThroughNodes(e,t,s,r,i){const o=this.createIterator(t,e,r);let n,a,c=[],h=[],l=()=>(({prevNode:a,node:n}=this.getIteratorNode(o)),n);for(;l();)this.iframes&&this.forEachIframe(t,e=>this.checkIframeFilter(n,a,e,c),t=>{this.createInstanceOnIframe(t).forEachNode(e,e=>h.push(e),r)}),h.push(n);h.forEach(e=>{s(e)}),this.iframes&&this.handleOpenIframes(c,e,s,r),i()}forEachNode(e,t,s,r=(()=>{})){const i=this.getContexts();let o=i.length;o||r(),i.forEach(i=>{const n=()=>{this.iterateThroughNodes(e,i,t,s,()=>{--o<=0&&r()})};this.iframes?this.waitForIframes(i,n):n()})}}class t{constructor(e){this.ctx=e,this.ie=!1;const t=window.navigator.userAgent;(t.indexOf("MSIE")>-1||t.indexOf("Trident")>-1)&&(this.ie=!0)}set opt(e){this._opt=Object.assign({},{element:"",className:"",exclude:[],iframes:!1,iframesTimeout:5e3,separateWordSearch:!0,diacritics:!0,synonyms:{},accuracy:"partially",acrossElements:!1,caseSensitive:!1,ignoreJoiners:!1,ignoreGroups:0,ignorePunctuation:[],wildcards:"disabled",each:()=>{},noMatch:()=>{},filter:()=>!0,done:()=>{},debug:!1,log:window.console},e)}get opt(){return this._opt}get iterator(){return new e(this.ctx,this.opt.iframes,this.opt.exclude,this.opt.iframesTimeout)}log(e,t="debug"){const s=this.opt.log;this.opt.debug&&"object"==typeof s&&"function"==typeof s[t]&&s[t](`mark.js: ${e}`)}escapeStr(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}createRegExp(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e)}createSynonymsRegExp(e){const t=this.opt.synonyms,s=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(let i in t)if(t.hasOwnProperty(i)){const o=t[i],n="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o);""!==n&&""!==a&&(e=e.replace(new RegExp(`(${this.escapeStr(n)}|${this.escapeStr(a)})`,`gm${s}`),r+`(${this.processSynomyms(n)}|`+`${this.processSynomyms(a)})`+r))}return e}processSynomyms(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}setupWildcardsRegExp(e){return(e=e.replace(/(?:\\)*\?/g,e=>"\\"===e.charAt(0)?"?":"")).replace(/(?:\\)*\*/g,e=>"\\"===e.charAt(0)?"*":"")}createWildcardsRegExp(e){let t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}setupIgnoreJoinersRegExp(e){return e.replace(/[^(|)\\]/g,(e,t,s)=>{let r=s.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}createJoinersRegExp(e){let t=[];const s=this.opt.ignorePunctuation;return Array.isArray(s)&&s.length&&t.push(this.escapeStr(s.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join(`[${t.join("")}]*`):e}createDiacriticsRegExp(e){const t=this.opt.caseSensitive?"":"i",s=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"];let r=[];return e.split("").forEach(i=>{s.every(s=>{if(-1!==s.indexOf(i)){if(r.indexOf(s)>-1)return!1;e=e.replace(new RegExp(`[${s}]`,`gm${t}`),`[${s}]`),r.push(s)}return!0})}),e}createMergedBlanksRegExp(e){return e.replace(/[\s]+/gim,"[\\s]+")}createAccuracyRegExp(e){const t="!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿";let s=this.opt.accuracy,r="string"==typeof s?s:s.value,i="string"==typeof s?[]:s.limiters,o="";switch(i.forEach(e=>{o+=`|${this.escapeStr(e)}`}),r){case"partially":default:return`()(${e})`;case"complementary":return`()([^${o="\\s"+(o||this.escapeStr(t))}]*${e}[^${o}]*)`;case"exactly":return`(^|\\s${o})(${e})(?=$|\\s${o})`}}getSeparatedKeywords(e){let t=[];return e.forEach(e=>{this.opt.separateWordSearch?e.split(" ").forEach(e=>{e.trim()&&-1===t.indexOf(e)&&t.push(e)}):e.trim()&&-1===t.indexOf(e)&&t.push(e)}),{keywords:t.sort((e,t)=>t.length-e.length),length:t.length}}isNumeric(e){return Number(parseFloat(e))==e}checkRanges(e){if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];const t=[];let s=0;return e.sort((e,t)=>e.start-t.start).forEach(e=>{let{start:r,end:i,valid:o}=this.callNoMatchOnInvalidRanges(e,s);o&&(e.start=r,e.length=i-r,t.push(e),s=i)}),t}callNoMatchOnInvalidRanges(e,t){let s,r,i=!1;return e&&void 0!==e.start?(r=(s=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-s>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+`${JSON.stringify(e)}`),this.opt.noMatch(e))):(this.log(`Ignoring invalid range: ${JSON.stringify(e)}`),this.opt.noMatch(e)),{start:s,end:r,valid:i}}checkWhitespaceRanges(e,t,s){let r,i=!0,o=s.length,n=t-o,a=parseInt(e.start,10)-n;return(r=(a=a>o?o:a)+parseInt(e.length,10))>o&&(r=o,this.log(`End range automatically set to the max value of ${o}`)),a<0||r-a<0||a>o||r>o?(i=!1,this.log(`Invalid range: ${JSON.stringify(e)}`),this.opt.noMatch(e)):""===s.substring(a,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:a,end:r,valid:i}}getTextNodes(e){let t="",s=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,e=>{s.push({start:t.length,end:(t+=e.textContent).length,node:e})},e=>this.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT,()=>{e({value:t,nodes:s})})}matchesExclude(t){return e.matches(t,this.opt.exclude.concat(["script","style","title","head","html"]))}wrapRangeInTextNode(e,t,s){const r=this.opt.element?this.opt.element:"mark",i=e.splitText(t),o=i.splitText(s-t);let n=document.createElement(r);return n.setAttribute("data-markjs","true"),this.opt.className&&n.setAttribute("class",this.opt.className),n.textContent=i.textContent,i.parentNode.replaceChild(n,i),o}wrapRangeInMappedTextNode(e,t,s,r,i){e.nodes.every((o,n)=>{const a=e.nodes[n+1];if(void 0===a||a.start>t){if(!r(o.node))return!1;const a=t-o.start,c=(s>o.end?o.end:s)-o.start,h=e.value.substr(0,o.start),l=e.value.substr(c+o.start);if(o.node=this.wrapRangeInTextNode(o.node,a,c),e.value=h+l,e.nodes.forEach((t,s)=>{s>=n&&(e.nodes[s].start>0&&s!==n&&(e.nodes[s].start-=c),e.nodes[s].end-=c)}),s-=c,i(o.node.previousSibling,o.start),!(s>o.end))return!1;t=o.end}return!0})}wrapMatches(e,t,s,r,i){const o=0===t?0:t+1;this.getTextNodes(t=>{t.nodes.forEach(t=>{let i;for(t=t.node;null!==(i=e.exec(t.textContent))&&""!==i[o];){if(!s(i[o],t))continue;let n=i.index;if(0!==o)for(let e=1;e{let n;for(;null!==(n=e.exec(t.value))&&""!==n[o];){let i=n.index;if(0!==o)for(let e=1;es(n[o],e),(t,s)=>{e.lastIndex=s,r(t)})}i()})}wrapRangeFromIndex(e,t,s,r){this.getTextNodes(i=>{const o=i.value.length;e.forEach((e,r)=>{let{start:n,end:a,valid:c}=this.checkWhitespaceRanges(e,o,i.value);c&&this.wrapRangeInMappedTextNode(i,n,a,s=>t(s,e,i.value.substring(n,a),r),t=>{s(t,e)})}),r()})}unwrapMatches(e){const t=e.parentNode;let s=document.createDocumentFragment();for(;e.firstChild;)s.appendChild(e.removeChild(e.firstChild));t.replaceChild(s,e),this.ie?this.normalizeTextNode(t):t.normalize()}normalizeTextNode(e){if(e){if(3===e.nodeType)for(;e.nextSibling&&3===e.nextSibling.nodeType;)e.nodeValue+=e.nextSibling.nodeValue,e.parentNode.removeChild(e.nextSibling);else this.normalizeTextNode(e.firstChild);this.normalizeTextNode(e.nextSibling)}}markRegExp(e,t){this.opt=t,this.log(`Searching with expression "${e}"`);let s=0,r="wrapMatches";const i=e=>{s++,this.opt.each(e)};this.opt.acrossElements&&(r="wrapMatchesAcrossElements"),this[r](e,this.opt.ignoreGroups,(e,t)=>this.opt.filter(t,e,s),i,()=>{0===s&&this.opt.noMatch(e),this.opt.done(s)})}mark(e,t){this.opt=t;let s=0,r="wrapMatches";const{keywords:i,length:o}=this.getSeparatedKeywords("string"==typeof e?[e]:e),n=this.opt.caseSensitive?"":"i",a=e=>{let t=new RegExp(this.createRegExp(e),`gm${n}`),c=0;this.log(`Searching with expression "${t}"`),this[r](t,1,(t,r)=>this.opt.filter(r,e,s,c),e=>{c++,s++,this.opt.each(e)},()=>{0===c&&this.opt.noMatch(e),i[o-1]===e?this.opt.done(s):a(i[i.indexOf(e)+1])})};this.opt.acrossElements&&(r="wrapMatchesAcrossElements"),0===o?this.opt.done(s):a(i[0])}markRanges(e,t){this.opt=t;let s=0,r=this.checkRanges(e);r&&r.length?(this.log("Starting to mark with the following ranges: "+JSON.stringify(r)),this.wrapRangeFromIndex(r,(e,t,s,r)=>this.opt.filter(e,t,s,r),(e,t)=>{s++,this.opt.each(e,t)},()=>{this.opt.done(s)})):this.opt.done(s)}unmark(t){this.opt=t;let s=this.opt.element?this.opt.element:"*";s+="[data-markjs]",this.opt.className&&(s+=`.${this.opt.className}`),this.log(`Removal selector "${s}"`),this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT,e=>{this.unwrapMatches(e)},t=>{const r=e.matches(t,s),i=this.matchesExclude(t);return!r||i?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},this.opt.done)}}return function(e){const s=new t(e);return this.mark=((e,t)=>(s.mark(e,t),this)),this.markRegExp=((e,t)=>(s.markRegExp(e,t),this)),this.markRanges=((e,t)=>(s.markRanges(e,t),this)),this.unmark=(e=>(s.unmark(e),this)),this}}); 8 | -------------------------------------------------------------------------------- /src/resource/lib/mark.js-8.11.1/mark.min.js: -------------------------------------------------------------------------------- 1 | /*!*************************************************** 2 | * mark.js v8.11.1 3 | * https://markjs.io/ 4 | * Copyright (c) 2014–2018, Julian Kühnel 5 | * Released under the MIT license https://git.io/vwTVl 6 | *****************************************************/ 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Mark=t()}(this,function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},n=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1])||arguments[1],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;t(this,e),this.ctx=n,this.iframes=r,this.exclude=i,this.iframesTimeout=o}return n(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(function(t){var n=e.filter(function(e){return e.contains(t)}).length>0;-1!==e.indexOf(t)||n||e.push(t)}),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var i=e.contentWindow;if(r=i.document,!i||!r)throw new Error("iframe inaccessible")}catch(e){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t=e.getAttribute("src").trim();return"about:blank"===e.contentWindow.location.href&&"about:blank"!==t&&t}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,i=!1,o=null,a=function a(){if(!i){i=!0,clearTimeout(o);try{r.isIframeBlank(e)||(e.removeEventListener("load",a),r.getIframeContents(e,t,n))}catch(e){n()}}};e.addEventListener("load",a),o=setTimeout(a,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(e){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,function(){return!0},function(e){r++,n.waitForIframes(e.querySelector("html"),function(){--r||t()})},function(e){e||t()})}},{key:"forEachIframe",value:function(t,n,r){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=t.querySelectorAll("iframe"),s=a.length,c=0;a=Array.prototype.slice.call(a);var u=function(){--s<=0&&o(c)};s||u(),a.forEach(function(t){e.matches(t,i.exclude)?u():i.onIframeReady(t,function(e){n(t)&&(c++,r(e)),u()},u)})}},{key:"createIterator",value:function(e,t,n){return document.createNodeIterator(e,t,n,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode();return{prevNode:t,node:null===t?e.nextNode():e.nextNode()&&e.nextNode()}}},{key:"checkIframeFilter",value:function(e,t,n,r){var i=!1,o=!1;return r.forEach(function(e,t){e.val===n&&(i=t,o=e.handled)}),this.compareNodeIframe(e,t,n)?(!1!==i||o?!1===i||o||(r[i].handled=!0):r.push({val:n,handled:!0}),!0):(!1===i&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var i=this;e.forEach(function(e){e.handled||i.getIframeContents(e.val,function(e){i.createInstanceOnIframe(e).forEachNode(t,n,r)})})}},{key:"iterateThroughNodes",value:function(e,t,n,r,i){for(var o,a=this,s=this.createIterator(t,e,r),c=[],u=[],l=void 0,h=void 0;void 0,o=a.getIteratorNode(s),h=o.prevNode,l=o.node;)this.iframes&&this.forEachIframe(t,function(e){return a.checkIframeFilter(l,h,e,c)},function(t){a.createInstanceOnIframe(t).forEachNode(e,function(e){return u.push(e)},r)}),u.push(l);u.forEach(function(e){n(e)}),this.iframes&&this.handleOpenIframes(c,e,n,r),i()}},{key:"forEachNode",value:function(e,t,n){var r=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},o=this.getContexts(),a=o.length;a||i(),o.forEach(function(o){var s=function(){r.iterateThroughNodes(e,o,t,n,function(){--a<=0&&i()})};r.iframes?r.waitForIframes(o,s):s()})}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var i=!1;return n.every(function(t){return!r.call(e,t)||(i=!0,!1)}),i}return!1}}]),e}(),o=function(){function o(e){t(this,o),this.ctx=e,this.ie=!1;var n=window.navigator.userAgent;(n.indexOf("MSIE")>-1||n.indexOf("Trident")>-1)&&(this.ie=!0)}return n(o,[{key:"log",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",r=this.opt.log;this.opt.debug&&"object"===(void 0===r?"undefined":e(r))&&"function"==typeof r[n]&&r[n]("mark.js: "+t)}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createRegExp",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e)}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o);""!==a&&""!==s&&(e=e.replace(new RegExp("("+this.escapeStr(a)+"|"+this.escapeStr(s)+")","gm"+n),r+"("+this.processSynomyms(a)+"|"+this.processSynomyms(s)+")"+r))}return e}},{key:"processSynomyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,function(e){return"\\"===e.charAt(0)?"?":""})).replace(/(?:\\)*\*/g,function(e){return"\\"===e.charAt(0)?"*":""})}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"],r=[];return e.split("").forEach(function(i){n.every(function(n){if(-1!==n.indexOf(i)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0})}),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n=this.opt.accuracy,r="string"==typeof n?n:n.value,i="";switch(("string"==typeof n?[]:n.limiters).forEach(function(e){i+="|"+t.escapeStr(e)}),r){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿")))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach(function(e){t.opt.separateWordSearch?e.split(" ").forEach(function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)}):e.trim()&&-1===n.indexOf(e)&&n.push(e)}),{keywords:n.sort(function(e,t){return t.length-e.length}),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort(function(e,t){return e.start-t.start}).forEach(function(e){var i=t.callNoMatchOnInvalidRanges(e,r),o=i.start,a=i.end;i.valid&&(e.start=o,e.length=a-o,n.push(e),r=a)}),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,i=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:i}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,i=!0,o=n.length,a=t-o,s=parseInt(e.start,10)-a;return(r=(s=s>o?o:s)+parseInt(e.length,10))>o&&(r=o,this.log("End range automatically set to the max value of "+o)),s<0||r-s<0||s>o||r>o?(i=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:i}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})},function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},function(){e({value:n,nodes:r})})}},{key:"matchesExclude",value:function(e){return i.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,t,n){var r=this.opt.element?this.opt.element:"mark",i=e.splitText(t),o=i.splitText(n-t),a=document.createElement(r);return a.setAttribute("data-markjs","true"),this.opt.className&&a.setAttribute("class",this.opt.className),a.textContent=i.textContent,i.parentNode.replaceChild(a,i),o}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,i){var o=this;e.nodes.every(function(a,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(a.node))return!1;var u=t-a.start,l=(n>a.end?a.end:n)-a.start,h=e.value.substr(0,a.start),f=e.value.substr(l+a.start);if(a.node=o.wrapRangeInTextNode(a.node,u,l),e.value=h+f,e.nodes.forEach(function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=l),e.nodes[n].end-=l)}),n-=l,i(a.node.previousSibling,a.start),!(n>a.end))return!1;t=a.end}return!0})}},{key:"wrapMatches",value:function(e,t,n,r,i){var o=this,a=0===t?0:t+1;this.getTextNodes(function(t){t.nodes.forEach(function(t){t=t.node;for(var i=void 0;null!==(i=e.exec(t.textContent))&&""!==i[a];)if(n(i[a],t)){var s=i.index;if(0!==a)for(var c=1;c img { 146 | height: auto; 147 | margin: 15px auto; 148 | max-width: 90% !important; 149 | width: auto; 150 | } 151 | 152 | .viewer-footer { 153 | bottom: 0; 154 | left: 0; 155 | overflow: hidden; 156 | position: absolute; 157 | right: 0; 158 | text-align: center; 159 | } 160 | 161 | .viewer-navbar { 162 | background-color: rgba(0, 0, 0, 50%); 163 | overflow: hidden; 164 | } 165 | 166 | .viewer-list { 167 | box-sizing: content-box; 168 | height: 50px; 169 | margin: 0; 170 | overflow: hidden; 171 | padding: 1px 0 172 | } 173 | 174 | .viewer-list > li { 175 | color: transparent; 176 | cursor: pointer; 177 | float: left; 178 | font-size: 0; 179 | height: 50px; 180 | line-height: 0; 181 | opacity: 0.5; 182 | overflow: hidden; 183 | transition: opacity 0.15s; 184 | width: 30px 185 | } 186 | 187 | .viewer-list > li:focus, 188 | .viewer-list > li:hover { 189 | opacity: 0.75; 190 | } 191 | 192 | .viewer-list > li:focus { 193 | outline: 0; 194 | } 195 | 196 | .viewer-list > li + li { 197 | margin-left: 1px; 198 | } 199 | 200 | .viewer-list > .viewer-loading { 201 | position: relative 202 | } 203 | 204 | .viewer-list > .viewer-loading::after { 205 | border-width: 2px; 206 | height: 20px; 207 | margin-left: -10px; 208 | margin-top: -10px; 209 | width: 20px; 210 | } 211 | 212 | .viewer-list > .viewer-active, 213 | .viewer-list > .viewer-active:focus, 214 | .viewer-list > .viewer-active:hover { 215 | opacity: 1; 216 | } 217 | 218 | .viewer-player { 219 | background-color: #000; 220 | bottom: 0; 221 | cursor: none; 222 | display: none; 223 | left: 0; 224 | position: absolute; 225 | right: 0; 226 | top: 0; 227 | z-index: 1 228 | } 229 | 230 | .viewer-player > img { 231 | left: 0; 232 | position: absolute; 233 | top: 0; 234 | } 235 | 236 | .viewer-toolbar > ul { 237 | display: inline-block; 238 | margin: 0 auto 5px; 239 | overflow: hidden; 240 | padding: 6px 3px 241 | } 242 | 243 | .viewer-toolbar > ul > li { 244 | background-color: rgba(0, 0, 0, 50%); 245 | border-radius: 50%; 246 | cursor: pointer; 247 | float: left; 248 | height: 24px; 249 | overflow: hidden; 250 | transition: background-color 0.15s; 251 | width: 24px 252 | } 253 | 254 | .viewer-toolbar > ul > li:focus, 255 | .viewer-toolbar > ul > li:hover { 256 | background-color: rgba(0, 0, 0, 80%); 257 | } 258 | 259 | .viewer-toolbar > ul > li:focus { 260 | box-shadow: 0 0 3px #fff; 261 | outline: 0; 262 | position: relative; 263 | z-index: 1; 264 | } 265 | 266 | .viewer-toolbar > ul > li::before { 267 | margin: 2px; 268 | } 269 | 270 | .viewer-toolbar > ul > li + li { 271 | margin-left: 1px; 272 | } 273 | 274 | .viewer-toolbar > ul > .viewer-small { 275 | height: 18px; 276 | margin-bottom: 3px; 277 | margin-top: 3px; 278 | width: 18px 279 | } 280 | 281 | .viewer-toolbar > ul > .viewer-small::before { 282 | margin: -1px; 283 | } 284 | 285 | .viewer-toolbar > ul > .viewer-large { 286 | height: 30px; 287 | margin-bottom: -3px; 288 | margin-top: -3px; 289 | width: 30px 290 | } 291 | 292 | .viewer-toolbar > ul > .viewer-large::before { 293 | margin: 5px; 294 | } 295 | 296 | .viewer-tooltip { 297 | background-color: rgba(0, 0, 0, 80%); 298 | border-radius: 10px; 299 | color: #fff; 300 | display: none; 301 | font-size: 12px; 302 | height: 20px; 303 | left: 50%; 304 | line-height: 20px; 305 | margin-left: -25px; 306 | margin-top: -10px; 307 | position: absolute; 308 | text-align: center; 309 | top: 50%; 310 | width: 50px; 311 | } 312 | 313 | .viewer-title { 314 | color: #ccc; 315 | display: inline-block; 316 | font-size: 12px; 317 | line-height: 1.2; 318 | margin: 0 5% 5px; 319 | max-width: 90%; 320 | opacity: 0.8; 321 | overflow: hidden; 322 | text-overflow: ellipsis; 323 | transition: opacity 0.15s; 324 | white-space: nowrap 325 | } 326 | 327 | .viewer-title:hover { 328 | opacity: 1; 329 | } 330 | 331 | .viewer-button { 332 | -webkit-app-region: no-drag; 333 | background-color: rgba(0, 0, 0, 50%); 334 | border-radius: 50%; 335 | cursor: pointer; 336 | height: 80px; 337 | overflow: hidden; 338 | position: absolute; 339 | right: -40px; 340 | top: -40px; 341 | transition: background-color 0.15s; 342 | width: 80px 343 | } 344 | 345 | .viewer-button:focus, 346 | .viewer-button:hover { 347 | background-color: rgba(0, 0, 0, 80%); 348 | } 349 | 350 | .viewer-button:focus { 351 | box-shadow: 0 0 3px #fff; 352 | outline: 0; 353 | } 354 | 355 | .viewer-button::before { 356 | bottom: 15px; 357 | left: 15px; 358 | position: absolute; 359 | } 360 | 361 | .viewer-fixed { 362 | position: fixed; 363 | } 364 | 365 | .viewer-open { 366 | overflow: hidden; 367 | } 368 | 369 | .viewer-show { 370 | display: block; 371 | } 372 | 373 | .viewer-hide { 374 | display: none; 375 | } 376 | 377 | .viewer-backdrop { 378 | background-color: rgba(0, 0, 0, 50%); 379 | } 380 | 381 | .viewer-invisible { 382 | visibility: hidden; 383 | } 384 | 385 | .viewer-move { 386 | cursor: move; 387 | cursor: -webkit-grab; 388 | cursor: grab; 389 | } 390 | 391 | .viewer-fade { 392 | opacity: 0; 393 | } 394 | 395 | .viewer-in { 396 | opacity: 1; 397 | } 398 | 399 | .viewer-transition { 400 | transition: all 0.3s; 401 | } 402 | 403 | @-webkit-keyframes viewer-spinner { 404 | 0% { 405 | transform: rotate(0deg); 406 | } 407 | 408 | 100% { 409 | transform: rotate(360deg); 410 | } 411 | } 412 | 413 | @keyframes viewer-spinner { 414 | 0% { 415 | transform: rotate(0deg); 416 | } 417 | 418 | 100% { 419 | transform: rotate(360deg); 420 | } 421 | } 422 | 423 | .viewer-loading::after { 424 | -webkit-animation: viewer-spinner 1s linear infinite; 425 | animation: viewer-spinner 1s linear infinite; 426 | border: 4px solid rgba(255, 255, 255, 10%); 427 | border-left-color: rgba(255, 255, 255, 50%); 428 | border-radius: 50%; 429 | content: ""; 430 | display: inline-block; 431 | height: 40px; 432 | left: 50%; 433 | margin-left: -20px; 434 | margin-top: -20px; 435 | position: absolute; 436 | top: 50%; 437 | width: 40px; 438 | z-index: 1; 439 | } 440 | 441 | @media (max-width: 767px) { 442 | .viewer-hide-xs-down { 443 | display: none; 444 | } 445 | } 446 | 447 | @media (max-width: 991px) { 448 | .viewer-hide-sm-down { 449 | display: none; 450 | } 451 | } 452 | 453 | @media (max-width: 1199px) { 454 | .viewer-hide-md-down { 455 | display: none; 456 | } 457 | } 458 | -------------------------------------------------------------------------------- /src/resource/lib/viewerjs-1.10.5/viewer.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Viewer.js v1.10.5 3 | * https://fengyuanchen.github.io/viewerjs 4 | * 5 | * Copyright 2015-present Chen Fengyuan 6 | * Released under the MIT license 7 | * 8 | * Date: 2022-04-05T08:21:00.150Z 9 | */.viewer-close:before,.viewer-flip-horizontal:before,.viewer-flip-vertical:before,.viewer-fullscreen-exit:before,.viewer-fullscreen:before,.viewer-next:before,.viewer-one-to-one:before,.viewer-play:before,.viewer-prev:before,.viewer-reset:before,.viewer-rotate-left:before,.viewer-rotate-right:before,.viewer-zoom-in:before,.viewer-zoom-out:before{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAAUCAYAAABWOyJDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAQPSURBVHic7Zs/iFxVFMa/0U2UaJGksUgnIVhYxVhpjDbZCBmLdAYECxsRFBTUamcXUiSNncgKQbSxsxH8gzAP3FU2jY0kKKJNiiiIghFlccnP4p3nPCdv3p9778vsLOcHB2bfveeb7955c3jvvNkBIMdxnD64a94GHMfZu3iBcRynN7zAOI7TG15gHCeeNUkr8zaxG2lbYDYsdgMbktBsP03jdQwljSXdtBhLOmtjowC9Mg9L+knSlcD8TNKpSA9lBpK2JF2VdDSR5n5J64m0qli399hNFMUlpshQii5jbXTbHGviB0nLNeNDSd9VO4A2UdB2fp+x0eCnaXxWXGA2X0au/3HgN9P4LFCjIANOJdrLr0zzZ+BEpNYDwKbpnQMeAw4m8HjQtM6Z9qa917zPQwFr3M5KgA6J5rTJCdFZJj9/lyvGhsDvwFNVuV2MhhjrK6b9bFiE+j1r87eBl4HDwCF7/U/k+ofAX5b/EXBv5JoLMuILzf3Ap6Z3EzgdqHMCuF7hcQf4HDgeoHnccncqdK/TvSDWffFXI/exICY/xZyqc6XLWF1UFZna4gJ7q8BsRvgd2/xXpo6P+D9dfT7PpECtA3cnWPM0GXGFZh/wgWltA+cDNC7X+AP4GzjZQe+k5dRxuYPeiuXU7e1qwLpDz7dFjXKRaSwuMLvAlG8zZlG+YmiK1HoFqT7wP2z+4Q45TfEGcMt01xLoNZEBTwRqD4BLpnMLeC1A41UmVxsXgXeBayV/Wx20rpTyrpnWRft7p6O/FdqzGrDukPNtkaMoMo3FBdBSQMOnYBCReyf05s126fU9ytfX98+mY54Kxnp7S9K3kj6U9KYdG0h6UdLbkh7poFXMfUnSOyVvL0h6VtIXHbS6nOP+s/Zm9mvyXW1uuC9ohZ72E9uDmXWLJOB1GxsH+DxPftsB8B6wlGDN02TAkxG6+4D3TWsbeC5CS8CDFce+AW500LhhOW2020TRjK3b21HEmgti9m0RonxbdMZeVzV+/4tF3cBpP7E9mKHNL5q8h5g0eYsCMQz0epq8gQrwMXAgcs0FGXGFRcB9wCemF9PkbYqM/Bas7fxLwNeJPdTdpo4itQti8lPMqTpXuozVRVXPpbHI3KkNTB1NfkL81j2mvhDp91HgV9MKuRIqrykj3WPq4rHyL+axj8/qGPmTqi6F9YDlHOvJU6oYcTsh/TYSzWmTE6JT19CtLTJt32D6CmHe0eQn1O8z5AXgT4sx4Vcu0/EQecMydB8z0hUWkTd2t4CrwNEePqMBcAR4mrBbwyXLPWJa8zrXmmLEhNBmfpkuY2102xxrih+pb+ieAb6vGhuA97UcJ5KR8gZ77K+99xxeYBzH6Q3/Z0fHcXrDC4zjOL3hBcZxnN74F+zlvXFWXF9PAAAAAElFTkSuQmCC");background-repeat:no-repeat;background-size:280px;color:transparent;display:block;font-size:0;height:20px;line-height:0;width:20px}.viewer-zoom-in:before{background-position:0 0;content:"Zoom In"}.viewer-zoom-out:before{background-position:-20px 0;content:"Zoom Out"}.viewer-one-to-one:before{background-position:-40px 0;content:"One to One"}.viewer-reset:before{background-position:-60px 0;content:"Reset"}.viewer-prev:before{background-position:-80px 0;content:"Previous"}.viewer-play:before{background-position:-100px 0;content:"Play"}.viewer-next:before{background-position:-120px 0;content:"Next"}.viewer-rotate-left:before{background-position:-140px 0;content:"Rotate Left"}.viewer-rotate-right:before{background-position:-160px 0;content:"Rotate Right"}.viewer-flip-horizontal:before{background-position:-180px 0;content:"Flip Horizontal"}.viewer-flip-vertical:before{background-position:-200px 0;content:"Flip Vertical"}.viewer-fullscreen:before{background-position:-220px 0;content:"Enter Full Screen"}.viewer-fullscreen-exit:before{background-position:-240px 0;content:"Exit Full Screen"}.viewer-close:before{background-position:-260px 0;content:"Close"}.viewer-container{-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;bottom:0;direction:ltr;font-size:0;left:0;line-height:0;overflow:hidden;position:absolute;right:0;top:0;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.viewer-container ::-moz-selection,.viewer-container::-moz-selection{background-color:transparent}.viewer-container ::selection,.viewer-container::selection{background-color:transparent}.viewer-container:focus{outline:0}.viewer-container img{display:block;height:auto;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.viewer-canvas{bottom:0;left:0;overflow:hidden;position:absolute;right:0;top:0}.viewer-canvas>img{height:auto;margin:15px auto;max-width:90%!important;width:auto}.viewer-footer{bottom:0;left:0;overflow:hidden;position:absolute;right:0;text-align:center}.viewer-navbar{background-color:rgba(0,0,0,.5);overflow:hidden}.viewer-list{box-sizing:content-box;height:50px;margin:0;overflow:hidden;padding:1px 0}.viewer-list>li{color:transparent;cursor:pointer;float:left;font-size:0;height:50px;line-height:0;opacity:.5;overflow:hidden;transition:opacity .15s;width:30px}.viewer-list>li:focus,.viewer-list>li:hover{opacity:.75}.viewer-list>li:focus{outline:0}.viewer-list>li+li{margin-left:1px}.viewer-list>.viewer-loading{position:relative}.viewer-list>.viewer-loading:after{border-width:2px;height:20px;margin-left:-10px;margin-top:-10px;width:20px}.viewer-list>.viewer-active,.viewer-list>.viewer-active:focus,.viewer-list>.viewer-active:hover{opacity:1}.viewer-player{background-color:#000;bottom:0;cursor:none;display:none;right:0;z-index:1}.viewer-player,.viewer-player>img{left:0;position:absolute;top:0}.viewer-toolbar>ul{display:inline-block;margin:0 auto 5px;overflow:hidden;padding:6px 3px}.viewer-toolbar>ul>li{background-color:rgba(0,0,0,.5);border-radius:50%;cursor:pointer;float:left;height:24px;overflow:hidden;transition:background-color .15s;width:24px}.viewer-toolbar>ul>li:focus,.viewer-toolbar>ul>li:hover{background-color:rgba(0,0,0,.8)}.viewer-toolbar>ul>li:focus{box-shadow:0 0 3px #fff;outline:0;position:relative;z-index:1}.viewer-toolbar>ul>li:before{margin:2px}.viewer-toolbar>ul>li+li{margin-left:1px}.viewer-toolbar>ul>.viewer-small{height:18px;margin-bottom:3px;margin-top:3px;width:18px}.viewer-toolbar>ul>.viewer-small:before{margin:-1px}.viewer-toolbar>ul>.viewer-large{height:30px;margin-bottom:-3px;margin-top:-3px;width:30px}.viewer-toolbar>ul>.viewer-large:before{margin:5px}.viewer-tooltip{background-color:rgba(0,0,0,.8);border-radius:10px;color:#fff;display:none;font-size:12px;height:20px;left:50%;line-height:20px;margin-left:-25px;margin-top:-10px;position:absolute;text-align:center;top:50%;width:50px}.viewer-title{color:#ccc;display:inline-block;font-size:12px;line-height:1.2;margin:0 5% 5px;max-width:90%;opacity:.8;overflow:hidden;text-overflow:ellipsis;transition:opacity .15s;white-space:nowrap}.viewer-title:hover{opacity:1}.viewer-button{-webkit-app-region:no-drag;background-color:rgba(0,0,0,.5);border-radius:50%;cursor:pointer;height:80px;overflow:hidden;position:absolute;right:-40px;top:-40px;transition:background-color .15s;width:80px}.viewer-button:focus,.viewer-button:hover{background-color:rgba(0,0,0,.8)}.viewer-button:focus{box-shadow:0 0 3px #fff;outline:0}.viewer-button:before{bottom:15px;left:15px;position:absolute}.viewer-fixed{position:fixed}.viewer-open{overflow:hidden}.viewer-show{display:block}.viewer-hide{display:none}.viewer-backdrop{background-color:rgba(0,0,0,.5)}.viewer-invisible{visibility:hidden}.viewer-move{cursor:move;cursor:-webkit-grab;cursor:grab}.viewer-fade{opacity:0}.viewer-in{opacity:1}.viewer-transition{transition:all .3s}@-webkit-keyframes viewer-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes viewer-spinner{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.viewer-loading:after{-webkit-animation:viewer-spinner 1s linear infinite;animation:viewer-spinner 1s linear infinite;border:4px solid hsla(0,0%,100%,.1);border-left-color:hsla(0,0%,100%,.5);border-radius:50%;content:"";display:inline-block;height:40px;left:50%;margin-left:-20px;margin-top:-20px;position:absolute;top:50%;width:40px;z-index:1}@media (max-width:767px){.viewer-hide-xs-down{display:none}}@media (max-width:991px){.viewer-hide-sm-down{display:none}}@media (max-width:1199px){.viewer-hide-md-down{display:none}} -------------------------------------------------------------------------------- /src/resource/script.js: -------------------------------------------------------------------------------- 1 | Array.prototype.remove = function (val) { 2 | const index = this.indexOf(val); 3 | if (index > -1) { 4 | this.splice(index, 1); 5 | } 6 | }; 7 | 8 | document.addEventListener('DOMContentLoaded', function () { 9 | const utils = { 10 | getQueryString: function (variable) { 11 | const query = window.location.search.substring(1); 12 | const vars = query.split('&'); 13 | for (var i = 0; i < vars.length; i++) { 14 | const pair = vars[i].split('='); 15 | if (pair[0] == variable) { 16 | return decodeURIComponent(pair[1]); 17 | } 18 | } 19 | return false; 20 | }, 21 | }; 22 | 23 | const LAST_VISIT_STORAGE_KEY = 'LAST_VISIT_KEY_FJHY3PHJ00'; 24 | const COLLAPSE_STORAGE_KEY = 'COLLAPSE_KEY_IXIFMU64D7'; 25 | 26 | const isMobile = Boolean(document.body.clientWidth < 900); 27 | const currPath = decodeURIComponent(window.location.pathname); 28 | const isIndex = [ 29 | `${window.root}/`, 30 | `${window.root}/index.html`, 31 | '/', 32 | '/index.html', 33 | ].includes(currPath); 34 | const lastVisitPathInStore = window.localStorage.getItem( 35 | LAST_VISIT_STORAGE_KEY, 36 | ); 37 | 38 | // navigate to last visit 39 | /*(function () { 40 | if (isIndex && lastVisitPathInStore) { 41 | fetch(lastVisitPathInStore) 42 | .then(res => { 43 | if (res.status === 200) { 44 | window.location.href = lastVisitPathInStore; 45 | } else { 46 | window.localStorage.removeItem(LAST_VISIT_STORAGE_KEY); 47 | } 48 | }); 49 | } 50 | })();*/ 51 | 52 | // menu 53 | (function () { 54 | const $dirs = $('#menu .dir'); 55 | const $loading = $('#menu .loading'); 56 | const $links = $('#menu .children > a'); 57 | const host = window.location.protocol + '//' + window.location.host; 58 | 59 | const getCurrCollapseArr = function () { 60 | return JSON.parse( 61 | window.localStorage.getItem(COLLAPSE_STORAGE_KEY) || '[]', 62 | ); 63 | }; 64 | const currCollapseArr = getCurrCollapseArr(); 65 | 66 | const toggleMenu = function (id) { 67 | const $parent = $(`#${id}`).parent('.parent'); 68 | $parent.toggleClass('expand'); 69 | const currCollapseArr = getCurrCollapseArr(); 70 | 71 | const hasExpand = $parent.hasClass('expand'); 72 | 73 | if (hasExpand) { 74 | currCollapseArr.remove(id); 75 | } else { 76 | currCollapseArr.push(id); 77 | } 78 | window.localStorage.setItem( 79 | COLLAPSE_STORAGE_KEY, 80 | JSON.stringify(currCollapseArr), 81 | ); 82 | }; 83 | 84 | const expandMenuById = function (id) { 85 | const $parents = $(`#${id}`).parents('.parent'); 86 | $parents.each(function () { 87 | $(this).addClass('expand'); 88 | }); 89 | }; 90 | 91 | const scrollToId = function (id) { 92 | if (!id) { 93 | return; 94 | } 95 | const ele = $(`#${id}`); 96 | if (ele.length > 0) { 97 | $('#menu').scrollTop(ele.offset().top - 100); 98 | } 99 | }; 100 | 101 | // 设置 dir 102 | $dirs.each(function () { 103 | const id = $(this).attr('id'); 104 | const $parent = $(this).parent('.parent'); 105 | const $triangle = $(this).children('.triangle'); 106 | const href = decodeURIComponent($(this).data('href')); 107 | 108 | if (currCollapseArr.includes(id)) { 109 | $parent.removeClass('expand'); 110 | } 111 | 112 | if (href) { 113 | const _path = href.replace(host, ''); 114 | const isActive = currPath === _path; 115 | 116 | if (isActive) { 117 | expandMenuById(id); 118 | scrollToId(id); 119 | $(this).addClass('active'); 120 | } 121 | } 122 | 123 | // 跳转指引 124 | $(this).on('click', function () { 125 | if (href) { 126 | window.location.href = href; 127 | } else { 128 | toggleMenu(id); 129 | } 130 | }); 131 | 132 | // 三角点击事件 133 | $triangle.on('click', function (event) { 134 | event.stopPropagation(); 135 | toggleMenu(id); 136 | }); 137 | }); 138 | 139 | // 设置 links 140 | $links.each(function () { 141 | const href = decodeURIComponent($(this).prop('href')); 142 | const _path = href.replace(host, ''); 143 | const isActive = currPath === _path; 144 | const isLastVisit = lastVisitPathInStore === _path; 145 | const $children = $(this).parent('.children'); 146 | const id = $children.attr('id'); 147 | 148 | if (isActive) { 149 | expandMenuById(id); 150 | scrollToId(id); 151 | $children.addClass('active'); 152 | } 153 | 154 | if (isLastVisit) { 155 | $(this).addClass('last-visit'); 156 | } 157 | }); 158 | 159 | $loading.remove(); 160 | })(); 161 | 162 | // expand-all 163 | (function () { 164 | if (isMobile) { 165 | return; 166 | } 167 | 168 | const $expandAll = $('#expand-all'); 169 | const $parents = $('#menu .parent'); 170 | 171 | $expandAll.on('click', function () { 172 | $parents.addClass('expand'); 173 | window.localStorage.setItem(COLLAPSE_STORAGE_KEY, '[]'); 174 | }); 175 | })(); 176 | 177 | // collapse-all 178 | (function () { 179 | if (isMobile) { 180 | return; 181 | } 182 | 183 | const $collapseAll = $('#collapse-all'); 184 | const $parents = $('#menu .parent'); 185 | const $dirs = $('#menu .dir'); 186 | const ids = $.map($dirs, function (item) { 187 | return $(item).attr('id'); 188 | }); 189 | 190 | $collapseAll.on('click', function () { 191 | $parents.removeClass('expand'); 192 | window.localStorage.setItem(COLLAPSE_STORAGE_KEY, JSON.stringify(ids)); 193 | }); 194 | })(); 195 | 196 | // menu drag 197 | (function () { 198 | if (isMobile) { 199 | return; 200 | } 201 | 202 | const $drager = $('#drager'); 203 | const $body = $('body'); 204 | const $menu = $('#menu'); 205 | 206 | $drager.mouseover(function () { 207 | if ($menu.hasClass('expand')) { 208 | $(this).css('cursor', 'e-resize'); 209 | } else { 210 | $(this).css('cursor', 'unset'); 211 | } 212 | }); 213 | 214 | $drager.mousedown(function () { 215 | if ($menu.hasClass('expand')) { 216 | $(this).css('cursor', 'e-resize'); 217 | } else { 218 | $(this).css('cursor', 'unset'); 219 | } 220 | $body.mousemove(function (e) { 221 | const _x = e.pageX; 222 | 223 | if (_x < 245) { 224 | return; 225 | } 226 | 227 | $menu.animate( 228 | { 229 | width: _x, 230 | }, 231 | 0, 232 | ); 233 | }); 234 | }); 235 | 236 | $body.mouseup(function () { 237 | $(this).unbind('mousemove'); 238 | $(this).css('cursor', 'default'); 239 | }); 240 | })(); 241 | 242 | // menu switcher 243 | (function () { 244 | if (isMobile) { 245 | return; 246 | } 247 | 248 | const $menu = $('#menu'); 249 | const $expandAll = $('#expand-all'); 250 | const $collapseAll = $('#collapse-all'); 251 | const $switcher = $('#drager > #switcher'); 252 | 253 | $switcher.on('click', function () { 254 | $menu.removeAttr('style'); 255 | $menu.toggleClass('expand'); 256 | $expandAll.toggle(); 257 | $collapseAll.toggle(); 258 | $(this).toggleClass('expand'); 259 | }); 260 | })(); 261 | 262 | // mobile_menu 263 | (function () { 264 | if (!isMobile) { 265 | return; 266 | } 267 | 268 | const $mobileMenu = $('#mobile_menu'); 269 | const $menu = $('#menu'); 270 | const $content = $('body > .content.markdown-body'); 271 | $mobileMenu.on('click', function () { 272 | $menu.toggleClass('show'); 273 | }); 274 | 275 | $content.on('click', function () { 276 | $menu.removeClass('show'); 277 | }); 278 | })(); 279 | 280 | // search_bar 281 | (function () { 282 | const $input = $('#search_bar > input'); 283 | const $clear = $('#search_bar > #clear'); 284 | let timer = null; 285 | 286 | const getSearchResult = (str) => { 287 | str = str.toLowerCase(); 288 | const tree = window.__doc_builder_dir_tree__ || []; 289 | const res = []; 290 | 291 | const fn = (arr) => { 292 | arr.forEach((info) => { 293 | const isDir = !!info.dirname; 294 | if (isDir) { 295 | fn(info.children); 296 | } else { 297 | const findInTitle = info.basename.toLowerCase().indexOf(str) !== -1; 298 | const findInContent = 299 | info.content.toLowerCase().indexOf(str) !== -1; 300 | 301 | if (findInTitle || findInContent) { 302 | res.push(info); 303 | } 304 | } 305 | }); 306 | }; 307 | 308 | fn(tree); 309 | return res; 310 | }; 311 | 312 | const addHighlight = (str, keyword) => { 313 | const regExp = new RegExp(keyword, 'gi'); 314 | const text = regExp.exec(str); 315 | return str.replace( 316 | regExp, 317 | '' + (text?.[0] || keyword) + '', 318 | ); 319 | }; 320 | 321 | const handleInputChange = (value) => { 322 | value = value.trim().toLowerCase(); 323 | const res = getSearchResult(value); 324 | const showSearchResult = value.length !== 0; 325 | const showEmpty = res.length === 0; 326 | const $wrapEle = $('#search_result'); 327 | let html = ''; 328 | 329 | if (value.length !== 0) { 330 | $clear.show(); 331 | } else { 332 | $clear.hide(); 333 | } 334 | 335 | if (showEmpty) { 336 | html = '
No Results!
'; 337 | } else { 338 | html = res 339 | .map((info) => { 340 | const index = info.content.toLowerCase().indexOf(value); 341 | const summary = `...${info.content.substring( 342 | index, 343 | index + 50, 344 | )}...`; 345 | const href = `${window.root}/${info.id}.html?search=${value}`; 346 | 347 | return ` 348 | 349 |
${addHighlight(info.basename, value)}
350 |
${addHighlight(summary, value)}
351 |
352 | `; 353 | }) 354 | .join(''); 355 | } 356 | 357 | if (showSearchResult) { 358 | $wrapEle.html(html); 359 | $wrapEle.show(); 360 | } else { 361 | $wrapEle.hide(); 362 | } 363 | }; 364 | 365 | $input.bind('input propertychange', function (e) { 366 | if (timer) { 367 | clearTimeout(timer); 368 | } 369 | 370 | timer = setTimeout(() => { 371 | handleInputChange(e.target.value); 372 | }, 500); 373 | }); 374 | 375 | $clear.on('click', function () { 376 | $input.val(''); 377 | handleInputChange(''); 378 | }); 379 | 380 | // add search input hotkey 381 | document.addEventListener('keyup', (e) => { 382 | if (e.key === 's') { 383 | $input.trigger('focus'); 384 | } 385 | }); 386 | })(); 387 | 388 | // keyword highlight 389 | (function () { 390 | const search = utils.getQueryString('search'); 391 | 392 | if (search) { 393 | $('.content.markdown-body').mark(search, { className: 'keyword' }); 394 | } 395 | })(); 396 | 397 | // image viewer 398 | (function () { 399 | $('.markdown-body img').viewer({ 400 | title: false, 401 | toolbar: false, 402 | navbar: false, 403 | }); 404 | })(); 405 | 406 | // back to top 407 | (function () { 408 | if (isMobile) { 409 | return; 410 | } 411 | 412 | const $btt = $('#btt'); 413 | const $content = $('body > .content'); 414 | 415 | $content.scroll(function () { 416 | if ($content.scrollTop() > 50) { 417 | $btt.fadeIn(200); 418 | } else { 419 | $btt.fadeOut(200); 420 | } 421 | }); 422 | 423 | $btt.on('click', function () { 424 | $content.animate( 425 | { 426 | scrollTop: 0, 427 | }, 428 | 200, 429 | ); 430 | }); 431 | })(); 432 | 433 | // navigate to hash 434 | (function () { 435 | const hash = window.location.hash.slice(1); 436 | const $content = $('body > .content.markdown-body'); 437 | 438 | if (hash) { 439 | const ele = document.getElementById(hash); 440 | $content.scrollTop($(ele)?.offset()?.top || 0); 441 | } 442 | })(); 443 | 444 | // set last visit 445 | (function () { 446 | if (isIndex) { 447 | return; 448 | } 449 | window.localStorage.setItem(LAST_VISIT_STORAGE_KEY, currPath); 450 | })(); 451 | }); 452 | -------------------------------------------------------------------------------- /src/resource/style.less: -------------------------------------------------------------------------------- 1 | // variables 2 | @mobile_width: 900px; 3 | @font_family: 'Microsoft JhengHei', 'Microsoft YaHei', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, 4 | sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'; 5 | @font_color: #333333; 6 | @primary_color: #0969da; 7 | 8 | :root { 9 | // info 10 | --info-title-color: #193c47; 11 | --info-bg-color: #eef9fd; 12 | --info-border-color: #4cb3d4; 13 | 14 | // note 15 | --note-title-color: #474748; 16 | --note-bg-color: #fdfdfe; 17 | --note-border-color: #d4d5d8; 18 | 19 | // tip 20 | --tip-title-color: #003100; 21 | --tip-bg-color: #e6f6e6; 22 | --tip-border-color: #009400; 23 | 24 | // warning 25 | --warning-title-color: #4d3800; 26 | --warning-bg-color: #fff8e6; 27 | --warning-border-color: #e6a700; 28 | 29 | // danger 30 | --danger-title-color: #4b1113; 31 | --danger-bg-color: #ffebec; 32 | --danger-border-color: #e13238; 33 | } 34 | 35 | // mixins 36 | .img(@cursor: pointer) { 37 | box-shadow: 0 0 7px 0 #aaaaaa; 38 | border-radius: 5px; 39 | padding: 10px; 40 | background-color: #ffffff; 41 | cursor: @cursor; 42 | box-sizing: border-box; 43 | } 44 | 45 | .ddd { 46 | white-space: nowrap; 47 | overflow: hidden; 48 | text-overflow: ellipsis; 49 | } 50 | 51 | ::-webkit-scrollbar { 52 | width: 4px; 53 | height: 4px; 54 | background-color: #f7f7f7; 55 | } 56 | 57 | /*定义滚动条轨道 内阴影+圆角*/ 58 | ::-webkit-scrollbar-track { 59 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 60 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 61 | border-radius: 4px; 62 | background-color: #f7f7f7; 63 | } 64 | 65 | /*定义滑块 内阴影+圆角*/ 66 | ::-webkit-scrollbar-thumb { 67 | border-radius: 4px; 68 | -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 69 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 70 | background-color: #ababab; 71 | } 72 | 73 | * { 74 | margin: 0; 75 | padding: 0; 76 | box-sizing: border-box; 77 | } 78 | 79 | html, 80 | body { 81 | overflow-x: hidden; 82 | overflow-y: hidden; 83 | color: @font_color; 84 | background-color: #ffffff; 85 | font-family: @font_family; 86 | } 87 | 88 | a { 89 | &:active, 90 | &:hover { 91 | opacity: 0.7; 92 | } 93 | } 94 | 95 | @media print { 96 | .menu, 97 | .drager, 98 | .table-of-contents, 99 | #btt { 100 | display: none !important; 101 | } 102 | 103 | body { 104 | height: max-content !important; 105 | } 106 | 107 | html, 108 | body { 109 | overflow-y: auto; 110 | } 111 | } 112 | 113 | body { 114 | display: flex; 115 | justify-content: space-between; 116 | font-size: 14px; 117 | height: 100vh; 118 | width: 100vw; 119 | @menu_width: 245px; 120 | 121 | > .menu { 122 | @item_height: 40px; 123 | @step: 10px; 124 | @background-color: #f7f7f7; 125 | 126 | width: 0; 127 | overflow-y: auto; 128 | background-color: @background-color; 129 | transition: all 0.2s; 130 | display: flex; 131 | flex-direction: column; 132 | max-height: 100vh; 133 | padding-bottom: 50px; 134 | border-right: 1px solid #cccccc; 135 | position: relative; 136 | 137 | @media screen and (max-width: @mobile_width) { 138 | width: 0; 139 | border-right: unset; 140 | } 141 | 142 | > .loading { 143 | position: absolute; 144 | top: 0; 145 | left: 0; 146 | right: 0; 147 | bottom: 0; 148 | width: 100%; 149 | display: flex; 150 | align-items: center; 151 | justify-content: center; 152 | z-index: 99; 153 | background-color: @background-color; 154 | } 155 | 156 | > .search_bar { 157 | width: 100%; 158 | margin-bottom: 5px; 159 | position: relative; 160 | @input_height: 40px; 161 | 162 | > input { 163 | width: 100%; 164 | border: unset; 165 | padding: 8px 30px 8px 8px; 166 | height: @input_height; 167 | } 168 | 169 | > .clear { 170 | position: absolute; 171 | top: calc(@input_height / 2 - 7px); 172 | right: 8px; 173 | height: 14px; 174 | width: 14px; 175 | cursor: pointer; 176 | display: none; 177 | 178 | &:after, 179 | &:hover { 180 | opacity: 0.7; 181 | } 182 | } 183 | 184 | > .search_result { 185 | position: absolute; 186 | width: 100%; 187 | left: 0; 188 | right: 0; 189 | background-color: #ffffff; 190 | display: none; 191 | z-index: 99; 192 | box-shadow: 0 5px 10px -5px #cccccc; 193 | 194 | > .empty { 195 | text-align: center; 196 | padding: 20px 0; 197 | } 198 | 199 | > .item { 200 | border-bottom: 1px solid #eeeeee; 201 | padding: 15px; 202 | cursor: pointer; 203 | text-decoration: none; 204 | display: block; 205 | color: @font_color; 206 | 207 | .keyword { 208 | color: red; 209 | } 210 | 211 | &:after, 212 | &:hover { 213 | opacity: 0.7; 214 | } 215 | 216 | &:last-child { 217 | border-bottom: unset; 218 | } 219 | 220 | > .title { 221 | font-weight: 900; 222 | margin-bottom: 5px; 223 | } 224 | 225 | > .content { 226 | word-break: break-all; 227 | } 228 | } 229 | } 230 | } 231 | 232 | &.show { 233 | width: 60vw; 234 | } 235 | 236 | &.expand { 237 | min-width: @menu_width; 238 | max-width: 50vw; 239 | width: max-content; 240 | 241 | @media screen and (max-width: @mobile_width) { 242 | width: 0; 243 | min-width: unset; 244 | max-width: unset; 245 | } 246 | 247 | &.show { 248 | width: 60vw; 249 | } 250 | } 251 | 252 | ul, 253 | li { 254 | list-style-type: none; 255 | list-style: none; 256 | } 257 | 258 | .parent { 259 | margin-left: @step; 260 | overflow: hidden; 261 | flex-shrink: 0; 262 | height: @item_height; 263 | transition: all 0.2s; 264 | 265 | &.expand { 266 | height: auto; 267 | 268 | > .dir { 269 | > .triangle { 270 | transform: rotate(180deg); 271 | } 272 | } 273 | } 274 | 275 | > .dir { 276 | justify-content: space-between; 277 | padding-right: 5px; 278 | 279 | &.active { 280 | > span { 281 | color: #0969da; 282 | } 283 | } 284 | 285 | &:hover, 286 | &:active { 287 | opacity: 0.7; 288 | cursor: pointer; 289 | } 290 | 291 | > span { 292 | color: #000000; 293 | font-weight: 900; 294 | 295 | .ddd(); 296 | } 297 | 298 | > .triangle { 299 | flex-shrink: 0; 300 | height: 24px; 301 | width: 24px; 302 | background-repeat: no-repeat; 303 | background-position: center; 304 | background-size: contain; 305 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAAXNSR0IArs4c6QAAAMNJREFUSEvtksEJwzAMRa3gMTqFsQm9N9sk0yTbtPdiYjxFxjBWcU6hlPLd0OQinb/00OOTOmnoJK4S8GHmRbWo/psBKRestm3bSwl77xd4aRP8WbUx5l7uxBi7w8DGmJGI+gJk5inGONTCqz+21vbMPG5BRDSEEKYaeBXYOXfLOa+K36dpmm6e5wcKh8GlTCmlp1JqLdWHWbTWV7RsMLiUiYj0t4+YOaFlg8GoQjQnYNTU7pyo3q0QPSCqUVO7c6epfgGFYjEfQmd1ZwAAAABJRU5ErkJggg=='); 306 | transition: all 0.2s; 307 | } 308 | } 309 | 310 | > .children { 311 | min-height: 30px; 312 | 313 | > a { 314 | height: 30px; 315 | } 316 | 317 | &:last-child { 318 | margin-bottom: 10px; 319 | } 320 | 321 | &::before { 322 | content: ''; 323 | border-radius: 50%; 324 | height: 4px; 325 | width: 4px; 326 | background-color: @font_color; 327 | margin-right: 6px; 328 | } 329 | } 330 | } 331 | 332 | .dir, 333 | .children { 334 | min-height: @item_height; 335 | flex-shrink: 0; 336 | display: flex; 337 | align-items: center; 338 | } 339 | 340 | .children { 341 | padding-left: @step; 342 | .ddd(); 343 | 344 | &.active { 345 | > a { 346 | color: @primary_color; 347 | font-weight: 900; 348 | } 349 | 350 | &::before { 351 | background-color: @primary_color; 352 | } 353 | } 354 | 355 | &.about { 356 | border-top: 1px solid #cccccc; 357 | margin-top: @step; 358 | padding-top: @step; 359 | } 360 | 361 | > a { 362 | .ddd(); 363 | color: @font_color; 364 | text-decoration: none; 365 | display: flex; 366 | align-items: center; 367 | height: 100%; 368 | width: 100%; 369 | 370 | &.last-visit { 371 | &::after { 372 | content: '上次看到'; 373 | font-size: 12px; 374 | transform: scale(0.8); 375 | border-radius: 6px; 376 | padding: 2px 3px; 377 | color: #ffffff; 378 | background-color: #666666; 379 | display: flex; 380 | align-items: center; 381 | justify-content: center; 382 | } 383 | } 384 | } 385 | } 386 | } 387 | 388 | > .drager { 389 | width: 20px; 390 | position: relative; 391 | 392 | @media screen and (max-width: @mobile_width) { 393 | display: none; 394 | } 395 | 396 | &:hover, 397 | &:active { 398 | > .btn { 399 | opacity: 1; 400 | } 401 | } 402 | 403 | > .btn { 404 | opacity: 0; 405 | position: absolute; 406 | left: 0; 407 | right: 0; 408 | height: 32px; 409 | width: 32px; 410 | border-radius: 0 3px 3px 0; 411 | box-shadow: 0 1px 4px -2px rgb(0 0 0 / 13%), 0 2px 8px rgb(0 0 0 / 8%), 0 8px 16px 4px rgb(0 0 0 / 4%); 412 | align-items: center; 413 | justify-content: center; 414 | background-color: #ffffff; 415 | z-index: 99; 416 | display: flex; 417 | transition: all 0.2s; 418 | cursor: pointer; 419 | 420 | background-repeat: no-repeat; 421 | background-position: center; 422 | background-size: 18px; 423 | } 424 | 425 | > .switcher { 426 | top: 50px; 427 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAALGPC/xhBQAAAdRJREFUaEPt2TFI1VEYhvE7ZG2iRaMoCg2FTg25iC3ioqCL0GRL0NBUQbnU5uAkOjgFEYiLuAgO4dbQItQQtEtTbbWkgz5nO3xcOB//9zsOch74jS9+y+XIvb1Wq9VqXacGMWt4u42u29Bu4gQXhucgZRveR9hD3sCTsg3tFewhH+BJ2YY2D3vIFwyhlLINbQynyA/5jYcopWzDO0J+SPIEnpRtaBuwh7yHJ2Ub2lPYQ3bhSdmGNo3/yA9Jb8AISinb0NLrax+uv3iMUso2vH4P1zN4UrahrcEekj60npRtaMuwhxxgAKWUbWgPYB+uH7iPUso2tBv4jPyQcyyilLINbwv5IclLeFK2od2DPWQHnpRteBPoeoyyrdI27EGv4UnZhpc+sMfIj0kf2CWUUrZVmsIv5Af9xCRKKdsqrSA/JjlE+tKglLKt0jvYgzbhSdlWaQ/2oBfwpGzDu4PvyI/5hzmUUrZVmsEZ8oO+YRSllG2VniM/JtmHJ2VbpX7/S63Dk7Ktkn3wklV4UrbhjcM+eH/wCKWUbZUWkB+TfMUwSinbKqVvzu1B6csGT8q2Sp9gD3oLT8o2vFvo+mONsq1S+jkg/fGct7voum21Wq3WVdbrXQLPHlthDLZk8gAAAABJRU5ErkJggg=='); 428 | 429 | &.expand { 430 | opacity: 1; 431 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAALGPC/xhBQAAAdpJREFUaEPt2TFIllEUxvFvSN3ClMYoDBqMnBpqCVuiJcEWwUkXoaGpgnTJzaEpcmgKJBCXaAkcoq3BRcghcI+m3HKxhvqf7XJI7oHnXBS5f/iND57l5ZX3G/R6vV7vNDftjCGa357HiWR//K+zi2HUUrZNeg5/0AYiKdsmvYU/6CkiKdv0RvEF/qD7qKVsm3QTP1Ee8x1XUEvZNmke5TFmG5GUbZNW4Q96iUjKtkmb8ActIpKyTe8S7J1QHnOE26ilbJt0F79QHmQHRt78yrZJSyiPMdEXnrJtkj2s/qAVRFK26Q3hA/xBD1FL2TZpEt9QHmMvvOuopWybNIM/KA/6hHOopWyb9ATlMeY1IinbJr2BP+gaIinb9P53zFVEUrapPYM/ZB2RlG1qs/AP7GdEHlhlm9oN7KM85AemUEvZpmYfEz6iPMTMoZayTe8V/CEvEEnZpvYY/pAtRFK2qd3DIcpD9jCOWso2tcv4ivKQ37iDWso2vfcoDzGPEEnZprYGf0j0fyJlm9oC/CH24oqkbFO7hQOUh9iLawK1lG1qF7CD8hDzALWUbXr2UcAfYl/aIynb1JbhD3mHSMo2teN+rBlBLWXbJDuodBHR/NZ+Yuj1er3eWWgw+AcsqVthQJlPLQAAAABJRU5ErkJggg=='); 432 | } 433 | } 434 | 435 | > .expand-all { 436 | top: 92px; 437 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAALGPC/xhBQAAARpJREFUaEPtmTEKwkAQRYOVnsRSQbD2EB7BU9hoYydYWFh6FLXwKl7AA+h/4sIS1srFzMg8eJCkCPthN8xMmiAIgsRMrjuWNXwNL3p0LGv4mghS0SpBgD3apUFNhm9d05NXeXndOeYo04Hd88AjS5l/eXAhXTGX7RB4l1PpgpG8yVIQ5Mz0pWkG8ixLAXIP0jRjuZNbuZEnmRbP9SpzIt3QDuKWCGKNCGKNCGKNCGKNCGINt0EoBPPCsB2EQpKCksKSAtM0lOhp8Z+k1KfkNw1NE81TKQDSdNF8uYB2lra2FIQ22BUMGtohGEi4hBFQCsFoyDUM5zgzDOtc8xcjU3OURv2/tArxx6qiESSHPcqLurTaOQmCwDVN8wQrNXEw/Il29wAAAABJRU5ErkJggg=='); 438 | } 439 | 440 | > .collapse-all { 441 | top: 134px; 442 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABGdBTUEAALGPC/xhBQAAAN5JREFUaEPtmjEKAjEQRVN4GZs9g2JhuY2nsfIo3sTOk2zpHfR/mEAIsdEiM8N/8CBks5DPFpkMW4QQUzl0huUB3ybHYVEQbyiINxTEA0eT50Yf5ATPpmsWuMG6+W9yDde65gJHm2/lmhBc4SgA5bNQ3GEfgnPh2MEnrCE45lxI9vBlchya1RQiIzfI0sKD3MvP8OX2HJipghC+PPrMM/wriBCOSVGipCga05TxKS5WKa66KZoPqdpBtQHHZhxLi7p5jtm0qw28UPRBwqIg3lAQbyiIN9qfBagQYgqlfABzngHuSAZeVwAAAABJRU5ErkJggg=='); 443 | } 444 | } 445 | 446 | > .mobile_menu { 447 | display: none; 448 | position: fixed; 449 | bottom: calc(7px + 1vw); 450 | right: calc(7px + 1vw); 451 | background-color: rgba(255, 255, 255, 0.8); 452 | outline: 1px solid #cccccc; 453 | border-radius: 50%; 454 | height: 45px; 455 | width: 45px; 456 | align-items: center; 457 | justify-content: center; 458 | z-index: 99; 459 | 460 | > img { 461 | height: 27px; 462 | width: 27px; 463 | } 464 | 465 | &:active, 466 | &:hover { 467 | opacity: 0.7; 468 | } 469 | 470 | @media screen and (max-width: @mobile_width) { 471 | display: flex; 472 | } 473 | } 474 | 475 | > .content { 476 | flex: 1; 477 | overflow-y: auto; 478 | overflow-x: hidden; 479 | padding: calc(10px + 1vw) calc(50px + 1vw) 100px calc(50px + 1vw - 20px); 480 | 481 | @media screen and (max-width: @mobile_width) { 482 | padding: 0.8rem 0.8rem 100px; 483 | } 484 | 485 | &.markdown-body { 486 | font-family: @font_family; 487 | font-size: 14px; 488 | 489 | .keyword { 490 | color: red; 491 | } 492 | 493 | img { 494 | .img(zoom-in); 495 | display: block; 496 | margin: 0 auto; 497 | 498 | + figcaption { 499 | margin: 6px auto; 500 | font-size: 0.8rem; 501 | text-align: center; 502 | 503 | &:only-child { 504 | display: none; 505 | } 506 | } 507 | } 508 | 509 | h1, 510 | h2, 511 | h3, 512 | h4, 513 | h5 { 514 | > a { 515 | color: var(--color-fg-default); 516 | } 517 | } 518 | 519 | .info, 520 | .note, 521 | .tip, 522 | .warning, 523 | .danger { 524 | position: relative; 525 | margin: 1rem 0; 526 | padding: 0.3rem 1rem; 527 | border-left-width: 0.3rem; 528 | border-left-style: solid; 529 | border-radius: 0.5rem; 530 | color: inherit; 531 | 532 | & > *:first-child { 533 | margin-top: 16px; 534 | margin-bottom: 16px; 535 | } 536 | 537 | p { 538 | line-height: 1.5; 539 | } 540 | } 541 | 542 | .info { 543 | border-color: var(--info-border-color); 544 | background: var(--info-bg-color); 545 | } 546 | 547 | .note { 548 | border-color: var(--note-border-color); 549 | background: var(--note-bg-color); 550 | } 551 | 552 | .tip { 553 | border-color: var(--tip-border-color); 554 | background: var(--tip-bg-color); 555 | } 556 | 557 | .warning { 558 | border-color: var(--warning-border-color); 559 | background: var(--warning-bg-color); 560 | } 561 | 562 | .danger { 563 | border-color: var(--danger-border-color); 564 | background: var(--danger-bg-color); 565 | } 566 | 567 | hr.footnotes-sep { 568 | display: none; 569 | } 570 | } 571 | 572 | > .btt { 573 | position: fixed; 574 | bottom: 50px; 575 | right: calc(50px + 1vw); 576 | height: 42px; 577 | width: 42px; 578 | box-shadow: 0 1px 4px -2px rgb(0 0 0 / 13%), 0 2px 8px rgb(0 0 0 / 8%), 0 8px 16px 4px rgb(0 0 0 / 4%); 579 | background-color: #ffffff; 580 | border-radius: 50%; 581 | //display: flex; 582 | align-items: center; 583 | justify-content: center; 584 | background-repeat: no-repeat; 585 | background-size: 70%; 586 | background-position: center; 587 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAApFJREFUaEPt189rE0EUB/Dv26I2PUgv/gXaXX9c/Qf8D3oSqtCDgtmkogXFehBs8SC2oAdpd4OiiKLgyZPn/gMeFXeLePfiQcgmavbJbpsawsR9u5lRCZNTIG/ezOe9md0JYUI+NCEOWMj/1knbEdsRQxWwW8tQYSunFXek5sc3AMyTg6jybCUGcgoPwJskdNclw0SQHEG4J0moPYaxIsGIIDPNuM6MUPsiBQmJ4Le33FZRqAiSJak14wVOOWv3X/uQQ1Gy5b6STCiGSJL9yxijkIP1nZNTDm9mwF5KS99bcx9MYY1BMoTj4DWBT2WLZ9D7NMVZUxgjkGFEvwsmMdohoxCmMVohRQiTGG0QFYKZ14jodn5GBr6bODNaIEoE4RZSPjAIAdFPAu6Y6MzYEOV2IqwkW+76tB+tDkI6obc67Uc3ieiubsxYEPWZ4GtJ4N3PFqqC7N0SroOxoRNTGaJGOFeS4NjD/gJHQXJMY2cZ4Ae6MJUgKgQxNdvhXDD45v4TJMf40WUQ7cPHec+UhqgRfKkdeo+Grx9FkCx+xo/rTL9v1lUxpSDKpxNwoRO4T1V3KAkkP0vNjxeJncfjbLNSkJofvwDh/P6EzIud0Hs+6iIohexiokViejaQazsJ3DPSS2Y5SCP+AuBInpxwrui/QhnI3tNsAYyXu4vnd0ngnTYCObT0yXXSXoucqY325tG3RZOUheRnphHNM+gqc2+tE57YLpqj/3upjkiTSh6/ZXMVxVtIUYXyA6y4okjGVYmxHZFUzXZEUqWhGLu1JEWzW0tSJbu1KlRpYrbW7PLn2W73x9esBkk3PYwnx79VqIdoiNGnlmgFmoIsRFMhtaWxHdFWSk2JbEc0FVJbmonpyC9HrqlC1gKCEwAAAABJRU5ErkJggg=='); 588 | cursor: pointer; 589 | display: none; 590 | z-index: 99; 591 | 592 | &:hover, 593 | &:active { 594 | opacity: 0.7; 595 | } 596 | 597 | @media screen and (max-width: @mobile_width) { 598 | display: none; 599 | } 600 | 601 | &.withToc { 602 | right: calc(@menu_width + 50px + 1vw); 603 | } 604 | } 605 | } 606 | 607 | > .table-of-contents { 608 | overflow-y: auto; 609 | width: @menu_width; 610 | padding: 15px; 611 | line-height: 1.8; 612 | max-height: 100vh; 613 | border-left: 1px solid #cccccc; 614 | background-color: #f7f7f7; 615 | 616 | ul { 617 | padding-left: 1em; 618 | } 619 | 620 | a { 621 | text-decoration: none; 622 | color: #555555; 623 | 624 | &.active { 625 | font-weight: 900; 626 | color: @font_color; 627 | } 628 | 629 | &:hover, 630 | &:active { 631 | text-decoration: underline; 632 | } 633 | } 634 | 635 | @media screen and (max-width: @mobile_width) { 636 | display: none; 637 | } 638 | } 639 | } 640 | 641 | .viewer-container { 642 | img { 643 | .img(unset); 644 | } 645 | } 646 | -------------------------------------------------------------------------------- /src/types.d.ts: -------------------------------------------------------------------------------- 1 | export interface IConfig { 2 | port: number; 3 | host: string; 4 | output: string; 5 | input: string; 6 | resource: string; 7 | title: string; 8 | root: string; 9 | ignore: Array; 10 | } 11 | 12 | export interface IOption extends Omit { 13 | config: string; 14 | ignore: string; 15 | } 16 | 17 | export interface IDirTree { 18 | id: string; 19 | filename: string; 20 | isRootIndexFile?: boolean; 21 | isIndexFile?: boolean; 22 | basename: string; 23 | path: string; 24 | dirname?: string; 25 | children?: IDirTree[]; 26 | content?: string; 27 | } 28 | 29 | export interface IEjsData { 30 | root: string; 31 | html: string; 32 | title: string; 33 | basename: string; 34 | tocHtml: string; 35 | menuHtml: string; 36 | version: string; 37 | timeString: string; 38 | } 39 | -------------------------------------------------------------------------------- /src/utils/config.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { IConfig, IOption } from '../types'; 3 | 4 | export const CWD = process.cwd(); 5 | export const APP_NAME = 'doc-builder'; 6 | 7 | export const getConfig = (options: IOption): IConfig => { 8 | let cfgByFile: Partial = {}; 9 | 10 | if (options.config) { 11 | const filepath = path.join(CWD, options.config); 12 | cfgByFile = require(filepath); 13 | } 14 | 15 | const port: number = (function () { 16 | if (!isNaN(Number(cfgByFile.port))) { 17 | return Number(cfgByFile.port); 18 | } 19 | return Number(options.port); 20 | })(); 21 | 22 | const _root = cfgByFile.root || options.root; 23 | const root = _root ? `/${_root}` : _root; 24 | 25 | const result = { 26 | port, 27 | host: cfgByFile.host || options.host, 28 | output: cfgByFile.output || options.output, 29 | input: cfgByFile.input || options.input, 30 | resource: cfgByFile.resource || options.resource, 31 | title: cfgByFile.title || options.title, 32 | root, 33 | ignore: cfgByFile.ignore || options.ignore.split(','), 34 | }; 35 | 36 | return result; 37 | }; 38 | -------------------------------------------------------------------------------- /src/utils/getTocHtmlByMd.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 根据 markdown 生成 toc html 3 | */ 4 | import { slugifyFn } from './index'; 5 | 6 | const markdownToc = require('markdown-toc'); 7 | 8 | interface Item { 9 | lvl: number; 10 | content: string | null; 11 | slug: string | null; 12 | children?: Array; 13 | parent: Item | null; 14 | } 15 | 16 | const getMinLevel = (headlineItems: Array) => { 17 | return Math.min(...headlineItems.map((item) => item.lvl)); 18 | }; 19 | 20 | const addListItem = ( 21 | lvl: number, 22 | content: string | null, 23 | slug: string | null, 24 | rootNode: Item | null, 25 | ) => { 26 | const listItem = { lvl, content, slug, children: [], parent: rootNode }; 27 | rootNode?.children?.push(listItem); 28 | return listItem; 29 | }; 30 | 31 | const flatHeadlineItemsToNestedTree = (headlineItems: Array) => { 32 | const toc: Item = { 33 | lvl: getMinLevel(headlineItems) - 1, 34 | slug: null, 35 | content: null, 36 | children: [], 37 | parent: null, 38 | }; 39 | let currentRootNode: Item | null = toc; 40 | let prevListItem = currentRootNode; 41 | 42 | headlineItems.forEach((item) => { 43 | if (item.lvl > prevListItem.lvl) { 44 | Array.from({ length: item.lvl - prevListItem.lvl }).forEach((_) => { 45 | currentRootNode = prevListItem; 46 | prevListItem = addListItem(item.lvl, null, null, currentRootNode); 47 | }); 48 | prevListItem.content = item.content; 49 | prevListItem.slug = item.slug; 50 | } else if (item.lvl === prevListItem.lvl) { 51 | prevListItem = addListItem( 52 | item.lvl, 53 | item.content, 54 | item.slug, 55 | currentRootNode, 56 | ); 57 | } else if (item.lvl < prevListItem.lvl) { 58 | for (let i = 0; i < prevListItem.lvl - item.lvl; i++) { 59 | currentRootNode = currentRootNode?.parent as any; 60 | } 61 | prevListItem = addListItem( 62 | item.lvl, 63 | item.content, 64 | item.slug, 65 | currentRootNode, 66 | ); 67 | } 68 | }); 69 | 70 | return toc; 71 | }; 72 | 73 | const tocItemToHtml = (tocItem: Item): string => { 74 | return ( 75 | '
    ' + 76 | tocItem?.children 77 | ?.map((childItem: Item) => { 78 | let li = `
  • `; 79 | const anchor = childItem.slug; 80 | const text = childItem.content; 81 | 82 | li += 83 | (anchor 84 | ? `${text}` 85 | : text) || ''; 86 | 87 | return ( 88 | li + 89 | ((childItem?.children?.length as number) > 0 90 | ? tocItemToHtml(childItem) 91 | : '') + 92 | '
  • ' 93 | ); 94 | }) 95 | .join('') + 96 | '
' 97 | ); 98 | }; 99 | 100 | const getTocHtmlByMd = (md: string): string => { 101 | const flatHeadlineItems = markdownToc(md, { 102 | slugify: slugifyFn, 103 | }).json; 104 | 105 | if (flatHeadlineItems.length <= 1) { 106 | return ''; 107 | } 108 | 109 | const nestedTree = flatHeadlineItemsToNestedTree(flatHeadlineItems); 110 | const html = tocItemToHtml(nestedTree); 111 | return html; 112 | }; 113 | 114 | export default getTocHtmlByMd; 115 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | import { IConfig, IEjsData } from '../types'; 2 | import { IDirTree } from '../types'; 3 | import fs from 'fs-extra'; 4 | import path from 'path'; 5 | import mdInstance from './mdInstance'; 6 | import ejs from 'ejs'; 7 | import getTocHtmlByMd from './getTocHtmlByMd'; 8 | import chalk from 'chalk'; 9 | import md5 from 'md5'; 10 | import { INDEX_FILE_NAME } from '../constants'; 11 | import { networkInterfaces } from 'os'; 12 | import logger from './logger'; 13 | 14 | const { version } = require('../../package.json'); 15 | 16 | export const sleep = (t = 3000) => 17 | new Promise((resolve) => setTimeout(resolve, t)); 18 | 19 | // 获取文件树 20 | export const getDirTree = (params: { 21 | inputPath: string; 22 | config: IConfig; 23 | }): Array => { 24 | const { inputPath, config } = params; 25 | 26 | const fn = (dir: string) => { 27 | const res: Array = []; 28 | const filenames = fs.readdirSync(dir); 29 | 30 | for (const filename of filenames) { 31 | const extname = path.extname(filename); 32 | const realPath = path.join(dir, filename); 33 | 34 | const isIndexFile = (function () { 35 | return filename === INDEX_FILE_NAME; 36 | })(); 37 | 38 | const isRootIndexFile = (function () { 39 | return isIndexFile && path.relative(inputPath, realPath) === 'index.md'; 40 | })(); 41 | 42 | const basename = (function () { 43 | if (isIndexFile && !isRootIndexFile) { 44 | return dir.split(path.sep).slice(-1)[0]; 45 | } 46 | return filename.substring(0, filename.indexOf(extname)); 47 | })(); 48 | 49 | const id = isRootIndexFile ? 'index' : md5(realPath); 50 | const stat = fs.lstatSync(realPath); 51 | const isDirectory = stat.isDirectory(); 52 | const isFile = stat.isFile(); 53 | const isStartsWithDot = filename.startsWith('.'); 54 | 55 | const isIgnore = config.ignore.some((item) => { 56 | return path.join(inputPath, item) === realPath; 57 | }); 58 | 59 | if (isStartsWithDot || isIgnore) { 60 | continue; 61 | } 62 | 63 | if (['.md', '.markdown'].includes(extname) && isFile) { 64 | const markdown = fs.readFileSync(path.join(dir, filename), { 65 | encoding: 'utf-8', 66 | }); 67 | 68 | res.push({ 69 | id, 70 | isRootIndexFile, 71 | isIndexFile, 72 | filename, 73 | basename, 74 | path: dir, 75 | content: mdInstance 76 | .render(markdown) 77 | .replace(/<[^>]+>/g, '') 78 | .replace(/[\r\n]/g, ''), 79 | }); 80 | } else if (isDirectory) { 81 | res.push({ 82 | id, 83 | dirname: filename, 84 | filename: '', 85 | basename, 86 | path: dir, 87 | children: fn(path.join(dir, filename)), 88 | }); 89 | } 90 | } 91 | 92 | res.sort((a, b) => { 93 | if (a.children && b.children) { 94 | if (!a.dirname < !b.dirname) { 95 | return -1; 96 | } else { 97 | return 1; 98 | } 99 | } 100 | if (a.children) { 101 | return -1; 102 | } else { 103 | return 1; 104 | } 105 | }); 106 | 107 | return res; 108 | }; 109 | 110 | let res = fn(inputPath); 111 | res = res.filter((i) => i.dirname !== 'resource'); 112 | 113 | return res; 114 | }; 115 | 116 | // 根据文件树生成菜单 html 117 | const getMenuHtmlByDirTree = ( 118 | dirTree: Array, 119 | config: IConfig, 120 | ): string => { 121 | let res = ''; 122 | 123 | for (const item of dirTree) { 124 | if (item.isIndexFile) { 125 | continue; 126 | } 127 | 128 | const isDir = !!item.dirname; 129 | if (isDir) { 130 | const indexChildren = item.children?.find((i) => i.isIndexFile); 131 | const href = indexChildren 132 | ? `${config.root}/${indexChildren.id}.html` 133 | : ''; 134 | 135 | res += ` 136 |
    137 |
  • 140 | ${item.dirname} 141 |
    142 |
  • 143 | ${getMenuHtmlByDirTree(item.children || [], config)} 144 |
145 | `; 146 | } else { 147 | const href = `${config.root}/${item.id}.html`; 148 | 149 | res += ` 150 |
  • 151 | ${item.basename} 152 |
  • 153 | `; 154 | } 155 | } 156 | 157 | return res; 158 | }; 159 | 160 | // 根据文件树执行渲染 ejs 生成 html 161 | export const renderDirTree = async (params: { 162 | dirTree: Array; 163 | config: IConfig; 164 | outputPath: string; 165 | }) => { 166 | const { dirTree, config, outputPath } = params; 167 | const menuHtml = getMenuHtmlByDirTree(dirTree, config); 168 | const chinaTimeString = getChinaTimeString(); 169 | 170 | const renderByFileInfoArr = (fileInfoArr: Array = []) => { 171 | fileInfoArr.forEach((info: IDirTree) => { 172 | const isDir = !!info.dirname; 173 | 174 | if (!isDir) { 175 | const markdown = fs.readFileSync(path.join(info.path, info.filename), { 176 | encoding: 'utf-8', 177 | }); 178 | const html = mdInstance.render(markdown); 179 | const tocHtml = getTocHtmlByMd(markdown); 180 | const basename = info.basename; 181 | const ejsData: IEjsData = { 182 | root: config.root, 183 | html: html, 184 | title: config.title, 185 | basename: info.isRootIndexFile ? '' : basename, 186 | tocHtml, 187 | menuHtml, 188 | version, 189 | timeString: chinaTimeString, 190 | }; 191 | 192 | ejs.renderFile( 193 | path.resolve(__dirname, '../ejs/tpl.ejs'), 194 | ejsData, 195 | function (err: Error | null, str: string) { 196 | if (err) { 197 | throw err; 198 | } 199 | 200 | fs.writeFileSync(path.join(outputPath, `${info.id}.html`), str, { 201 | encoding: 'utf-8', 202 | }); 203 | }, 204 | ); 205 | } else { 206 | renderByFileInfoArr(info.children); 207 | } 208 | }); 209 | }; 210 | 211 | const hasUserIndex: boolean = dirTree.some((i) => i.isRootIndexFile); 212 | 213 | if (!hasUserIndex) { 214 | dirTree.push({ 215 | id: 'index', 216 | filename: 'default_index.md', 217 | basename: 'index', 218 | path: path.resolve(__dirname, '..'), 219 | }); 220 | } 221 | 222 | renderByFileInfoArr(dirTree); 223 | }; 224 | 225 | // 拷贝模板资源 226 | export const copyTplResource = async (outputPath: string) => { 227 | fs.copySync( 228 | path.resolve(__dirname, '../resource'), 229 | path.join(outputPath, 'resource'), 230 | ); 231 | }; 232 | 233 | // 获取墙国时间 234 | export const getChinaTimeString = () => { 235 | const timezone = 8; 236 | const offsetGmt = new Date().getTimezoneOffset(); 237 | const nowDate = new Date().getTime(); 238 | const targetDate = new Date( 239 | nowDate + offsetGmt * 60 * 1000 + timezone * 60 * 60 * 1000, 240 | ); 241 | return targetDate.toLocaleString(); 242 | }; 243 | 244 | // 禁用 github 的 jekyll 245 | export const genNojekyllFile = async (outputPath: string) => { 246 | fs.writeFileSync(path.join(outputPath, '.nojekyll'), '', { 247 | encoding: 'utf-8', 248 | }); 249 | }; 250 | 251 | // 生成文件树 json 252 | export const genDirTreeJson = async ( 253 | dirTree: Array, 254 | outputPath: string, 255 | ) => { 256 | fs.writeFileSync( 257 | path.join(outputPath, 'dir_tree.json'), 258 | JSON.stringify(dirTree), 259 | { encoding: 'utf-8' }, 260 | ); 261 | }; 262 | 263 | // 拷贝用户的资源 264 | export const copyUserResource = async (params: { 265 | resourcePath: string; 266 | outputPath: string; 267 | config: IConfig; 268 | }) => { 269 | const { resourcePath, outputPath, config } = params; 270 | 271 | try { 272 | fs.copySync(resourcePath, path.join(outputPath, config.resource)); 273 | } catch (_) { 274 | // 275 | } 276 | }; 277 | 278 | // 通用 slugification function 279 | export const slugifyFn = (str: string, opt?: any) => { 280 | const r = encodeURIComponent( 281 | String(str).trim().toLowerCase().replace(/\s+/g, '-'), 282 | ); 283 | if (opt) { 284 | if (opt.num === 0) { 285 | return r; 286 | } 287 | return r + '-' + opt.num; 288 | } 289 | return r; 290 | }; 291 | 292 | // 生成 manifest.json 293 | export const genManifest = (params: { 294 | config: IConfig; 295 | outputPath: string; 296 | }) => { 297 | const { config, outputPath } = params; 298 | 299 | const res = { 300 | name: config.title, 301 | short_name: config.title, 302 | display: 'standalone', 303 | start_url: config.root, 304 | orientation: 'natural', 305 | icons: [ 306 | { 307 | src: `${config.root}/resource/icons/128.png`, 308 | sizes: '128x128', 309 | }, 310 | { 311 | src: `${config.root}/resource/icons/144.png`, 312 | sizes: '144x144', 313 | }, 314 | { 315 | src: `${config.root}/resource/icons/192.png`, 316 | sizes: '192x192', 317 | }, 318 | { 319 | src: `${config.root}/resource/icons/256.png`, 320 | sizes: '256x256', 321 | }, 322 | { 323 | src: `${config.root}/resource/icons/512.png`, 324 | sizes: '512x512', 325 | }, 326 | ], 327 | }; 328 | 329 | fs.writeFileSync( 330 | path.join(outputPath, 'manifest.json'), 331 | JSON.stringify(res), 332 | { encoding: 'utf-8' }, 333 | ); 334 | }; 335 | 336 | export const printInfo = (config: IConfig) => { 337 | console.log( 338 | chalk.blueBright(` 339 | ----------------- DOC BUILDER ${version} ----------------- 340 | 341 | your config: 342 | 343 | ${JSON.stringify(config, null, 2)} 344 | 345 | ----------------------------------------------------- 346 | `), 347 | ); 348 | }; 349 | 350 | export const printIpAddrs = (options: { 351 | host: string | number; 352 | port: string | number; 353 | }) => { 354 | const { host, port } = options; 355 | const nets: any = networkInterfaces(); 356 | const results = []; 357 | 358 | for (const name of Object.keys(nets)) { 359 | for (const net of nets[name]) { 360 | // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses 361 | // 'IPv4' is in Node <= 17, from 18 it's a number 4 or 6 362 | const familyV4Value = typeof net.family === 'string' ? 'IPv4' : 4; 363 | if (net.family === familyV4Value && !net.internal) { 364 | results.push(net.address); 365 | } 366 | } 367 | } 368 | 369 | if (host === '0.0.0.0') { 370 | logger.info( 371 | `\nserver run at:\n${results 372 | .map((i) => `http://${i}:${port}`) 373 | .join('\n')}\n`, 374 | ); 375 | } else { 376 | logger.info(`run at http://${host}:${port}`); 377 | } 378 | }; 379 | -------------------------------------------------------------------------------- /src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 打印客户日志封装 3 | */ 4 | import chalk from 'chalk'; 5 | 6 | const logger = { 7 | info: (...args: any) => { 8 | console.log( 9 | `\n\r[${new Date().toLocaleString()}]`, 10 | chalk.blueBright(...args), 11 | ); 12 | }, 13 | error: (...args: any) => { 14 | console.log( 15 | `\n\r[${new Date().toLocaleString()}] ERROR:`, 16 | chalk.redBright(...args), 17 | ); 18 | }, 19 | }; 20 | 21 | export default logger; 22 | -------------------------------------------------------------------------------- /src/utils/mdInstance.ts: -------------------------------------------------------------------------------- 1 | import markdownIt from 'markdown-it'; 2 | import markdownItAnchor from 'markdown-it-anchor'; 3 | import { slugifyFn } from './index'; 4 | import hljs from 'highlight.js'; 5 | 6 | const mdInstance = markdownIt({ 7 | html: true, 8 | linkify: true, 9 | // 代码高亮 10 | highlight: function (str, lang) { 11 | if (lang && hljs.getLanguage(lang)) { 12 | try { 13 | return hljs.highlight(str, { language: lang }).value; 14 | } catch (_) { 15 | // 16 | } 17 | } 18 | 19 | return ''; 20 | }, 21 | }); 22 | 23 | mdInstance 24 | .use(markdownItAnchor, { 25 | slugify: (s) => slugifyFn(s), 26 | permalink: markdownItAnchor.permalink.headerLink(), 27 | }) 28 | .use(require('markdown-it-sub')) 29 | .use(require('markdown-it-sup')) 30 | .use(require('markdown-it-mark')) 31 | .use(require('markdown-it-attrs')) 32 | .use(require('markdown-it-task-lists')) 33 | .use(require('markdown-it-footnote')) 34 | .use(require('markdown-it-imsize')) 35 | .use(require('markdown-it-image-figures'), { figcaption: true }) 36 | .use(require('markdown-it-container'), 'info') 37 | .use(require('markdown-it-container'), 'note') 38 | .use(require('markdown-it-container'), 'tip') 39 | .use(require('markdown-it-container'), 'warning') 40 | .use(require('markdown-it-container'), 'danger'); 41 | 42 | // a 标签新窗口打开 43 | const defaultRender = 44 | mdInstance.renderer.rules.link_open || 45 | function (tokens, idx, options, env, self) { 46 | return self.renderToken(tokens, idx, options); 47 | }; 48 | 49 | mdInstance.renderer.rules.link_open = function ( 50 | tokens, 51 | idx, 52 | options, 53 | env, 54 | self, 55 | ) { 56 | const targetIndex = tokens[idx].attrIndex('target'); 57 | 58 | if ( 59 | targetIndex < 0 && 60 | !['header-anchor', 'current'].includes(String(tokens[idx].attrGet('class'))) 61 | ) { 62 | tokens[idx].attrPush(['target', '_blank']); 63 | } 64 | 65 | return defaultRender(tokens, idx, options, env, self); 66 | }; 67 | 68 | export default mdInstance; 69 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": "src", 4 | "outDir": "./bin/", 5 | "noEmitOnError": true, 6 | "noUnusedLocals": false, 7 | "esModuleInterop": true, 8 | "noUnusedParameters": false, 9 | "moduleResolution": "node", 10 | "strictPropertyInitialization": false, 11 | "module": "CommonJS", 12 | "strict": true, 13 | "target": "ES5", 14 | "sourceMap": false, 15 | "declaration": false, 16 | "lib": [ 17 | "es2017" 18 | ], 19 | "resolveJsonModule": true, 20 | "importHelpers": true 21 | }, 22 | "include": ["src/**/*.ts"], 23 | "exclude": ["node_modules", "./bin/"] 24 | } 25 | --------------------------------------------------------------------------------