2016-12-22 19:11:28 +08:00
|
|
|
'use strict'
|
|
|
|
/* global hexo */
|
|
|
|
|
2018-10-04 19:07:24 +08:00
|
|
|
const _ = require('lodash')
|
|
|
|
const path = require('path')
|
|
|
|
const fs = require('fs')
|
|
|
|
const cheerio = require('cheerio')
|
2016-12-22 19:11:28 +08:00
|
|
|
|
|
|
|
var options = _.assign({
|
|
|
|
enable: true,
|
2018-10-04 19:07:24 +08:00
|
|
|
inject: true,
|
2016-12-23 18:46:01 +08:00
|
|
|
version: 'latest',
|
2018-10-04 19:07:24 +08:00
|
|
|
className: 'github-emoji',
|
2016-12-22 19:11:28 +08:00
|
|
|
}, hexo.config.githubEmojis)
|
|
|
|
|
|
|
|
if (options.enable !== false) {
|
2018-10-04 19:07:24 +08:00
|
|
|
const emojis = _.assign(
|
|
|
|
{},
|
|
|
|
require('./emojis.json'),
|
|
|
|
loadCustomEmojis(options.customEmojis || options.localEmojis),
|
|
|
|
)
|
2016-12-22 19:11:28 +08:00
|
|
|
|
2018-10-04 19:07:24 +08:00
|
|
|
fs.writeFile(
|
|
|
|
path.join(__dirname, 'emojis.json'),
|
|
|
|
JSON.stringify(emojis, null, ' '),
|
|
|
|
function (err) { err && console.warn(err) },
|
|
|
|
)
|
2016-12-22 19:11:28 +08:00
|
|
|
|
2018-10-04 19:07:24 +08:00
|
|
|
hexo.extend.filter.register('after_post_render', data => {
|
|
|
|
if (!options.inject && data['no-emoji']) { return data }
|
|
|
|
|
2019-04-12 14:04:16 +08:00
|
|
|
const $ = cheerio.load(data.content, {decodeEntities: false})
|
2019-04-12 14:35:34 +08:00
|
|
|
const excerpt = cheerio.load(data.excerpt, {decodeEntities: false})
|
2018-10-04 19:07:24 +08:00
|
|
|
|
|
|
|
if (options.inject) {
|
|
|
|
$('body').append(`<script>
|
|
|
|
document.querySelectorAll('.${options.className}')
|
|
|
|
.forEach(el => {
|
|
|
|
if (!el.dataset.src) { return; }
|
|
|
|
const img = document.createElement('img');
|
|
|
|
img.style = 'display:none !important;';
|
|
|
|
img.src = el.dataset.src;
|
|
|
|
img.addEventListener('error', () => {
|
|
|
|
img.remove();
|
|
|
|
el.style.color = 'inherit';
|
|
|
|
el.style.backgroundImage = 'none';
|
|
|
|
el.style.background = 'none';
|
|
|
|
});
|
|
|
|
img.addEventListener('load', () => {
|
|
|
|
img.remove();
|
|
|
|
});
|
|
|
|
document.body.appendChild(img);
|
|
|
|
});
|
|
|
|
</script>`)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!data['no-emoji']) {
|
|
|
|
replaceColons($('body')[0], $, emojis)
|
2019-04-12 14:06:02 +08:00
|
|
|
replaceColons(excerpt('body')[0], excerpt, emojis)
|
2018-10-04 19:07:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
data.content = $('body').html()
|
2019-04-12 14:06:02 +08:00
|
|
|
data.excerpt = excerpt('body').html()
|
2018-10-04 19:07:24 +08:00
|
|
|
return data
|
|
|
|
})
|
|
|
|
|
|
|
|
hexo.extend.helper.register('github_emoji', name => renderEmoji(emojis, name))
|
|
|
|
hexo.extend.tag.register('github_emoji', args => renderEmoji(emojis, args[0]))
|
|
|
|
}
|
|
|
|
|
|
|
|
function replaceColons (node, $, emojis) {
|
|
|
|
node.children.forEach(child => {
|
|
|
|
if (child.type === 'text') {
|
|
|
|
const content = child.data.replace(
|
|
|
|
/:(\w+):/ig,
|
|
|
|
(match, p1) => emojis[p1] ? renderEmoji(emojis, p1) : match,
|
|
|
|
)
|
|
|
|
if (content !== child.data) {
|
|
|
|
$(child).replaceWith($.parseHTML(content))
|
|
|
|
}
|
|
|
|
} else if (child.type === 'tag') {
|
|
|
|
if (child.name !== 'pre' && child.name !== 'code') {
|
|
|
|
replaceColons(child, $, emojis)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadCustomEmojis (customEmojis) {
|
2016-12-23 18:46:01 +08:00
|
|
|
// JSON string
|
2018-10-04 19:07:24 +08:00
|
|
|
if (_.isString(customEmojis)) {
|
2016-12-22 19:11:28 +08:00
|
|
|
try {
|
2018-10-04 19:07:24 +08:00
|
|
|
customEmojis = JSON.parse(customEmojis)
|
|
|
|
Object.keys(customEmojis).forEach(name => {
|
|
|
|
if (_.isString(customEmojis[name])) {
|
|
|
|
customEmojis[name] = {
|
|
|
|
src: customEmojis[name],
|
2016-12-23 18:46:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2018-10-04 19:07:24 +08:00
|
|
|
} catch (err) {
|
|
|
|
customEmojis = {}
|
|
|
|
console.warn('hexo-filter-github-emojis: Custom emojis not valid. Skipped.')
|
2016-12-22 19:11:28 +08:00
|
|
|
}
|
|
|
|
}
|
2018-10-04 19:07:24 +08:00
|
|
|
|
|
|
|
if (!_.isObject(customEmojis)) {
|
|
|
|
customEmojis = {}
|
2016-12-25 18:18:12 +08:00
|
|
|
}
|
2016-12-22 19:11:28 +08:00
|
|
|
|
2018-10-04 19:07:24 +08:00
|
|
|
Object.values(customEmojis).forEach(emoji => {
|
|
|
|
if (emoji.codepoints && !_.isArray(emoji.codepoints)) {
|
|
|
|
emoji.codepoints = emoji.codepoints.split(' ')
|
2016-12-22 19:11:28 +08:00
|
|
|
}
|
|
|
|
})
|
2018-10-04 19:07:24 +08:00
|
|
|
}
|
2016-12-22 19:11:28 +08:00
|
|
|
|
2018-10-04 19:07:24 +08:00
|
|
|
function renderEmoji (emojis, name) {
|
|
|
|
if (!emojis[name]) { return name }
|
2017-06-26 07:25:18 +08:00
|
|
|
|
2018-10-04 19:07:24 +08:00
|
|
|
const styles = _.isObject(options.styles)
|
|
|
|
? Object.keys(options.styles)
|
|
|
|
.filter(k => _.isString(options.styles[k]))
|
|
|
|
.map(k => k + ':' + options.styles[k])
|
|
|
|
: []
|
2017-06-26 07:25:18 +08:00
|
|
|
|
2018-10-04 19:07:24 +08:00
|
|
|
if (options.inject) {
|
|
|
|
styles.push(
|
|
|
|
'color: transparent',
|
|
|
|
`background:no-repeat url(${emojis[name].src}) center/contain`,
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
styles.push(`background-image:url(${emojis[name].src})`)
|
|
|
|
}
|
2017-06-26 15:52:12 +08:00
|
|
|
|
2018-10-04 19:07:24 +08:00
|
|
|
const codepoints = emojis[name].codepoints
|
|
|
|
? emojis[name].codepoints.map(c => `&#x${c};`).join('')
|
|
|
|
: ' '
|
2017-06-26 15:51:51 +08:00
|
|
|
|
2018-10-04 19:07:24 +08:00
|
|
|
return `<span class="${options.className}" style="${styles.join(';')}" data-src="${emojis[name].src}">${codepoints}</span>`
|
2016-12-22 19:11:28 +08:00
|
|
|
}
|