Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: external_link should use after_render #3675

Merged
merged 9 commits into from
Oct 1, 2019
6 changes: 5 additions & 1 deletion lib/hexo/default_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ module.exports = {
new_post_name: ':title.md',
default_layout: 'post',
titlecase: false,
external_link: true,
external_link: {
enable: true,
field: 'site',
exclude: ''
},
filename_case: 0,
render_drafts: false,
post_asset_folder: false,
Expand Down
42 changes: 32 additions & 10 deletions lib/plugins/filter/after_post_render/external_link.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,43 @@
'use strict';

const url = require('url');
const { parse } = require('url');

const isExternal = (url, config) => {
const exclude = Array.isArray(config.external_link.exclude) ? config.external_link.exclude :
[config.external_link.exclude];
const data = parse(url);
const host = data.hostname;
const sitehost = parse(config.url).hostname || config.url;

if (!data.protocol || !sitehost) return false;

if (exclude && exclude.length) {
for (const i of exclude) {
if (host === i) return false;
}
}

if (host !== sitehost) return true;

return false;
};

function externalLinkFilter(data) {
const { config } = this;
if (!config.external_link) return;

const siteHost = url.parse(config.url).hostname || config.url;
if (typeof config.external_link === 'undefined' || typeof config.external_link === 'object' ||
config.external_link === true) {
config.external_link = Object.assign({
enable: true,
field: 'site',
exclude: ''
}, config.external_link);
}
if (config.external_link === false || config.external_link.enable === false ||
config.external_link.field !== 'post') return;

data.content = data.content.replace(/<a.*?(href=['"](.*?)['"]).*?>/gi, (str, hrefStr, href) => {
if (/target=/gi.test(str)) return str;

const data = url.parse(href);
// Exit if the link doesn't have protocol, which means it's a internal link
// Exit if the url has same host with config.url
if (!data.protocol || data.hostname === siteHost) return str;
if (/target=/gi.test(str) || !isExternal(href, config)) return str;

if (/rel=/gi.test(str)) {
str = str.replace(/rel="(.*?)"/gi, (relStr, rel) => {
Expand All @@ -26,7 +49,6 @@ function externalLinkFilter(data) {

return str.replace(hrefStr, `${hrefStr} target="_blank" rel="noopener"`);
});

}

module.exports = externalLinkFilter;
62 changes: 62 additions & 0 deletions lib/plugins/filter/after_render/external_link.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use strict';

const { parse } = require('url');

/**
* Check whether the link is external
* @param {String} url The url to check
* @param {Object} config The site config
* @returns {Boolean} True if the link doesn't have protocol or link has same host with config.url
*/
const isExternal = (url, config) => {
const exclude = Array.isArray(config.external_link.exclude) ? config.external_link.exclude :
[config.external_link.exclude];
const data = parse(url);
const host = data.hostname;
const sitehost = parse(config.url).hostname || config.url;

if (!data.protocol || !sitehost) return false;

if (exclude && exclude.length) {
for (const i of exclude) {
if (host === i) return false;
}
}

if (host !== sitehost) return true;

return false;
};

function externalLinkFilter(data) {
const { config } = this;

if (typeof config.external_link === 'undefined' || typeof config.external_link === 'object' ||
config.external_link === true) {
config.external_link = Object.assign({
enable: true,
field: 'site',
exclude: ''
}, config.external_link);
}
if (config.external_link === false || config.external_link.enable === false ||
config.external_link.field !== 'site') return;

data = data.replace(/<a.*?(href=['"](.*?)['"]).*?>/gi, (str, hrefStr, href) => {
if (/target=/gi.test(str) || !isExternal(href, config)) return str;

if (/rel=/gi.test(str)) {
str = str.replace(/rel="(.*?)"/gi, (relStr, rel) => {
if (!rel.includes('noopenner')) relStr = relStr.replace(rel, `${rel} noopener`);
return relStr;
});
return str.replace(hrefStr, `${hrefStr} target="_blank"`);
}

return str.replace(hrefStr, `${hrefStr} target="_blank" rel="noopener"`);
});

return data;
}

module.exports = externalLinkFilter;
8 changes: 8 additions & 0 deletions lib/plugins/filter/after_render/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict';

module.exports = ctx => {
const { filter } = ctx.extend;

filter.register('after_render:html', require('./external_link'));
filter.register('after_render:html', require('./meta_generator'));
};
2 changes: 1 addition & 1 deletion lib/plugins/filter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module.exports = ctx => {
const { filter } = ctx.extend;

require('./after_render')(ctx);
require('./after_post_render')(ctx);
require('./before_post_render')(ctx);
require('./before_exit')(ctx);
Expand All @@ -11,5 +12,4 @@ module.exports = ctx => {

filter.register('new_post_path', require('./new_post_path'));
filter.register('post_permalink', require('./post_permalink'));
filter.register('after_render:html', require('./meta_generator'));
};