diff --git a/.eslintignore b/.eslintignore index a3b85480f..b9a9017c5 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,4 +2,10 @@ packages/docsify-server-renderer/build.js node_modules build -server.js \ No newline at end of file +server.js +cypress +lib +themes +build +docs/ +**/*.md \ No newline at end of file diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index a8f7cd0c9..000000000 --- a/.eslintrc +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "xo-space/browser", - "rules": { - "semi": [2, "never"], - "no-return-assign": "off", - "no-unused-expressions": "off", - "no-new-func": "off", - "no-multi-assign": "off", - "no-mixed-operators": "off", - "max-params": "off", - "no-script-url": "off", - "camelcase": "off", - "no-warning-comments": "off" - }, - "globals": { - "Docsify": true, - "$docsify": true, - "process": true - } -} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..087ae9e76 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,63 @@ +module.exports = { + root: true, + parser: 'babel-eslint', + parserOptions: { + sourceType: 'module', + ecmaVersion: 2019, + }, + env: { + jest: true, + browser: true, + node: true, + es6: true, + }, + plugins: ['prettier', 'import'], + extends: ['eslint:recommended', 'plugin:import/recommended'], + settings: { + 'import/ignore': ['node_modules', '.json$'], + }, + rules: { + 'prettier/prettier': ['error'], + camelcase: ['warn'], + curly: ['error', 'all'], + 'dot-notation': ['error'], + eqeqeq: ['error'], + 'handle-callback-err': ['error'], + 'new-cap': ['error'], + 'no-alert': ['error'], + 'no-caller': ['error'], + 'no-eval': ['error'], + 'no-labels': ['error'], + 'no-lonely-if': ['error'], + 'no-new': ['error'], + 'no-proto': ['error'], + 'no-return-assign': ['error'], + 'no-self-compare': ['error'], + 'no-shadow': ['warn'], + 'no-shadow-restricted-names': ['error'], + 'no-useless-call': ['error'], + 'no-var': ['error'], + 'no-void': ['error'], + 'no-with': ['error'], + radix: ['error'], + 'spaced-comment': ['error', 'always'], + strict: ['error', 'global'], + yoda: ['error', 'never'], + + // Import rules + // Search way how integrate with `lerna` + 'import/no-unresolved': 'off', + 'import/imports-first': ['error'], + 'import/newline-after-import': ['error'], + 'import/no-duplicates': ['error'], + 'import/no-mutable-exports': ['error'], + 'import/no-named-as-default': ['error'], + 'import/no-named-as-default-member': ['error'], + 'import/order': ['warn'], + }, + globals: { + Docsify: 'writable', + $docsify: 'writable', + dom: 'writable', + }, +}; diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 000000000..3b2c8b180 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,20 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 60 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 +# Issues with these labels will never be considered stale +exemptLabels: + - pinned + - security + - On hold + - enhancement + - bug +# Label to use when marking an issue as stale +staleLabel: wontfix +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 000000000..09fd229fa --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,31 @@ +name: Testing the e2e test suites + +on: + push: + branches: + - master + - develop + pull_request: + branches: + - master + - develop + +jobs: + build: + runs-on: ubuntu-16.04 + strategy: + matrix: + node-version: [10.x, 12.x, 13.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: bootstrap + run: npm run bootstrap + - name: Build + run: npm run build + - name: end to end + run: npm run test:e2e diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..8e40422e8 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,31 @@ +name: Linting Checks + +on: + push: + branches: + - master + - develop + pull_request: + branches: + - master + - develop + +jobs: + build: + runs-on: ubuntu-16.04 + strategy: + matrix: + node-version: [10.x, 12.x, 13.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: bootstrap + run: npm run bootstrap + - name: Build + run: npm run build + - name: Linting + run: npm run lint diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml new file mode 100644 index 000000000..45c001f7a --- /dev/null +++ b/.github/workflows/unit.yml @@ -0,0 +1,31 @@ +name: Unit tests Suite + +on: + push: + branches: + - master + - develop + pull_request: + branches: + - master + - develop + +jobs: + build: + runs-on: ubuntu-16.04 + strategy: + matrix: + node-version: [10.x, 12.x, 13.x] + + steps: + - uses: actions/checkout@v1 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: bootstrap + run: npm run bootstrap + - name: Build + run: npm run build + - name: Unit tests + run: npm run test diff --git a/.gitignore b/.gitignore index ea4b5b805..e9803a96f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ node_modules themes/ lib/ +cypress/integration/examples +cypress/fixtures/docs # exceptions !.gitkeep \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 000000000..a425d3f76 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,4 @@ +module.exports = { + singleQuote: true, + trailingComma: 'es5', +}; diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 87576c5a3..000000000 --- a/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -sudo: false -language: node_js -node_js: stable diff --git a/.vscode/settings.json b/.vscode/settings.json index 9bf4d12b5..65a196532 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,3 @@ { - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true + "editor.defaultFormatter": "esbenp.prettier-vscode" } diff --git a/README.md b/README.md index b8da0d8e5..e6fda5ba4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- docsify + docsify

@@ -10,8 +10,11 @@

Backers on Open Collective - Sponsors on Open Collective - Travis Status + + Sponsors on Open Collective + Unit tests Suite + Linting Checks + Testing the e2e test suites npm donate gitter @@ -107,5 +110,3 @@ This project exists thanks to all the people who contribute. [[Contribute](CONTR ## License [MIT](LICENSE) - -[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fdocsifyjs%2Fdocsify.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fdocsifyjs%2Fdocsify?ref=badge_large) diff --git a/cypress.json b/cypress.json new file mode 100644 index 000000000..60ed5aa53 --- /dev/null +++ b/cypress.json @@ -0,0 +1,3 @@ +{ + "video": false +} diff --git a/cypress/fixtures/tpl/docs.index.html b/cypress/fixtures/tpl/docs.index.html new file mode 100644 index 000000000..94d9526e1 --- /dev/null +++ b/cypress/fixtures/tpl/docs.index.html @@ -0,0 +1,123 @@ + + + + + docsify-e2e-tests + + + + + + + + + + + + + + + +

Loading Docsify e2e tests suite...
+ + + + + + + + + + + + + diff --git a/cypress/integration/sidebar/config.spec.js b/cypress/integration/sidebar/config.spec.js new file mode 100644 index 000000000..4c1b511a7 --- /dev/null +++ b/cypress/integration/sidebar/config.spec.js @@ -0,0 +1,344 @@ +context('sidebar.configurations', () => { + beforeEach(() => { + cy.visit('http://localhost:3000'); + }); + + const quickStartIds = [ + 'initialize', + 'writing-content', + 'preview-your-site', + 'manual-initialization', + 'loading-dialog', + ]; + quickStartIds.forEach(id => { + it('go to #quickstart?id=' + id, () => { + cy.get( + '.sidebar-nav > :nth-child(1) > :nth-child(1) > ul > :nth-child(1) > a' + ).click(); + + cy.get(`a.section-link[href='#/quickstart?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + + const configurationIds = [ + 'el', + 'repo', + 'maxlevel', + 'loadnavbar', + 'loadsidebar', + 'hidesidebar', + 'submaxlevel', + 'auto2top', + 'homepage', + 'basepath', + 'relativepath', + 'coverpage', + 'logo', + 'name', + 'namelink', + 'markdown', + 'themecolor', + 'alias', + 'autoheader', + 'executescript', + 'noemoji', + 'mergenavbar', + 'formatupdated', + 'externallinktarget', + 'cornerexternallinktarget', + 'externallinkrel', + 'routermode', + 'nocompilelinks', + 'onlycover', + 'requestheaders', + 'ext', + 'fallbacklanguages', + 'notfoundpage', + ]; + configurationIds.forEach(id => { + it('go to #configuration?id=' + id, () => { + cy.get('[href="#/configuration"]').click(); + + cy.get(`a.section-link[href='#/configuration?id=${id}']`) + .click() + .then(() => { + cy.wait(500); // its more far from the cover + cy.matchImageSnapshot(); + }); + }); + }); + + const morePagesIds = [ + 'sidebar', + 'nested-sidebars', + 'set-page-titles-from-sidebar-selection', + 'table-of-contents', + 'ignoring-subheaders', + ]; + morePagesIds.forEach(id => { + it('go to #more-pages?id=' + id, () => { + cy.get('[href="#/more-pages"]').click(); + + cy.get(`a.section-link[href='#/more-pages?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + + const customNavbarIds = [ + 'html', + 'markdown', + 'nesting', + 'combining-custom-navbars-with-the-emoji-plugin', + ]; + customNavbarIds.forEach(id => { + it('go to #custom-navbar?id=' + id, () => { + cy.get('[href="#/custom-navbar"]').click(); + + cy.get(`a.section-link[href='#/custom-navbar?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + + const coverIds = [ + 'basic-usage', + 'custom-background', + 'coverpage-as-homepage', + 'multiple-covers', + ]; + coverIds.forEach(id => { + it('go to #cover?id=' + id, () => { + cy.get('[href="#/cover"]').click(); + + cy.get(`a.section-link[href='#/cover?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + + const themesIds = ['other-themes']; + themesIds.forEach(id => { + it('go to #themes?id=' + id, () => { + cy.get('[href="#/themes"]').click(); + + cy.get(`a.section-link[href='#/themes?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + + const pluginsIds = [ + 'full-text-search', + 'google-analytics', + 'emoji', + 'external-script', + 'zoom-image', + 'edit-on-github', + 'demo-code-with-instant-preview-and-jsfiddle-integration', + 'copy-to-clipboard', + 'disqus', + 'gitalk', + 'pagination', + 'codefund', + 'tabs', + 'more-plugins', + ]; + pluginsIds.forEach(id => { + it('go to #plugins?id=' + id, () => { + cy.get('[href="#/plugins"]').click(); + + cy.get(`a.section-link[href='#/plugins?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + + const writeAPluginIds = ['full-configuration', 'example', 'tips']; + writeAPluginIds.forEach(id => { + it('go to #write-a-plugin?id=' + id, () => { + cy.get('[href="#/write-a-plugin"]').click(); + + cy.get(`a.section-link[href='#/write-a-plugin?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + + const markdownIds = ['supports-mermaid']; + markdownIds.forEach(id => { + it('go to #markdown?id=' + id, () => { + cy.get('[href="#/markdown"]').click(); + + cy.get(`a.section-link[href='#/markdown?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + + it('go to #Language-highlight', () => { + cy.get('a[href="#/language-highlight"]') + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + + // const deployIds = [ + // 'github-pages', + // 'gitlab-pages', + // 'firebase-hosting', + // 'vps', + // 'netlify', + // 'zeit-now', + // 'aws-amplify' + // ] + // deployIds.forEach(id => { + // it('go to #deploy?id=' + id, () => { + // cy.get('[href="#/deploy"]').click() + + // cy.get(`a.section-link[href='#/deploy?id=${id}']`) + // .click() + // .then(() => { + // cy.wait(500) + // cy.matchImageSnapshot() + // }) + // }) + // }) + + const helpersIds = [ + 'important-content', + 'general-tips', + 'ignore-to-compile-link', + 'set-target-attribute-for-link', + 'disable-link', + 'github-task-lists', + 'customise-id-for-headings', + 'markdown-in-html-tag', + ]; + helpersIds.forEach(id => { + it('go to #helpers?id=' + id, () => { + cy.get('[href="#/helpers"]').click(); + + cy.get(`a.section-link[href='#/helpers?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + + const vueIds = ['basic-usage', 'combine-vuep-to-write-playground']; + vueIds.forEach(id => { + it('go to #vue?id=' + id, () => { + cy.get('[href="#/vue"]').click(); + + cy.get(`a.section-link[href='#/vue?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + + const cdnIds = [ + 'latest-version', + 'specific-version', + 'compressed-file', + 'other-cdn', + ]; + cdnIds.forEach(id => { + it('go to #cdn?id=' + id, () => { + cy.get('[href="#/cdn"]').click(); + + cy.get(`a.section-link[href='#/cdn?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + + const pwaIds = ['create-serviceworker', 'register', 'enjoy-it']; + pwaIds.forEach(id => { + it('go to #pwa?id=' + id, () => { + cy.get('[href="#/pwa"]').click(); + + cy.get(`a.section-link[href='#/pwa?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + + const ssrIds = [ + 'why-ssr', + 'quick-start', + 'custom-template', + 'configuration', + 'deploy-for-your-vps', + ]; + + ssrIds.forEach(id => { + it('go to #ssr?id=' + id, () => { + cy.get('[href="#/ssr"]').click(); + + cy.get(`a.section-link[href='#/ssr?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); + const embedFilesIds = [ + 'embedded-file-type', + 'embedded-code-fragments', + 'tag-attribute', + 'the-code-block-highlight', + ]; + embedFilesIds.forEach(id => { + it('go to #embed-files?id=' + id, () => { + cy.get('[href="#/embed-files"]').click(); + + cy.get(`a.section-link[href='#/embed-files?id=${id}']`) + .click() + .then(() => { + cy.wait(500); + cy.matchImageSnapshot(); + }); + }); + }); +}); diff --git a/cypress/live.server.js b/cypress/live.server.js new file mode 100644 index 000000000..bb22b8f07 --- /dev/null +++ b/cypress/live.server.js @@ -0,0 +1,13 @@ +const path = require('path') +const LiveServer = require('live-server') + +const fixturePath = path.join(__dirname, './fixtures/docs') +const args = process.argv.slice(2) +console.log('[e2e tests] : args passed to live server', args) +const params = { + port: args[0] || 3000, + root: args[1] || fixturePath, + open: false + // NoBrowser: true +} +LiveServer.start(params) diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js new file mode 100644 index 000000000..aebcffbd7 --- /dev/null +++ b/cypress/plugins/index.js @@ -0,0 +1,18 @@ +// *********************************************************** +// This example plugins/index.js can be used to load plugins +// +// You can change the location of this file or turn off loading +// the plugins file with the 'pluginsFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/plugins-guide +// *********************************************************** + +// This function is called when a project is opened or re-opened (e.g. due to +// the project's config changing) +const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin') +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config + addMatchImageSnapshotPlugin(on, config) +} diff --git a/cypress/setup.js b/cypress/setup.js new file mode 100644 index 000000000..6372ff347 --- /dev/null +++ b/cypress/setup.js @@ -0,0 +1,75 @@ +const copyDir = require('copy-dir') +const path = require('path') +const fs = require('fs') +const { spawn } = require('child_process') + +const setup = async () => { + const PORT = process.env.PORT || 3000 + global.__LIVESERVER__ = null + global.PORT = PORT + + /** + * IN this test suite, we are going to test our docs site with all the css,js linked to our local build packages + * + * 1.1 Copy ../docs --> ./fixtures/docs + * 1.2 copy lib,themes --> ./fixtures/ + * 2. change the content of fixtures/docs/index.html to use all the links from our local build + * 3. now jest runner will run to test all the *.spec.js files + * + */ + + const shippedDirs = ['lib', 'themes'] + + // 1 + const docsPath = path.join(process.cwd(), './docs') + const fixtureDocsPath = path.join(__dirname, './fixtures/docs') + + // 1.1 + console.log('[cypress test docs] Copying the docs --> cypress/fixtures/docs') + copyDir.sync(docsPath, fixtureDocsPath) + + // 1.2 + shippedDirs.forEach(dir => { + const fromPath = path.join(process.cwd(), dir) + const toPath = path.join(__dirname, `./fixtures/docs/${dir}`) + console.log( + `[cypress test docs] Copying ${dir} --> cypress/fixtures/docs/${dir}` + ) + copyDir.sync(fromPath, toPath) + }) + + // 2 + console.log( + '[cypress test docs] Replacing content the tpl/index.html --> cypress/fixtures/docs/index.html' + ) + const indexHTMLtplPath = path.join( + __dirname, + './fixtures/tpl/docs.index.html' + ) + const fixtureIndexPath = path.join(__dirname, './fixtures/docs/index.html') + const data = fs.readFileSync(indexHTMLtplPath, 'utf8') + + // 3 + const fixturePath = path.join(__dirname, './fixtures/docs') + + fs.writeFileSync(fixtureIndexPath, data, 'utf8') + const child = spawn('node', [ + path.join(__dirname, './live.server.js'), + PORT, + fixturePath + ]) + child.on('exit', code => { + console.log(`Child process exited with code ${code}`) + }) + child.stdout.on('data', data => { + console.log(`stdout: ${data}`) + }) + child.stderr.on('data', data => { + console.log(`stderr: ${data}`) + }) + + // LiveServer.start(params) + global.__LIVESERVER__ = child +} + +setup() diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #Language-highlight.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #Language-highlight.snap.png new file mode 100644 index 000000000..c39f80f1a Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #Language-highlight.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=compressed-file.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=compressed-file.snap.png new file mode 100644 index 000000000..fa2acf15f Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=compressed-file.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=latest-version.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=latest-version.snap.png new file mode 100644 index 000000000..1ef50abe8 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=latest-version.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=other-cdn.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=other-cdn.snap.png new file mode 100644 index 000000000..2193959a0 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=other-cdn.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=specific-version.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=specific-version.snap.png new file mode 100644 index 000000000..04e364cf3 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #cdnid=specific-version.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=alias.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=alias.snap.png new file mode 100644 index 000000000..aaa0ed544 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=alias.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=auto2top.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=auto2top.snap.png new file mode 100644 index 000000000..2ac6312cd Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=auto2top.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=autoheader.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=autoheader.snap.png new file mode 100644 index 000000000..779f27af3 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=autoheader.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=basepath.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=basepath.snap.png new file mode 100644 index 000000000..da2c844d8 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=basepath.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=cornerexternallinktarget.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=cornerexternallinktarget.snap.png new file mode 100644 index 000000000..c41b09bbe Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=cornerexternallinktarget.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=coverpage.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=coverpage.snap.png new file mode 100644 index 000000000..3c05b08b0 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=coverpage.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=el.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=el.snap.png new file mode 100644 index 000000000..d9982b684 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=el.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=executescript.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=executescript.snap.png new file mode 100644 index 000000000..48ca3772a Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=executescript.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=ext.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=ext.snap.png new file mode 100644 index 000000000..21f3e0e01 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=ext.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=externallinkrel.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=externallinkrel.snap.png new file mode 100644 index 000000000..52f1f0149 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=externallinkrel.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=externallinktarget.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=externallinktarget.snap.png new file mode 100644 index 000000000..797a914b0 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=externallinktarget.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=fallbacklanguages.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=fallbacklanguages.snap.png new file mode 100644 index 000000000..cdb789fcc Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=fallbacklanguages.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=formatupdated.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=formatupdated.snap.png new file mode 100644 index 000000000..b8e49a654 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=formatupdated.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=hidesidebar.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=hidesidebar.snap.png new file mode 100644 index 000000000..cbc01ef90 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=hidesidebar.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=homepage.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=homepage.snap.png new file mode 100644 index 000000000..b2adecfc9 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=homepage.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=loadnavbar.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=loadnavbar.snap.png new file mode 100644 index 000000000..71f703d11 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=loadnavbar.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=loadsidebar.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=loadsidebar.snap.png new file mode 100644 index 000000000..50485725b Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=loadsidebar.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=logo.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=logo.snap.png new file mode 100644 index 000000000..bae3433a7 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=logo.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=markdown.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=markdown.snap.png new file mode 100644 index 000000000..4685abd7d Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=markdown.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=maxlevel.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=maxlevel.snap.png new file mode 100644 index 000000000..9446381a7 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=maxlevel.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=mergenavbar.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=mergenavbar.snap.png new file mode 100644 index 000000000..a34d06cd0 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=mergenavbar.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=name.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=name.snap.png new file mode 100644 index 000000000..013977a49 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=name.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=namelink.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=namelink.snap.png new file mode 100644 index 000000000..ae20a5ddb Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=namelink.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=nocompilelinks.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=nocompilelinks.snap.png new file mode 100644 index 000000000..619704cbe Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=nocompilelinks.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=noemoji.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=noemoji.snap.png new file mode 100644 index 000000000..321a77e2f Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=noemoji.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=notfoundpage.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=notfoundpage.snap.png new file mode 100644 index 000000000..6ccfef833 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=notfoundpage.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=onlycover.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=onlycover.snap.png new file mode 100644 index 000000000..3c5937436 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=onlycover.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=relativepath.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=relativepath.snap.png new file mode 100644 index 000000000..16c7a96ab Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=relativepath.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=repo.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=repo.snap.png new file mode 100644 index 000000000..8e5cd6c7d Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=repo.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=requestheaders.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=requestheaders.snap.png new file mode 100644 index 000000000..eda49e1ec Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=requestheaders.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=routermode.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=routermode.snap.png new file mode 100644 index 000000000..744b49515 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=routermode.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=submaxlevel.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=submaxlevel.snap.png new file mode 100644 index 000000000..19bf00e35 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=submaxlevel.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=themecolor.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=themecolor.snap.png new file mode 100644 index 000000000..0ae49f942 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #configurationid=themecolor.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=basic-usage.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=basic-usage.snap.png new file mode 100644 index 000000000..debcf6e2c Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=basic-usage.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=coverpage-as-homepage.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=coverpage-as-homepage.snap.png new file mode 100644 index 000000000..51751720f Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=coverpage-as-homepage.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=custom-background.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=custom-background.snap.png new file mode 100644 index 000000000..17a306e13 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=custom-background.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=multiple-covers.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=multiple-covers.snap.png new file mode 100644 index 000000000..354dd3b69 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #coverid=multiple-covers.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=combining-custom-navbars-with-the-emoji-plugin.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=combining-custom-navbars-with-the-emoji-plugin.snap.png new file mode 100644 index 000000000..2fe604473 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=combining-custom-navbars-with-the-emoji-plugin.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=html.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=html.snap.png new file mode 100644 index 000000000..87d117c52 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=html.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=markdown.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=markdown.snap.png new file mode 100644 index 000000000..e31a5840f Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=markdown.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=nesting.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=nesting.snap.png new file mode 100644 index 000000000..60effa6b9 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #custom-navbarid=nesting.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=embedded-code-fragments.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=embedded-code-fragments.snap.png new file mode 100644 index 000000000..f8e05430c Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=embedded-code-fragments.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=embedded-file-type.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=embedded-file-type.snap.png new file mode 100644 index 000000000..702af8421 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=embedded-file-type.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=tag-attribute.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=tag-attribute.snap.png new file mode 100644 index 000000000..8b4ee81a1 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=tag-attribute.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=the-code-block-highlight.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=the-code-block-highlight.snap.png new file mode 100644 index 000000000..682642579 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #embed-filesid=the-code-block-highlight.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=customise-id-for-headings.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=customise-id-for-headings.snap.png new file mode 100644 index 000000000..8f03a0760 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=customise-id-for-headings.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=disable-link.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=disable-link.snap.png new file mode 100644 index 000000000..a6a717d33 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=disable-link.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=general-tips.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=general-tips.snap.png new file mode 100644 index 000000000..3e0e3f178 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=general-tips.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=github-task-lists.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=github-task-lists.snap.png new file mode 100644 index 000000000..02770c0ed Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=github-task-lists.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=ignore-to-compile-link.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=ignore-to-compile-link.snap.png new file mode 100644 index 000000000..8e7074c26 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=ignore-to-compile-link.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=important-content.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=important-content.snap.png new file mode 100644 index 000000000..d8ac2fa35 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=important-content.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=markdown-in-html-tag.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=markdown-in-html-tag.snap.png new file mode 100644 index 000000000..842a27530 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=markdown-in-html-tag.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=set-target-attribute-for-link.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=set-target-attribute-for-link.snap.png new file mode 100644 index 000000000..962347631 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #helpersid=set-target-attribute-for-link.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #markdownid=supports-mermaid.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #markdownid=supports-mermaid.snap.png new file mode 100644 index 000000000..25a0244fe Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #markdownid=supports-mermaid.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=ignoring-subheaders.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=ignoring-subheaders.snap.png new file mode 100644 index 000000000..d94e8ff6d Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=ignoring-subheaders.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=nested-sidebars.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=nested-sidebars.snap.png new file mode 100644 index 000000000..726d86bf6 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=nested-sidebars.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=set-page-titles-from-sidebar-selection.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=set-page-titles-from-sidebar-selection.snap.png new file mode 100644 index 000000000..aca69af3f Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=set-page-titles-from-sidebar-selection.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=sidebar.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=sidebar.snap.png new file mode 100644 index 000000000..3e3ec1552 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=sidebar.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=table-of-contents.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=table-of-contents.snap.png new file mode 100644 index 000000000..9d011dd48 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #more-pagesid=table-of-contents.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=codefund.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=codefund.snap.png new file mode 100644 index 000000000..2e59a75b1 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=codefund.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=copy-to-clipboard.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=copy-to-clipboard.snap.png new file mode 100644 index 000000000..4b16c2317 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=copy-to-clipboard.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=demo-code-with-instant-preview-and-jsfiddle-integration.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=demo-code-with-instant-preview-and-jsfiddle-integration.snap.png new file mode 100644 index 000000000..6d38a0be9 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=demo-code-with-instant-preview-and-jsfiddle-integration.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=disqus.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=disqus.snap.png new file mode 100644 index 000000000..a44c2de01 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=disqus.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=edit-on-github.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=edit-on-github.snap.png new file mode 100644 index 000000000..d39fd6180 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=edit-on-github.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=emoji.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=emoji.snap.png new file mode 100644 index 000000000..a7333e856 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=emoji.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=external-script.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=external-script.snap.png new file mode 100644 index 000000000..c47986174 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=external-script.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=full-text-search.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=full-text-search.snap.png new file mode 100644 index 000000000..7205b155e Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=full-text-search.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=gitalk.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=gitalk.snap.png new file mode 100644 index 000000000..3b041be20 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=gitalk.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=google-analytics.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=google-analytics.snap.png new file mode 100644 index 000000000..411faa937 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=google-analytics.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=more-plugins.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=more-plugins.snap.png new file mode 100644 index 000000000..3ef52aa51 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=more-plugins.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=pagination.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=pagination.snap.png new file mode 100644 index 000000000..4f007a4ca Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=pagination.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=tabs.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=tabs.snap.png new file mode 100644 index 000000000..1bcb05baf Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=tabs.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=zoom-image.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=zoom-image.snap.png new file mode 100644 index 000000000..e54fac3c8 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pluginsid=zoom-image.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=create-serviceworker.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=create-serviceworker.snap.png new file mode 100644 index 000000000..b90a0e883 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=create-serviceworker.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=enjoy-it.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=enjoy-it.snap.png new file mode 100644 index 000000000..72521e0e5 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=enjoy-it.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=register.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=register.snap.png new file mode 100644 index 000000000..2ddcc370f Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #pwaid=register.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=initialize.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=initialize.snap.png new file mode 100644 index 000000000..295545618 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=initialize.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=loading-dialog.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=loading-dialog.snap.png new file mode 100644 index 000000000..0b770801f Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=loading-dialog.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=manual-initialization.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=manual-initialization.snap.png new file mode 100644 index 000000000..8fd07268f Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=manual-initialization.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=preview-your-site.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=preview-your-site.snap.png new file mode 100644 index 000000000..f455bc5c8 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=preview-your-site.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=writing-content.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=writing-content.snap.png new file mode 100644 index 000000000..1c33262e1 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #quickstartid=writing-content.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=configuration.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=configuration.snap.png new file mode 100644 index 000000000..0dde65b3c Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=configuration.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=custom-template.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=custom-template.snap.png new file mode 100644 index 000000000..e47a8c8f8 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=custom-template.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=deploy-for-your-vps.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=deploy-for-your-vps.snap.png new file mode 100644 index 000000000..1960a4f47 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=deploy-for-your-vps.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=quick-start.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=quick-start.snap.png new file mode 100644 index 000000000..1cbcfa138 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=quick-start.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=why-ssr.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=why-ssr.snap.png new file mode 100644 index 000000000..5a228ed17 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #ssrid=why-ssr.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #themesid=other-themes.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #themesid=other-themes.snap.png new file mode 100644 index 000000000..2bf44b529 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #themesid=other-themes.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #vueid=basic-usage.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #vueid=basic-usage.snap.png new file mode 100644 index 000000000..094800a70 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #vueid=basic-usage.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #vueid=combine-vuep-to-write-playground.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #vueid=combine-vuep-to-write-playground.snap.png new file mode 100644 index 000000000..10bd8d6e9 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #vueid=combine-vuep-to-write-playground.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=example.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=example.snap.png new file mode 100644 index 000000000..7408c6a19 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=example.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=full-configuration.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=full-configuration.snap.png new file mode 100644 index 000000000..75bd8bb57 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=full-configuration.snap.png differ diff --git a/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=tips.snap.png b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=tips.snap.png new file mode 100644 index 000000000..889ee9d01 Binary files /dev/null and b/cypress/snapshots/sidebar/config.spec.js/sidebar.configurations -- go to #write-a-pluginid=tips.snap.png differ diff --git a/cypress/support/commands.js b/cypress/support/commands.js new file mode 100644 index 000000000..3e9454afa --- /dev/null +++ b/cypress/support/commands.js @@ -0,0 +1,41 @@ +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add("login", (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) + +import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command' +addMatchImageSnapshotCommand({ + failureThreshold: 10.0, + failureThresholdType: 'percent', + customDiffConfig: { threshold: 10.0 }, + capture: 'viewport', + timeout: '60000' +}) +Cypress.Commands.add('setResolution', size => { + if (Cypress._.isArray(size)) { + cy.viewport(size[0], size[1]) + } else { + cy.viewport(size) + } +}) diff --git a/cypress/support/index.js b/cypress/support/index.js new file mode 100644 index 000000000..d68db96df --- /dev/null +++ b/cypress/support/index.js @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/docs/_media/example.js b/docs/_media/example.js index 7b6f668cc..8cad2d730 100644 --- a/docs/_media/example.js +++ b/docs/_media/example.js @@ -5,12 +5,12 @@ const PORT = 8080 /// [demo] const result = fetch(`${URL}:${PORT}`) - .then(function(response) { - return response.json(); + .then(function (response) { + return response.json() + }) + .then(function (myJson) { + console.log(JSON.stringify(myJson)) }) - .then(function(myJson) { - console.log(JSON.stringify(myJson)); - }); /// [demo] result.then(console.log).catch(console.error) diff --git a/docs/cdn.md b/docs/cdn.md index eba77a845..82b2d2d90 100644 --- a/docs/cdn.md +++ b/docs/cdn.md @@ -1,15 +1,15 @@ # CDN -Recommended: [unpkg](//unpkg.com), which will reflect the latest version as soon as it is published to npm. You can also browse the source of the npm package at [unpkg.com/docsify/](//unpkg.com/docsify/). +Recommended: [jsDelivr](//cdn.jsdelivr.net), which will reflect the latest version as soon as it is published to npm. You can also browse the source of the npm package at [cdn.jsdelivr.net/npm/docsify/](//cdn.jsdelivr.net/npm/docsify/). ## Latest version ```html - + - + ``` Alternatively, use [compressed files](#compressed-file). @@ -18,28 +18,28 @@ Alternatively, use [compressed files](#compressed-file). ```html - + - + ``` ## Compressed file ```html - + - + ``` ```html - + - + ``` ## Other CDN diff --git a/docs/configuration.md b/docs/configuration.md index bcbe2e0de..11797c794 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -7,8 +7,8 @@ You can configure the `window.$docsify`. window.$docsify = { repo: 'docsifyjs/docsify', maxLevel: 3, - coverpage: true - } + coverpage: true, + }; ``` @@ -21,7 +21,7 @@ The DOM element to be mounted on initialization. It can be a CSS selector string ```js window.$docsify = { - el: '#app' + el: '#app', }; ``` @@ -36,7 +36,7 @@ Configure the repository url or a string of `username/repo` can add the [GitHub window.$docsify = { repo: 'docsifyjs/docsify', // or - repo: 'https://github.com/docsifyjs/docsify/' + repo: 'https://github.com/docsifyjs/docsify/', }; ``` @@ -49,7 +49,7 @@ Maximum Table of content level. ```js window.$docsify = { - maxLevel: 4 + maxLevel: 4, }; ``` @@ -66,7 +66,7 @@ window.$docsify = { loadNavbar: true, // load from nav.md - loadNavbar: 'nav.md' + loadNavbar: 'nav.md', }; ``` @@ -83,7 +83,20 @@ window.$docsify = { loadSidebar: true, // load from summary.md - loadSidebar: 'summary.md' + loadSidebar: 'summary.md', +}; +``` + +## hideSidebar + +- Type : `Boolean` +- Default: `true` + +This option will completely hide your sidebar and wont render any content of the side even . + +```js +window.$docsify = { + hideSidebar: true, }; ``` @@ -96,7 +109,7 @@ Add table of contents (TOC) in custom sidebar. ```js window.$docsify = { - subMaxLevel: 2 + subMaxLevel: 2, }; ``` @@ -109,7 +122,7 @@ Scrolls to the top of the screen when the route is changed. ```js window.$docsify = { - auto2top: true + auto2top: true, }; ``` @@ -127,7 +140,7 @@ window.$docsify = { // Or use the readme in your repo homepage: - 'https://raw.githubusercontent.com/docsifyjs/docsify/master/README.md' + 'https://raw.githubusercontent.com/docsifyjs/docsify/master/README.md', }; ``` @@ -146,7 +159,7 @@ window.$docsify = { // Even can load files from other repo basePath: - 'https://raw.githubusercontent.com/ryanmcdermott/clean-code-javascript/master/' + 'https://raw.githubusercontent.com/ryanmcdermott/clean-code-javascript/master/', }; ``` @@ -186,7 +199,7 @@ window.$docsify = { relativePath: true, // Relative path disabled (default value) - relativePath: false + relativePath: false, }; ``` @@ -210,8 +223,8 @@ window.$docsify = { // mutiple covers and custom file name coverpage: { '/': 'cover.md', - '/zh-cn/': 'cover.md' - } + '/zh-cn/': 'cover.md', + }, }; ``` @@ -223,7 +236,7 @@ Website logo as it appears in the sidebar, you can resize by CSS. ```js window.$docsify = { - logo: '/_media/icon.svg' + logo: '/_media/icon.svg', }; ``` @@ -235,7 +248,15 @@ Website name as it appears in the sidebar. ```js window.$docsify = { - name: 'docsify' + name: 'docsify', +}; +``` + +The name field can also contain custom HTML for easier customization: + +```js +window.$docsify = { + name: 'docsify', }; ``` @@ -253,8 +274,8 @@ window.$docsify = { // For each route nameLink: { '/zh-cn/': '/zh-cn/', - '/': '/' - } + '/': '/', + }, }; ``` @@ -272,15 +293,15 @@ window.$docsify = { renderer: { link: function() { // ... - } - } + }, + }, }, // function markdown: function(marked, renderer) { // ... return marked; - } + }, }; ``` @@ -292,7 +313,7 @@ Customize the theme color. Use [CSS3 variables](https://developer.mozilla.org/en ```js window.$docsify = { - themeColor: '#3F51B5' + themeColor: '#3F51B5', }; ``` @@ -309,8 +330,8 @@ window.$docsify = { '/zh-cn/changelog': '/changelog', '/changelog': 'https://raw.githubusercontent.com/docsifyjs/docsify/master/CHANGELOG', - '/.*/_sidebar.md': '/_sidebar.md' // See #301 - } + '/.*/_sidebar.md': '/_sidebar.md', // See #301 + }, }; ``` @@ -323,7 +344,7 @@ If `loadSidebar` and `autoHeader` are both enabled, for each link in `_sidebar.m ```js window.$docsify = { loadSidebar: true, - autoHeader: true + autoHeader: true, }; ``` @@ -335,7 +356,7 @@ Execute the script on the page. Only parse the first script tag([demo](themes)). ```js window.$docsify = { - executeScript: true + executeScript: true, }; ``` @@ -357,10 +378,12 @@ Disabled emoji parse. ```js window.$docsify = { - noEmoji: true + noEmoji: true, }; ``` +?> If this options is `false` but you dont want to emojify some specific colons , [Refer this](https://github.com/docsifyjs/docsify/issues/742#issuecomment-586313143) + ## mergeNavbar - type: `Boolean` @@ -369,7 +392,7 @@ Navbar will be merged with the sidebar on smaller screens. ```js window.$docsify = { - mergeNavbar: true + mergeNavbar: true, }; ``` @@ -388,7 +411,7 @@ window.$docsify = { // ... return time; - } + }, }; ``` @@ -401,7 +424,7 @@ Target to open external links inside the markdown. Default `'_blank'` (new windo ```js window.$docsify = { - externalLinkTarget: '_self' // default: '_blank' + externalLinkTarget: '_self', // default: '_blank' }; ``` @@ -414,7 +437,7 @@ Target to open external link at the top right corner. Default `'_blank'` (new wi ```js window.$docsify = { - cornerExternalLinkTarget: '_self' // default: '_blank' + cornerExternalLinkTarget: '_self', // default: '_blank' }; ``` @@ -427,7 +450,7 @@ Default `'noopener'` (no opener) prevents the newly opened external page (when [ ```js window.$docsify = { - externalLinkTarget: '' // default: 'noopener' + externalLinkTarget: '', // default: 'noopener' }; ``` @@ -438,7 +461,7 @@ window.$docsify = { ```js window.$docsify = { - routerMode: 'history' // default: 'hash' + routerMode: 'history', // default: 'hash' }; ``` @@ -450,7 +473,7 @@ Sometimes we do not want docsify to handle our links. See [#203](https://github. ```js window.$docsify = { - noCompileLinks: ['/foo', '/bar/.*'] + noCompileLinks: ['/foo', '/bar/.*'], }; ``` @@ -462,7 +485,7 @@ Only coverpage is loaded when visiting the home page. ```js window.$docsify = { - onlyCover: false + onlyCover: false, }; ``` @@ -475,8 +498,18 @@ Set the request resource headers. ```js window.$docsify = { requestHeaders: { - 'x-token': 'xxx' - } + 'x-token': 'xxx', + }, +}; +``` + +Such as setting the cache + +```js +window.$docsify = { + requestHeaders: { + 'cache-control': 'max-age=600', + }, }; ``` @@ -488,7 +521,7 @@ Request file extension. ```js window.$docsify = { - ext: '.md' + ext: '.md', }; ``` @@ -506,7 +539,7 @@ Example: ```js window.$docsify = { - fallbackLanguages: ['fr', 'de'] + fallbackLanguages: ['fr', 'de'], }; ``` @@ -518,7 +551,7 @@ Load the `_404.md` file: ```js window.$docsify = { - notFoundPage: true + notFoundPage: true, }; ``` @@ -526,7 +559,7 @@ Load the customised path of the 404 page: ```js window.$docsify = { - notFoundPage: 'my404.md' + notFoundPage: 'my404.md', }; ``` @@ -536,9 +569,22 @@ Load the right 404 page according to the localisation: window.$docsify = { notFoundPage: { '/': '_404.md', - '/de': 'de/_404.md' - } + '/de': 'de/_404.md', + }, }; ``` > Note: The options with fallbackLanguages didn't work with the `notFoundPage` options. + +## topMargin + +- type: `Number` +- default: `0` + +Adds a space on top when scrolling content page to reach the selected section. This is useful in case you have a _sticky-header_ layout and you want to align anchors to the end of your header. + +```js +window.$docsify = { + topMargin: 90, // default: 0 +}; +``` \ No newline at end of file diff --git a/docs/cover.md b/docs/cover.md index 555f4ff7a..878747a7e 100644 --- a/docs/cover.md +++ b/docs/cover.md @@ -14,7 +14,7 @@ Set `coverpage` to **true**, and create a `_coverpage.md`: coverpage: true } - + ``` ```markdown diff --git a/docs/custom-navbar.md b/docs/custom-navbar.md index 324ad8104..14b6c8b3b 100644 --- a/docs/custom-navbar.md +++ b/docs/custom-navbar.md @@ -30,7 +30,7 @@ Alternatively, you can create a custom markdown-based navigation file by setting loadNavbar: true } - + ``` ```markdown @@ -82,8 +82,8 @@ If you use the [emoji plugin](plugins#emoji): // ... } - - + + ``` you could, for example, use flag emojis in your custom navbar Markdown file: diff --git a/docs/deploy.md b/docs/deploy.md index 6bfe90445..d68b5c9dc 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -128,9 +128,10 @@ frontend: ``` -6. Add the following Redirect rules in their displayed order. +6. Add the following Redirect rules in their displayed order. Note that the second record is a PNG image where you can change it with any image format you are using. | Source address | Target address | Type | |----------------|----------------|---------------| | /<*>.md | /<*>.md | 200 (Rewrite) | +| /<*>.png | /<*>.png | 200 (Rewrite) | | /<*> | /index.html | 200 (Rewrite) | diff --git a/docs/helpers.md b/docs/helpers.md index b047d3673..83c59784a 100644 --- a/docs/helpers.md +++ b/docs/helpers.md @@ -2,6 +2,8 @@ docsify extends Markdown syntax to make your documents more readable. +> Note: For the special code syntax cases, you'd better put them within a code backticks to avoid any conflicting from configurations or emojis. + ## important content Important content like: @@ -81,9 +83,12 @@ You will get `link`html. Do not worry, you can still set ti - [ ] bim - [ ] lim -## Image resizing +## Image + +### Resizing ```md +![logo](https://docsify.js.org/_media/icon.svg ':size=WIDTHxHEIGHT') ![logo](https://docsify.js.org/_media/icon.svg ':size=50x100') ![logo](https://docsify.js.org/_media/icon.svg ':size=100') @@ -96,6 +101,18 @@ You will get `link`html. Do not worry, you can still set ti ![logo](https://docsify.js.org/_media/icon.svg ':size=100') ![logo](https://docsify.js.org/_media/icon.svg ':size=10%') +### Customise class + +```md +![logo](https://docsify.js.org/_media/icon.svg ':class=someCssClass') +``` + +### Customise ID + +```md +![logo](https://docsify.js.org/_media/icon.svg ':id=someCssId') +``` + ## Customise ID for headings ```md diff --git a/docs/index.html b/docs/index.html index 6d0e008b2..39c32b814 100644 --- a/docs/index.html +++ b/docs/index.html @@ -10,11 +10,13 @@ - - - - - + + + + + + + ` + return ``; } diff --git a/src/core/router/history/abstract.js b/src/core/router/history/abstract.js index 2c0bd951d..02881f165 100644 --- a/src/core/router/history/abstract.js +++ b/src/core/router/history/abstract.js @@ -1,25 +1,25 @@ -import {History} from './base' -import {parseQuery} from '../util' +import { parseQuery } from '../util'; +import { History } from './base'; export class AbstractHistory extends History { constructor(config) { - super(config) - this.mode = 'abstract' + super(config); + this.mode = 'abstract'; } parse(path) { - let query = '' + let query = ''; - const queryIndex = path.indexOf('?') + const queryIndex = path.indexOf('?'); if (queryIndex >= 0) { - query = path.slice(queryIndex + 1) - path = path.slice(0, queryIndex) + query = path.slice(queryIndex + 1); + path = path.slice(0, queryIndex); } return { path, file: this.getFile(path), - query: parseQuery(query) - } + query: parseQuery(query), + }; } } diff --git a/src/core/router/history/base.js b/src/core/router/history/base.js index 7ea763d8d..68c98b7f5 100644 --- a/src/core/router/history/base.js +++ b/src/core/router/history/base.js @@ -4,57 +4,59 @@ import { stringifyQuery, cleanPath, replaceSlug, - resolvePath -} from '../util' -import {noop, merge} from '../../util/core' + resolvePath, +} from '../util'; +import { noop, merge } from '../../util/core'; -const cached = {} +const cached = {}; function getAlias(path, alias, last) { const match = Object.keys(alias).filter(key => { - const re = cached[key] || (cached[key] = new RegExp(`^${key}$`)) - return re.test(path) && path !== last - })[0] + const re = cached[key] || (cached[key] = new RegExp(`^${key}$`)); + return re.test(path) && path !== last; + })[0]; - return match ? - getAlias(path.replace(cached[match], alias[match]), alias, path) : - path + return match + ? getAlias(path.replace(cached[match], alias[match]), alias, path) + : path; } function getFileName(path, ext) { - return new RegExp(`\\.(${ext.replace(/^\./, '')}|html)$`, 'g').test(path) ? - path : - /\/$/g.test(path) ? `${path}README${ext}` : `${path}${ext}` + return new RegExp(`\\.(${ext.replace(/^\./, '')}|html)$`, 'g').test(path) + ? path + : /\/$/g.test(path) + ? `${path}README${ext}` + : `${path}${ext}`; } export class History { constructor(config) { - this.config = config + this.config = config; } getBasePath() { - return this.config.basePath + return this.config.basePath; } getFile(path = this.getCurrentPath(), isRelative) { - const {config} = this - const base = this.getBasePath() - const ext = typeof config.ext === 'string' ? config.ext : '.md' + const { config } = this; + const base = this.getBasePath(); + const ext = typeof config.ext === 'string' ? config.ext : '.md'; - path = config.alias ? getAlias(path, config.alias) : path - path = getFileName(path, ext) - path = path === `/README${ext}` ? config.homepage || path : path - path = isAbsolutePath(path) ? path : getPath(base, path) + path = config.alias ? getAlias(path, config.alias) : path; + path = getFileName(path, ext); + path = path === `/README${ext}` ? config.homepage || path : path; + path = isAbsolutePath(path) ? path : getPath(base, path); if (isRelative) { - path = path.replace(new RegExp(`^${base}`), '') + path = path.replace(new RegExp(`^${base}`), ''); } - return path + return path; } onchange(cb = noop) { - cb() + cb(); } getCurrentPath() {} @@ -64,23 +66,28 @@ export class History { parse() {} toURL(path, params, currentRoute) { - const local = currentRoute && path[0] === '#' - const route = this.parse(replaceSlug(path)) + const local = currentRoute && path[0] === '#'; + const route = this.parse(replaceSlug(path)); - route.query = merge({}, route.query, params) - path = route.path + stringifyQuery(route.query) - path = path.replace(/\.md(\?)|\.md$/, '$1') + route.query = merge({}, route.query, params); + path = route.path + stringifyQuery(route.query); + path = path.replace(/\.md(\?)|\.md$/, '$1'); if (local) { - const idIndex = currentRoute.indexOf('?') + const idIndex = currentRoute.indexOf('?'); path = - (idIndex > 0 ? currentRoute.substring(0, idIndex) : currentRoute) + path + (idIndex > 0 ? currentRoute.substring(0, idIndex) : currentRoute) + + path; } if (this.config.relativePath && path.indexOf('/') !== 0) { - const currentDir = currentRoute.substring(0, currentRoute.lastIndexOf('/') + 1) - return cleanPath(resolvePath(currentDir + path)) + const currentDir = currentRoute.substring( + 0, + currentRoute.lastIndexOf('/') + 1 + ); + return cleanPath(resolvePath(currentDir + path)); } - return cleanPath('/' + path) + + return cleanPath('/' + path); } } diff --git a/src/core/router/history/hash.js b/src/core/router/history/hash.js index 2674d5d0d..166af9ab5 100644 --- a/src/core/router/history/hash.js +++ b/src/core/router/history/hash.js @@ -1,76 +1,95 @@ -import {History} from './base' -import {noop} from '../../util/core' -import {on} from '../../util/dom' -import {parseQuery, cleanPath, replaceSlug} from '../util' +import { noop } from '../../util/core'; +import { on } from '../../util/dom'; +import { parseQuery, cleanPath, replaceSlug } from '../util'; +import { History } from './base'; function replaceHash(path) { - const i = location.href.indexOf('#') - location.replace(location.href.slice(0, i >= 0 ? i : 0) + '#' + path) + const i = location.href.indexOf('#'); + location.replace(location.href.slice(0, i >= 0 ? i : 0) + '#' + path); } export class HashHistory extends History { constructor(config) { - super(config) - this.mode = 'hash' + super(config); + this.mode = 'hash'; } getBasePath() { - const path = window.location.pathname || '' - const base = this.config.basePath + const path = window.location.pathname || ''; + const base = this.config.basePath; - return /^(\/|https?:)/g.test(base) ? base : cleanPath(path + '/' + base) + return /^(\/|https?:)/g.test(base) ? base : cleanPath(path + '/' + base); } getCurrentPath() { // We can't use location.hash here because it's not // consistent across browsers - Firefox will pre-decode it! - const href = location.href - const index = href.indexOf('#') - return index === -1 ? '' : href.slice(index + 1) + const href = location.href; + const index = href.indexOf('#'); + return index === -1 ? '' : href.slice(index + 1); } onchange(cb = noop) { - on('hashchange', cb) + // The hashchange event does not tell us if it originated from + // a clicked link or by moving back/forward in the history; + // therefore we set a `navigating` flag when a link is clicked + // to be able to tell these two scenarios apart + let navigating = false; + + on('click', e => { + const el = e.target.tagName === 'A' ? e.target : e.target.parentNode; + + if (el.tagName === 'A' && !/_blank/.test(el.target)) { + navigating = true; + } + }); + + on('hashchange', e => { + const source = navigating ? 'navigate' : 'history'; + navigating = false; + cb({ event: e, source }); + }); } normalize() { - let path = this.getCurrentPath() + let path = this.getCurrentPath(); - path = replaceSlug(path) + path = replaceSlug(path); if (path.charAt(0) === '/') { - return replaceHash(path) + return replaceHash(path); } - replaceHash('/' + path) + + replaceHash('/' + path); } /** * Parse the url - * @param {string} [path=location.herf] + * @param {string} [path=location.herf] URL to be parsed * @return {object} { path, query } */ parse(path = location.href) { - let query = '' + let query = ''; - const hashIndex = path.indexOf('#') + const hashIndex = path.indexOf('#'); if (hashIndex >= 0) { - path = path.slice(hashIndex + 1) + path = path.slice(hashIndex + 1); } - const queryIndex = path.indexOf('?') + const queryIndex = path.indexOf('?'); if (queryIndex >= 0) { - query = path.slice(queryIndex + 1) - path = path.slice(0, queryIndex) + query = path.slice(queryIndex + 1); + path = path.slice(0, queryIndex); } return { path, file: this.getFile(path, true), - query: parseQuery(query) - } + query: parseQuery(query), + }; } toURL(path, params, currentRoute) { - return '#' + super.toURL(path, params, currentRoute) + return '#' + super.toURL(path, params, currentRoute); } } diff --git a/src/core/router/history/html5.js b/src/core/router/history/html5.js index 04c53919b..d0b2a9a31 100644 --- a/src/core/router/history/html5.js +++ b/src/core/router/history/html5.js @@ -1,65 +1,67 @@ -import {History} from './base' -import {noop} from '../../util/core' -import {on} from '../../util/dom' -import {parseQuery, getPath} from '../util' +import { noop } from '../../util/core'; +import { on } from '../../util/dom'; +import { parseQuery, getPath } from '../util'; +import { History } from './base'; export class HTML5History extends History { constructor(config) { - super(config) - this.mode = 'history' + super(config); + this.mode = 'history'; } getCurrentPath() { - const base = this.getBasePath() - let path = window.location.pathname + const base = this.getBasePath(); + let path = window.location.pathname; if (base && path.indexOf(base) === 0) { - path = path.slice(base.length) + path = path.slice(base.length); } - return (path || '/') + window.location.search + window.location.hash + return (path || '/') + window.location.search + window.location.hash; } onchange(cb = noop) { on('click', e => { - const el = e.target.tagName === 'A' ? e.target : e.target.parentNode + const el = e.target.tagName === 'A' ? e.target : e.target.parentNode; if (el.tagName === 'A' && !/_blank/.test(el.target)) { - e.preventDefault() - const url = el.href - window.history.pushState({key: url}, '', url) - cb() + e.preventDefault(); + const url = el.href; + window.history.pushState({ key: url }, '', url); + cb({ event: e, source: 'navigate' }); } - }) + }); - on('popstate', cb) + on('popstate', e => { + cb({ event: e, source: 'history' }); + }); } /** * Parse the url - * @param {string} [path=location.href] + * @param {string} [path=location.href] URL to be parsed * @return {object} { path, query } */ parse(path = location.href) { - let query = '' + let query = ''; - const queryIndex = path.indexOf('?') + const queryIndex = path.indexOf('?'); if (queryIndex >= 0) { - query = path.slice(queryIndex + 1) - path = path.slice(0, queryIndex) + query = path.slice(queryIndex + 1); + path = path.slice(0, queryIndex); } - const base = getPath(location.origin) - const baseIndex = path.indexOf(base) + const base = getPath(location.origin); + const baseIndex = path.indexOf(base); if (baseIndex > -1) { - path = path.slice(baseIndex + base.length) + path = path.slice(baseIndex + base.length); } return { path, file: this.getFile(path), - query: parseQuery(query) - } + query: parseQuery(query), + }; } } diff --git a/src/core/router/index.js b/src/core/router/index.js index 943fe6c3e..1cb2f67d8 100644 --- a/src/core/router/index.js +++ b/src/core/router/index.js @@ -1,45 +1,47 @@ -import {HashHistory} from './history/hash' -import {HTML5History} from './history/html5' -import {supportsPushState} from '../util/env' -import * as dom from '../util/dom' +import { supportsPushState } from '../util/env'; +import * as dom from '../util/dom'; +import { HashHistory } from './history/hash'; +import { HTML5History } from './history/html5'; +import { noop } from '../util/core'; export function routerMixin(proto) { - proto.route = {} + proto.route = {}; } -let lastRoute = {} +let lastRoute = {}; function updateRender(vm) { - vm.router.normalize() - vm.route = vm.router.parse() - dom.body.setAttribute('data-page', vm.route.file) + vm.router.normalize(); + vm.route = vm.router.parse(); + dom.body.setAttribute('data-page', vm.route.file); } export function initRouter(vm) { - const config = vm.config - const mode = config.routerMode || 'hash' - let router + const config = vm.config; + const mode = config.routerMode || 'hash'; + let router; if (mode === 'history' && supportsPushState) { - router = new HTML5History(config) + router = new HTML5History(config); } else { - router = new HashHistory(config) + router = new HashHistory(config); } - vm.router = router - updateRender(vm) - lastRoute = vm.route + vm.router = router; + updateRender(vm); + lastRoute = vm.route; - router.onchange(_ => { - updateRender(vm) - vm._updateRender() + // eslint-disable-next-line no-unused-vars + router.onchange(params => { + updateRender(vm); + vm._updateRender(); if (lastRoute.path === vm.route.path) { - vm.$resetEvents() - return + vm.$resetEvents(params.source); + return; } - vm.$fetch() - lastRoute = vm.route - }) + vm.$fetch(noop, vm.$resetEvents.bind(vm, params.source)); + lastRoute = vm.route; + }); } diff --git a/src/core/router/util.js b/src/core/router/util.js index 2ed88c58f..ba2eed8a1 100644 --- a/src/core/router/util.js +++ b/src/core/router/util.js @@ -1,76 +1,81 @@ -import {cached} from '../util/core' +import { cached } from '../util/core'; -const decode = decodeURIComponent -const encode = encodeURIComponent +const decode = decodeURIComponent; +const encode = encodeURIComponent; export function parseQuery(query) { - const res = {} + const res = {}; - query = query.trim().replace(/^(\?|#|&)/, '') + query = query.trim().replace(/^(\?|#|&)/, ''); if (!query) { - return res + return res; } // Simple parse - query.split('&').forEach(function (param) { - const parts = param.replace(/\+/g, ' ').split('=') + query.split('&').forEach(function(param) { + const parts = param.replace(/\+/g, ' ').split('='); - res[parts[0]] = parts[1] && decode(parts[1]) - }) + res[parts[0]] = parts[1] && decode(parts[1]); + }); - return res + return res; } export function stringifyQuery(obj, ignores = []) { - const qs = [] + const qs = []; for (const key in obj) { if (ignores.indexOf(key) > -1) { - continue + continue; } + qs.push( - obj[key] ? - `${encode(key)}=${encode(obj[key])}`.toLowerCase() : - encode(key) - ) + obj[key] + ? `${encode(key)}=${encode(obj[key])}`.toLowerCase() + : encode(key) + ); } - return qs.length ? `?${qs.join('&')}` : '' + return qs.length ? `?${qs.join('&')}` : ''; } export const isAbsolutePath = cached(path => { - return /(:|(\/{2}))/g.test(path) -}) + return /(:|(\/{2}))/g.test(path); +}); export const getParentPath = cached(path => { - return /\/$/g.test(path) ? - path : - (path = path.match(/(\S*\/)[^/]+$/)) ? path[1] : '' -}) + if (/\/$/g.test(path)) { + return path; + } + + const matchingParts = path.match(/(\S*\/)[^/]+$/); + return matchingParts ? matchingParts[1] : ''; +}); export const cleanPath = cached(path => { - return path.replace(/^\/+/, '/').replace(/([^:])\/{2,}/g, '$1/') -}) + return path.replace(/^\/+/, '/').replace(/([^:])\/{2,}/g, '$1/'); +}); export const resolvePath = cached(path => { - const segments = path.replace(/^\//, '').split('/') - let resolved = [] + const segments = path.replace(/^\//, '').split('/'); + let resolved = []; for (let i = 0, len = segments.length; i < len; i++) { - const segment = segments[i] + const segment = segments[i]; if (segment === '..') { - resolved.pop() + resolved.pop(); } else if (segment !== '.') { - resolved.push(segment) + resolved.push(segment); } } - return '/' + resolved.join('/') -}) + + return '/' + resolved.join('/'); +}); export function getPath(...args) { - return cleanPath(args.join('/')) + return cleanPath(args.join('/')); } export const replaceSlug = cached(path => { - return path.replace('#', '?id=') -}) + return path.replace('#', '?id='); +}); diff --git a/src/core/util/core.js b/src/core/util/core.js index c538e2223..9d2638412 100644 --- a/src/core/util/core.js +++ b/src/core/util/core.js @@ -1,74 +1,68 @@ /** * Create a cached version of a pure function. + * @param {*} fn The function call to be cached + * @void */ + export function cached(fn) { - const cache = Object.create(null) - return function (str) { - const key = isPrimitive(str) ? str : JSON.stringify(str) - const hit = cache[key] - return hit || (cache[key] = fn(str)) - } + const cache = Object.create(null); + return function(str) { + const key = isPrimitive(str) ? str : JSON.stringify(str); + const hit = cache[key]; + return hit || (cache[key] = fn(str)); + }; } /** * Hyphenate a camelCase string. */ export const hyphenate = cached(str => { - return str.replace(/([A-Z])/g, m => '-' + m.toLowerCase()) -}) + return str.replace(/([A-Z])/g, m => '-' + m.toLowerCase()); +}); -export const hasOwn = Object.prototype.hasOwnProperty +export const hasOwn = Object.prototype.hasOwnProperty; /** * Simple Object.assign polyfill + * @param {Object} to The object to be merged with + * @returns {Object} The merged object */ export const merge = Object.assign || - function (to) { + function(to) { for (let i = 1; i < arguments.length; i++) { - const from = Object(arguments[i]) + const from = Object(arguments[i]); for (const key in from) { if (hasOwn.call(from, key)) { - to[key] = from[key] + to[key] = from[key]; } } } - return to - } + return to; + }; /** * Check if value is primitive + * @param {*} value Checks if a value is primitive + * @returns {Boolean} Result of the check */ export function isPrimitive(value) { - return typeof value === 'string' || typeof value === 'number' + return typeof value === 'string' || typeof value === 'number'; } /** - * Perform no operation. + * Performs no operation. + * @void */ export function noop() {} /** * Check if value is function + * @param {*} obj Any javascript object + * @returns {Boolean} True if the passed-in value is a function */ export function isFn(obj) { - return typeof obj === 'function' + return typeof obj === 'function'; } - -/** - * escape String - */ -export function escapeString(string) { - const entityMap = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - '\'': ''', - '/': '/' - } - - return String(string).replace(/[&<>"'/]/g, s => entityMap[s]) -} \ No newline at end of file diff --git a/src/core/util/dom.js b/src/core/util/dom.js index 388927d11..b17628636 100644 --- a/src/core/util/dom.js +++ b/src/core/util/dom.js @@ -1,43 +1,50 @@ -import {isFn} from '../util/core' -import {inBrowser} from './env' +import { isFn } from '../util/core'; +import { inBrowser } from './env'; -const cacheNode = {} +const cacheNode = {}; /** * Get Node - * @param {String|Element} el - * @param {Boolean} noCache - * @return {Element} + * @param {String|Element} el A DOM element + * @param {Boolean} noCache Flag to use or not use the cache + * @return {Element} The found node element */ export function getNode(el, noCache = false) { if (typeof el === 'string') { if (typeof window.Vue !== 'undefined') { - return find(el) + return find(el); } - el = noCache ? find(el) : cacheNode[el] || (cacheNode[el] = find(el)) + + el = noCache ? find(el) : cacheNode[el] || (cacheNode[el] = find(el)); } - return el + return el; } -export const $ = inBrowser && document +export const $ = inBrowser && document; -export const body = inBrowser && $.body +export const body = inBrowser && $.body; -export const head = inBrowser && $.head +export const head = inBrowser && $.head; /** - * Find element + * Find elements + * @param {String|Element} el The root element where to perform the search from + * @param {Element} node The query + * @returns {Element} The found DOM element * @example * find('nav') => document.querySelector('nav') * find(nav, 'a') => nav.querySelector('a') */ export function find(el, node) { - return node ? el.querySelector(node) : $.querySelector(el) + return node ? el.querySelector(node) : $.querySelector(el); } /** * Find all elements + * @param {String|Element} el The root element where to perform the search from + * @param {Element} node The query + * @returns {Array} An array of DOM elements * @example * findAll('a') => [].slice.call(document.querySelectorAll('a')) * findAll(nav, 'a') => [].slice.call(nav.querySelectorAll('a')) @@ -45,48 +52,52 @@ export function find(el, node) { export function findAll(el, node) { return [].slice.call( node ? el.querySelectorAll(node) : $.querySelectorAll(el) - ) + ); } export function create(node, tpl) { - node = $.createElement(node) + node = $.createElement(node); if (tpl) { - node.innerHTML = tpl + node.innerHTML = tpl; } - return node + + return node; } export function appendTo(target, el) { - return target.appendChild(el) + return target.appendChild(el); } export function before(target, el) { - return target.insertBefore(el, target.children[0]) + return target.insertBefore(el, target.children[0]); } export function on(el, type, handler) { - isFn(type) ? - window.addEventListener(el, type) : - el.addEventListener(type, handler) + isFn(type) + ? window.addEventListener(el, type) + : el.addEventListener(type, handler); } export function off(el, type, handler) { - isFn(type) ? - window.removeEventListener(el, type) : - el.removeEventListener(type, handler) + isFn(type) + ? window.removeEventListener(el, type) + : el.removeEventListener(type, handler); } /** * Toggle class - * + * @param {String|Element} el The element that needs the class to be toggled + * @param {Element} type The type of action to be performed on the classList (toggle by default) + * @param {String} val Name of the class to be toggled + * @void * @example * toggleClass(el, 'active') => el.classList.toggle('active') * toggleClass(el, 'add', 'active') => el.classList.add('active') */ export function toggleClass(el, type, val) { - el && el.classList[val ? type : 'toggle'](val || type) + el && el.classList[val ? type : 'toggle'](val || type); } export function style(content) { - appendTo(head, create('style', content)) + appendTo(head, create('style', content)); } diff --git a/src/core/util/env.js b/src/core/util/env.js index cd5163558..015179c58 100644 --- a/src/core/util/env.js +++ b/src/core/util/env.js @@ -1,13 +1,13 @@ -export const inBrowser = !process.env.SSR +export const inBrowser = !process.env.SSR; -export const isMobile = inBrowser && document.body.clientWidth <= 600 +export const isMobile = inBrowser && document.body.clientWidth <= 600; /** * @see https://github.com/MoOx/pjax/blob/master/lib/is-supported.js */ export const supportsPushState = inBrowser && - (function () { + (function() { // Borrowed wholesale from https://github.com/defunkt/jquery-pjax return ( window.history && @@ -17,5 +17,5 @@ export const supportsPushState = !navigator.userAgent.match( /((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/ ) - ) - })() + ); + })(); diff --git a/src/core/util/index.js b/src/core/util/index.js index eba6598f5..444ea9d47 100644 --- a/src/core/util/index.js +++ b/src/core/util/index.js @@ -1,3 +1,3 @@ -export * from './core' -export * from './env' -export * from '../router/util' +export * from './core'; +export * from './env'; +export * from '../router/util'; diff --git a/src/core/util/polyfill/css-vars.js b/src/core/util/polyfill/css-vars.js index fb3a80a2b..34e201f28 100644 --- a/src/core/util/polyfill/css-vars.js +++ b/src/core/util/polyfill/css-vars.js @@ -1,36 +1,36 @@ -import * as dom from '../dom' -import {get} from '../../fetch/ajax' +import * as dom from '../dom'; +import { get } from '../../fetch/ajax'; function replaceVar(block, color) { block.innerHTML = block.innerHTML.replace( /var\(\s*--theme-color.*?\)/g, color - ) + ); } -export default function (color) { +export default function(color) { // Variable support if (window.CSS && window.CSS.supports && window.CSS.supports('(--v:red)')) { - return + return; } const styleBlocks = dom.findAll('style:not(.inserted),link'); [].forEach.call(styleBlocks, block => { if (block.nodeName === 'STYLE') { - replaceVar(block, color) + replaceVar(block, color); } else if (block.nodeName === 'LINK') { - const href = block.getAttribute('href') + const href = block.getAttribute('href'); if (!/\.css$/.test(href)) { - return + return; } get(href).then(res => { - const style = dom.create('style', res) + const style = dom.create('style', res); - dom.head.appendChild(style) - replaceVar(style, color) - }) + dom.head.appendChild(style); + replaceVar(style, color); + }); } - }) + }); } diff --git a/src/plugins/disqus.js b/src/plugins/disqus.js index dba7aef82..4355692ec 100644 --- a/src/plugins/disqus.js +++ b/src/plugins/disqus.js @@ -1,51 +1,52 @@ -const fixedPath = location.href.replace('/-/', '/#/') +/* eslint-disable no-unused-vars */ +const fixedPath = location.href.replace('/-/', '/#/'); if (fixedPath !== location.href) { - location.href = fixedPath + location.href = fixedPath; } function install(hook, vm) { - const dom = Docsify.dom - const disqus = vm.config.disqus + const dom = Docsify.dom; + const disqus = vm.config.disqus; if (!disqus) { - throw Error('$docsify.disqus is required') + throw Error('$docsify.disqus is required'); } hook.init(_ => { - const script = dom.create('script') + const script = dom.create('script'); - script.async = true - script.src = `https://${disqus}.disqus.com/embed.js` - script.setAttribute('data-timestamp', Number(new Date())) - dom.appendTo(dom.body, script) - }) + script.async = true; + script.src = `https://${disqus}.disqus.com/embed.js`; + script.setAttribute('data-timestamp', Number(new Date())); + dom.appendTo(dom.body, script); + }); hook.mounted(_ => { - const div = dom.create('div') - div.id = 'disqus_thread' - const main = dom.getNode('#main') - div.style = `width: ${main.clientWidth}px; margin: 0 auto 20px;` - dom.appendTo(dom.find('.content'), div) + const div = dom.create('div'); + div.id = 'disqus_thread'; + const main = dom.getNode('#main'); + div.style = `width: ${main.clientWidth}px; margin: 0 auto 20px;`; + dom.appendTo(dom.find('.content'), div); // eslint-disable-next-line window.disqus_config = function() { - this.page.url = location.origin + '/-' + vm.route.path - this.page.identifier = vm.route.path - this.page.title = document.title - } - }) + this.page.url = location.origin + '/-' + vm.route.path; + this.page.identifier = vm.route.path; + this.page.title = document.title; + }; + }); hook.doneEach(_ => { if (typeof window.DISQUS !== 'undefined') { window.DISQUS.reset({ reload: true, - config: function () { - this.page.url = location.origin + '/-' + vm.route.path - this.page.identifier = vm.route.path - this.page.title = document.title - } - }) + config: function() { + this.page.url = location.origin + '/-' + vm.route.path; + this.page.identifier = vm.route.path; + this.page.title = document.title; + }, + }); } - }) + }); } -$docsify.plugins = [].concat(install, $docsify.plugins) +$docsify.plugins = [].concat(install, $docsify.plugins); diff --git a/src/plugins/emoji.js b/src/plugins/emoji.js index e65e42c4b..2898c3d04 100644 --- a/src/plugins/emoji.js +++ b/src/plugins/emoji.js @@ -1508,17 +1508,17 @@ const AllGithubEmoji = [ 'zero', 'zimbabwe', 'zipper_mouth_face', - 'zzz' -] + 'zzz', +]; // Emoji from All-Github-Emoji-Icons // https://github.com/scotch-io/All-Github-Emoji-Icons -window.emojify = function (match, $1) { - return AllGithubEmoji.indexOf($1) === -1 ? - match : - '' +
         $1 +
