diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts
index 60d0b95e..a5a623f1 100644
--- a/src/components/chat/bubbles.ts
+++ b/src/components/chat/bubbles.ts
@@ -235,9 +235,10 @@ export default class ChatBubbles {
this.bubbleGroups.removeBubble(bubble, tempId); */
if(message.media?.webpage && !bubble.querySelector('.web')) {
- const mounted = this.getMountedBubble(mid);
+ this.renderMessage(message, true, false, bubble, false);
+ /* const mounted = this.getMountedBubble(mid);
if(!mounted) return;
- this.renderMessage(mounted.message, true, false, mounted.bubble, false);
+ this.renderMessage(mounted.message, true, false, mounted.bubble, false); */
}
//delete this.bubbles[tempId];
diff --git a/src/components/chat/input.ts b/src/components/chat/input.ts
index 17fe03ac..2ab7faa9 100644
--- a/src/components/chat/input.ts
+++ b/src/components/chat/input.ts
@@ -12,7 +12,7 @@ import apiManager from "../../lib/mtproto/mtprotoworker";
import opusDecodeController from "../../lib/opusDecodeController";
import RichTextProcessor from "../../lib/richtextprocessor";
import { attachClickEvent, blurActiveElement, cancelEvent, cancelSelection, findUpClassName, getRichValue, getSelectedNodes, isInputEmpty, markdownTags, MarkdownType, placeCaretAtEnd, serializeNodes } from "../../helpers/dom";
-import { ButtonMenuItemOptions } from '../buttonMenu';
+import ButtonMenu, { ButtonMenuItemOptions } from '../buttonMenu';
import emoticonsDropdown from "../emoticonsDropdown";
import PopupCreatePoll from "../popupCreatePoll";
import PopupForward from '../popupForward';
@@ -28,6 +28,7 @@ import DivAndCaption from '../divAndCaption';
import ButtonMenuToggle from '../buttonMenuToggle';
import ListenerSetter from '../../helpers/listenerSetter';
import Button from '../button';
+import { attachContextMenuListener, openBtnMenu } from '../misc';
const RECORD_MIN_TIME = 500;
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
@@ -55,6 +56,9 @@ export default class ChatInput {
public attachMenu: HTMLButtonElement;
private attachMenuButtons: (ButtonMenuItemOptions & {verify: (peerId: number) => boolean})[];
+ public sendMenu: HTMLDivElement;
+ private sendMenuButtons: (ButtonMenuItemOptions & {verify: (peerId: number) => boolean})[];
+
public replyElements: {
container?: HTMLElement,
cancelBtn?: HTMLButtonElement,
@@ -187,6 +191,26 @@ export default class ChatInput {
this.attachMenu.classList.add('attach-file', 'tgico-attach');
this.attachMenu.classList.remove('tgico-more');
+ this.sendMenuButtons = [{
+ icon: 'mute',
+ text: 'Send Without Sound',
+ onClick: () => {
+
+ },
+ verify: (peerId: number) => true
+ }, {
+ icon: 'schedule',
+ text: 'Schedule Message',
+ onClick: () => {
+
+ },
+ verify: (peerId: number) => true
+ }];
+
+ this.sendMenu = ButtonMenu(this.sendMenuButtons, this.listenerSetter);
+ this.sendMenu.classList.add('menu-send', 'top-left');
+ //this.inputContainer.append(this.sendMenu);
+
this.recordTimeEl = document.createElement('div');
this.recordTimeEl.classList.add('record-time');
@@ -213,7 +237,16 @@ export default class ChatInput {
`);
- this.btnSendContainer.append(this.recordRippleEl, this.btnSend);
+ attachContextMenuListener(this.btnSend, (e: any) => {
+ if(this.isInputEmpty()) {
+ return;
+ }
+
+ cancelEvent(e);
+ openBtnMenu(this.sendMenu);
+ }, this.listenerSetter);
+
+ this.btnSendContainer.append(this.recordRippleEl, this.btnSend, this.sendMenu);
this.inputContainer.append(this.btnCancelRecord, this.btnSendContainer);
@@ -691,17 +724,21 @@ export default class ChatInput {
//console.log('messageInput input', this.messageInput.innerText, this.serializeNodes(Array.from(this.messageInput.childNodes)));
//const value = this.messageInput.innerText;
- const value = getRichValue(this.messageInput);
+ const richValue = getRichValue(this.messageInput);
- const entities = RichTextProcessor.parseEntities(value);
- //console.log('messageInput entities', entities);
+ //const entities = RichTextProcessor.parseEntities(value);
+ const markdownEntities: MessageEntity[] = [];
+ const value = RichTextProcessor.parseMarkdown(richValue, markdownEntities);
+ const entities = RichTextProcessor.mergeEntities(markdownEntities, RichTextProcessor.parseEntities(value));
+
+ //this.chat.log('messageInput entities', richValue, value, markdownEntities);
if(this.stickersHelper) {
let emoticon = '';
if(entities.length && entities[0]._ == 'messageEntityEmoji') {
const entity = entities[0];
- if(entity.length == value.length && !entity.offset) {
- emoticon = value;
+ if(entity.length == richValue.length && !entity.offset) {
+ emoticon = richValue;
}
}
@@ -714,16 +751,18 @@ export default class ChatInput {
this.undoHistory.length = 0;
}
- const urlEntities = entities.filter(e => e._ == 'messageEntityUrl');
+ const urlEntities: Array = entities.filter(e => e._ == 'messageEntityUrl' || e._ == 'messageEntityTextUrl') as any;
if(urlEntities.length) {
- const richEntities: MessageEntity[] = [];
- const richValue = RichTextProcessor.parseMarkdown(getRichValue(this.messageInput), richEntities);
- //console.log('messageInput url', entities, richEntities);
for(const entity of urlEntities) {
- const url = value.slice(entity.offset, entity.offset + entity.length);
+ let url: string;
+ if(entity._ === 'messageEntityTextUrl') {
+ url = entity.url;
+ } else {
+ url = richValue.slice(entity.offset, entity.offset + entity.length);
- if(!(url.includes('http://') || url.includes('https://')) && !richEntities.find(e => e._ == 'messageEntityTextUrl')) {
- continue;
+ if(!(url.includes('http://') || url.includes('https://'))) {
+ continue;
+ }
}
//console.log('messageInput url:', url);
@@ -732,7 +771,7 @@ export default class ChatInput {
this.lastUrl = url;
this.willSendWebPage = null;
apiManager.invokeApi('messages.getWebPage', {
- url: url,
+ url,
hash: 0
}).then((webpage) => {
webpage = this.appWebPagesManager.saveWebPage(webpage);
@@ -762,7 +801,7 @@ export default class ChatInput {
}
}
- if(!value.trim() && !serializeNodes(Array.from(this.messageInput.childNodes)).trim()) {
+ if(!richValue.trim() && !serializeNodes(Array.from(this.messageInput.childNodes)).trim()) {
this.messageInput.innerHTML = '';
this.appMessagesManager.setTyping(this.chat.peerId, 'sendMessageCancelAction');
diff --git a/src/components/misc.ts b/src/components/misc.ts
index f55b4abd..4a3dd647 100644
--- a/src/components/misc.ts
+++ b/src/components/misc.ts
@@ -134,7 +134,8 @@ export const closeBtnMenu = () => {
if(openedMenu) {
openedMenu.classList.remove('active');
openedMenu.parentElement.classList.remove('menu-open');
- openedMenu.previousElementSibling.remove(); // remove overlay
+ //openedMenu.previousElementSibling.remove(); // remove overlay
+ if(menuOverlay) menuOverlay.remove();
openedMenu = null;
}
@@ -165,7 +166,7 @@ window.addEventListener('resize', () => {
} */
});
-let openedMenu: HTMLElement = null, openedMenuOnClose: () => void = null;
+let openedMenu: HTMLElement = null, openedMenuOnClose: () => void = null, menuOverlay: HTMLElement = null;
export function openBtnMenu(menuElement: HTMLElement, onClose?: () => void) {
closeBtnMenu();
@@ -173,9 +174,19 @@ export function openBtnMenu(menuElement: HTMLElement, onClose?: () => void) {
openedMenu.classList.add('active');
openedMenu.parentElement.classList.add('menu-open');
- const overlay = document.createElement('div');
- overlay.classList.add('btn-menu-overlay');
- openedMenu.parentElement.insertBefore(overlay, openedMenu);
+ if(!menuOverlay) {
+ menuOverlay = document.createElement('div');
+ menuOverlay.classList.add('btn-menu-overlay');
+
+ // ! because this event must be canceled, and can't cancel on menu click (below)
+ menuOverlay.addEventListener(CLICK_EVENT_NAME, (e) => {
+ cancelEvent(e);
+ onClick(e);
+ });
+ }
+
+ openedMenu.parentElement.insertBefore(menuOverlay, openedMenu);
+
//document.body.classList.add('disable-hover');
openedMenuOnClose = onClose;
@@ -186,11 +197,11 @@ export function openBtnMenu(menuElement: HTMLElement, onClose?: () => void) {
window.addEventListener('contextmenu', onClick, {once: true});
}
- // ! because this event must be canceled, and can't cancel on menu click (below)
+ /* // ! because this event must be canceled, and can't cancel on menu click (below)
overlay.addEventListener(CLICK_EVENT_NAME, (e) => {
cancelEvent(e);
onClick(e);
- });
+ }); */
// ! safari iOS doesn't handle window click event on overlay, idk why
document.addEventListener(CLICK_EVENT_NAME, onClick);
diff --git a/src/components/sidebarRight/tabs/sharedMedia.ts b/src/components/sidebarRight/tabs/sharedMedia.ts
index 029e05ef..44d90a35 100644
--- a/src/components/sidebarRight/tabs/sharedMedia.ts
+++ b/src/components/sidebarRight/tabs/sharedMedia.ts
@@ -690,7 +690,7 @@ export default class AppSharedMediaTab implements SliderTab {
const peerId = this.peerId;
- let typesToLoad = single ? [this.sharedMediaType] : this.sharedMediaTypes.filter(t => t !== this.sharedMediaType);
+ let typesToLoad = single ? [this.sharedMediaType] : this.sharedMediaTypes.filter(t => t !== this.sharedMediaType && t !== 'inputMessagesFilterEmpty');
typesToLoad = typesToLoad.filter(type => !this.loadedAllMedia[type]
|| this.usedFromHistory[type] < this.historiesStorage[peerId][type].length);
diff --git a/src/lib/rlottie/rlottie.worker.ts b/src/lib/rlottie/rlottie.worker.ts
index 6fc6c0e3..246a5db1 100644
--- a/src/lib/rlottie/rlottie.worker.ts
+++ b/src/lib/rlottie/rlottie.worker.ts
@@ -119,6 +119,10 @@ const queryableFunctions = {
throw new Error('Invalid file');
} */
+ /* let perf = performance.now();
+ let json = JSON.parse(jsString);
+ console.log('sticker decode:', performance.now() - perf); */
+
const match = jsString.match(/"fr":\s*?(\d+?),/);
const frameRate = +match?.[1] || DEFAULT_FPS;
diff --git a/src/scss/partials/_button.scss b/src/scss/partials/_button.scss
index 631a26db..7e4ed86c 100644
--- a/src/scss/partials/_button.scss
+++ b/src/scss/partials/_button.scss
@@ -192,11 +192,14 @@
//background-color: rgba(0, 0, 0, .2);
}
- &-toggle &-overlay {
+ /* &-toggle */&-overlay {
left: -100vw;
right: -100vw;
top: -100vh;
bottom: -100vh;
+
+ width: auto !important;
+ max-width: none !important;
}
}