refactor(script): remove unused hexo helpers
parent
8e88905c48
commit
4234234c6c
|
@ -1,40 +0,0 @@
|
||||||
/**
|
|
||||||
* Helper functions for controlling layout.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* <%- get_widgets(position) %>
|
|
||||||
* <%- has_column() %>
|
|
||||||
* <%- column_count() %>
|
|
||||||
*/
|
|
||||||
module.exports = function (hexo) {
|
|
||||||
hexo.extend.helper.register('has_widget', function (type) {
|
|
||||||
const hasWidgets = hexo.extend.helper.get('has_config').bind(this)('widgets');
|
|
||||||
if (!hasWidgets) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const widgets = hexo.extend.helper.get('get_config').bind(this)('widgets');
|
|
||||||
return widgets.some(widget => widget.hasOwnProperty('type') && widget.type === type);
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('get_widgets', function (position) {
|
|
||||||
const hasWidgets = hexo.extend.helper.get('has_config').bind(this)('widgets');
|
|
||||||
if (!hasWidgets) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const widgets = hexo.extend.helper.get('get_config').bind(this)('widgets');
|
|
||||||
return widgets.filter(widget => widget.hasOwnProperty('position') && widget.position === position);
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('has_column', function (position) {
|
|
||||||
const getWidgets = hexo.extend.helper.get('get_widgets').bind(this);
|
|
||||||
return getWidgets(position).length > 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('column_count', function () {
|
|
||||||
let columns = 1;
|
|
||||||
const hasColumn = hexo.extend.helper.get('has_column').bind(this);
|
|
||||||
columns += hasColumn('left') ? 1 : 0;
|
|
||||||
columns += hasColumn('right') ? 1 : 0;
|
|
||||||
return columns;
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,194 +0,0 @@
|
||||||
/**
|
|
||||||
* Helper functions that override Hexo built-in helpers.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* <%- _list_archives() %>
|
|
||||||
* <%- _list_categories() %>
|
|
||||||
* <%- _list_tags() %>
|
|
||||||
* <%- _toc(content) %>
|
|
||||||
* <%- _js(url, defer, async) %>
|
|
||||||
* <%- _css(url) %>
|
|
||||||
* <%- _partial(url) %>
|
|
||||||
*/
|
|
||||||
const cheerio = require('cheerio');
|
|
||||||
const { existsSync } = require('fs');
|
|
||||||
const { relative, dirname, join, extname } = require('path');
|
|
||||||
const { LRUMap } = require('../utils/lru');
|
|
||||||
|
|
||||||
const __archives = [];
|
|
||||||
const __categories = [];
|
|
||||||
const __tags = [];
|
|
||||||
|
|
||||||
const __fragmentCache = new LRUMap(20);
|
|
||||||
|
|
||||||
module.exports = function (hexo) {
|
|
||||||
hexo.extend.helper.register('_list_archives', function () {
|
|
||||||
if (__archives.length) {
|
|
||||||
return __archives;
|
|
||||||
}
|
|
||||||
const $ = cheerio.load(this.list_archives(), { decodeEntities: false });
|
|
||||||
$('.archive-list-item').each(function () {
|
|
||||||
__archives.push({
|
|
||||||
url: $(this).find('.archive-list-link').attr('href'),
|
|
||||||
name: $(this).find('.archive-list-link').text(),
|
|
||||||
count: $(this).find('.archive-list-count').text()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return __archives;
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('_list_categories', function () {
|
|
||||||
if (__categories.length) {
|
|
||||||
return __categories;
|
|
||||||
}
|
|
||||||
const $ = cheerio.load(this.list_categories({ depth: 2 }), { decodeEntities: false });
|
|
||||||
function traverse(root) {
|
|
||||||
const categories = [];
|
|
||||||
root.find('> .category-list-item').each(function () {
|
|
||||||
const category = {
|
|
||||||
url: $(this).find('> .category-list-link').attr('href'),
|
|
||||||
name: $(this).find('> .category-list-link').text(),
|
|
||||||
count: $(this).find('> .category-list-count').text()
|
|
||||||
};
|
|
||||||
if ($(this).find('> .category-list-child').length) {
|
|
||||||
category['children'] = traverse($(this).find('> .category-list-child'));
|
|
||||||
}
|
|
||||||
categories.push(category);
|
|
||||||
});
|
|
||||||
return categories;
|
|
||||||
}
|
|
||||||
__categories.push(...traverse($('.category-list')));
|
|
||||||
return __categories;
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('_list_tags', function () {
|
|
||||||
if (__tags.length) {
|
|
||||||
return __tags;
|
|
||||||
}
|
|
||||||
const $ = cheerio.load(this.list_tags(), { decodeEntities: false });
|
|
||||||
$('.tag-list-item').each(function () {
|
|
||||||
__tags.push({
|
|
||||||
url: $(this).find('.tag-list-link').attr('href'),
|
|
||||||
name: $(this).find('.tag-list-link').text(),
|
|
||||||
count: $(this).find('.tag-list-count').text()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return __tags;
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Export a tree of headings of an article
|
|
||||||
* {
|
|
||||||
* "1": {
|
|
||||||
* "id": "How-to-enable-table-of-content-for-a-post",
|
|
||||||
* "index": "1"
|
|
||||||
* },
|
|
||||||
* "2": {
|
|
||||||
* "1": {
|
|
||||||
* "1": {
|
|
||||||
* "id": "Third-level-title",
|
|
||||||
* "index": "2.1.1"
|
|
||||||
* },
|
|
||||||
* "id": "Second-level-title",
|
|
||||||
* "index": "2.1"
|
|
||||||
* },
|
|
||||||
* "2": {
|
|
||||||
* "id": "Another-second-level-title",
|
|
||||||
* "index": "2.2"
|
|
||||||
* },
|
|
||||||
* "id": "First-level-title",
|
|
||||||
* "index": "2"
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
hexo.extend.helper.register('_toc', (content) => {
|
|
||||||
const $ = cheerio.load(content, { decodeEntities: false });
|
|
||||||
const toc = {};
|
|
||||||
const levels = [0, 0, 0];
|
|
||||||
// Get top 3 headings that are present in the content
|
|
||||||
const tags = [1, 2, 3, 4, 5, 6].map(i => 'h' + i).filter(h => $(h).length > 0).slice(0, 3);
|
|
||||||
if (tags.length === 0) {
|
|
||||||
return toc;
|
|
||||||
}
|
|
||||||
$(tags.join(',')).each(function () {
|
|
||||||
const level = tags.indexOf(this.name);
|
|
||||||
const id = $(this).attr('id');
|
|
||||||
const text = $(this).text();
|
|
||||||
|
|
||||||
for (let i = 0; i < levels.length; i++) {
|
|
||||||
if (i > level) {
|
|
||||||
levels[i] = 0;
|
|
||||||
} else if (i < level) {
|
|
||||||
if (levels[i] === 0) {
|
|
||||||
// if headings start with a lower level heading, set the former heading index to 1
|
|
||||||
// e.g. h3, h2, h1, h2, h3 => 1.1.1, 1.2, 2, 2.1, 2.1.1
|
|
||||||
levels[i] = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
levels[i] += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let node = toc;
|
|
||||||
for (let i of levels.slice(0, level + 1)) {
|
|
||||||
if (!node.hasOwnProperty(i)) {
|
|
||||||
node[i] = {};
|
|
||||||
}
|
|
||||||
node = node[i];
|
|
||||||
}
|
|
||||||
node.id = id;
|
|
||||||
node.text = text;
|
|
||||||
node.index = levels.slice(0, level + 1).join('.');
|
|
||||||
});
|
|
||||||
return toc;
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('_js', function (url, defer = false, async = false) {
|
|
||||||
const urlFor = hexo.extend.helper.get('url_for').bind(this);
|
|
||||||
if (!url.endsWith('.js') && !url.includes('?')) {
|
|
||||||
url += '.js';
|
|
||||||
}
|
|
||||||
return `<script src="${urlFor(url)}"${async ? ' async' : ''}${defer ? ' defer' : ''}></script>`;
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('_css', function (url) {
|
|
||||||
const urlFor = hexo.extend.helper.get('url_for').bind(this);
|
|
||||||
if (!url.endsWith('.css') && !url.includes('?')) {
|
|
||||||
url += '.css';
|
|
||||||
}
|
|
||||||
return `<link rel="stylesheet" href="${urlFor(url)}">`;
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('_partial', function (name, locals, options = {}) {
|
|
||||||
const { md5, partial, view_dir, page } = this;
|
|
||||||
const currentView = this.filename.substring(view_dir.length);
|
|
||||||
let _locals = Object.assign({}, locals, { layout: false });
|
|
||||||
|
|
||||||
let { path } = hexo.theme.getView(join(dirname(currentView), name)) || hexo.theme.getView(name);
|
|
||||||
path = join(view_dir, path.substring(0, path.length - extname(path).length) + '.locals.js');
|
|
||||||
|
|
||||||
if (!existsSync(path)) {
|
|
||||||
// fallback to default partial
|
|
||||||
return partial(name, locals, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
_locals = require(path)(this, _locals);
|
|
||||||
if (_locals === null) {
|
|
||||||
// partial should be empty
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_locals === false) {
|
|
||||||
// do not cache this fragment
|
|
||||||
return partial(name, locals, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
const language = page.lang || page.language;
|
|
||||||
const fragment = relative(view_dir, path.substring(0, path.length - '.locals.js'.length));
|
|
||||||
const cacheId = [fragment, language, md5(JSON.stringify(_locals))].join('-');
|
|
||||||
|
|
||||||
if (!__fragmentCache.has(cacheId)) {
|
|
||||||
__fragmentCache.set(cacheId, partial(name, _locals, { cache: false, only: options.only || false }));
|
|
||||||
}
|
|
||||||
return __fragmentCache.get(cacheId);
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -2,50 +2,10 @@
|
||||||
* Helper functions for page/post.
|
* Helper functions for page/post.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* <%- is_categories(page) %>
|
|
||||||
* <%- is_tags(page) %>
|
|
||||||
* <%- page_title(page) %>
|
|
||||||
* <%- has_thumbnail(post) %>
|
* <%- has_thumbnail(post) %>
|
||||||
* <%- get_thumbnail(post) %>
|
* <%- get_thumbnail(post) %>
|
||||||
* <%- get_og_image(post) %>
|
|
||||||
*/
|
*/
|
||||||
module.exports = function (hexo) {
|
module.exports = function (hexo) {
|
||||||
hexo.extend.helper.register('is_categories', function (page = null) {
|
|
||||||
return (page === null ? this.page : page).__categories;
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('is_tags', function (page = null) {
|
|
||||||
return (page === null ? this.page : page).__tags;
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate html head title based on page type
|
|
||||||
*/
|
|
||||||
hexo.extend.helper.register('page_title', function (page = null) {
|
|
||||||
page = page === null ? this.page : page;
|
|
||||||
let title = page.title;
|
|
||||||
|
|
||||||
if (this.is_archive()) {
|
|
||||||
title = this._p('common.archive', Infinity);
|
|
||||||
if (this.is_month()) {
|
|
||||||
title += ': ' + page.year + '/' + page.month;
|
|
||||||
} else if (this.is_year()) {
|
|
||||||
title += ': ' + page.year;
|
|
||||||
}
|
|
||||||
} else if (this.is_category()) {
|
|
||||||
title = this._p('common.category', 1) + ': ' + page.category;
|
|
||||||
} else if (this.is_tag()) {
|
|
||||||
title = this._p('common.tag', 1) + ': ' + page.tag;
|
|
||||||
} else if (this.is_categories()) {
|
|
||||||
title = this._p('common.category', Infinity);
|
|
||||||
} else if (this.is_tags()) {
|
|
||||||
title = this._p('common.tag', Infinity);
|
|
||||||
}
|
|
||||||
|
|
||||||
const siteTitle = hexo.extend.helper.get('get_config').bind(this)('title', '', true);
|
|
||||||
return [title, siteTitle].filter(str => typeof (str) !== 'undefined' && str.trim() !== '').join(' - ');
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('has_thumbnail', function (post) {
|
hexo.extend.helper.register('has_thumbnail', function (post) {
|
||||||
const getConfig = hexo.extend.helper.get('get_config').bind(this);
|
const getConfig = hexo.extend.helper.get('get_config').bind(this);
|
||||||
const allowThumbnail = getConfig('article.thumbnail', true);
|
const allowThumbnail = getConfig('article.thumbnail', true);
|
||||||
|
@ -59,29 +19,4 @@ module.exports = function (hexo) {
|
||||||
const hasThumbnail = hexo.extend.helper.get('has_thumbnail').bind(this)(post);
|
const hasThumbnail = hexo.extend.helper.get('has_thumbnail').bind(this)(post);
|
||||||
return this.url_for(hasThumbnail ? post.thumbnail : 'images/thumbnail.svg');
|
return this.url_for(hasThumbnail ? post.thumbnail : 'images/thumbnail.svg');
|
||||||
});
|
});
|
||||||
|
|
||||||
hexo.extend.helper.register('has_og_image', function (post) {
|
|
||||||
return post.hasOwnProperty('og_image');
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('get_og_image', function (post) {
|
|
||||||
const getConfig = hexo.extend.helper.get('get_config').bind(this);
|
|
||||||
const hasConfig = hexo.extend.helper.get('has_config').bind(this);
|
|
||||||
|
|
||||||
const hasOGImage = hexo.extend.helper.get('has_og_image').bind(this)(post);
|
|
||||||
const hasThumbnail = hexo.extend.helper.get('has_thumbnail').bind(this)(post);
|
|
||||||
|
|
||||||
const getThumbnail = hexo.extend.helper.get('get_thumbnail').bind(this);
|
|
||||||
|
|
||||||
let og_image
|
|
||||||
|
|
||||||
if (hasOGImage)
|
|
||||||
og_image = post.og_image
|
|
||||||
else if (hasThumbnail)
|
|
||||||
og_image = getThumbnail(post);
|
|
||||||
else
|
|
||||||
og_image = getConfig('article.og_image', '/images/og_image.png');
|
|
||||||
|
|
||||||
return this.url_for(og_image);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
/**
|
|
||||||
* Helper functions related the site properties.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* <%- is_same_link(url_a, url_b) %>
|
|
||||||
* <%- get_domain(url) %>
|
|
||||||
* <%- post_count() %>
|
|
||||||
* <%- category_count() %>
|
|
||||||
* <%- tag_count() %>
|
|
||||||
* <%- duration() %>
|
|
||||||
* <%- word_count(content) %>
|
|
||||||
* <%- md5(data) %>
|
|
||||||
* <%- meta() %>
|
|
||||||
* <%- hexo_version() %>
|
|
||||||
*/
|
|
||||||
const URL = require('url').URL;
|
|
||||||
const moment = require('moment');
|
|
||||||
const crypto = require('crypto');
|
|
||||||
|
|
||||||
module.exports = function (hexo) {
|
|
||||||
hexo.extend.helper.register('is_same_link', function (a, b) {
|
|
||||||
function santize(url) {
|
|
||||||
let paths = url.replace(/(^\w+:|^)\/\//, '').split('#')[0].split('/').filter(p => p.trim() !== '');
|
|
||||||
if (paths.length > 0 && paths[paths.length - 1].trim() === 'index.html') {
|
|
||||||
paths = paths.slice(0, paths.length - 1)
|
|
||||||
}
|
|
||||||
return paths.join('/');
|
|
||||||
}
|
|
||||||
return santize(this.url_for(a)) == santize(this.url_for(b));
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('get_domain', function (link) {
|
|
||||||
const url = new URL(link);
|
|
||||||
return url.hostname;
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('post_count', function () {
|
|
||||||
return this.site.posts.length;
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('category_count', function () {
|
|
||||||
return this.site.categories.filter(category => category.length).length;
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('tag_count', function () {
|
|
||||||
return this.site.tags.filter(tag => tag.length).length;
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Export moment.duration
|
|
||||||
*/
|
|
||||||
hexo.extend.helper.register('duration', function () {
|
|
||||||
return moment.duration.apply(moment, arguments);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the word count of a paragraph.
|
|
||||||
*/
|
|
||||||
hexo.extend.helper.register('word_count', function (content) {
|
|
||||||
content = content.replace(/<\/?[a-z][^>]*>/gi, '');
|
|
||||||
content = content.trim();
|
|
||||||
return content ? (content.match(/[\u00ff-\uffff]|[a-zA-Z]+/g) || []).length : 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('md5', function (data) {
|
|
||||||
return crypto.createHash('md5').update(data).digest("hex");
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('meta', function () {
|
|
||||||
function trim(str) {
|
|
||||||
return str.trim().replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1');
|
|
||||||
}
|
|
||||||
|
|
||||||
function split(str, sep) {
|
|
||||||
const result = [];
|
|
||||||
let matched = null;
|
|
||||||
while (matched = sep.exec(str)) {
|
|
||||||
result.push(matched[0]);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getConfig = hexo.extend.helper.get('get_config').bind(this);
|
|
||||||
const metas = getConfig('meta', []);
|
|
||||||
const metaDOMArray = metas.map(function (meta) {
|
|
||||||
const entities = split(meta, /(?:[^\\;]+|\\.)+/g);
|
|
||||||
const entityArray = entities.map(function (entity) {
|
|
||||||
const keyValue = split(entity, /(?:[^\\=]+|\\.)+/g);
|
|
||||||
if (keyValue.length < 2) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const key = trim(keyValue[0]);
|
|
||||||
const value = trim(keyValue[1]);
|
|
||||||
return key + '="' + value + '"';
|
|
||||||
}).filter(function (entity) {
|
|
||||||
return entity;
|
|
||||||
});
|
|
||||||
return '<meta ' + entityArray.join(' ') + ' />';
|
|
||||||
});
|
|
||||||
return metaDOMArray.join('\n');
|
|
||||||
});
|
|
||||||
|
|
||||||
hexo.extend.helper.register('hexo_version', function (data) {
|
|
||||||
return hexo.version;
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,305 +0,0 @@
|
||||||
/**
|
|
||||||
* A doubly linked list-based Least Recently Used (LRU) cache. Will keep most
|
|
||||||
* recently used items while discarding least recently used items when its limit
|
|
||||||
* is reached.
|
|
||||||
*
|
|
||||||
* Licensed under MIT. Copyright (c) 2010 Rasmus Andersson <http://hunch.se/>
|
|
||||||
* See README.md for details.
|
|
||||||
*
|
|
||||||
* Illustration of the design:
|
|
||||||
*
|
|
||||||
* entry entry entry entry
|
|
||||||
* ______ ______ ______ ______
|
|
||||||
* | head |.newer => | |.newer => | |.newer => | tail |
|
|
||||||
* | A | | B | | C | | D |
|
|
||||||
* |______| <= older.|______| <= older.|______| <= older.|______|
|
|
||||||
*
|
|
||||||
* removed <-- <-- <-- <-- <-- <-- <-- <-- <-- <-- <-- added
|
|
||||||
*/
|
|
||||||
(function (g, f) {
|
|
||||||
const e = typeof exports == 'object' ? exports : typeof g == 'object' ? g : {};
|
|
||||||
f(e);
|
|
||||||
if (typeof define == 'function' && define.amd) { define('lru', e); }
|
|
||||||
})(this, function (exports) {
|
|
||||||
|
|
||||||
const NEWER = Symbol('newer');
|
|
||||||
const OLDER = Symbol('older');
|
|
||||||
|
|
||||||
function LRUMap(limit, entries) {
|
|
||||||
if (typeof limit !== 'number') {
|
|
||||||
// called as (entries)
|
|
||||||
entries = limit;
|
|
||||||
limit = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.size = 0;
|
|
||||||
this.limit = limit;
|
|
||||||
this.oldest = this.newest = undefined;
|
|
||||||
this._keymap = new Map();
|
|
||||||
|
|
||||||
if (entries) {
|
|
||||||
this.assign(entries);
|
|
||||||
if (limit < 1) {
|
|
||||||
this.limit = this.size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.LRUMap = LRUMap;
|
|
||||||
|
|
||||||
function Entry(key, value) {
|
|
||||||
this.key = key;
|
|
||||||
this.value = value;
|
|
||||||
this[NEWER] = undefined;
|
|
||||||
this[OLDER] = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LRUMap.prototype._markEntryAsUsed = function (entry) {
|
|
||||||
if (entry === this.newest) {
|
|
||||||
// Already the most recenlty used entry, so no need to update the list
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// HEAD--------------TAIL
|
|
||||||
// <.older .newer>
|
|
||||||
// <--- add direction --
|
|
||||||
// A B C <D> E
|
|
||||||
if (entry[NEWER]) {
|
|
||||||
if (entry === this.oldest) {
|
|
||||||
this.oldest = entry[NEWER];
|
|
||||||
}
|
|
||||||
entry[NEWER][OLDER] = entry[OLDER]; // C <-- E.
|
|
||||||
}
|
|
||||||
if (entry[OLDER]) {
|
|
||||||
entry[OLDER][NEWER] = entry[NEWER]; // C. --> E
|
|
||||||
}
|
|
||||||
entry[NEWER] = undefined; // D --x
|
|
||||||
entry[OLDER] = this.newest; // D. --> E
|
|
||||||
if (this.newest) {
|
|
||||||
this.newest[NEWER] = entry; // E. <-- D
|
|
||||||
}
|
|
||||||
this.newest = entry;
|
|
||||||
};
|
|
||||||
|
|
||||||
LRUMap.prototype.assign = function (entries) {
|
|
||||||
let entry, limit = this.limit || Number.MAX_VALUE;
|
|
||||||
this._keymap.clear();
|
|
||||||
let it = entries[Symbol.iterator]();
|
|
||||||
for (let itv = it.next(); !itv.done; itv = it.next()) {
|
|
||||||
let e = new Entry(itv.value[0], itv.value[1]);
|
|
||||||
this._keymap.set(e.key, e);
|
|
||||||
if (!entry) {
|
|
||||||
this.oldest = e;
|
|
||||||
} else {
|
|
||||||
entry[NEWER] = e;
|
|
||||||
e[OLDER] = entry;
|
|
||||||
}
|
|
||||||
entry = e;
|
|
||||||
if (limit-- == 0) {
|
|
||||||
throw new Error('overflow');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.newest = entry;
|
|
||||||
this.size = this._keymap.size;
|
|
||||||
};
|
|
||||||
|
|
||||||
LRUMap.prototype.get = function (key) {
|
|
||||||
// First, find our cache entry
|
|
||||||
var entry = this._keymap.get(key);
|
|
||||||
if (!entry) return; // Not cached. Sorry.
|
|
||||||
// As <key> was found in the cache, register it as being requested recently
|
|
||||||
this._markEntryAsUsed(entry);
|
|
||||||
return entry.value;
|
|
||||||
};
|
|
||||||
|
|
||||||
LRUMap.prototype.set = function (key, value) {
|
|
||||||
var entry = this._keymap.get(key);
|
|
||||||
|
|
||||||
if (entry) {
|
|
||||||
// update existing
|
|
||||||
entry.value = value;
|
|
||||||
this._markEntryAsUsed(entry);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// new entry
|
|
||||||
this._keymap.set(key, (entry = new Entry(key, value)));
|
|
||||||
|
|
||||||
if (this.newest) {
|
|
||||||
// link previous tail to the new tail (entry)
|
|
||||||
this.newest[NEWER] = entry;
|
|
||||||
entry[OLDER] = this.newest;
|
|
||||||
} else {
|
|
||||||
// we're first in -- yay
|
|
||||||
this.oldest = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add new entry to the end of the linked list -- it's now the freshest entry.
|
|
||||||
this.newest = entry;
|
|
||||||
++this.size;
|
|
||||||
if (this.size > this.limit) {
|
|
||||||
// we hit the limit -- remove the head
|
|
||||||
this.shift();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
LRUMap.prototype.shift = function () {
|
|
||||||
// todo: handle special case when limit == 1
|
|
||||||
var entry = this.oldest;
|
|
||||||
if (entry) {
|
|
||||||
if (this.oldest[NEWER]) {
|
|
||||||
// advance the list
|
|
||||||
this.oldest = this.oldest[NEWER];
|
|
||||||
this.oldest[OLDER] = undefined;
|
|
||||||
} else {
|
|
||||||
// the cache is exhausted
|
|
||||||
this.oldest = undefined;
|
|
||||||
this.newest = undefined;
|
|
||||||
}
|
|
||||||
// Remove last strong reference to <entry> and remove links from the purged
|
|
||||||
// entry being returned:
|
|
||||||
entry[NEWER] = entry[OLDER] = undefined;
|
|
||||||
this._keymap.delete(entry.key);
|
|
||||||
--this.size;
|
|
||||||
return [entry.key, entry.value];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Following code is optional and can be removed without breaking the core
|
|
||||||
// functionality.
|
|
||||||
|
|
||||||
LRUMap.prototype.find = function (key) {
|
|
||||||
let e = this._keymap.get(key);
|
|
||||||
return e ? e.value : undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
LRUMap.prototype.has = function (key) {
|
|
||||||
return this._keymap.has(key);
|
|
||||||
};
|
|
||||||
|
|
||||||
LRUMap.prototype['delete'] = function (key) {
|
|
||||||
var entry = this._keymap.get(key);
|
|
||||||
if (!entry) return;
|
|
||||||
this._keymap.delete(entry.key);
|
|
||||||
if (entry[NEWER] && entry[OLDER]) {
|
|
||||||
// relink the older entry with the newer entry
|
|
||||||
entry[OLDER][NEWER] = entry[NEWER];
|
|
||||||
entry[NEWER][OLDER] = entry[OLDER];
|
|
||||||
} else if (entry[NEWER]) {
|
|
||||||
// remove the link to us
|
|
||||||
entry[NEWER][OLDER] = undefined;
|
|
||||||
// link the newer entry to head
|
|
||||||
this.oldest = entry[NEWER];
|
|
||||||
} else if (entry[OLDER]) {
|
|
||||||
// remove the link to us
|
|
||||||
entry[OLDER][NEWER] = undefined;
|
|
||||||
// link the newer entry to head
|
|
||||||
this.newest = entry[OLDER];
|
|
||||||
} else {// if(entry[OLDER] === undefined && entry.newer === undefined) {
|
|
||||||
this.oldest = this.newest = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.size--;
|
|
||||||
return entry.value;
|
|
||||||
};
|
|
||||||
|
|
||||||
LRUMap.prototype.clear = function () {
|
|
||||||
// Not clearing links should be safe, as we don't expose live links to user
|
|
||||||
this.oldest = this.newest = undefined;
|
|
||||||
this.size = 0;
|
|
||||||
this._keymap.clear();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function EntryIterator(oldestEntry) { this.entry = oldestEntry; }
|
|
||||||
EntryIterator.prototype[Symbol.iterator] = function () { return this; }
|
|
||||||
EntryIterator.prototype.next = function () {
|
|
||||||
let ent = this.entry;
|
|
||||||
if (ent) {
|
|
||||||
this.entry = ent[NEWER];
|
|
||||||
return { done: false, value: [ent.key, ent.value] };
|
|
||||||
} else {
|
|
||||||
return { done: true, value: undefined };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
function KeyIterator(oldestEntry) { this.entry = oldestEntry; }
|
|
||||||
KeyIterator.prototype[Symbol.iterator] = function () { return this; }
|
|
||||||
KeyIterator.prototype.next = function () {
|
|
||||||
let ent = this.entry;
|
|
||||||
if (ent) {
|
|
||||||
this.entry = ent[NEWER];
|
|
||||||
return { done: false, value: ent.key };
|
|
||||||
} else {
|
|
||||||
return { done: true, value: undefined };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function ValueIterator(oldestEntry) { this.entry = oldestEntry; }
|
|
||||||
ValueIterator.prototype[Symbol.iterator] = function () { return this; }
|
|
||||||
ValueIterator.prototype.next = function () {
|
|
||||||
let ent = this.entry;
|
|
||||||
if (ent) {
|
|
||||||
this.entry = ent[NEWER];
|
|
||||||
return { done: false, value: ent.value };
|
|
||||||
} else {
|
|
||||||
return { done: true, value: undefined };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
LRUMap.prototype.keys = function () {
|
|
||||||
return new KeyIterator(this.oldest);
|
|
||||||
};
|
|
||||||
|
|
||||||
LRUMap.prototype.values = function () {
|
|
||||||
return new ValueIterator(this.oldest);
|
|
||||||
};
|
|
||||||
|
|
||||||
LRUMap.prototype.entries = function () {
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
LRUMap.prototype[Symbol.iterator] = function () {
|
|
||||||
return new EntryIterator(this.oldest);
|
|
||||||
};
|
|
||||||
|
|
||||||
LRUMap.prototype.forEach = function (fun, thisObj) {
|
|
||||||
if (typeof thisObj !== 'object') {
|
|
||||||
thisObj = this;
|
|
||||||
}
|
|
||||||
let entry = this.oldest;
|
|
||||||
while (entry) {
|
|
||||||
fun.call(thisObj, entry.value, entry.key, this);
|
|
||||||
entry = entry[NEWER];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Returns a JSON (array) representation */
|
|
||||||
LRUMap.prototype.toJSON = function () {
|
|
||||||
var s = new Array(this.size), i = 0, entry = this.oldest;
|
|
||||||
while (entry) {
|
|
||||||
s[i++] = { key: entry.key, value: entry.value };
|
|
||||||
entry = entry[NEWER];
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Returns a String representation */
|
|
||||||
LRUMap.prototype.toString = function () {
|
|
||||||
var s = '', entry = this.oldest;
|
|
||||||
while (entry) {
|
|
||||||
s += String(entry.key) + ':' + entry.value;
|
|
||||||
entry = entry[NEWER];
|
|
||||||
if (entry) {
|
|
||||||
s += ' < ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
|
|
@ -17,10 +17,10 @@ module.exports = class extends Component {
|
||||||
function renderArticleList(posts, year, month = null) {
|
function renderArticleList(posts, year, month = null) {
|
||||||
const time = moment([page.year, page.month ? page.month - 1 : null].filter(i => i !== null));
|
const time = moment([page.year, page.month ? page.month - 1 : null].filter(i => i !== null));
|
||||||
|
|
||||||
return <div class="card widget">
|
return <div className="card widget">
|
||||||
<div class="card-content">
|
<div className="card-content">
|
||||||
<h3 class="tag is-link">{month === null ? year : time.locale(language).format('MMMM YYYY')}</h3>
|
<h3 className="tag is-link">{month === null ? year : time.locale(language).format('MMMM YYYY')}</h3>
|
||||||
<div class="timeline">
|
<div className="timeline">
|
||||||
{posts.map(post => {
|
{posts.map(post => {
|
||||||
const categories = [];
|
const categories = [];
|
||||||
post.categories.forEach((category, i) => {
|
post.categories.forEach((category, i) => {
|
||||||
|
@ -29,21 +29,21 @@ module.exports = class extends Component {
|
||||||
categories.push('/');
|
categories.push('/');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return <article class="media">
|
return <article className="media">
|
||||||
{has_thumbnail(post) ? <a href={url_for((post.link || post.path))} class="media-left">
|
{has_thumbnail(post) ? <a href={url_for((post.link || post.path))} className="media-left">
|
||||||
<p class="image is-64x64">
|
<p className="image is-64x64">
|
||||||
<img class="thumbnail" src={get_thumbnail(post)} alt={post.title || get_thumbnail(post)} />
|
<img className="thumbnail" src={get_thumbnail(post)} alt={post.title || get_thumbnail(post)} />
|
||||||
</p>
|
</p>
|
||||||
</a> : null}
|
</a> : null}
|
||||||
<div class="media-content">
|
<div className="media-content">
|
||||||
<div class="content">
|
<div className="content">
|
||||||
<time class="has-text-grey is-size-7 is-block is-uppercase"
|
<time className="has-text-grey is-size-7 is-block is-uppercase"
|
||||||
datetime={date_xml(post.date)}>{date(post.date)}</time>
|
datetime={date_xml(post.date)}>{date(post.date)}</time>
|
||||||
<a class="title has-link-black-ter is-size-6 has-text-weight-normal"
|
<a className="title has-link-black-ter is-size-6 has-text-weight-normal"
|
||||||
href={url_for((post.link || post.path))} >{post.title}</a>
|
href={url_for((post.link || post.path))} >{post.title}</a>
|
||||||
<div class="level article-meta is-mobile">
|
<div className="level article-meta is-mobile">
|
||||||
<div class="level-left">
|
<div className="level-left">
|
||||||
{categories.length ? <div class="level-item is-size-7 is-uppercase">
|
{categories.length ? <div className="level-item is-size-7 is-uppercase">
|
||||||
{categories}
|
{categories}
|
||||||
</div> : null}
|
</div> : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,15 +11,15 @@ module.exports = class extends Component {
|
||||||
const { url_for, _p } = helper;
|
const { url_for, _p } = helper;
|
||||||
|
|
||||||
return <Fragment>
|
return <Fragment>
|
||||||
<div class="card">
|
<div className="card">
|
||||||
<div class="card-content">
|
<div className="card-content">
|
||||||
<nav class="breadcrumb" aria-label="breadcrumbs">
|
<nav className="breadcrumb" aria-label="breadcrumbs">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href={url_for('/categories')}>{_p('common.category', Infinity)}</a></li>
|
<li><a href={url_for('/categories')}>{_p('common.category', Infinity)}</a></li>
|
||||||
{page.parents.map(category => {
|
{page.parents.map(category => {
|
||||||
return <li><a href={url_for(category.path)}>{category.name}</a></li>
|
return <li><a href={url_for(category.path)}>{category.name}</a></li>
|
||||||
})}
|
})}
|
||||||
<li class="is-active"><a href="#" aria-current="page">{page.category}</a></li>
|
<li className="is-active"><a href="#" aria-current="page">{page.category}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,6 +5,78 @@ const MetaTags = require('../misc/meta');
|
||||||
const OpenGraph = require('../misc/open_graph');
|
const OpenGraph = require('../misc/open_graph');
|
||||||
const Plugins = require('./plugins');
|
const Plugins = require('./plugins');
|
||||||
|
|
||||||
|
function isArchivePage(page) {
|
||||||
|
return !!page.archive;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCategoriesPage(page) {
|
||||||
|
return !!page.__categories;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTagsPage(page) {
|
||||||
|
return !!page.__tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMonthPage(page, year, month) {
|
||||||
|
if (!isArchivePage(page)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (year) {
|
||||||
|
if (month) {
|
||||||
|
return page.year === year && page.month === month;
|
||||||
|
}
|
||||||
|
return page.month === year;
|
||||||
|
}
|
||||||
|
return page.year && page.month;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isYearPage(page, year) {
|
||||||
|
if (!isArchivePage(page)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (year) {
|
||||||
|
return page.year === year;
|
||||||
|
}
|
||||||
|
return !!page.year;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCategoryPage(page, category) {
|
||||||
|
if (category) {
|
||||||
|
return page.category === category;
|
||||||
|
}
|
||||||
|
return !!page.category;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTagPage(page, tag) {
|
||||||
|
if (tag) {
|
||||||
|
return page.tag === tag;
|
||||||
|
}
|
||||||
|
return !!page.tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPageTitle(page, siteTitle, _p) {
|
||||||
|
let title = page.title;
|
||||||
|
|
||||||
|
if (isArchivePage(page)) {
|
||||||
|
title = _p('common.archive', Infinity);
|
||||||
|
if (isMonthPage()) {
|
||||||
|
title += ': ' + page.year + '/' + page.month;
|
||||||
|
} else if (isYearPage(page)) {
|
||||||
|
title += ': ' + page.year;
|
||||||
|
}
|
||||||
|
} else if (isCategoryPage()) {
|
||||||
|
title = _p('common.category', 1) + ': ' + page.category;
|
||||||
|
} else if (isTagPage()) {
|
||||||
|
title = _p('common.tag', 1) + ': ' + page.tag;
|
||||||
|
} else if (isCategoriesPage(page)) {
|
||||||
|
title = _p('common.category', Infinity);
|
||||||
|
} else if (isTagsPage(page)) {
|
||||||
|
title = _p('common.tag', Infinity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [title, siteTitle].filter(str => typeof (str) !== 'undefined' && str.trim() !== '').join(' - ');
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = class extends Component {
|
module.exports = class extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { env, site, config, helper, page } = this.props;
|
const { env, site, config, helper, page } = this.props;
|
||||||
|
@ -55,6 +127,8 @@ module.exports = class extends Component {
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||||
<MetaTags meta={meta} />
|
<MetaTags meta={meta} />
|
||||||
|
|
||||||
|
<title>{getPageTitle(page, config.title, _p)}</title>
|
||||||
|
|
||||||
{open_graph ? <OpenGraph
|
{open_graph ? <OpenGraph
|
||||||
type={is_post() ? 'article' : 'website'}
|
type={is_post() ? 'article' : 'website'}
|
||||||
title={page.title || config.title}
|
title={page.title || config.title}
|
||||||
|
|
|
@ -22,12 +22,12 @@ module.exports = class extends Component {
|
||||||
<head>
|
<head>
|
||||||
<Head env={env} site={site} config={config} helper={helper} page={page} />
|
<Head env={env} site={site} config={config} helper={helper} page={page} />
|
||||||
</head>
|
</head>
|
||||||
<body class={`is-${columnCount}-column`}>
|
<body className={`is-${columnCount}-column`}>
|
||||||
<Navbar config={config} helper={helper} page={page} />
|
<Navbar config={config} helper={helper} page={page} />
|
||||||
<section class="section">
|
<section className="section">
|
||||||
<div class="container">
|
<div className="container">
|
||||||
<div class="columns">
|
<div className="columns">
|
||||||
<div class={{
|
<div className={{
|
||||||
column: true,
|
column: true,
|
||||||
'has-order-2': true,
|
'has-order-2': true,
|
||||||
'column-main': true,
|
'column-main': true,
|
||||||
|
|
|
@ -11,12 +11,12 @@ module.exports = class extends Component {
|
||||||
const { url_for, _p } = helper;
|
const { url_for, _p } = helper;
|
||||||
|
|
||||||
return <Fragment>
|
return <Fragment>
|
||||||
<div class="card">
|
<div className="card">
|
||||||
<div class="card-content">
|
<div className="card-content">
|
||||||
<nav class="breadcrumb" aria-label="breadcrumbs">
|
<nav className="breadcrumb" aria-label="breadcrumbs">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href={url_for('/tags')}>{_p('common.tag', Infinity)}</a></li>
|
<li><a href={url_for('/tags')}>{_p('common.tag', Infinity)}</a></li>
|
||||||
<li class="is-active"><a href="#" aria-current="page">{page.tag}</a></li>
|
<li className="is-active"><a href="#" aria-current="page">{page.tag}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,10 +7,7 @@ require('../includes/generators/tags')(hexo);
|
||||||
require('../includes/generators/insight')(hexo);
|
require('../includes/generators/insight')(hexo);
|
||||||
require('../includes/helpers/cdn')(hexo);
|
require('../includes/helpers/cdn')(hexo);
|
||||||
require('../includes/helpers/config')(hexo);
|
require('../includes/helpers/config')(hexo);
|
||||||
require('../includes/helpers/layout')(hexo);
|
|
||||||
require('../includes/helpers/override')(hexo);
|
|
||||||
require('../includes/helpers/page')(hexo);
|
require('../includes/helpers/page')(hexo);
|
||||||
require('../includes/helpers/site')(hexo);
|
|
||||||
|
|
||||||
// Fix large blog rendering OOM
|
// Fix large blog rendering OOM
|
||||||
const hooks = [
|
const hooks = [
|
||||||
|
|
Loading…
Reference in New Issue