-        '' -} + '" />'; +}; diff --git a/src/plugins/external-script.js b/src/plugins/external-script.js index 2954030a1..f8bf9175f 100644 --- a/src/plugins/external-script.js +++ b/src/plugins/external-script.js @@ -1,25 +1,25 @@ function handleExternalScript() { - const container = Docsify.dom.getNode('#main') - const scripts = Docsify.dom.findAll(container, 'script') + const container = Docsify.dom.getNode('#main'); + const scripts = Docsify.dom.findAll(container, 'script'); - for (let i = scripts.length; i--;) { - const script = scripts[i] + for (let i = scripts.length; i--; ) { + const script = scripts[i]; if (script && script.src) { - const newScript = document.createElement('script') + const newScript = document.createElement('script'); Array.prototype.slice.call(script.attributes).forEach(attribute => { - newScript[attribute.name] = attribute.value - }) + newScript[attribute.name] = attribute.value; + }); - script.parentNode.insertBefore(newScript, script) - script.parentNode.removeChild(script) + script.parentNode.insertBefore(newScript, script); + script.parentNode.removeChild(script); } } } -const install = function (hook) { - hook.doneEach(handleExternalScript) -} +const install = function(hook) { + hook.doneEach(handleExternalScript); +}; -window.$docsify.plugins = [].concat(install, window.$docsify.plugins) +window.$docsify.plugins = [].concat(install, window.$docsify.plugins); diff --git a/src/plugins/front-matter/index.js b/src/plugins/front-matter/index.js index cb90ed91f..e91c4efc3 100644 --- a/src/plugins/front-matter/index.js +++ b/src/plugins/front-matter/index.js @@ -1,13 +1,13 @@ -import parser from './parser' +import parser from './parser'; -const install = function (hook, vm) { +const install = function(hook, vm) { hook.beforeEach(content => { - const {attributes, body} = parser(content) + const { attributes, body } = parser(content); - vm.frontmatter = attributes + vm.frontmatter = attributes; - return body - }) -} + return body; + }); +}; -$docsify.plugins = [].concat(install, $docsify.plugins) +$docsify.plugins = [].concat(install, $docsify.plugins); diff --git a/src/plugins/ga.js b/src/plugins/ga.js index 2d6419bbf..2a6474ac0 100644 --- a/src/plugins/ga.js +++ b/src/plugins/ga.js @@ -1,38 +1,40 @@ +/* eslint-disable no-console */ // From https://github.com/egoist/vue-ga/blob/master/src/index.js function appendScript() { - const script = document.createElement('script') - script.async = true - script.src = 'https://www.google-analytics.com/analytics.js' - document.body.appendChild(script) + const script = document.createElement('script'); + script.async = true; + script.src = 'https://www.google-analytics.com/analytics.js'; + document.body.appendChild(script); } function init(id) { - appendScript() + appendScript(); window.ga = window.ga || - function () { - (window.ga.q = window.ga.q || []).push(arguments) - } - window.ga.l = Number(new Date()) - window.ga('create', id, 'auto') + function() { + (window.ga.q = window.ga.q || []).push(arguments); + }; + + window.ga.l = Number(new Date()); + window.ga('create', id, 'auto'); } function collect() { if (!window.ga) { - init($docsify.ga) + init($docsify.ga); } - window.ga('set', 'page', location.hash) - window.ga('send', 'pageview') + window.ga('set', 'page', location.hash); + window.ga('send', 'pageview'); } -const install = function (hook) { +const install = function(hook) { if (!$docsify.ga) { - console.error('[Docsify] ga is required.') - return + console.error('[Docsify] ga is required.'); + return; } - hook.beforeEach(collect) -} + hook.beforeEach(collect); +}; -$docsify.plugins = [].concat(install, $docsify.plugins) +$docsify.plugins = [].concat(install, $docsify.plugins); diff --git a/src/plugins/gitalk.js b/src/plugins/gitalk.js index 8ba9acec6..b8d5f46e4 100644 --- a/src/plugins/gitalk.js +++ b/src/plugins/gitalk.js @@ -1,23 +1,24 @@ +/* eslint-disable no-unused-vars */ function install(hook) { - const dom = Docsify.dom + const dom = Docsify.dom; hook.mounted(_ => { - const div = dom.create('div') - div.id = 'gitalk-container' - const main = dom.getNode('#main') - div.style = `width: ${main.clientWidth}px; margin: 0 auto 20px;` - dom.appendTo(dom.find('.content'), div) - }) + const div = dom.create('div'); + div.id = 'gitalk-container'; + const main = dom.getNode('#main'); + div.style = `width: ${main.clientWidth}px; margin: 0 auto 20px;`; + dom.appendTo(dom.find('.content'), div); + }); hook.doneEach(_ => { - const el = document.getElementById('gitalk-container') + const el = document.getElementById('gitalk-container'); while (el.hasChildNodes()) { - el.removeChild(el.firstChild) + el.removeChild(el.firstChild); } // eslint-disable-next-line - gitalk.render('gitalk-container') - }) + gitalk.render('gitalk-container'); + }); } -$docsify.plugins = [].concat(install, $docsify.plugins) +$docsify.plugins = [].concat(install, $docsify.plugins); diff --git a/src/plugins/matomo.js b/src/plugins/matomo.js index 7b61cba7c..2074be767 100644 --- a/src/plugins/matomo.js +++ b/src/plugins/matomo.js @@ -1,37 +1,39 @@ function appendScript(options) { - const script = document.createElement('script') - script.async = true - script.src = options.host + '/matomo.js' - document.body.appendChild(script) + const script = document.createElement('script'); + script.async = true; + script.src = options.host + '/matomo.js'; + document.body.appendChild(script); } function init(options) { - window._paq = window._paq || [] - window._paq.push(['trackPageView']) - window._paq.push(['enableLinkTracking']) + window._paq = window._paq || []; + window._paq.push(['trackPageView']); + window._paq.push(['enableLinkTracking']); setTimeout(function() { - appendScript(options) - window._paq.push(['setTrackerUrl', options.host + '/matomo.php']) - window._paq.push(['setSiteId', options.id + '']) - }, 0) + appendScript(options); + window._paq.push(['setTrackerUrl', options.host + '/matomo.php']); + window._paq.push(['setSiteId', String(options.id)]); + }, 0); } function collect() { if (!window._paq) { - init($docsify.matomo) + init($docsify.matomo); } - window._paq.push(['setCustomUrl', window.location.hash.substr(1)]) - window._paq.push(['setDocumentTitle', document.title]) - window._paq.push(['trackPageView']) + + window._paq.push(['setCustomUrl', window.location.hash.substr(1)]); + window._paq.push(['setDocumentTitle', document.title]); + window._paq.push(['trackPageView']); } -const install = function (hook) { +const install = function(hook) { if (!$docsify.matomo) { - console.error('[Docsify] matomo is required.') - return + // eslint-disable-next-line no-console + console.error('[Docsify] matomo is required.'); + return; } - hook.beforeEach(collect) -} + hook.beforeEach(collect); +}; -$docsify.plugins = [].concat(install, $docsify.plugins) +$docsify.plugins = [].concat(install, $docsify.plugins); diff --git a/src/plugins/search/component.js b/src/plugins/search/component.js index 4daf5fd3e..21add7ef2 100644 --- a/src/plugins/search/component.js +++ b/src/plugins/search/component.js @@ -1,7 +1,8 @@ -import {search} from './search' +/* eslint-disable no-unused-vars */ +import { search } from './search'; -let NO_DATA_TEXT = '' -let options +let NO_DATA_TEXT = ''; +let options; function style() { const code = ` @@ -97,14 +98,13 @@ function style() { .app-name.hide, .sidebar-nav.hide { display: none; -}` +}`; - Docsify.dom.style(code) + Docsify.dom.style(code); } function tpl(defaultValue = '') { - const html = - `
+ const html = `
@@ -115,117 +115,120 @@ function tpl(defaultValue = '') {
-
` - const el = Docsify.dom.create('div', html) - const aside = Docsify.dom.find('aside') + `; + const el = Docsify.dom.create('div', html); + const aside = Docsify.dom.find('aside'); - Docsify.dom.toggleClass(el, 'search') - Docsify.dom.before(aside, el) + Docsify.dom.toggleClass(el, 'search'); + Docsify.dom.before(aside, el); } function doSearch(value) { - const $search = Docsify.dom.find('div.search') - const $panel = Docsify.dom.find($search, '.results-panel') - const $clearBtn = Docsify.dom.find($search, '.clear-button') - const $sidebarNav = Docsify.dom.find('.sidebar-nav') - const $appName = Docsify.dom.find('.app-name') + const $search = Docsify.dom.find('div.search'); + const $panel = Docsify.dom.find($search, '.results-panel'); + const $clearBtn = Docsify.dom.find($search, '.clear-button'); + const $sidebarNav = Docsify.dom.find('.sidebar-nav'); + const $appName = Docsify.dom.find('.app-name'); if (!value) { - $panel.classList.remove('show') - $clearBtn.classList.remove('show') - $panel.innerHTML = '' + $panel.classList.remove('show'); + $clearBtn.classList.remove('show'); + $panel.innerHTML = ''; if (options.hideOtherSidebarContent) { - $sidebarNav.classList.remove('hide') - $appName.classList.remove('hide') + $sidebarNav.classList.remove('hide'); + $appName.classList.remove('hide'); } - return + + return; } - const matchs = search(value) - let html = '' + const matchs = search(value); + + let html = ''; matchs.forEach(post => { html += `

