Browse Source

Fix jumping scroll

Enable reactions & views updates
master
Eduard Kuzmenko 2 years ago
parent
commit
c805347e83
  1. 265
      src/components/chat/bubbles.ts
  2. 8
      src/components/chat/messageRender.ts
  3. 2
      src/components/chat/selection.ts
  4. 150
      src/helpers/scrollSaver.ts
  5. 2
      src/lib/rootScope.ts
  6. 3
      src/scss/partials/_chatBubble.scss
  7. 16
      src/test_scroll_saving.js

265
src/components/chat/bubbles.ts

@ -136,6 +136,12 @@ export const STICKY_OFFSET = 3; @@ -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 { @@ -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;
// }
// const bubble = await this.getBubbleByMessage(message);
// if(!bubble) {
// return;
// }
// if(message.grouped_id) {
// const grouped = await this.getGroupedBubble(message.grouped_id);
// message = grouped.message;
// }
// 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();
// }
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 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();
// }
// });
// }
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(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 { @@ -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();
// }
// different = true;
// postViews.innerHTML = str;
// }
// });
// }
// }
// if(scrollSaver) {
// scrollSaver.restore();
// }
// });
// });
const postViewsElements = Array.from(bubble.querySelectorAll('.post-views')) as HTMLElement[];
if(!postViewsElements.length) continue;
const str = formatNumber(views, 1);
let different = false;
postViewsElements.forEach((postViews) => {
if(different || postViews.textContent !== str) {
if(!scrollSaver) {
scrollSaver = this.createScrollSaver(true);
scrollSaver.save();
}
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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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;
}
}
return lastElem;
}
// 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;
// }
public async scrollToBubbleIfLast(bubble: HTMLElement) {
if(this.getLastBubble() === bubble) {
@ -3205,7 +3202,7 @@ export default class ChatBubbles { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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;
}

8
src/components/chat/messageRender.ts

@ -35,9 +35,10 @@ export namespace MessageRender { @@ -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 { @@ -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();

2
src/components/chat/selection.ts

@ -817,7 +817,7 @@ export default class ChatSelection extends AppSelection { @@ -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);
}

150
src/helpers/scrollSaver.ts

@ -5,14 +5,18 @@ @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -54,60 +91,85 @@ export default class ScrollSaver {
} else {
previousScrollHeightMinusTop = scrollTop;
} */
}
/* if(DEBUG) {
this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, scrollHeight, previousScrollHeightMinusTop);
} */
private onRestore(useReflow?: boolean) {
if(IS_SAFARI && useReflow/* && !isAppleMobile */) { // * fix blinking and jumping
reflowScrollableElement(this.container);
}
}
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 = '');
this.onRestore(useReflow);
}
public restore(useReflow?: boolean) {
const {container, scrollHeightMinusTop: previousScrollHeightMinusTop, scrollable} = this;
if(previousScrollHeightMinusTop === undefined) {
throw new Error('scroll was not saved');
}
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;
// }
const scrollHeight = container.scrollHeight;
if(scrollHeight === this.scrollHeight) {
return;
if(!this.anchor.parentElement) { // try to find new anchor
this.findAndSetAnchor();
}
this.scrollHeight = scrollHeight;
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 addedHeight = scrollHeight - previousScrollHeight;
// // 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 = (10000 - addedHeight) + 'px'; */
// /* const scrollHeight = scrollHeight;
// const addedHeight = scrollHeight - previousScrollHeight;
this.chatInner.style.paddingTop = (padding - addedHeight) + 'px';
// 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;
// //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);
} */
// 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);
}
// /* if(DEBUG) {
// this.log('performHistoryResult: will set up scrollTop:', newScrollTop, this.isHeavyAnimationInProgress);
// } */
/* if(DEBUG) {
this.log('performHistoryResult: have set up scrollTop:', newScrollTop, container.scrollTop, container.scrollHeight, this.isHeavyAnimationInProgress);
} */
// this.setScrollTop(newScrollTop, useReflow);
return;
}
// /* if(DEBUG) {
// this.log('performHistoryResult: have set up scrollTop:', newScrollTop, container.scrollTop, container.scrollHeight, this.isHeavyAnimationInProgress);
// } */
// }
}
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.ScrollSaver = ScrollSaver);

2
src/lib/rootScope.ts

@ -148,8 +148,6 @@ export type BroadcastEvents = { @@ -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

3
src/scss/partials/_chatBubble.scss

@ -987,11 +987,12 @@ $bubble-beside-button-width: 38px; @@ -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

@ -0,0 +1,16 @@ @@ -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…
Cancel
Save