Merge pull request #1246 from MayhemYDG/linkify

Add Linkification.
This commit is contained in:
Mayhem 2013-08-19 15:45:52 -07:00
commit f4433ccf4c
7 changed files with 117 additions and 0 deletions

View File

@ -1,3 +1,7 @@
- **New feature**: `Linkify` and `Clean Links`, enabled by default
- Linkify will turn text URLs into working links.
- Clean Links will get rid of spoiler and code tags in linkified URLs used to bypass spam blocks.
## 3.9.0 - *2013-08-18*
- **New feature**: `Desktop Notifications`

View File

@ -31,6 +31,7 @@ module.exports = (grunt) ->
'src/Quotelinks/**/*'
'src/Posting/**/*'
'src/Images/**/*'
'src/Linkification/**/*'
'src/Menu/**/*'
'src/Monitoring/**/*'
'src/Archive/**/*'

View File

@ -27,6 +27,9 @@ Config =
'Image Hover': [false, 'Show a floating expanded image on hover.']
'Sauce': [true, 'Add sauce links to images.']
'Reveal Spoilers': [false, 'Reveal spoiler thumbnails.']
'Linkification':
'Linkify': [true, 'Convert text links into hyperlinks.']
'Clean Links': [true, 'Remove spoiler and code tags commonly used to bypass blocked links.']
'Menu':
'Menu': [true, 'Add a drop-down menu to posts.']
'Report Link': [true, 'Add a report link to the menu.']

View File

@ -128,6 +128,7 @@ Main =
initFeature 'Index Navigation', Nav
initFeature 'Keybinds', Keybinds
initFeature 'Show Dice Roll', Dice
initFeature 'Linkify', Linkify
# c.timeEnd 'All initializations'
$.on d, 'AddCallback', Main.addCallback

View File

@ -56,6 +56,8 @@ class Post
@kill() if that.isArchived
parseComment: ->
# Merge text nodes and remove empty ones.
@nodes.comment.normalize()
# Get the comment's text.
# <br> -> \n
# Remove:

View File

@ -0,0 +1,104 @@
Linkify =
init: ->
return if g.VIEW is 'catalog' or !Conf['Linkify']
# 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.catchAll
walker = d.createTreeWalker @nodes.comment, 4
range = d.createRange()
for link in links
boundaries = Linkify.find link, walker
# break unless boundaries
anchor = Linkify.createLink link
if Linkify.surround anchor, range, boundaries
if (parent = anchor.parentNode).href is anchor.href
# Replace already-linkified links,
# f.e.: https://boards.4chan.org/b/%
$.replace parent, anchor
Linkify.cleanLink anchor, link if Conf['Clean Links']
walker.currentNode = anchor.lastChild
else
walker.currentNode = boundaries.endNode
range.detach()
find: (link, walker) ->
# Walk through the nodes until we find the entire link.
text = ''
while node = walker.nextNode()
text += node.data
break if text.indexOf(link) > -1
# return unless node
startNode = endNode = node
# Walk backwards to find the startNode.
text = node.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}"
$.el 'a',
href: link
className: 'linkified'
target: '_blank'
surround: (anchor, range, boundaries) ->
{startOffset, endOffset, startNode, endNode} = boundaries
range.setStart startNode, startOffset
range.setEnd endNode, endOffset
try
range.surroundContents anchor
true
catch
<% if (type === 'crx') { %>
# Chrome bug: crbug.com/275848
return true if anchor.parentNode
<% } %>
# Attempt to handle cases such as:
# [spoiler]www.[/spoiler]example.com #
# www.example[spoiler].com[/spoiler] #
return false if boundaries.areRelocated
Linkify.relocate boundaries
Linkify.surround anchor, range, boundaries
relocate: (boundaries) ->
# What do you mean, "silly"?
boundaries.areRelocated = true
if boundaries.startOffset is 0
parentNode = boundaries.startNode
until parentNode.previousSibling
{parentNode} = parentNode
parent = parentNode.parentNode
boundaries.startNode = parent
boundaries.startOffset = [parent.childNodes...].indexOf parentNode
if boundaries.endOffset is boundaries.endNode.length
parentNode = boundaries.endNode
until parentNode.nextSibling
{parentNode} = parentNode
parent = parentNode.parentNode
boundaries.endNode = parent
boundaries.endOffset = [parent.childNodes...].indexOf(parentNode) + 1
cleanLink: (anchor, link) ->
{length} = link
for node in $$ 's, .prettyprint', anchor
$.replace node, [node.childNodes...] if length > node.textContent.length
return

View File

@ -72,3 +72,5 @@ ExpandComment =
Fourchan.code.call post
if g.BOARD.ID is 'sci'
Fourchan.math.call post
if Conf['Linkify']
Linkify.node.call post