Private search in RS & search highlight query & sidebar stripe animation
This commit is contained in:
parent
bd0a2bdf39
commit
dd877bee83
236
src/components/appSearch.ts
Normal file
236
src/components/appSearch.ts
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
import appDialogsManager from "../lib/appManagers/appDialogsManager";
|
||||||
|
import Scrollable from "./scrollable";
|
||||||
|
import appMessagesIDsManager from "../lib/appManagers/appMessagesIDsManager";
|
||||||
|
import appUsersManager from "../lib/appManagers/appUsersManager";
|
||||||
|
import appPeersManager from '../lib/appManagers/appPeersManager';
|
||||||
|
import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
||||||
|
import { numberWithCommas, escapeRegExp } from "../lib/utils";
|
||||||
|
import { formatPhoneNumber } from "./misc";
|
||||||
|
|
||||||
|
export class SearchGroup {
|
||||||
|
container: HTMLDivElement;
|
||||||
|
nameEl: HTMLDivElement;
|
||||||
|
list: HTMLUListElement;
|
||||||
|
|
||||||
|
constructor(public name: string, public type: string) {
|
||||||
|
this.list = document.createElement('ul');
|
||||||
|
this.container = document.createElement('div');
|
||||||
|
this.nameEl = document.createElement('div');
|
||||||
|
this.nameEl.classList.add('search-group__name');
|
||||||
|
this.nameEl.innerText = name;
|
||||||
|
|
||||||
|
this.container.classList.add('search-group');
|
||||||
|
this.container.append(this.nameEl, this.list);
|
||||||
|
this.container.style.display = 'none';
|
||||||
|
|
||||||
|
appDialogsManager.setListClickListener(this.list);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.container.style.display = 'none';
|
||||||
|
this.list.innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
setActive() {
|
||||||
|
this.container.style.display = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class AppSearch {
|
||||||
|
private minMsgID = 0;
|
||||||
|
private loadedCount = 0;
|
||||||
|
private foundCount = 0;
|
||||||
|
private offsetRate = 0;
|
||||||
|
|
||||||
|
private searchPromise: Promise<void> = null;
|
||||||
|
private searchTimeout: number = 0;
|
||||||
|
|
||||||
|
private query = '';
|
||||||
|
|
||||||
|
private listsContainer: HTMLDivElement = null;
|
||||||
|
|
||||||
|
private peerID = 0; // 0 - means global
|
||||||
|
|
||||||
|
private scrollable: Scrollable;
|
||||||
|
|
||||||
|
constructor(public container: HTMLDivElement, public searchInput: HTMLInputElement, public searchGroups: {[group: string]: SearchGroup}) {
|
||||||
|
this.scrollable = new Scrollable(this.container);
|
||||||
|
this.listsContainer = this.scrollable.container;
|
||||||
|
for(let i in this.searchGroups) {
|
||||||
|
this.listsContainer.append(this.searchGroups[i].container);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.searchInput.addEventListener('input', (e) => {
|
||||||
|
let value = this.searchInput.value;
|
||||||
|
if(!value.trim()) {
|
||||||
|
//this.peerID = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.query = value;
|
||||||
|
this.reset(false);
|
||||||
|
this.searchMore();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.scrollable.onScrolledBottom = () => {
|
||||||
|
if(!this.query.trim()) return;
|
||||||
|
|
||||||
|
if(!this.searchTimeout) {
|
||||||
|
this.searchTimeout = setTimeout(() => {
|
||||||
|
this.searchMore();
|
||||||
|
this.searchTimeout = 0;
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public reset(all = true) {
|
||||||
|
if(all) {
|
||||||
|
this.searchInput.value = '';
|
||||||
|
this.query = '';
|
||||||
|
this.peerID = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.minMsgID = 0;
|
||||||
|
this.loadedCount = 0;
|
||||||
|
this.foundCount = 0;
|
||||||
|
this.offsetRate = 0;
|
||||||
|
|
||||||
|
for(let i in this.searchGroups) {
|
||||||
|
this.searchGroups[i].clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.searchPromise = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public beginSearch(peerID?: number) {
|
||||||
|
if(peerID) {
|
||||||
|
this.peerID = peerID;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.searchInput.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private searchMore() {
|
||||||
|
if(this.searchPromise) return this.searchPromise;
|
||||||
|
|
||||||
|
let query = this.query;
|
||||||
|
|
||||||
|
if(!query.trim()) return;
|
||||||
|
|
||||||
|
if(this.loadedCount != 0 && this.loadedCount >= this.foundCount) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
let maxID = appMessagesIDsManager.getMessageIDInfo(this.minMsgID)[0];
|
||||||
|
|
||||||
|
if(!this.peerID && !maxID) {
|
||||||
|
appUsersManager.searchContacts(query, 20).then((contacts: any) => {
|
||||||
|
if(this.searchInput.value != query) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////this.log('input search contacts result:', contacts);
|
||||||
|
|
||||||
|
let setResults = (results: any, group: SearchGroup, showMembersCount = false) => {
|
||||||
|
results.forEach((inputPeer: any) => {
|
||||||
|
let peerID = appPeersManager.getPeerID(inputPeer);
|
||||||
|
let peer = appPeersManager.getPeer(peerID);
|
||||||
|
let originalDialog = appMessagesManager.getDialogByPeerID(peerID)[0];
|
||||||
|
|
||||||
|
//////////this.log('contacts peer', peer);
|
||||||
|
|
||||||
|
if(!originalDialog) {
|
||||||
|
/////////this.log('no original dialog by peerID:', peerID);
|
||||||
|
|
||||||
|
originalDialog = {
|
||||||
|
peerID: peerID,
|
||||||
|
pFlags: {},
|
||||||
|
peer: peer
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let {dialog, dom} = appDialogsManager.addDialog(originalDialog, group.list, false);
|
||||||
|
|
||||||
|
if(showMembersCount && (peer.participants_count || peer.participants)) {
|
||||||
|
let regExp = new RegExp(`(${escapeRegExp(query)})`, 'gi');
|
||||||
|
dom.titleSpan.innerHTML = dom.titleSpan.innerHTML.replace(regExp, '<i>$1</i>');
|
||||||
|
|
||||||
|
let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID);
|
||||||
|
let participants_count = peer.participants_count || peer.participants.participants.length;
|
||||||
|
let subtitle = numberWithCommas(participants_count) + ' ' + (isChannel ? 'subscribers' : 'members');
|
||||||
|
dom.lastMessageSpan.innerText = subtitle;
|
||||||
|
} else {
|
||||||
|
let username = appPeersManager.getPeerUsername(peerID);
|
||||||
|
if(!username) {
|
||||||
|
let user = appUsersManager.getUser(peerID);
|
||||||
|
if(user && user.phone) {
|
||||||
|
username = '+' + formatPhoneNumber(user.phone).formatted;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
username = '@' + username;
|
||||||
|
}
|
||||||
|
|
||||||
|
dom.lastMessageSpan.innerHTML = '<i>' + username + '</i>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(results.length) {
|
||||||
|
group.setActive();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
setResults(contacts.my_results, this.searchGroups.contacts, true);
|
||||||
|
setResults(contacts.results, this.searchGroups.globalContacts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.searchPromise = appMessagesManager.getSearch(this.peerID, query, null, maxID, 20, this.offsetRate).then(res => {
|
||||||
|
this.searchPromise = null;
|
||||||
|
|
||||||
|
if(this.searchInput.value != query) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////this.log('input search result:', this.peerID, query, null, maxID, 20, res);
|
||||||
|
|
||||||
|
let {count, history, next_rate} = res;
|
||||||
|
|
||||||
|
if(history[0] == this.minMsgID) {
|
||||||
|
history.shift();
|
||||||
|
}
|
||||||
|
|
||||||
|
let searchGroup = this.searchGroups['messages'];
|
||||||
|
searchGroup.setActive();
|
||||||
|
|
||||||
|
history.forEach((msgID: number) => {
|
||||||
|
let message = appMessagesManager.getMessage(msgID);
|
||||||
|
let originalDialog = appMessagesManager.getDialogByPeerID(message.peerID)[0];
|
||||||
|
|
||||||
|
if(!originalDialog) {
|
||||||
|
////////this.log('no original dialog by message:', message);
|
||||||
|
|
||||||
|
originalDialog = {
|
||||||
|
peerID: message.peerID,
|
||||||
|
pFlags: {},
|
||||||
|
peer: message.to_id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let {dialog, dom} = appDialogsManager.addDialog(originalDialog, searchGroup.list, false);
|
||||||
|
appDialogsManager.setLastMessage(dialog, message, dom, query);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.minMsgID = history[history.length - 1];
|
||||||
|
this.offsetRate = next_rate;
|
||||||
|
this.loadedCount += history.length;
|
||||||
|
|
||||||
|
if(!this.foundCount) {
|
||||||
|
this.foundCount = count;
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('search error', err);
|
||||||
|
this.searchPromise = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -34,7 +34,9 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
|||||||
lottieLoader.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
lottieLoader.checkAnimations(false, EMOTICONSSTICKERGROUP);
|
||||||
lazyLoadQueue.check(); // for stickers
|
lazyLoadQueue.check(); // for stickers
|
||||||
});
|
});
|
||||||
(tabs.children[0] as HTMLLIElement).click(); // set media
|
|
||||||
|
(tabs.firstElementChild.children[0] as HTMLLIElement).click(); // set emoji tab
|
||||||
|
(tabs.lastElementChild as HTMLSpanElement).style.cssText = 'width: 44.1719px; transform: translateX(88.5781px);'; // мы снова встретились))))))
|
||||||
|
|
||||||
let emoticonsMenuOnClick = (menu: HTMLUListElement, heights: number[], scroll: Scrollable, menuScroll?: Scrollable) => {
|
let emoticonsMenuOnClick = (menu: HTMLUListElement, heights: number[], scroll: Scrollable, menuScroll?: Scrollable) => {
|
||||||
menu.addEventListener('click', function(e) {
|
menu.addEventListener('click', function(e) {
|
||||||
@ -151,7 +153,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
|||||||
let heights: number[] = [0];
|
let heights: number[] = [0];
|
||||||
|
|
||||||
let prevCategoryIndex = 1;
|
let prevCategoryIndex = 1;
|
||||||
let menu = contentEmojiDiv.nextElementSibling as HTMLUListElement;
|
let menu = contentEmojiDiv.nextElementSibling.firstElementChild as HTMLUListElement;
|
||||||
let emojiScroll = new Scrollable(contentEmojiDiv, 'y', 500, 'EMOJI', null);
|
let emojiScroll = new Scrollable(contentEmojiDiv, 'y', 500, 'EMOJI', null);
|
||||||
emojiScroll.container.addEventListener('scroll', (e) => {
|
emojiScroll.container.addEventListener('scroll', (e) => {
|
||||||
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll.container);
|
prevCategoryIndex = emoticonsContentOnScroll(menu, heights, prevCategoryIndex, emojiScroll.container);
|
||||||
@ -205,7 +207,7 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
|
|||||||
//let stickersDiv = contentStickersDiv.querySelector('.os-content') as HTMLDivElement;
|
//let stickersDiv = contentStickersDiv.querySelector('.os-content') as HTMLDivElement;
|
||||||
|
|
||||||
let menuWrapper = contentStickersDiv.nextElementSibling as HTMLDivElement;
|
let menuWrapper = contentStickersDiv.nextElementSibling as HTMLDivElement;
|
||||||
let menu = menuWrapper.firstElementChild as HTMLUListElement;
|
let menu = menuWrapper.firstElementChild.firstElementChild as HTMLUListElement;
|
||||||
|
|
||||||
let menuScroll = new Scrollable(menuWrapper, 'x');
|
let menuScroll = new Scrollable(menuWrapper, 'x');
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { whichChild, findUpTag, cancelEvent } from "../lib/utils";
|
import { whichChild, findUpTag } from "../lib/utils";
|
||||||
|
|
||||||
let rippleClickID = 0;
|
let rippleClickID = 0;
|
||||||
export function ripple(elem: HTMLElement, callback: (id: number) => Promise<boolean | void> = () => Promise.resolve(), onEnd: (id: number) => void = null) {
|
export function ripple(elem: HTMLElement, callback: (id: number) => Promise<boolean | void> = () => Promise.resolve(), onEnd: (id: number) => void = null) {
|
||||||
@ -141,13 +141,13 @@ export function putPreloader(elem: Element, returnDiv = false) {
|
|||||||
elem.innerHTML += html;
|
elem.innerHTML += html;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement, onClick?: (id: number, tabContent: HTMLDivElement) => void, onTransitionEnd?: () => void, transitionTime = 300) {
|
export function horizontalMenu(tabs: HTMLElement, content: HTMLDivElement, onClick?: (id: number, tabContent: HTMLDivElement) => void, onTransitionEnd?: () => void, transitionTime = 300) {
|
||||||
let hideTimeout: number = 0;
|
let hideTimeout: number = 0;
|
||||||
let prevTabContent: HTMLDivElement = null;
|
let prevTabContent: HTMLDivElement = null;
|
||||||
|
|
||||||
let prevId = -1;
|
let prevId = -1;
|
||||||
let children = Array.from(content.children);
|
let children = Array.from(content.children);
|
||||||
let tabsChildren = tabs ? Array.from(tabs.children) : [];
|
let tabsChildren = tabs ? Array.from(tabs.firstElementChild.children) : [];
|
||||||
let activeInSlide: Set<Element> = new Set();
|
let activeInSlide: Set<Element> = new Set();
|
||||||
|
|
||||||
let selectTab = (id: number) => {
|
let selectTab = (id: number) => {
|
||||||
@ -227,6 +227,11 @@ export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement,
|
|||||||
};
|
};
|
||||||
|
|
||||||
if(tabs) {
|
if(tabs) {
|
||||||
|
let activeStripe = document.createElement('span');
|
||||||
|
activeStripe.classList.add('menu-horizontal__stripe');
|
||||||
|
|
||||||
|
tabs.append(activeStripe);
|
||||||
|
|
||||||
tabs.addEventListener('click', function(e) {
|
tabs.addEventListener('click', function(e) {
|
||||||
let target = e.target as HTMLLIElement;
|
let target = e.target as HTMLLIElement;
|
||||||
|
|
||||||
@ -242,7 +247,6 @@ export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement,
|
|||||||
let tabContent = content.children[id] as HTMLDivElement;
|
let tabContent = content.children[id] as HTMLDivElement;
|
||||||
|
|
||||||
if(activeInSlide.size >= 2 && !activeInSlide.has(tabContent)) {
|
if(activeInSlide.size >= 2 && !activeInSlide.has(tabContent)) {
|
||||||
cancelEvent(e);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,6 +258,12 @@ export function horizontalMenu(tabs: HTMLUListElement, content: HTMLDivElement,
|
|||||||
let prev = tabs.querySelector('li.active') as HTMLLIElement;
|
let prev = tabs.querySelector('li.active') as HTMLLIElement;
|
||||||
prev && prev.classList.remove('active');
|
prev && prev.classList.remove('active');
|
||||||
|
|
||||||
|
let tabsRect = tabs.getBoundingClientRect();
|
||||||
|
let textRect = target.firstElementChild.getBoundingClientRect();
|
||||||
|
activeStripe.style.cssText = `width: ${textRect.width + (2 * 2)}px; transform: translateX(${textRect.left - tabsRect.left}px);`;
|
||||||
|
//activeStripe.style.transform = `scaleX(${textRect.width}) translateX(${(textRect.left - tabsRect.left) / textRect.width + 0.5}px)`;
|
||||||
|
console.log('tabs click:', tabsRect, textRect);
|
||||||
|
|
||||||
target.classList.add('active');
|
target.classList.add('active');
|
||||||
selectTab(id);
|
selectTab(id);
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { langPack, findUpClassName, $rootScope } from "../utils";
|
import { langPack, findUpClassName, $rootScope, escapeRegExp } from "../utils";
|
||||||
import appImManager, { AppImManager } from "./appImManager";
|
import appImManager, { AppImManager } from "./appImManager";
|
||||||
import appPeersManager from './appPeersManager';
|
import appPeersManager from './appPeersManager';
|
||||||
import appMessagesManager, { AppMessagesManager } from "./appMessagesManager";
|
import appMessagesManager, { AppMessagesManager } from "./appMessagesManager";
|
||||||
@ -420,7 +420,7 @@ export class AppDialogsManager {
|
|||||||
chatsHidden.down = inBottom;
|
chatsHidden.down = inBottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setLastMessage(dialog: any, lastMessage?: any, dom?: DialogDom) {
|
public setLastMessage(dialog: any, lastMessage?: any, dom?: DialogDom, highlightWord?: string) {
|
||||||
if(!lastMessage) {
|
if(!lastMessage) {
|
||||||
lastMessage = appMessagesManager.getMessage(dialog.top_message);
|
lastMessage = appMessagesManager.getMessage(dialog.top_message);
|
||||||
}
|
}
|
||||||
@ -497,12 +497,58 @@ export class AppDialogsManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(lastMessage.action) {
|
if(lastMessage.action) {
|
||||||
// @ts-ignore
|
let action = lastMessage.action;
|
||||||
lastMessageText = langPack[lastMessage.action._];
|
|
||||||
|
console.log('lastMessage action:', action);
|
||||||
|
|
||||||
|
let suffix = '';
|
||||||
|
let _ = action._;
|
||||||
|
if(_ == "messageActionPhoneCall") {
|
||||||
|
_ += '.' + action.type;
|
||||||
|
|
||||||
|
let duration = action.duration;
|
||||||
|
if(duration) {
|
||||||
|
let d = [];
|
||||||
|
|
||||||
|
d.push(duration % 60 + ' s');
|
||||||
|
if(duration > 60) d.push((duration / 60 | 0) + ' min');
|
||||||
|
if(duration > 3600) d.push((duration / 3600 | 0) + ' h');
|
||||||
|
suffix = ' (' + d.reverse().join(' ') + ')';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dom.lastMessageSpan.innerHTML = lastMessageText +
|
// @ts-ignore
|
||||||
(lastMessage.message ? RichTextProcessor.wrapRichText(lastMessage.message.replace(/\n/g, ' '), {noLinebreakers: true}) : '');
|
lastMessageText = '<i>' + langPack[_] + suffix + '</i>';
|
||||||
|
}
|
||||||
|
|
||||||
|
let messageText = lastMessage.message;
|
||||||
|
let messageWrapped = '';
|
||||||
|
if(messageText) {
|
||||||
|
let entities = RichTextProcessor.parseEntities(messageText, {noLinebreakers: true});
|
||||||
|
if(highlightWord) {
|
||||||
|
let regExp = new RegExp(escapeRegExp(highlightWord), 'gi');
|
||||||
|
let match: any;
|
||||||
|
|
||||||
|
if(!entities) entities = [];
|
||||||
|
let found = false;
|
||||||
|
while((match = regExp.exec(messageText)) !== null) {
|
||||||
|
entities.push({_: 'messageEntityHighlight', length: highlightWord.length, offset: match.index});
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(found) {
|
||||||
|
entities.sort((a: any, b: any) => a.offset - b.offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
messageWrapped = RichTextProcessor.wrapRichText(messageText.replace(/\n/g, ' '), {
|
||||||
|
noLinebreakers: true,
|
||||||
|
entities: entities,
|
||||||
|
noTextFormat: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
dom.lastMessageSpan.innerHTML = lastMessageText + messageWrapped;
|
||||||
|
|
||||||
/* if(lastMessage.from_id == auth.id) { // You: */
|
/* if(lastMessage.from_id == auth.id) { // You: */
|
||||||
if(peer._ != 'peerUser' && peerID != -lastMessage.from_id) {
|
if(peer._ != 'peerUser' && peerID != -lastMessage.from_id) {
|
||||||
|
@ -26,6 +26,8 @@ import LazyLoadQueue from '../../components/lazyLoadQueue';
|
|||||||
|
|
||||||
console.log('appImManager included!');
|
console.log('appImManager included!');
|
||||||
|
|
||||||
|
appSidebarLeft; // just to include
|
||||||
|
|
||||||
let testScroll = false;
|
let testScroll = false;
|
||||||
|
|
||||||
export class AppImManager {
|
export class AppImManager {
|
||||||
@ -343,7 +345,7 @@ export class AppImManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ids = Object.keys(this.bubbles).map(k => +k).filter(id => {
|
let ids = Object.keys(this.bubbles).map(k => +k).filter(id => {
|
||||||
if(!this.scrollable.visibleElements.find(e => e.element == this.bubbles[id])) return false;
|
//if(!this.scrollable.visibleElements.find(e => e.element == this.bubbles[id])) return false;
|
||||||
|
|
||||||
let message = appMessagesManager.getMessage(id);
|
let message = appMessagesManager.getMessage(id);
|
||||||
|
|
||||||
@ -370,7 +372,9 @@ export class AppImManager {
|
|||||||
|
|
||||||
this.searchBtn.addEventListener('click', (e) => {
|
this.searchBtn.addEventListener('click', (e) => {
|
||||||
if(this.peerID) {
|
if(this.peerID) {
|
||||||
appSidebarLeft.beginSearch(this.peerID);
|
appSidebarRight.beginSearch();
|
||||||
|
//appSidebarLeft.archivedCount;
|
||||||
|
//appSidebarLeft.beginSearch(this.peerID);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -912,6 +916,8 @@ export class AppImManager {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
appSidebarRight.searchCloseBtn.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear
|
// clear
|
||||||
|
@ -1,50 +1,16 @@
|
|||||||
import { logger } from "../polyfill";
|
//import { logger } from "../polyfill";
|
||||||
import { formatPhoneNumber } from "../../components/misc";
|
|
||||||
import Scrollable from '../../components/scrollable';
|
|
||||||
import appMessagesManager from "./appMessagesManager";
|
|
||||||
import appDialogsManager from "./appDialogsManager";
|
import appDialogsManager from "./appDialogsManager";
|
||||||
import { isElementInViewport, numberWithCommas, $rootScope } from "../utils";
|
import { $rootScope } from "../utils";
|
||||||
import appMessagesIDsManager from "./appMessagesIDsManager";
|
|
||||||
import appImManager from "./appImManager";
|
import appImManager from "./appImManager";
|
||||||
import appUsersManager from "./appUsersManager";
|
|
||||||
import apiManager from "../mtproto/apiManager";
|
import apiManager from "../mtproto/apiManager";
|
||||||
import appPeersManager from './appPeersManager';
|
import AppSearch, { SearchGroup } from "../../components/appSearch";
|
||||||
|
|
||||||
class SearchGroup {
|
|
||||||
container: HTMLDivElement;
|
|
||||||
nameEl: HTMLDivElement;
|
|
||||||
list: HTMLUListElement;
|
|
||||||
|
|
||||||
constructor(public name: string, public type: string) {
|
|
||||||
this.list = document.createElement('ul');
|
|
||||||
this.container = document.createElement('div');
|
|
||||||
this.nameEl = document.createElement('div');
|
|
||||||
this.nameEl.classList.add('search-group__name');
|
|
||||||
this.nameEl.innerText = name;
|
|
||||||
|
|
||||||
this.container.classList.add('search-group');
|
|
||||||
this.container.append(this.nameEl, this.list);
|
|
||||||
this.container.style.display = 'none';
|
|
||||||
|
|
||||||
appDialogsManager.setListClickListener(this.list);
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
this.container.style.display = 'none';
|
|
||||||
this.list.innerHTML = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
setActive() {
|
|
||||||
this.container.style.display = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AppSidebarLeft {
|
class AppSidebarLeft {
|
||||||
private sidebarEl = document.querySelector('.page-chats .chats-container') as HTMLDivElement;
|
private sidebarEl = document.getElementById('column-left') as HTMLDivElement;
|
||||||
private searchInput = document.getElementById('global-search') as HTMLInputElement;
|
|
||||||
private toolsBtn = this.sidebarEl.querySelector('.sidebar-tools-button') as HTMLButtonElement;
|
private toolsBtn = this.sidebarEl.querySelector('.sidebar-tools-button') as HTMLButtonElement;
|
||||||
private backBtn = this.sidebarEl.querySelector('.sidebar-back-button') as HTMLButtonElement;
|
private backBtn = this.sidebarEl.querySelector('.sidebar-back-button') as HTMLButtonElement;
|
||||||
private searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement;
|
private searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement;
|
||||||
|
private searchInput = document.getElementById('global-search') as HTMLInputElement;
|
||||||
|
|
||||||
private menuEl = this.toolsBtn.querySelector('.btn-menu');
|
private menuEl = this.toolsBtn.querySelector('.btn-menu');
|
||||||
private savedBtn = this.menuEl.querySelector('.menu-saved');
|
private savedBtn = this.menuEl.querySelector('.menu-saved');
|
||||||
@ -52,36 +18,15 @@ class AppSidebarLeft {
|
|||||||
private logOutBtn = this.menuEl.querySelector('.menu-logout');
|
private logOutBtn = this.menuEl.querySelector('.menu-logout');
|
||||||
public archivedCount = this.archivedBtn.querySelector('.archived-count') as HTMLSpanElement;
|
public archivedCount = this.archivedBtn.querySelector('.archived-count') as HTMLSpanElement;
|
||||||
|
|
||||||
private listsContainer: HTMLDivElement = null;
|
//private log = logger('SL');
|
||||||
|
|
||||||
private log = logger('SL');
|
private globalSearch = new AppSearch(this.searchContainer, this.searchInput, {
|
||||||
|
|
||||||
private peerID = 0;
|
|
||||||
private minMsgID = 0;
|
|
||||||
private loadedCount = 0;
|
|
||||||
private foundCount = 0;
|
|
||||||
private offsetRate = 0;
|
|
||||||
|
|
||||||
private searchPromise: Promise<void> = null;
|
|
||||||
private searchTimeout: number = 0;
|
|
||||||
|
|
||||||
private query = '';
|
|
||||||
|
|
||||||
public searchGroups: {[group: string]: SearchGroup} = {};
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.searchGroups = {
|
|
||||||
contacts: new SearchGroup('Contacts and Chats', 'contacts'),
|
contacts: new SearchGroup('Contacts and Chats', 'contacts'),
|
||||||
globalContacts: new SearchGroup('Global Search', 'contacts'),
|
globalContacts: new SearchGroup('Global Search', 'contacts'),
|
||||||
globalMessages: new SearchGroup('Global Search', 'messages'),
|
messages: new SearchGroup('Global Search', 'messages')
|
||||||
privateMessages: new SearchGroup('Private Search', 'messages')
|
});
|
||||||
};
|
|
||||||
|
|
||||||
this.listsContainer = new Scrollable(this.searchContainer).container;
|
|
||||||
for(let i in this.searchGroups) {
|
|
||||||
this.listsContainer.append(this.searchGroups[i].container);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
constructor() {
|
||||||
this.savedBtn.addEventListener('click', (e) => {
|
this.savedBtn.addEventListener('click', (e) => {
|
||||||
///////this.log('savedbtn click');
|
///////this.log('savedbtn click');
|
||||||
setTimeout(() => { // menu doesn't close if no timeout (lol)
|
setTimeout(() => { // menu doesn't close if no timeout (lol)
|
||||||
@ -102,18 +47,16 @@ class AppSidebarLeft {
|
|||||||
apiManager.logOut();
|
apiManager.logOut();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.listsContainer.addEventListener('scroll', this.onSidebarScroll.bind(this));
|
|
||||||
|
|
||||||
this.searchInput.addEventListener('focus', (e) => {
|
this.searchInput.addEventListener('focus', (e) => {
|
||||||
this.toolsBtn.classList.remove('active');
|
this.toolsBtn.classList.remove('active');
|
||||||
this.backBtn.classList.add('active');
|
this.backBtn.classList.add('active');
|
||||||
this.searchContainer.classList.add('active');
|
this.searchContainer.classList.add('active');
|
||||||
|
|
||||||
if(!this.searchInput.value) {
|
/* if(!this.globalSearch.searchInput.value) {
|
||||||
for(let i in this.searchGroups) {
|
for(let i in this.globalSearch.searchGroups) {
|
||||||
this.searchGroups[i].clear();
|
this.globalSearch.searchGroups[i].clear();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
this.searchInput.addEventListener('blur', (e) => {
|
this.searchInput.addEventListener('blur', (e) => {
|
||||||
if(!this.searchInput.value) {
|
if(!this.searchInput.value) {
|
||||||
@ -129,45 +72,12 @@ class AppSidebarLeft {
|
|||||||
}, {once: true});
|
}, {once: true});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.searchInput.addEventListener('input', (e) => {
|
|
||||||
//console.log('messageInput input', this.innerText, serializeNodes(Array.from(messageInput.childNodes)));
|
|
||||||
let value = this.searchInput.value;
|
|
||||||
////////this.log('input', value);
|
|
||||||
|
|
||||||
if(!value.trim()) {
|
|
||||||
//this.peerID = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.query = value;
|
|
||||||
this.minMsgID = 0;
|
|
||||||
this.loadedCount = 0;
|
|
||||||
this.foundCount = 0;
|
|
||||||
this.offsetRate = 0;
|
|
||||||
|
|
||||||
for(let i in this.searchGroups) {
|
|
||||||
this.searchGroups[i].clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.searchPromise = null;
|
|
||||||
this.searchMore();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.backBtn.addEventListener('click', (e) => {
|
this.backBtn.addEventListener('click', (e) => {
|
||||||
appDialogsManager.chatsArchivedContainer.classList.remove('active');
|
appDialogsManager.chatsArchivedContainer.classList.remove('active');
|
||||||
this.toolsBtn.classList.add('active');
|
this.toolsBtn.classList.add('active');
|
||||||
this.backBtn.classList.remove('active');
|
this.backBtn.classList.remove('active');
|
||||||
this.searchInput.value = '';
|
|
||||||
this.searchContainer.classList.remove('active');
|
this.searchContainer.classList.remove('active');
|
||||||
this.peerID = 0;
|
this.globalSearch.reset();
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener('resize', () => {
|
|
||||||
//this.chatsLoadCount = Math.round(document.body.scrollHeight / 70 * 1.5);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.onSidebarScroll();
|
|
||||||
}, 0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$rootScope.$on('dialogs_archived_unread', (e: CustomEvent) => {
|
$rootScope.$on('dialogs_archived_unread', (e: CustomEvent) => {
|
||||||
@ -178,154 +88,6 @@ class AppSidebarLeft {
|
|||||||
this.log('got top categories:', categories);
|
this.log('got top categories:', categories);
|
||||||
}); */
|
}); */
|
||||||
}
|
}
|
||||||
|
|
||||||
public onSidebarScroll() {
|
|
||||||
if(!this.query.trim()) return;
|
|
||||||
|
|
||||||
let elements = Array.from(this.searchGroups[this.peerID ? 'privateMessages' : 'globalMessages'].list.childNodes).slice(-5);
|
|
||||||
for(let li of elements) {
|
|
||||||
if(isElementInViewport(li)) {
|
|
||||||
this.log('Will load more search');
|
|
||||||
|
|
||||||
if(!this.searchTimeout) {
|
|
||||||
this.searchTimeout = setTimeout(() => {
|
|
||||||
this.searchMore();
|
|
||||||
this.searchTimeout = 0;
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public beginSearch(peerID?: number) {
|
|
||||||
if(peerID) {
|
|
||||||
this.peerID = peerID;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.searchInput.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
private searchMore() {
|
|
||||||
if(this.searchPromise) return this.searchPromise;
|
|
||||||
|
|
||||||
let query = this.query;
|
|
||||||
|
|
||||||
if(!query.trim()) return;
|
|
||||||
|
|
||||||
if(this.loadedCount != 0 && this.loadedCount >= this.foundCount) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
let maxID = appMessagesIDsManager.getMessageIDInfo(this.minMsgID)[0];
|
|
||||||
|
|
||||||
if(!this.peerID && !maxID) {
|
|
||||||
appUsersManager.searchContacts(query, 20).then((contacts: any) => {
|
|
||||||
if(this.searchInput.value != query) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////this.log('input search contacts result:', contacts);
|
|
||||||
|
|
||||||
let setResults = (results: any, group: SearchGroup, showMembersCount = false) => {
|
|
||||||
results.forEach((inputPeer: any) => {
|
|
||||||
let peerID = appPeersManager.getPeerID(inputPeer);
|
|
||||||
let peer = appPeersManager.getPeer(peerID);
|
|
||||||
let originalDialog = appMessagesManager.getDialogByPeerID(peerID)[0];
|
|
||||||
|
|
||||||
//////////this.log('contacts peer', peer);
|
|
||||||
|
|
||||||
if(!originalDialog) {
|
|
||||||
/////////this.log('no original dialog by peerID:', peerID);
|
|
||||||
|
|
||||||
originalDialog = {
|
|
||||||
peerID: peerID,
|
|
||||||
pFlags: {},
|
|
||||||
peer: peer
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let {dialog, dom} = appDialogsManager.addDialog(originalDialog, group.list, false);
|
|
||||||
|
|
||||||
if(showMembersCount && (peer.participants_count || peer.participants)) {
|
|
||||||
let isChannel = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID);
|
|
||||||
let participants_count = peer.participants_count || peer.participants.participants.length;
|
|
||||||
let subtitle = numberWithCommas(participants_count) + ' ' + (isChannel ? 'subscribers' : 'members');
|
|
||||||
dom.lastMessageSpan.innerText = subtitle;
|
|
||||||
} else {
|
|
||||||
let username = appPeersManager.getPeerUsername(peerID);
|
|
||||||
if(!username) {
|
|
||||||
let user = appUsersManager.getUser(peerID);
|
|
||||||
if(user && user.phone) {
|
|
||||||
username = '+' + formatPhoneNumber(user.phone).formatted;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
username = '@' + username;
|
|
||||||
}
|
|
||||||
|
|
||||||
dom.lastMessageSpan.innerText = username;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if(results.length) {
|
|
||||||
group.setActive();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
setResults(contacts.my_results, this.searchGroups.contacts, true);
|
|
||||||
setResults(contacts.results, this.searchGroups.globalContacts);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.searchPromise = appMessagesManager.getSearch(this.peerID, query, null, maxID, 20, this.offsetRate).then(res => {
|
|
||||||
this.searchPromise = null;
|
|
||||||
|
|
||||||
if(this.searchInput.value != query) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////this.log('input search result:', this.peerID, query, null, maxID, 20, res);
|
|
||||||
|
|
||||||
let {count, history, next_rate} = res;
|
|
||||||
|
|
||||||
if(history[0] == this.minMsgID) {
|
|
||||||
history.shift();
|
|
||||||
}
|
|
||||||
|
|
||||||
let searchGroup = this.searchGroups[this.peerID ? 'privateMessages' : 'globalMessages'];
|
|
||||||
searchGroup.setActive();
|
|
||||||
|
|
||||||
history.forEach((msgID: number) => {
|
|
||||||
let message = appMessagesManager.getMessage(msgID);
|
|
||||||
let originalDialog = appMessagesManager.getDialogByPeerID(message.peerID)[0];
|
|
||||||
|
|
||||||
if(!originalDialog) {
|
|
||||||
////////this.log('no original dialog by message:', message);
|
|
||||||
|
|
||||||
originalDialog = {
|
|
||||||
peerID: message.peerID,
|
|
||||||
pFlags: {},
|
|
||||||
peer: message.to_id
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let {dialog, dom} = appDialogsManager.addDialog(originalDialog, searchGroup.list, false);
|
|
||||||
appDialogsManager.setLastMessage(dialog, message, dom);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.minMsgID = history[history.length - 1];
|
|
||||||
this.offsetRate = next_rate;
|
|
||||||
this.loadedCount += history.length;
|
|
||||||
|
|
||||||
if(!this.foundCount) {
|
|
||||||
this.foundCount = count;
|
|
||||||
}
|
|
||||||
}).catch(err => {
|
|
||||||
this.log.error('search error', err);
|
|
||||||
this.searchPromise = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const appSidebarLeft = new AppSidebarLeft();
|
const appSidebarLeft = new AppSidebarLeft();
|
||||||
|
@ -12,12 +12,14 @@ import appImManager from "./appImManager";
|
|||||||
import appMediaViewer from "./appMediaViewer";
|
import appMediaViewer from "./appMediaViewer";
|
||||||
import LazyLoadQueue from "../../components/lazyLoadQueue";
|
import LazyLoadQueue from "../../components/lazyLoadQueue";
|
||||||
import { wrapDocument, wrapAudio } from "../../components/wrappers";
|
import { wrapDocument, wrapAudio } from "../../components/wrappers";
|
||||||
|
import AppSearch, { SearchGroup } from "../../components/appSearch";
|
||||||
|
|
||||||
const testScroll = false;
|
const testScroll = false;
|
||||||
|
|
||||||
class AppSidebarRight {
|
class AppSidebarRight {
|
||||||
public sidebarEl = document.querySelector('.profile-container') as HTMLDivElement;
|
public sidebarEl = document.getElementById('column-right') as HTMLDivElement;
|
||||||
public profileContentEl = document.querySelector('.profile-content') as HTMLDivElement;
|
public profileContainer = this.sidebarEl.querySelector('.profile-container') as HTMLDivElement;
|
||||||
|
public profileContentEl = this.sidebarEl.querySelector('.profile-content') as HTMLDivElement;
|
||||||
public profileElements = {
|
public profileElements = {
|
||||||
avatar: this.profileContentEl.querySelector('.profile-avatar') as HTMLDivElement,
|
avatar: this.profileContentEl.querySelector('.profile-avatar') as HTMLDivElement,
|
||||||
name: this.profileContentEl.querySelector('.profile-name') as HTMLDivElement,
|
name: this.profileContentEl.querySelector('.profile-name') as HTMLDivElement,
|
||||||
@ -89,11 +91,18 @@ class AppSidebarRight {
|
|||||||
|
|
||||||
public urlsToRevoke: string[] = [];
|
public urlsToRevoke: string[] = [];
|
||||||
|
|
||||||
|
private searchContainer = this.sidebarEl.querySelector('#search-private-container') as HTMLDivElement;
|
||||||
|
public searchCloseBtn = this.searchContainer.querySelector('.sidebar-close-button') as HTMLButtonElement;
|
||||||
|
private searchInput = document.getElementById('private-search') as HTMLInputElement;
|
||||||
|
public privateSearch = new AppSearch(this.searchContainer.querySelector('.chats-container') as HTMLDivElement, this.searchInput, {
|
||||||
|
messages: new SearchGroup('Private Search', 'messages')
|
||||||
|
});
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
let container = this.profileContentEl.querySelector('.profile-tabs-content') as HTMLDivElement;
|
let container = this.profileContentEl.querySelector('.profile-tabs-content') as HTMLDivElement;
|
||||||
this.profileTabs = this.profileContentEl.querySelector('.profile-tabs') as HTMLUListElement;
|
this.profileTabs = this.profileContentEl.querySelector('.profile-tabs') as HTMLUListElement;
|
||||||
|
|
||||||
this.scroll = new Scrollable(this.sidebarEl, 'y', 1200, 'SR');
|
this.scroll = new Scrollable(this.profileContainer, 'y', 1200, 'SR');
|
||||||
this.scroll.container.addEventListener('scroll', this.onSidebarScroll.bind(this));
|
this.scroll.container.addEventListener('scroll', this.onSidebarScroll.bind(this));
|
||||||
this.scroll.onScrolledBottom = () => {
|
this.scroll.onScrolledBottom = () => {
|
||||||
if(this.sharedMediaSelected && !this.scroll.hiddenElements.down.length && this.sharedMediaSelected.childElementCount/* && false */) {
|
if(this.sharedMediaSelected && !this.scroll.hiddenElements.down.length && this.sharedMediaSelected.childElementCount/* && false */) {
|
||||||
@ -132,6 +141,11 @@ class AppSidebarRight {
|
|||||||
this.toggleSidebar(false);
|
this.toggleSidebar(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.searchCloseBtn.addEventListener('click', () => {
|
||||||
|
this.searchContainer.classList.remove('active');
|
||||||
|
this.privateSearch.reset();
|
||||||
|
});
|
||||||
|
|
||||||
this.sharedMedia.contentMedia.addEventListener('click', (e) => {
|
this.sharedMedia.contentMedia.addEventListener('click', (e) => {
|
||||||
let target = e.target as HTMLDivElement;
|
let target = e.target as HTMLDivElement;
|
||||||
|
|
||||||
@ -176,6 +190,12 @@ class AppSidebarRight {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public beginSearch() {
|
||||||
|
this.toggleSidebar(true);
|
||||||
|
this.searchContainer.classList.add('active');
|
||||||
|
this.privateSearch.beginSearch(this.peerID);
|
||||||
|
}
|
||||||
|
|
||||||
public onSidebarScroll() {
|
public onSidebarScroll() {
|
||||||
this.lazyLoadQueueSidebar.check();
|
this.lazyLoadQueueSidebar.check();
|
||||||
}
|
}
|
||||||
@ -192,11 +212,7 @@ class AppSidebarRight {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.sidebarEl.classList.contains('active')) {
|
this.sidebarEl.classList.toggle('active');
|
||||||
this.sidebarEl.classList.remove('active');
|
|
||||||
} else {
|
|
||||||
this.sidebarEl.classList.add('active');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public performSearchResult(ids: number[], type: string) {
|
public performSearchResult(ids: number[], type: string) {
|
||||||
@ -533,7 +549,7 @@ class AppSidebarRight {
|
|||||||
this.savedVirtualStates = {};
|
this.savedVirtualStates = {};
|
||||||
this.prevTabID = -1;
|
this.prevTabID = -1;
|
||||||
this.scroll.setVirtualContainer(null);
|
this.scroll.setVirtualContainer(null);
|
||||||
(this.profileTabs.children[1] as HTMLLIElement).click(); // set media
|
(this.profileTabs.firstElementChild.children[1] as HTMLLIElement).click(); // set media
|
||||||
|
|
||||||
//this.scroll.getScrollTopOffset();
|
//this.scroll.getScrollTopOffset();
|
||||||
|
|
||||||
|
@ -547,6 +547,11 @@ function wrapRichText (text, options = {}) {
|
|||||||
)
|
)
|
||||||
break
|
break
|
||||||
case 'messageEntityBold':
|
case 'messageEntityBold':
|
||||||
|
if(options.noTextFormat) {
|
||||||
|
html.push(wrapRichNestedText(entityText, entity.nested, options));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
html.push(
|
html.push(
|
||||||
'<strong>',
|
'<strong>',
|
||||||
wrapRichNestedText(entityText, entity.nested, options),
|
wrapRichNestedText(entityText, entity.nested, options),
|
||||||
@ -554,13 +559,30 @@ function wrapRichText (text, options = {}) {
|
|||||||
)
|
)
|
||||||
break
|
break
|
||||||
case 'messageEntityItalic':
|
case 'messageEntityItalic':
|
||||||
|
if(options.noTextFormat) {
|
||||||
|
html.push(wrapRichNestedText(entityText, entity.nested, options));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
html.push(
|
html.push(
|
||||||
'<em>',
|
'<em>',
|
||||||
wrapRichNestedText(entityText, entity.nested, options),
|
wrapRichNestedText(entityText, entity.nested, options),
|
||||||
'</em>'
|
'</em>'
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
case 'messageEntityHighlight':
|
||||||
|
html.push(
|
||||||
|
'<i>',
|
||||||
|
wrapRichNestedText(entityText, entity.nested, options),
|
||||||
|
'</i>'
|
||||||
|
)
|
||||||
|
break;
|
||||||
case 'messageEntityCode':
|
case 'messageEntityCode':
|
||||||
|
if(options.noTextFormat) {
|
||||||
|
html.push(encodeEntities(entityText));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
html.push(
|
html.push(
|
||||||
'<code>',
|
'<code>',
|
||||||
encodeEntities(entityText),
|
encodeEntities(entityText),
|
||||||
@ -568,6 +590,11 @@ function wrapRichText (text, options = {}) {
|
|||||||
)
|
)
|
||||||
break
|
break
|
||||||
case 'messageEntityPre':
|
case 'messageEntityPre':
|
||||||
|
if(options.noTextFormat) {
|
||||||
|
html.push(encodeEntities(entityText));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
html.push(
|
html.push(
|
||||||
'<pre><code', (entity.language ? ' class="language-' + encodeEntities(entity.language) + '"' : ''), '>',
|
'<pre><code', (entity.language ? ' class="language-' + encodeEntities(entity.language) + '"' : ''), '>',
|
||||||
encodeEntities(entityText),
|
encodeEntities(entityText),
|
||||||
|
@ -615,6 +615,13 @@ export function listUniqSorted (list) {
|
|||||||
return resultList
|
return resultList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// credits to https://github.com/sindresorhus/escape-string-regexp/blob/master/index.js
|
||||||
|
export function escapeRegExp(str) {
|
||||||
|
return str
|
||||||
|
.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
|
||||||
|
.replace(/-/g, '\\x2d');
|
||||||
|
}
|
||||||
|
|
||||||
export function encodeEntities (value) {
|
export function encodeEntities (value) {
|
||||||
return value.replace(/&/g, '&').replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, function (value) {
|
return value.replace(/&/g, '&').replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, function (value) {
|
||||||
var hi = value.charCodeAt(0)
|
var hi = value.charCodeAt(0)
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
.chats-container {
|
.chats-container {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
.input-search {
|
.input-search {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -155,8 +157,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.user-title {
|
.user-title {
|
||||||
max-width: 80%;
|
|
||||||
|
|
||||||
img.emoji {
|
img.emoji {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
@ -174,13 +174,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.user-last-message {
|
.user-last-message {
|
||||||
max-width: 80%;
|
|
||||||
|
|
||||||
i {
|
|
||||||
font-style: normal;
|
|
||||||
color: $darkblue;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.emoji {
|
img.emoji {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
@ -194,6 +187,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-title, .user-last-message {
|
||||||
|
max-width: 80%;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-style: normal;
|
||||||
|
color: $darkblue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.message-status {
|
.message-status {
|
||||||
margin-right: .1rem;
|
margin-right: .1rem;
|
||||||
//margin-top: .3rem;
|
//margin-top: .3rem;
|
||||||
@ -241,4 +243,17 @@
|
|||||||
.unread-muted, .tgico-pinnedchat {
|
.unread-muted, .tgico-pinnedchat {
|
||||||
background: #c5c9cc;
|
background: #c5c9cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-group {
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 1px solid #DADCE0;
|
||||||
|
padding: 1rem 0 .5rem;
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
color: $color-gray;
|
||||||
|
padding: 0 1.85rem;
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,7 +195,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.emoji-padding, .stickers-padding {
|
.emoji-padding, .stickers-padding {
|
||||||
.menu-horizontal > li {
|
.menu-horizontal li {
|
||||||
font-size: 1.65rem;
|
font-size: 1.65rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,43 +1,13 @@
|
|||||||
.chats-container {
|
#column-left {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
.sidebar-content {
|
|
||||||
width: 100%;
|
|
||||||
max-height: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex; /* idk why but need */
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
> div {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#chats-container {
|
#chats-container {
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
#search-container, #chats-archived-container {
|
|
||||||
display: none;
|
|
||||||
width: 100%;
|
|
||||||
max-height: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 3;
|
|
||||||
background: #fff;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-header__btn-container {
|
.sidebar-header__btn-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 39.75px;
|
width: 39.75px;
|
||||||
@ -97,16 +67,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-group {
|
|
||||||
width: 100%;
|
|
||||||
border-bottom: 1px solid #DADCE0;
|
|
||||||
padding: 1rem 0 .5rem;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
|
|
||||||
&__name {
|
|
||||||
color: $color-gray;
|
|
||||||
padding: 0 1.85rem;
|
|
||||||
padding-bottom: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
.profile-container {
|
#column-right {
|
||||||
width: 0%;
|
width: 0%;
|
||||||
/* grid-column: 3; */
|
/* grid-column: 3; */
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: .2s ease-in-out;
|
transition: .2s ease-in-out;
|
||||||
|
|
||||||
|
.profile-container {
|
||||||
> .scrollable {
|
> .scrollable {
|
||||||
min-width: 25vw;
|
min-width: 25vw;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -15,6 +16,7 @@
|
|||||||
min-width: calc(#{$large-screen} / 4 - 1px);
|
min-width: calc(#{$large-screen} / 4 - 1px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:not(.active) {
|
&:not(.active) {
|
||||||
border-left-width: 0;
|
border-left-width: 0;
|
||||||
@ -27,6 +29,13 @@
|
|||||||
.sidebar-header {
|
.sidebar-header {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#search-private-container {
|
||||||
|
.chats-container {
|
||||||
|
position: relative;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-content {
|
.profile-content {
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
.sidebar {
|
.sidebar {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-left {
|
&-left {
|
||||||
border-right: 1px solid #DADCE0;
|
border-right: 1px solid #DADCE0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-right {
|
&-right {
|
||||||
border-left: 1px solid #DADCE0;
|
border-left: 1px solid #DADCE0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-header {
|
&-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 7.5px 20px 7.5px 15px;
|
padding: 7.5px 20px 7.5px 15px;
|
||||||
min-height: 60px;
|
min-height: 60px;
|
||||||
|
|
||||||
.sidebar-title {
|
&__title {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding-left: 2rem;
|
padding-left: 2rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@ -29,3 +28,17 @@
|
|||||||
margin-left: .5rem;
|
margin-left: .5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-content {
|
||||||
|
width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex; /* idk why but need */
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1422,16 +1422,22 @@ div.scrollable::-webkit-scrollbar-thumb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.menu-horizontal {
|
.menu-horizontal {
|
||||||
width: 100%;
|
|
||||||
color: $darkgrey;
|
color: $darkgrey;
|
||||||
margin-top: 0px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
border-bottom: 1px solid $lightgrey;
|
border-bottom: 1px solid $lightgrey;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
> li {
|
li {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: .75rem 1rem;
|
padding: .75rem 1rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -1441,21 +1447,24 @@ div.scrollable::-webkit-scrollbar-thumb {
|
|||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
position: relative;
|
|
||||||
color: $blue;
|
color: $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:after {
|
&__stripe {
|
||||||
content: '';
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: $blue;
|
background: $blue;
|
||||||
left: 24px;
|
//left: 0;
|
||||||
right: 24px;
|
left: -2px;
|
||||||
|
transition: .3s transform, .3s width;
|
||||||
|
//transition: .3s transform;
|
||||||
bottom: -1px;
|
bottom: -1px;
|
||||||
height: 4px;
|
height: 4px;
|
||||||
|
width: 1px; // need if using transform
|
||||||
|
transform: scaleX(1) translateX(0px);
|
||||||
border-top-left-radius: 2px;
|
border-top-left-radius: 2px;
|
||||||
border-top-right-radius: 2px;
|
border-top-right-radius: 2px;
|
||||||
}
|
z-index: 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1493,7 +1502,7 @@ div.scrollable::-webkit-scrollbar-thumb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.justify-start {
|
.justify-start {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-send-photo {
|
.popup-send-photo {
|
||||||
@ -1609,7 +1618,7 @@ div.scrollable::-webkit-scrollbar-thumb {
|
|||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chats-container {
|
#column-left {
|
||||||
width: 25%;
|
width: 25%;
|
||||||
/* grid-column: 1; */
|
/* grid-column: 1; */
|
||||||
}
|
}
|
||||||
@ -1635,6 +1644,24 @@ div.scrollable::-webkit-scrollbar-thumb {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#search-container, #chats-archived-container, .sidebar-search {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 3;
|
||||||
|
background: #fff;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: $large-screen) {
|
@media (min-width: $large-screen) {
|
||||||
border-top-width: 0;
|
border-top-width: 0;
|
||||||
border-bottom-width: 0;
|
border-bottom-width: 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user