* Fix duplicate comment on pessimistic creation - comment creation checks for comment's ID existence in cache - invoice.confirmedAt included in useCanEdit deps for anons live comments * switch to some as sets are not worth it * only check for duplicates if a pessimistic payment method has been used * default to empty array * add comment about side-effects * record ownership of an item to avoid injecting it via live comments * trigger check only if the incoming comment is ours, cleanup * correct conditions, correct comments, light cleanup * fix: add defensive condition to ownership recorder, better name * refactor: unified comment injection logic with deduplication, useCommentsView hook; revert sessionStorage-based fix * adjust live comments naming around the codebase * listen for hmac presence for anon edits * always return the injected comment createdAt to bump live comments * refactor: improve live comments hook readability - latest comment createdAt persistence helper - preserveScroll returns the returning value of the callback - compact conditional logic - refresh code comments - refresh naming - group constants - reorder imports * flat comment injection, fetch flat comments instead of the entire subtree that would've been deduplicated anyway, cleanup * always align new comment fragment to the comments query structure * generic useCommentsView hook * update comment counts if live injecting into fragments without comments field * fix: pass parentId, if a comment has a top level parent it always has the comments field * fix: update CommentsViewAt only if we actually injected a comment into cache * correct injectComment result usage * pass markViewedAt to further centralize side effects, remove live from Item server typedefs * fix: don't update counts for ancestors that are already up to date, update commentsViewedAt per batch not per comment * port: fix coalesce, useCommentsView hook and outline changes * update hmac field in cache on paid invoice, hmac as useCanEdit effect dependency * comments and light cleanup, update useCommentsView * efficient hasComments logic for live comments, establish a gql fragment * fix: typo on topLevel evaluation * limit extra evaluations to live comments scenarios * update comments * support live comments ncomments increments for anon view tracking
53 lines
1.7 KiB
JavaScript
53 lines
1.7 KiB
JavaScript
export default function preserveScroll (callback) {
|
|
// preserve the actual scroll position
|
|
const scrollTop = window.scrollY
|
|
|
|
// if the scroll position is at the top, we don't need to preserve it, just call the callback
|
|
if (scrollTop <= 0) {
|
|
return callback()
|
|
}
|
|
|
|
// get a reference element at the center of the viewport to track if content is added above it
|
|
const ref = document.elementFromPoint(window.innerWidth / 2, window.innerHeight / 2)
|
|
const refTop = ref ? ref.getBoundingClientRect().top + scrollTop : scrollTop
|
|
|
|
// observe the document for changes in height
|
|
const observer = new window.MutationObserver(() => {
|
|
// request animation frame to ensure the DOM is updated
|
|
window.requestAnimationFrame(() => {
|
|
// we can't proceed if we couldn't find a traceable reference element
|
|
if (!ref) {
|
|
cleanup()
|
|
return
|
|
}
|
|
|
|
// get the new position of the reference element along with the new scroll position
|
|
const newRefTop = ref ? ref.getBoundingClientRect().top + window.scrollY : window.scrollY
|
|
// has the reference element moved?
|
|
const refMoved = newRefTop - refTop
|
|
|
|
// if the reference element moved, we need to scroll to the new position
|
|
if (refMoved > 0) {
|
|
window.scrollTo({
|
|
// some browsers don't respond well to fractional scroll position, so we round up the new position to the nearest integer
|
|
top: scrollTop + Math.ceil(refMoved),
|
|
behavior: 'instant'
|
|
})
|
|
}
|
|
|
|
cleanup()
|
|
})
|
|
})
|
|
|
|
const timeout = setTimeout(() => cleanup(), 1000) // fallback
|
|
|
|
function cleanup () {
|
|
clearTimeout(timeout)
|
|
observer.disconnect()
|
|
}
|
|
|
|
observer.observe(document.body, { childList: true, subtree: true })
|
|
|
|
return callback()
|
|
}
|