Introduce Header.{scrollToIfNeeded,getTopOf,getBottomOf}() and use them.

4chan X - now with proper bottom header support.
This commit is contained in:
Mayhem 2013-11-03 01:27:23 +01:00
parent 54eaa9adea
commit 81a2b096a1
7 changed files with 66 additions and 75 deletions

View File

@ -247,12 +247,28 @@ Header =
return unless /^p\d+$/.test(hash) and post = $.id hash
return if (Get.postFromRoot post).isHidden
Header.scrollTo post
scrollTo: (root) ->
scrollTo: (root, down, needed) ->
if down
x = Header.getBottomOf root
window.scrollBy 0, -x unless needed and x >= 0
else
x = Header.getTopOf root
window.scrollBy 0, x unless needed and x >= 0
scrollToIfNeeded: (root, down) ->
Header.scrollTo root, down, true
getTopOf: (root) ->
{top} = root.getBoundingClientRect()
unless Conf['Bottom header']
headRect = Header.toggle.getBoundingClientRect()
top -= headRect.top + headRect.height
window.scrollBy 0, top
top -= headRect.top + headRect.height
top
getBottomOf: (root) ->
{clientHeight} = doc
bottom = clientHeight - root.getBoundingClientRect().bottom
if Conf['Bottom header']
headRect = Header.toggle.getBoundingClientRect()
bottom -= clientHeight - headRect.bottom + headRect.height
bottom
addShortcut: (el, index) ->
shortcut = $.el 'span',

View File

@ -50,7 +50,7 @@ Index =
className: 'pagelist'
hidden: true
innerHTML: <%= importHTML('General/Index-pagelist') %>
Index.currentPage = Index.getCurrentPage()
@currentPage = @getCurrentPage()
$.on window, 'popstate', @cb.popstate
$.on @pagelist, 'click', @cb.pageNav
$.asap (-> $('.pagelist', doc) or d.readyState isnt 'loading'), ->
@ -81,7 +81,7 @@ Index =
Index.pageNav +a.pathname.split('/')[2]
scrollToIndex: ->
Header.scrollTo Index.root if Index.root.getBoundingClientRect().top < 0
Header.scrollToIfNeeded Index.root
getCurrentPage: ->
+window.location.pathname.split('/')[2]

View File

@ -45,7 +45,7 @@ ImageExpand =
continue unless file and file.isImage and doc.contains post.nodes.root
if ImageExpand.on and
(!Conf['Expand spoilers'] and file.isSpoiler or
Conf['Expand from here'] and file.thumb.getBoundingClientRect().top < 0)
Conf['Expand from here'] and Header.getTopOf(file.thumb) < 0)
continue
$.queueTask func, post
return
@ -60,13 +60,10 @@ ImageExpand =
# Scroll back to the thumbnail when contracting the image
# to avoid being left miles away from the relevant post.
rect = post.nodes.root.getBoundingClientRect()
if rect.top < 0
y = rect.top
unless Conf['Bottom header']
headRect = Header.toggle.getBoundingClientRect()
y -= headRect.top + headRect.height
if rect.left < 0
top = Header.getTopOf post.nodes.root
if top < 0
y = top
if post.nodes.root.getBoundingClientRect().left < 0
x = -window.scrollX
window.scrollBy x, y if x or y
ImageExpand.contract post
@ -104,13 +101,12 @@ ImageExpand =
$.addClass post.nodes.root, 'expanded-image'
$.rmClass post.file.thumb, 'expanding'
return
prev = post.nodes.root.getBoundingClientRect()
{bottom} = post.nodes.root.getBoundingClientRect()
$.queueTask ->
$.addClass post.nodes.root, 'expanded-image'
$.rmClass post.file.thumb, 'expanding'
return unless prev.top + prev.height <= 0
curr = post.nodes.root.getBoundingClientRect()
window.scrollBy 0, curr.height - prev.height + curr.top - prev.top
return unless bottom <= 0
window.scrollBy 0, post.nodes.root.getBoundingClientRect().bottom - bottom
error: ->
post = Get.postFromNode @

View File

