Search multiselect
Fix keyboard inputs on iOS Alt+ArrowUp/ArrowDown shortcut
This commit is contained in:
parent
30e923f119
commit
c2604ec14d
@ -1684,7 +1684,9 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
|||||||
onForwardClick = () => {
|
onForwardClick = () => {
|
||||||
if(this.currentMessageId) {
|
if(this.currentMessageId) {
|
||||||
//appSidebarRight.forwardTab.open([this.currentMessageId]);
|
//appSidebarRight.forwardTab.open([this.currentMessageId]);
|
||||||
new PopupForward(this.currentPeerId, [this.currentMessageId], () => {
|
new PopupForward({
|
||||||
|
[this.currentPeerId]: [this.currentMessageId]
|
||||||
|
}, () => {
|
||||||
return this.close();
|
return this.close();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import AppMediaViewer from "./appMediaViewer";
|
|||||||
import { SearchGroup, SearchGroupType } from "./appSearch";
|
import { SearchGroup, SearchGroupType } from "./appSearch";
|
||||||
import { horizontalMenu } from "./horizontalMenu";
|
import { horizontalMenu } from "./horizontalMenu";
|
||||||
import LazyLoadQueue from "./lazyLoadQueue";
|
import LazyLoadQueue from "./lazyLoadQueue";
|
||||||
import { putPreloader } from "./misc";
|
import { attachContextMenuListener, openBtnMenu, positionMenu, putPreloader } from "./misc";
|
||||||
import { ripple } from "./ripple";
|
import { ripple } from "./ripple";
|
||||||
import Scrollable, { ScrollableX } from "./scrollable";
|
import Scrollable, { ScrollableX } from "./scrollable";
|
||||||
import { wrapDocument, wrapPhoto, wrapVideo } from "./wrappers";
|
import { wrapDocument, wrapPhoto, wrapVideo } from "./wrappers";
|
||||||
@ -42,6 +42,14 @@ import { isTouchSupported } from "../helpers/touchSupport";
|
|||||||
import handleTabSwipe from "../helpers/dom/handleTabSwipe";
|
import handleTabSwipe from "../helpers/dom/handleTabSwipe";
|
||||||
import windowSize from "../helpers/windowSize";
|
import windowSize from "../helpers/windowSize";
|
||||||
import { formatPhoneNumber } from "../helpers/formatPhoneNumber";
|
import { formatPhoneNumber } from "../helpers/formatPhoneNumber";
|
||||||
|
import ButtonMenu, { ButtonMenuItemOptions } from "./buttonMenu";
|
||||||
|
import PopupForward from "./popups/forward";
|
||||||
|
import PopupDeleteMessages from "./popups/deleteMessages";
|
||||||
|
import Row from "./row";
|
||||||
|
import htmlToDocumentFragment from "../helpers/dom/htmlToDocumentFragment";
|
||||||
|
import { SearchSelection } from "./chat/selection";
|
||||||
|
import { cancelEvent } from "../helpers/dom/cancelEvent";
|
||||||
|
import { attachClickEvent, simulateClickEvent } from "../helpers/dom/clickEvent";
|
||||||
|
|
||||||
//const testScroll = false;
|
//const testScroll = false;
|
||||||
|
|
||||||
@ -69,6 +77,149 @@ export type SearchSuperMediaTab = {
|
|||||||
scroll?: {scrollTop: number, scrollHeight: number}
|
scroll?: {scrollTop: number, scrollHeight: number}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SearchContextMenu {
|
||||||
|
private buttons: (ButtonMenuItemOptions & {verify?: () => boolean, withSelection?: true})[];
|
||||||
|
private element: HTMLElement;
|
||||||
|
private target: HTMLElement;
|
||||||
|
private peerId: number;
|
||||||
|
private mid: number;
|
||||||
|
private isSelected: boolean;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private attachTo: HTMLElement,
|
||||||
|
private searchSuper: AppSearchSuper
|
||||||
|
) {
|
||||||
|
const onContextMenu = (e: MouseEvent) => {
|
||||||
|
if(this.init) {
|
||||||
|
this.init();
|
||||||
|
this.init = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let item: HTMLElement;
|
||||||
|
try {
|
||||||
|
item = findUpClassName(e.target, 'search-super-item');
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
|
if(!item) return;
|
||||||
|
|
||||||
|
if(e instanceof MouseEvent) e.preventDefault();
|
||||||
|
if(this.element.classList.contains('active')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(e instanceof MouseEvent) e.cancelBubble = true;
|
||||||
|
|
||||||
|
this.target = item;
|
||||||
|
this.peerId = +item.dataset.peerId;
|
||||||
|
this.mid = +item.dataset.mid;
|
||||||
|
this.isSelected = searchSuper.selection.isMidSelected(this.peerId, this.mid);
|
||||||
|
|
||||||
|
this.buttons.forEach(button => {
|
||||||
|
let good: boolean;
|
||||||
|
|
||||||
|
if(this.isSelected && !button.withSelection) {
|
||||||
|
good = false;
|
||||||
|
} else {
|
||||||
|
good = button.verify ? button.verify() : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.element.classList.toggle('hide', !good);
|
||||||
|
});
|
||||||
|
|
||||||
|
item.classList.add('menu-open');
|
||||||
|
|
||||||
|
positionMenu(e, this.element);
|
||||||
|
openBtnMenu(this.element, () => {
|
||||||
|
item.classList.remove('menu-open');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if(isTouchSupported) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
attachContextMenuListener(attachTo, onContextMenu as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private init() {
|
||||||
|
this.buttons = [{
|
||||||
|
icon: 'forward',
|
||||||
|
text: 'Forward',
|
||||||
|
onClick: this.onForwardClick
|
||||||
|
}, {
|
||||||
|
icon: 'forward',
|
||||||
|
text: 'Message.Context.Selection.Forward',
|
||||||
|
onClick: this.onForwardClick,
|
||||||
|
verify: () => this.isSelected &&
|
||||||
|
!this.searchSuper.selection.selectionForwardBtn.classList.contains('hide'),
|
||||||
|
withSelection: true
|
||||||
|
}, {
|
||||||
|
icon: 'message',
|
||||||
|
text: 'Message.Context.Goto',
|
||||||
|
onClick: this.onGotoClick,
|
||||||
|
withSelection: true
|
||||||
|
}, {
|
||||||
|
icon: 'select',
|
||||||
|
text: 'Message.Context.Select',
|
||||||
|
onClick: this.onSelectClick
|
||||||
|
}, {
|
||||||
|
icon: 'select',
|
||||||
|
text: 'Message.Context.Selection.Clear',
|
||||||
|
onClick: this.onClearSelectionClick,
|
||||||
|
verify: () => this.isSelected,
|
||||||
|
withSelection: true
|
||||||
|
}, {
|
||||||
|
icon: 'delete danger',
|
||||||
|
text: 'Delete',
|
||||||
|
onClick: this.onDeleteClick,
|
||||||
|
verify: () => appMessagesManager.canDeleteMessage(appMessagesManager.getMessageByPeer(this.peerId, this.mid))
|
||||||
|
}, {
|
||||||
|
icon: 'delete danger',
|
||||||
|
text: 'Message.Context.Selection.Delete',
|
||||||
|
onClick: this.onDeleteClick,
|
||||||
|
verify: () => this.isSelected && !this.searchSuper.selection.selectionDeleteBtn.classList.contains('hide'),
|
||||||
|
withSelection: true
|
||||||
|
}];
|
||||||
|
|
||||||
|
this.element = ButtonMenu(this.buttons);
|
||||||
|
this.element.classList.add('search-contextmenu', 'contextmenu');
|
||||||
|
document.getElementById('page-chats').append(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onGotoClick = () => {
|
||||||
|
rootScope.dispatchEvent('history_focus', {
|
||||||
|
peerId: this.peerId,
|
||||||
|
mid: this.mid,
|
||||||
|
threadId: this.searchSuper.searchContext.threadId
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private onForwardClick = () => {
|
||||||
|
if(this.searchSuper.selection.isSelecting) {
|
||||||
|
simulateClickEvent(this.searchSuper.selection.selectionForwardBtn);
|
||||||
|
} else {
|
||||||
|
new PopupForward({
|
||||||
|
[this.peerId]: [this.mid]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private onSelectClick = () => {
|
||||||
|
this.searchSuper.selection.toggleByElement(this.target);
|
||||||
|
};
|
||||||
|
|
||||||
|
private onClearSelectionClick = () => {
|
||||||
|
this.searchSuper.selection.cancelSelection();
|
||||||
|
};
|
||||||
|
|
||||||
|
private onDeleteClick = () => {
|
||||||
|
if(this.searchSuper.selection.isSelecting) {
|
||||||
|
simulateClickEvent(this.searchSuper.selection.selectionDeleteBtn);
|
||||||
|
} else {
|
||||||
|
new PopupDeleteMessages(this.peerId, [this.mid], 'chat');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default class AppSearchSuper {
|
export default class AppSearchSuper {
|
||||||
public tabs: {[t in SearchSuperType]: HTMLDivElement} = {} as any;
|
public tabs: {[t in SearchSuperType]: HTMLDivElement} = {} as any;
|
||||||
|
|
||||||
@ -76,8 +227,9 @@ export default class AppSearchSuper {
|
|||||||
|
|
||||||
public container: HTMLElement;
|
public container: HTMLElement;
|
||||||
public nav: HTMLElement;
|
public nav: HTMLElement;
|
||||||
private navScrollableContainer: HTMLDivElement;
|
public navScrollableContainer: HTMLDivElement;
|
||||||
private tabsContainer: HTMLElement;
|
public tabsContainer: HTMLElement;
|
||||||
|
public navScrollable: ScrollableX;
|
||||||
private tabsMenu: HTMLElement;
|
private tabsMenu: HTMLElement;
|
||||||
private prevTabId = -1;
|
private prevTabId = -1;
|
||||||
|
|
||||||
@ -88,7 +240,7 @@ export default class AppSearchSuper {
|
|||||||
public usedFromHistory: Partial<{[type in SearchSuperType]: number}> = {};
|
public usedFromHistory: Partial<{[type in SearchSuperType]: number}> = {};
|
||||||
public urlsToRevoke: string[] = [];
|
public urlsToRevoke: string[] = [];
|
||||||
|
|
||||||
private searchContext: SearchSuperContext;
|
public searchContext: SearchSuperContext;
|
||||||
public loadMutex: Promise<any> = Promise.resolve();
|
public loadMutex: Promise<any> = Promise.resolve();
|
||||||
|
|
||||||
private nextRates: Partial<{[type in SearchSuperType]: number}> = {};
|
private nextRates: Partial<{[type in SearchSuperType]: number}> = {};
|
||||||
@ -127,16 +279,23 @@ export default class AppSearchSuper {
|
|||||||
public onChangeTab?: (mediaTab: SearchSuperMediaTab) => void;
|
public onChangeTab?: (mediaTab: SearchSuperMediaTab) => void;
|
||||||
public showSender? = false;
|
public showSender? = false;
|
||||||
|
|
||||||
|
private searchContextMenu: SearchContextMenu;
|
||||||
|
public selection: SearchSelection;
|
||||||
|
|
||||||
constructor(options: Pick<AppSearchSuper, 'mediaTabs' | 'scrollable' | 'searchGroups' | 'asChatList' | 'groupByMonth' | 'hideEmptyTabs' | 'onChangeTab' | 'showSender'>) {
|
constructor(options: Pick<AppSearchSuper, 'mediaTabs' | 'scrollable' | 'searchGroups' | 'asChatList' | 'groupByMonth' | 'hideEmptyTabs' | 'onChangeTab' | 'showSender'>) {
|
||||||
safeAssign(this, options);
|
safeAssign(this, options);
|
||||||
|
|
||||||
this.container = document.createElement('div');
|
this.container = document.createElement('div');
|
||||||
this.container.classList.add('search-super');
|
this.container.classList.add('search-super');
|
||||||
|
|
||||||
|
this.searchContextMenu = new SearchContextMenu(this.container, this);
|
||||||
|
this.selection = new SearchSelection(this, appMessagesManager);
|
||||||
|
|
||||||
const navScrollableContainer = this.navScrollableContainer = document.createElement('div');
|
const navScrollableContainer = this.navScrollableContainer = document.createElement('div');
|
||||||
navScrollableContainer.classList.add('search-super-tabs-scrollable', 'menu-horizontal-scrollable', 'sticky');
|
navScrollableContainer.classList.add('search-super-tabs-scrollable', 'menu-horizontal-scrollable', 'sticky');
|
||||||
|
|
||||||
const navScrollable = new ScrollableX(navScrollableContainer);
|
const navScrollable = this.navScrollable = new ScrollableX(navScrollableContainer);
|
||||||
|
navScrollable.container.classList.add('search-super-nav-scrollable');
|
||||||
|
|
||||||
const nav = this.nav = document.createElement('nav');
|
const nav = this.nav = document.createElement('nav');
|
||||||
nav.classList.add('search-super-tabs', 'menu-horizontal-div');
|
nav.classList.add('search-super-tabs', 'menu-horizontal-div');
|
||||||
@ -285,6 +444,13 @@ export default class AppSearchSuper {
|
|||||||
this.onTransitionEnd();
|
this.onTransitionEnd();
|
||||||
}, undefined, navScrollable);
|
}, undefined, navScrollable);
|
||||||
|
|
||||||
|
attachClickEvent(this.tabsContainer, (e) => {
|
||||||
|
if(this.selection.isSelecting) {
|
||||||
|
cancelEvent(e);
|
||||||
|
this.selection.toggleByElement(findUpClassName(e.target, 'search-super-item'));
|
||||||
|
}
|
||||||
|
}, {capture: true, passive: false});
|
||||||
|
|
||||||
const onMediaClick = (className: string, targetClassName: string, inputFilter: MyInputMessagesFilter, e: MouseEvent) => {
|
const onMediaClick = (className: string, targetClassName: string, inputFilter: MyInputMessagesFilter, e: MouseEvent) => {
|
||||||
const target = findUpClassName(e.target as HTMLDivElement, className);
|
const target = findUpClassName(e.target as HTMLDivElement, className);
|
||||||
|
|
||||||
@ -314,8 +480,20 @@ export default class AppSearchSuper {
|
|||||||
.openMedia(message, targets[idx].element, 0, false, targets.slice(0, idx), targets.slice(idx + 1));
|
.openMedia(message, targets[idx].element, 0, false, targets.slice(0, idx), targets.slice(idx + 1));
|
||||||
};
|
};
|
||||||
|
|
||||||
this.tabs.inputMessagesFilterPhotoVideo.addEventListener('click', onMediaClick.bind(null, 'grid-item', 'grid-item', 'inputMessagesFilterPhotoVideo'));
|
attachClickEvent(this.tabs.inputMessagesFilterPhotoVideo, onMediaClick.bind(null, 'grid-item', 'grid-item', 'inputMessagesFilterPhotoVideo'));
|
||||||
this.tabs.inputMessagesFilterDocument.addEventListener('click', onMediaClick.bind(null, 'document-with-thumb', 'media-container', 'inputMessagesFilterDocument'));
|
attachClickEvent(this.tabs.inputMessagesFilterDocument, onMediaClick.bind(null, 'document-with-thumb', 'media-container', 'inputMessagesFilterDocument'));
|
||||||
|
|
||||||
|
attachClickEvent(this.tabs.inputMessagesFilterUrl, (e) => {
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
if(target.tagName === 'A') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const a = findUpClassName(target, 'row').querySelector('.anchor-url:last-child') as HTMLAnchorElement;
|
||||||
|
a.click();
|
||||||
|
} catch(err) {}
|
||||||
|
});
|
||||||
|
|
||||||
this.mediaTab = this.mediaTabs[0];
|
this.mediaTab = this.mediaTabs[0];
|
||||||
|
|
||||||
@ -593,7 +771,7 @@ export default class AppSearchSuper {
|
|||||||
let div = document.createElement('div');
|
let div = document.createElement('div');
|
||||||
|
|
||||||
let previewDiv = document.createElement('div');
|
let previewDiv = document.createElement('div');
|
||||||
previewDiv.classList.add('preview');
|
previewDiv.classList.add('preview', 'row-media');
|
||||||
|
|
||||||
//this.log('wrapping webpage', webpage);
|
//this.log('wrapping webpage', webpage);
|
||||||
|
|
||||||
@ -618,7 +796,19 @@ export default class AppSearchSuper {
|
|||||||
|
|
||||||
let title = webpage.rTitle || '';
|
let title = webpage.rTitle || '';
|
||||||
let subtitle = webpage.rDescription || '';
|
let subtitle = webpage.rDescription || '';
|
||||||
let url = RichTextProcessor.wrapRichText(webpage.url || '');
|
|
||||||
|
const subtitleFragment = htmlToDocumentFragment(subtitle);
|
||||||
|
const aFragment = htmlToDocumentFragment(RichTextProcessor.wrapRichText(webpage.url || ''));
|
||||||
|
const a = aFragment.firstElementChild;
|
||||||
|
if(a instanceof HTMLAnchorElement) {
|
||||||
|
a.innerText = decodeURIComponent(a.href);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(subtitleFragment.firstChild) {
|
||||||
|
subtitleFragment.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
subtitleFragment.append(a);
|
||||||
|
|
||||||
if(!title) {
|
if(!title) {
|
||||||
//title = new URL(webpage.url).hostname;
|
//title = new URL(webpage.url).hostname;
|
||||||
@ -632,18 +822,32 @@ export default class AppSearchSuper {
|
|||||||
titleAdditionHTML = `<div class="sent-time">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;
|
titleAdditionHTML = `<div class="sent-time">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const row = new Row({
|
||||||
|
title,
|
||||||
|
titleRight: titleAdditionHTML,
|
||||||
|
subtitle: subtitleFragment,
|
||||||
|
havePadding: true,
|
||||||
|
clickable: true,
|
||||||
|
noRipple: true
|
||||||
|
});
|
||||||
|
|
||||||
|
/* const mediaDiv = document.createElement('div');
|
||||||
|
mediaDiv.classList.add('row-media'); */
|
||||||
|
|
||||||
|
row.container.append(previewDiv);
|
||||||
|
|
||||||
|
/* ripple(div);
|
||||||
div.append(previewDiv);
|
div.append(previewDiv);
|
||||||
div.insertAdjacentHTML('beforeend', `
|
div.insertAdjacentHTML('beforeend', `
|
||||||
<div class="title">${title}${titleAdditionHTML}</div>
|
<div class="title">${title}${titleAdditionHTML}</div>
|
||||||
<div class="subtitle">${subtitle}</div>
|
<div class="subtitle">${subtitle}</div>
|
||||||
<div class="url">${url}</div>
|
<div class="url">${url}</div>
|
||||||
${sender}
|
${sender}
|
||||||
`);
|
`); */
|
||||||
|
|
||||||
if(div.innerText.trim().length) {
|
if(row.container.innerText.trim().length) {
|
||||||
elemsToAppend.push({element: div, message});
|
elemsToAppend.push({element: row.container, message});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -675,6 +879,10 @@ export default class AppSearchSuper {
|
|||||||
element.dataset.mid = '' + message.mid;
|
element.dataset.mid = '' + message.mid;
|
||||||
element.dataset.peerId = '' + message.peerId;
|
element.dataset.peerId = '' + message.peerId;
|
||||||
monthContainer.items[method](element);
|
monthContainer.items[method](element);
|
||||||
|
|
||||||
|
if(this.selection.isSelecting) {
|
||||||
|
this.selection.toggleElementCheckbox(element, true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1245,6 +1453,10 @@ export default class AppSearchSuper {
|
|||||||
this.usedFromHistory[mediaTab.inputFilter] = -1;
|
this.usedFromHistory[mediaTab.inputFilter] = -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(this.selection.isSelecting) {
|
||||||
|
this.selection.cancelSelection();
|
||||||
|
}
|
||||||
|
|
||||||
// * must go to first tab (это костыль)
|
// * must go to first tab (это костыль)
|
||||||
/* const membersTab = this.mediaTabsMap.get('members');
|
/* const membersTab = this.mediaTabsMap.get('members');
|
||||||
if(membersTab) {
|
if(membersTab) {
|
||||||
|
@ -439,6 +439,7 @@ export default class ChatBubbles {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// attachClickEvent(this.bubblesContainer, this.onBubblesClick, {listenerSetter: this.listenerSetter});
|
||||||
this.listenerSetter.add(this.bubblesContainer)('click', this.onBubblesClick/* , {capture: true, passive: false} */);
|
this.listenerSetter.add(this.bubblesContainer)('click', this.onBubblesClick/* , {capture: true, passive: false} */);
|
||||||
|
|
||||||
if(DEBUG) {
|
if(DEBUG) {
|
||||||
@ -865,7 +866,7 @@ export default class ChatBubbles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!isTouchSupported && findUpClassName(target, 'time')) {
|
if(!isTouchSupported && findUpClassName(target, 'time')) {
|
||||||
this.chat.selection.toggleByBubble(bubble);
|
this.chat.selection.toggleByElement(bubble);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -884,7 +885,7 @@ export default class ChatBubbles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//this.chatSelection.toggleByBubble(bubble);
|
//this.chatSelection.toggleByBubble(bubble);
|
||||||
this.chat.selection.toggleByBubble(findUpClassName(target, 'grouped-item') || bubble);
|
this.chat.selection.toggleByElement(findUpClassName(target, 'grouped-item') || bubble);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1076,7 +1077,9 @@ export default class ChatBubbles {
|
|||||||
} else if(target.classList.contains('forward')) {
|
} else if(target.classList.contains('forward')) {
|
||||||
const mid = +bubble.dataset.mid;
|
const mid = +bubble.dataset.mid;
|
||||||
const message = this.appMessagesManager.getMessageByPeer(this.peerId, mid);
|
const message = this.appMessagesManager.getMessageByPeer(this.peerId, mid);
|
||||||
new PopupForward(this.peerId, this.appMessagesManager.getMidsByMessage(message));
|
new PopupForward({
|
||||||
|
[this.peerId]: this.appMessagesManager.getMidsByMessage(message)
|
||||||
|
});
|
||||||
//appSidebarRight.forwardTab.open([mid]);
|
//appSidebarRight.forwardTab.open([mid]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1390,7 +1393,7 @@ export default class ChatBubbles {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if(permanent && this.chat.selection.isSelecting) {
|
if(permanent && this.chat.selection.isSelecting) {
|
||||||
this.chat.selection.deleteSelectedMids(mids);
|
this.chat.selection.deleteSelectedMids(this.peerId, mids);
|
||||||
}
|
}
|
||||||
|
|
||||||
animationIntersector.checkAnimations(false, CHAT_ANIMATION_GROUP);
|
animationIntersector.checkAnimations(false, CHAT_ANIMATION_GROUP);
|
||||||
@ -2213,6 +2216,7 @@ export default class ChatBubbles {
|
|||||||
// ! reset due to album edit or delete item
|
// ! reset due to album edit or delete item
|
||||||
this.bubbles[+message.mid] = bubble;
|
this.bubbles[+message.mid] = bubble;
|
||||||
bubble.dataset.mid = message.mid;
|
bubble.dataset.mid = message.mid;
|
||||||
|
bubble.dataset.peerId = '' + message.peerId;
|
||||||
bubble.dataset.timestamp = message.date;
|
bubble.dataset.timestamp = message.date;
|
||||||
|
|
||||||
const loadPromises: Promise<any>[] = [];
|
const loadPromises: Promise<any>[] = [];
|
||||||
@ -2281,7 +2285,7 @@ export default class ChatBubbles {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let canHaveTail = true;
|
let canHaveTail = true;
|
||||||
|
let isStandaloneMedia = false;
|
||||||
let needToSetHTML = true;
|
let needToSetHTML = true;
|
||||||
if(totalEntities && !messageMedia) {
|
if(totalEntities && !messageMedia) {
|
||||||
let emojiEntities = totalEntities.filter((e) => e._ === 'messageEntityEmoji');
|
let emojiEntities = totalEntities.filter((e) => e._ === 'messageEntityEmoji');
|
||||||
@ -2308,6 +2312,7 @@ export default class ChatBubbles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bubble.classList.add('is-message-empty', 'emoji-big');
|
bubble.classList.add('is-message-empty', 'emoji-big');
|
||||||
|
isStandaloneMedia = true;
|
||||||
canHaveTail = false;
|
canHaveTail = false;
|
||||||
needToSetHTML = false;
|
needToSetHTML = false;
|
||||||
}
|
}
|
||||||
@ -2391,7 +2396,9 @@ export default class ChatBubbles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new Promise<number>((resolve, reject) => {
|
return new Promise<number>((resolve, reject) => {
|
||||||
new PopupForward(this.peerId, [], (peerId) => {
|
new PopupForward({
|
||||||
|
[this.peerId]: []
|
||||||
|
}, (peerId) => {
|
||||||
resolve(peerId);
|
resolve(peerId);
|
||||||
}, () => {
|
}, () => {
|
||||||
reject();
|
reject();
|
||||||
@ -2468,8 +2475,6 @@ export default class ChatBubbles {
|
|||||||
const isOut = our && (!message.fwd_from || this.peerId !== rootScope.myId);
|
const isOut = our && (!message.fwd_from || this.peerId !== rootScope.myId);
|
||||||
let nameContainer: HTMLElement = bubbleContainer;
|
let nameContainer: HTMLElement = bubbleContainer;
|
||||||
|
|
||||||
let isStandaloneMedia = false;
|
|
||||||
|
|
||||||
// media
|
// media
|
||||||
if(messageMedia/* && messageMedia._ === 'messageMediaPhoto' */) {
|
if(messageMedia/* && messageMedia._ === 'messageMediaPhoto' */) {
|
||||||
let attachmentDiv = document.createElement('div');
|
let attachmentDiv = document.createElement('div');
|
||||||
@ -2856,7 +2861,7 @@ export default class ChatBubbles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(this.chat.selection.isSelecting) {
|
if(this.chat.selection.isSelecting) {
|
||||||
this.chat.selection.toggleBubbleCheckbox(bubble, true);
|
this.chat.selection.toggleElementCheckbox(bubble, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
let savedFrom = '';
|
let savedFrom = '';
|
||||||
|
@ -19,11 +19,10 @@ import PopupPinMessage from "../popups/unpinMessage";
|
|||||||
import { copyTextToClipboard } from "../../helpers/clipboard";
|
import { copyTextToClipboard } from "../../helpers/clipboard";
|
||||||
import PopupSendNow from "../popups/sendNow";
|
import PopupSendNow from "../popups/sendNow";
|
||||||
import { toast } from "../toast";
|
import { toast } from "../toast";
|
||||||
import I18n, { i18n, LangPackKey } from "../../lib/langPack";
|
import I18n, { LangPackKey } from "../../lib/langPack";
|
||||||
import findUpClassName from "../../helpers/dom/findUpClassName";
|
import findUpClassName from "../../helpers/dom/findUpClassName";
|
||||||
import { cancelEvent } from "../../helpers/dom/cancelEvent";
|
import { cancelEvent } from "../../helpers/dom/cancelEvent";
|
||||||
import cancelSelection from "../../helpers/dom/cancelSelection";
|
import { attachClickEvent, simulateClickEvent } from "../../helpers/dom/clickEvent";
|
||||||
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
|
||||||
import isSelectionEmpty from "../../helpers/dom/isSelectionEmpty";
|
import isSelectionEmpty from "../../helpers/dom/isSelectionEmpty";
|
||||||
import { Message } from "../../layer";
|
import { Message } from "../../layer";
|
||||||
import PopupReportMessages from "../popups/reportMessages";
|
import PopupReportMessages from "../popups/reportMessages";
|
||||||
@ -33,6 +32,7 @@ export default class ChatContextMenu {
|
|||||||
private element: HTMLElement;
|
private element: HTMLElement;
|
||||||
|
|
||||||
private isSelectable: boolean;
|
private isSelectable: boolean;
|
||||||
|
private isSelected: boolean;
|
||||||
private target: HTMLElement;
|
private target: HTMLElement;
|
||||||
private isTargetAGroupedItem: boolean;
|
private isTargetAGroupedItem: boolean;
|
||||||
private isTextSelected: boolean;
|
private isTextSelected: boolean;
|
||||||
@ -75,17 +75,6 @@ export default class ChatContextMenu {
|
|||||||
let mid = +bubble.dataset.mid;
|
let mid = +bubble.dataset.mid;
|
||||||
if(!mid) return;
|
if(!mid) return;
|
||||||
|
|
||||||
// * если открыть контекстное меню для альбома не по бабблу, и последний элемент не выбран, чтобы показать остальные пункты
|
|
||||||
if(chat.selection.isSelecting && !contentWrapper) {
|
|
||||||
const mids = this.chat.getMidsByMid(mid);
|
|
||||||
if(mids.length > 1) {
|
|
||||||
const selectedMid = chat.selection.selectedMids.has(mid) ? mid : mids.find(mid => chat.selection.selectedMids.has(mid));
|
|
||||||
if(selectedMid) {
|
|
||||||
mid = selectedMid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isSelectable = this.chat.selection.canSelectBubble(bubble);
|
this.isSelectable = this.chat.selection.canSelectBubble(bubble);
|
||||||
this.peerId = this.chat.peerId;
|
this.peerId = this.chat.peerId;
|
||||||
//this.msgID = msgID;
|
//this.msgID = msgID;
|
||||||
@ -97,6 +86,19 @@ export default class ChatContextMenu {
|
|||||||
);
|
);
|
||||||
this.isUsernameTarget = this.target.tagName === 'A' && this.target.classList.contains('mention');
|
this.isUsernameTarget = this.target.tagName === 'A' && this.target.classList.contains('mention');
|
||||||
|
|
||||||
|
// * если открыть контекстное меню для альбома не по бабблу, и последний элемент не выбран, чтобы показать остальные пункты
|
||||||
|
if(chat.selection.isSelecting && !contentWrapper) {
|
||||||
|
const mids = this.chat.getMidsByMid(mid);
|
||||||
|
if(mids.length > 1) {
|
||||||
|
const selectedMid = this.chat.selection.isMidSelected(this.peerId, mid) ?
|
||||||
|
mid :
|
||||||
|
mids.find(mid => this.chat.selection.isMidSelected(this.peerId, mid));
|
||||||
|
if(selectedMid) {
|
||||||
|
mid = selectedMid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const groupedItem = findUpClassName(this.target, 'grouped-item');
|
const groupedItem = findUpClassName(this.target, 'grouped-item');
|
||||||
this.isTargetAGroupedItem = !!groupedItem;
|
this.isTargetAGroupedItem = !!groupedItem;
|
||||||
if(groupedItem) {
|
if(groupedItem) {
|
||||||
@ -105,6 +107,7 @@ export default class ChatContextMenu {
|
|||||||
this.mid = mid;
|
this.mid = mid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isSelected = this.chat.selection.isMidSelected(this.peerId, this.mid);
|
||||||
this.message = this.chat.getMessage(this.mid);
|
this.message = this.chat.getMessage(this.mid);
|
||||||
|
|
||||||
this.buttons.forEach(button => {
|
this.buttons.forEach(button => {
|
||||||
@ -147,29 +150,10 @@ export default class ChatContextMenu {
|
|||||||
if(good) {
|
if(good) {
|
||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
//onContextMenu((e as TouchEvent).changedTouches[0]);
|
//onContextMenu((e as TouchEvent).changedTouches[0]);
|
||||||
onContextMenu((e as TouchEvent).changedTouches ? (e as TouchEvent).changedTouches[0] : e as MouseEvent);
|
// onContextMenu((e as TouchEvent).changedTouches ? (e as TouchEvent).changedTouches[0] : e as MouseEvent);
|
||||||
|
onContextMenu(e);
|
||||||
}
|
}
|
||||||
}, {listenerSetter: this.chat.bubbles.listenerSetter});
|
}, {listenerSetter: this.chat.bubbles.listenerSetter});
|
||||||
|
|
||||||
attachContextMenuListener(attachTo, (e) => {
|
|
||||||
if(chat.selection.isSelecting) return;
|
|
||||||
|
|
||||||
// * these two lines will fix instant text selection on iOS Safari
|
|
||||||
document.body.classList.add('no-select'); // * need no-select on body because chat-input transforms in channels
|
|
||||||
attachTo.addEventListener('touchend', (e) => {
|
|
||||||
cancelEvent(e); // ! this one will fix propagation to document loader button, etc
|
|
||||||
document.body.classList.remove('no-select');
|
|
||||||
|
|
||||||
//this.chat.bubbles.onBubblesClick(e);
|
|
||||||
}, {once: true, capture: true});
|
|
||||||
|
|
||||||
cancelSelection();
|
|
||||||
//cancelEvent(e as any);
|
|
||||||
const bubble = findUpClassName(e.target, 'grouped-item') || findUpClassName(e.target, 'bubble');
|
|
||||||
if(bubble) {
|
|
||||||
chat.selection.toggleByBubble(bubble);
|
|
||||||
}
|
|
||||||
}, this.chat.bubbles.listenerSetter);
|
|
||||||
} else attachContextMenuListener(attachTo, onContextMenu, this.chat.bubbles.listenerSetter);
|
} else attachContextMenuListener(attachTo, onContextMenu, this.chat.bubbles.listenerSetter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +167,7 @@ export default class ChatContextMenu {
|
|||||||
icon: 'send2',
|
icon: 'send2',
|
||||||
text: 'Message.Context.Selection.SendNow',
|
text: 'Message.Context.Selection.SendNow',
|
||||||
onClick: this.onSendScheduledClick,
|
onClick: this.onSendScheduledClick,
|
||||||
verify: () => this.chat.type === 'scheduled' && this.chat.selection.selectedMids.has(this.mid) && !this.chat.selection.selectionSendNowBtn.hasAttribute('disabled'),
|
verify: () => this.chat.type === 'scheduled' && this.isSelected && !this.chat.selection.selectionSendNowBtn.hasAttribute('disabled'),
|
||||||
notDirect: () => true,
|
notDirect: () => true,
|
||||||
withSelection: true
|
withSelection: true
|
||||||
}, {
|
}, {
|
||||||
@ -228,7 +212,21 @@ export default class ChatContextMenu {
|
|||||||
icon: 'copy',
|
icon: 'copy',
|
||||||
text: 'Message.Context.Selection.Copy',
|
text: 'Message.Context.Selection.Copy',
|
||||||
onClick: this.onCopyClick,
|
onClick: this.onCopyClick,
|
||||||
verify: () => this.chat.selection.selectedMids.has(this.mid) && !![...this.chat.selection.selectedMids].find(mid => !!this.chat.getMessage(mid).message),
|
verify: () => {
|
||||||
|
if(!this.isSelected) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const [peerId, mids] of this.chat.selection.selectedMids) {
|
||||||
|
for(const mid of mids) {
|
||||||
|
if(!!this.appMessagesManager.getMessageByPeer(peerId, mid).message) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
notDirect: () => true,
|
notDirect: () => true,
|
||||||
withSelection: true
|
withSelection: true
|
||||||
}, {
|
}, {
|
||||||
@ -319,7 +317,7 @@ export default class ChatContextMenu {
|
|||||||
text: 'Message.Context.Selection.Forward',
|
text: 'Message.Context.Selection.Forward',
|
||||||
onClick: this.onForwardClick,
|
onClick: this.onForwardClick,
|
||||||
verify: () => this.chat.selection.selectionForwardBtn &&
|
verify: () => this.chat.selection.selectionForwardBtn &&
|
||||||
this.chat.selection.selectedMids.has(this.mid) &&
|
this.isSelected &&
|
||||||
!this.chat.selection.selectionForwardBtn.hasAttribute('disabled'),
|
!this.chat.selection.selectionForwardBtn.hasAttribute('disabled'),
|
||||||
notDirect: () => true,
|
notDirect: () => true,
|
||||||
withSelection: true
|
withSelection: true
|
||||||
@ -336,14 +334,14 @@ export default class ChatContextMenu {
|
|||||||
icon: 'select',
|
icon: 'select',
|
||||||
text: 'Message.Context.Select',
|
text: 'Message.Context.Select',
|
||||||
onClick: this.onSelectClick,
|
onClick: this.onSelectClick,
|
||||||
verify: () => !this.message.action && !this.chat.selection.selectedMids.has(this.mid) && this.isSelectable,
|
verify: () => !this.message.action && !this.isSelected && this.isSelectable,
|
||||||
notDirect: () => true,
|
notDirect: () => true,
|
||||||
withSelection: true
|
withSelection: true
|
||||||
}, {
|
}, {
|
||||||
icon: 'select',
|
icon: 'select',
|
||||||
text: 'Message.Context.Selection.Clear',
|
text: 'Message.Context.Selection.Clear',
|
||||||
onClick: this.onClearSelectionClick,
|
onClick: this.onClearSelectionClick,
|
||||||
verify: () => this.chat.selection.selectedMids.has(this.mid),
|
verify: () => this.isSelected,
|
||||||
notDirect: () => true,
|
notDirect: () => true,
|
||||||
withSelection: true
|
withSelection: true
|
||||||
}, {
|
}, {
|
||||||
@ -355,7 +353,7 @@ export default class ChatContextMenu {
|
|||||||
icon: 'delete danger',
|
icon: 'delete danger',
|
||||||
text: 'Message.Context.Selection.Delete',
|
text: 'Message.Context.Selection.Delete',
|
||||||
onClick: this.onDeleteClick,
|
onClick: this.onDeleteClick,
|
||||||
verify: () => this.chat.selection.selectedMids.has(this.mid) && !this.chat.selection.selectionDeleteBtn.hasAttribute('disabled'),
|
verify: () => this.isSelected && !this.chat.selection.selectionDeleteBtn.hasAttribute('disabled'),
|
||||||
notDirect: () => true,
|
notDirect: () => true,
|
||||||
withSelection: true
|
withSelection: true
|
||||||
}];
|
}];
|
||||||
@ -364,11 +362,11 @@ export default class ChatContextMenu {
|
|||||||
this.element.id = 'bubble-contextmenu';
|
this.element.id = 'bubble-contextmenu';
|
||||||
this.element.classList.add('contextmenu');
|
this.element.classList.add('contextmenu');
|
||||||
this.chat.container.append(this.element);
|
this.chat.container.append(this.element);
|
||||||
};
|
}
|
||||||
|
|
||||||
private onSendScheduledClick = () => {
|
private onSendScheduledClick = () => {
|
||||||
if(this.chat.selection.isSelecting) {
|
if(this.chat.selection.isSelecting) {
|
||||||
this.chat.selection.selectionSendNowBtn.click();
|
simulateClickEvent(this.chat.selection.selectionSendNowBtn);
|
||||||
} else {
|
} else {
|
||||||
new PopupSendNow(this.peerId, this.chat.getMidsByMid(this.mid));
|
new PopupSendNow(this.peerId, this.chat.getMidsByMid(this.mid));
|
||||||
}
|
}
|
||||||
@ -384,11 +382,15 @@ export default class ChatContextMenu {
|
|||||||
|
|
||||||
private onCopyClick = () => {
|
private onCopyClick = () => {
|
||||||
if(isSelectionEmpty()) {
|
if(isSelectionEmpty()) {
|
||||||
const mids = this.chat.selection.isSelecting ? [...this.chat.selection.selectedMids].sort((a, b) => a - b) : [this.mid];
|
const mids = this.chat.selection.isSelecting ?
|
||||||
|
[...this.chat.selection.selectedMids.get(this.peerId)].sort((a, b) => a - b) :
|
||||||
|
[this.mid];
|
||||||
|
|
||||||
const str = mids.reduce((acc, mid) => {
|
const str = mids.reduce((acc, mid) => {
|
||||||
const message = this.chat.getMessage(mid);
|
const message = this.chat.getMessage(mid);
|
||||||
return acc + (message?.message ? message.message + '\n' : '');
|
return acc + (message?.message ? message.message + '\n' : '');
|
||||||
}, '').trim();
|
}, '').trim();
|
||||||
|
|
||||||
copyTextToClipboard(str);
|
copyTextToClipboard(str);
|
||||||
} else {
|
} else {
|
||||||
document.execCommand('copy');
|
document.execCommand('copy');
|
||||||
@ -443,14 +445,17 @@ export default class ChatContextMenu {
|
|||||||
|
|
||||||
private onForwardClick = () => {
|
private onForwardClick = () => {
|
||||||
if(this.chat.selection.isSelecting) {
|
if(this.chat.selection.isSelecting) {
|
||||||
this.chat.selection.selectionForwardBtn.click();
|
simulateClickEvent(this.chat.selection.selectionForwardBtn);
|
||||||
} else {
|
} else {
|
||||||
new PopupForward(this.peerId, this.isTargetAGroupedItem ? [this.mid] : this.chat.getMidsByMid(this.mid));
|
const mids = this.isTargetAGroupedItem ? [this.mid] : this.chat.getMidsByMid(this.mid);
|
||||||
|
new PopupForward({
|
||||||
|
[this.peerId]: mids
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private onSelectClick = () => {
|
private onSelectClick = () => {
|
||||||
this.chat.selection.toggleByBubble(findUpClassName(this.target, 'grouped-item') || findUpClassName(this.target, 'bubble'));
|
this.chat.selection.toggleByElement(findUpClassName(this.target, 'grouped-item') || findUpClassName(this.target, 'bubble'));
|
||||||
};
|
};
|
||||||
|
|
||||||
private onClearSelectionClick = () => {
|
private onClearSelectionClick = () => {
|
||||||
@ -459,7 +464,7 @@ export default class ChatContextMenu {
|
|||||||
|
|
||||||
private onDeleteClick = () => {
|
private onDeleteClick = () => {
|
||||||
if(this.chat.selection.isSelecting) {
|
if(this.chat.selection.isSelecting) {
|
||||||
this.chat.selection.selectionDeleteBtn.click();
|
simulateClickEvent(this.chat.selection.selectionDeleteBtn);
|
||||||
} else {
|
} else {
|
||||||
new PopupDeleteMessages(this.peerId, this.isTargetAGroupedItem ? [this.mid] : this.chat.getMidsByMid(this.mid), this.chat.type);
|
new PopupDeleteMessages(this.peerId, this.isTargetAGroupedItem ? [this.mid] : this.chat.getMidsByMid(this.mid), this.chat.type);
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,7 @@ import PeerTitle from '../peerTitle';
|
|||||||
import { fastRaf } from '../../helpers/schedulers';
|
import { fastRaf } from '../../helpers/schedulers';
|
||||||
import PopupDeleteMessages from '../popups/deleteMessages';
|
import PopupDeleteMessages from '../popups/deleteMessages';
|
||||||
import fixSafariStickyInputFocusing, { IS_STICKY_INPUT_BUGGED } from '../../helpers/dom/fixSafariStickyInputFocusing';
|
import fixSafariStickyInputFocusing, { IS_STICKY_INPUT_BUGGED } from '../../helpers/dom/fixSafariStickyInputFocusing';
|
||||||
|
import { copy } from '../../helpers/object';
|
||||||
|
|
||||||
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.';
|
||||||
@ -117,8 +118,7 @@ export default class ChatInput {
|
|||||||
|
|
||||||
private getWebPagePromise: Promise<void>;
|
private getWebPagePromise: Promise<void>;
|
||||||
private willSendWebPage: WebPage = null;
|
private willSendWebPage: WebPage = null;
|
||||||
private forwardingMids: number[] = [];
|
private forwarding: {[fromPeerId: number]: number[]};
|
||||||
private forwardingFromPeerId: number = 0;
|
|
||||||
public replyToMsgId: number;
|
public replyToMsgId: number;
|
||||||
public editMsgId: number;
|
public editMsgId: number;
|
||||||
private noWebPage: true;
|
private noWebPage: true;
|
||||||
@ -1402,7 +1402,7 @@ export default class ChatInput {
|
|||||||
private onBtnSendClick = (e: Event) => {
|
private onBtnSendClick = (e: Event) => {
|
||||||
cancelEvent(e);
|
cancelEvent(e);
|
||||||
|
|
||||||
if(!this.recorder || this.recording || !this.isInputEmpty() || this.forwardingMids.length || this.editMsgId) {
|
if(!this.recorder || this.recording || !this.isInputEmpty() || this.forwarding || this.editMsgId) {
|
||||||
if(this.recording) {
|
if(this.recording) {
|
||||||
if((Date.now() - this.recordStartTime) < RECORD_MIN_TIME) {
|
if((Date.now() - this.recordStartTime) < RECORD_MIN_TIME) {
|
||||||
this.onCancelRecordClick();
|
this.onCancelRecordClick();
|
||||||
@ -1526,13 +1526,11 @@ export default class ChatInput {
|
|||||||
if(this.helperWaitingForward) return;
|
if(this.helperWaitingForward) return;
|
||||||
this.helperWaitingForward = true;
|
this.helperWaitingForward = true;
|
||||||
|
|
||||||
const fromId = this.forwardingFromPeerId;
|
|
||||||
const mids = this.forwardingMids.slice();
|
|
||||||
const helperFunc = this.helperFunc;
|
const helperFunc = this.helperFunc;
|
||||||
this.clearHelper();
|
this.clearHelper();
|
||||||
this.updateSendBtn();
|
this.updateSendBtn();
|
||||||
let selected = false;
|
let selected = false;
|
||||||
new PopupForward(fromId, mids, () => {
|
new PopupForward(copy(this.forwarding), () => {
|
||||||
selected = true;
|
selected = true;
|
||||||
}, () => {
|
}, () => {
|
||||||
this.helperWaitingForward = false;
|
this.helperWaitingForward = false;
|
||||||
@ -1593,7 +1591,7 @@ export default class ChatInput {
|
|||||||
const isInputEmpty = this.isInputEmpty();
|
const isInputEmpty = this.isInputEmpty();
|
||||||
|
|
||||||
if(this.editMsgId) icon = 'edit';
|
if(this.editMsgId) icon = 'edit';
|
||||||
else if(!this.recorder || this.recording || !isInputEmpty || this.forwardingMids.length) icon = this.chat.type === 'scheduled' ? 'schedule' : 'send';
|
else if(!this.recorder || this.recording || !isInputEmpty || this.forwarding) icon = this.chat.type === 'scheduled' ? 'schedule' : 'send';
|
||||||
else icon = 'record';
|
else icon = 'record';
|
||||||
|
|
||||||
['send', 'record', 'edit', 'schedule'].forEach(i => {
|
['send', 'record', 'edit', 'schedule'].forEach(i => {
|
||||||
@ -1673,17 +1671,18 @@ export default class ChatInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// * wait for sendText set messageId for invokeAfterMsg
|
// * wait for sendText set messageId for invokeAfterMsg
|
||||||
if(this.forwardingMids.length) {
|
if(this.forwarding) {
|
||||||
const mids = this.forwardingMids.slice();
|
const forwarding = copy(this.forwarding);
|
||||||
const fromPeerId = this.forwardingFromPeerId;
|
|
||||||
const peerId = this.chat.peerId;
|
const peerId = this.chat.peerId;
|
||||||
const silent = this.sendSilent;
|
const silent = this.sendSilent;
|
||||||
const scheduleDate = this.scheduleDate;
|
const scheduleDate = this.scheduleDate;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.appMessagesManager.forwardMessages(peerId, fromPeerId, mids, {
|
for(const fromPeerId in forwarding) {
|
||||||
silent,
|
this.appMessagesManager.forwardMessages(peerId, +fromPeerId, forwarding[fromPeerId], {
|
||||||
scheduleDate: scheduleDate
|
silent,
|
||||||
});
|
scheduleDate: scheduleDate
|
||||||
|
});
|
||||||
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1751,17 +1750,26 @@ export default class ChatInput {
|
|||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
|
|
||||||
public initMessagesForward(fromPeerId: number, mids: number[]) {
|
public initMessagesForward(fromPeerIdsMids: {[fromPeerId: number]: number[]}) {
|
||||||
const f = () => {
|
const f = () => {
|
||||||
//const peerTitles: string[]
|
//const peerTitles: string[]
|
||||||
const smth: Set<string | number> = new Set(mids.map(mid => {
|
const fromPeerIds = Object.keys(fromPeerIdsMids).map(str => +str);
|
||||||
const message = this.appMessagesManager.getMessageByPeer(fromPeerId, mid);
|
const smth: Set<string | number> = new Set();
|
||||||
if(message.fwd_from && message.fwd_from.from_name && !message.fromId && !message.fwdFromId) {
|
let length = 0;
|
||||||
return message.fwd_from.from_name;
|
|
||||||
} else {
|
fromPeerIds.forEach(fromPeerId => {
|
||||||
return message.fromId;
|
const mids = fromPeerIdsMids[fromPeerId];
|
||||||
}
|
mids.forEach(mid => {
|
||||||
}));
|
const message = this.appMessagesManager.getMessageByPeer(fromPeerId, mid);
|
||||||
|
if(message.fwd_from?.from_name && !message.fromId && !message.fwdFromId) {
|
||||||
|
smth.add(message.fwd_from.from_name);
|
||||||
|
} else {
|
||||||
|
smth.add(message.fromId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
length += mids.length;
|
||||||
|
});
|
||||||
|
|
||||||
const onlyFirstName = smth.size > 2;
|
const onlyFirstName = smth.size > 2;
|
||||||
const peerTitles = [...smth].map(smth => {
|
const peerTitles = [...smth].map(smth => {
|
||||||
@ -1777,25 +1785,30 @@ export default class ChatInput {
|
|||||||
title.append(peerTitles[0], i18n('AndOther', [peerTitles.length - 1]));
|
title.append(peerTitles[0], i18n('AndOther', [peerTitles.length - 1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstMessage = this.appMessagesManager.getMessageByPeer(fromPeerId, mids[0]);
|
let firstMessage: any, usingFullAlbum: boolean;
|
||||||
|
if(fromPeerIds.length === 1) {
|
||||||
|
const fromPeerId = fromPeerIds[0];
|
||||||
|
const mids = fromPeerIdsMids[fromPeerId];
|
||||||
|
firstMessage = this.appMessagesManager.getMessageByPeer(fromPeerId, mids[0]);
|
||||||
|
|
||||||
let usingFullAlbum = !!firstMessage.grouped_id;
|
usingFullAlbum = !!firstMessage.grouped_id;
|
||||||
if(firstMessage.grouped_id) {
|
if(usingFullAlbum) {
|
||||||
const albumMids = this.appMessagesManager.getMidsByMessage(firstMessage);
|
const albumMids = this.appMessagesManager.getMidsByMessage(firstMessage);
|
||||||
if(albumMids.length !== mids.length || albumMids.find(mid => !mids.includes(mid))) {
|
if(albumMids.length !== length || albumMids.find(mid => !mids.includes(mid))) {
|
||||||
usingFullAlbum = false;
|
usingFullAlbum = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const replyFragment = this.appMessagesManager.wrapMessageForReply(firstMessage, undefined, mids);
|
if(usingFullAlbum || length === 1) {
|
||||||
if(usingFullAlbum || mids.length === 1) {
|
const mids = fromPeerIdsMids[fromPeerIds[0]];
|
||||||
|
const replyFragment = this.appMessagesManager.wrapMessageForReply(firstMessage, undefined, mids);
|
||||||
this.setTopInfo('forward', f, title, replyFragment);
|
this.setTopInfo('forward', f, title, replyFragment);
|
||||||
} else {
|
} else {
|
||||||
this.setTopInfo('forward', f, title, i18n('ForwardedMessageCount', [mids.length]));
|
this.setTopInfo('forward', f, title, i18n('ForwardedMessageCount', [length]));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.forwardingMids = mids.slice();
|
this.forwarding = fromPeerIdsMids;
|
||||||
this.forwardingFromPeerId = fromPeerId;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
f();
|
f();
|
||||||
@ -1845,8 +1858,7 @@ export default class ChatInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.replyToMsgId = undefined;
|
this.replyToMsgId = undefined;
|
||||||
this.forwardingMids.length = 0;
|
this.forwarding = undefined;
|
||||||
this.forwardingFromPeerId = 0;
|
|
||||||
this.editMsgId = undefined;
|
this.editMsgId = undefined;
|
||||||
this.helperType = this.helperFunc = undefined;
|
this.helperType = this.helperFunc = undefined;
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ export function wrapReplyDivAndCaption(options: {
|
|||||||
media = media.webpage;
|
media = media.webpage;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(media.photo || (media.document && ['video', 'sticker', 'gif', 'round'].indexOf(media.document.type) !== -1)) {
|
if(media.photo || (media.document && ['video', 'sticker', 'gif', 'round', 'photo'].indexOf(media.document.type) !== -1)) {
|
||||||
middleware = appImManager.chat.bubbles.getMiddleware();
|
middleware = appImManager.chat.bubbles.getMiddleware();
|
||||||
const lazyLoadQueue = appImManager.chat.bubbles.lazyLoadQueue;
|
const lazyLoadQueue = appImManager.chat.bubbles.lazyLoadQueue;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -249,13 +249,13 @@ export default class ChatTopbar {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const original = selection.toggleByBubble.bind(selection);
|
const original = selection.toggleByElement.bind(selection);
|
||||||
selection.toggleByBubble = (bubble) => {
|
selection.toggleByElement = (bubble) => {
|
||||||
appStateManager.pushToState('chatContextMenuHintWasShown', true);
|
appStateManager.pushToState('chatContextMenuHintWasShown', true);
|
||||||
toast(i18n('Chat.Menu.Hint'));
|
toast(i18n('Chat.Menu.Hint'));
|
||||||
|
|
||||||
selection.toggleByBubble = original;
|
selection.toggleByElement = original;
|
||||||
selection.toggleByBubble(bubble);
|
selection.toggleByElement(bubble);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -8,7 +8,12 @@ import appImManager from "../../lib/appManagers/appImManager";
|
|||||||
import PopupPickUser from "./pickUser";
|
import PopupPickUser from "./pickUser";
|
||||||
|
|
||||||
export default class PopupForward extends PopupPickUser {
|
export default class PopupForward extends PopupPickUser {
|
||||||
constructor(fromPeerId: number, mids: number[], onSelect?: (peerId: number) => Promise<void> | void, onClose?: () => void, overrideOnSelect = false) {
|
constructor(
|
||||||
|
peerIdMids: {[fromPeerId: number]: number[]},
|
||||||
|
onSelect?: (peerId: number) => Promise<void> | void,
|
||||||
|
onClose?: () => void,
|
||||||
|
overrideOnSelect = false
|
||||||
|
) {
|
||||||
super({
|
super({
|
||||||
peerTypes: ['dialogs', 'contacts'],
|
peerTypes: ['dialogs', 'contacts'],
|
||||||
onSelect: overrideOnSelect ? onSelect : async(peerId) => {
|
onSelect: overrideOnSelect ? onSelect : async(peerId) => {
|
||||||
@ -20,7 +25,7 @@ export default class PopupForward extends PopupPickUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
appImManager.setInnerPeer(peerId);
|
appImManager.setInnerPeer(peerId);
|
||||||
appImManager.chat.input.initMessagesForward(fromPeerId, mids.slice());
|
appImManager.chat.input.initMessagesForward(peerIdMids);
|
||||||
},
|
},
|
||||||
onClose,
|
onClose,
|
||||||
placeholder: 'ShareModal.Search.ForwardPlaceholder',
|
placeholder: 'ShareModal.Search.ForwardPlaceholder',
|
||||||
|
@ -73,11 +73,13 @@ export default class RangeSelector {
|
|||||||
this.rect = this.container.getBoundingClientRect();
|
this.rect = this.container.getBoundingClientRect();
|
||||||
this.mousedown = true;
|
this.mousedown = true;
|
||||||
this.scrub(event);
|
this.scrub(event);
|
||||||
|
this.container.classList.add('is-focused');
|
||||||
this.events?.onMouseDown && this.events.onMouseDown(event);
|
this.events?.onMouseDown && this.events.onMouseDown(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
protected onMouseUp = (event: GrabEvent) => {
|
protected onMouseUp = (event: GrabEvent) => {
|
||||||
this.mousedown = false;
|
this.mousedown = false;
|
||||||
|
this.container.classList.remove('is-focused');
|
||||||
this.events?.onMouseUp && this.events.onMouseUp(event);
|
this.events?.onMouseUp && this.events.onMouseUp(event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import { SliderSuperTab } from "./slider";
|
|||||||
import RadioForm from "./radioForm";
|
import RadioForm from "./radioForm";
|
||||||
import { i18n, LangPackKey } from "../lib/langPack";
|
import { i18n, LangPackKey } from "../lib/langPack";
|
||||||
import replaceContent from "../helpers/dom/replaceContent";
|
import replaceContent from "../helpers/dom/replaceContent";
|
||||||
|
import setInnerHTML from "../helpers/dom/setInnerHTML";
|
||||||
|
|
||||||
export default class Row {
|
export default class Row {
|
||||||
public container: HTMLElement;
|
public container: HTMLElement;
|
||||||
@ -24,7 +25,7 @@ export default class Row {
|
|||||||
|
|
||||||
constructor(options: Partial<{
|
constructor(options: Partial<{
|
||||||
icon: string,
|
icon: string,
|
||||||
subtitle: string,
|
subtitle: string | HTMLElement | DocumentFragment,
|
||||||
subtitleLangKey: LangPackKey,
|
subtitleLangKey: LangPackKey,
|
||||||
subtitleLangArgs: any[],
|
subtitleLangArgs: any[],
|
||||||
radioField: Row['radioField'],
|
radioField: Row['radioField'],
|
||||||
@ -35,7 +36,8 @@ export default class Row {
|
|||||||
titleRight: string | HTMLElement,
|
titleRight: string | HTMLElement,
|
||||||
clickable: boolean | ((e: Event) => void),
|
clickable: boolean | ((e: Event) => void),
|
||||||
navigationTab: SliderSuperTab,
|
navigationTab: SliderSuperTab,
|
||||||
havePadding: boolean
|
havePadding: boolean,
|
||||||
|
noRipple: boolean
|
||||||
}> = {}) {
|
}> = {}) {
|
||||||
this.container = document.createElement(options.radioField || options.checkboxField ? 'label' : 'div');
|
this.container = document.createElement(options.radioField || options.checkboxField ? 'label' : 'div');
|
||||||
this.container.classList.add('row');
|
this.container.classList.add('row');
|
||||||
@ -44,7 +46,11 @@ export default class Row {
|
|||||||
this.subtitle.classList.add('row-subtitle');
|
this.subtitle.classList.add('row-subtitle');
|
||||||
this.subtitle.setAttribute('dir', 'auto');
|
this.subtitle.setAttribute('dir', 'auto');
|
||||||
if(options.subtitle) {
|
if(options.subtitle) {
|
||||||
this.subtitle.innerHTML = options.subtitle;
|
if(typeof(options.subtitle) === 'string') {
|
||||||
|
setInnerHTML(this.subtitle, options.subtitle);
|
||||||
|
} else {
|
||||||
|
this.subtitle.append(options.subtitle);
|
||||||
|
}
|
||||||
} else if(options.subtitleLangKey) {
|
} else if(options.subtitleLangKey) {
|
||||||
this.subtitle.append(i18n(options.subtitleLangKey, options.subtitleLangArgs));
|
this.subtitle.append(i18n(options.subtitleLangKey, options.subtitleLangArgs));
|
||||||
}
|
}
|
||||||
@ -137,7 +143,10 @@ export default class Row {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.container.classList.add('row-clickable', 'hover-effect');
|
this.container.classList.add('row-clickable', 'hover-effect');
|
||||||
ripple(this.container, undefined, undefined, true);
|
|
||||||
|
if(!options.noRipple) {
|
||||||
|
ripple(this.container, undefined, undefined, true);
|
||||||
|
}
|
||||||
|
|
||||||
/* if(options.radioField || options.checkboxField) {
|
/* if(options.radioField || options.checkboxField) {
|
||||||
this.container.prepend(this.container.lastElementChild);
|
this.container.prepend(this.container.lastElementChild);
|
||||||
|
86
src/components/sendingStatus.ts
Normal file
86
src/components/sendingStatus.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* https://github.com/morethanwords/tweb
|
||||||
|
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||||
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Message } from "../layer";
|
||||||
|
/* import findUpClassName from "../helpers/dom/findUpClassName";
|
||||||
|
import rootScope from "../lib/rootScope";
|
||||||
|
import Transition from "./transition"; */
|
||||||
|
|
||||||
|
export enum SENDING_STATUS {
|
||||||
|
Error = -1,
|
||||||
|
Pending,
|
||||||
|
Sent,
|
||||||
|
Read
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getSendingStatus(message: Message.message | Message.messageService) {
|
||||||
|
return message.pFlags.is_outgoing ?
|
||||||
|
SENDING_STATUS.Pending : (
|
||||||
|
message.pFlags.unread ?
|
||||||
|
SENDING_STATUS.Sent :
|
||||||
|
SENDING_STATUS.Read
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setSendingStatus(
|
||||||
|
container: HTMLElement,
|
||||||
|
message?: Message.message | Message.messageService,
|
||||||
|
disableAnimationIfRippleFound?: boolean
|
||||||
|
) {
|
||||||
|
let className: 'check' | 'checks' | 'sending';
|
||||||
|
if(message?.pFlags.out) {
|
||||||
|
if(message.pFlags.is_outgoing) {
|
||||||
|
className = 'sending';
|
||||||
|
} else if(message.pFlags.unread) {
|
||||||
|
className = 'check';
|
||||||
|
} else {
|
||||||
|
className = 'checks';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!className) {
|
||||||
|
container.textContent = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const iconClassName = 'tgico-' + className;
|
||||||
|
const lastElement = container.lastElementChild as HTMLElement;
|
||||||
|
if(lastElement && lastElement.classList.contains(iconClassName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const element = document.createElement('i');
|
||||||
|
element.classList.add('sending-status-icon', /* 'transition-item', */ iconClassName);
|
||||||
|
container.append(element);
|
||||||
|
|
||||||
|
if(lastElement) {
|
||||||
|
lastElement.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if(!lastElement) {
|
||||||
|
element.classList.add('active');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const select = Transition(container, undefined, 350, () => {
|
||||||
|
lastElement.remove();
|
||||||
|
}, false, true, false);
|
||||||
|
|
||||||
|
let animate = rootScope.settings.animationsEnabled && className !== 'sending' && !lastElement.classList.contains('tgico-sending');
|
||||||
|
if(disableAnimationIfRippleFound && animate) {
|
||||||
|
const parent = findUpClassName(container, 'rp');
|
||||||
|
if(parent.querySelector('.c-ripple__circle') || parent.matches(':hover')) {
|
||||||
|
animate = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select(element, animate, lastElement); */
|
||||||
|
|
||||||
|
/* SetTransition(lastElement, 'is-visible', false, 350, () => {
|
||||||
|
// lastElement.remove();
|
||||||
|
}, 2);
|
||||||
|
SetTransition(element, 'is-visible', true, 350, undefined, 2); */
|
||||||
|
}
|
@ -245,7 +245,8 @@ class PeerProfileAvatars {
|
|||||||
|
|
||||||
const rect = this.container.getBoundingClientRect();
|
const rect = this.container.getBoundingClientRect();
|
||||||
|
|
||||||
const e = (_e as TouchEvent).touches ? (_e as TouchEvent).touches[0] : _e as MouseEvent;
|
// const e = (_e as TouchEvent).touches ? (_e as TouchEvent).touches[0] : _e as MouseEvent;
|
||||||
|
const e = _e;
|
||||||
const x = e.pageX;
|
const x = e.pageX;
|
||||||
|
|
||||||
const clickX = x - rect.left;
|
const clickX = x - rect.left;
|
||||||
@ -1055,16 +1056,15 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
|||||||
const inputFilter = mediaTab.inputFilter;
|
const inputFilter = mediaTab.inputFilter;
|
||||||
const filtered = this.searchSuper.filterMessagesByType(mids.map(mid => appMessagesManager.getMessageByPeer(peerId, mid)), inputFilter);
|
const filtered = this.searchSuper.filterMessagesByType(mids.map(mid => appMessagesManager.getMessageByPeer(peerId, mid)), inputFilter);
|
||||||
if(filtered.length) {
|
if(filtered.length) {
|
||||||
if(this.historiesStorage[peerId][inputFilter]) {
|
const history = this.historiesStorage[peerId][inputFilter];
|
||||||
this.historiesStorage[peerId][inputFilter].unshift(...filtered.map(message => ({mid: message.mid, peerId: message.peerId})));
|
if(history) {
|
||||||
|
history.unshift(...filtered.map(message => ({mid: message.mid, peerId: message.peerId})));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.peerId === peerId && this.searchSuper.usedFromHistory[inputFilter] !== -1) {
|
if(this.peerId === peerId && this.searchSuper.usedFromHistory[inputFilter] !== -1) {
|
||||||
this.searchSuper.usedFromHistory[inputFilter] += filtered.length;
|
this.searchSuper.usedFromHistory[inputFilter] += filtered.length;
|
||||||
this.searchSuper.performSearchResult(filtered, mediaTab, false);
|
this.searchSuper.performSearchResult(filtered, mediaTab, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1078,17 +1078,21 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
|||||||
for(const type of this.searchSuper.mediaTabs) {
|
for(const type of this.searchSuper.mediaTabs) {
|
||||||
const inputFilter = type.inputFilter;
|
const inputFilter = type.inputFilter;
|
||||||
|
|
||||||
if(!this.historiesStorage[peerId][inputFilter]) continue;
|
|
||||||
|
|
||||||
const history = this.historiesStorage[peerId][inputFilter];
|
const history = this.historiesStorage[peerId][inputFilter];
|
||||||
|
if(!history) continue;
|
||||||
|
|
||||||
const idx = history.findIndex(m => m.mid === mid);
|
const idx = history.findIndex(m => m.mid === mid);
|
||||||
if(idx !== -1) {
|
if(idx !== -1) {
|
||||||
history.splice(idx, 1);
|
history.splice(idx, 1);
|
||||||
|
|
||||||
if(this.peerId === peerId) {
|
if(this.peerId === peerId) {
|
||||||
const container = this.searchSuper.tabs[inputFilter];
|
const container = this.searchSuper.tabs[inputFilter];
|
||||||
const div = container.querySelector(`div[data-mid="${mid}"][data-peer-id="${peerId}"]`);
|
const div = container.querySelector(`div[data-mid="${mid}"][data-peer-id="${peerId}"]`) as HTMLElement;
|
||||||
if(div) {
|
if(div) {
|
||||||
|
if(this.searchSuper.selection.isSelecting) {
|
||||||
|
this.searchSuper.selection.toggleByElement(div);
|
||||||
|
}
|
||||||
|
|
||||||
div.remove();
|
div.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,10 @@ const SetTransition = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if(forwards && className && element.classList.contains(className) && !element.classList.contains('animating')) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
if(useRafs && rootScope.settings.animationsEnabled && duration) {
|
if(useRafs && rootScope.settings.animationsEnabled && duration) {
|
||||||
element.dataset.raf = '' + window.requestAnimationFrame(() => {
|
element.dataset.raf = '' + window.requestAnimationFrame(() => {
|
||||||
delete element.dataset.raf;
|
delete element.dataset.raf;
|
||||||
|
@ -10,6 +10,7 @@ import { dispatchHeavyAnimationEvent } from "../hooks/useHeavyAnimationCheck";
|
|||||||
import whichChild from "../helpers/dom/whichChild";
|
import whichChild from "../helpers/dom/whichChild";
|
||||||
import findUpClassName from "../helpers/dom/findUpClassName";
|
import findUpClassName from "../helpers/dom/findUpClassName";
|
||||||
import { isSafari } from "../helpers/userAgent";
|
import { isSafari } from "../helpers/userAgent";
|
||||||
|
import { cancelEvent } from "../helpers/dom/cancelEvent";
|
||||||
|
|
||||||
function slideNavigation(tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) {
|
function slideNavigation(tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) {
|
||||||
const width = prevTabContent.getBoundingClientRect().width;
|
const width = prevTabContent.getBoundingClientRect().width;
|
||||||
@ -80,7 +81,13 @@ function slideTabs(tabContent: HTMLElement, prevTabContent: HTMLElement, toRight
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TransitionSlider = (content: HTMLElement, type: 'tabs' | 'navigation' | 'zoom-fade' | 'slide-fade' | 'none'/* | 'counter' */, transitionTime: number, onTransitionEnd?: (id: number) => void, isHeavy = true) => {
|
export const TransitionSlider = (
|
||||||
|
content: HTMLElement,
|
||||||
|
type: 'tabs' | 'navigation' | 'zoom-fade' | 'slide-fade' | 'none'/* | 'counter' */,
|
||||||
|
transitionTime: number,
|
||||||
|
onTransitionEnd?: (id: number) => void,
|
||||||
|
isHeavy = true
|
||||||
|
) => {
|
||||||
let animationFunction: TransitionFunction = null;
|
let animationFunction: TransitionFunction = null;
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
@ -101,62 +108,94 @@ export const TransitionSlider = (content: HTMLElement, type: 'tabs' | 'navigatio
|
|||||||
|
|
||||||
type TransitionFunction = (tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) => void | (() => void);
|
type TransitionFunction = (tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) => void | (() => void);
|
||||||
|
|
||||||
const Transition = (content: HTMLElement, animationFunction: TransitionFunction, transitionTime: number, onTransitionEnd?: (id: number) => void, isHeavy = true) => {
|
const Transition = (
|
||||||
|
content: HTMLElement,
|
||||||
|
animationFunction: TransitionFunction,
|
||||||
|
transitionTime: number,
|
||||||
|
onTransitionEnd?: (id: number) => void,
|
||||||
|
isHeavy = true,
|
||||||
|
once = false,
|
||||||
|
withAnimationListener = true
|
||||||
|
) => {
|
||||||
const onTransitionEndCallbacks: Map<HTMLElement, Function> = new Map();
|
const onTransitionEndCallbacks: Map<HTMLElement, Function> = new Map();
|
||||||
let animationDeferred: CancellablePromise<void>;
|
let animationDeferred: CancellablePromise<void>;
|
||||||
let animationStarted = 0;
|
// let animationStarted = 0;
|
||||||
let from: HTMLElement = null;
|
let from: HTMLElement = null;
|
||||||
|
|
||||||
// TODO: check for transition type (transform, etc) using by animationFunction
|
if(withAnimationListener) {
|
||||||
content.addEventListener(animationFunction ? 'transitionend' : 'animationend', (e) => {
|
const listenerName = animationFunction ? 'transitionend' : 'animationend';
|
||||||
if((e.target as HTMLElement).parentElement !== content) {
|
|
||||||
return;
|
const onEndEvent = (e: TransitionEvent | AnimationEvent) => {
|
||||||
|
cancelEvent(e);
|
||||||
|
|
||||||
|
if((e.target as HTMLElement).parentElement !== content) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log('Transition: transitionend', /* content, */ e, selectTab.prevId, performance.now() - animationStarted);
|
||||||
|
|
||||||
|
const callback = onTransitionEndCallbacks.get(e.target as HTMLElement);
|
||||||
|
if(callback) callback();
|
||||||
|
|
||||||
|
if(e.target !== from) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!animationDeferred && isHeavy) return;
|
||||||
|
|
||||||
|
if(animationDeferred) {
|
||||||
|
animationDeferred.resolve();
|
||||||
|
animationDeferred = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(onTransitionEnd) {
|
||||||
|
onTransitionEnd(selectTab.prevId());
|
||||||
|
}
|
||||||
|
|
||||||
|
content.classList.remove('animating', 'backwards', 'disable-hover');
|
||||||
|
|
||||||
|
if(once) {
|
||||||
|
content.removeEventListener(listenerName, onEndEvent/* , {capture: false} */);
|
||||||
|
from = animationDeferred = undefined;
|
||||||
|
onTransitionEndCallbacks.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: check for transition type (transform, etc) using by animationFunction
|
||||||
|
content.addEventListener(listenerName, onEndEvent/* , {passive: true, capture: false} */);
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectTab(id: number | HTMLElement, animate = true, overrideFrom?: typeof from) {
|
||||||
|
if(overrideFrom) {
|
||||||
|
from = overrideFrom;
|
||||||
}
|
}
|
||||||
|
|
||||||
//console.log('Transition: transitionend', /* content, */ e, selectTab.prevId, performance.now() - animationStarted);
|
|
||||||
|
|
||||||
const callback = onTransitionEndCallbacks.get(e.target as HTMLElement);
|
|
||||||
if(callback) callback();
|
|
||||||
|
|
||||||
if(e.target !== from) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!animationDeferred && isHeavy) return;
|
|
||||||
|
|
||||||
if(animationDeferred) {
|
|
||||||
animationDeferred.resolve();
|
|
||||||
animationDeferred = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(onTransitionEnd) {
|
|
||||||
onTransitionEnd(selectTab.prevId());
|
|
||||||
}
|
|
||||||
|
|
||||||
content.classList.remove('animating', 'backwards', 'disable-hover');
|
|
||||||
});
|
|
||||||
|
|
||||||
function selectTab(id: number | HTMLElement, animate = true) {
|
|
||||||
const self = selectTab;
|
|
||||||
|
|
||||||
if(id instanceof HTMLElement) {
|
if(id instanceof HTMLElement) {
|
||||||
id = whichChild(id);
|
id = whichChild(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const prevId = self.prevId();
|
const prevId = selectTab.prevId();
|
||||||
if(id === prevId) return false;
|
if(id === prevId) return false;
|
||||||
|
|
||||||
//console.log('selectTab id:', id);
|
//console.log('selectTab id:', id);
|
||||||
|
|
||||||
const _from = from;
|
|
||||||
const to = content.children[id] as HTMLElement;
|
const to = content.children[id] as HTMLElement;
|
||||||
|
|
||||||
if(!rootScope.settings.animationsEnabled || prevId === -1) {
|
if(!rootScope.settings.animationsEnabled || prevId === -1) {
|
||||||
animate = false;
|
animate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!withAnimationListener) {
|
||||||
|
const timeout = content.dataset.timeout;
|
||||||
|
if(timeout !== undefined) {
|
||||||
|
clearTimeout(+timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete content.dataset.timeout;
|
||||||
|
}
|
||||||
|
|
||||||
if(!animate) {
|
if(!animate) {
|
||||||
if(_from) _from.classList.remove('active', 'to', 'from');
|
if(from) from.classList.remove('active', 'to', 'from');
|
||||||
if(to) {
|
if(to) {
|
||||||
to.classList.remove('to', 'from');
|
to.classList.remove('to', 'from');
|
||||||
to.classList.add('active');
|
to.classList.add('active');
|
||||||
@ -170,12 +209,21 @@ const Transition = (content: HTMLElement, animationFunction: TransitionFunction,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!withAnimationListener) {
|
||||||
|
content.dataset.timeout = '' + window.setTimeout(() => {
|
||||||
|
to.classList.remove('to');
|
||||||
|
from && from.classList.remove('from');
|
||||||
|
content.classList.remove('animating', 'backwards', 'disable-hover');
|
||||||
|
delete content.dataset.timeout;
|
||||||
|
}, transitionTime);
|
||||||
|
}
|
||||||
|
|
||||||
if(from) {
|
if(from) {
|
||||||
from.classList.remove('to');
|
from.classList.remove('to');
|
||||||
from.classList.add('from');
|
from.classList.add('from');
|
||||||
}
|
}
|
||||||
|
|
||||||
content.classList.add('animating', 'disable-hover');
|
content.classList.add('animating'/* , 'disable-hover' */);
|
||||||
const toRight = prevId < id;
|
const toRight = prevId < id;
|
||||||
content.classList.toggle('backwards', !toRight);
|
content.classList.toggle('backwards', !toRight);
|
||||||
|
|
||||||
@ -200,7 +248,8 @@ const Transition = (content: HTMLElement, animationFunction: TransitionFunction,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_from/* && false */) {
|
if(from/* && false */) {
|
||||||
|
const _from = from;
|
||||||
const callback = () => {
|
const callback = () => {
|
||||||
_from.classList.remove('active', 'from');
|
_from.classList.remove('active', 'from');
|
||||||
|
|
||||||
@ -223,7 +272,7 @@ const Transition = (content: HTMLElement, animationFunction: TransitionFunction,
|
|||||||
if(isHeavy) {
|
if(isHeavy) {
|
||||||
if(!animationDeferred) {
|
if(!animationDeferred) {
|
||||||
animationDeferred = deferredPromise<void>();
|
animationDeferred = deferredPromise<void>();
|
||||||
animationStarted = performance.now();
|
// animationStarted = performance.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchHeavyAnimationEvent(animationDeferred, transitionTime * 2);
|
dispatchHeavyAnimationEvent(animationDeferred, transitionTime * 2);
|
||||||
|
@ -550,7 +550,7 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
|
|||||||
icoDiv.classList.add('document-ico');
|
icoDiv.classList.add('document-ico');
|
||||||
|
|
||||||
const cacheContext = appDownloadManager.getCacheContext(doc);
|
const cacheContext = appDownloadManager.getCacheContext(doc);
|
||||||
if(doc.thumbs?.length || (message.pFlags.is_outgoing && cacheContext.url && doc.type === 'photo')) {
|
if((doc.thumbs?.length || (message.pFlags.is_outgoing && cacheContext.url && doc.type === 'photo')) && doc.mime_type !== 'image/gif') {
|
||||||
docDiv.classList.add('document-with-thumb');
|
docDiv.classList.add('document-with-thumb');
|
||||||
|
|
||||||
let imgs: HTMLImageElement[] = [];
|
let imgs: HTMLImageElement[] = [];
|
||||||
@ -1564,6 +1564,7 @@ export function wrapGroupedDocuments({albumMustBeRenderedFull, message, bubble,
|
|||||||
const container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
container.classList.add('document-container');
|
container.classList.add('document-container');
|
||||||
container.dataset.mid = '' + mid;
|
container.dataset.mid = '' + mid;
|
||||||
|
container.dataset.peerId = '' + message.peerId;
|
||||||
|
|
||||||
const wrapper = document.createElement('div');
|
const wrapper = document.createElement('div');
|
||||||
wrapper.classList.add('document-wrapper');
|
wrapper.classList.add('document-wrapper');
|
||||||
|
@ -16,7 +16,7 @@ export const MAIN_DOMAIN = 'web.telegram.org';
|
|||||||
const App = {
|
const App = {
|
||||||
id: 1025907,
|
id: 1025907,
|
||||||
hash: '452b0359b988148995f22ff0f4229750',
|
hash: '452b0359b988148995f22ff0f4229750',
|
||||||
version: '0.8.2',
|
version: '0.8.3',
|
||||||
langPackVersion: '0.3.3',
|
langPackVersion: '0.3.3',
|
||||||
langPack: 'macos',
|
langPack: 'macos',
|
||||||
langPackCode: 'en',
|
langPackCode: 'en',
|
||||||
|
@ -8,9 +8,9 @@ import type ListenerSetter from "../listenerSetter";
|
|||||||
import { isTouchSupported } from "../touchSupport";
|
import { isTouchSupported } from "../touchSupport";
|
||||||
import simulateEvent from "./dispatchEvent";
|
import simulateEvent from "./dispatchEvent";
|
||||||
|
|
||||||
export const CLICK_EVENT_NAME: 'mousedown' | 'touchend' | 'click' = (isTouchSupported ? 'mousedown' : 'click') as any;
|
export const CLICK_EVENT_NAME: 'mousedown' /* | 'touchend' */ | 'click' = (isTouchSupported ? 'mousedown' : 'click') as any;
|
||||||
export type AttachClickOptions = AddEventListenerOptions & Partial<{listenerSetter: ListenerSetter, touchMouseDown: true}>;
|
export type AttachClickOptions = AddEventListenerOptions & Partial<{listenerSetter: ListenerSetter, touchMouseDown: true}>;
|
||||||
export function attachClickEvent(elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options: AttachClickOptions = {}) {
|
export function attachClickEvent(elem: HTMLElement | Window, callback: (e: /* TouchEvent | */MouseEvent) => void, options: AttachClickOptions = {}) {
|
||||||
const add = options.listenerSetter ? options.listenerSetter.add(elem) : elem.addEventListener.bind(elem);
|
const add = options.listenerSetter ? options.listenerSetter.add(elem) : elem.addEventListener.bind(elem);
|
||||||
// const remove = options.listenerSetter ? options.listenerSetter.removeManual.bind(options.listenerSetter, elem) : elem.removeEventListener.bind(elem);
|
// const remove = options.listenerSetter ? options.listenerSetter.removeManual.bind(options.listenerSetter, elem) : elem.removeEventListener.bind(elem);
|
||||||
|
|
||||||
@ -46,11 +46,11 @@ export function attachClickEvent(elem: HTMLElement, callback: (e: TouchEvent | M
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function detachClickEvent(elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options?: AddEventListenerOptions) {
|
export function detachClickEvent(elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options?: AddEventListenerOptions) {
|
||||||
if(CLICK_EVENT_NAME === 'touchend') {
|
// if(CLICK_EVENT_NAME === 'touchend') {
|
||||||
elem.removeEventListener('touchstart', callback, options);
|
// elem.removeEventListener('touchstart', callback, options);
|
||||||
} else {
|
// } else {
|
||||||
elem.removeEventListener(CLICK_EVENT_NAME, callback, options);
|
elem.removeEventListener(CLICK_EVENT_NAME, callback, options);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function simulateClickEvent(elem: HTMLElement) {
|
export function simulateClickEvent(elem: HTMLElement) {
|
||||||
|
@ -56,7 +56,7 @@ if(IS_STICKY_INPUT_BUGGED) {
|
|||||||
// let hasFocus = false;
|
// let hasFocus = false;
|
||||||
let lastFocusOutTimeStamp = 0;
|
let lastFocusOutTimeStamp = 0;
|
||||||
document.addEventListener('focusin', (e) => {
|
document.addEventListener('focusin', (e) => {
|
||||||
if((e.timeStamp - lastFocusOutTimeStamp) < 50/* && document.activeElement === input */) {
|
if(!(e.target as HTMLElement).classList.contains('is-sticky-input-bugged') || (e.timeStamp - lastFocusOutTimeStamp) < 50/* && document.activeElement === input */) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -793,6 +793,7 @@ const lang = {
|
|||||||
"Message.Context.Select": "Select",
|
"Message.Context.Select": "Select",
|
||||||
"Message.Context.Pin": "Pin",
|
"Message.Context.Pin": "Pin",
|
||||||
"Message.Context.Unpin": "Unpin",
|
"Message.Context.Unpin": "Unpin",
|
||||||
|
"Message.Context.Goto": "Show Message",
|
||||||
"MessageContext.CopyMessageLink1": "Copy Message Link",
|
"MessageContext.CopyMessageLink1": "Copy Message Link",
|
||||||
"NewPoll.Anonymous": "Anonymous Voting",
|
"NewPoll.Anonymous": "Anonymous Voting",
|
||||||
"NewPoll.Explanation.Placeholder": "Add a Comment (Optional)",
|
"NewPoll.Explanation.Placeholder": "Add a Comment (Optional)",
|
||||||
|
@ -22,7 +22,7 @@ import rootScope from "../rootScope";
|
|||||||
import apiUpdatesManager from "./apiUpdatesManager";
|
import apiUpdatesManager from "./apiUpdatesManager";
|
||||||
import appPeersManager from './appPeersManager';
|
import appPeersManager from './appPeersManager';
|
||||||
import appImManager from "./appImManager";
|
import appImManager from "./appImManager";
|
||||||
import appMessagesManager, { Dialog } from "./appMessagesManager";
|
import appMessagesManager, { Dialog, MyMessage } from "./appMessagesManager";
|
||||||
import appStateManager, { State } from "./appStateManager";
|
import appStateManager, { State } from "./appStateManager";
|
||||||
import appUsersManager from "./appUsersManager";
|
import appUsersManager from "./appUsersManager";
|
||||||
import Button from "../../components/button";
|
import Button from "../../components/button";
|
||||||
@ -51,6 +51,7 @@ import windowSize from "../../helpers/windowSize";
|
|||||||
import isInDOM from "../../helpers/dom/isInDOM";
|
import isInDOM from "../../helpers/dom/isInDOM";
|
||||||
import appPhotosManager, { MyPhoto } from "./appPhotosManager";
|
import appPhotosManager, { MyPhoto } from "./appPhotosManager";
|
||||||
import { MyDocument } from "./appDocsManager";
|
import { MyDocument } from "./appDocsManager";
|
||||||
|
import { setSendingStatus } from "../../components/sendingStatus";
|
||||||
|
|
||||||
export type DialogDom = {
|
export type DialogDom = {
|
||||||
avatarEl: AvatarElement,
|
avatarEl: AvatarElement,
|
||||||
@ -440,6 +441,7 @@ export class AppDialogsManager {
|
|||||||
public setFilterId(filterId: number) {
|
public setFilterId(filterId: number) {
|
||||||
this.filterId = filterId;
|
this.filterId = filterId;
|
||||||
this.indexKey = appMessagesManager.dialogsStorage ? appMessagesManager.dialogsStorage.getDialogIndexKey(this.filterId) : 'index';
|
this.indexKey = appMessagesManager.dialogsStorage ? appMessagesManager.dialogsStorage.getDialogIndexKey(this.filterId) : 'index';
|
||||||
|
rootScope.filterId = filterId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async onStateLoaded(state: State) {
|
private async onStateLoaded(state: State) {
|
||||||
@ -1433,22 +1435,15 @@ export class AppDialogsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const lastMessage = dialog.draft?._ === 'draftMessage' ?
|
let setStatusMessage: MyMessage;
|
||||||
dialog.draft :
|
if(dialog.draft?._ !== 'draftMessage') {
|
||||||
appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);
|
const lastMessage: MyMessage = appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);
|
||||||
if(!lastMessage.deleted && lastMessage.pFlags.out && lastMessage.peerId !== rootScope.myId/* &&
|
if(!lastMessage.deleted && lastMessage.pFlags.out && lastMessage.peerId !== rootScope.myId) {
|
||||||
dialog.read_outbox_max_id */) { // maybe comment, 06.20.2020
|
setStatusMessage = lastMessage;
|
||||||
const isUnread = !!lastMessage.pFlags?.unread
|
|
||||||
/* && dialog.read_outbox_max_id !== 0 */; // maybe uncomment, 31.01.2020
|
|
||||||
|
|
||||||
if(isUnread) {
|
|
||||||
dom.statusSpan.classList.remove('tgico-checks');
|
|
||||||
dom.statusSpan.classList.add('tgico-check');
|
|
||||||
} else {
|
|
||||||
dom.statusSpan.classList.remove('tgico-check');
|
|
||||||
dom.statusSpan.classList.add('tgico-checks');
|
|
||||||
}
|
}
|
||||||
} else dom.statusSpan.classList.remove('tgico-check', 'tgico-checks');
|
}
|
||||||
|
|
||||||
|
setSendingStatus(dom.statusSpan, setStatusMessage, true);
|
||||||
|
|
||||||
const filter = appMessagesManager.filtersStorage.getFilter(this.filterId);
|
const filter = appMessagesManager.filtersStorage.getFilter(this.filterId);
|
||||||
let isPinned: boolean;
|
let isPinned: boolean;
|
||||||
@ -1672,7 +1667,7 @@ export class AppDialogsManager {
|
|||||||
li.dataset.peerId = '' + peerId;
|
li.dataset.peerId = '' + peerId;
|
||||||
|
|
||||||
const statusSpan = document.createElement('span');
|
const statusSpan = document.createElement('span');
|
||||||
statusSpan.classList.add('message-status');
|
statusSpan.classList.add('message-status', 'sending-status'/* , 'transition', 'reveal' */);
|
||||||
|
|
||||||
const lastTimeSpan = document.createElement('span');
|
const lastTimeSpan = document.createElement('span');
|
||||||
lastTimeSpan.classList.add('message-time');
|
lastTimeSpan.classList.add('message-time');
|
||||||
|
@ -806,6 +806,16 @@ export class AppImManager {
|
|||||||
|
|
||||||
if(e.code === 'KeyC' && (e.ctrlKey || e.metaKey) && target.tagName !== 'INPUT') {
|
if(e.code === 'KeyC' && (e.ctrlKey || e.metaKey) && target.tagName !== 'INPUT') {
|
||||||
return;
|
return;
|
||||||
|
} else if(e.altKey && (e.code === 'ArrowUp' || e.code === 'ArrowDown') && rootScope.peerId) {
|
||||||
|
const folder = appMessagesManager.dialogsStorage.getFolder(rootScope.filterId, true);
|
||||||
|
const idx = folder.findIndex(dialog => dialog.peerId === rootScope.peerId);
|
||||||
|
if(idx !== -1) {
|
||||||
|
const nextIndex = e.code === 'ArrowUp' ? idx - 1 : idx + 1;
|
||||||
|
const nextDialog = folder[nextIndex];
|
||||||
|
if(nextDialog) {
|
||||||
|
this.setPeer(nextDialog.peerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if(e.code === 'ArrowUp') {
|
} else if(e.code === 'ArrowUp') {
|
||||||
if(!chat.input.editMsgId && chat.input.isInputEmpty()) {
|
if(!chat.input.editMsgId && chat.input.isInputEmpty()) {
|
||||||
const historyStorage = appMessagesManager.getHistoryStorage(chat.peerId, chat.threadId);
|
const historyStorage = appMessagesManager.getHistoryStorage(chat.peerId, chat.threadId);
|
||||||
@ -854,23 +864,18 @@ export class AppImManager {
|
|||||||
|
|
||||||
document.body.addEventListener('keydown', onKeyDown);
|
document.body.addEventListener('keydown', onKeyDown);
|
||||||
|
|
||||||
rootScope.addEventListener('history_multiappend', (e) => {
|
rootScope.addEventListener('history_multiappend', (msgIdsByPeer) => {
|
||||||
const msgIdsByPeer = e;
|
|
||||||
|
|
||||||
for(const peerId in msgIdsByPeer) {
|
for(const peerId in msgIdsByPeer) {
|
||||||
appSidebarRight.sharedMediaTab.renderNewMessages(+peerId, Array.from(msgIdsByPeer[peerId]));
|
appSidebarRight.sharedMediaTab.renderNewMessages(+peerId, Array.from(msgIdsByPeer[peerId]));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
rootScope.addEventListener('history_delete', (e) => {
|
rootScope.addEventListener('history_delete', ({peerId, msgs}) => {
|
||||||
const {peerId, msgs} = e;
|
|
||||||
|
|
||||||
appSidebarRight.sharedMediaTab.deleteDeletedMessages(peerId, Array.from(msgs));
|
appSidebarRight.sharedMediaTab.deleteDeletedMessages(peerId, Array.from(msgs));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Calls when message successfully sent and we have an id
|
// Calls when message successfully sent and we have an id
|
||||||
rootScope.addEventListener('message_sent', (e) => {
|
rootScope.addEventListener('message_sent', ({storage, tempId, mid}) => {
|
||||||
const {storage, tempId, mid} = e;
|
|
||||||
const message = appMessagesManager.getMessageFromStorage(storage, mid);
|
const message = appMessagesManager.getMessageFromStorage(storage, mid);
|
||||||
appSidebarRight.sharedMediaTab.renderNewMessages(message.peerId, [mid]);
|
appSidebarRight.sharedMediaTab.renderNewMessages(message.peerId, [mid]);
|
||||||
});
|
});
|
||||||
|
@ -2171,7 +2171,7 @@ export class AppMessagesManager {
|
|||||||
//return Object.keys(this.groupedMessagesStorage[grouped_id]).map(id => +id).sort((a, b) => a - b);
|
//return Object.keys(this.groupedMessagesStorage[grouped_id]).map(id => +id).sort((a, b) => a - b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getMidsByMessage(message: any) {
|
public getMidsByMessage(message: Message.message) {
|
||||||
if(message?.grouped_id) return this.getMidsByAlbum(message.grouped_id);
|
if(message?.grouped_id) return this.getMidsByAlbum(message.grouped_id);
|
||||||
else return [message.mid];
|
else return [message.mid];
|
||||||
}
|
}
|
||||||
|
@ -147,6 +147,7 @@ export class RootScope extends EventListenerBase<{
|
|||||||
public connectionStatus: {[name: string]: ConnectionStatusChange} = {};
|
public connectionStatus: {[name: string]: ConnectionStatusChange} = {};
|
||||||
public settings: State['settings'];
|
public settings: State['settings'];
|
||||||
public peerId = 0;
|
public peerId = 0;
|
||||||
|
public filterId = 0;
|
||||||
public systemTheme: Theme['name'];
|
public systemTheme: Theme['name'];
|
||||||
public config: Partial<Config.config> = {
|
public config: Partial<Config.config> = {
|
||||||
forwarded_count_max: 100,
|
forwarded_count_max: 100,
|
||||||
|
@ -155,6 +155,11 @@ Utility Classes
|
|||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.disable-hover/* ,
|
||||||
|
.disable-hover * */ {
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* .flex-grow {
|
/* .flex-grow {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 1;
|
z-index: 3;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
//background-color: rgba(0, 0, 0, .2);
|
//background-color: rgba(0, 0, 0, .2);
|
||||||
|
@ -1147,11 +1147,6 @@ $chat-helper-size: 36px;
|
|||||||
|
|
||||||
@include respond-to(handhelds) {
|
@include respond-to(handhelds) {
|
||||||
padding: 0 $chat-padding-handhelds;
|
padding: 0 $chat-padding-handhelds;
|
||||||
|
|
||||||
html.is-ios & {
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-webkit-touch-callout: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-chat {
|
&.is-chat {
|
||||||
|
@ -221,7 +221,8 @@ $bubble-margin: .25rem;
|
|||||||
// ! hide context menu for media on android
|
// ! hide context menu for media on android
|
||||||
.bubbles.is-selecting & {
|
.bubbles.is-selecting & {
|
||||||
img,
|
img,
|
||||||
video {
|
video,
|
||||||
|
a {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1031,7 +1032,7 @@ $bubble-margin: .25rem;
|
|||||||
&-title,
|
&-title,
|
||||||
&-subtitle,
|
&-subtitle,
|
||||||
i {
|
i {
|
||||||
color: #fff;
|
color: #fff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-border {
|
&-border {
|
||||||
@ -1412,31 +1413,31 @@ $bubble-margin: .25rem;
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
/* position: relative;
|
/* position: relative;
|
||||||
width: max-content; */
|
width: max-content; */
|
||||||
bottom: .1rem;
|
bottom: .1875rem;
|
||||||
right: .2rem;
|
right: .1875rem;
|
||||||
border-radius: 12px;
|
border-radius: .75rem;
|
||||||
background-color: var(--message-time-background);
|
background-color: var(--message-time-background);
|
||||||
padding: 0 .2rem;
|
padding: 0 .3125rem;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|
||||||
.time {
|
.time {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
color: #fff;
|
|
||||||
visibility: visible;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 2.5px;
|
padding: 0;
|
||||||
line-height: 18px;
|
margin: 0;
|
||||||
pointer-events: all; // show title
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
|
|
||||||
&:after {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
display: none;
|
right: unset;
|
||||||
|
bottom: unset;
|
||||||
|
color: #fff;
|
||||||
|
margin: inherit;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2102,6 +2103,10 @@ $bubble-margin: .25rem;
|
|||||||
.reply, .name {
|
.reply, .name {
|
||||||
right: calc(100% + 10px);
|
right: calc(100% + 10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.just-media) {
|
&:not(.just-media) {
|
||||||
@ -2117,14 +2122,6 @@ $bubble-margin: .25rem;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.sticker,
|
|
||||||
&.round,
|
|
||||||
&.emoji-big {
|
|
||||||
.message {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.quote:before {
|
.quote:before {
|
||||||
background-color: var(--message-out-primary-color);
|
background-color: var(--message-out-primary-color);
|
||||||
}
|
}
|
||||||
@ -2152,10 +2149,6 @@ $bubble-margin: .25rem;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-message-empty .time .inner {
|
|
||||||
color: var(--message-out-primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* &.is-message-empty .time:after {
|
/* &.is-message-empty .time:after {
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
} */
|
} */
|
||||||
|
@ -109,6 +109,7 @@ ul.chatlist {
|
|||||||
} */
|
} */
|
||||||
|
|
||||||
li {
|
li {
|
||||||
|
--background: unset;
|
||||||
//height: var(--height);
|
//height: var(--height);
|
||||||
height: 72px;
|
height: 72px;
|
||||||
//max-height: var(--height);
|
//max-height: var(--height);
|
||||||
@ -124,12 +125,14 @@ ul.chatlist {
|
|||||||
padding-right: 8.5px;
|
padding-right: 8.5px;
|
||||||
padding-left: 8.5px; */
|
padding-left: 8.5px; */
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
background: var(--background);
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
@include respond-to(handhelds) {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include hover-background-effect();
|
//@include hover-background-effect();
|
||||||
|
@include hover(gray, --background, false);
|
||||||
|
|
||||||
&.is-muted {
|
&.is-muted {
|
||||||
.user-title {
|
.user-title {
|
||||||
@ -183,13 +186,13 @@ ul.chatlist {
|
|||||||
} */
|
} */
|
||||||
|
|
||||||
&.menu-open {
|
&.menu-open {
|
||||||
background: var(--light-secondary-text-color);
|
--background: var(--light-secondary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@include respond-to(not-handhelds) {
|
@include respond-to(not-handhelds) {
|
||||||
&.active {
|
&.active {
|
||||||
|
--background: var(--primary-color) !important;
|
||||||
//background: var(--light-secondary-text-color);
|
//background: var(--light-secondary-text-color);
|
||||||
background: var(--primary-color) !important;
|
|
||||||
|
|
||||||
.user-caption,
|
.user-caption,
|
||||||
.tgico-chatspinned:before,
|
.tgico-chatspinned:before,
|
||||||
@ -405,25 +408,25 @@ ul.chatlist {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.message-status {
|
.message-status {
|
||||||
margin-right: .1rem;
|
margin-right: 0.125rem;
|
||||||
//margin-top: .3rem;
|
|
||||||
margin-top: -.3rem;
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
color: var(--chatlist-status-color);
|
||||||
&[class*=" tgico-"] {
|
line-height: 1;
|
||||||
color: var(--chatlist-status-color);
|
width: 1.25rem;
|
||||||
font-size: 1.25rem;
|
height: 1.25rem;
|
||||||
}
|
font-size: 1.25rem;
|
||||||
|
position: relative;
|
||||||
|
margin-top: -.0625rem;
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-time {
|
/* .message-time {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
} */
|
||||||
|
|
||||||
.tgico-chatspinned {
|
.tgico-chatspinned {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
@ -56,10 +56,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-background {
|
&-background {
|
||||||
|
// it is needed for circle scale animation
|
||||||
top: -15%;
|
top: -15%;
|
||||||
right: -15%;
|
right: -15%;
|
||||||
bottom: -15%;
|
bottom: -15%;
|
||||||
left: -15%;
|
left: -15%;
|
||||||
|
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-color);
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
@ -138,6 +140,14 @@
|
|||||||
|
|
||||||
.checkbox-box {
|
.checkbox-box {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
&-background {
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
&-border {
|
&-border {
|
||||||
border: 2px solid var(--secondary-color);
|
border: 2px solid var(--secondary-color);
|
||||||
@ -147,6 +157,10 @@
|
|||||||
&-check {
|
&-check {
|
||||||
--offset: calc(var(--size) - (var(--size) / 2 + .125rem));
|
--offset: calc(var(--size) - (var(--size) / 2 + .125rem));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html.is-safari & {
|
||||||
|
-webkit-mask-image: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,6 +287,9 @@ video::-webkit-media-controls-enclosure {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
outline: none;
|
outline: none;
|
||||||
caret-color: var(--color);
|
caret-color: var(--color);
|
||||||
|
position: absolute;
|
||||||
|
top: -.5rem;
|
||||||
|
bottom: -.5rem;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
@ -348,17 +351,24 @@ video::-webkit-media-controls-enclosure {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(calc(var(--thumb-size) / 2), -50%);
|
transform: translate(calc(var(--thumb-size) / 2), -50%) scale(1);
|
||||||
|
|
||||||
|
@include animation-level(2) {
|
||||||
|
transition: transform .125s ease-in-out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.is-focused .progress-line__filled:not(.progress-line__loaded):after {
|
||||||
|
transform: translate(calc(var(--thumb-size) / 2), -50%) scale(1.25);
|
||||||
|
}
|
||||||
|
|
||||||
&__loaded, &:before {
|
&__loaded, &:before {
|
||||||
opacity: .3;
|
opacity: .3;
|
||||||
background-color: var(--secondary-color);
|
background-color: var(--secondary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
&__seek,
|
|
||||||
&__filled,
|
&__filled,
|
||||||
&__loaded {
|
&__loaded {
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
padding-left: 4.25rem;
|
padding-left: 4.25rem;
|
||||||
height: 70px;
|
height: 70px;
|
||||||
|
|
||||||
|
.media-photo {
|
||||||
|
border-radius: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
&-ico {
|
&-ico {
|
||||||
background-color: var(--background-color);
|
background-color: var(--background-color);
|
||||||
border-radius: $border-radius;
|
border-radius: $border-radius;
|
||||||
|
@ -194,7 +194,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.checkbox-field {
|
/* .checkbox-field {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-left: -54px;
|
margin-left: -54px;
|
||||||
@ -202,7 +202,7 @@
|
|||||||
|
|
||||||
.checkbox-caption {
|
.checkbox-caption {
|
||||||
padding-left: 54px;
|
padding-left: 54px;
|
||||||
}
|
} */
|
||||||
|
|
||||||
&-wrapper {
|
&-wrapper {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
@ -310,7 +310,9 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.document-name, .audio-title, .title {
|
.document-name,
|
||||||
|
.audio-title,
|
||||||
|
.title {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
@ -347,6 +349,11 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.checkbox-field {
|
||||||
|
right: .25rem;
|
||||||
|
top: .25rem;
|
||||||
|
}
|
||||||
|
|
||||||
/* span.video-play {
|
/* span.video-play {
|
||||||
background-color: var(--message-time-background);
|
background-color: var(--message-time-background);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@ -357,6 +364,37 @@
|
|||||||
} */
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
&-box {
|
||||||
|
box-shadow: 0px 0px 3px 0px rgb(0 0 0 / 40%);
|
||||||
|
|
||||||
|
&-border {
|
||||||
|
border-color: var(--message-checkbox-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-background {
|
||||||
|
background-color: var(--message-checkbox-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-field {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.document,
|
||||||
|
.audio {
|
||||||
|
.checkbox-field {
|
||||||
|
top: 50%;
|
||||||
|
left: 0;
|
||||||
|
margin-left: 2rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&-content-media &-month {
|
&-content-media &-month {
|
||||||
&-items {
|
&-items {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -385,7 +423,8 @@
|
|||||||
//height: 54px;
|
//height: 54px;
|
||||||
height: calc(48px + 1.5rem);
|
height: calc(48px + 1.5rem);
|
||||||
|
|
||||||
&-ico, &-download {
|
&-ico,
|
||||||
|
&-download {
|
||||||
width: 48px;
|
width: 48px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
border-radius: 5px !important;
|
border-radius: 5px !important;
|
||||||
@ -412,73 +451,87 @@
|
|||||||
.search-super-item {
|
.search-super-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-top: 20px;
|
padding-left: 4.4375rem;
|
||||||
margin-left: 5px;
|
|
||||||
padding-bottom: 2px;
|
|
||||||
//padding-bottom: 10px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-left: 60px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
//min-height: 48px;
|
min-height: 4.375rem;
|
||||||
min-height: 58px;
|
cursor: pointer;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
.preview {
|
.row-media {
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
width: 3rem;
|
width: 3rem;
|
||||||
border-radius: .375rem;
|
border-radius: .375rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
left: .6875rem;
|
||||||
|
|
||||||
|
&.empty {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 2rem;
|
||||||
|
color: #fff;
|
||||||
|
text-transform: uppercase;
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .anchor-url {
|
||||||
|
&:before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
|
||||||
top: 0;
|
top: 0;
|
||||||
|
right: 0;
|
||||||
&.empty {
|
bottom: 0;
|
||||||
display: flex;
|
left: 0;
|
||||||
align-items: center;
|
content: " ";
|
||||||
justify-content: center;
|
cursor: pointer;
|
||||||
font-size: 2rem;
|
|
||||||
color: #fff;
|
|
||||||
text-transform: uppercase;
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-photo {
|
|
||||||
object-fit: cover;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
.url {
|
.media-photo {
|
||||||
white-space: nowrap;
|
object-fit: cover;
|
||||||
text-overflow: ellipsis;
|
width: 100%;
|
||||||
overflow: hidden;
|
height: 100%;
|
||||||
font-size: 14px;
|
border-radius: inherit;
|
||||||
margin-top: -1px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.row-title {
|
||||||
font-size: 16px;
|
margin-top: .1875rem;
|
||||||
margin-top: 2px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.subtitle {
|
.row-subtitle {
|
||||||
font-size: 14px;
|
overflow: hidden;
|
||||||
max-width: 310px;
|
white-space: pre-wrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-break: break-word;
|
||||||
|
|
||||||
&.sender {
|
&.sender {
|
||||||
margin-top: 2px;
|
margin-top: .125rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-super-month-items {
|
.sent-time {
|
||||||
padding: 0 24px 15px 15px;
|
margin: 1px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
.checkbox-field {
|
||||||
padding: 0 16px 15px 7px;
|
padding: 0 !important;
|
||||||
|
margin: 2rem 0 0 -1.75rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include respond-to(not-handhelds) {
|
||||||
|
.search-super-month-items {
|
||||||
|
margin: .5625rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include respond-to(handhelds) {
|
||||||
|
.search-super-month-name {
|
||||||
|
padding: .875rem 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-content-music, &-content-voice {
|
&-content-music, &-content-voice {
|
||||||
@ -528,6 +581,76 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-tabs-scrollable {
|
||||||
|
.search-super-nav-scrollable {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-super-nav-scrollable,
|
||||||
|
.search-super-selection-container {
|
||||||
|
@include animation-level(2) {
|
||||||
|
transition: opacity .2s ease-in-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-selecting {
|
||||||
|
&:not(.backwards) {
|
||||||
|
.search-super-nav-scrollable {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-super-selection-container {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-selecting {
|
||||||
|
a {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
&:not(.menu-open) {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-selection {
|
||||||
|
&-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 1rem;
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
.btn-icon + .btn-icon {
|
||||||
|
margin-left: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include respond-to(handhelds) {
|
||||||
|
padding: 0 .5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-count {
|
||||||
|
flex-grow: 1;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
white-space: nowrap;
|
||||||
|
text-transform: capitalize;
|
||||||
|
margin-left: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-container {
|
#search-container {
|
||||||
|
@ -115,4 +115,8 @@
|
|||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
left: .5rem;
|
left: .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.menu-open {
|
||||||
|
background-color: var(--light-secondary-text-color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,7 @@
|
|||||||
/*
|
// * Jolly Cobra's transition
|
||||||
* https://github.com/morethanwords/tweb
|
|
||||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
|
||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
.transition {
|
.transition {
|
||||||
--easeOutSine: cubic-bezier(.39, .575, .565, 1);
|
> .transition-item {
|
||||||
--easeInSine: cubic-bezier(.47, 0, .745, .715);
|
|
||||||
|
|
||||||
.transition-item {
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@ -71,6 +64,8 @@
|
|||||||
* slide-fade
|
* slide-fade
|
||||||
*/
|
*/
|
||||||
&.slide-fade {
|
&.slide-fade {
|
||||||
|
--easeOutSine: cubic-bezier(.39, .575, .565, 1);
|
||||||
|
--easeInSine: cubic-bezier(.47, 0, .745, .715);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
> .from {
|
> .from {
|
||||||
@ -117,6 +112,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* &.reveal {
|
||||||
|
> .to {
|
||||||
|
clip-path: inset(0 100% 0 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.animating {
|
||||||
|
> .to {
|
||||||
|
animation: reveal-in 350ms ease-in;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -188,6 +195,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* @keyframes reveal-in {
|
||||||
|
0% {
|
||||||
|
clip-path: inset(0 100% 0 0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
clip-path: inset(0 0 0 0);
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
/* .zoom-fade {
|
/* .zoom-fade {
|
||||||
transition: .15s ease-in-out opacity, .15s ease-in-out transform;
|
transition: .15s ease-in-out opacity, .15s ease-in-out transform;
|
||||||
transform: scale3d(1.1, 1.1, 1);
|
transform: scale3d(1.1, 1.1, 1);
|
||||||
|
@ -406,6 +406,10 @@ html.is-ios {
|
|||||||
//&, body {
|
//&, body {
|
||||||
position: fixed; // fix iOS fullscreen scroll
|
position: fixed; // fix iOS fullscreen scroll
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
// disable image longtapping
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@supports(padding: unquote('max(0px)')) {
|
@supports(padding: unquote('max(0px)')) {
|
||||||
@ -490,11 +494,6 @@ input, textarea, button, select, a, div {
|
|||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
.disable-hover/* ,
|
|
||||||
.disable-hover * */ {
|
|
||||||
pointer-events: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include respond-to(not-handhelds) {
|
@include respond-to(not-handhelds) {
|
||||||
.only-handhelds {
|
.only-handhelds {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
@ -1359,3 +1358,20 @@ middle-ellipsis-element {
|
|||||||
content: "W";
|
content: "W";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sending-status {
|
||||||
|
&:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* &.animating {
|
||||||
|
.sending-status-icon {
|
||||||
|
background: var(--background);
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
position: absolute;
|
||||||
|
line-height: 1 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user