Add archive selection.

This commit is contained in:
Mayhem 2013-05-06 06:57:29 +02:00
parent f1b6647475
commit 538e117746
14 changed files with 384 additions and 106 deletions

View File

@ -1,3 +1,6 @@
- **New feature**: `Archive selection`
- Select which archive you want for specific boards and redirection type.
- Access it in the `Archives` tab of the Settings window.
- Fix quote previews getting 'stuck' in Opera. - Fix quote previews getting 'stuck' in Opera.
### 3.3.1 - *2013-05-04* ### 3.3.1 - *2013-05-04*

View File

@ -122,6 +122,7 @@ module.exports = function(grunt) {
'src/**/*', 'src/**/*',
'html/**/*', 'html/**/*',
'css/**/*', 'css/**/*',
'json/**/*',
'img/**/*' 'img/**/*'
], ],
tasks: 'build' tasks: 'build'

View File

@ -358,6 +358,18 @@ a[href="javascript:;"] {
.section-rice textarea { .section-rice textarea {
height: 150px; height: 150px;
} }
.section-archives table {
width: 100%;
}
.section-archives th:not(:first-child) {
width: 30%;
}
.section-archives td {
text-align: center;
}
.section-archives select {
width: 90%;
}
#fourchanx-settings fieldset { #fourchanx-settings fieldset {
border: 1px solid; border: 1px solid;
border-radius: 3px; border-radius: 3px;

View File

@ -0,0 +1,12 @@
<div class="warning" #{if Conf['404 Redirect'] then 'hidden' else ''}><code>404 Redirect</code> is disabled.</div>
<p>Disabled selections indicate that only one archive is available for that board and redirection type.</p>
<table>
<caption>Archived boards</caption>
<thead>
<th>Board</th>
<th>Thread redirection</th>
<th>Post fetching</th>
<th>File redirection</th>
</thead>
<tbody></tbody>
</table>

100
json/archives.json Normal file
View File

@ -0,0 +1,100 @@
[{
"uid": 0,
"name": "Foolz",
"domain": "archive.foolz.us",
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["a", "co", "gd", "jp", "m", "q", "sp", "tg", "tv", "vp", "vr", "wsg"],
"files": ["a", "gd", "jp", "m", "q", "tg", "vp", "vr", "wsg"]
}, {
"uid": 1,
"name": "NSFW Foolz",
"domain": "nsfw.foolz.us",
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["u"],
"files": ["u"]
}, {
"uid": 2,
"name": "The Dark Cave",
"domain": "archive.thedarkcave.org",
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["c", "int", "out", "po"],
"files": ["c", "po"]
}, {
"uid": 3,
"name": "4plebs",
"domain": "archive.4plebs.org",
"http": true,
"https": false,
"software": "foolfuuka",
"boards": ["hr", "tg", "tv", "x"],
"files": ["hr", "tg", "tv", "x"]
}, {
"uid": 4,
"name": "Nyafuu",
"domain": "archive.nyafuu.org",
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["c", "w", "wg"],
"files": ["c", "w", "wg"]
}, {
"uid": 5,
"name": "Love is Over",
"domain": "loveisover.me",
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["d", "h", "v"],
"files": ["d", "h", "v"]
}, {
"uid": 6,
"name": "nth-chan",
"domain": "nth.pensivenonsen.se",
"http": true,
"https": false,
"software": "foolfuuka",
"boards": [],
"files": []
}, {
"uid": 7,
"name": "Install Gentoo",
"domain": "archive.installgentoo.net",
"http": true,
"https": true,
"software": "fuuka",
"boards": ["diy", "g", "sci"],
"files": []
}, {
"uid": 8,
"name": "Rebecca Black Tech",
"domain": "rbt.asia",
"http": true,
"https": true,
"software": "fuuka",
"boards": ["cgl", "g", "mu", "w"],
"files": ["cgl", "g", "mu", "w"]
}, {
"uid": 9,
"name": "Heinessen",
"domain": "archive.heinessen.com",
"http": true,
"https": false,
"software": "fuuka",
"boards": ["an", "fit", "k", "mlp", "r9k", "toy", "x"],
"files": ["an", "k", "toy", "x"]
}, {
"uid": 10,
"name": "warosu",
"domain": "fuuka.warosu.org",
"http": true,
"https": true,
"software": "fuuka",
"boards": ["3", "cgl", "ck", "fa", "ic", "jp", "lit", "q", "s4s", "tg", "vr"],
"files": ["3", "cgl", "ck", "fa", "ic", "jp", "lit", "q", "s4s", "vr"]
}]

101
json/archives1.json Normal file
View File

@ -0,0 +1,101 @@
{
"Foolz": {
"uid": 0,
"domain": "archive.foolz.us",
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["a", "co", "gd", "jp", "m", "q", "sp", "tg", "tv", "vp", "vr", "wsg"],
"files": ["a", "gd", "jp", "m", "q", "tg", "vp", "vr", "wsg"]
},
"NSFW Foolz": {
"uid": 1,
"domain": "nsfw.foolz.us",
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["u"],
"files": ["u"]
},
"The Dark Cave": {
"uid": 2,
"domain": "archive.thedarkcave.org",
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["c", "int", "out", "po"],
"files": ["c", "po"]
},
"4plebs": {
"uid": 3,
"domain": "archive.4plebs.org",
"http": true,
"https": false,
"software": "foolfuuka",
"boards": ["hr", "tg", "tv", "x"],
"files": ["hr", "tg", "tv", "x"]
},
"Nyafuu": {
"uid": 4,
"domain": "archive.nyafuu.org",
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["c", "w", "wg"],
"files": ["c", "w", "wg"]
},
"Love is Over": {
"uid": 5,
"domain": "loveisover.me",
"http": true,
"https": true,
"software": "foolfuuka",
"boards": ["d", "h", "v"],
"files": ["d", "h", "v"]
},
"nth-chan": {
"uid": 6,
"domain": "nth.pensivenonsen.se",
"http": true,
"https": false,
"software": "foolfuuka",
"boards": ["vg"],
"files": ["vg"]
},
"Install Gentoo": {
"uid": 7,
"domain": "archive.installgentoo.net",
"http": true,
"https": true,
"software": "fuuka",
"boards": ["diy", "g", "sci"],
"files": []
},
"Rebecca Black Tech": {
"uid": 8,
"domain": "rbt.asia",
"http": true,
"https": true,
"software": "fuuka",
"boards": ["cgl", "g", "mu", "w"],
"files": ["cgl", "g", "mu", "w"]
},
"Heinessen": {
"uid": 9,
"domain": "archive.heinessen.com",
"http": true,
"https": false,
"software": "fuuka",
"boards": ["an", "fit", "k", "mlp", "r9k", "toy", "x"],
"files": ["an", "k", "toy", "x"]
},
"warosu": {
"uid": 10,
"domain": "fuuka.warosu.org",
"http": true,
"https": true,
"software": "fuuka",
"boards": ["cgl", "ck", "fa", "jp", "lit", "q", "s4s", "tg", "vr"],
"files": ["cgl", "ck", "fa", "jp", "lit", "q", "s4s", "tg", "vr"]
}
}

View File

@ -1,102 +1,78 @@
Redirect = Redirect =
image: (boardID, filename) -> archives: `<%= JSON.stringify(grunt.file.readJSON('json/archives.json')) %>`
# Do not use g.BOARD, the image url can originate from a cross-quote. thread: {}
switch boardID post: {}
when 'a', 'gd', 'jp', 'm', 'q', 'tg', 'vp', 'vr', 'wsg' file: {}
"//archive.foolz.us/#{boardID}/full_image/#{filename}"
when 'u'
"//nsfw.foolz.us/#{boardID}/full_image/#{filename}"
when 'po'
"//archive.thedarkcave.org/#{boardID}/full_image/#{filename}"
when 'hr', 'tv'
"http://archive.4plebs.org/#{boardID}/full_image/#{filename}"
when 'c', 'w', 'wg'
"//archive.nyafuu.org/#{boardID}/full_image/#{filename}"
when 'd', 'h', 'v'
"//loveisover.me/#{boardID}/full_image/#{filename}"
when 'vg'
"http://nth.pensivenonsen.se/#{boardID}/full_image/#{filename}"
when 'ck', 'fa', 'lit', 's4s'
"//fuuka.warosu.org/#{boardID}/full_image/#{filename}"
when 'cgl', 'g', 'mu'
"//rbt.asia/#{boardID}/full_image/#{filename}"
when 'an', 'k', 'toy', 'x'
"http://archive.heinessen.com/#{boardID}/full_image/#{filename}"
post: (boardID, postID) ->
# XXX foolz had HSTS set for 120 days, which broke XHR+CORS+Redirection when on HTTP.
# Remove necessary HTTPS procotol in September 2013.
switch boardID
when 'a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg'
"https://archive.foolz.us/_/api/chan/post/?board=#{boardID}&num=#{postID}"
when 'u'
"https://nsfw.foolz.us/_/api/chan/post/?board=#{boardID}&num=#{postID}"
when 'int', 'out', 'po'
"//archive.thedarkcave.org/_/api/chan/post/?board=#{boardID}&num=#{postID}"
when 'hr', 'x'
"http://archive.4plebs.org/_/api/chan/post/?board=#{boardID}&num=#{postID}"
when 'c', 'w', 'wg'
"//archive.nyafuu.org/_/api/chan/post/?board=#{boardID}&num=#{postID}"
when 'd', 'h', 'v'
"//loveisover.me/_/api/chan/post/?board=#{boardID}&num=#{postID}"
when 'vg'
"http://nth.pensivenonsen.se/_/api/chan/post/?board=#{boardID}&num=#{postID}"
# for fuuka-based archives:
# https://github.com/eksopl/fuuka/issues/27
to: (data) ->
{boardID} = data
switch boardID
when 'a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg'
Redirect.path '//archive.foolz.us', 'foolfuuka', data
when 'u'
Redirect.path '//nsfw.foolz.us', 'foolfuuka', data
when 'int', 'out', 'po'
Redirect.path '//archive.thedarkcave.org', 'foolfuuka', data
when 'hr'
Redirect.path 'http://archive.4plebs.org', 'foolfuuka', data
when 'c', 'w', 'wg'
Redirect.path '//archive.nyafuu.org', 'foolfuuka', data
when 'd', 'h', 'v'
Redirect.path '//loveisover.me', 'foolfuuka', data
when 'vg'
Redirect.path 'http://nth.pensivenonsen.se', 'foolfuuka', data
when 'ck', 'fa', 'lit', 's4s'
Redirect.path '//fuuka.warosu.org', 'fuuka', data
when 'diy', 'g', 'sci'
Redirect.path '//archive.installgentoo.net', 'fuuka', data
when 'cgl', 'mu'
Redirect.path '//rbt.asia', 'fuuka', data
when 'an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'
Redirect.path 'http://archive.heinessen.com', 'fuuka', data
else
if data.threadID then "//boards.4chan.org/#{boardID}/" else ''
path: (base, archiver, data) ->
if data.isSearch
{boardID, type, value} = data
type = if type is 'name'
'username'
else if type is 'MD5'
'image'
else
type
value = encodeURIComponent value
return if archiver is 'foolfuuka'
"#{base}/#{boardID}/search/#{type}/#{value}"
else if type is 'image'
"#{base}/#{boardID}/?task=search2&search_media_hash=#{value}"
else
"#{base}/#{boardID}/?task=search2&search_#{type}=#{value}"
{boardID, threadID, postID} = data init: ->
# keep the number only if the location.hash was sent f.e. for boardID, data of Conf['selectedArchives']
for type, uid of data
for archive in Redirect.archives
continue if archive.uid isnt uid or type is 'post' and archive.software isnt 'foolfuuka'
arr = if type is 'file'
archive.files
else
archive.boards
Redirect[type][boardID] = archive if boardID in arr
for archive in Redirect.archives
for boardID in archive.boards
unless boardID of Redirect.thread
Redirect.thread[boardID] = archive
unless boardID of Redirect.post or archive.software isnt 'foolfuuka'
Redirect.post[boardID] = archive
unless boardID of Redirect.file or boardID not in archive.files
Redirect.file[boardID] = archive
return
to: (dest, data) ->
archive = (if dest is 'search' then Redirect.thread else Redirect[dest])[data.boardID]
return '' unless archive
Redirect[dest] archive, data
protocol: (archive) ->
protocol = location.protocol
unless archive[protocol[0...-1]]
protocol = if protocol is 'https:' then 'http:' else 'https:'
"#{protocol}//"
thread: (archive, {boardID, threadID, postID}) ->
# Keep the post number only if the location.hash was sent f.e.
path = if threadID path = if threadID
"#{boardID}/thread/#{threadID}" "#{boardID}/thread/#{threadID}"
else else
"#{boardID}/post/#{postID}" "#{boardID}/post/#{postID}"
if archiver is 'foolfuuka' if archive.software is 'foolfuuka'
path += '/' path += '/'
if threadID and postID if threadID and postID
path += if archiver is 'foolfuuka' path += if archive.software is 'foolfuuka'
"##{postID}" "##{postID}"
else else
"#p#{postID}" "#p#{postID}"
"#{base}/#{path}" "#{Redirect.protocol archive}#{archive.domain}/#{path}"
post: (archive, {boardID, postID}) ->
# For fuuka-based archives:
# https://github.com/eksopl/fuuka/issues/27
protocol = Redirect.protocol archive
# XXX foolz had HSTS set for 120 days, which broke XHR+CORS+Redirection when on HTTP.
# Remove necessary HTTPS procotol in September 2013.
if archive.name in ['Foolz', 'NSFW Foolz']
protocol = 'https://'
"#{protocol}#{archive.domain}/_/api/chan/post/?board=#{boardID}&num=#{postID}"
file: (archive, {boardID, filename}) ->
"#{Redirect.protocol archive}#{archive.domain}/#{boardID}/full_image/#{filename}"
search: (archive, {boardID, type, value}) ->
type = if type is 'name'
'username'
else if type is 'MD5'
'image'
else
type
value = encodeURIComponent value
path = if archive.software is 'foolfuuka'
"#{boardID}/search/#{type}/#{value}"
else
"#{boardID}/?task=search2&search_#{if type is 'image' then 'media_hash' else type}=#{value}"
"#{Redirect.protocol archive}#{archive.domain}/#{path}"

View File

@ -71,7 +71,7 @@ Get =
if threadID if threadID
$.cache "//api.4chan.org/#{boardID}/res/#{threadID}.json", -> $.cache "//api.4chan.org/#{boardID}/res/#{threadID}.json", ->
Get.fetchedPost @, boardID, threadID, postID, root, context Get.fetchedPost @, boardID, threadID, postID, root, context
else if url = Redirect.post boardID, postID else if url = Redirect.to 'post', {boardID, postID}
$.cache url, -> $.cache url, ->
Get.archivedPost @, boardID, postID, root, context Get.archivedPost @, boardID, postID, root, context
insert: (post, root, context) -> insert: (post, root, context) ->
@ -97,7 +97,7 @@ Get =
{status} = req {status} = req
if status not in [200, 304] if status not in [200, 304]
# The thread can die by the time we check a quote. # The thread can die by the time we check a quote.
if url = Redirect.post boardID, postID if url = Redirect.to 'post', {boardID, postID}
$.cache url, -> $.cache url, ->
Get.archivedPost @, boardID, postID, root, context Get.archivedPost @, boardID, postID, root, context
else else
@ -115,7 +115,7 @@ Get =
break if post.no is postID # we found it! break if post.no is postID # we found it!
if post.no > postID if post.no > postID
# The post can be deleted by the time we check a quote. # The post can be deleted by the time we check a quote.
if url = Redirect.post boardID, postID if url = Redirect.to 'post', {boardID, postID}
$.cache url, -> $.cache url, ->
Get.archivedPost @, boardID, postID, root, context Get.archivedPost @, boardID, postID, root, context
else else

View File

@ -14,6 +14,7 @@ Main =
flatten null, Config flatten null, Config
for db in DataBoards for db in DataBoards
Conf[db] = boards: {} Conf[db] = boards: {}
Conf['selectedArchives'] = {}
$.get Conf, Main.initFeatures $.get Conf, Main.initFeatures
$.on d, '4chanMainInit', Main.initStyle $.on d, '4chanMainInit', Main.initStyle
@ -43,8 +44,11 @@ Main =
when 'images.4chan.org' when 'images.4chan.org'
$.ready -> $.ready ->
if Conf['404 Redirect'] and d.title is '4chan - 404 Not Found' if Conf['404 Redirect'] and d.title is '4chan - 404 Not Found'
url = Redirect.image pathname[1], pathname[3] Redirect.init()
location.href = url if url URL = Redirect.to 'file',
boardID: pathname[1]
filename: pathname[3]
location.href = URL if URL
return return
initFeature = (name, module) -> initFeature = (name, module) ->
@ -65,6 +69,7 @@ Main =
initFeature 'Announcement Hiding', PSAHiding initFeature 'Announcement Hiding', PSAHiding
initFeature 'Fourchan thingies', Fourchan initFeature 'Fourchan thingies', Fourchan
initFeature 'Custom CSS', CustomCSS initFeature 'Custom CSS', CustomCSS
initFeature 'Redirect', Redirect
initFeature 'Resurrect Quotes', Quotify initFeature 'Resurrect Quotes', Quotify
initFeature 'Filter', Filter initFeature 'Filter', Filter
initFeature 'Thread Hiding', ThreadHiding initFeature 'Thread Hiding', ThreadHiding
@ -148,7 +153,7 @@ Main =
initReady: -> initReady: ->
if d.title is '4chan - 404 Not Found' if d.title is '4chan - 404 Not Found'
if Conf['404 Redirect'] and g.VIEW is 'thread' if Conf['404 Redirect'] and g.VIEW is 'thread'
href = Redirect.to href = Redirect.to 'thread',
boardID: g.BOARD.ID boardID: g.BOARD.ID
threadID: g.THREADID threadID: g.THREADID
postID: +location.hash.match /\d+/ # post number or 0 postID: +location.hash.match /\d+/ # post number or 0

View File

@ -41,6 +41,7 @@ Settings =
Settings.addSection 'QR', Settings.qr Settings.addSection 'QR', Settings.qr
Settings.addSection 'Sauce', Settings.sauce Settings.addSection 'Sauce', Settings.sauce
Settings.addSection 'Rice', Settings.rice Settings.addSection 'Rice', Settings.rice
Settings.addSection 'Archives', Settings.archives
Settings.addSection 'Keybinds', Settings.keybinds Settings.addSection 'Keybinds', Settings.keybinds
$.on d, 'AddSettingsSection', Settings.addSection $.on d, 'AddSettingsSection', Settings.addSection
$.on d, 'OpenSettings', (e) -> Settings.open e.detail $.on d, 'OpenSettings', (e) -> Settings.open e.detail
@ -386,6 +387,69 @@ Settings =
usercss: -> usercss: ->
CustomCSS.update() CustomCSS.update()
archives: (section) ->
section.innerHTML = """
<%= grunt.file.read('html/General/Settings-section-Archives.html').replace(/>\s+</g, '><').trim() %>
"""
boards = {}
for archive in Redirect.archives
for boardID in archive.boards
data = boards[boardID] or= {
thread: []
post: []
file: []
}
data.thread.push archive
if archive.software is 'foolfuuka'
data.post.push archive
if boardID in archive.files
data.file.push archive
rows = []
for boardID in Object.keys(boards).sort() # Alphabetical order
row = $.el 'tr'
rows.push row
$.add row, $.el 'th',
textContent: "/#{boardID}/"
className: if boardID is g.BOARD.ID then 'warning' else ''
data = boards[boardID]
Settings.addArchiveCell row, boardID, data, 'thread'
Settings.addArchiveCell row, boardID, data, 'post'
Settings.addArchiveCell row, boardID, data, 'file'
$.add $('tbody', section), rows
$.get 'selectedArchives', Conf['selectedArchives'], ({selectedArchives}) ->
for boardID, data of selectedArchives
for type, uid of data
if option = $ "select[data-boardid='#{boardID}'][data-type='#{type}'] > option[value='#{uid}']", section
option.selected = true
return
addArchiveCell: (row, boardID, data, type) ->
options = []
for archive in data[type]
options.push $.el 'option',
textContent: archive.name
value: archive.uid
td = $.el 'td'
{length} = options
if length
td.innerHTML = '<select></select>'
select = td.firstElementChild
unless select.disabled = length is 1
# XXX GM can't into datasets
select.setAttribute 'data-boardid', boardID
select.setAttribute 'data-type', type
$.on select, 'change', Settings.saveSelectedArchive
$.add select, options
else
td.textContent = 'N/A'
$.add row, td
saveSelectedArchive: ->
$.get 'selectedArchives', Conf['selectedArchives'], ({selectedArchives}) =>
(selectedArchives[@dataset.boardid] or= {})[@dataset.type] = +@value
$.set 'selectedArchives', selectedArchives
keybinds: (section) -> keybinds: (section) ->
section.innerHTML = """ section.innerHTML = """
<%= grunt.file.read('html/General/Settings-section-Keybinds.html').replace(/>\s+</g, '><').trim() %> <%= grunt.file.read('html/General/Settings-section-Keybinds.html').replace(/>\s+</g, '><').trim() %>

View File

@ -136,7 +136,10 @@ ImageExpand =
src = @src.split '/' src = @src.split '/'
if src[2] is 'images.4chan.org' if src[2] is 'images.4chan.org'
if URL = Redirect.image src[3], src[5] URL = Redirect.to 'file',
boardID: src[3]
filename: src[5].replace /\?.+$/, ''
if URL
setTimeout ImageExpand.expand, 10000, post, URL setTimeout ImageExpand.expand, 10000, post, URL
return return
if g.DEAD or post.isDead or post.file.isDead if g.DEAD or post.isDead or post.file.isDead

View File

@ -28,7 +28,10 @@ ImageHover =
src = @src.split '/' src = @src.split '/'
if src[2] is 'images.4chan.org' if src[2] is 'images.4chan.org'
if URL = Redirect.image src[3], src[5].replace /\?.+$/, '' URL = Redirect.to 'file',
boardID: src[3]
filename: src[5].replace /\?.+$/, ''
if URL
@src = URL @src = URL
return return
if g.DEAD or post.isDead or post.file.isDead if g.DEAD or post.isDead or post.file.isDead

View File

@ -10,8 +10,7 @@ ArchiveLink =
el: div el: div
order: 90 order: 90
open: ({ID, thread, board}) -> open: ({ID, thread, board}) ->
redirect = Redirect.to {postID: ID, threadID: thread.ID, boardID: board.ID} !!Redirect.to 'thread', {postID: ID, threadID: thread.ID, boardID: board.ID}
redirect isnt "//boards.4chan.org/#{board}/"
subEntries: [] subEntries: []
for type in [ for type in [
@ -35,18 +34,17 @@ ArchiveLink =
open = if type is 'post' open = if type is 'post'
({ID, thread, board}) -> ({ID, thread, board}) ->
el.href = Redirect.to {postID: ID, threadID: thread.ID, boardID: board.ID} el.href = Redirect.to 'thread', {postID: ID, threadID: thread.ID, boardID: board.ID}
true true
else else
(post) -> (post) ->
value = Filter[type] post value = Filter[type] post
# We want to parse the exact same stuff as the filter does already. # We want to parse the exact same stuff as the filter does already.
return false unless value return false unless value
el.href = Redirect.to el.href = Redirect.to 'search',
boardID: post.board.ID boardID: post.board.ID
type: type type: type
value: value value: value
isSearch: true
true true
return { return {

View File

@ -47,14 +47,14 @@ Quotify =
a.setAttribute 'data-boardid', boardID a.setAttribute 'data-boardid', boardID
a.setAttribute 'data-threadid', post.thread.ID a.setAttribute 'data-threadid', post.thread.ID
a.setAttribute 'data-postid', postID a.setAttribute 'data-postid', postID
else if redirect = Redirect.to {boardID, threadID: 0, postID} else if redirect = Redirect.to 'thread', {boardID, threadID: 0, postID}
# Replace the .deadlink span if we can redirect. # Replace the .deadlink span if we can redirect.
a = $.el 'a', a = $.el 'a',
href: redirect href: redirect
className: 'deadlink' className: 'deadlink'
target: '_blank' target: '_blank'
textContent: "#{quote}\u00A0(Dead)" textContent: "#{quote}\u00A0(Dead)"
if Redirect.post boardID, postID if Redirect.to 'post', {boardID, postID}
# Make it function as a normal quote if we can fetch the post. # Make it function as a normal quote if we can fetch the post.
$.addClass a, 'quotelink' $.addClass a, 'quotelink'
a.setAttribute 'data-boardid', boardID a.setAttribute 'data-boardid', boardID