hexo-theme-stellar/source/js/plugins/linkcard.js

119 lines
3.4 KiB
JavaScript
Raw Normal View History

2022-10-25 22:41:56 +08:00
// 本插件由CardLink定制而成原项目源码: https://github.com/Lete114/CardLink
var cardLink = {};
cardLink.caches = {};
cardLink.server = 'https://api.allorigins.win/raw?url=';
/**
* Remove '/' and '/index.html'
* @param {String} params
* @returns { String }
*/
function indexHandler(params) {
let path = params.replace(/(\/index\.html|\/)*$/gi, '')
if (path.length === 0) path += '/'
return path
}
/**
* Determine if it is a ['https://', 'http://', '//'] protocol
* @param {String} url Website url
* @returns {Boolean}
*/
function isHttp(url) {
return /^(https?:)?\/\//g.test(url)
}
function renderer(el, obj) {
el.querySelector('.title').innerHTML = obj.title;
if (obj.icon && obj.icon.length > 0) {
el.querySelector('.img').style = 'background-image: url("' + obj.icon + '");';
}
if (obj.desc && obj.desc.length > 0) {
el.querySelector('.desc').innerHTML = obj.desc;
}
}
/**
* Get info
* @param {Element} el Element
* @param {String} html String type html
* @param {String} link Website address
*/
// eslint-disable-next-line max-statements
function getInfo(el, html, link) {
try {
let title, icon, desc
const doc = new DOMParser().parseFromString(html, 'text/html')
// If there is no title, no card link is generated
title = doc.querySelector('title')
if (title) {
title = title.textContent
// Get the src of the first img tag in the body tag
// icon = doc.querySelector('body img')
// icon = icon && icon.getAttribute('src')
if (/^data:image/.test(icon)) icon = ''
// If there is no src then get the site icon
if (!icon) {
const links = [].slice.call(doc.querySelectorAll('link[rel][href]'))
icon = links.find((_el) => _el.rel.includes('icon'))
icon = icon && icon.getAttribute('href')
}
desc = doc.querySelector('head meta[name="description"]')
if (desc) {
desc = desc.content;
}
// If `icon` is not the ['https://', 'http://', '//'] protocol, splice on the `origin` of the a tag
if (icon && !isHttp(icon)) icon = new URL(link).origin + icon
cardLink.caches[link] = { title, link, icon, desc }
renderer(el, cardLink.caches[link])
}
} catch (error) {
// eslint-disable-next-line no-console
console.warn('CardLink Error: Failed to parse', error)
}
}
function fetchPage(link, callback) {
fetch(link)
.then((result) => result.text())
.then(callback)
.catch((error) => {
const server = cardLink.server
// eslint-disable-next-line no-console
if (link.includes(server) || !server) return console.error('CardLink Error:', error)
fetchPage(server + link, callback)
})
}
/**
* Create card links
* @param {NodeList} nodes A collection of nodes or a collection of arrays,
* if it is an array then the array must always contain node element
*/
function setCardLink(nodes) {
// If the `nodes` do not contain a `forEach` method, then the default `a[cardlink]` is used
nodes = 'forEach' in (nodes || {}) ? nodes : document.querySelectorAll('a[cardlink]')
nodes.forEach((el) => {
// If it is not a tag element then it is not processed
if (el.nodeType !== 1) return
el.removeAttribute('cardlink')
const link = el.href
const cache = cardLink.caches[link]
if (cache) return renderer(el, cache)
if (isHttp(link)) {
fetchPage(link, (html) => {
getInfo(el, html, link)
})
}
})
}