${post.title}

${post.content}

-
` - }) +`; + }); - $panel.classList.add('show') - $clearBtn.classList.add('show') - $panel.innerHTML = html || `

${NO_DATA_TEXT}

` + $panel.classList.add('show'); + $clearBtn.classList.add('show'); + $panel.innerHTML = html || `

${NO_DATA_TEXT}

`; if (options.hideOtherSidebarContent) { - $sidebarNav.classList.add('hide') - $appName.classList.add('hide') + $sidebarNav.classList.add('hide'); + $appName.classList.add('hide'); } } function bindEvents() { - const $search = Docsify.dom.find('div.search') - const $input = Docsify.dom.find($search, 'input') - const $inputWrap = Docsify.dom.find($search, '.input-wrap') + const $search = Docsify.dom.find('div.search'); + const $input = Docsify.dom.find($search, 'input'); + const $inputWrap = Docsify.dom.find($search, '.input-wrap'); - let timeId + let timeId; // Prevent to Fold sidebar Docsify.dom.on( $search, 'click', e => e.target.tagName !== 'A' && e.stopPropagation() - ) + ); Docsify.dom.on($input, 'input', e => { - clearTimeout(timeId) - timeId = setTimeout(_ => doSearch(e.target.value.trim()), 100) - }) + clearTimeout(timeId); + timeId = setTimeout(_ => doSearch(e.target.value.trim()), 100); + }); Docsify.dom.on($inputWrap, 'click', e => { // Click input outside if (e.target.tagName !== 'INPUT') { - $input.value = '' - doSearch() + $input.value = ''; + doSearch(); } - }) + }); } function updatePlaceholder(text, path) { - const $input = Docsify.dom.getNode('.search input[type="search"]') + const $input = Docsify.dom.getNode('.search input[type="search"]'); if (!$input) { - return + return; } + if (typeof text === 'string') { - $input.placeholder = text + $input.placeholder = text; } else { - const match = Object.keys(text).filter(key => path.indexOf(key) > -1)[0] - $input.placeholder = text[match] + const match = Object.keys(text).filter(key => path.indexOf(key) > -1)[0]; + $input.placeholder = text[match]; } } function updateNoData(text, path) { if (typeof text === 'string') { - NO_DATA_TEXT = text + NO_DATA_TEXT = text; } else { - const match = Object.keys(text).filter(key => path.indexOf(key) > -1)[0] - NO_DATA_TEXT = text[match] + const match = Object.keys(text).filter(key => path.indexOf(key) > -1)[0]; + NO_DATA_TEXT = text[match]; } } function updateOptions(opts) { - options = opts + options = opts; } export function init(opts, vm) { - const keywords = vm.router.parse().query.s + const keywords = vm.router.parse().query.s; - updateOptions(opts) - style() - tpl(keywords) - bindEvents() - keywords && setTimeout(_ => doSearch(keywords), 500) + updateOptions(opts); + style(); + tpl(keywords); + bindEvents(); + keywords && setTimeout(_ => doSearch(keywords), 500); } export function update(opts, vm) { - updateOptions(opts) - updatePlaceholder(opts.placeholder, vm.route.path) - updateNoData(opts.noData, vm.route.path) + updateOptions(opts); + updatePlaceholder(opts.placeholder, vm.route.path); + updateNoData(opts.noData, vm.route.path); } diff --git a/src/plugins/search/index.js b/src/plugins/search/index.js index bbd3af6f0..3bfd3b6b5 100644 --- a/src/plugins/search/index.js +++ b/src/plugins/search/index.js @@ -1,5 +1,6 @@ -import {init as initComponet, update as updateComponent} from './component' -import {init as initSearch} from './search' +/* eslint-disable no-unused-vars */ +import { init as initComponet, update as updateComponent } from './component'; +import { init as initSearch } from './search'; const CONFIG = { placeholder: 'Type to search', @@ -8,35 +9,36 @@ const CONFIG = { depth: 2, maxAge: 86400000, // 1 day hideOtherSidebarContent: false, - namespace: undefined -} + namespace: undefined, +}; -const install = function (hook, vm) { - const {util} = Docsify - const opts = vm.config.search || CONFIG +const install = function(hook, vm) { + const { util } = Docsify; + const opts = vm.config.search || CONFIG; if (Array.isArray(opts)) { - CONFIG.paths = opts + CONFIG.paths = opts; } else if (typeof opts === 'object') { - CONFIG.paths = Array.isArray(opts.paths) ? opts.paths : 'auto' - CONFIG.maxAge = util.isPrimitive(opts.maxAge) ? opts.maxAge : CONFIG.maxAge - CONFIG.placeholder = opts.placeholder || CONFIG.placeholder - CONFIG.noData = opts.noData || CONFIG.noData - CONFIG.depth = opts.depth || CONFIG.depth - CONFIG.hideOtherSidebarContent = opts.hideOtherSidebarContent || CONFIG.hideOtherSidebarContent - CONFIG.namespace = opts.namespace || CONFIG.namespace + CONFIG.paths = Array.isArray(opts.paths) ? opts.paths : 'auto'; + CONFIG.maxAge = util.isPrimitive(opts.maxAge) ? opts.maxAge : CONFIG.maxAge; + CONFIG.placeholder = opts.placeholder || CONFIG.placeholder; + CONFIG.noData = opts.noData || CONFIG.noData; + CONFIG.depth = opts.depth || CONFIG.depth; + CONFIG.hideOtherSidebarContent = + opts.hideOtherSidebarContent || CONFIG.hideOtherSidebarContent; + CONFIG.namespace = opts.namespace || CONFIG.namespace; } - const isAuto = CONFIG.paths === 'auto' + const isAuto = CONFIG.paths === 'auto'; hook.mounted(_ => { - initComponet(CONFIG, vm) - !isAuto && initSearch(CONFIG, vm) - }) + initComponet(CONFIG, vm); + !isAuto && initSearch(CONFIG, vm); + }); hook.doneEach(_ => { - updateComponent(CONFIG, vm) - isAuto && initSearch(CONFIG, vm) - }) -} + updateComponent(CONFIG, vm); + isAuto && initSearch(CONFIG, vm); + }); +}; -$docsify.plugins = [].concat(install, $docsify.plugins) +$docsify.plugins = [].concat(install, $docsify.plugins); diff --git a/src/plugins/search/search.js b/src/plugins/search/search.js index 2c9febfbc..29d74b79e 100644 --- a/src/plugins/search/search.js +++ b/src/plugins/search/search.js @@ -1,15 +1,21 @@ -let INDEXS = {} +/* eslint-disable no-unused-vars */ +let INDEXS = {}; const LOCAL_STORAGE = { EXPIRE_KEY: 'docsify.search.expires', - INDEX_KEY: 'docsify.search.index' -} + INDEX_KEY: 'docsify.search.index', +}; function resolveExpireKey(namespace) { - return namespace ? `${LOCAL_STORAGE.EXPIRE_KEY}/${namespace}` : LOCAL_STORAGE.EXPIRE_KEY + return namespace + ? `${LOCAL_STORAGE.EXPIRE_KEY}/${namespace}` + : LOCAL_STORAGE.EXPIRE_KEY; } + function resolveIndexKey(namespace) { - return namespace ? `${LOCAL_STORAGE.INDEX_KEY}/${namespace}` : LOCAL_STORAGE.INDEX_KEY + return namespace + ? `${LOCAL_STORAGE.INDEX_KEY}/${namespace}` + : LOCAL_STORAGE.INDEX_KEY; } function escapeHtml(string) { @@ -18,117 +24,132 @@ function escapeHtml(string) { '<': '<', '>': '>', '"': '"', - '\'': ''', - '/': '/' - } + "'": ''', + '/': '/', + }; - return String(string).replace(/[&<>"'/]/g, s => entityMap[s]) + return String(string).replace(/[&<>"'/]/g, s => entityMap[s]); } function getAllPaths(router) { - const paths = [] - - Docsify.dom.findAll('.sidebar-nav a:not(.section-link):not([data-nosearch])').forEach(node => { - const href = node.href - const originHref = node.getAttribute('href') - const path = router.parse(href).path - - if ( - path && - paths.indexOf(path) === -1 && - !Docsify.util.isAbsolutePath(originHref) - ) { - paths.push(path) - } - }) + const paths = []; + + Docsify.dom + .findAll('.sidebar-nav a:not(.section-link):not([data-nosearch])') + .forEach(node => { + const href = node.href; + const originHref = node.getAttribute('href'); + const path = router.parse(href).path; + + if ( + path && + paths.indexOf(path) === -1 && + !Docsify.util.isAbsolutePath(originHref) + ) { + paths.push(path); + } + }); - return paths + return paths; } function saveData(maxAge, expireKey, indexKey) { - localStorage.setItem(expireKey, Date.now() + maxAge) - localStorage.setItem(indexKey, JSON.stringify(INDEXS)) + localStorage.setItem(expireKey, Date.now() + maxAge); + localStorage.setItem(indexKey, JSON.stringify(INDEXS)); } export function genIndex(path, content = '', router, depth) { - const tokens = window.marked.lexer(content) - const slugify = window.Docsify.slugify - const index = {} - let slug + const tokens = window.marked.lexer(content); + const slugify = window.Docsify.slugify; + const index = {}; + let slug; tokens.forEach(token => { if (token.type === 'heading' && token.depth <= depth) { - slug = router.toURL(path, {id: slugify(token.text)}) - index[slug] = {slug, title: token.text, body: ''} + slug = router.toURL(path, { id: slugify(token.text) }); + index[slug] = { slug, title: token.text, body: '' }; } else { if (!slug) { - return + return; } + if (!index[slug]) { - index[slug] = {slug, title: '', body: ''} + index[slug] = { slug, title: '', body: '' }; } else if (index[slug].body) { - index[slug].body += '\n' + (token.text || '') + index[slug].body += '\n' + (token.text || ''); } else { - index[slug].body = token.text + if (!token.text) { + if (token.type === 'table') { + token.text = token.cells + .map(function(rows) { + return rows.join(' | '); + }) + .join(' |\n '); + } + } + + index[slug].body = index[slug].body + ? index[slug].body + token.text + : token.text; } } - }) - slugify.clear() - return index + }); + slugify.clear(); + return index; } /** - * @param {String} query - * @returns {Array} + * @param {String} query Search query + * @returns {Array} Array of results */ export function search(query) { - const matchingResults = [] - let data = [] + const matchingResults = []; + let data = []; Object.keys(INDEXS).forEach(key => { - data = data.concat(Object.keys(INDEXS[key]).map(page => INDEXS[key][page])) - }) + data = data.concat(Object.keys(INDEXS[key]).map(page => INDEXS[key][page])); + }); - query = query.trim() - let keywords = query.split(/[\s\-,\\/]+/) + query = query.trim(); + let keywords = query.split(/[\s\-,\\/]+/); if (keywords.length !== 1) { - keywords = [].concat(query, keywords) + keywords = [].concat(query, keywords); } for (let i = 0; i < data.length; i++) { - const post = data[i] - let matchesScore = 0 - let resultStr = '' - const postTitle = post.title && post.title.trim() - const postContent = post.body && post.body.trim() - const postUrl = post.slug || '' + const post = data[i]; + let matchesScore = 0; + let resultStr = ''; + const postTitle = post.title && post.title.trim(); + const postContent = post.body && post.body.trim(); + const postUrl = post.slug || ''; if (postTitle) { - keywords.forEach( keyword => { + keywords.forEach(keyword => { // From https://github.com/sindresorhus/escape-string-regexp const regEx = new RegExp( keyword.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'), 'gi' ); - let indexTitle = -1 - let indexContent = -1 + let indexTitle = -1; + let indexContent = -1; - indexTitle = postTitle ? postTitle.search(regEx) : -1 - indexContent = postContent ? postContent.search(regEx) : -1 + indexTitle = postTitle ? postTitle.search(regEx) : -1; + indexContent = postContent ? postContent.search(regEx) : -1; if (indexTitle >= 0 || indexContent >= 0) { matchesScore += indexTitle >= 0 ? 3 : indexContent >= 0 ? 2 : 0; if (indexContent < 0) { - indexContent = 0 + indexContent = 0; } - let start = 0 - let end = 0 + let start = 0; + let end = 0; - start = indexContent < 11 ? 0 : indexContent - 10 - end = start === 0 ? 70 : indexContent + keyword.length + 60 + start = indexContent < 11 ? 0 : indexContent - 10; + end = start === 0 ? 70 : indexContent + keyword.length + 60; - if (end > postContent.length) { - end = postContent.length + if (postContent && end > postContent.length) { + end = postContent.length; } const matchContent = @@ -136,21 +157,21 @@ export function search(query) { escapeHtml(postContent) .substring(start, end) .replace(regEx, `${keyword}`) + - '...' + '...'; - resultStr += matchContent + resultStr += matchContent; } - }) + }); if (matchesScore > 0) { const matchingPost = { title: escapeHtml(postTitle), content: postContent ? resultStr : '', url: postUrl, - score: matchesScore - } + score: matchesScore, + }; - matchingResults.push(matchingPost) + matchingResults.push(matchingPost); } } } @@ -159,35 +180,35 @@ export function search(query) { } export function init(config, vm) { - const isAuto = config.paths === 'auto' + const isAuto = config.paths === 'auto'; - const expireKey = resolveExpireKey(config.namespace) - const indexKey = resolveIndexKey(config.namespace) + const expireKey = resolveExpireKey(config.namespace); + const indexKey = resolveIndexKey(config.namespace); - const isExpired = localStorage.getItem(expireKey) < Date.now() + const isExpired = localStorage.getItem(expireKey) < Date.now(); - INDEXS = JSON.parse(localStorage.getItem(indexKey)) + INDEXS = JSON.parse(localStorage.getItem(indexKey)); if (isExpired) { - INDEXS = {} + INDEXS = {}; } else if (!isAuto) { - return + return; } - const paths = isAuto ? getAllPaths(vm.router) : config.paths - const len = paths.length - let count = 0 + const paths = isAuto ? getAllPaths(vm.router) : config.paths; + const len = paths.length; + let count = 0; paths.forEach(path => { if (INDEXS[path]) { - return count++ + return count++; } - Docsify - .get(vm.router.getFile(path), false, vm.config.requestHeaders) - .then(result => { - INDEXS[path] = genIndex(path, result, vm.router, config.depth) - len === ++count && saveData(config.maxAge, expireKey, indexKey) - }) - }) + Docsify.get(vm.router.getFile(path), false, vm.config.requestHeaders).then( + result => { + INDEXS[path] = genIndex(path, result, vm.router, config.depth); + len === ++count && saveData(config.maxAge, expireKey, indexKey); + } + ); + }); } diff --git a/src/plugins/zoom-image.js b/src/plugins/zoom-image.js index faf92e1dd..f227e9fee 100644 --- a/src/plugins/zoom-image.js +++ b/src/plugins/zoom-image.js @@ -1,21 +1,30 @@ -import mediumZoom from 'medium-zoom' +/* eslint-disable no-unused-vars */ +import mediumZoom from 'medium-zoom'; -const matchesSelector = Element.prototype.matches || Element.prototype.webkitMatchesSelector || Element.prototype.msMatchesSelector +const matchesSelector = + Element.prototype.matches || + Element.prototype.webkitMatchesSelector || + Element.prototype.msMatchesSelector; function install(hook) { - let zoom + let zoom; hook.doneEach(_ => { - let elms = Array.apply(null, document.querySelectorAll('.markdown-section img:not(.emoji):not([data-no-zoom])')) + let elms = Array.apply( + null, + document.querySelectorAll( + '.markdown-section img:not(.emoji):not([data-no-zoom])' + ) + ); - elms = elms.filter(elm => matchesSelector.call(elm, 'a img') === false) + elms = elms.filter(elm => matchesSelector.call(elm, 'a img') === false); if (zoom) { - zoom.detach() + zoom.detach(); } - zoom = mediumZoom(elms) - }) + zoom = mediumZoom(elms); + }); } -$docsify.plugins = [].concat(install, $docsify.plugins) +$docsify.plugins = [].concat(install, $docsify.plugins); diff --git a/src/themes/basic/_layout.styl b/src/themes/basic/_layout.styl index 387fd7994..3d6d5c33b 100644 --- a/src/themes/basic/_layout.styl +++ b/src/themes/basic/_layout.styl @@ -120,6 +120,7 @@ li input[type='checkbox'] margin 0 1rem padding 5px 0 position relative + cursor pointer ul background-color #fff @@ -277,8 +278,9 @@ main.hidden transition opacity 0.3s width $sidebar-width - 16px z-index 30 + cursor pointer - .sidebar-toggle-button:hover + &:hover .sidebar-toggle-button opacity 0.4 span @@ -305,7 +307,7 @@ body.sticky /* markdown content found on pages */ .markdown-section margin 0 auto - max-width 800px + max-width 80% padding 30px 15px 40px 15px position relative diff --git a/test/_helper.js b/test/_helper.js index 4b4abce89..afd0c07fd 100644 --- a/test/_helper.js +++ b/test/_helper.js @@ -1,23 +1,31 @@ -// load ES6 modules in Node.js on the fly -require = require('esm')(module/*, options*/) +/* eslint-disable no-global-assign */ +// Load ES6 modules in Node.js on the fly +require = require('esm')( + module /* , options */ +); /* eslint-disable-line no-global-assign */ -const path = require('path') -const {expect} = require('chai') +const path = require('path'); +const { expect } = require('chai'); -const {JSDOM} = require('jsdom') +const { JSDOM } = require('jsdom'); function ready(callback) { - const state = document.readyState + const state = document.readyState; if (state === 'complete' || state === 'interactive') { - return setTimeout(callback, 0) + return setTimeout(callback, 0); } - document.addEventListener('DOMContentLoaded', callback) + document.addEventListener('DOMContentLoaded', callback); } -module.exports.init = function(fixture = 'default', config = {}, markup) { - if (markup == null) { - markup = ` + +module.exports.init = function( + fixture = 'default', + config = {}, + markup = null +) { + if (markup === null || markup === undefined) { + markup = ` @@ -26,62 +34,67 @@ module.exports.init = function(fixture = 'default', config = {}, markup) { window.$docsify = ${JSON.stringify(config, null, 2)} - ` - } - const rootPath = path.join(__dirname, 'fixtures', fixture) - - const dom = new JSDOM(markup) - dom.reconfigure({ url: 'file:///' + rootPath }) - - global.window = dom.window - global.document = dom.window.document - global.navigator = dom.window.navigator - global.location = dom.window.location - global.XMLHttpRequest = dom.window.XMLHttpRequest - - // mimic src/core/index.js but for Node.js - function Docsify() { - this._init() - } - - const proto = Docsify.prototype - - const {initMixin} = require('../src/core/init') - const {routerMixin} = require('../src/core//router') - const {renderMixin} = require('../src/core//render') - const {fetchMixin} = require('../src/core/fetch') - const {eventMixin} = require('../src/core//event') - - initMixin(proto) - routerMixin(proto) - renderMixin(proto) - fetchMixin(proto) - eventMixin(proto) - - const NOT_INIT_PATTERN = '' - - return new Promise((resolve, reject) => { - ready(() => { - const docsify = new Docsify() - // NOTE: I was not able to get it working with a callback, but polling works usually at the first time - const id = setInterval(() => { - if (dom.window.document.body.innerHTML.indexOf(NOT_INIT_PATTERN) == -1) { - clearInterval(id) - return resolve({ - docsify: docsify, - dom: dom - }) - } - }, 10) - }) - - }) -} + `; + } + + const rootPath = path.join(__dirname, 'fixtures', fixture); + + const dom = new JSDOM(markup); + dom.reconfigure({ url: 'file:///' + rootPath }); + + global.window = dom.window; + global.document = dom.window.document; + global.navigator = dom.window.navigator; + global.location = dom.window.location; + global.XMLHttpRequest = dom.window.XMLHttpRequest; + + // Mimic src/core/index.js but for Node.js + function Docsify() { + this._init(); + } + + const proto = Docsify.prototype; + + const { initMixin } = require('../src/core/init'); + const { routerMixin } = require('../src/core//router'); + const { renderMixin } = require('../src/core//render'); + const { fetchMixin } = require('../src/core/fetch'); + const { eventMixin } = require('../src/core//event'); + + initMixin(proto); + routerMixin(proto); + renderMixin(proto); + fetchMixin(proto); + eventMixin(proto); + + const NOT_INIT_PATTERN = ''; + + return new Promise(resolve => { + ready(() => { + const docsify = new Docsify(); + // NOTE: I was not able to get it working with a callback, but polling works usually at the first time + const id = setInterval(() => { + if ( + dom.window.document.body.innerHTML.indexOf(NOT_INIT_PATTERN) === -1 + ) { + clearInterval(id); + return resolve({ + docsify: docsify, + dom: dom, + }); + } + }, 10); + }); + }); +}; + module.exports.expectSameDom = function(actual, expected) { - const WHITESPACES_BETWEEN_TAGS = />(\s\s+)(\s\s+) **Time** is money, my friend!') - expect(output).equal('

Time is money, my friend!

') - }) - - describe('lists', function() { - it('as unordered task list', async function() { - const {docsify, dom} = await init() - const output = docsify.compiler.compile(` -- [x] Task 1 -- [ ] Task 2 -- [ ] Task 3`) - expect(output, ``) - }) - - it('as ordered task list', async function() { - const {docsify, dom} = await init() - const output = docsify.compiler.compile(` -1. [ ] Task 1 -2. [x] Task 2`) - expectSameDom(output, `
    -
  1. -
  2. -
`) - }) - - it('normal unordered', async function() { - const {docsify, dom} = await init() - const output = docsify.compiler.compile(` -- [linktext](link) -- just text`) - expectSameDom(output, ``) - }) - - it('unordered with custom start', async function() { - const {docsify, dom} = await init() - const output = docsify.compiler.compile(` -1. first -2. second - -text - -3. third`) - expectSameDom(output, `
    -
  1. first
  2. -
  3. second
  4. -
-

text

-
    -
  1. third
  2. -
`) - }) - - it('nested', async function() { - const {docsify, dom} = await init() - const output = docsify.compiler.compile(` -- 1 -- 2 - - 2 a - - 2 b -- 3`) - expectSameDom(output, ``) - }) - }) - -}) diff --git a/test/unit/render.test.js b/test/unit/render.test.js new file mode 100644 index 000000000..60ed5e0a0 --- /dev/null +++ b/test/unit/render.test.js @@ -0,0 +1,322 @@ +const { expect } = require('chai'); +const { init, expectSameDom } = require('../_helper'); + +describe('render', function() { + it('important content (tips)', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile('!> **Time** is money, my friend!'); + expect(output).equal( + '

Time is money, my friend!

' + ); + }); + + describe('lists', function() { + it('as unordered task list', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile(` +- [x] Task 1 +- [ ] Task 2 +- [ ] Task 3`); + expect( + output, + `` + ); + }); + + it('as ordered task list', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile(` +1. [ ] Task 1 +2. [x] Task 2`); + expectSameDom( + output, + `
    +
  1. +
  2. +
` + ); + }); + + it('normal unordered', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile(` +- [linktext](link) +- just text`); + expectSameDom( + output, + `` + ); + }); + + it('unordered with custom start', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile(` +1. first +2. second + +text + +3. third`); + expectSameDom( + output, + `
    +
  1. first
  2. +
  3. second
  4. +
+

text

+
    +
  1. third
  2. +
` + ); + }); + + it('nested', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile(` +- 1 +- 2 + - 2 a + - 2 b +- 3`); + expectSameDom( + output, + `` + ); + }); + }); + + describe('image', function() { + it('regular', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile('![alt text](http://imageUrl)'); + + expectSameDom( + output, + '

alt text

' + ); + }); + + it('class', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile( + "![alt text](http://imageUrl ':class=someCssClass')" + ); + + expectSameDom( + output, + '

alt text

' + ); + }); + + it('id', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile( + "![alt text](http://imageUrl ':id=someCssID')" + ); + + expectSameDom( + output, + '

alt text

' + ); + }); + + it('no-zoom', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile( + "![alt text](http://imageUrl ':no-zoom')" + ); + + expectSameDom( + output, + '

alt text

' + ); + }); + + describe('size', function() { + it('width and height', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile( + "![alt text](http://imageUrl ':size=WIDTHxHEIGHT')" + ); + + expectSameDom( + output, + '

alt text

' + ); + }); + + it('width', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile( + "![alt text](http://imageUrl ':size=50')" + ); + + expectSameDom( + output, + '

alt text

' + ); + }); + }); + }); + + describe('heading', function() { + it('h1', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile('# h1 tag'); + expectSameDom( + output, + ` +

+ + h1 tag + +

` + ); + }); + + it('h2', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile('## h2 tag'); + expectSameDom( + output, + ` +

+ + h2 tag + +

` + ); + }); + + it('h3', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile('### h3 tag'); + expectSameDom( + output, + ` +

+ + h3 tag + +

` + ); + }); + + it('h4', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile('#### h4 tag'); + expectSameDom( + output, + ` +

+ + h4 tag + +

` + ); + }); + + it('h5', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile('##### h5 tag'); + expectSameDom( + output, + ` +
+ + h5 tag + +
` + ); + }); + + it('h6', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile('###### h6 tag'); + expectSameDom( + output, + ` +
+ + h6 tag + +
` + ); + }); + }); + + describe('link', function() { + it('regular', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile('[alt text](http://url)'); + + expectSameDom( + output, + '

alt text

' + ); + }); + + it('disabled', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile( + "[alt text](http://url ':disabled')" + ); + + expectSameDom( + output, + '

alt text

' + ); + }); + + it('target', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile( + "[alt text](http://url ':target=_self')" + ); + + expectSameDom( + output, + '

alt text

' + ); + }); + + it('class', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile( + "[alt text](http://url ':class=someCssClass')" + ); + + expectSameDom( + output, + '

alt text

' + ); + }); + + it('id', async function() { + const { docsify } = await init(); + const output = docsify.compiler.compile( + "[alt text](http://url ':id=someCssID')" + ); + + expectSameDom( + output, + '

alt text

' + ); + }); + }); +}); diff --git a/test/unit/util.js b/test/unit/util.js deleted file mode 100644 index 1e65dafe0..000000000 --- a/test/unit/util.js +++ /dev/null @@ -1,30 +0,0 @@ -/* eslint-env node, chai, mocha */ -require = require('esm')(module/*, options*/) -const {expect} = require('chai') -const {resolvePath} = require('../../src/core/router/util') - -describe('router/util', function () { - it('resolvePath', async function () { - // WHEN - const result = resolvePath('hello.md') - - // THEN - expect(result).equal('/hello.md') - }) - - it('resolvePath with dot', async function () { - // WHEN - const result = resolvePath('./hello.md') - - // THEN - expect(result).equal('/hello.md') - }) - - it('resolvePath with two dots', async function () { - // WHEN - const result = resolvePath('test/../hello.md') - - // THEN - expect(result).equal('/hello.md') - }) -}) diff --git a/test/unit/util.test.js b/test/unit/util.test.js new file mode 100644 index 000000000..9dadf28a3 --- /dev/null +++ b/test/unit/util.test.js @@ -0,0 +1,32 @@ +/* eslint-disable no-global-assign */ +require = require('esm')( + module /* , options */ +); /* eslint-disable-line no-global-assign */ +const { expect } = require('chai'); +const { resolvePath } = require('../../src/core/router/util'); + +describe('router/util', function() { + it('resolvePath', async function() { + // WHEN + const result = resolvePath('hello.md'); + + // THEN + expect(result).equal('/hello.md'); + }); + + it('resolvePath with dot', async function() { + // WHEN + const result = resolvePath('./hello.md'); + + // THEN + expect(result).equal('/hello.md'); + }); + + it('resolvePath with two dots', async function() { + // WHEN + const result = resolvePath('test/../hello.md'); + + // THEN + expect(result).equal('/hello.md'); + }); +});