Skip to content

Commit

Permalink
fix: Unable to navigate on server without default index support (#1372)
Browse files Browse the repository at this point in the history
* Fix: Cannot serve off `/.../index.html`

Docsify must be hosted on a server that supports a default directory
index (i.e. maps `/.../` -> `/.../index.html`).

Some platforms do not support this, however. For example, HTML apps
hosted on the popular game/software platform, Itch.io.

This change supports hosting Docsify off an explicit path file, such as
`/index.html`. It does this by:

 1. Adding handling for paths like `index.html#/blah`, and
 2. Normalising paths with fragments back to markdown paths

For example, `http://example.org/index.html#/blah` would be mapped to
`http://example.org/blah.md`.

This fixes:

#427

* Add end-to-end test for index file hosting

* Add code comments for explicit file changes

* Add additional tests for index file hosting

* Add additional tests for index file hosting

* [wip] Attempt to switch tests to Jest

* Add e2e test for new Jest test framework

* Verify sidebar links use file hosting

* Fix: endsWith() not supported for IE11

* Refactor: utility method moved to utility file

* Fix IE11 error from use of String.includes()

Co-authored-by: John Hildenbiddle <jhildenbiddle@users.noreply.github.com>
  • Loading branch information
rgladwell and jhildenbiddle authored Feb 7, 2021
1 parent 14ce7f3 commit 759ffac
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 4 deletions.
13 changes: 10 additions & 3 deletions src/core/router/history/hash.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { noop } from '../../util/core';
import { on } from '../../util/dom';
import { parseQuery, cleanPath, replaceSlug } from '../util';
import { parseQuery, cleanPath, replaceSlug, endsWith } 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);
}

export class HashHistory extends History {
constructor(config) {
super(config);
Expand All @@ -18,7 +17,15 @@ export class HashHistory extends History {
const path = window.location.pathname || '';
const base = this.config.basePath;

return /^(\/|https?:)/g.test(base) ? base : cleanPath(path + '/' + base);
// This handles the case where Docsify is served off an
// explicit file path, i.e.`/base/index.html#/blah`. This
// prevents the `/index.html` part of the URI from being
// remove during routing.
// See here: https://github.com/docsifyjs/docsify/pull/1372
const basePath = endsWith(path, '.html')
? path + '#/' + base
: path + '/' + base;
return /^(\/|https?:)/g.test(base) ? base : cleanPath(basePath);
}

getCurrentPath() {
Expand Down
36 changes: 35 additions & 1 deletion src/core/router/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,44 @@ export const resolvePath = cached(path => {
return '/' + resolved.join('/');
});

/**
* Normalises the URI path to handle the case where Docsify is
* hosted off explicit files, i.e. /index.html. This function
* eliminates any path segments that contain `#` fragments.
*
* This is used to map browser URIs to markdown file sources.
*
* For example:
*
* http://example.org/base/index.html#/blah
*
* would be mapped to:
*
* http://example.org/base/blah.md.
*
* See here for more information:
*
* https://github.com/docsifyjs/docsify/pull/1372
*
* @param {string} path The URI path to normalise
* @return {string} { path, query }
*/

function normaliseFragment(path) {
return path
.split('/')
.filter(p => p.indexOf('#') === -1)
.join('/');
}

export function getPath(...args) {
return cleanPath(args.join('/'));
return cleanPath(args.map(normaliseFragment).join('/'));
}

export const replaceSlug = cached(path => {
return path.replace('#', '?id=');
});

export function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
28 changes: 28 additions & 0 deletions test/e2e/index-file.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const docsifyInit = require('../helpers/docsify-init');

describe(`Index file hosting`, function() {
const sharedOptions = {
config: {
basePath: `${TEST_HOST}/docs/index.html#/`,
},
testURL: `${TEST_HOST}/docs/index.html#/`,
};

test('should serve from index file', async () => {
await docsifyInit(sharedOptions);

await expect(page).toHaveText(
'#main',
'A magical documentation site generator'
);
expect(page.url()).toMatch(/index\.html#\/$/);
});

test('should use index file links in sidebar from index file hosting', async () => {
await docsifyInit(sharedOptions);

await page.click('a[href="#/quickstart"]');
await expect(page).toHaveText('#main', 'Quick start');
expect(page.url()).toMatch(/index\.html#\/quickstart$/);
});
});

1 comment on commit 759ffac

@vercel
Copy link

@vercel vercel bot commented on 759ffac Feb 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.