Skip to content

Commit

Permalink
support custom permalink (#127)
Browse files Browse the repository at this point in the history
  • Loading branch information
ikeq authored Aug 31, 2019
1 parent a9deba8 commit 7441aed
Show file tree
Hide file tree
Showing 18 changed files with 77 additions and 55 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
- SPA built with [angular]
- Custom accent color, background, fonts, dark mode
- Custom code syntax highlighting
- Sub-page
- Search
- Comments
- [Disqus]
Expand Down Expand Up @@ -54,7 +53,6 @@
2\. Config `HEXO/_config.yml` as follows:

```yml
permalink: post/:title/
theme: inside
```
Expand Down
2 changes: 0 additions & 2 deletions README_zh-Hans.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
- SPA built with [angular]
- 自定义色调、背景、字体、暗色主题
- 自定义代码语法高亮
- 可嵌套 page 路由
- 评论
- [Disqus]
- [LiveRe]
Expand Down Expand Up @@ -53,7 +52,6 @@
2\. 配置 `HEXO/_config.yml` 如下:

```yml
permalink: post/:title/
theme: inside
```
Expand Down
2 changes: 0 additions & 2 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ module.exports = function (hexo) {

// override default language
site.language = utils.localeId(site.language);
// override default permalink
site.permalink = 'post/:title/';

const __ = this.theme.i18n.__(site.language);

Expand Down
6 changes: 3 additions & 3 deletions lib/filter/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const cheerio = require('cheerio');
const { date } = require('hexo/lib/plugins/helper/date');
const bounded = '<div class="article-bounded"></div>';
const table = '<div class="article-table"></div>';
const { snippet, getPagePath, parseToc, isObject, isEmptyObject, localeId, pick } = require('../utils');
const { snippet, parseToc, isObject, isEmptyObject, localeId, pick, trimHtml } = require('../utils');

// cache
let hasComments, hasReward, hasToc, copyright, dateHelper, uriReplacer;
Expand Down Expand Up @@ -37,7 +37,7 @@ module.exports = function (data) {
s => s;

// relative link
data.link = isPage ? getPagePath(data.source) : `post/${data.slug}`;
data.link = trimHtml(data.path);
// permalink link
data.plink = `${config.url}/${data.link}/`;
// type
Expand All @@ -47,7 +47,7 @@ module.exports = function (data) {
data.comments = hasComments && data.comments !== false;

// asset path
const assetPath = isPage ? getPagePath(data.source, true) : data.link;
const assetPath = isPage ? trimHtml(data.path, true) : data.link;

// Make sure articles without titles are also accessible
if (!data.title) data.title = data.slug
Expand Down
21 changes: 20 additions & 1 deletion lib/generator/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,28 @@ module.exports = function (locals) {
parseBackground(sidebar_background).color || accent_color]
.concat(parseBackground(background).color || (theme.pwa && theme.pwa.theme_color) || [])

// post routes
config.routes = {}
config.routes.posts = [...locals.posts
.reduce((set, post) => {
// convert `/path/to/path/` to `:a/:b/:c`
const link = post.link.split('/').filter(i => i)
.map((_, i) => ':' + String.fromCharCode(97 + i))
.join('/')
set.add(link)
return set
}, new Set)].sort()
// page routes
if (locals.pages.length)
config.routes = locals.pages.map(page => page.link).sort();
config.routes.pages = [...locals.pages
.reduce((set, post) => {
// convert `/path/to/path/` to `path/:a/:b`
const link = post.link.split('/').filter(i => i)
.map((partial, i) => i === 0 ? partial : ':' + String.fromCharCode(97 + i))
.join('/')
set.add(link)
return set
}, new Set)].sort()

if (config.count.categories) config.firstCategory = locals.categories[0].name;

Expand Down
6 changes: 3 additions & 3 deletions lib/generator/entries/pages.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
const { flattenDeep } = require('lodash');
const { getPagePath, pick } = require('../../utils');
const { pick } = require('../../utils');
const { page: pageProps } = require('./properties');

module.exports = function ({ locals: { pages }, helpers }) {
return flattenDeep([
pages.map(page => [
helpers.generateJson({
path: `page/${page.link}`,
path: page.link,
data: pick(page, pageProps)
}),
helpers.generateHtml({
path: getPagePath(page.source),
path: page.link,
data: page
})
]),
Expand Down
4 changes: 2 additions & 2 deletions lib/generator/entries/posts.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module.exports = function ({ theme, locals: { posts }, helpers }) {

return [
helpers.generateJson({
path: `${post.link}`,
path: post.link,
data: pick(post, postProps)
}),
helpers.generateHtml({
Expand All @@ -31,7 +31,7 @@ module.exports = function ({ theme, locals: { posts }, helpers }) {
if (a.date === b.date) return 0;
return a.date > b.date ? -1 : 1;
}).map(pick(postListProps)), { perPage: config.per_page }, [
{ type: 'json', id: 'posts' },
{ type: 'json', id: 'page' },
{ type: 'html', id: index => index === 1 ? '' : `page/${index}`, extend: { type: 'posts' } },
])
]);
Expand Down
26 changes: 13 additions & 13 deletions lib/generator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const generators = [
require('./manifest'),
require('./sw')
];
const builtInRoutes = ['page', 'post', 'categories', 'tags', 'archives', 'search', '404'];
const builtInRoutes = ['page', 'categories', 'tags', 'archives', 'search', '404'];

module.exports = function (hexo) {
// Remove hexo default generators
Expand All @@ -27,21 +27,21 @@ module.exports = function (hexo) {
return data;
}).filter(data => data.posts.length),

pages: locals.pages
// Filter built-in routes to improve compatibility
.filter(page => {
if (builtInRoutes.includes(page.path.split('/')[0])) {
hexo.log.warn(page.path + ' won\'t be rendered.');
return false;
}
pages: locals.pages.filter(filterBuiltInRoutes).toArray(),

return true;
})
.toArray(),

posts: locals.posts.filter(published).sort('-date').toArray()
posts: locals.posts.filter(published).filter(filterBuiltInRoutes).sort('-date').toArray()
};

return flatten(generators.map(fn => fn.call(this, sLocals)));
});

// Filter built-in routes to improve compatibility
function filterBuiltInRoutes(post) {
if (builtInRoutes.includes(post.path.split('/')[0])) {
hexo.log.warn(post.path + ' won\'t be rendered.');
return false;
}

return true;
}
};
6 changes: 3 additions & 3 deletions lib/helper/url_trim.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = function (url) {
if (!url) return '';
const { trimHtml } = require('../utils')

return url.replace(/index.html$/, '');
module.exports = function (url) {
return url ? trimHtml(url) + '/' : '';
}
27 changes: 16 additions & 11 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,26 @@ exports.base64 = function (str) {
}

/**
* Align page path to support sub page
* Remove `/*.html`
*
* source/page/index.md => /root/page
* source/page/v2.md => /root/page/v2
*
* @param {string} source page.source
* @param {boolean} keepIndex
* @param {string} url
* @param {boolean} keepIndex keep `index` for `index.html`, used for post_asset_folder
* @returns {string}
*/
exports.getPagePath = function (source, keepIndex) {
let [paths, md] = source.split(/\/(?=[^\/]*md$)/);
exports.trimHtml = function (url, keepIndex) {
if (!url) return '';
url = url.split('/')

const last = url.pop()
if (last) {
if (last === 'index.html') {
if (keepIndex) url.push('index')
} else {
url.push(last.split('.')[0])
}
}

if (md !== 'index.md') paths += '/' + md.substring(0, md.indexOf('.md'));
else if (keepIndex) paths += '/index';
return paths;
return url.join('/');
}

exports.Pagination = class {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hexo-theme-inside",
"version": "2.4.0-beta.1",
"version": "2.4.0-beta.2",
"description": "❤️ SPA, flat and clean theme for Hexo.",
"scripts": {
"test": "jasmine --config=test/jasmine.json"
Expand Down
2 changes: 1 addition & 1 deletion source/_resources.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"root":"is-a","styles":["styles.9477318680c7e6b720a2.css"],"scripts":["runtime.caef73fae70e33459c5a.js","polyfills.28555e618578fe61f50a.js"],"locales":{"zh-Hans":"main.5be06e990995039d250c.zh-Hans.js","zh-Hant":"main.8afb50983316ecb0cc35.zh-Hant.js","en":"main.aa5336b38b728b66fcad.js","ja":"main.c53a7c81fe2a67caf1e3.ja.js"}}
{"root":"is-a","styles":["styles.9477318680c7e6b720a2.css"],"scripts":["runtime.caef73fae70e33459c5a.js","polyfills.28555e618578fe61f50a.js"],"locales":{"en":"main.3c8fe2175e9d028e033b.js","ja":"main.45d1e4209486560b00ce.ja.js","zh-Hans":"main.5f57ed8aacba80770b83.zh-Hans.js","zh-Hant":"main.dec5dcd89e85221e092e.zh-Hant.js"}}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion test/scripts/filters/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@ describe('post', function () {
layout: 'post',
excerpt: '',
content: '',
slug: 'test'
slug: 'test',
path: 'post/test'
}
post.call(this.ctx, data);
expect(data.link).toBe('post/test');
expect(data.plink).toBe('//example.com/post/test/');

data.layout = 'page';
data.path = 'test'
data.source = 'test/index.md';
post.call(this.ctx, data);
expect(data.link).toBe('test');
Expand Down Expand Up @@ -105,6 +107,7 @@ describe('post', function () {
layout: 'post',
excerpt: '',
slug: 'test',
path: 'post/test',
content: '<h2 id="Title"><a href="#Title" class="headerlink" title="Title"></a>Title</h2>'
};

Expand Down
13 changes: 7 additions & 6 deletions test/scripts/utils/rest.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
const cheerio = require('cheerio');

describe('utils/rest', function () {
const { type, isEmptyObject, pick, md5, base64, getPagePath, Pagination, parseToc, escapeIdentifier, localeId, parseJs, snippet, tag, parseBackground } = require('../../../lib/utils');
const { type, isEmptyObject, pick, md5, base64, Pagination, parseToc, escapeIdentifier, localeId, parseJs, snippet, tag, parseBackground, trimHtml } = require('../../../lib/utils');

it('type()', function () {
expect(type({})).toBe('object');
Expand Down Expand Up @@ -38,11 +38,6 @@ describe('utils/rest', function () {
expect(base64('foo/a')).toBe('Zm9vL2E');
})

it('getPagePath()', function () {
expect(getPagePath('root/page/index.md')).toEqual('root/page');
expect(getPagePath('root/page/v2.md')).toEqual('root/page/v2');
});

it('Pagination', function () {
const pagination = new Pagination({
html: { generateFn: ({ path, data }) => ({ path: path + '/index.html', data, layout: 'index' }) },
Expand Down Expand Up @@ -187,4 +182,10 @@ describe('utils/rest', function () {
expect(parseBackground('xxx.jpg')).toEqual({ image: 'xxx.jpg' })
})

it('trimHtml()', function () {
expect(trimHtml('post/a/b/')).toBe('post/a/b')
expect(trimHtml('post/a/b.html')).toBe('post/a/b')
expect(trimHtml('post/a/index.html')).toBe('post/a')
expect(trimHtml('post/a/index.html', true)).toBe('post/a/index')
})
});

0 comments on commit 7441aed

Please sign in to comment.