@ -183,43 +183,31 @@ Keybinds =
location.href = url
hl: (delta, thread) ->
postEl = $ '.reply.highlight', thread
unless delta
if postEl = $ '.reply.highlight', thread
$.rmClass postEl, 'highlight'
$.rmClass postEl, 'highlight' if postEl
return
if Conf['Bottom header']
topMargin = 0
else
headRect = Header.toggle.getBoundingClientRect()
topMargin = headRect.top + headRect.height
if postEl = $ '.reply.highlight', thread
$.rmClass postEl, 'highlight'
rect = postEl.getBoundingClientRect()
if rect.bottom >= topMargin and rect.top <= doc.clientHeight # We're at least partially visible
if postEl
{height} = postEl.getBoundingClientRect()
if Header.getTopOf(postEl) >= -height and Header.getBottomOf(postEl) >= -height # We're at least partially visible
root = postEl.parentNode
axe = if delta is +1
'following'
else
'preceding'
next = $.x "#{axe}-sibling::div[contains(@class,'replyContainer')][1]/child::div[contains(@class,'reply')]", root
unless next
@focus postEl
return
return unless g.VIEW is 'thread' or $.x('ancestor::div[parent::div[@class="board"]]', next) is thread
rect = next.getBoundingClientRect()
if rect.top < 0 or rect.bottom > doc.clientHeight
if delta is -1
window.scrollBy 0, rect.top - topMargin
else
next.scrollIntoView false
return unless next = $.x "#{axe}-sibling::div[contains(@class,'replyContainer')][1]/child::div[contains(@class,'reply')]", root
Header.scrollToIfNeeded next, delta is +1
@focus next
$.rmClass postEl, 'highlight'
return
$.rmClass postEl, 'highlight'
replies = $$ '.reply', thread
replies.reverse() if delta is -1
for reply in replies
rect = reply.getBoundingClientRect()
if delta is +1 and rect.top >= topMargin or delta is -1 and rect.bottom <= doc.clientHeight
if delta is +1 and Header.getTopOf(reply) > 0 or delta is -1 and Header.getBottomOf(reply) > 0
@focus reply
return

View File

@ -38,29 +38,24 @@ Nav =
else
Nav.scroll +1
getThread: (full) ->
if Conf['Bottom header']
topMargin = 0
else
headRect = Header.toggle.getBoundingClientRect()
topMargin = headRect.top + headRect.height
threads = $$('.thread').filter (thread) ->
thread = Get.threadFromRoot thread
!(thread.isHidden and !thread.stub)
for thread, i in threads
rect = thread.getBoundingClientRect()
if rect.bottom > topMargin # not scrolled past
return if full then [threads, thread, i, rect, topMargin] else thread
getThread: ->
for threadRoot in $$ '.thread'
thread = Get.threadFromRoot threadRoot
continue if thread.isHidden and !thread.stub
if Header.getTopOf(threadRoot) >= -threadRoot.getBoundingClientRect().height # not scrolled past
return threadRoot
return $ '.board'
scroll: (delta) ->
[threads, thread, i, rect, topMargin] = Nav.getThread true
top = rect.top - topMargin
# unless we're not at the beginning of the current thread
# (and thus wanting to move to beginning)
# or we're above the first thread and don't want to skip it
if (delta is -1 and top > -5) or (delta is +1 and top < 5)
top = threads[i + delta]?.getBoundingClientRect().top - topMargin
window.scrollBy 0, top
thread = Nav.getThread()
axe = if delta is +1
'following'
else
'preceding'
if next = $.x "#{axe}-sibling::div[contains(@class,'thread')][1]", thread
# Unless we're not at the beginning of the current thread,
# and thus wanting to move to beginning,
# or we're above the first thread and don't want to skip it.
top = Header.getTopOf thread
thread = next if delta is +1 and top < 5 or delta is -1 and top > -5
Header.scrollTo thread

View File

@ -246,8 +246,7 @@ ThreadUpdater =
ThreadUpdater.lastPost = posts[count - 1].ID
Main.callbackNodes Post, posts
scroll = Conf['Auto Scroll'] and ThreadUpdater.scrollBG() and
ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25
scroll = Conf['Auto Scroll'] and ThreadUpdater.scrollBG() and Header.getBottomOf(ThreadUpdater.root) > -25
$.add ThreadUpdater.root, nodes
sendEvent()
if scroll

View File

@ -42,18 +42,16 @@ Unread =
while root = $.x 'preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root
break unless (post = Get.postFromRoot root).isHidden
return unless root
onload = -> root.scrollIntoView false if checkPosition root
down = true
else
# Scroll to the last read post.
posts = Object.keys Unread.thread.posts
{root} = Unread.thread.posts[posts[posts.length - 1]].nodes
onload = -> Header.scrollTo root if checkPosition root
checkPosition = (target) ->
# Scroll to the target unless we scrolled past it.
target.getBoundingClientRect().bottom > doc.clientHeight
# Prevent the browser to scroll back to
# the previous scroll location on page load.
$.on window, 'load', onload
$.on window, 'load', ->
# Scroll to the target unless we scrolled past it.
Header.scrollTo root, down if Header.getBottomOf(root) < 0
sync: ->
lastReadPost = Unread.db.get
@ -102,7 +100,7 @@ Unread =
body: post.info.comment
icon: Favicon.logo
notif.onclick = ->
Header.scrollTo post.nodes.root
Header.scrollToIfNeeded post.nodes.root, true
window.focus()
notif.onshow = ->
setTimeout ->
@ -132,9 +130,8 @@ Unread =
read: (e) ->
return if d.hidden or !Unread.posts.length
height = doc.clientHeight
for post, i in Unread.posts
break if post.nodes.root.getBoundingClientRect().bottom > height # post is not completely read
break if Header.getBottomOf(post.nodes.root) <= 0 # post is not completely read
return unless i
Unread.lastReadPost = Unread.posts.splice(0, i)[i - 1].ID