Introduce Header.{scrollToIfNeeded,getTopOf,getBottomOf}() and use them.
4chan X - now with proper bottom header support.
This commit is contained in:
parent
54eaa9adea
commit
81a2b096a1
@ -247,12 +247,28 @@ Header =
|
|||||||
return unless /^p\d+$/.test(hash) and post = $.id hash
|
return unless /^p\d+$/.test(hash) and post = $.id hash
|
||||||
return if (Get.postFromRoot post).isHidden
|
return if (Get.postFromRoot post).isHidden
|
||||||
Header.scrollTo post
|
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()
|
{top} = root.getBoundingClientRect()
|
||||||
unless Conf['Bottom header']
|
unless Conf['Bottom header']
|
||||||
headRect = Header.toggle.getBoundingClientRect()
|
headRect = Header.toggle.getBoundingClientRect()
|
||||||
top -= headRect.top + headRect.height
|
top -= headRect.top + headRect.height
|
||||||
window.scrollBy 0, top
|
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) ->
|
addShortcut: (el, index) ->
|
||||||
shortcut = $.el 'span',
|
shortcut = $.el 'span',
|
||||||
|
|||||||
@ -50,7 +50,7 @@ Index =
|
|||||||
className: 'pagelist'
|
className: 'pagelist'
|
||||||
hidden: true
|
hidden: true
|
||||||
innerHTML: <%= importHTML('General/Index-pagelist') %>
|
innerHTML: <%= importHTML('General/Index-pagelist') %>
|
||||||
Index.currentPage = Index.getCurrentPage()
|
@currentPage = @getCurrentPage()
|
||||||
$.on window, 'popstate', @cb.popstate
|
$.on window, 'popstate', @cb.popstate
|
||||||
$.on @pagelist, 'click', @cb.pageNav
|
$.on @pagelist, 'click', @cb.pageNav
|
||||||
$.asap (-> $('.pagelist', doc) or d.readyState isnt 'loading'), ->
|
$.asap (-> $('.pagelist', doc) or d.readyState isnt 'loading'), ->
|
||||||
@ -81,7 +81,7 @@ Index =
|
|||||||
Index.pageNav +a.pathname.split('/')[2]
|
Index.pageNav +a.pathname.split('/')[2]
|
||||||
|
|
||||||
scrollToIndex: ->
|
scrollToIndex: ->
|
||||||
Header.scrollTo Index.root if Index.root.getBoundingClientRect().top < 0
|
Header.scrollToIfNeeded Index.root
|
||||||
|
|
||||||
getCurrentPage: ->
|
getCurrentPage: ->
|
||||||
+window.location.pathname.split('/')[2]
|
+window.location.pathname.split('/')[2]
|
||||||
|
|||||||
@ -45,7 +45,7 @@ ImageExpand =
|
|||||||
continue unless file and file.isImage and doc.contains post.nodes.root
|
continue unless file and file.isImage and doc.contains post.nodes.root
|
||||||
if ImageExpand.on and
|
if ImageExpand.on and
|
||||||
(!Conf['Expand spoilers'] and file.isSpoiler or
|
(!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
|
continue
|
||||||
$.queueTask func, post
|
$.queueTask func, post
|
||||||
return
|
return
|
||||||
@ -60,13 +60,10 @@ ImageExpand =
|
|||||||
|
|
||||||
# Scroll back to the thumbnail when contracting the image
|
# Scroll back to the thumbnail when contracting the image
|
||||||
# to avoid being left miles away from the relevant post.
|
# to avoid being left miles away from the relevant post.
|
||||||
rect = post.nodes.root.getBoundingClientRect()
|
top = Header.getTopOf post.nodes.root
|
||||||
if rect.top < 0
|
if top < 0
|
||||||
y = rect.top
|
y = top
|
||||||
unless Conf['Bottom header']
|
if post.nodes.root.getBoundingClientRect().left < 0
|
||||||
headRect = Header.toggle.getBoundingClientRect()
|
|
||||||
y -= headRect.top + headRect.height
|
|
||||||
if rect.left < 0
|
|
||||||
x = -window.scrollX
|
x = -window.scrollX
|
||||||
window.scrollBy x, y if x or y
|
window.scrollBy x, y if x or y
|
||||||
ImageExpand.contract post
|
ImageExpand.contract post
|
||||||
@ -104,13 +101,12 @@ ImageExpand =
|
|||||||
$.addClass post.nodes.root, 'expanded-image'
|
$.addClass post.nodes.root, 'expanded-image'
|
||||||
$.rmClass post.file.thumb, 'expanding'
|
$.rmClass post.file.thumb, 'expanding'
|
||||||
return
|
return
|
||||||
prev = post.nodes.root.getBoundingClientRect()
|
{bottom} = post.nodes.root.getBoundingClientRect()
|
||||||
$.queueTask ->
|
$.queueTask ->
|
||||||
$.addClass post.nodes.root, 'expanded-image'
|
$.addClass post.nodes.root, 'expanded-image'
|
||||||
$.rmClass post.file.thumb, 'expanding'
|
$.rmClass post.file.thumb, 'expanding'
|
||||||
return unless prev.top + prev.height <= 0
|
return unless bottom <= 0
|
||||||
curr = post.nodes.root.getBoundingClientRect()
|
window.scrollBy 0, post.nodes.root.getBoundingClientRect().bottom - bottom
|
||||||
window.scrollBy 0, curr.height - prev.height + curr.top - prev.top
|
|
||||||
|
|
||||||
error: ->
|
error: ->
|
||||||
post = Get.postFromNode @
|
post = Get.postFromNode @
|
||||||
|
|||||||
@ -183,43 +183,31 @@ Keybinds =
|
|||||||
location.href = url
|
location.href = url
|
||||||
|
|
||||||
hl: (delta, thread) ->
|
hl: (delta, thread) ->
|
||||||
|
postEl = $ '.reply.highlight', thread
|
||||||
|
|
||||||
unless delta
|
unless delta
|
||||||
if postEl = $ '.reply.highlight', thread
|
$.rmClass postEl, 'highlight' if postEl
|
||||||
$.rmClass postEl, 'highlight'
|
|
||||||
return
|
return
|
||||||
if Conf['Bottom header']
|
|
||||||
topMargin = 0
|
if postEl
|
||||||
else
|
{height} = postEl.getBoundingClientRect()
|
||||||
headRect = Header.toggle.getBoundingClientRect()
|
if Header.getTopOf(postEl) >= -height and Header.getBottomOf(postEl) >= -height # We're at least partially visible
|
||||||
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
|
|
||||||
root = postEl.parentNode
|
root = postEl.parentNode
|
||||||
axe = if delta is +1
|
axe = if delta is +1
|
||||||
'following'
|
'following'
|
||||||
else
|
else
|
||||||
'preceding'
|
'preceding'
|
||||||
next = $.x "#{axe}-sibling::div[contains(@class,'replyContainer')][1]/child::div[contains(@class,'reply')]", root
|
return unless next = $.x "#{axe}-sibling::div[contains(@class,'replyContainer')][1]/child::div[contains(@class,'reply')]", root
|
||||||
unless next
|
Header.scrollToIfNeeded next, delta is +1
|
||||||
@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
|
|
||||||
@focus next
|
@focus next
|
||||||
|
$.rmClass postEl, 'highlight'
|
||||||
return
|
return
|
||||||
|
$.rmClass postEl, 'highlight'
|
||||||
|
|
||||||
replies = $$ '.reply', thread
|
replies = $$ '.reply', thread
|
||||||
replies.reverse() if delta is -1
|
replies.reverse() if delta is -1
|
||||||
for reply in replies
|
for reply in replies
|
||||||
rect = reply.getBoundingClientRect()
|
if delta is +1 and Header.getTopOf(reply) > 0 or delta is -1 and Header.getBottomOf(reply) > 0
|
||||||
if delta is +1 and rect.top >= topMargin or delta is -1 and rect.bottom <= doc.clientHeight
|
|
||||||
@focus reply
|
@focus reply
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@ -38,29 +38,24 @@ Nav =
|
|||||||
else
|
else
|
||||||
Nav.scroll +1
|
Nav.scroll +1
|
||||||
|
|
||||||
getThread: (full) ->
|
getThread: ->
|
||||||
if Conf['Bottom header']
|
for threadRoot in $$ '.thread'
|
||||||
topMargin = 0
|
thread = Get.threadFromRoot threadRoot
|
||||||
else
|
continue if thread.isHidden and !thread.stub
|
||||||
headRect = Header.toggle.getBoundingClientRect()
|
if Header.getTopOf(threadRoot) >= -threadRoot.getBoundingClientRect().height # not scrolled past
|
||||||
topMargin = headRect.top + headRect.height
|
return threadRoot
|
||||||
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
|
|
||||||
return $ '.board'
|
return $ '.board'
|
||||||
|
|
||||||
scroll: (delta) ->
|
scroll: (delta) ->
|
||||||
[threads, thread, i, rect, topMargin] = Nav.getThread true
|
thread = Nav.getThread()
|
||||||
top = rect.top - topMargin
|
axe = if delta is +1
|
||||||
|
'following'
|
||||||
# unless we're not at the beginning of the current thread
|
else
|
||||||
# (and thus wanting to move to beginning)
|
'preceding'
|
||||||
# or we're above the first thread and don't want to skip it
|
if next = $.x "#{axe}-sibling::div[contains(@class,'thread')][1]", thread
|
||||||
if (delta is -1 and top > -5) or (delta is +1 and top < 5)
|
# Unless we're not at the beginning of the current thread,
|
||||||
top = threads[i + delta]?.getBoundingClientRect().top - topMargin
|
# and thus wanting to move to beginning,
|
||||||
|
# or we're above the first thread and don't want to skip it.
|
||||||
window.scrollBy 0, top
|
top = Header.getTopOf thread
|
||||||
|
thread = next if delta is +1 and top < 5 or delta is -1 and top > -5
|
||||||
|
Header.scrollTo thread
|
||||||
|
|||||||
@ -246,8 +246,7 @@ ThreadUpdater =
|
|||||||
ThreadUpdater.lastPost = posts[count - 1].ID
|
ThreadUpdater.lastPost = posts[count - 1].ID
|
||||||
Main.callbackNodes Post, posts
|
Main.callbackNodes Post, posts
|
||||||
|
|
||||||
scroll = Conf['Auto Scroll'] and ThreadUpdater.scrollBG() and
|
scroll = Conf['Auto Scroll'] and ThreadUpdater.scrollBG() and Header.getBottomOf(ThreadUpdater.root) > -25
|
||||||
ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25
|
|
||||||
$.add ThreadUpdater.root, nodes
|
$.add ThreadUpdater.root, nodes
|
||||||
sendEvent()
|
sendEvent()
|
||||||
if scroll
|
if scroll
|
||||||
|
|||||||
@ -42,18 +42,16 @@ Unread =
|
|||||||
while root = $.x 'preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root
|
while root = $.x 'preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root
|
||||||
break unless (post = Get.postFromRoot root).isHidden
|
break unless (post = Get.postFromRoot root).isHidden
|
||||||
return unless root
|
return unless root
|
||||||
onload = -> root.scrollIntoView false if checkPosition root
|
down = true
|
||||||
else
|
else
|
||||||
# Scroll to the last read post.
|
# Scroll to the last read post.
|
||||||
posts = Object.keys Unread.thread.posts
|
posts = Object.keys Unread.thread.posts
|
||||||
{root} = Unread.thread.posts[posts[posts.length - 1]].nodes
|
{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
|
# Prevent the browser to scroll back to
|
||||||
# the previous scroll location on page load.
|
# 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: ->
|
sync: ->
|
||||||
lastReadPost = Unread.db.get
|
lastReadPost = Unread.db.get
|
||||||
@ -102,7 +100,7 @@ Unread =
|
|||||||
body: post.info.comment
|
body: post.info.comment
|
||||||
icon: Favicon.logo
|
icon: Favicon.logo
|
||||||
notif.onclick = ->
|
notif.onclick = ->
|
||||||
Header.scrollTo post.nodes.root
|
Header.scrollToIfNeeded post.nodes.root, true
|
||||||
window.focus()
|
window.focus()
|
||||||
notif.onshow = ->
|
notif.onshow = ->
|
||||||
setTimeout ->
|
setTimeout ->
|
||||||
@ -132,9 +130,8 @@ Unread =
|
|||||||
|
|
||||||
read: (e) ->
|
read: (e) ->
|
||||||
return if d.hidden or !Unread.posts.length
|
return if d.hidden or !Unread.posts.length
|
||||||
height = doc.clientHeight
|
|
||||||
for post, i in Unread.posts
|
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
|
return unless i
|
||||||
|
|
||||||
Unread.lastReadPost = Unread.posts.splice(0, i)[i - 1].ID
|
Unread.lastReadPost = Unread.posts.splice(0, i)[i - 1].ID
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user