Skip to content

Instantly share code, notes, and snippets.

/linkify-on-click.js

Created Nov 13, 2015
Embed
What would you like to do?
Userscript to turn plain text URIs into links on click.
// ==UserScript==
// @name Linkify on click
// @version 1.15
// @date 2015-11-08
// @author helb (based on linkify.js by Sergey Voronov)
// @description Turns plain text URIs into links on click. Modifier+Click to convert all. [Opera 12 / Firefox 42]
// ==/UserScript==
(function(){
///////////////////////////////////////////////////////////////////
// SETTINGS
// Link style (comment/uncomment as needed). Examples:
// 'text-decoration: overline !important;'
// 'border-width: 1px 0 !important; border-style: dotted !important;'
// 'border-width: 1px 0 !important; border-style: dashed !important;'
// 'font-style: italic; background-color: #fffbb9; color: #008000; border-top: thin dashed #008000; border-bottom: thin dashed #008000;'
//var linkifyStyle = 'font-style: italic; background-color: #fffbb9; color: #008000; border-top: thin dashed #008000; border-bottom: thin dashed #008000;';
linkifyAuto = 2; // Automatic handling: 0 = fully manual, 1 = on load, 2 = auto-update on content changes
linkifyManual = 1; // Manual update on — doubleclick anywhere while holding modifier (Shift+Ctrl+doubleclick to linkify immediately)
///////////////////////////////////////////////////////////////////
linkifyClass = 'linkifiedEl';
///////////////////////////////////////////////////////////////////
// DO NOT EDIT
// Enable the script if we're not displaying svg files
if (!window.location.href.match(/\.(svg)$/i) ){
function convert(e) {
if (typeof linkifyStyle !== 'undefined' && convert.initStage < 2)
{
if (!document || !document.documentElement)
return;
var anchorCSS = document.createElement('style');
anchorCSS.setAttribute('type', 'text/css');
anchorCSS.appendChild(document.createTextNode('a.' + linkifyClass + ' {' + linkifyStyle + '}'));
document.documentElement.appendChild(anchorCSS);
convert.initStage++;
};
var els = [];
if (e.ctrlKey || e.shiftKey || e.altKey){
spanIt();
els = document.getElementsByClassName(linkifyClass);
}
else {
els.push(e.target);
}
for (var i = 0; i < els.length; i++)
{
var linkElement = document.createElement('a');
linkElement.setAttribute('class', linkifyClass);
linkElement.setAttribute('href', els[i].title ? els[i].title : els[i].textContent);
linkElement.text = els[i].textContent;
els[i].parentNode.replaceChild(linkElement, els[i]);
}
}
function spanIt(evt) {
if (!(document.documentElement instanceof HTMLHtmlElement)) return;
var baseNode = (!evt || evt.length !== undefined || evt.target === undefined || evt.target == document) ? document.body : evt.target;
//alert(baseNode);
if (linkifyAuto == 2)
obsrvr.disconnect()
else if (linkifyAuto == 22)
document.removeEventListener('DOMNodeInserted', spanIt, false);
//RegExp is splitted in parts to simplify modification
//after connecting together it is
// \b(?:(_?[hx]..ps?:\/\/)|(_?f.p:\/\/)|(mailto:)|(www\d*\.)|(ftp\d*\.)|(magnet:))[^\^\[\]{}|\\\'"<>`\s]*[^!@\^()\[\]{}|\\:;\'",.?<>`\s]
//You can try to write better, but remember about Backreferences (used in GetLinkHREF to determining kind of link)
var sProtocol = '(_?[hx]..ps?:\/\/)|(_?f.p:\/\/)|(mailto:)|(www\\d*\\.)|(ftp\\d*\\.)|(magnet:)';
var sURLPathChars = '[^\\^\\[\\]{}|\\\\\'"<>`\\s]';
var sEndChars = '[^!@\\^()\\[\\]{}|\\\\:;\'",.?<>`\\s]';
var sURLPath = sURLPathChars + '*' + sEndChars;
var sRegExpHTTP = '\\b(?:' + sProtocol + ')' + sURLPath
var rRegExpHTTP = RegExp(sRegExpHTTP, 'i');
var textNodes = getTextNodes(baseNode),
foundText, matchedText, matchedHref, textNode, spanElement;
for (var i = 0, textNode, disp; textNode = textNodes[i]; i++)
{
if (textNode.parentNode.class == linkifyClass) continue;
//Find something that looks like URL
while (foundText = rRegExpHTTP.exec(textNode.data) )
{
//Remember found text
matchedText = foundText[0];
matchedHref = GetLinkHREF(foundText);
textNode = textNode.splitText(foundText.index);
spanElement = document.createElement('span');
spanElement.setAttribute('class', linkifyClass);
if (matchedHref != matchedText)
spanElement.setAttribute('title', matchedHref);
textNode.deleteData(0,((spanElement = spanElement.cloneNode(false)).textContent = matchedText).length);
spanElement.onclick = convert;
textNode.parentNode.insertBefore(spanElement, textNode);
}
}
if (linkifyAuto == 2)
obsrvr.observe(document.body, {childList: true, subtree: true})
else if (linkifyAuto == 22)
document.addEventListener('DOMNodeInserted', spanIt, false);
}
function fixEvents(node){
var els = node.getElementsByClassName(linkifyClass);
for (var i = 0; i < els.length; i++) {
els[i].onclick = convert;
}
}
function GetLinkHREF(aMatch) {
if (aMatch[1]) return aMatch[0].replace(/^_?[hx]..p/i,'http');
if (aMatch[2]) return aMatch[0].replace(/^_?f.p/i,'ftp');
// if (aMatch[3]) //email
if (aMatch[4]) return 'http://' + aMatch[0];
if (aMatch[5]) return 'ftp://' + aMatch[0];
// if (aMatch[6]) //magnet
return aMatch[0];
}
function getTextNodes(el) {
var n, a=[], walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false); // = 0x00000004
while (n = walk.nextNode())
if (n.parentNode.nodeName.toLowerCase() !== 'script' && n.parentNode.nodeName.toLowerCase() !== 'style' && n.parentNode.nodeName.toLowerCase() !== 'noscript' && n.parentNode.className !== linkifyClass && n.parentNode.tagName.toLowerCase() !== 'a')
a.push(n);
return a;
}
convert.initStage = 1;
if (linkifyAuto > 0)
document.addEventListener('DOMContentLoaded', spanIt, false);
if (linkifyAuto == 2) {
try {
var obsrvr = new MutationObserver(function(mutations){ spanIt(mutations); });
if (!obsrvr) linkifyAuto = 22;
} catch (e) {
linkifyAuto = 22;
}
}
if (linkifyManual)
document.addEventListener('dblclick', function(e){
if (e.ctrlKey && e.shiftKey) { spanIt(); convert(e); }
else if (e.ctrlKey || e.shiftKey || e.altKey) { fixEvents(document.body); spanIt(); }
}, false);
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment