diff --git a/app/assets/javascripts/diffs/components/sticky_viewport_filler_height.vue b/app/assets/javascripts/diffs/components/sticky_viewport_filler_height.vue index bc1252c45ea0014fa25c49e5e8ca202ae575e98c..a985ed974c95a6378c323db6498a60abfbe0155e 100644 --- a/app/assets/javascripts/diffs/components/sticky_viewport_filler_height.vue +++ b/app/assets/javascripts/diffs/components/sticky_viewport_filler_height.vue @@ -37,31 +37,36 @@ export default { // 6ms is enough to target 120fps default: 6, }, + getOffsetParent: { + type: Function, + required: false, + default() { + return this.$refs.root.parentElement; + }, + }, }, data() { return { visible: false, currentTop: 0, - parentRect: { bottom: 0, height: 0 }, + offsetParent: null, + offsetParentRect: { bottom: 0, height: 0 }, + offsetParentObserver: null, viewportHeight: 0, rootObserver: null, - parentObserver: null, }; }, computed: { - parent() { - return this.$refs.root.parentElement; - }, throttledSampleRects() { return throttle(this.sampleRects, this.samplingRate, { leading: true }); }, endReached() { - return this.viewportHeight > this.parentRect.bottom; + return this.viewportHeight > this.offsetParentRect.bottom; }, availableHeight() { // parent is fully scrolled, the sticky element is pushed from both top and bottom if (this.endReached) { - return this.parentRect.bottom - Math.max(this.currentTop, this.stickyTopOffset); + return this.offsetParentRect.bottom - Math.max(this.currentTop, this.stickyTopOffset); } return this.viewportHeight - this.currentTop - this.stickyBottomOffset; }, @@ -74,21 +79,22 @@ export default { visible(isVisible) { if (isVisible) { this.sampleRects(); - this.observerParentResize(); + this.observerOffsetParentResize(); this.observeViewportChanges(); } else { - this.disconnectParent(); + this.disconnectOffsetParent(); this.disconnectViewport(); } }, }, mounted() { + this.offsetParent = this.getOffsetParent(); this.observeRootVisibility(); this.cacheViewportHeight(); }, beforeDestroy() { this.disconnectRoot(); - this.disconnectParent(); + this.disconnectOffsetParent(); this.disconnectViewport(); }, methods: { @@ -99,9 +105,9 @@ export default { observeElementOnce(this.$refs.root, ([root]) => { this.currentTop = root.boundingClientRect.top; }); - observeElementOnce(this.parent, ([parent]) => { + observeElementOnce(this.offsetParent, ([parent]) => { const { bottom, height } = parent.boundingClientRect; - this.parentRect = { bottom, height }; + this.offsetParentRect = { bottom, height }; }); }, observeRootVisibility() { @@ -110,10 +116,10 @@ export default { }); this.rootObserver.observe(this.$refs.root); }, - observerParentResize() { + observerOffsetParentResize() { // parent could grow, we might no longer be at the bottom of the parent element - this.parentObserver = new ResizeObserver(throttle(this.sampleRects, 20)); - this.parentObserver.observe(this.parent); + this.offsetParentObserver = new ResizeObserver(throttle(this.sampleRects, 20)); + this.offsetParentObserver.observe(this.offsetParent); }, observeViewportChanges() { window.addEventListener('scroll', this.throttledSampleRects, { passive: true }); @@ -124,10 +130,10 @@ export default { this.rootObserver.disconnect(); this.rootObserver = null; }, - disconnectParent() { - if (!this.parentObserver) return; - this.parentObserver.disconnect(); - this.parentObserver = null; + disconnectOffsetParent() { + if (!this.offsetParentObserver) return; + this.offsetParentObserver.disconnect(); + this.offsetParentObserver = null; }, disconnectViewport() { this.throttledSampleRects.cancel(); diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue index 1ddd8bb834703497f3deb41ae350140148f903d1..92d4847755e1fa302e9a42d99b5e37e4ee1ea729 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -25,6 +25,7 @@ import { sanitize } from '~/lib/dompurify'; import { shouldDisableShortcuts } from '~/behaviors/shortcuts/shortcuts_toggle'; import { keysFor, ISSUABLE_EDIT_DESCRIPTION } from '~/behaviors/shortcuts/keybindings'; import ShortcutsWorkItems from '~/behaviors/shortcuts/shortcuts_work_items'; +import StickyViewportFillerHeight from '~/diffs/components/sticky_viewport_filler_height.vue'; import { i18n, WIDGET_TYPE_ASSIGNEES, @@ -110,6 +111,7 @@ export default { SHOW_SIDEBAR_STORAGE_KEY: 'work_item_show_sidebar', ENABLE_TRUNCATION_STORAGE_KEY: 'work_item_truncate_descriptions', components: { + StickyViewportFillerHeight, DesignDropzone, DesignWidget, DesignUploadButton, @@ -1145,6 +1147,7 @@ export default {