comment, cleanup and improve autoresize/autoscroll

This commit is contained in:
Henry Jameson 2019-09-25 19:30:55 +03:00
parent 0f55359b49
commit 0d6a9f5a62
2 changed files with 50 additions and 36 deletions

View file

@ -277,6 +277,8 @@ const PostStatusForm = {
resize (e) { resize (e) {
const target = e.target || e const target = e.target || e
if (!(target instanceof window.Element)) { return } if (!(target instanceof window.Element)) { return }
// Reset to default height for empty form, nothing else to do here.
if (target.value === '') { if (target.value === '') {
target.style.height = null target.style.height = null
this.$refs['emoji-input'].resize() this.$refs['emoji-input'].resize()
@ -284,61 +286,74 @@ const PostStatusForm = {
} }
const rootRef = this.$refs['root'] const rootRef = this.$refs['root']
const scroller = this.$el.closest('.sidebar-scroller') || /* Scroller is either `window` (replies in TL), sidebar (main post form,
* replies in notifs) or mobile post form. Note that getting and setting
* scroll is different for `Window` and `Element`s
*/
const scrollerRef = this.$el.closest('.sidebar-scroller') ||
this.$el.closest('.post-form-modal-view') || this.$el.closest('.post-form-modal-view') ||
window window
// Getting info about padding we have to account for, removing 'px' part
const topPaddingStr = window.getComputedStyle(target)['padding-top'] const topPaddingStr = window.getComputedStyle(target)['padding-top']
const bottomPaddingStr = window.getComputedStyle(target)['padding-bottom'] const bottomPaddingStr = window.getComputedStyle(target)['padding-bottom']
// Remove "px" at the end of the values
const topPadding = Number(topPaddingStr.substring(0, topPaddingStr.length - 2)) const topPadding = Number(topPaddingStr.substring(0, topPaddingStr.length - 2))
const bottomPadding = Number(bottomPaddingStr.substring(0, bottomPaddingStr.length - 2)) const bottomPadding = Number(bottomPaddingStr.substring(0, bottomPaddingStr.length - 2))
const vertPadding = topPadding + bottomPadding const vertPadding = topPadding + bottomPadding
const oldHeightStr = target.style.height || '' const oldHeightStr = target.style.height || ''
const oldHeight = Number(oldHeightStr.substring(0, oldHeightStr.length - 2)) const oldHeight = Number(oldHeightStr.substring(0, oldHeightStr.length - 2))
const tempScroll = scroller === window ? scroller.scrollY : scroller.scrollTop /* Explanation:
*
* https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight
* scrollHeight returns element's scrollable content height, i.e. visible
* element + overscrolled parts of it. We use it to determine when text
* inside the textarea exceeded its height, so we can set height to prevent
* overscroll, i.e. make textarea grow with the text. HOWEVER, since we
* explicitly set new height, scrollHeight won't go below that, so we can't
* SHRINK the textarea when there's extra space. To workaround that we set
* height to 'auto' which makes textarea tiny again, so that scrollHeight
* will match text height again. HOWEVER, shrinking textarea can screw with
* the scroll since there might be not enough padding around root to even
* varrant a scroll, so it will jump to 0 and refuse to move anywhere,
* so we check current scroll position before shrinking and then restore it
* with needed delta.
*/
// Auto is needed to make textbox shrink when removing lines // this part has to be BEFORE the content size update
target.style.height = 'auto' const currentScroll = scrollerRef === window
const newHeight = target.scrollHeight - vertPadding ? scrollerRef.scrollY
target.style.height = `${oldHeight}px` : scrollerRef.scrollTop
const scrollerHeight = scrollerRef === window
if (scroller === window) { ? scrollerRef.innerHeight
scroller.scroll(0, tempScroll) : scrollerRef.offsetHeight
} else {
scroller.scrollTop = tempScroll
}
const currentScroll = scroller === window ? scroller.scrollY : scroller.scrollTop
const scrollerHeight = scroller === window ? scroller.innerHeight : scroller.offsetHeight
const scrollerBottomBorder = currentScroll + scrollerHeight const scrollerBottomBorder = currentScroll + scrollerHeight
const rootBottomBorder = rootRef.offsetHeight + // BEGIN content size update
findOffset(rootRef, scroller).top target.style.height = 'auto'
const newHeight = target.scrollHeight - vertPadding
target.style.height = `${newHeight}px`
// END content size update
// We check where the bottom border of root element is, this uses findOffset
// to find offset relative to scrollable container (scroller)
const rootBottomBorder = rootRef.offsetHeight + findOffset(rootRef, scrollerRef).top
const textareaSizeChangeDelta = newHeight - oldHeight || 0 const textareaSizeChangeDelta = newHeight - oldHeight || 0
const rootChangeDelta = rootBottomBorder - scrollerBottomBorder + textareaSizeChangeDelta const isBottomObstructed = scrollerBottomBorder < rootBottomBorder
const rootChangeDelta = rootBottomBorder - scrollerBottomBorder
const totalDelta = textareaSizeChangeDelta +
(isBottomObstructed ? rootChangeDelta : 0)
// console.log('CURRENT SCROLL', currentScroll) const targetScroll = currentScroll + totalDelta
console.log('BOTTOM BORDERS', rootBottomBorder, scrollerBottomBorder)
console.log('BOTTOM DELTA', rootBottomBorder - scrollerBottomBorder) if (scrollerRef === window) {
const targetScroll = scrollerBottomBorder < rootBottomBorder scrollerRef.scroll(0, targetScroll)
? currentScroll + rootChangeDelta
: currentScroll + textareaSizeChangeDelta
if (scroller === window) {
scroller.scroll(0, targetScroll)
} else { } else {
scroller.scrollTop = targetScroll scrollerRef.scrollTop = targetScroll
} }
target.style.height = `${newHeight}px`
console.log(scroller, rootRef)
// console.log('SCROLL TO BUTTON', scrollerBottomBorder < rootBottomBorder)
// console.log('DELTA B', rootChangeDelta)
// console.log('DELTA D', textareaSizeChangeDelta)
// console.log('TARGET', targetScroll)
// console.log('ACTUAL', scroller.scrollTop || scroller.scrollY || 0)
this.$refs['emoji-input'].resize() this.$refs['emoji-input'].resize()
}, },
showEmojiPicker () { showEmojiPicker () {

View file

@ -9,7 +9,6 @@ export const findOffset = (child, parent, { top = 0, left = 0 } = {}, ignorePadd
result.left += ignorePadding ? 0 : leftPadding result.left += ignorePadding ? 0 : leftPadding
} }
console.log('eee', parent, child.offsetParent)
if (child.offsetParent && (parent === window || parent.contains(child.offsetParent) || parent === child.offsetParent)) { if (child.offsetParent && (parent === window || parent.contains(child.offsetParent) || parent === child.offsetParent)) {
return findOffset(child.offsetParent, parent, result, false) return findOffset(child.offsetParent, parent, result, false)
} else { } else {