|
|
@ -15,8 +15,7 @@ export default class ScrollSaver { |
|
|
|
private scrollHeightMinusTop: number; |
|
|
|
private scrollHeightMinusTop: number; |
|
|
|
private scrollTop: number; |
|
|
|
private scrollTop: number; |
|
|
|
private clientHeight: number; |
|
|
|
private clientHeight: number; |
|
|
|
private anchor: HTMLElement; |
|
|
|
private elements: {element: HTMLElement, rect: DOMRect}[]; |
|
|
|
private rect: DOMRect; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* |
|
|
|
* |
|
|
@ -43,43 +42,50 @@ export default class ScrollSaver { |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public findAnchor() { |
|
|
|
public findElements() { |
|
|
|
const {container} = this; |
|
|
|
const {container} = this; |
|
|
|
const containerRect = container.getBoundingClientRect(); |
|
|
|
const containerRect = container.getBoundingClientRect(); |
|
|
|
const bubbles = Array.from(container.querySelectorAll(this.query)) as HTMLElement[]; |
|
|
|
const bubbles = Array.from(container.querySelectorAll(this.query)) as HTMLElement[]; |
|
|
|
let rect: DOMRect, anchor: HTMLElement; |
|
|
|
const elements: ScrollSaver['elements'] = []; |
|
|
|
for(const bubble of bubbles) { |
|
|
|
for(const bubble of bubbles) { |
|
|
|
const elementRect = bubble.getBoundingClientRect(); |
|
|
|
const elementRect = bubble.getBoundingClientRect(); |
|
|
|
const visibleRect = getVisibleRect(bubble, container, undefined, elementRect, containerRect); |
|
|
|
const visibleRect = getVisibleRect(bubble, container, undefined, elementRect, containerRect); |
|
|
|
if(visibleRect) { |
|
|
|
if(visibleRect) { |
|
|
|
rect = elementRect; |
|
|
|
elements.push({element: bubble, rect: elementRect}); |
|
|
|
anchor = bubble; |
|
|
|
|
|
|
|
// break; // find first
|
|
|
|
// break; // find first
|
|
|
|
} else if(anchor) { // find last
|
|
|
|
} else if(elements.length) { // find last
|
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if(!rect) { |
|
|
|
if(!elements.length) { |
|
|
|
const bubble = bubbles[0]; |
|
|
|
const bubble = bubbles[0]; |
|
|
|
if(bubble) { |
|
|
|
if(bubble) { |
|
|
|
rect = bubble.getBoundingClientRect(); |
|
|
|
elements.push({element: bubble, rect: bubble.getBoundingClientRect()}); |
|
|
|
anchor = bubble; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return {rect, anchor}; |
|
|
|
return elements; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public findAndSetAnchor() { |
|
|
|
public replaceSaved(from: HTMLElement, to: HTMLElement) { |
|
|
|
const {rect, anchor} = this.findAnchor(); |
|
|
|
if(!this.elements) { |
|
|
|
this.rect = rect; |
|
|
|
return; |
|
|
|
this.anchor = anchor; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const idx = this.elements.findIndex(({element}) => from === element); |
|
|
|
|
|
|
|
if(idx !== -1) { |
|
|
|
|
|
|
|
this.elements[idx].element = to; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public findAndSetElements() { |
|
|
|
|
|
|
|
this.elements = this.findElements(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public save() { |
|
|
|
public save() { |
|
|
|
this.findAndSetAnchor(); |
|
|
|
this.findAndSetElements(); |
|
|
|
// console.warn('scroll save', this.anchor, this.rect);
|
|
|
|
console.warn('scroll save', this.elements); |
|
|
|
this._save(); |
|
|
|
this._save(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -121,21 +127,32 @@ export default class ScrollSaver { |
|
|
|
const {scrollTop, scrollHeight} = this.scrollable; |
|
|
|
const {scrollTop, scrollHeight} = this.scrollable; |
|
|
|
this.scrollHeight = scrollHeight; |
|
|
|
this.scrollHeight = scrollHeight; |
|
|
|
|
|
|
|
|
|
|
|
if(!this.anchor?.parentElement) { // try to find new anchor
|
|
|
|
let anchor: ScrollSaver['elements'][0]; |
|
|
|
this.findAndSetAnchor(); |
|
|
|
// for(let i = this.elements.length - 1; i >= 0; --i) {
|
|
|
|
|
|
|
|
// const _anchor = this.elements[i];
|
|
|
|
|
|
|
|
// if(_anchor.element.parentElement) {
|
|
|
|
|
|
|
|
// anchor = _anchor;
|
|
|
|
|
|
|
|
// break;
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
anchor = this.elements[this.elements.length - 1]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(!anchor?.element?.parentElement) { // try to find new anchor
|
|
|
|
|
|
|
|
this.findAndSetElements(); |
|
|
|
|
|
|
|
anchor = this.elements[this.elements.length - 1]; |
|
|
|
|
|
|
|
|
|
|
|
if(!this.anchor) { // fallback to old method if smth is really strange
|
|
|
|
if(!anchor) { // fallback to old method if smth is really strange
|
|
|
|
this._restore(useReflow); |
|
|
|
this._restore(useReflow); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const rect = this.rect; |
|
|
|
const {element, rect} = anchor; |
|
|
|
const newRect = this.anchor.getBoundingClientRect(); |
|
|
|
const newRect = element.getBoundingClientRect(); |
|
|
|
const diff = newRect.bottom - rect.bottom; |
|
|
|
const diff = newRect.bottom - rect.bottom; |
|
|
|
this.setScrollTop(scrollTop + diff, useReflow); |
|
|
|
this.setScrollTop(scrollTop + diff, useReflow); |
|
|
|
// if(diff) debugger;
|
|
|
|
// if(diff) debugger;
|
|
|
|
// console.warn('scroll restore', rect, diff, newRect);
|
|
|
|
console.warn('scroll restore', rect, diff, newRect); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public _restore(useReflow?: boolean) { |
|
|
|
public _restore(useReflow?: boolean) { |
|
|
|