4chan-x/src/Linkification/Linkify.coffee
2013-05-01 12:58:05 -07:00

285 lines
8.7 KiB
CoffeeScript

Linkify =
init: ->
return if g.VIEW is 'catalog' or not Conf['Linkify']
if Conf['Comment Expansion']
ExpandComment.callbacks.push @node
Post::callbacks.push
name: 'Linkify'
cb: @node
regString: ///(
\b(
[a-z]+://
|
[a-z]{3,}\.[-a-z0-9]+\.[a-z]+
|
[-a-z0-9]+\.[a-z]
|
[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+
|
[a-z]{3,}:[a-z0-9?]
|
[a-z0-9._%+-:]+@[a-z0-9.-]+\.[a-z0-9]
)
[^\s'"]+
)///gi
cypher: $.el 'div'
node: ->
if @isClone and Conf['Embedding']
for embedder in $$ '.embedder', @nodes.comment
$.on embedder, "click", Linkify.toggle
return
snapshot = $.X './/text()', @nodes.comment
cypher = Linkify.cypher
i = -1
len = snapshot.snapshotLength
while ++i < len
nodes = $.frag()
node = snapshot.snapshotItem i
data = node.data
# Test for valid links
continue unless node.parentNode and Linkify.regString.test data
Linkify.regString.lastIndex = 0
cypherText = []
if next = node.nextSibling
cypher.textContent = node.textContent
cypherText[0] = cypher.innerHTML
while (next.nodeName.toLowerCase() is 'wbr' or next.nodeName.toLowerCase() is 's') and (lookahead = next.nextSibling) and ((name = lookahead.nodeName) is "#text" or name.toLowerCase() is 'br')
cypher.textContent = lookahead.textContent
cypherText.push if spoiler = next.innerHTML then "<s>#{spoiler.replace /</g, ' <'}</s>" else '<wbr>'
cypherText.push cypher.innerHTML
$.rm next
next = lookahead.nextSibling
$.rm lookahead if lookahead.nodeName is "#text"
unless next
break
if cypherText.length
data = cypherText.join ''
links = data.match Linkify.regString
for link in links
index = data.indexOf link
if text = data[...index]
# press button get bacon
cypher.innerHTML = text
for child in [cypher.childNodes...]
$.add nodes, child
cypher.innerHTML = (if link.indexOf(':') < 0 then (if link.indexOf('@') > 0 then 'mailto:' + link else 'http://' + link) else link).replace /<(wbr|s|\/s)>/g, ''
a = $.el 'a',
innerHTML: link
className: 'linkify'
rel: 'nofollow noreferrer'
target: '_blank'
href: cypher.textContent
$.add nodes, Linkify.embedder a
data = data[index + link.length..]
if data
# Potential text after the last valid link.
cypher.innerHTML = data
# Convert <wbr> into elements
for child in [cypher.childNodes...]
$.add nodes, child
$.replace node, nodes
if Conf['Auto-embed']
embeds = $$ '.embedder', @nodes.comment
for embed in embeds
embed.click()
return
toggle: ->
# We setup the link to be replaced by the embedded video
embed = @previousElementSibling
# Unembed.
if @className.contains "embedded"
# Recreate the original link.
el = $.el 'a',
rel: 'nofollow noreferrer'
target: 'blank'
className: 'linkify'
href: url = @getAttribute("data-originalURL")
textContent: @getAttribute("data-title") or url
@textContent = '(embed)'
$.addClass el, "#{@getAttribute 'data-service'}"
else
# We create an element to embed
el = (type = Linkify.types[@getAttribute("data-service")]).el.call @
# Set style values.
el.style.cssText = if style = type.style
style
else
"border: 0; width: 640px; height: 390px"
@textContent = '(unembed)'
$.replace embed, el
$.toggleClass @, 'embedded'
types:
YouTube:
regExp: /.*(?:youtu.be\/|youtube.*v=|youtube.*\/embed\/|youtube.*\/v\/|youtube.*videos\/)([^#\&\?]*)\??(t\=.*)?/
el: ->
$.el 'iframe',
src: "//www.youtube.com/embed/#{@name}#{if @option then '#' + @option else ''}"
title:
api: -> "https://gdata.youtube.com/feeds/api/videos/#{@name}?alt=json&fields=title/text(),yt:noembed,app:control/yt:state/@reasonCode"
text: -> JSON.parse(@responseText).entry.title.$t
Vocaroo:
regExp: /.*(?:vocaroo.com\/)([^#\&\?]*).*/
style: 'border: 0; width: 150px; height: 45px;'
el: ->
$.el 'object',
innerHTML: "<embed src='http://vocaroo.com/player.swf?playMediaID=#{@name.replace /^i\//, ''}&autoplay=0' width='150' height='45' pluginspage='http://get.adobe.com/flashplayer/' type='application/x-shockwave-flash'></embed>"
Vimeo:
regExp: /.*(?:vimeo.com\/)([^#\&\?]*).*/
el: ->
$.el 'iframe',
src: "//player.vimeo.com/video/#{@name}"
title:
api: -> "https://vimeo.com/api/oembed.json?url=http://vimeo.com/#{@name}"
text: -> JSON.parse(@responseText).title
LiveLeak:
regExp: /.*(?:liveleak.com\/view.+i=)([0-9a-z_]+)/
el: ->
$.el 'iframe',
src: "http://www.liveleak.com/e/#{@name}?autostart=true"
audio:
regExp: /(.*\.(mp3|ogg|wav))$/
el: ->
$.el 'audio',
controls: 'controls'
preload: 'auto'
src: @name
image:
regExp: /(http|www).*\.(gif|png|jpg|jpeg|bmp)$/
style: 'border: 0; width: auto; height: auto;'
el: ->
$.el 'div',
innerHTML: "<a target=_blank href='#{@getAttribute 'data-originalURL'}'><img src='#{@getAttribute 'data-originalURL'}'></a>"
SoundCloud:
regExp: /.*(?:soundcloud.com\/|snd.sc\/)([^#\&\?]*).*/
style: 'height: auto; width: 500px; display: inline-block;'
el: ->
div = $.el 'div',
className: "soundcloud"
name: "soundcloud"
$.ajax(
"//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/#{@name}"
div: div
onloadend: ->
@div.innerHTML = JSON.parse(@responseText).html
false)
div
title:
api: -> "//soundcloud.com/oembed?show_artwork=false&&maxwidth=500px&show_comments=false&format=json&url=https://www.soundcloud.com/#{@name}"
text: -> JSON.parse(@responseText).title
pastebin:
regExp: /.*(?:pastebin.com\/(?!u\/))([^#\&\?]*).*/
el: ->
div = $.el 'iframe',
src: "http://pastebin.com/embed_iframe.php?i=#{@name}"
gist:
regExp: /.*(?:gist.github.com.*\/)([^\/][^\/]*)$/
el: ->
div = $.el 'iframe',
# Github doesn't allow embedding straight from the site, so we use an external site to bypass that.
src: "http://www.purplegene.com/script?url=https://gist.github.com/#{@name}.js"
title:
api: -> "https://api.github.com/gists/#{@name}"
text: ->
response = JSON.parse(@responseText).files
return file for file of response when response.hasOwnProperty file
InstallGentoo:
regExp: /.*(?:paste.installgentoo.com\/view\/)([0-9a-z_]+)/
el: ->
$.el 'iframe',
src: "http://paste.installgentoo.com/view/embed/#{@name}"
embedder: (a) ->
return [a] unless Conf['Link Title']
titles = {}
callbacks = ->
a.textContent = switch @status
when 200, 304
title = "#{service.text.call @}"
embed.setAttribute 'data-title', title
titles[embed.name] = [title, Date.now()]
$.set 'CachedTitles', titles
title
when 404
"[#{key}] Not Found"
when 403
"[#{key}] Forbidden or Private"
else
"[#{key}] #{@status}'d"
for key, type of Linkify.types
continue unless match = a.href.match type.regExp
embed = $.el 'a',
name: (a.name = match[1])
option: match[2]
className: 'embedder'
href: 'javascript:;'
textContent: '(embed)'
embed.setAttribute 'data-service', key
embed.setAttribute 'data-originalURL', a.href
$.addClass a, "#{embed.getAttribute 'data-service'}"
$.on embed, 'click', Linkify.toggle
unless Conf['Embedding']
embed.hidden = true
if Conf['Link Title'] and (service = type.title)
$.get 'CachedTitles', {}, (item) ->
titles = item['CachedTitles']
if title = titles[match[1]]
a.textContent = title[0]
embed.setAttribute 'data-title', title[0]
else
try
$.cache service.api.call(a), callbacks
catch err
a.innerHTML = "[#{key}] <span class=warning>Title Link Blocked</span> (are you using NoScript?)</a>"
return [a, $.tn(' '), embed]
return [a]