hexo-component-inferno 4.2.2 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -18
- package/asset/css/github-calendar.css +41 -0
- package/asset/js/algolia.js +18 -69
- package/asset/js/github-calendar.js +185 -0
- package/asset/js/google_cse.js +19 -68
- package/asset/js/insight.js +45 -208
- package/lib/core/commented_yaml.js +35 -0
- package/lib/core/default_value.js +150 -0
- package/lib/core/schema.js +8 -196
- package/lib/core/schema_util.js +14 -0
- package/lib/hexo/helper/cdn.js +10 -97
- package/lib/hexo/tag/tabs.js +4 -84
- package/lib/schema/comment/artalk.json +7 -1
- package/lib/schema/comment/cusdis.json +1 -1
- package/lib/schema/comment/facebook.json +1 -1
- package/lib/schema/comment/gitalk.json +23 -6
- package/lib/schema/comment/gitment.json +1 -1
- package/lib/schema/comment/livere.json +9 -3
- package/lib/schema/comment/twikoo.json +3 -3
- package/lib/schema/comment/waline.json +28 -3
- package/lib/schema/misc/open_graph.json +2 -1
- package/lib/schema/plugin/cookie_consent.json +2 -2
- package/lib/schema/plugin/mathjax.json +1 -1
- package/lib/schema/plugin/outdated_browser.json +1 -1
- package/lib/schema/share/bdshare.json +1 -1
- package/lib/schema/share/sharejs.json +1 -1
- package/lib/schema/share/web_share.json +13 -0
- package/lib/schema/widget/github_calendar.json +30 -0
- package/lib/schema/widget/profile.json +67 -0
- package/lib/util/archives.js +86 -0
- package/lib/util/categories.js +102 -0
- package/lib/util/cdn-rules.js +109 -0
- package/lib/util/cdn.js +116 -0
- package/lib/util/consent.js +122 -0
- package/lib/util/deprecate.js +1 -1
- package/lib/util/gallery.js +227 -0
- package/lib/util/insight-search.js +98 -0
- package/lib/util/searchbox.js +88 -0
- package/lib/util/tab-options.js +109 -0
- package/lib/view/comment/artalk.js +24 -6
- package/lib/view/comment/cusdis.js +4 -0
- package/lib/view/comment/disqus.js +1 -1
- package/lib/view/comment/disqusjs.js +7 -6
- package/lib/view/comment/facebook.js +3 -16
- package/lib/view/comment/gitalk.js +18 -15
- package/lib/view/comment/gitment.js +2 -2
- package/lib/view/comment/livere.js +25 -4
- package/lib/view/comment/twikoo.js +5 -3
- package/lib/view/comment/valine.js +4 -3
- package/lib/view/comment/waline.js +8 -6
- package/lib/view/misc/open_graph.js +3 -5
- package/lib/view/plugin/cookie_consent.js +8 -7
- package/lib/view/plugin/gallery.js +42 -19
- package/lib/view/plugin/katex.js +4 -4
- package/lib/view/plugin/mathjax.js +10 -7
- package/lib/view/plugin/outdated_browser.js +59 -45
- package/lib/view/plugin/progressbar.js +6 -1
- package/lib/view/plugin/waline_pageview.js +2 -2
- package/lib/view/search/algolia.js +8 -3
- package/lib/view/search/google_cse.js +13 -10
- package/lib/view/search/insight.js +9 -2
- package/lib/view/share/addthis.js +4 -9
- package/lib/view/share/addtoany.js +23 -5
- package/lib/view/share/bdshare.js +9 -30
- package/lib/view/share/sharejs.js +7 -34
- package/lib/view/share/sharethis.js +21 -6
- package/lib/view/share/web_share.js +153 -0
- package/lib/view/widget/archives.js +19 -71
- package/lib/view/widget/categories.js +20 -67
- package/lib/view/widget/github_calendar.js +94 -0
- package/lib/view/widget/profile.js +194 -0
- package/lib/view/widget/subscribe_email.js +4 -26
- package/package.json +6 -4
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"$id": "/plugin/cookie_consent.json",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "Cookie notice and tracking consent\nhttps://www.osano.com/cookieconsent/",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
|
7
7
|
"type": {
|
|
8
8
|
"type": "string",
|
|
9
|
-
"description": "
|
|
9
|
+
"description": "info: notice only; opt-in: load after consent; opt-out: load until denied",
|
|
10
10
|
"default": "info",
|
|
11
11
|
"nullable": true
|
|
12
12
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"$id": "/plugin/mathjax.json",
|
|
4
|
-
"description": "Enable
|
|
4
|
+
"description": "Enable MathJax math typesetting\nhttps://www.mathjax.org/",
|
|
5
5
|
"type": "boolean",
|
|
6
6
|
"default": false
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"$id": "/plugin/outdated_browser.json",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "Warn when required CSS features are unsupported",
|
|
5
5
|
"type": "boolean",
|
|
6
6
|
"default": false
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"$id": "/share/sharejs.json",
|
|
4
|
-
"description": "
|
|
4
|
+
"description": "Share.js (retired; select web_share or addtoany)",
|
|
5
5
|
"type": "object",
|
|
6
6
|
"properties": {
|
|
7
7
|
"type": {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "/share/web_share.json",
|
|
4
|
+
"description": "Social sharing links and a native Web Share button",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"type": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"const": "web_share"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"required": ["type"]
|
|
13
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "/widget/github_calendar.json",
|
|
4
|
+
"description": "Responsive GitHub contribution calendar. Data is loaded from the third-party github-contributions-api.jogruber.de service; no GitHub token is needed",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"type": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"const": "github_calendar"
|
|
10
|
+
},
|
|
11
|
+
"username": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"description": "GitHub username. Leave empty to hide this widget",
|
|
14
|
+
"pattern": "^$|^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,37}[a-zA-Z0-9])?$",
|
|
15
|
+
"nullable": true
|
|
16
|
+
},
|
|
17
|
+
"title": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "Widget title. Leave empty to use the translated default",
|
|
20
|
+
"nullable": true
|
|
21
|
+
},
|
|
22
|
+
"color": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Optional six-digit hex color, for example '#40c463'. Leave empty to use the theme's calendar palette",
|
|
25
|
+
"pattern": "^$|^#?[a-fA-F0-9]{6}$",
|
|
26
|
+
"nullable": true
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"required": ["type"]
|
|
30
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "/widget/profile.json",
|
|
4
|
+
"description": "Profile widget configurations",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"type": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"const": "profile",
|
|
10
|
+
"nullable": true
|
|
11
|
+
},
|
|
12
|
+
"author": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "Author name",
|
|
15
|
+
"examples": ["Your name"],
|
|
16
|
+
"nullable": true
|
|
17
|
+
},
|
|
18
|
+
"author_title": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "Author title",
|
|
21
|
+
"examples": ["Your title"],
|
|
22
|
+
"nullable": true
|
|
23
|
+
},
|
|
24
|
+
"location": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"description": "Author's current location",
|
|
27
|
+
"examples": ["Your location"],
|
|
28
|
+
"nullable": true
|
|
29
|
+
},
|
|
30
|
+
"avatar": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"description": "URL or path to the avatar image",
|
|
33
|
+
"nullable": true
|
|
34
|
+
},
|
|
35
|
+
"avatar_rounded": {
|
|
36
|
+
"type": "boolean",
|
|
37
|
+
"description": "Whether show the rounded avatar image",
|
|
38
|
+
"default": false,
|
|
39
|
+
"nullable": true
|
|
40
|
+
},
|
|
41
|
+
"gravatar": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"description": "Email address for the Gravatar",
|
|
44
|
+
"nullable": true
|
|
45
|
+
},
|
|
46
|
+
"follow_link": {
|
|
47
|
+
"type": "string",
|
|
48
|
+
"description": "URL or path for the follow button",
|
|
49
|
+
"examples": ["https://github.com/ppoffice"],
|
|
50
|
+
"nullable": true
|
|
51
|
+
},
|
|
52
|
+
"social_links": {
|
|
53
|
+
"$ref": "/misc/poly_links.json",
|
|
54
|
+
"description": "Links to be shown on the bottom of the profile widget",
|
|
55
|
+
"examples": [
|
|
56
|
+
{
|
|
57
|
+
"Github": { "icon": "fab fa-github", "url": "https://github.com/ppoffice" },
|
|
58
|
+
"Facebook": { "icon": "fab fa-facebook", "url": "https://facebook.com" },
|
|
59
|
+
"Twitter": { "icon": "fab fa-twitter", "url": "https://twitter.com" },
|
|
60
|
+
"Dribbble": { "icon": "fab fa-dribbble", "url": "https://dribbble.com" },
|
|
61
|
+
"RSS": { "icon": "fas fa-rss", "url": "/" }
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"required": ["type"]
|
|
67
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal option and grouping logic for the archives widget. No Hexo imports, helpers or JSX.
|
|
3
|
+
* @module util/archives
|
|
4
|
+
* @private
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
function firstSet(...values) {
|
|
8
|
+
return values.find(value => value !== null && typeof value !== 'undefined');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolve archive option aliases/defaults without coercing false, zero or empty strings.
|
|
13
|
+
* @param {Object} widget Archives widget options.
|
|
14
|
+
* @returns {Object} Resolved grouping, ordering, formatting, limit and count-display options.
|
|
15
|
+
*/
|
|
16
|
+
function resolveArchiveOptions(widget) {
|
|
17
|
+
const groupBy = firstSet(widget.group_by, 'monthly');
|
|
18
|
+
const order = firstSet(widget.order, -1);
|
|
19
|
+
const {
|
|
20
|
+
format,
|
|
21
|
+
amount
|
|
22
|
+
} = widget;
|
|
23
|
+
const showCount = firstSet(widget.show_count, widget.showCount, true);
|
|
24
|
+
return {
|
|
25
|
+
groupBy,
|
|
26
|
+
order,
|
|
27
|
+
format,
|
|
28
|
+
amount,
|
|
29
|
+
showCount
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Same conversion as Hexo's toMomentLocale, without depending on Hexo's private modules.
|
|
34
|
+
function toMomentLocale(lang) {
|
|
35
|
+
if (lang === undefined) return undefined;
|
|
36
|
+
if (!lang || lang === 'en' || lang === 'default') return 'en';
|
|
37
|
+
return lang.toLowerCase().replace('_', '-');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Group already ordered posts by consecutive formatted names and apply the archive limit.
|
|
42
|
+
* The first date in each group supplies its year/month even when a custom format merges years.
|
|
43
|
+
* Sorting stays with the Hexo collection adapter; this function only needs forEach and date.clone.
|
|
44
|
+
* @param {{forEach: Function}} posts Ordered records with Moment-compatible date values.
|
|
45
|
+
* @param {Object} options groupBy/format/amount plus the selected language code and timezone.
|
|
46
|
+
* @returns {Object} Selected groups ({name, year, month, count}) and hasMore; URLs remain unresolved.
|
|
47
|
+
*/
|
|
48
|
+
function groupArchives(posts, options) {
|
|
49
|
+
const {
|
|
50
|
+
groupBy,
|
|
51
|
+
format,
|
|
52
|
+
amount,
|
|
53
|
+
timezone
|
|
54
|
+
} = options;
|
|
55
|
+
const language = toMomentLocale(options.language);
|
|
56
|
+
const groups = [];
|
|
57
|
+
let length = 0;
|
|
58
|
+
posts.forEach(post => {
|
|
59
|
+
let date = post.date.clone();
|
|
60
|
+
if (timezone) date = date.tz(timezone);
|
|
61
|
+
if (language) date = date.locale(language);
|
|
62
|
+
const year = date.year();
|
|
63
|
+
const month = date.month() + 1;
|
|
64
|
+
const name = date.format(format || (groupBy === 'monthly' ? 'MMMM YYYY' : 'YYYY'));
|
|
65
|
+
const last = groups[length - 1];
|
|
66
|
+
if (!last || last.name !== name) {
|
|
67
|
+
length = groups.push({
|
|
68
|
+
name,
|
|
69
|
+
year,
|
|
70
|
+
month,
|
|
71
|
+
count: 1
|
|
72
|
+
});
|
|
73
|
+
} else {
|
|
74
|
+
last.count++;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
const hasMore = amount > 0 && groups.length > amount;
|
|
78
|
+
return {
|
|
79
|
+
groups: hasMore ? groups.slice(0, amount) : groups,
|
|
80
|
+
hasMore
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
module.exports = {
|
|
84
|
+
resolveArchiveOptions,
|
|
85
|
+
groupArchives
|
|
86
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal category option and tree preparation, independent of Hexo initialization and JSX.
|
|
3
|
+
* @module util/categories
|
|
4
|
+
* @private
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
function firstSet(...values) {
|
|
8
|
+
return values.find(value => value !== null && typeof value !== 'undefined');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolve aliases/defaults without coercing explicit false, zero or empty strings.
|
|
13
|
+
* @param {Object} widget Categories widget options.
|
|
14
|
+
* @returns {Object} order, orderBy, showCurrent and showCount.
|
|
15
|
+
*/
|
|
16
|
+
function resolveCategoryOptions(widget) {
|
|
17
|
+
const order = firstSet(widget.order, 1);
|
|
18
|
+
const orderBy = firstSet(widget.order_by, widget.orderBy, 'name');
|
|
19
|
+
const showCurrent = firstSet(widget.show_current, widget.showCurrent, false);
|
|
20
|
+
const showCount = firstSet(widget.show_count, widget.showCount, true);
|
|
21
|
+
return {
|
|
22
|
+
order,
|
|
23
|
+
orderBy,
|
|
24
|
+
showCurrent,
|
|
25
|
+
showCount
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Parse depth only after the caller's empty-source check, retaining parseInt and zero-as-unlimited.
|
|
31
|
+
* @param {*} depth Widget depth.
|
|
32
|
+
* @param {*} fallback Legacy top-level props.depth.
|
|
33
|
+
* @returns {number} Parsed depth, or zero for an unset/unparseable value.
|
|
34
|
+
*/
|
|
35
|
+
function resolveCategoryDepth(depth, fallback) {
|
|
36
|
+
return parseInt(firstSet(depth, fallback), 10) || 0;
|
|
37
|
+
}
|
|
38
|
+
function prepareQuery(categories, parent, orderBy, order) {
|
|
39
|
+
const query = {};
|
|
40
|
+
if (parent) query.parent = parent;else query.parent = {
|
|
41
|
+
$exists: false
|
|
42
|
+
};
|
|
43
|
+
return categories.find(query).sort(orderBy, order).filter(cat => cat.length);
|
|
44
|
+
}
|
|
45
|
+
function currentCategory(cat, page) {
|
|
46
|
+
let isCurrent = false;
|
|
47
|
+
for (let j = 0; j < cat.length; j++) {
|
|
48
|
+
const post = cat.posts.data[j];
|
|
49
|
+
if (post && post._id === page._id) {
|
|
50
|
+
isCurrent = true;
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Preserve both the raw prefix test and its falsey/unset result, rather than coercing to boolean.
|
|
55
|
+
return isCurrent || page.base && page.base.startsWith(cat.path);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Prepare the category tree through the collection's existing find/sort/filter/map contract.
|
|
60
|
+
* URLs are resolved in the original depth-first postorder, even for subsequently hidden roots.
|
|
61
|
+
* Keeping the URL helper at this point also preserves helper calls before later query/current errors.
|
|
62
|
+
* @param {Object} categories Queryable source with the existing find/sort/filter/map contract.
|
|
63
|
+
* @param {Object} options Resolved order/orderBy/showCurrent/depth plus raw amount.
|
|
64
|
+
* @param {Object} page Current page; an unset page skips current checks.
|
|
65
|
+
* @param {Function} url_for Existing URL helper, not a generic node projection.
|
|
66
|
+
* @returns {Object} Selected categories ({children, isCurrent, name, count, url}) and hasMore.
|
|
67
|
+
*/
|
|
68
|
+
function prepareCategories(categories, options, page, url_for) {
|
|
69
|
+
const {
|
|
70
|
+
order,
|
|
71
|
+
orderBy,
|
|
72
|
+
showCurrent,
|
|
73
|
+
depth,
|
|
74
|
+
amount
|
|
75
|
+
} = options;
|
|
76
|
+
function hierarchicalList(level, parent) {
|
|
77
|
+
return prepareQuery(categories, parent, orderBy, order).map(cat => {
|
|
78
|
+
let children = [];
|
|
79
|
+
if (!depth || level + 1 < depth) children = hierarchicalList(level + 1, cat._id);
|
|
80
|
+
let isCurrent = false;
|
|
81
|
+
if (showCurrent && page) isCurrent = currentCategory(cat, page);
|
|
82
|
+
return {
|
|
83
|
+
children,
|
|
84
|
+
isCurrent,
|
|
85
|
+
name: cat.name,
|
|
86
|
+
count: cat.length,
|
|
87
|
+
url: url_for(cat.path)
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const list = hierarchicalList(0);
|
|
92
|
+
const hasMore = amount > 0 && list.length > amount;
|
|
93
|
+
return {
|
|
94
|
+
categories: hasMore ? list.slice(0, amount) : list,
|
|
95
|
+
hasMore
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
module.exports = {
|
|
99
|
+
resolveCategoryOptions,
|
|
100
|
+
resolveCategoryDepth,
|
|
101
|
+
prepareCategories
|
|
102
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider templates and package compatibility rules, private to the URL resolver.
|
|
3
|
+
* @module util/cdn-rules
|
|
4
|
+
* @private
|
|
5
|
+
*/
|
|
6
|
+
const PROVIDERS = {
|
|
7
|
+
LIBRARY: {
|
|
8
|
+
cdnjs: '[cdnjs]https://cdnjs.cloudflare.com/ajax/libs/${ package }/${ version }/${ filename }',
|
|
9
|
+
loli: '[cdnjs]https://cdnjs.loli.net/ajax/libs/${ package }/${ version }/${ filename }',
|
|
10
|
+
jsdelivr: 'https://cdn.jsdelivr.net/npm/${ package }@${ version }/${ filename }',
|
|
11
|
+
unpkg: 'https://unpkg.com/${ package }@${ version }/${ filename }'
|
|
12
|
+
},
|
|
13
|
+
FONT: {
|
|
14
|
+
google: 'https://fonts.googleapis.com/${ type }?family=${ fontname }',
|
|
15
|
+
loli: 'https://fonts.loli.net/${ type }?family=${ fontname }',
|
|
16
|
+
fontim: 'https://fonts.font.im/${ type }?family=${ fontname }',
|
|
17
|
+
ustc: 'https://fonts.lug.ustc.edu.cn/${ type }?family=${ fontname }'
|
|
18
|
+
},
|
|
19
|
+
ICON: {
|
|
20
|
+
loli: 'https://cdnjs.loli.net/ajax/libs/font-awesome/6.0.0/css/all.min.css',
|
|
21
|
+
fontawesome: 'https://use.fontawesome.com/releases/v6.0.0/css/all.css'
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
function stripPrefix(filename, prefix) {
|
|
25
|
+
return filename.startsWith(prefix) ? filename.substr(prefix.length) : filename;
|
|
26
|
+
}
|
|
27
|
+
function stripMin(filename) {
|
|
28
|
+
return filename.indexOf('.min.') > -1 ? filename.replace(/\.min\./gi, '.') : filename;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// An absent mapping preserves the npm path; null means the provider lacks the package.
|
|
32
|
+
const PACKAGE_RULES = {
|
|
33
|
+
'justified-gallery': {
|
|
34
|
+
cdnjs: null
|
|
35
|
+
},
|
|
36
|
+
'@mathjax/mathjax-newcm-font': {
|
|
37
|
+
cdnjs: null
|
|
38
|
+
},
|
|
39
|
+
lightgallery: {
|
|
40
|
+
// cdnjs itself serves this release, but its loli mirror lacks the CSS, core and plugins.
|
|
41
|
+
unavailable: [{
|
|
42
|
+
provider: 'loli',
|
|
43
|
+
version: '3.0.0'
|
|
44
|
+
}]
|
|
45
|
+
},
|
|
46
|
+
disqusjs: {
|
|
47
|
+
cdnjs: {
|
|
48
|
+
filename: file => stripPrefix(file, 'dist/browser/')
|
|
49
|
+
},
|
|
50
|
+
unpkg: {
|
|
51
|
+
filename: file => file.startsWith('dist/browser/') ? file : file.replace(/\.min\./gi, '.')
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
moment: {
|
|
55
|
+
cdnjs: {
|
|
56
|
+
package: 'moment.js',
|
|
57
|
+
filename: file => stripPrefix(file, 'min/')
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
outdatedbrowser: {
|
|
61
|
+
cdnjs: {
|
|
62
|
+
package: 'outdated-browser',
|
|
63
|
+
filename: file => stripPrefix(file, 'outdatedbrowser/')
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
'highlight.js': {
|
|
67
|
+
cdnjs: {
|
|
68
|
+
filename: file => file.endsWith('.css') && file.indexOf('.min.') === -1 ? file.substr(0, file.length - 4) + '.min.css' : file
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
mathjax: {
|
|
72
|
+
cdnjs: {
|
|
73
|
+
filename: file => stripMin(stripPrefix(file, 'unpacked/'))
|
|
74
|
+
},
|
|
75
|
+
unpkg: {
|
|
76
|
+
filename: stripMin
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
katex: {
|
|
80
|
+
cdnjs: {
|
|
81
|
+
package: 'KaTeX'
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
'pace-js': {
|
|
85
|
+
cdnjs: {
|
|
86
|
+
package: 'pace'
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
clipboard: {
|
|
90
|
+
cdnjs: {
|
|
91
|
+
package: 'clipboard.js'
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
cookieconsent: {
|
|
95
|
+
cdnjs: {
|
|
96
|
+
filename: file => stripPrefix(file, 'build/')
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
'@waline/client': {
|
|
100
|
+
cdnjs: {
|
|
101
|
+
package: 'waline'
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
module.exports = {
|
|
106
|
+
PROVIDERS,
|
|
107
|
+
PACKAGE_RULES,
|
|
108
|
+
stripPrefix
|
|
109
|
+
};
|
package/lib/util/cdn.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure CDN URL resolution. Hexo registration and package compatibility rules stay separate.
|
|
3
|
+
* @module util/cdn
|
|
4
|
+
* @private
|
|
5
|
+
*/
|
|
6
|
+
const {
|
|
7
|
+
PROVIDERS,
|
|
8
|
+
PACKAGE_RULES,
|
|
9
|
+
stripPrefix
|
|
10
|
+
} = require('./cdn-rules');
|
|
11
|
+
function selectLibraryProvider(providers, name) {
|
|
12
|
+
const {
|
|
13
|
+
cdn_overrides: overrides
|
|
14
|
+
} = providers;
|
|
15
|
+
return typeof overrides === 'object' && overrides !== null && overrides[name] ? overrides[name] : providers.cdn || 'jsdelivr';
|
|
16
|
+
}
|
|
17
|
+
function packageRule(name) {
|
|
18
|
+
return Object.prototype.hasOwnProperty.call(PACKAGE_RULES, name) ? PACKAGE_RULES[name] : {};
|
|
19
|
+
}
|
|
20
|
+
function resolveLibraryAsset(provider, asset) {
|
|
21
|
+
let template = provider in PROVIDERS.LIBRARY ? PROVIDERS.LIBRARY[provider] : provider;
|
|
22
|
+
const unavailable = typeof asset.package === 'string' && packageRule(asset.package).unavailable;
|
|
23
|
+
if (unavailable && unavailable.some(entry => entry.provider === provider && entry.version === asset.version)) {
|
|
24
|
+
return {
|
|
25
|
+
template: PROVIDERS.LIBRARY.jsdelivr,
|
|
26
|
+
asset
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
let family = provider === 'unpkg' ? 'unpkg' : null;
|
|
30
|
+
if (template.startsWith('[cdnjs]')) {
|
|
31
|
+
family = 'cdnjs';
|
|
32
|
+
template = template.substr(7);
|
|
33
|
+
}
|
|
34
|
+
if (!family) return {
|
|
35
|
+
template,
|
|
36
|
+
asset
|
|
37
|
+
};
|
|
38
|
+
try {
|
|
39
|
+
const mapping = packageRule(asset.package)[family];
|
|
40
|
+
if (mapping === null) return {
|
|
41
|
+
template: PROVIDERS.LIBRARY.jsdelivr,
|
|
42
|
+
asset
|
|
43
|
+
};
|
|
44
|
+
if (mapping) {
|
|
45
|
+
// Commit a mapping only after its path conversion succeeds. Later failures retain renames.
|
|
46
|
+
asset = {
|
|
47
|
+
package: mapping.package || asset.package,
|
|
48
|
+
version: asset.version,
|
|
49
|
+
filename: mapping.filename ? mapping.filename(asset.filename) : asset.filename
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (family === 'cdnjs') asset.filename = stripPrefix(asset.filename, 'dist/');
|
|
53
|
+
} catch (e) {
|
|
54
|
+
template = PROVIDERS.LIBRARY.jsdelivr;
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
template,
|
|
58
|
+
asset
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function formatLibraryUrl({
|
|
62
|
+
template,
|
|
63
|
+
asset
|
|
64
|
+
}) {
|
|
65
|
+
return template.replace(/\${\s*package\s*}/gi, asset.package).replace(/\${\s*version\s*}/gi, asset.version).replace(/\${\s*filename\s*}/gi, asset.filename);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Resolve a library URL with optional per-package provider overrides.
|
|
70
|
+
* @param {Object} providers Provider configuration.
|
|
71
|
+
* @param {string} _package npm package name.
|
|
72
|
+
* @param {string} version Library version.
|
|
73
|
+
* @param {string} filename Path in the npm package.
|
|
74
|
+
* @returns {string} The resolved URL.
|
|
75
|
+
*/
|
|
76
|
+
function resolveCdn(providers, _package, version, filename) {
|
|
77
|
+
const provider = selectLibraryProvider(providers, _package);
|
|
78
|
+
return formatLibraryUrl(resolveLibraryAsset(provider, {
|
|
79
|
+
package: _package,
|
|
80
|
+
version,
|
|
81
|
+
filename
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Resolve a web font URL; only undefined selects provider/type defaults.
|
|
87
|
+
* @param {Object} providers Provider configuration.
|
|
88
|
+
* @param {string} fontName Font family expression, unchanged by URL encoding.
|
|
89
|
+
* @param {string} [type=css] Google Fonts endpoint type.
|
|
90
|
+
* @returns {string} The resolved font URL.
|
|
91
|
+
*/
|
|
92
|
+
function resolveFontCdn(providers, fontName, type = 'css') {
|
|
93
|
+
let {
|
|
94
|
+
fontcdn = 'google'
|
|
95
|
+
} = providers;
|
|
96
|
+
if (fontcdn in PROVIDERS.FONT) fontcdn = PROVIDERS.FONT[fontcdn];
|
|
97
|
+
return fontcdn.replace(/\${\s*fontname\s*}/gi, fontName).replace(/\${\s*type\s*}/gi, type);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Select an icon provider URL without interpolating/coercing a custom value.
|
|
102
|
+
* @param {Object} providers Provider configuration.
|
|
103
|
+
* @returns {*} The known URL or original custom value.
|
|
104
|
+
*/
|
|
105
|
+
function resolveIconCdn(providers) {
|
|
106
|
+
let {
|
|
107
|
+
iconcdn = 'fontawesome'
|
|
108
|
+
} = providers;
|
|
109
|
+
if (iconcdn in PROVIDERS.ICON) iconcdn = PROVIDERS.ICON[iconcdn];
|
|
110
|
+
return iconcdn;
|
|
111
|
+
}
|
|
112
|
+
module.exports = {
|
|
113
|
+
resolveCdn,
|
|
114
|
+
resolveFontCdn,
|
|
115
|
+
resolveIconCdn
|
|
116
|
+
};
|