Fix jumping scroll
Enable reactions & views updates
This commit is contained in:
parent
02f0c9db0f
commit
c805347e83
@ -136,6 +136,12 @@ export const STICKY_OFFSET = 3;
|
||||
const SCROLLED_DOWN_THRESHOLD = 300;
|
||||
const PEER_CHANGED_ERROR = new Error('peer changed');
|
||||
|
||||
const DO_NOT_SLICE_VIEWPORT = false;
|
||||
const DO_NOT_SLICE_VIEWPORT_ON_RENDER = false;
|
||||
const DO_NOT_UPDATE_MESSAGE_VIEWS = false;
|
||||
const DO_NOT_UPDATE_MESSAGE_REACTIONS = false;
|
||||
const DO_NOT_UPDATE_MESSAGE_REPLY = false;
|
||||
|
||||
type Bubble = {
|
||||
bubble: HTMLElement,
|
||||
mids: Set<number>,
|
||||
@ -510,63 +516,50 @@ export default class ChatBubbles {
|
||||
this.safeRenderMessage(message, true, bubble);
|
||||
});
|
||||
|
||||
// if(this.chat.type !== 'scheduled' && false) {
|
||||
// this.listenerSetter.add(rootScope)('missed_reactions_element', async({message, changedResults}) => {
|
||||
// if(this.peerId !== message.peerId || !message.reactions || !message.reactions.results.length) {
|
||||
// return;
|
||||
// }
|
||||
if(this.chat.type !== 'scheduled' && !DO_NOT_UPDATE_MESSAGE_REACTIONS/* && false */) {
|
||||
this.listenerSetter.add(rootScope)('messages_reactions', async(arr) => {
|
||||
let scrollSaver: ScrollSaver;
|
||||
|
||||
const a = arr.map(async({message, changedResults}) => {
|
||||
if(this.peerId !== message.peerId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await this.getMountedBubble(message.mid, message);
|
||||
if(!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {bubble: result.bubble, message, changedResults};
|
||||
});
|
||||
|
||||
let top: number;
|
||||
(await Promise.all(a)).filter(Boolean).forEach(({bubble, message, changedResults}) => {
|
||||
if(!scrollSaver) {
|
||||
scrollSaver = this.createScrollSaver(false);
|
||||
scrollSaver.save();
|
||||
}
|
||||
|
||||
// const bubble = await this.getBubbleByMessage(message);
|
||||
// if(!bubble) {
|
||||
// return;
|
||||
// }
|
||||
const key = message.peerId + '_' + message.mid;
|
||||
const set = REACTIONS_ELEMENTS.get(key);
|
||||
if(set) {
|
||||
for(const element of set) {
|
||||
element.update(message, changedResults);
|
||||
}
|
||||
} else if(!message.reactions || !message.reactions.results.length) {
|
||||
return;
|
||||
} else {
|
||||
this.appendReactionsElementToBubble(bubble, message, message, changedResults);
|
||||
}
|
||||
});
|
||||
|
||||
// if(message.grouped_id) {
|
||||
// const grouped = await this.getGroupedBubble(message.grouped_id);
|
||||
// message = grouped.message;
|
||||
// }
|
||||
if(scrollSaver) {
|
||||
scrollSaver.restore();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// this.appendReactionsElementToBubble(bubble, message, changedResults);
|
||||
// });
|
||||
|
||||
// this.listenerSetter.add(rootScope)('messages_reactions', async(arr) => {
|
||||
// let scrollSaver: ScrollSaver;
|
||||
|
||||
// const promises = arr.map(async({message, changedResults}) => {
|
||||
// if(this.peerId !== message.peerId) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const bubble = await this.getBubbleByMessage(message);
|
||||
// if(!bubble) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if(!scrollSaver) {
|
||||
// scrollSaver = new ScrollSaver(this.scrollable, true);
|
||||
// scrollSaver.save();
|
||||
// }
|
||||
|
||||
// const key = message.peerId + '_' + message.mid;
|
||||
// const set = REACTIONS_ELEMENTS.get(key);
|
||||
// if(set) {
|
||||
// for(const element of set) {
|
||||
// element.update(message, changedResults);
|
||||
// }
|
||||
// } else {
|
||||
// rootScope.dispatchEvent('missed_reactions_element', {message, changedResults});
|
||||
// }
|
||||
// });
|
||||
|
||||
// await Promise.all(promises);
|
||||
|
||||
// if(scrollSaver) {
|
||||
// scrollSaver.restore();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
this.listenerSetter.add(rootScope)('messages_downloaded', async({peerId, mids}) => {
|
||||
!DO_NOT_UPDATE_MESSAGE_REPLY && this.listenerSetter.add(rootScope)('messages_downloaded', async({peerId, mids}) => {
|
||||
const middleware = this.getMiddleware();
|
||||
await getHeavyAnimationPromise();
|
||||
if(!middleware()) return;
|
||||
@ -885,38 +878,38 @@ export default class ChatBubbles {
|
||||
}
|
||||
});
|
||||
|
||||
// this.listenerSetter.add(rootScope)('messages_views', (arr) => {
|
||||
// fastRaf(() => {
|
||||
// let scrollSaver: ScrollSaver;
|
||||
// for(const {peerId, views, mid} of arr) {
|
||||
// if(this.peerId !== peerId) return;
|
||||
!DO_NOT_UPDATE_MESSAGE_VIEWS && this.listenerSetter.add(rootScope)('messages_views', (arr) => {
|
||||
fastRaf(() => {
|
||||
let scrollSaver: ScrollSaver;
|
||||
for(const {peerId, views, mid} of arr) {
|
||||
if(this.peerId !== peerId) continue;
|
||||
|
||||
// const bubble = this.bubbles[mid];
|
||||
// if(!bubble) return;
|
||||
const bubble = this.bubbles[mid];
|
||||
if(!bubble) continue;
|
||||
|
||||
// const postViewsElements = Array.from(bubble.querySelectorAll('.post-views')) as HTMLElement[];
|
||||
// if(postViewsElements.length) {
|
||||
// const str = formatNumber(views, 1);
|
||||
// let different = false;
|
||||
// postViewsElements.forEach((postViews) => {
|
||||
// if(different || postViews.innerHTML !== str) {
|
||||
// if(!scrollSaver) {
|
||||
// scrollSaver = new ScrollSaver(this.scrollable, true);
|
||||
// scrollSaver.save();
|
||||
// }
|
||||
const postViewsElements = Array.from(bubble.querySelectorAll('.post-views')) as HTMLElement[];
|
||||
if(!postViewsElements.length) continue;
|
||||
|
||||
// different = true;
|
||||
// postViews.innerHTML = str;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
const str = formatNumber(views, 1);
|
||||
let different = false;
|
||||
postViewsElements.forEach((postViews) => {
|
||||
if(different || postViews.textContent !== str) {
|
||||
if(!scrollSaver) {
|
||||
scrollSaver = this.createScrollSaver(true);
|
||||
scrollSaver.save();
|
||||
}
|
||||
|
||||
// if(scrollSaver) {
|
||||
// scrollSaver.restore();
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
different = true;
|
||||
postViews.textContent = str;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(scrollSaver) {
|
||||
scrollSaver.restore();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.observer = new SuperIntersectionObserver({root: this.scrollable.container});
|
||||
|
||||
@ -948,6 +941,11 @@ export default class ChatBubbles {
|
||||
return this.chat.peerId;
|
||||
}
|
||||
|
||||
private createScrollSaver(reverse = true) {
|
||||
const scrollSaver = new ScrollSaver(this.scrollable, '.bubbles-group .bubble', reverse);
|
||||
return scrollSaver;
|
||||
}
|
||||
|
||||
private unreadedObserverCallback = (entry: IntersectionObserverEntry) => {
|
||||
if(entry.isIntersecting) {
|
||||
const target = entry.target as HTMLElement;
|
||||
@ -1351,8 +1349,12 @@ export default class ChatBubbles {
|
||||
bubble = findUpClassName(target, 'bubble');
|
||||
} catch(err) {}
|
||||
|
||||
if(!bubble) {
|
||||
if(!bubble && !this.chat.selection.isSelecting) {
|
||||
const avatar = findUpClassName(target, 'user-avatar');
|
||||
if(!avatar) {
|
||||
return;
|
||||
}
|
||||
|
||||
const peerId = avatar.dataset.peerId.toPeerId();
|
||||
if(peerId !== NULL_PEER_ID) {
|
||||
this.chat.appImManager.setInnerPeer({peerId});
|
||||
@ -1803,12 +1805,6 @@ export default class ChatBubbles {
|
||||
}
|
||||
}
|
||||
|
||||
// public async getBubbleByMessage(message: Message.message | Message.messageService) {
|
||||
// if(!(message as Message.message).grouped_id) return this.bubbles[message.mid];
|
||||
// const grouped = await this.getGroupedBubble((message as Message.message).grouped_id);
|
||||
// return grouped?.bubble;
|
||||
// }
|
||||
|
||||
public getBubbleGroupedItems(bubble: HTMLElement) {
|
||||
return Array.from(bubble.querySelectorAll('.grouped-item')) as HTMLElement[];
|
||||
}
|
||||
@ -2184,10 +2180,8 @@ export default class ChatBubbles {
|
||||
}
|
||||
|
||||
public getLastBubble() {
|
||||
const lastDateGroup = this.getLastDateGroup();
|
||||
if(lastDateGroup) {
|
||||
return lastDateGroup.lastElementChild as HTMLElement;
|
||||
}
|
||||
const group = this.bubbleGroups.getLastGroup();
|
||||
return group?.lastItem?.bubble;
|
||||
}
|
||||
|
||||
public scrollToBubble(
|
||||
@ -2200,13 +2194,16 @@ export default class ChatBubbles {
|
||||
|
||||
let fallbackToElementStartWhenCentering: HTMLElement;
|
||||
// * if it's a start, then scroll to start of the group
|
||||
if(bubble && position !== 'end' && whichChild(bubble) === (this.stickyIntersector ? STICKY_OFFSET : 1)/* && this.chat.setPeerPromise */) {
|
||||
const dateGroup = bubble.parentElement;
|
||||
// if(whichChild(dateGroup) === 0) {
|
||||
fallbackToElementStartWhenCentering = dateGroup;
|
||||
// position = 'start';
|
||||
// element = dateGroup;
|
||||
// }
|
||||
if(bubble && position !== 'end') {
|
||||
const item = this.bubbleGroups.getItemByBubble(bubble);
|
||||
if(item.group.firstItem === item && whichChild(item.group.container) === (this.stickyIntersector ? STICKY_OFFSET : 1)) {
|
||||
const dateGroup = item.group.container.parentElement;
|
||||
// if(whichChild(dateGroup) === 0) {
|
||||
fallbackToElementStartWhenCentering = dateGroup;
|
||||
// position = 'start';
|
||||
// element = dateGroup;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// const isLastBubble = this.getLastBubble() === bubble;
|
||||
@ -2274,18 +2271,18 @@ export default class ChatBubbles {
|
||||
}
|
||||
|
||||
// ! can't get it by chatInner.lastElementChild because placeholder can be the last...
|
||||
private getLastDateGroup() {
|
||||
let lastTime = 0, lastElem: HTMLElement;
|
||||
for(const i in this.dateMessages) {
|
||||
const dateMessage = this.dateMessages[i];
|
||||
if(dateMessage.firstTimestamp > lastTime) {
|
||||
lastElem = dateMessage.container;
|
||||
lastTime = dateMessage.firstTimestamp;
|
||||
}
|
||||
}
|
||||
// private getLastDateGroup() {
|
||||
// let lastTime = 0, lastElem: HTMLElement;
|
||||
// for(const i in this.dateMessages) {
|
||||
// const dateMessage = this.dateMessages[i];
|
||||
// if(dateMessage.firstTimestamp > lastTime) {
|
||||
// lastElem = dateMessage.container;
|
||||
// lastTime = dateMessage.firstTimestamp;
|
||||
// }
|
||||
// }
|
||||
|
||||
return lastElem;
|
||||
}
|
||||
// return lastElem;
|
||||
// }
|
||||
|
||||
public async scrollToBubbleIfLast(bubble: HTMLElement) {
|
||||
if(this.getLastBubble() === bubble) {
|
||||
@ -3205,7 +3202,7 @@ export default class ChatBubbles {
|
||||
|
||||
const isMessage = message._ === 'message';
|
||||
const groupedId = isMessage && message.grouped_id;
|
||||
let albumMids: number[];
|
||||
let albumMids: number[], reactionsMessage: Message.message;
|
||||
|
||||
const albumMustBeRenderedFull = this.chat.type !== 'pinned';
|
||||
if(groupedId && albumMustBeRenderedFull) { // will render only last album's message
|
||||
@ -3215,6 +3212,10 @@ export default class ChatBubbles {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(isMessage) {
|
||||
reactionsMessage = groupedId ? await this.managers.appMessagesManager.getGroupsFirstMessage(message) : message;
|
||||
}
|
||||
|
||||
const peerId = this.peerId;
|
||||
// * can't use 'message.pFlags.out' here because this check will be used to define side of message (left-right)
|
||||
@ -3420,9 +3421,10 @@ export default class ChatBubbles {
|
||||
setInnerHTML(messageDiv, richText);
|
||||
}
|
||||
|
||||
const timeSpan = await MessageRender.setTime({
|
||||
const timeSpan = MessageRender.setTime({
|
||||
chatType: this.chat.type,
|
||||
message
|
||||
message,
|
||||
reactionsMessage
|
||||
});
|
||||
messageDiv.append(timeSpan);
|
||||
bubbleContainer.prepend(messageDiv);
|
||||
@ -4224,7 +4226,7 @@ export default class ChatBubbles {
|
||||
}
|
||||
|
||||
if(isMessage) {
|
||||
this.appendReactionsElementToBubble(bubble, message);
|
||||
this.appendReactionsElementToBubble(bubble, message, reactionsMessage);
|
||||
}
|
||||
|
||||
/* if(isMessage) {
|
||||
@ -4242,13 +4244,12 @@ export default class ChatBubbles {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private async appendReactionsElementToBubble(bubble: HTMLElement, message: Message.message, changedResults?: ReactionCount[]) {
|
||||
private appendReactionsElementToBubble(bubble: HTMLElement, message: Message.message, reactionsMessage: Message.message, changedResults?: ReactionCount[]) {
|
||||
if(this.peerId.isUser()/* || true */) {
|
||||
return;
|
||||
}
|
||||
|
||||
const reactionsMessage = await this.managers.appMessagesManager.getGroupsFirstMessage(message);
|
||||
if(!reactionsMessage.reactions || !reactionsMessage.reactions.results.length) {
|
||||
if(!reactionsMessage?.reactions || !reactionsMessage.reactions.results.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4268,9 +4269,10 @@ export default class ChatBubbles {
|
||||
|
||||
let timeSpan: HTMLElement = documentMessageDiv && documentMessageDiv.querySelector('.time');
|
||||
if(!timeSpan) {
|
||||
timeSpan = await MessageRender.setTime({
|
||||
timeSpan = MessageRender.setTime({
|
||||
chatType: this.chat.type,
|
||||
message
|
||||
message,
|
||||
reactionsMessage
|
||||
});
|
||||
}
|
||||
|
||||
@ -4299,15 +4301,16 @@ export default class ChatBubbles {
|
||||
}
|
||||
|
||||
this.log.warn('onRender');
|
||||
const scrollSaver = new ScrollSaver(this.scrollable, reverse);
|
||||
const scrollSaver = this.createScrollSaver(reverse);
|
||||
scrollSaver.save(); // * let's save scroll position by point before the slicing, not after
|
||||
|
||||
if(this.getRenderedLength() && !this.chat.setPeerPromise) {
|
||||
const viewportSlice = this.getViewportSlice();
|
||||
this.deleteViewportSlice(viewportSlice, true);
|
||||
}
|
||||
|
||||
scrollSaver.save();
|
||||
const saved = scrollSaver.getSaved();
|
||||
// scrollSaver.save(); // ! slicing will corrupt scroll position
|
||||
// const saved = scrollSaver.getSaved();
|
||||
// const hadScroll = saved.scrollHeight !== saved.clientHeight;
|
||||
|
||||
(this.messagesQueuePromise || Promise.resolve()).then(() => {
|
||||
@ -4957,7 +4960,9 @@ export default class ChatBubbles {
|
||||
}
|
||||
|
||||
public deleteViewportSlice(slice: ReturnType<ChatBubbles['getViewportSlice']>, ignoreScrollSaving?: boolean) {
|
||||
// return;
|
||||
if(DO_NOT_SLICE_VIEWPORT_ON_RENDER) {
|
||||
return;
|
||||
}
|
||||
|
||||
const {invisibleTop, invisibleBottom} = slice;
|
||||
const invisible = invisibleTop.concat(invisibleBottom);
|
||||
@ -4979,7 +4984,7 @@ export default class ChatBubbles {
|
||||
|
||||
let scrollSaver: ScrollSaver;
|
||||
if(!!invisibleTop.length !== !!invisibleBottom.length && !ignoreScrollSaving) {
|
||||
scrollSaver = new ScrollSaver(this.scrollable, !!invisibleTop.length);
|
||||
scrollSaver = this.createScrollSaver(!!invisibleTop.length);
|
||||
scrollSaver.save();
|
||||
}
|
||||
|
||||
@ -4994,7 +4999,7 @@ export default class ChatBubbles {
|
||||
|
||||
public sliceViewport(ignoreHeavyAnimation?: boolean) {
|
||||
// Safari cannot reset the scroll.
|
||||
if(IS_SAFARI || (this.isHeavyAnimationInProgress && !ignoreHeavyAnimation)/* || true */) {
|
||||
if(IS_SAFARI || (this.isHeavyAnimationInProgress && !ignoreHeavyAnimation) || DO_NOT_SLICE_VIEWPORT) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -35,9 +35,10 @@ export namespace MessageRender {
|
||||
|
||||
}; */
|
||||
|
||||
export const setTime = async(options: {
|
||||
export const setTime = (options: {
|
||||
chatType: ChatType,
|
||||
message: Message.message | Message.messageService
|
||||
message: Message.message | Message.messageService,
|
||||
reactionsMessage?: Message.message
|
||||
}) => {
|
||||
const {chatType, message} = options;
|
||||
const date = new Date(message.date * 1000);
|
||||
@ -83,8 +84,7 @@ export namespace MessageRender {
|
||||
if(message.peer_id._ === 'peerUser'/* && message.reactions?.results?.length */) {
|
||||
hasReactions = true;
|
||||
|
||||
reactionsMessage = await rootScope.managers.appMessagesManager.getGroupsFirstMessage(message);
|
||||
|
||||
reactionsMessage = options.reactionsMessage;
|
||||
reactionsElement = new ReactionsElement();
|
||||
reactionsElement.init(reactionsMessage, 'inline', true);
|
||||
reactionsElement.render();
|
||||
|
@ -817,7 +817,7 @@ export default class ChatSelection extends AppSelection {
|
||||
}
|
||||
|
||||
protected getMidsFromGroupContainer(groupContainer: HTMLElement) {
|
||||
const elements = Array.from(groupContainer.querySelectorAll('.grouped-item')) as HTMLElement[];
|
||||
const elements = this.chat.bubbles.getBubbleGroupedItems(groupContainer);
|
||||
if(!elements.length) {
|
||||
elements.push(groupContainer);
|
||||
}
|
||||
|
@ -5,14 +5,18 @@
|
||||
*/
|
||||
|
||||
import Scrollable from "../components/scrollable";
|
||||
import { MOUNT_CLASS_TO } from "../config/debug";
|
||||
import { IS_SAFARI } from "../environment/userAgent";
|
||||
import getVisibleRect from "./dom/getVisibleRect";
|
||||
import reflowScrollableElement from "./dom/reflowScrollableElement";
|
||||
|
||||
export default class ScrollSaver {
|
||||
private scrollHeight: number;
|
||||
private scrollHeightMinusTop: number;
|
||||
// private scrollHeightMinusTop: number;
|
||||
private scrollTop: number;
|
||||
private clientHeight: number;
|
||||
private anchor: HTMLElement;
|
||||
private rect: DOMRect;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -21,6 +25,7 @@ export default class ScrollSaver {
|
||||
*/
|
||||
constructor(
|
||||
private scrollable: Scrollable,
|
||||
private query: string,
|
||||
private reverse: boolean
|
||||
) {
|
||||
|
||||
@ -38,7 +43,39 @@ export default class ScrollSaver {
|
||||
};
|
||||
}
|
||||
|
||||
public findAnchor() {
|
||||
const {container} = this;
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const bubbles = Array.from(container.querySelectorAll(this.query)) as HTMLElement[];
|
||||
let rect: DOMRect, anchor: HTMLElement;
|
||||
for(const bubble of bubbles) {
|
||||
const elementRect = bubble.getBoundingClientRect();
|
||||
const visibleRect = getVisibleRect(bubble, container, undefined, elementRect, containerRect);
|
||||
if(visibleRect) {
|
||||
rect = elementRect;
|
||||
anchor = bubble;
|
||||
// break; // find first
|
||||
} else if(anchor) { // find last
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {rect, anchor};
|
||||
}
|
||||
|
||||
public findAndSetAnchor() {
|
||||
const {rect, anchor} = this.findAnchor();
|
||||
this.rect = rect;
|
||||
this.anchor = anchor;
|
||||
}
|
||||
|
||||
public save() {
|
||||
this.findAndSetAnchor();
|
||||
// console.warn('scroll save', this.anchor, this.rect);
|
||||
this._save();
|
||||
}
|
||||
|
||||
public _save() {
|
||||
const {scrollTop, scrollHeight, clientHeight} = this.container;
|
||||
|
||||
//previousScrollHeight = scrollHeight;
|
||||
@ -46,7 +83,7 @@ export default class ScrollSaver {
|
||||
this.scrollHeight = scrollHeight;
|
||||
this.scrollTop = scrollTop;
|
||||
this.clientHeight = clientHeight;
|
||||
this.scrollHeightMinusTop = this.reverse ? scrollHeight - scrollTop : scrollTop;
|
||||
// this.scrollHeightMinusTop = this.reverse ? scrollHeight - scrollTop : scrollTop;
|
||||
|
||||
//this.chatInner.style.paddingTop = padding + 'px';
|
||||
/* if(reverse) {
|
||||
@ -54,60 +91,85 @@ export default class ScrollSaver {
|
||||
} else {
|
||||
previousScrollHeightMinusTop = scrollTop;
|
||||
} */
|
||||
|
||||
/* if(DEBUG) {
|
||||
this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, scrollHeight, previousScrollHeightMinusTop);
|
||||
} */
|
||||
}
|
||||
|
||||
public restore(useReflow?: boolean) {
|
||||
const {container, scrollHeightMinusTop: previousScrollHeightMinusTop, scrollable} = this;
|
||||
if(previousScrollHeightMinusTop === undefined) {
|
||||
throw new Error('scroll was not saved');
|
||||
private onRestore(useReflow?: boolean) {
|
||||
if(IS_SAFARI && useReflow/* && !isAppleMobile */) { // * fix blinking and jumping
|
||||
reflowScrollableElement(this.container);
|
||||
}
|
||||
}
|
||||
|
||||
const scrollHeight = container.scrollHeight;
|
||||
if(scrollHeight === this.scrollHeight) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.scrollHeight = scrollHeight;
|
||||
|
||||
/* const scrollHeight = container.scrollHeight;
|
||||
const addedHeight = scrollHeight - previousScrollHeight;
|
||||
|
||||
this.chatInner.style.paddingTop = (10000 - addedHeight) + 'px'; */
|
||||
/* const scrollHeight = scrollHeight;
|
||||
const addedHeight = scrollHeight - previousScrollHeight;
|
||||
|
||||
this.chatInner.style.paddingTop = (padding - addedHeight) + 'px';
|
||||
|
||||
//const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||
const newScrollTop = reverse ? scrollHeight - addedHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||
this.log('performHistoryResult: will set scrollTop',
|
||||
previousScrollHeightMinusTop, scrollHeight,
|
||||
newScrollTop, container.container.clientHeight); */
|
||||
//const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||
const newScrollTop = this.reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||
|
||||
/* if(DEBUG) {
|
||||
this.log('performHistoryResult: will set up scrollTop:', newScrollTop, this.isHeavyAnimationInProgress);
|
||||
} */
|
||||
|
||||
private setScrollTop(newScrollTop: number, useReflow?: boolean) {
|
||||
// touchSupport for safari iOS
|
||||
//isTouchSupported && isApple && (container.container.style.overflow = 'hidden');
|
||||
this.scrollable.setScrollTopSilently(this.scrollTop = newScrollTop);
|
||||
//container.scrollTop = scrollHeight;
|
||||
//isTouchSupported && isApple && (container.container.style.overflow = '');
|
||||
|
||||
if(IS_SAFARI && useReflow/* && !isAppleMobile */) { // * fix blinking and jumping
|
||||
reflowScrollableElement(container);
|
||||
this.onRestore(useReflow);
|
||||
}
|
||||
|
||||
public restore(useReflow?: boolean) {
|
||||
const {scrollTop, scrollHeight} = this.scrollable;
|
||||
this.scrollHeight = scrollHeight;
|
||||
|
||||
// if(!this.anchor.parentElement) { // fallback to old method if element has disappeared (e.g. edited)
|
||||
// this._restore(useReflow);
|
||||
// return;
|
||||
// }
|
||||
|
||||
if(!this.anchor.parentElement) { // try to find new anchor
|
||||
this.findAndSetAnchor();
|
||||
}
|
||||
|
||||
/* if(DEBUG) {
|
||||
this.log('performHistoryResult: have set up scrollTop:', newScrollTop, container.scrollTop, container.scrollHeight, this.isHeavyAnimationInProgress);
|
||||
} */
|
||||
|
||||
return;
|
||||
const rect = this.rect;
|
||||
const newRect = this.anchor.getBoundingClientRect();
|
||||
const diff = newRect.bottom - rect.bottom;
|
||||
this.setScrollTop(scrollTop + diff, useReflow);
|
||||
// console.warn('scroll restore', rect, diff, newRect);
|
||||
}
|
||||
|
||||
// public _restore(useReflow?: boolean) {
|
||||
// const {scrollHeightMinusTop: previousScrollHeightMinusTop, scrollable} = this;
|
||||
// // if(previousScrollHeightMinusTop === undefined) {
|
||||
// // throw new Error('scroll was not saved');
|
||||
// // }
|
||||
|
||||
// // const scrollHeight = container.scrollHeight;
|
||||
// const scrollHeight = this.scrollHeight;
|
||||
// // if(scrollHeight === this.scrollHeight) {
|
||||
// // return;
|
||||
// // }
|
||||
|
||||
// // this.scrollHeight = scrollHeight;
|
||||
|
||||
// /* const scrollHeight = container.scrollHeight;
|
||||
// const addedHeight = scrollHeight - previousScrollHeight;
|
||||
|
||||
// this.chatInner.style.paddingTop = (10000 - addedHeight) + 'px'; */
|
||||
// /* const scrollHeight = scrollHeight;
|
||||
// const addedHeight = scrollHeight - previousScrollHeight;
|
||||
|
||||
// this.chatInner.style.paddingTop = (padding - addedHeight) + 'px';
|
||||
|
||||
// //const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||
// const newScrollTop = reverse ? scrollHeight - addedHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||
// this.log('performHistoryResult: will set scrollTop',
|
||||
// previousScrollHeightMinusTop, scrollHeight,
|
||||
// newScrollTop, container.container.clientHeight); */
|
||||
// //const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||
// const newScrollTop = this.reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;
|
||||
|
||||
// /* if(DEBUG) {
|
||||
// this.log('performHistoryResult: will set up scrollTop:', newScrollTop, this.isHeavyAnimationInProgress);
|
||||
// } */
|
||||
|
||||
// this.setScrollTop(newScrollTop, useReflow);
|
||||
|
||||
// /* if(DEBUG) {
|
||||
// this.log('performHistoryResult: have set up scrollTop:', newScrollTop, container.scrollTop, container.scrollHeight, this.isHeavyAnimationInProgress);
|
||||
// } */
|
||||
// }
|
||||
}
|
||||
|
||||
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.ScrollSaver = ScrollSaver);
|
||||
|
@ -148,8 +148,6 @@ export type BroadcastEvents = {
|
||||
|
||||
'quick_reaction': string,
|
||||
|
||||
'missed_reactions_element': {message: Message.message, changedResults: ReactionCount[]},
|
||||
|
||||
'service_notification': Update.updateServiceNotification,
|
||||
|
||||
'logging_out': void
|
||||
|
@ -987,11 +987,12 @@ $bubble-beside-button-width: 38px;
|
||||
}
|
||||
|
||||
.bubbles.has-groups & {
|
||||
pointer-events: none;
|
||||
|
||||
.bubble-content-wrapper {
|
||||
transform: scale3d(.8, .8, 1) translateX(0);
|
||||
//transform: scale(.8) translateX(0);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
16
src/test_scroll_saving.js
Normal file
16
src/test_scroll_saving.js
Normal file
@ -0,0 +1,16 @@
|
||||
var chatInner = appImManager.chat.bubbles.chatInner;
|
||||
var dateGroup = chatInner.firstElementChild;
|
||||
var topBubble = chatInner.querySelector('[data-mid="6318129151"]').parentElement;
|
||||
var bottomBubble = chatInner.querySelector('[data-mid="6318587903"]').parentElement;
|
||||
topBubble.remove();
|
||||
bottomBubble.remove();
|
||||
var f = () => {
|
||||
var scrollSaver = appImManager.chat.bubbles.createScrollSaver();
|
||||
scrollSaver.save();
|
||||
|
||||
dateGroup.prepend(topBubble);
|
||||
dateGroup.append(bottomBubble);
|
||||
scrollSaver.restore();
|
||||
};
|
||||
// f();
|
||||
setTimeout(() => f(), 1000);
|
Loading…
Reference in New Issue
Block a user