Browse Source

FIx unneeded webPage refresh

Fix locking scroll due to tab swipe on iOS
master
morethanwords 3 years ago
parent
commit
409f30d806
  1. 26
      src/components/chat/bubbles.ts
  2. 21
      src/components/chat/input.ts
  3. 17
      src/components/inputField.ts
  4. 7
      src/components/scrollable.ts
  5. 3
      src/helpers/dom/handleHorizontalSwipe.ts
  6. 36
      src/helpers/fastSmoothScroll.ts
  7. 4
      src/layer.d.ts
  8. 2
      src/lib/appManagers/appDraftsManager.ts
  9. 12
      src/lib/appManagers/appImManager.ts
  10. 45
      src/lib/appManagers/appMessagesManager.ts
  11. 11
      src/lib/appManagers/appWebPagesManager.ts
  12. 4
      src/scripts/in/schema_additional_params.json
  13. 3
      src/scss/partials/_chat.scss

26
src/components/chat/bubbles.ts

@ -133,7 +133,7 @@ export default class ChatBubbles {
private loadedTopTimes = 0; private loadedTopTimes = 0;
private loadedBottomTimes = 0; private loadedBottomTimes = 0;
private messagesQueuePromise: Promise<void> = null; public messagesQueuePromise: Promise<void> = null;
private messagesQueue: {message: any, bubble: HTMLElement, reverse: boolean, promises: Promise<void>[]}[] = []; private messagesQueue: {message: any, bubble: HTMLElement, reverse: boolean, promises: Promise<void>[]}[] = [];
private messagesQueueOnRender: () => void = null; private messagesQueueOnRender: () => void = null;
private messagesQueueOnRenderAdditional: () => void = null; private messagesQueueOnRenderAdditional: () => void = null;
@ -1409,6 +1409,10 @@ export default class ChatBubbles {
if(msgId > 0 && msgId <= maxId) { if(msgId > 0 && msgId <= maxId) {
const bubble = this.bubbles[msgId]; const bubble = this.bubbles[msgId];
if(bubble) { if(bubble) {
if(bubble.classList.contains('is-sending')) {
continue;
}
bubble.classList.remove('is-sent', 'is-sending'); // is-sending can be when there are bulk of updates (e.g. sending command to Stickers bot) bubble.classList.remove('is-sent', 'is-sending'); // is-sending can be when there are bulk of updates (e.g. sending command to Stickers bot)
bubble.classList.add('is-read'); bubble.classList.add('is-read');
} }
@ -1533,7 +1537,25 @@ export default class ChatBubbles {
} }
} }
return this.scrollable.scrollIntoViewNew(element, position, 4, undefined, forceDirection, forceDuration); return this.scrollable.scrollIntoViewNew(
element,
position,
4,
undefined,
forceDirection,
forceDuration,
'y',
({rect}) => {
let height = windowSize.windowH;
height -= this.chat.topbar.container.getBoundingClientRect().height;
height -= 78;
return height;
const rowsWrapperHeight = this.chat.input.rowsWrapper.getBoundingClientRect().height;
const diff = rowsWrapperHeight - 54;
return rect.height + diff;
}
);
} }
public scrollToBubbleEnd(bubble = this.getLastBubble()) { public scrollToBubbleEnd(bubble = this.getLastBubble()) {

21
src/components/chat/input.ts

@ -82,7 +82,6 @@ import PopupPeer from '../popups/peer';
import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport'; import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';
import appMediaPlaybackController from '../appMediaPlaybackController'; import appMediaPlaybackController from '../appMediaPlaybackController';
import { NULL_PEER_ID } from '../../lib/mtproto/mtproto_config'; import { NULL_PEER_ID } from '../../lib/mtproto/mtproto_config';
import replaceContent from '../../helpers/dom/replaceContent';
const RECORD_MIN_TIME = 500; const RECORD_MIN_TIME = 500;
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.'; const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
@ -776,6 +775,14 @@ export default class ChatInput {
draft = this.appDraftsManager.getDraft(this.chat.peerId, this.chat.threadId); draft = this.appDraftsManager.getDraft(this.chat.peerId, this.chat.threadId);
if(!draft) { if(!draft) {
if(force) { // this situation can only happen when sending message with clearDraft
((this.chat.bubbles.messagesQueuePromise || Promise.resolve()) as Promise<any>).then(() => {
fastRaf(() => {
this.onMessageSent();
});
});
}
return false; return false;
} }
} }
@ -921,6 +928,7 @@ export default class ChatInput {
private attachMessageInputListeners() { private attachMessageInputListeners() {
this.listenerSetter.add(this.messageInput)('keydown', (e: KeyboardEvent) => { this.listenerSetter.add(this.messageInput)('keydown', (e: KeyboardEvent) => {
if(isSendShortcutPressed(e)) { if(isSendShortcutPressed(e)) {
cancelEvent(e);
this.sendMessage(); this.sendMessage();
} else if(e.ctrlKey || e.metaKey) { } else if(e.ctrlKey || e.metaKey) {
this.handleMarkdownShortcut(e); this.handleMarkdownShortcut(e);
@ -1758,6 +1766,8 @@ export default class ChatInput {
entities, entities,
noWebPage: this.noWebPage noWebPage: this.noWebPage
}); });
this.onMessageSent();
} else { } else {
new PopupDeleteMessages(this.chat.peerId, [this.editMsgId], this.chat.type); new PopupDeleteMessages(this.chat.peerId, [this.editMsgId], this.chat.type);
@ -1774,6 +1784,9 @@ export default class ChatInput {
silent: this.sendSilent, silent: this.sendSilent,
clearDraft: true clearDraft: true
}); });
this.onMessageSent(false, false);
// this.onMessageSent();
} }
// * wait for sendText set messageId for invokeAfterMsg // * wait for sendText set messageId for invokeAfterMsg
@ -1792,7 +1805,7 @@ export default class ChatInput {
}, 0); }, 0);
} }
this.onMessageSent(); // this.onMessageSent();
} }
public sendMessageWithDocument(document: MyDocument | string, force = false, clearDraft = false) { public sendMessageWithDocument(document: MyDocument | string, force = false, clearDraft = false) {
@ -1934,12 +1947,12 @@ export default class ChatInput {
if(message._ === 'messageEmpty') { // load missing replying message if(message._ === 'messageEmpty') { // load missing replying message
peerTitleEl = i18n('Loading'); peerTitleEl = i18n('Loading');
this.chat.appMessagesManager.wrapSingleMessage(this.chat.peerId, mid).then(() => { this.chat.appMessagesManager.wrapSingleMessage(this.chat.peerId, mid).then((_message) => {
if(this.replyToMsgId !== mid) { if(this.replyToMsgId !== mid) {
return; return;
} }
message = this.chat.getMessage(mid); message = _message;
if(message._ === 'messageEmpty') { if(message._ === 'messageEmpty') {
this.clearHelper('reply'); this.clearHelper('reply');
} else { } else {

17
src/components/inputField.ts

@ -93,7 +93,7 @@ class InputField {
public validate: () => boolean; public validate: () => boolean;
//public onLengthChange: (length: number, isOverflow: boolean) => void; //public onLengthChange: (length: number, isOverflow: boolean) => void;
protected wasInputFakeClientHeight: number; // protected wasInputFakeClientHeight: number;
// protected showScrollDebounced: () => void; // protected showScrollDebounced: () => void;
constructor(public options: InputFieldOptions = {}) { constructor(public options: InputFieldOptions = {}) {
@ -147,7 +147,7 @@ class InputField {
if(options.animate) { if(options.animate) {
input.classList.add('scrollable', 'scrollable-y'); input.classList.add('scrollable', 'scrollable-y');
this.wasInputFakeClientHeight = 0; // this.wasInputFakeClientHeight = 0;
// this.showScrollDebounced = debounce(() => this.input.classList.remove('no-scrollbar'), 150, false, true); // this.showScrollDebounced = debounce(() => this.input.classList.remove('no-scrollbar'), 150, false, true);
this.inputFake = document.createElement('div'); this.inputFake = document.createElement('div');
this.inputFake.setAttribute('contenteditable', 'true'); this.inputFake.setAttribute('contenteditable', 'true');
@ -237,14 +237,21 @@ class InputField {
} }
public onFakeInput() { public onFakeInput() {
const {scrollHeight, clientHeight} = this.inputFake; const {scrollHeight: newHeight/* , clientHeight */} = this.inputFake;
/* if(this.wasInputFakeClientHeight && this.wasInputFakeClientHeight !== clientHeight) { /* if(this.wasInputFakeClientHeight && this.wasInputFakeClientHeight !== clientHeight) {
this.input.classList.add('no-scrollbar'); // ! в сафари может вообще не появиться скролл после анимации, так как ему нужен полный reflow блока с overflow. this.input.classList.add('no-scrollbar'); // ! в сафари может вообще не появиться скролл после анимации, так как ему нужен полный reflow блока с overflow.
this.showScrollDebounced(); this.showScrollDebounced();
} */ } */
this.wasInputFakeClientHeight = clientHeight; const TRANSITION_DURATION_FACTOR = 50;
this.input.style.height = scrollHeight ? scrollHeight + 'px' : ''; const currentHeight = +this.input.style.height.replace('px', '');
const transitionDuration = Math.round(
TRANSITION_DURATION_FACTOR * Math.log(Math.abs(newHeight - currentHeight)),
);
// this.wasInputFakeClientHeight = clientHeight;
this.input.style.transitionDuration = `${transitionDuration}ms`;
this.input.style.height = newHeight ? newHeight + 'px' : '';
} }
get value() { get value() {

7
src/components/scrollable.ts

@ -6,7 +6,7 @@
import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport"; import { IS_TOUCH_SUPPORTED } from "../environment/touchSupport";
import { logger, LogTypes } from "../lib/logger"; import { logger, LogTypes } from "../lib/logger";
import fastSmoothScroll, { FocusDirection } from "../helpers/fastSmoothScroll"; import fastSmoothScroll, { FocusDirection, ScrollGetNormalSizeCallback } from "../helpers/fastSmoothScroll";
import useHeavyAnimationCheck from "../hooks/useHeavyAnimationCheck"; import useHeavyAnimationCheck from "../hooks/useHeavyAnimationCheck";
import { cancelEvent } from "../helpers/dom/cancelEvent"; import { cancelEvent } from "../helpers/dom/cancelEvent";
/* /*
@ -106,10 +106,11 @@ export class ScrollableBase {
maxDistance?: number, maxDistance?: number,
forceDirection?: FocusDirection, forceDirection?: FocusDirection,
forceDuration?: number, forceDuration?: number,
axis?: 'x' | 'y' axis?: 'x' | 'y',
getNormalSize?: ScrollGetNormalSizeCallback
) { ) {
//return Promise.resolve(); //return Promise.resolve();
return fastSmoothScroll(this.container, element, position, margin, maxDistance, forceDirection, forceDuration, axis); return fastSmoothScroll(this.container, element, position, margin, maxDistance, forceDirection, forceDuration, axis, getNormalSize);
} }
} }

3
src/helpers/dom/handleHorizontalSwipe.ts

@ -5,7 +5,6 @@
*/ */
import SwipeHandler, { SwipeHandlerOptions } from "../../components/swipeHandler"; import SwipeHandler, { SwipeHandlerOptions } from "../../components/swipeHandler";
import { IS_APPLE_MOBILE, IS_SAFARI } from "../../environment/userAgent";
import { cancelEvent } from "./cancelEvent"; import { cancelEvent } from "./cancelEvent";
import findUpClassName from "./findUpClassName"; import findUpClassName from "./findUpClassName";
import isSwipingBackSafari from "./isSwipingBackSafari"; import isSwipingBackSafari from "./isSwipingBackSafari";
@ -45,6 +44,6 @@ export default function handleHorizontalSwipe(options: SwipeHandlerHorizontalOpt
cancelY = false; cancelY = false;
options.onReset && options.onReset(); options.onReset && options.onReset();
}, },
cancelEvent: true cancelEvent: false // cannot use cancelEvent on Safari iOS because scroll will be canceled too
}); });
} }

36
src/helpers/fastSmoothScroll.ts

@ -12,9 +12,10 @@ import { animateSingle, cancelAnimationByKey } from './animation';
import rootScope from '../lib/rootScope'; import rootScope from '../lib/rootScope';
import isInDOM from './dom/isInDOM'; import isInDOM from './dom/isInDOM';
const MAX_DISTANCE = 1500;
const MIN_JS_DURATION = 250; const MIN_JS_DURATION = 250;
const MAX_JS_DURATION = 600; const MAX_JS_DURATION = 600;
const LONG_TRANSITION_MAX_DISTANCE = 1500;
const SHORT_TRANSITION_MAX_DISTANCE = 500;
export enum FocusDirection { export enum FocusDirection {
Up, Up,
@ -22,15 +23,18 @@ export enum FocusDirection {
Static, Static,
}; };
export type ScrollGetNormalSizeCallback = (options: {rect: DOMRect}) => number;
export default function fastSmoothScroll( export default function fastSmoothScroll(
container: HTMLElement, container: HTMLElement,
element: HTMLElement, element: HTMLElement,
position: ScrollLogicalPosition, position: ScrollLogicalPosition,
margin = 0, margin = 0,
maxDistance = MAX_DISTANCE, maxDistance = LONG_TRANSITION_MAX_DISTANCE,
forceDirection?: FocusDirection, forceDirection?: FocusDirection,
forceDuration?: number, forceDuration?: number,
axis: 'x' | 'y' = 'y' axis: 'x' | 'y' = 'y',
getNormalSize?: ScrollGetNormalSizeCallback
) { ) {
//return; //return;
@ -40,7 +44,7 @@ export default function fastSmoothScroll(
if(forceDirection === FocusDirection.Static) { if(forceDirection === FocusDirection.Static) {
forceDuration = 0; forceDuration = 0;
return scrollWithJs(container, element, position, margin, forceDuration, axis); return scrollWithJs(container, element, position, margin, forceDuration, axis, getNormalSize);
/* return Promise.resolve(); /* return Promise.resolve();
element.scrollIntoView({ block: position }); element.scrollIntoView({ block: position });
@ -82,9 +86,9 @@ export default function fastSmoothScroll(
} */ } */
} }
const promise = new Promise((resolve) => { const promise = new Promise<void>((resolve) => {
fastRaf(() => { fastRaf(() => {
scrollWithJs(container, element, position, margin, forceDuration, axis) scrollWithJs(container, element, position, margin, forceDuration, axis, getNormalSize)
.then(resolve); .then(resolve);
}); });
}); });
@ -93,7 +97,13 @@ export default function fastSmoothScroll(
} }
function scrollWithJs( function scrollWithJs(
container: HTMLElement, element: HTMLElement, position: ScrollLogicalPosition, margin = 0, forceDuration?: number, axis: 'x' | 'y' = 'y' container: HTMLElement,
element: HTMLElement,
position: ScrollLogicalPosition,
margin = 0,
forceDuration?: number,
axis: 'x' | 'y' = 'y',
getNormalSize?: ScrollGetNormalSizeCallback
) { ) {
if(!isInDOM(element)) { if(!isInDOM(element)) {
cancelAnimationByKey(container); cancelAnimationByKey(container);
@ -115,7 +125,7 @@ function scrollWithJs(
const elementPosition = elementRect[rectStartKey] - containerRect[rectStartKey]; const elementPosition = elementRect[rectStartKey] - containerRect[rectStartKey];
const elementSize = element[scrollSizeKey]; // margin is exclusive in DOMRect const elementSize = element[scrollSizeKey]; // margin is exclusive in DOMRect
const containerSize = containerRect[sizeKey]; const containerSize = getNormalSize ? getNormalSize({rect: containerRect}) : containerRect[sizeKey];
const scrollPosition = container[scrollPositionKey]; const scrollPosition = container[scrollPositionKey];
const scrollSize = container[scrollSizeKey]; const scrollSize = container[scrollSizeKey];
@ -177,8 +187,9 @@ function scrollWithJs(
} }
const target = container[scrollPositionKey] + path; const target = container[scrollPositionKey] + path;
const absPath = Math.abs(path);
const duration = forceDuration ?? ( const duration = forceDuration ?? (
MIN_JS_DURATION + (Math.abs(path) / MAX_DISTANCE) * (MAX_JS_DURATION - MIN_JS_DURATION) MIN_JS_DURATION + (absPath / LONG_TRANSITION_MAX_DISTANCE) * (MAX_JS_DURATION - MIN_JS_DURATION)
); );
const startAt = Date.now(); const startAt = Date.now();
@ -222,6 +233,7 @@ function scrollWithJs(
//transformable.style.minHeight = `${transformableHeight}px`; //transformable.style.minHeight = `${transformableHeight}px`;
*/ */
const transition = absPath < SHORT_TRANSITION_MAX_DISTANCE ? shortTransition : longTransition;
const tick = () => { const tick = () => {
const t = duration ? Math.min((Date.now() - startAt) / duration, 1) : 1; const t = duration ? Math.min((Date.now() - startAt) / duration, 1) : 1;
@ -258,6 +270,10 @@ function scrollWithJs(
return animateSingle(tick, container); return animateSingle(tick, container);
} }
function transition(t: number) { function longTransition(t: number) {
return 1 - ((1 - t) ** 5);
}
function shortTransition(t: number) {
return 1 - ((1 - t) ** 3.5); return 1 - ((1 - t) ** 3.5);
} }

4
src/layer.d.ts vendored

@ -816,7 +816,9 @@ export namespace Message {
flags?: number, flags?: number,
id: number, id: number,
peer_id?: Peer, peer_id?: Peer,
deleted?: boolean deleted?: boolean,
mid?: number,
pFlags?: {}
}; };
export type message = { export type message = {

2
src/lib/appManagers/appDraftsManager.ts

@ -251,7 +251,7 @@ export class AppDraftsManager {
if(threadId) { if(threadId) {
this.syncDraft(peerId, threadId); this.syncDraft(peerId, threadId);
} else { } else {
this.saveDraft(peerId, threadId, null, {notify: true/* , force: true */}); this.saveDraft(peerId, threadId, null, {notify: true, force: true});
} }
} }

12
src/lib/appManagers/appImManager.ts

@ -501,16 +501,22 @@ export class AppImManager {
return; return;
} }
if(chat.input.messageInput && if(
chat?.input?.messageInput &&
e.target !== chat.input.messageInput && e.target !== chat.input.messageInput &&
target.tagName !== 'INPUT' && target.tagName !== 'INPUT' &&
!target.hasAttribute('contenteditable') && !target.hasAttribute('contenteditable') &&
!IS_TOUCH_SUPPORTED && !IS_TOUCH_SUPPORTED &&
(!mediaSizes.isMobile || this.tabId === 1) && (!mediaSizes.isMobile || this.tabId === 1) &&
!this.chat.selection.isSelecting && !chat.selection.isSelecting &&
!this.chat.input.recording) { !chat.input.recording
) {
chat.input.messageInput.focus(); chat.input.messageInput.focus();
placeCaretAtEnd(chat.input.messageInput); placeCaretAtEnd(chat.input.messageInput);
// clone and dispatch same event to new input. it is needed for sending message if input was blurred
const newEvent = new KeyboardEvent(e.type, e);
chat.input.messageInput.dispatchEvent(newEvent);
} }
}; };

45
src/lib/appManagers/appMessagesManager.ts

@ -1073,7 +1073,7 @@ export class AppMessagesManager {
const messages = files.map((file, idx) => { const messages = files.map((file, idx) => {
const details = options.sendFileDetails[idx]; const details = options.sendFileDetails[idx];
const o: any = { const o: Parameters<AppMessagesManager['sendFile']>[2] = {
isGroupedItem: true, isGroupedItem: true,
isMedia: options.isMedia, isMedia: options.isMedia,
scheduleDate: options.scheduleDate, scheduleDate: options.scheduleDate,
@ -1094,7 +1094,9 @@ export class AppMessagesManager {
}); });
if(options.clearDraft) { if(options.clearDraft) {
appDraftsManager.clearDraft(peerId, options.threadId); setTimeout(() => {
appDraftsManager.clearDraft(peerId, options.threadId);
}, 0);
} }
// * test pending // * test pending
@ -1407,10 +1409,6 @@ export class AppMessagesManager {
}, 0); }, 0);
} }
if(!options.isGroupedItem && options.clearDraft) {
appDraftsManager.clearDraft(peerId, options.threadId);
}
this.pendingByRandomId[message.random_id] = { this.pendingByRandomId[message.random_id] = {
peerId, peerId,
tempId: messageId, tempId: messageId,
@ -1419,9 +1417,13 @@ export class AppMessagesManager {
}; };
if(!options.isGroupedItem && message.send) { if(!options.isGroupedItem && message.send) {
setTimeout(message.send, 0); setTimeout(() => {
//setTimeout(message.send, 4000); if(options.clearDraft) {
//setTimeout(message.send, 7000); appDraftsManager.clearDraft(peerId, options.threadId);
}
message.send();
}, 0);
} }
} }
@ -1966,15 +1968,20 @@ export class AppMessagesManager {
return promise; return promise;
} }
public getMessageFromStorage(storage: MessagesStorage, mid: number) { public generateEmptyMessage(mid: number): Message.messageEmpty {
return storage && storage.get(mid) || { return {
_: 'messageEmpty', _: 'messageEmpty',
id: mid, id: appMessagesIdsManager.getServerMessageId(mid),
mid,
deleted: true, deleted: true,
pFlags: {} pFlags: {}
}; };
} }
public getMessageFromStorage(storage: MessagesStorage, mid: number) {
return storage && storage.get(mid) || this.generateEmptyMessage(mid);
}
private createMessageStorage() { private createMessageStorage() {
const storage: MessagesStorage = new Map(); const storage: MessagesStorage = new Map();
@ -5455,7 +5462,6 @@ export class AppMessagesManager {
for(const [peerId, map] of this.needSingleMessages) { for(const [peerId, map] of this.needSingleMessages) {
const mids = [...map.keys()]; const mids = [...map.keys()];
const promises = [...map.values()];
const msgIds: InputMessage[] = mids.map((mid) => { const msgIds: InputMessage[] = mids.map((mid) => {
return { return {
_: 'inputMessageID', _: 'inputMessageID',
@ -5483,8 +5489,17 @@ export class AppMessagesManager {
this.saveMessages(getMessagesResult.messages); this.saveMessages(getMessagesResult.messages);
for(let i = 0; i < getMessagesResult.messages.length; ++i) { for(let i = 0; i < getMessagesResult.messages.length; ++i) {
const promise = promises[i]; const message = getMessagesResult.messages[i];
const mid = appMessagesIdsManager.generateMessageId(message.id);
const promise = map.get(mid);
promise.resolve(getMessagesResult.messages[i]); promise.resolve(getMessagesResult.messages[i]);
map.delete(mid);
}
if(map.size) {
for(const [mid, promise] of map) {
promise.resolve(this.generateEmptyMessage(mid));
}
} }
}).finally(() => { }).finally(() => {
rootScope.dispatchEvent('messages_downloaded', {peerId, mids}); rootScope.dispatchEvent('messages_downloaded', {peerId, mids});
@ -5497,7 +5512,7 @@ export class AppMessagesManager {
Promise.all(requestPromises).finally(() => { Promise.all(requestPromises).finally(() => {
this.fetchSingleMessagesPromise = null; this.fetchSingleMessagesPromise = null;
if(Object.keys(this.needSingleMessages).length) this.fetchSingleMessages(); if(this.needSingleMessages.size) this.fetchSingleMessages();
resolve(); resolve();
}); });
}, 0); }, 0);

11
src/lib/appManagers/appWebPagesManager.ts

@ -43,6 +43,13 @@ export class AppWebPagesManager {
if(apiWebPage._ === 'webPageNotModified') return; if(apiWebPage._ === 'webPageNotModified') return;
const {id} = apiWebPage; const {id} = apiWebPage;
const oldWebPage = this.webpages[id];
if(oldWebPage &&
oldWebPage._ === apiWebPage._ &&
(oldWebPage as WebPage.webPage).hash === (oldWebPage as WebPage.webPage).hash) {
return oldWebPage;
}
if(apiWebPage._ === 'webPage') { if(apiWebPage._ === 'webPage') {
if(apiWebPage.photo?._ === 'photo') { if(apiWebPage.photo?._ === 'photo') {
apiWebPage.photo = appPhotosManager.savePhoto(apiWebPage.photo, mediaContext); apiWebPage.photo = appPhotosManager.savePhoto(apiWebPage.photo, mediaContext);
@ -97,10 +104,10 @@ export class AppWebPagesManager {
pendingSet.add(messageKey); pendingSet.add(messageKey);
} }
if(this.webpages[id] === undefined) { if(oldWebPage === undefined) {
this.webpages[id] = apiWebPage; this.webpages[id] = apiWebPage;
} else { } else {
safeReplaceObject(this.webpages[id], apiWebPage); safeReplaceObject(oldWebPage, apiWebPage);
} }
if(!messageKey && pendingSet !== undefined) { if(!messageKey && pendingSet !== undefined) {

4
src/scripts/in/schema_additional_params.json

@ -99,7 +99,9 @@
}, { }, {
"predicate": "messageEmpty", "predicate": "messageEmpty",
"params": [ "params": [
{"name": "deleted", "type": "boolean"} {"name": "deleted", "type": "boolean"},
{"name": "mid", "type": "number"},
{"name": "pFlags", "type": "{}"}
] ]
}, { }, {
"predicate": "userFull", "predicate": "userFull",

3
src/scss/partials/_chat.scss

@ -917,7 +917,8 @@ $chat-helper-size: 36px;
pointer-events: none; pointer-events: none;
@include animation-level(2) { @include animation-level(2) {
transition: height var(--layer-transition), opacity var(--layer-transition); // transition: height var(--layer-transition), opacity var(--layer-transition);
transition: height .15s ease-out, opacity .15s ease-out;
} }
@include respond-to(esg-bottom-new) { @include respond-to(esg-bottom-new) {

Loading…
Cancel
Save