Move post fetching code into a class.
This commit is contained in:
parent
511dbf0ffc
commit
bacfbb4e64
@ -70,184 +70,3 @@ Get =
|
|||||||
for script in $$ 'script:not([src])', d.head
|
for script in $$ 'script:not([src])', d.head
|
||||||
return script.textContent if /\bcooldowns *=/.test script.textContent
|
return script.textContent if /\bcooldowns *=/.test script.textContent
|
||||||
''
|
''
|
||||||
postClone: (boardID, threadID, postID, root, context) ->
|
|
||||||
if post = g.posts["#{boardID}.#{postID}"]
|
|
||||||
Get.insert post, root, context
|
|
||||||
return
|
|
||||||
|
|
||||||
root.textContent = "Loading post No.#{postID}..."
|
|
||||||
if threadID
|
|
||||||
$.cache "//a.4cdn.org/#{boardID}/thread/#{threadID}.json", ->
|
|
||||||
Get.fetchedPost @, boardID, threadID, postID, root, context
|
|
||||||
else
|
|
||||||
Get.archivedPost boardID, postID, root, context
|
|
||||||
insert: (post, root, context) ->
|
|
||||||
# Stop here if the container has been removed while loading.
|
|
||||||
return unless root.parentNode
|
|
||||||
clone = post.addClone context, ($.hasClass root, 'dialog')
|
|
||||||
Main.callbackNodes Clone, [clone]
|
|
||||||
|
|
||||||
# Get rid of the side arrows.
|
|
||||||
{nodes} = clone
|
|
||||||
$.rmAll nodes.root
|
|
||||||
$.add nodes.root, nodes.post
|
|
||||||
|
|
||||||
$.rmAll root
|
|
||||||
$.add root, nodes.root
|
|
||||||
$.event 'PostsInserted'
|
|
||||||
fetchedPost: (req, boardID, threadID, postID, root, context) ->
|
|
||||||
# In case of multiple callbacks for the same request,
|
|
||||||
# don't parse the same original post more than once.
|
|
||||||
if post = g.posts["#{boardID}.#{postID}"]
|
|
||||||
Get.insert post, root, context
|
|
||||||
return
|
|
||||||
|
|
||||||
{status} = req
|
|
||||||
unless status in [200, 304]
|
|
||||||
# The thread can die by the time we check a quote.
|
|
||||||
unless Get.archivedPost boardID, postID, root, context
|
|
||||||
$.addClass root, 'warning'
|
|
||||||
root.textContent =
|
|
||||||
if status is 404
|
|
||||||
"Thread No.#{threadID} 404'd."
|
|
||||||
else
|
|
||||||
"Error #{req.statusText} (#{req.status})."
|
|
||||||
return
|
|
||||||
|
|
||||||
{posts} = req.response
|
|
||||||
Build.spoilerRange[boardID] = posts[0].custom_spoiler
|
|
||||||
for post in posts
|
|
||||||
break if post.no is postID # we found it!
|
|
||||||
|
|
||||||
if post.no isnt postID
|
|
||||||
# Cached requests can be stale and must be rechecked.
|
|
||||||
if req.cached
|
|
||||||
api = "//a.4cdn.org/#{boardID}/thread/#{threadID}.json"
|
|
||||||
$.cleanCache (url) -> url is api
|
|
||||||
$.cache api, ->
|
|
||||||
Get.fetchedPost @, boardID, threadID, postID, root, context
|
|
||||||
return
|
|
||||||
# The post can be deleted by the time we check a quote.
|
|
||||||
unless Get.archivedPost boardID, postID, root, context
|
|
||||||
$.addClass root, 'warning'
|
|
||||||
root.textContent = "Post No.#{postID} was not found."
|
|
||||||
return
|
|
||||||
|
|
||||||
board = g.boards[boardID] or
|
|
||||||
new Board boardID
|
|
||||||
thread = g.threads["#{boardID}.#{threadID}"] or
|
|
||||||
new Thread threadID, board
|
|
||||||
post = new Post Build.postFromObject(post, boardID), thread, board
|
|
||||||
post.isFetchedQuote = true
|
|
||||||
Main.callbackNodes Post, [post]
|
|
||||||
Get.insert post, root, context
|
|
||||||
archivedPost: (boardID, postID, root, context) ->
|
|
||||||
return false unless Conf['Resurrect Quotes']
|
|
||||||
return false unless url = Redirect.to 'post', {boardID, postID}
|
|
||||||
if /^https:\/\//.test(url) or location.protocol is 'http:'
|
|
||||||
$.cache url,
|
|
||||||
-> Get.parseArchivedPost @response, boardID, postID, root, context
|
|
||||||
,
|
|
||||||
responseType: 'json'
|
|
||||||
withCredentials: url.archive.withCredentials
|
|
||||||
return true
|
|
||||||
else if Conf['Except Archives from Encryption']
|
|
||||||
CrossOrigin.json url, (response) ->
|
|
||||||
{media} = response
|
|
||||||
if media then for key of media when /_link$/.test key
|
|
||||||
# Image/thumbnail URLs loaded over HTTP can be modified in transit.
|
|
||||||
# Require them to be from a known HTTP host so that no referrer is sent to them from an HTTPS page.
|
|
||||||
delete media[key] unless media[key]? and media[key].match(/^(http:\/\/[^\/]+\/)?/)[0] in url.archive.imagehosts
|
|
||||||
Get.parseArchivedPost response, boardID, postID, root, context
|
|
||||||
return true
|
|
||||||
return false
|
|
||||||
parseArchivedPost: (data, boardID, postID, root, context) ->
|
|
||||||
# In case of multiple callbacks for the same request,
|
|
||||||
# don't parse the same original post more than once.
|
|
||||||
if post = g.posts["#{boardID}.#{postID}"]
|
|
||||||
Get.insert post, root, context
|
|
||||||
return
|
|
||||||
|
|
||||||
if data.error
|
|
||||||
$.addClass root, 'warning'
|
|
||||||
root.textContent = data.error
|
|
||||||
return
|
|
||||||
|
|
||||||
# https://github.com/eksopl/fuuka/blob/master/Board/Yotsuba.pm#L413-452
|
|
||||||
# https://github.com/eksopl/asagi/blob/master/src/main/java/net/easymodo/asagi/Yotsuba.java#L109-138
|
|
||||||
comment = (data.comment or '').split /(\n|\[\/?(?:b|spoiler|code|moot|banned)\])/
|
|
||||||
comment = for text, i in comment
|
|
||||||
if i % 2 is 1
|
|
||||||
Get.archiveTags[text]
|
|
||||||
else
|
|
||||||
greentext = text[0] is '>'
|
|
||||||
text = text.replace /(\[\/?[a-z]+):lit(\])/, '$1$2'
|
|
||||||
text = for text2, j in text.split /(>>(?:>\/[a-z\d]+\/)?\d+)/g
|
|
||||||
if j % 2 is 1
|
|
||||||
<%= html('<span class="deadlink">${text2}</span>') %>
|
|
||||||
else
|
|
||||||
<%= html('${text2}') %>
|
|
||||||
text = <%= html('@{text}') %>
|
|
||||||
text = <%= html('<span class="quote">&{text}</span>') %> if greentext
|
|
||||||
text
|
|
||||||
comment = <%= html('@{comment}') %>
|
|
||||||
|
|
||||||
threadID = +data.thread_num
|
|
||||||
o =
|
|
||||||
# id
|
|
||||||
postID: postID
|
|
||||||
threadID: threadID
|
|
||||||
boardID: boardID
|
|
||||||
# info
|
|
||||||
name: data.name
|
|
||||||
capcode: switch data.capcode
|
|
||||||
when 'M' then 'mod'
|
|
||||||
when 'A' then 'admin'
|
|
||||||
when 'D' then 'developer'
|
|
||||||
tripcode: data.trip
|
|
||||||
uniqueID: data.poster_hash
|
|
||||||
email: data.email or ''
|
|
||||||
subject: data.title
|
|
||||||
flagCode: data.poster_country
|
|
||||||
flagName: data.poster_country_name
|
|
||||||
date: data.fourchan_date
|
|
||||||
dateUTC: data.timestamp
|
|
||||||
comment: comment
|
|
||||||
# file
|
|
||||||
if data.media?.media_filename
|
|
||||||
o.file =
|
|
||||||
name: data.media.media_filename
|
|
||||||
timestamp: data.media.media_orig
|
|
||||||
url: data.media.media_link or data.media.remote_media_link or
|
|
||||||
"//i.4cdn.org/#{boardID}/#{encodeURIComponent data.media[if boardID is 'f' then 'media_filename' else 'media_orig']}"
|
|
||||||
height: data.media.media_h
|
|
||||||
width: data.media.media_w
|
|
||||||
MD5: data.media.media_hash
|
|
||||||
size: data.media.media_size
|
|
||||||
turl: data.media.thumb_link or "//t.4cdn.org/#{boardID}/#{data.media.preview_orig}"
|
|
||||||
theight: data.media.preview_h
|
|
||||||
twidth: data.media.preview_w
|
|
||||||
isSpoiler: data.media.spoiler is '1'
|
|
||||||
o.file.tag = JSON.parse(data.media.exif).Tag if boardID is 'f'
|
|
||||||
|
|
||||||
board = g.boards[boardID] or
|
|
||||||
new Board boardID
|
|
||||||
thread = g.threads["#{boardID}.#{threadID}"] or
|
|
||||||
new Thread threadID, board
|
|
||||||
post = new Post Build.post(o), thread, board, {isArchived: true}
|
|
||||||
post.file.thumbURL = o.file.turl if post.file
|
|
||||||
post.isFetchedQuote = true
|
|
||||||
Main.callbackNodes Post, [post]
|
|
||||||
Get.insert post, root, context
|
|
||||||
archiveTags:
|
|
||||||
'\n': <%= html('<br>') %>
|
|
||||||
'[b]': <%= html('<b>') %>
|
|
||||||
'[/b]': <%= html('</b>') %>
|
|
||||||
'[spoiler]': <%= html('<s>') %>
|
|
||||||
'[/spoiler]': <%= html('</s>') %>
|
|
||||||
'[code]': <%= html('<pre class="prettyprint">') %>
|
|
||||||
'[/code]': <%= html('</pre>') %>
|
|
||||||
'[moot]': <%= html('<div style="padding:5px;margin-left:.5em;border-color:#faa;border:2px dashed rgba(255,0,0,.1);border-radius:2px">') %>
|
|
||||||
'[/moot]': <%= html('</div>') %>
|
|
||||||
'[banned]': <%= html('<strong style="color: red;">') %>
|
|
||||||
'[/banned]': <%= html('</strong>') %>
|
|
||||||
|
|||||||
@ -10,3 +10,4 @@
|
|||||||
<%= grunt.file.read('src/General/lib/simpledict.class') %>
|
<%= grunt.file.read('src/General/lib/simpledict.class') %>
|
||||||
<%= grunt.file.read('src/General/lib/set.class') %>
|
<%= grunt.file.read('src/General/lib/set.class') %>
|
||||||
<%= grunt.file.read('src/General/lib/connection.class') %>
|
<%= grunt.file.read('src/General/lib/connection.class') %>
|
||||||
|
<%= grunt.file.read('src/General/lib/fetcher.class') %>
|
||||||
|
|||||||
182
src/General/lib/fetcher.class
Normal file
182
src/General/lib/fetcher.class
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
class Fetcher
|
||||||
|
constructor: (@boardID, @threadID, @postID, @root, @context) ->
|
||||||
|
if post = g.posts["#{@boardID}.#{@postID}"]
|
||||||
|
@insert post
|
||||||
|
return
|
||||||
|
|
||||||
|
@root.textContent = "Loading post No.#{@postID}..."
|
||||||
|
if @threadID
|
||||||
|
$.cache "//a.4cdn.org/#{@boardID}/thread/#{@threadID}.json", do (self = @) -> ->
|
||||||
|
self.fetchedPost @
|
||||||
|
else
|
||||||
|
@archivedPost()
|
||||||
|
insert: (post) ->
|
||||||
|
# Stop here if the container has been removed while loading.
|
||||||
|
return unless @root.parentNode
|
||||||
|
clone = post.addClone @context, ($.hasClass @root, 'dialog')
|
||||||
|
Main.callbackNodes Clone, [clone]
|
||||||
|
|
||||||
|
# Get rid of the side arrows.
|
||||||
|
{nodes} = clone
|
||||||
|
$.rmAll nodes.root
|
||||||
|
$.add nodes.root, nodes.post
|
||||||
|
|
||||||
|
$.rmAll @root
|
||||||
|
$.add @root, nodes.root
|
||||||
|
$.event 'PostsInserted'
|
||||||
|
fetchedPost: (req) ->
|
||||||
|
# In case of multiple callbacks for the same request,
|
||||||
|
# don't parse the same original post more than once.
|
||||||
|
if post = g.posts["#{@boardID}.#{@postID}"]
|
||||||
|
@insert post
|
||||||
|
return
|
||||||
|
|
||||||
|
{status} = req
|
||||||
|
unless status in [200, 304]
|
||||||
|
# The thread can die by the time we check a quote.
|
||||||
|
unless @archivedPost()
|
||||||
|
$.addClass @root, 'warning'
|
||||||
|
@root.textContent =
|
||||||
|
if status is 404
|
||||||
|
"Thread No.#{@threadID} 404'd."
|
||||||
|
else
|
||||||
|
"Error #{req.statusText} (#{req.status})."
|
||||||
|
return
|
||||||
|
|
||||||
|
{posts} = req.response
|
||||||
|
Build.spoilerRange[@boardID] = posts[0].custom_spoiler
|
||||||
|
for post in posts
|
||||||
|
break if post.no is @postID # we found it!
|
||||||
|
|
||||||
|
if post.no isnt @postID
|
||||||
|
# Cached requests can be stale and must be rechecked.
|
||||||
|
if req.cached
|
||||||
|
api = "//a.4cdn.org/#{@boardID}/thread/#{@threadID}.json"
|
||||||
|
$.cleanCache (url) -> url is api
|
||||||
|
$.cache api, do (self = @) -> ->
|
||||||
|
self.fetchedPost @
|
||||||
|
return
|
||||||
|
# The post can be deleted by the time we check a quote.
|
||||||
|
unless @archivedPost()
|
||||||
|
$.addClass @root, 'warning'
|
||||||
|
@root.textContent = "Post No.#{@postID} was not found."
|
||||||
|
return
|
||||||
|
|
||||||
|
board = g.boards[@boardID] or
|
||||||
|
new Board @boardID
|
||||||
|
thread = g.threads["#{@boardID}.#{@threadID}"] or
|
||||||
|
new Thread @threadID, board
|
||||||
|
post = new Post Build.postFromObject(post, @boardID), thread, board
|
||||||
|
post.isFetchedQuote = true
|
||||||
|
Main.callbackNodes Post, [post]
|
||||||
|
@insert post
|
||||||
|
archivedPost: ->
|
||||||
|
return false unless Conf['Resurrect Quotes']
|
||||||
|
return false unless url = Redirect.to 'post', {@boardID, @postID}
|
||||||
|
if /^https:\/\//.test(url) or location.protocol is 'http:'
|
||||||
|
$.cache url,
|
||||||
|
do (self = @) -> -> self.parseArchivedPost @response
|
||||||
|
,
|
||||||
|
responseType: 'json'
|
||||||
|
withCredentials: url.archive.withCredentials
|
||||||
|
return true
|
||||||
|
else if Conf['Except Archives from Encryption']
|
||||||
|
CrossOrigin.json url, (response) =>
|
||||||
|
{media} = response
|
||||||
|
if media then for key of media when /_link$/.test key
|
||||||
|
# Image/thumbnail URLs loaded over HTTP can be modified in transit.
|
||||||
|
# Require them to be from a known HTTP host so that no referrer is sent to them from an HTTPS page.
|
||||||
|
delete media[key] unless media[key]? and media[key].match(/^(http:\/\/[^\/]+\/)?/)[0] in url.archive.imagehosts
|
||||||
|
@parseArchivedPost response
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
parseArchivedPost: (data) ->
|
||||||
|
# In case of multiple callbacks for the same request,
|
||||||
|
# don't parse the same original post more than once.
|
||||||
|
if post = g.posts["#{@boardID}.#{@postID}"]
|
||||||
|
@insert post
|
||||||
|
return
|
||||||
|
|
||||||
|
if data.error
|
||||||
|
$.addClass @root, 'warning'
|
||||||
|
@root.textContent = data.error
|
||||||
|
return
|
||||||
|
|
||||||
|
# https://github.com/eksopl/fuuka/blob/master/Board/Yotsuba.pm#L413-452
|
||||||
|
# https://github.com/eksopl/asagi/blob/master/src/main/java/net/easymodo/asagi/Yotsuba.java#L109-138
|
||||||
|
comment = (data.comment or '').split /(\n|\[\/?(?:b|spoiler|code|moot|banned)\])/
|
||||||
|
comment = for text, i in comment
|
||||||
|
if i % 2 is 1
|
||||||
|
@archiveTags[text]
|
||||||
|
else
|
||||||
|
greentext = text[0] is '>'
|
||||||
|
text = text.replace /(\[\/?[a-z]+):lit(\])/, '$1$2'
|
||||||
|
text = for text2, j in text.split /(>>(?:>\/[a-z\d]+\/)?\d+)/g
|
||||||
|
if j % 2 is 1
|
||||||
|
<%= html('<span class="deadlink">${text2}</span>') %>
|
||||||
|
else
|
||||||
|
<%= html('${text2}') %>
|
||||||
|
text = <%= html('@{text}') %>
|
||||||
|
text = <%= html('<span class="quote">&{text}</span>') %> if greentext
|
||||||
|
text
|
||||||
|
comment = <%= html('@{comment}') %>
|
||||||
|
|
||||||
|
@threadID = +data.thread_num
|
||||||
|
o =
|
||||||
|
# id
|
||||||
|
postID: @postID
|
||||||
|
threadID: @threadID
|
||||||
|
boardID: @boardID
|
||||||
|
# info
|
||||||
|
name: data.name
|
||||||
|
capcode: switch data.capcode
|
||||||
|
when 'M' then 'mod'
|
||||||
|
when 'A' then 'admin'
|
||||||
|
when 'D' then 'developer'
|
||||||
|
tripcode: data.trip
|
||||||
|
uniqueID: data.poster_hash
|
||||||
|
email: data.email or ''
|
||||||
|
subject: data.title
|
||||||
|
flagCode: data.poster_country
|
||||||
|
flagName: data.poster_country_name
|
||||||
|
date: data.fourchan_date
|
||||||
|
dateUTC: data.timestamp
|
||||||
|
comment: comment
|
||||||
|
# file
|
||||||
|
if data.media?.media_filename
|
||||||
|
o.file =
|
||||||
|
name: data.media.media_filename
|
||||||
|
timestamp: data.media.media_orig
|
||||||
|
url: data.media.media_link or data.media.remote_media_link or
|
||||||
|
"//i.4cdn.org/#{@boardID}/#{encodeURIComponent data.media[if @boardID is 'f' then 'media_filename' else 'media_orig']}"
|
||||||
|
height: data.media.media_h
|
||||||
|
width: data.media.media_w
|
||||||
|
MD5: data.media.media_hash
|
||||||
|
size: data.media.media_size
|
||||||
|
turl: data.media.thumb_link or "//t.4cdn.org/#{@boardID}/#{data.media.preview_orig}"
|
||||||
|
theight: data.media.preview_h
|
||||||
|
twidth: data.media.preview_w
|
||||||
|
isSpoiler: data.media.spoiler is '1'
|
||||||
|
o.file.tag = JSON.parse(data.media.exif).Tag if @boardID is 'f'
|
||||||
|
|
||||||
|
board = g.boards[@boardID] or
|
||||||
|
new Board @boardID
|
||||||
|
thread = g.threads["#{@boardID}.#{@threadID}"] or
|
||||||
|
new Thread @threadID, board
|
||||||
|
post = new Post Build.post(o), thread, board, {isArchived: true}
|
||||||
|
post.file.thumbURL = o.file.turl if post.file
|
||||||
|
post.isFetchedQuote = true
|
||||||
|
Main.callbackNodes Post, [post]
|
||||||
|
@insert post
|
||||||
|
archiveTags:
|
||||||
|
'\n': <%= html('<br>') %>
|
||||||
|
'[b]': <%= html('<b>') %>
|
||||||
|
'[/b]': <%= html('</b>') %>
|
||||||
|
'[spoiler]': <%= html('<s>') %>
|
||||||
|
'[/spoiler]': <%= html('</s>') %>
|
||||||
|
'[code]': <%= html('<pre class="prettyprint">') %>
|
||||||
|
'[/code]': <%= html('</pre>') %>
|
||||||
|
'[moot]': <%= html('<div style="padding:5px;margin-left:.5em;border-color:#faa;border:2px dashed rgba(255,0,0,.1);border-radius:2px">') %>
|
||||||
|
'[/moot]': <%= html('</div>') %>
|
||||||
|
'[banned]': <%= html('<strong style="color: red;">') %>
|
||||||
|
'[/banned]': <%= html('</strong>') %>
|
||||||
@ -60,7 +60,7 @@ QuoteInline =
|
|||||||
qroot = $.x 'ancestor::*[contains(@class,"postContainer")][1]', root
|
qroot = $.x 'ancestor::*[contains(@class,"postContainer")][1]', root
|
||||||
|
|
||||||
$.addClass qroot, 'hasInline'
|
$.addClass qroot, 'hasInline'
|
||||||
Get.postClone boardID, threadID, postID, inline, context
|
new Fetcher boardID, threadID, postID, inline, context
|
||||||
|
|
||||||
return unless (post = g.posts["#{boardID}.#{postID}"]) and
|
return unless (post = g.posts["#{boardID}.#{postID}"]) and
|
||||||
context.thread is post.thread
|
context.thread is post.thread
|
||||||
|
|||||||
@ -24,7 +24,7 @@ QuotePreview =
|
|||||||
className: 'dialog'
|
className: 'dialog'
|
||||||
|
|
||||||
$.add Header.hover, qp
|
$.add Header.hover, qp
|
||||||
Get.postClone boardID, threadID, postID, qp, Get.contextFromNode @
|
new Fetcher boardID, threadID, postID, qp, Get.contextFromNode @
|
||||||
|
|
||||||
UI.hover
|
UI.hover
|
||||||
root: @
|
root: @
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user