274 lines
6.8 KiB
CoffeeScript
274 lines
6.8 KiB
CoffeeScript
Navigate =
|
|
init: ->
|
|
return if g.VIEW is 'catalog' or g.BOARD.ID is 'f'
|
|
$.on window, 'popstate', Navigate.popstate
|
|
|
|
Thread.callbacks.push
|
|
name: 'Navigate'
|
|
cb: @thread
|
|
|
|
Post.callbacks.push
|
|
name: 'Navigate'
|
|
cb: @post
|
|
|
|
thread: ->
|
|
return if g.VIEW is 'thread' # The reply link only exist in index view
|
|
replyLink = $ 'a.replylink', @OP.nodes.info
|
|
$.on replyLink, 'click', Navigate.navigate
|
|
|
|
post: ->
|
|
# We don't need to reload the thread inside the thread
|
|
return if g.VIEW is 'thread' and not @isClone
|
|
postLink = $ 'a[title="Highlight this post"]', @nodes.info
|
|
$.on postLink, 'click', Navigate.navigate
|
|
|
|
clean: ->
|
|
{posts, threads} = g
|
|
|
|
# Garbage collection
|
|
g.posts = {}
|
|
g.threads = {}
|
|
g.BOARD.posts = {}
|
|
g.BOARD.threads = {}
|
|
|
|
# Delete nodes
|
|
$.rmAll $ '.board'
|
|
|
|
threadFeatures: [
|
|
['Unread Count', Unread]
|
|
['Quote Threading', QuoteThreading]
|
|
['Thread Stats', ThreadStats]
|
|
['Thread Updater', ThreadUpdater]
|
|
['Thread Expansion', ExpandThread]
|
|
]
|
|
|
|
disconnect: ->
|
|
features = if g.VIEW is 'thread'
|
|
Navigate.threadFeatures
|
|
else
|
|
[]
|
|
|
|
for [name, feature] in features
|
|
try
|
|
feature.disconnect()
|
|
catch err
|
|
errors = [] unless errors
|
|
errors.push
|
|
message: "Failed to disconnect feature #{name}."
|
|
error: err
|
|
|
|
Main.handleErrors errors if errors
|
|
|
|
return
|
|
|
|
reconnect: ->
|
|
features = if g.VIEW is 'thread'
|
|
Navigate.threadFeatures
|
|
else
|
|
[]
|
|
|
|
for [name, feature] in features
|
|
try
|
|
feature.init()
|
|
catch err
|
|
errors = [] unless errors
|
|
errors.push
|
|
message: "Failed to reconnect feature #{name}."
|
|
error: err
|
|
|
|
Main.handleErrors errors if errors
|
|
|
|
return
|
|
|
|
ready: ->
|
|
features = [
|
|
['Unread Count', Unread, Conf['Unread Count']]
|
|
['Quote Threading', QuoteThreading, Conf['Quote Threading'] and not Conf['Unread Count']]
|
|
]
|
|
|
|
for [name, feature, condition] in features
|
|
try
|
|
feature.ready() if condition
|
|
catch err
|
|
errors = [] unless errors
|
|
errors.push
|
|
message: "Failed to reconnect feature #{name}."
|
|
error: err
|
|
|
|
Main.handleErrors errors if errors
|
|
QR.generatePostableThreadsList()
|
|
|
|
updateContext: (view) ->
|
|
$.rmClass doc, g.VIEW
|
|
$.addClass doc, view
|
|
g.VIEW = view
|
|
|
|
switch view
|
|
when 'index'
|
|
QR.link.textContent = 'Start a Thread'
|
|
$.off d, 'ThreadUpdate', QR.statusCheck
|
|
$.on d, 'indexRefresh', QR.generatePostableThreadsList
|
|
when 'thread'
|
|
QR.link.textContent = 'Reply to Thread'
|
|
$.on d, 'ThreadUpdate', QR.statusCheck
|
|
$.off d, 'IndexRefresh', QR.generatePostableThreadsList
|
|
|
|
updateBoard: (boardID) ->
|
|
g.BOARD = new Board boardID
|
|
|
|
req = null
|
|
|
|
onload = (e) ->
|
|
if e.type is 'abort'
|
|
req.onloadend = null
|
|
return
|
|
|
|
return unless req.status is 200
|
|
|
|
try
|
|
for board in JSON.parse(req.response).boards
|
|
return Navigate.updateTitle board if board.board is boardID
|
|
|
|
catch err
|
|
Main.handleErrors [
|
|
message: "Navigation failed to update board name."
|
|
error: err
|
|
]
|
|
|
|
Header.setBoardList()
|
|
|
|
req = $.ajax '//a.4cdn.org/boards.json',
|
|
onabort: onload
|
|
onloadend: onload
|
|
|
|
updateTitle: ({board, title}) ->
|
|
$.rm subtitle if subtitle = $ '.boardSubtitle'
|
|
$('.boardTitle').textContent = d.title = "/#{board}/ - #{title}"
|
|
|
|
navigate: (e) ->
|
|
return if @hostname isnt 'boards.4chan.org' or window.location.hostname is 'rs.4chan.org'
|
|
|
|
path = @pathname.split '/'
|
|
hash = @hash
|
|
path.shift() if path[0] is ''
|
|
[boardID, view, threadID] = path
|
|
|
|
return if view is 'catalog' or 'f' in [boardID, g.BOARD.ID]
|
|
|
|
e.preventDefault() if e
|
|
history.pushState null, '', @pathname unless @id is 'popState'
|
|
|
|
view = if threadID
|
|
'thread'
|
|
else
|
|
view or 'index' # path is "/boardID/". See the problem?
|
|
|
|
if view isnt g.VIEW
|
|
Navigate.disconnect()
|
|
Navigate.clean()
|
|
Navigate.updateContext view
|
|
Navigate.reconnect()
|
|
|
|
if view is 'index'
|
|
if boardID is g.BOARD.ID
|
|
d.title = $('.boardTitle').textContent
|
|
else
|
|
Navigate.updateBoard boardID
|
|
Index.update()
|
|
|
|
# Moving from index to thread or thread to thread
|
|
else
|
|
onload = (e) -> Navigate.load e, hash
|
|
Navigate.req = $.ajax "//a.4cdn.org/#{boardID}/res/#{threadID}.json",
|
|
onabort: onload
|
|
onloadend: onload
|
|
|
|
setTimeout (->
|
|
if Navigate.req and !Navigate.notice
|
|
Navigate.notice = new Notice 'info', 'Loading thread...'
|
|
), 3 * $.SECOND
|
|
|
|
# Navigate.refresh {boardID, view, threadID}
|
|
|
|
load: (e) ->
|
|
$.rmClass Index.button, 'fa-spin'
|
|
{req, notice} = Navigate
|
|
delete Navigate.req
|
|
delete Navigate.notice
|
|
|
|
if e.type is 'abort'
|
|
req.onloadend = null
|
|
return
|
|
|
|
try
|
|
if req.status is 200
|
|
Navigate.parse JSON.parse(req.response).posts
|
|
catch err
|
|
console.error 'Navigate failure:'
|
|
console.log err
|
|
# network error or non-JSON content for example.
|
|
if notice
|
|
notice.setType 'error'
|
|
notice.el.lastElementChild.textContent = 'Navigation Failed.'
|
|
setTimeout notice.close, 2 * $.SECOND
|
|
else
|
|
new Notice 'error', 'Navigation Failed.', 2
|
|
return
|
|
|
|
parse: (data) ->
|
|
board = g.BOARD
|
|
threadRoot = Build.thread board, OP = data.shift(), true
|
|
thread = new Thread OP.no, board
|
|
|
|
nodes = [threadRoot]
|
|
posts = []
|
|
errors = null
|
|
|
|
makePost = (postNode) ->
|
|
try
|
|
posts.push new Post postNode, thread, board
|
|
catch err
|
|
# Skip posts that we failed to parse.
|
|
errors = [] unless errors
|
|
errors.push
|
|
message: "Parsing of Post No.#{thread.ID} failed. Post will be skipped."
|
|
error: err
|
|
|
|
makePost $('.opContainer', threadRoot)
|
|
|
|
for obj in data
|
|
nodes.push post = Build.postFromObject obj, board
|
|
makePost post
|
|
|
|
Main.handleErrors errors if errors
|
|
|
|
# Add the thread to a container to make sure all features work.
|
|
$.nodes Navigate.nodes = nodes
|
|
Main.callbackNodes Thread, [thread]
|
|
Main.callbackNodes Post, posts
|
|
|
|
Navigate.ready()
|
|
|
|
Navigate.buildThread()
|
|
Header.scrollToIfNeeded $ '.board'
|
|
|
|
buildThread: ->
|
|
board = $ '.board'
|
|
$.rmAll board
|
|
$.add board, Navigate.nodes
|
|
|
|
popstate: -> <% if (type === 'crx') { %> Navigate.popstate = -> <% } %> # blink/webkit throw a popstate on page load. Not what we want.
|
|
a = $.el 'a',
|
|
href: window.location
|
|
id: 'popState'
|
|
|
|
Navigate.navigate.call a
|
|
|
|
refresh: (context) ->
|
|
return
|
|
{boardID, view, threadID} = context
|
|
|
|
# Refresh features
|
|
feature.refresh() for [name, feature] in Main.features when feature.refresh
|
|
return
|