blog/themes/typing/scripts/openGraph.js

145 lines
3.9 KiB
JavaScript
Raw Normal View History

2019-08-09 13:02:51 +00:00
'use strict'
/* global hexo */
2019-05-25 14:40:44 +00:00
/*
* Modified from the hexo version,
* https://github.com/hexojs/hexo/blob/master/lib/plugins/helper/open_graph.js
* for compatibility with cloudinary.js
* the <meta name="og:image"> now use
* data-src attribute of <img>, instead of src
*/
'use strict'
const moment = require('moment')
const { escapeHTML, htmlTag, stripHTML } = require('hexo-util')
2019-08-11 02:09:48 +00:00
let cheerio
function meta (name, content, escape) {
if (escape !== false && typeof content === 'string') {
content = escapeHTML(content)
}
return `${htmlTag('meta', {
name,
content
})}\n`
}
function og (name, content, escape) {
if (escape !== false && typeof content === 'string') {
content = escapeHTML(content)
}
return `${htmlTag('meta', {
property: name,
content
})}\n`
}
function openGraphHelper (options = {}) {
const { config, page, theme } = this
const { content } = page
let images = page.photos || []
let description = page.excerpt || theme.description
const keywords = page.keywords || (page.tags && page.tags.length ? page.tags : undefined) || config.keywords
const title = page.title || theme.nickname
const type = (this.is_post() ? 'article' : 'website')
2019-08-09 13:14:39 +00:00
const url = this.url.replace(/index.html$/, '')
const siteName = theme.nickname
const twitterCard = options.twitter_card || 'summary'
const published = page.date || false
const updated = page.lastUpdated || false
const language = options.language || page.lang || page.language || config.language
let result = ''
if (!Array.isArray(images)) images = [images]
if (description) {
description = stripHTML(description).substring(0, 200)
.trim() // Remove prefixing/trailing spaces
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
.replace(/\n/g, ' ') // Replace new lines by spaces
}
if (!images.length && content && content.includes('<img')) {
images = images.slice()
2019-08-11 02:09:48 +00:00
if (!cheerio) cheerio = require('cheerio');
const $ = cheerio.load(content)
2019-08-11 02:14:42 +00:00
$('img').each((index, element) => {
const src = $(element).attr('data-src')
if (src) images.push(src)
})
}
if (description) {
result += meta('description', description, false)
}
if (keywords) {
if (typeof keywords === 'string') {
result += meta('keywords', keywords)
} else if (keywords.length) {
result += meta('keywords', keywords.map(tag => {
return tag.name ? tag.name : tag
}).filter(keyword => !!keyword).join())
}
}
result += og('og:type', type)
result += og('og:title', title)
result += og('og:url', url, false)
result += og('og:site_name', siteName)
if (description) {
result += og('og:description', description, false)
}
if (language) {
result += og('og:locale', language, false)
}
images = images.map(path => {
2019-08-09 13:02:51 +00:00
if (!new URL(path).host) {
// resolve `path`'s absolute path relative to current page's url
// `path` can be both absolute (starts with `/`) or relative.
2019-08-09 13:02:51 +00:00
return new URL(path, url || config.url)
}
return path
})
images.forEach(path => {
result += og('og:image', path, false)
})
if (published) {
if ((moment.isMoment(published) || moment.isDate(published)) && !isNaN(published.valueOf())) {
// Skip timezone conversion
2019-06-04 04:05:48 +00:00
result += og('article:published_time', moment(published).format('YYYY-MM-DD[T00:00:00.000Z]'))
}
}
if (updated) {
if ((moment.isMoment(updated) || moment.isDate(updated)) && !isNaN(updated.valueOf())) {
2019-06-04 04:05:48 +00:00
result += og('article:modified_time', moment(updated).format('YYYY-MM-DD[T00:00:00.000Z]'))
result += og('og:updated_time', moment(updated).format('YYYY-MM-DD[T00:00:00.000Z]'))
}
}
result += meta('twitter:card', twitterCard)
if (images.length) {
result += meta('twitter:image', images[0], false)
}
return result.trim()
}
hexo.extend.helper.register('openGraph', openGraphHelper)