86 lines
3.1 KiB
JavaScript
86 lines
3.1 KiB
JavaScript
// linkify.js - Convert bare URLs to link cards, video URLs to players
|
|
(function() {
|
|
var URL_RE = /(https?:\/\/[^\s一-鿿 -〿-<>"')\]]+)/g;
|
|
var VIDEO_RE = /\.(mp4|webm|ogg|mov)(\?|$)/i;
|
|
var FAVICON_API = 'https://api.usj.cc/api/favicon?url=';
|
|
|
|
function getDomain(url) {
|
|
try { return new URL(url).hostname; } catch (e) { return url; }
|
|
}
|
|
|
|
function makeVideo(url) {
|
|
var video = document.createElement('video');
|
|
video.className = 'post-video';
|
|
video.controls = true;
|
|
video.preload = 'metadata';
|
|
video.playsInline = true;
|
|
var source = document.createElement('source');
|
|
source.src = url;
|
|
video.appendChild(source);
|
|
return video;
|
|
}
|
|
|
|
function makeCard(url) {
|
|
var domain = getDomain(url);
|
|
var card = document.createElement('a');
|
|
card.className = 'link-card';
|
|
card.href = '/tiaozhuan.html?target=' + btoa(url);
|
|
card.target = '_blank';
|
|
card.rel = 'noopener';
|
|
card.innerHTML = '<img class="link-card-icon" src="' + FAVICON_API + domain + '" alt="" loading="lazy" onerror="this.style.display=\'none\'">' +
|
|
'<span class="link-card-body"><span class="link-card-title">' + domain + '</span>' +
|
|
'<span class="link-card-url">' + url + '</span></span>' +
|
|
'<span class="link-card-arrow">↗</span>';
|
|
return card;
|
|
}
|
|
|
|
function linkify(root) {
|
|
var walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
|
|
var textNodes = [];
|
|
while (walker.nextNode()) {
|
|
var node = walker.currentNode;
|
|
if (node.parentElement && node.parentElement.closest('a, .link-card, code, pre, video')) continue;
|
|
if (URL_RE.test(node.textContent)) textNodes.push(node);
|
|
}
|
|
|
|
textNodes.forEach(function(node) {
|
|
URL_RE.lastIndex = 0;
|
|
var text = node.textContent;
|
|
var parts = [];
|
|
var lastIdx = 0;
|
|
var match;
|
|
while ((match = URL_RE.exec(text)) !== null) {
|
|
if (match.index > lastIdx) {
|
|
parts.push(document.createTextNode(text.slice(lastIdx, match.index)));
|
|
}
|
|
if (VIDEO_RE.test(match[1])) {
|
|
parts.push(makeVideo(match[1]));
|
|
} else {
|
|
parts.push(makeCard(match[1]));
|
|
}
|
|
lastIdx = match.index + match[0].length;
|
|
}
|
|
if (parts.length === 0) return;
|
|
if (lastIdx < text.length) {
|
|
parts.push(document.createTextNode(text.slice(lastIdx)));
|
|
}
|
|
var frag = document.createDocumentFragment();
|
|
parts.forEach(function(p) { frag.appendChild(p); });
|
|
node.parentNode.replaceChild(frag, node);
|
|
});
|
|
}
|
|
|
|
function run() {
|
|
var content = document.querySelector('.post-content');
|
|
if (content) linkify(content);
|
|
}
|
|
|
|
window.initLinkify = run;
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', run);
|
|
} else {
|
|
run();
|
|
}
|
|
})();
|