From 6d5f422c3f228911ac9438034ce4be26b48adcf5 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Mon, 19 Aug 2013 12:21:49 +0200 Subject: [PATCH] Tweak/rewrite Linkify. --- src/Linkification/Linkify.coffee | 134 +++++++++++++------------------ 1 file changed, 58 insertions(+), 76 deletions(-) diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 6093e5e26..a8ad3dc4b 100644 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -2,91 +2,73 @@ Linkify = init: -> return if g.VIEW is 'catalog' or !Conf['Linkify'] - @catchAll = /\b(?:([a-z][\w-]+):(?:\/{1,3}|[a-z0-9%]|(\?(?:dn|xl|xt|as|xs|kt|mt|tr)=))|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\))+(?:\((?:[^\s()<>]+|(?:\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])/i - - @globalCatchAll = ///#{@catchAll.source}///g + # gruber revised + magnet support + # http://rodneyrehm.de/t/url-regex.html + @catchAll = /\b([a-z][\w-]+:(\/{1,3}|[a-z0-9%]|\?(dn|x[lts]|as|kt|mt|tr)=)|www\d{0,3}\.|[a-z0-9.\-]+\.[a-z]{2,4}\/)([^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])/g Post::callbacks.push name: 'Linkify' cb: @node node: -> - return if @isClone or !links = @info.comment.match Linkify.globalCatchAll - walker = d.createTreeWalker @nodes.comment, 4, null, false - anchor = false - while (node = walker.nextNode())? - {parentNode} = node - if parentNode.nodeName is 'A' - # prettyprint has some issues - if parentNode.textContent is links[0] - delete links[0] - walker.currentNode = parentNode.lastChild - continue - continue unless data = node.data - while !anchor - return unless link = links.shift() - [anchor, link] = Linkify.parseLink link - if data.length >= link.length and (index = data.indexOf link) >= 0 - walker.currentNode = Linkify.surround anchor, link, index, index + link.length, node - anchor = false - continue - index = found = 0 - nextContent = node.nextSibling?.textContent - while index isnt data.length - start = data[index++..] - startLength = start.length - threshold = startLength is 2 - if threshold and nextContent and link[...startLength + nextContent.length] is start + nextContent - found = true - if threshold or found = link[...startLength] is start - index-- - break - continue unless found - startNode = node - while start.length < link.length - start += data = (node = walker.nextNode())?.data - if Conf['Clean Links'] - {parentNode} = node - if parentNode.nodeName is 'S' and parentNode.textContent.length < link.length - $.replace parentNode, node - continue unless start[...link.length] is link - endIndex = link[start.length - data.length...].length - walker.currentNode = Linkify.surround anchor, link, index, endIndex, startNode, node - anchor = false + return if @isClone or !links = @info.comment.match Linkify.catchAll + walker = d.createTreeWalker @nodes.comment, 4 + for link in links + boundaries = Linkify.find link, walker + # continue unless boundaries + anchor = Linkify.createLink link + if Linkify.surround anchor, link, boundaries + Linkify.cleanLink anchor if Conf['Clean Links'] + walker.currentNode = anchor.lastChild + else + walker.currentNode = boundaries.endNode return - parseLink: (link) -> - unless result = link.match @catchAll - return false - [link, protocol, isMagnet] = result - try - decodeURIComponent link - catch - return false - target = if isMagnet or /^(irc|ftps?)$/.test protocol - '_self' - else - '_blank' - href = if protocol - link - else - "http://#{link}" - anchor = $.el 'a', - target: target - href: href - rel: 'noreferrer' - [anchor, link] + find: (link, walker) -> + # Walk through the nodes until we find the entire link. + text = '' + while node = walker.nextNode() + {data} = node + text += node.data + if text.indexOf(link) > -1 + startNode = endNode = node + break - surround: (anchor, link, startIndex, endIndex, startNode, endNode = startNode) -> - parent = startNode.parentNode - if parent?.nodeName is 'S' and parent.textContent.length < link.length - parentClone = parent.cloneNode true - $.replace parent, startNode + # Walk backwards to find the startNode. + text = data + until (index = text.indexOf link) > -1 + startNode = walker.previousNode() + text = "#{startNode.data}#{text}" + + return { + startNode, endNode + startOffset: index + endOffset: endNode.length - (text.length - index - link.length) + } + + createLink: (link) -> + unless /^[a-z][\w-]+:/.test link + link = "http://#{link}" + a = $.el 'a', + href: link + target: '_blank' + a + + surround: (anchor, link, {startOffset, endOffset, startNode, endNode}) -> + # parent = startNode.parentNode + # if parent?.nodeName is 'S' and parent.textContent.length < link.length + # parentClone = parent.cloneNode true + # $.replace parent, startNode range = d.createRange() - range.setStart startNode, startIndex - range.setEnd endNode, endIndex + range.setStart startNode, startOffset + range.setEnd endNode, endOffset try range.surroundContents anchor - if !Conf['Clean Links'] and parentClone and anchor.firstChild - $.replace anchor.firstChild, parentClone - endNode + # if !Conf['Clean Links'] and parentClone and anchor.firstChild + # $.replace anchor.firstChild, parentClone + true + catch + false + + cleanLink: (anchor) -> + # TODO