Fix commands entities on sending
Fix emojis without FE0F for Apple's devices Shortened autocomplete helpers
This commit is contained in:
parent
58e8c41adb
commit
b2e3683f93
@ -1,3 +1,9 @@
|
||||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import { getMiddleware } from "../../helpers/middleware";
|
||||
import AutocompleteHelper from "./autocompleteHelper";
|
||||
|
||||
|
114
src/components/chat/autocompletePeerHelper.ts
Normal file
114
src/components/chat/autocompletePeerHelper.ts
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import RichTextProcessor from "../../lib/richtextprocessor";
|
||||
import AvatarElement from "../avatar";
|
||||
import PeerTitle from "../peerTitle";
|
||||
import Scrollable from "../scrollable";
|
||||
import AutocompleteHelper from "./autocompleteHelper";
|
||||
import AutocompleteHelperController from "./autocompleteHelperController";
|
||||
|
||||
export default class AutocompletePeerHelper extends AutocompleteHelper {
|
||||
protected static BASE_CLASS = 'autocomplete-peer-helper';
|
||||
protected static BASE_CLASS_LIST_ELEMENT = AutocompletePeerHelper.BASE_CLASS + '-list-element';
|
||||
private scrollable: Scrollable;
|
||||
|
||||
constructor(appendTo: HTMLElement, controller: AutocompleteHelperController, protected className: string, onSelect: (target: Element) => boolean | void) {
|
||||
super({
|
||||
appendTo,
|
||||
controller,
|
||||
listType: 'y',
|
||||
onSelect
|
||||
});
|
||||
|
||||
this.container.classList.add(AutocompletePeerHelper.BASE_CLASS, className);
|
||||
}
|
||||
|
||||
protected init() {
|
||||
this.list = document.createElement('div');
|
||||
this.list.classList.add(AutocompletePeerHelper.BASE_CLASS + '-list');
|
||||
|
||||
this.container.append(this.list);
|
||||
|
||||
this.scrollable = new Scrollable(this.container);
|
||||
|
||||
this.addEventListener('visible', () => {
|
||||
setTimeout(() => { // it is not rendered yet
|
||||
this.scrollable.container.scrollTop = 0;
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
|
||||
public render(data: {peerId: number, name?: string, description?: string}[]) {
|
||||
if(this.init) {
|
||||
if(!data.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.init();
|
||||
this.init = null;
|
||||
}
|
||||
|
||||
if(data.length) {
|
||||
this.list.innerHTML = '';
|
||||
data.forEach(d => {
|
||||
const div = AutocompletePeerHelper.listElement({
|
||||
className: this.className,
|
||||
peerId: d.peerId,
|
||||
name: d.name,
|
||||
description: d.description
|
||||
});
|
||||
|
||||
this.list.append(div);
|
||||
});
|
||||
}
|
||||
|
||||
this.toggle(!data.length);
|
||||
}
|
||||
|
||||
public static listElement(options: {
|
||||
className: string,
|
||||
peerId: number,
|
||||
name?: string,
|
||||
description?: string
|
||||
}) {
|
||||
const BASE = AutocompletePeerHelper.BASE_CLASS_LIST_ELEMENT;
|
||||
options.className += '-list-element';
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.classList.add(BASE, options.className);
|
||||
div.dataset.peerId = '' + options.peerId;
|
||||
|
||||
const avatar = new AvatarElement();
|
||||
avatar.classList.add('avatar-30');
|
||||
avatar.setAttribute('dialog', '0');
|
||||
avatar.setAttribute('peer', '' + options.peerId);
|
||||
|
||||
const name = document.createElement('div');
|
||||
name.classList.add(BASE + '-name', options.className + '-name');
|
||||
if(!options.name) {
|
||||
name.append(new PeerTitle({
|
||||
peerId: options.peerId,
|
||||
dialog: false,
|
||||
onlyFirstName: false,
|
||||
plainText: false
|
||||
}).element);
|
||||
} else {
|
||||
name.innerHTML = RichTextProcessor.wrapEmojiText(options.name);
|
||||
}
|
||||
|
||||
div.append(avatar, name);
|
||||
|
||||
if(options.description) {
|
||||
const description = document.createElement('div');
|
||||
description.classList.add(BASE + '-description', options.className + '-description');
|
||||
description.innerHTML = RichTextProcessor.wrapEmojiText(options.description);
|
||||
div.append(description);
|
||||
}
|
||||
|
||||
return div;
|
||||
}
|
||||
}
|
@ -143,6 +143,10 @@ export default class ChatBubbles {
|
||||
private fetchNewPromise: Promise<void>;
|
||||
private historyStorage: HistoryStorage;
|
||||
|
||||
private passEntities: Partial<{
|
||||
[_ in MessageEntity['_']]: boolean
|
||||
}> = {};
|
||||
|
||||
constructor(private chat: Chat, private appMessagesManager: AppMessagesManager, private appStickersManager: AppStickersManager, private appUsersManager: AppUsersManager, private appInlineBotsManager: AppInlineBotsManager, private appPhotosManager: AppPhotosManager, private appDocsManager: AppDocsManager, private appPeersManager: AppPeersManager, private appChatsManager: AppChatsManager, private storage: typeof sessionStorage) {
|
||||
//this.chat.log.error('Bubbles construction');
|
||||
|
||||
@ -1544,6 +1548,10 @@ export default class ChatBubbles {
|
||||
|
||||
this.peerId = peerId;
|
||||
this.replyFollowHistory.length = 0;
|
||||
|
||||
this.passEntities = {
|
||||
messageEntityBotCommand: this.appPeersManager.isAnyGroup(this.peerId) || this.appUsersManager.isBot(this.peerId)
|
||||
};
|
||||
}
|
||||
|
||||
if(DEBUG) {
|
||||
@ -2029,7 +2037,8 @@ export default class ChatBubbles {
|
||||
entities: totalEntities
|
||||
}); */
|
||||
let richText = RichTextProcessor.wrapRichText(messageMessage, {
|
||||
entities: totalEntities
|
||||
entities: totalEntities,
|
||||
passEntities: this.passEntities
|
||||
});
|
||||
|
||||
let canHaveTail = true;
|
||||
|
@ -1,78 +1,23 @@
|
||||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import type ChatInput from "./input";
|
||||
import { BotCommand } from "../../layer";
|
||||
import RichTextProcessor from "../../lib/richtextprocessor";
|
||||
import AvatarElement from "../avatar";
|
||||
import Scrollable from "../scrollable";
|
||||
import AutocompleteHelper from "./autocompleteHelper";
|
||||
import AutocompleteHelperController from "./autocompleteHelperController";
|
||||
import AutocompletePeerHelper from "./autocompletePeerHelper";
|
||||
|
||||
export default class CommandsHelper extends AutocompleteHelper {
|
||||
private scrollable: Scrollable;
|
||||
|
||||
export default class CommandsHelper extends AutocompletePeerHelper {
|
||||
constructor(appendTo: HTMLElement, controller: AutocompleteHelperController, private chatInput: ChatInput) {
|
||||
super({
|
||||
appendTo,
|
||||
super(appendTo,
|
||||
controller,
|
||||
listType: 'y',
|
||||
onSelect: (target) => {
|
||||
const command = target.querySelector('.commands-helper-command-name').innerHTML;
|
||||
chatInput.messageInput.innerHTML = command;
|
||||
'commands-helper',
|
||||
(target) => {
|
||||
const innerHTML = target.querySelector(`.${AutocompletePeerHelper.BASE_CLASS_LIST_ELEMENT}-name`).innerHTML;
|
||||
chatInput.messageInput.innerHTML = innerHTML;
|
||||
chatInput.sendMessage();
|
||||
}
|
||||
});
|
||||
|
||||
this.container.classList.add('commands-helper');
|
||||
}
|
||||
|
||||
protected init() {
|
||||
this.list = document.createElement('div');
|
||||
this.list.classList.add('commands-helper-commands');
|
||||
|
||||
this.container.append(this.list);
|
||||
|
||||
this.scrollable = new Scrollable(this.container);
|
||||
|
||||
this.addEventListener('visible', () => {
|
||||
setTimeout(() => { // it is not rendered yet
|
||||
this.scrollable.container.scrollTop = 0;
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
|
||||
public render(commands: {userId: number, command: BotCommand}[]) {
|
||||
if(this.init) {
|
||||
if(!commands.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.init();
|
||||
this.init = null;
|
||||
}
|
||||
|
||||
if(commands.length) {
|
||||
this.list.innerHTML = '';
|
||||
commands.forEach(command => {
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('commands-helper-command');
|
||||
|
||||
const avatar = new AvatarElement();
|
||||
avatar.classList.add('avatar-30');
|
||||
avatar.setAttribute('dialog', '0');
|
||||
avatar.setAttribute('peer', '' + command.userId);
|
||||
|
||||
const name = document.createElement('div');
|
||||
name.classList.add('commands-helper-command-name');
|
||||
name.innerText = '/' + command.command.command;
|
||||
|
||||
const description = document.createElement('div');
|
||||
description.classList.add('commands-helper-command-description');
|
||||
description.innerHTML = RichTextProcessor.wrapEmojiText(command.command.description);
|
||||
|
||||
div.append(avatar, name, description);
|
||||
this.list.append(div);
|
||||
});
|
||||
}
|
||||
|
||||
this.toggle(!commands.length);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,9 @@
|
||||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import type ChatInput from "./input";
|
||||
import { appendEmoji, getEmojiFromElement } from "../emoticonsDropdown/tabs/emoji";
|
||||
import { ScrollableX } from "../scrollable";
|
||||
@ -54,5 +60,9 @@ export default class EmojiHelper extends AutocompleteHelper {
|
||||
|
||||
this.waitForKey = waitForKey ? 'ArrowUp' : undefined;
|
||||
this.toggle(!emojis.length);
|
||||
|
||||
/* window.requestAnimationFrame(() => {
|
||||
this.container.style.width = (3 * 2) + (emojis.length * 44) + 'px';
|
||||
}); */
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ import CommandsHelper from './commandsHelper';
|
||||
import AutocompleteHelperController from './autocompleteHelperController';
|
||||
import AutocompleteHelper from './autocompleteHelper';
|
||||
import appUsersManager from '../../lib/appManagers/appUsersManager';
|
||||
import MentionsHelper from './mentionsHelper';
|
||||
|
||||
const RECORD_MIN_TIME = 500;
|
||||
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
||||
@ -136,9 +137,10 @@ export default class ChatInput {
|
||||
private canUndoFromHTML = '';
|
||||
|
||||
private autocompleteHelperController: AutocompleteHelperController;
|
||||
private commandsHelper: CommandsHelper;
|
||||
private emojiHelper: EmojiHelper;
|
||||
private stickersHelper: StickersHelper;
|
||||
private emojiHelper: EmojiHelper;
|
||||
private commandsHelper: CommandsHelper;
|
||||
private mentionsHelper: MentionsHelper;
|
||||
private listenerSetter: ListenerSetter;
|
||||
|
||||
private pinnedControlBtn: HTMLButtonElement;
|
||||
@ -374,6 +376,7 @@ export default class ChatInput {
|
||||
this.stickersHelper = new StickersHelper(this.rowsWrapper, this.autocompleteHelperController);
|
||||
this.emojiHelper = new EmojiHelper(this.rowsWrapper, this.autocompleteHelperController, this);
|
||||
this.commandsHelper = new CommandsHelper(this.rowsWrapper, this.autocompleteHelperController, this);
|
||||
this.mentionsHelper = new MentionsHelper(this.rowsWrapper, this.autocompleteHelperController, this);
|
||||
this.rowsWrapper.append(this.newMessageWrapper);
|
||||
|
||||
this.btnCancelRecord = ButtonIcon('delete danger btn-circle z-depth-1 btn-record-cancel');
|
||||
@ -1179,34 +1182,19 @@ export default class ChatInput {
|
||||
RichTextProcessor.mergeEntities(entities, addEntities);
|
||||
|
||||
//const saveExecuted = this.prepareDocumentExecute();
|
||||
this.messageInputField.value = RichTextProcessor.wrapDraftText(newValue, {entities});
|
||||
// can't exec .value here because it will instantly check for autocomplete
|
||||
this.messageInputField.setValueSilently(RichTextProcessor.wrapDraftText(newValue, {entities}), true);
|
||||
|
||||
const caret = this.messageInput.querySelector('.composer-sel');
|
||||
setRichFocus(this.messageInput, caret);
|
||||
caret.remove();
|
||||
|
||||
// but it's needed to be checked only here
|
||||
this.onMessageInput();
|
||||
|
||||
//saveExecuted();
|
||||
|
||||
//document.execCommand('insertHTML', true, RichTextProcessor.wrapEmojiText(emoji));
|
||||
|
||||
//const str =
|
||||
|
||||
/* var newValuePrefix
|
||||
if(matches && matches[0]) {
|
||||
newValuePrefix = prefix.substr(0, matches.index) + ':' + emoji[1] + ':'
|
||||
} else {
|
||||
newValuePrefix = prefix + ':' + emoji[1] + ':'
|
||||
}
|
||||
|
||||
if(suffix.length) {
|
||||
const html = this.getRichHtml(newValuePrefix) + ' <span id="composer_sel' + ++selId + '"></span>' + this.getRichHtml(suffix)
|
||||
this.richTextareaEl.html(html)
|
||||
setRichFocus(textarea, $('#composer_sel' + this.selId)[0])
|
||||
} else {
|
||||
const html = this.getRichHtml(newValuePrefix) + ' '
|
||||
this.richTextareaEl.html(html)
|
||||
setRichFocus(textarea)
|
||||
} */
|
||||
}
|
||||
};
|
||||
|
||||
@ -1247,6 +1235,9 @@ export default class ChatInput {
|
||||
let foundHelper: AutocompleteHelper;
|
||||
const entity = entities[0];
|
||||
|
||||
const query = matches[2];
|
||||
const firstChar = query[0];
|
||||
|
||||
if(this.stickersHelper &&
|
||||
rootScope.settings.stickers.suggest &&
|
||||
(this.chat.peerId > 0 || this.appChatsManager.hasRights(this.chat.peerId, 'send_stickers')) &&
|
||||
@ -1254,50 +1245,45 @@ export default class ChatInput {
|
||||
foundHelper = this.stickersHelper;
|
||||
this.stickersHelper.checkEmoticon(value);
|
||||
} else
|
||||
//let query = cleanSearchText(matches[2]);
|
||||
//const firstChar = matches[2][0];
|
||||
//let query = cleanSearchText(query);
|
||||
|
||||
//console.log('autocomplete matches', matches);
|
||||
|
||||
/*if (matches[2] == '@') { // mentions
|
||||
if (this.mentions && this.mentions.index) {
|
||||
if (query.length) {
|
||||
var foundObject = SearchIndexManager.search(query, this.mentions.index)
|
||||
var foundUsers = []
|
||||
var user
|
||||
for (var i = 0, length = this.mentions.users.length; i < length; i++) {
|
||||
user = this.mentions.users[i]
|
||||
if (foundObject[user.id]) {
|
||||
foundUsers.push(user)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var foundUsers = this.mentions.users
|
||||
}
|
||||
if (foundUsers.length) {
|
||||
this.showMentionSuggestions(foundUsers)
|
||||
} else {
|
||||
this.hideSuggestions()
|
||||
}
|
||||
} else {
|
||||
this.hideSuggestions()
|
||||
/* if(firstChar === '@') { // mentions
|
||||
if(this.chat.peerId < 0) {
|
||||
foundHelper = this.mentionsHelper;
|
||||
this.chat.appProfileManager.getMentions(-this.chat.peerId, query).then(peerIds => {
|
||||
this.mentionsHelper.render(peerIds.map(peerId => {
|
||||
const user = this.chat.appUsersManager.getUser(peerId);
|
||||
return {
|
||||
peerId,
|
||||
description: user.username ? '@' + user.username : undefined
|
||||
};
|
||||
}));
|
||||
});
|
||||
}
|
||||
} else */ if(!matches[1] && matches[2][0] === '/') { // commands
|
||||
} else */if(!matches[1] && firstChar === '/') { // commands
|
||||
if(appUsersManager.isBot(this.chat.peerId)) {
|
||||
foundHelper = this.commandsHelper;
|
||||
this.chat.appProfileManager.getProfileByPeerId(this.chat.peerId).then(full => {
|
||||
const botInfos: BotInfo.botInfo[] = [].concat(full.bot_info);
|
||||
const index = new SearchIndex<string>(false, false);
|
||||
const index = new SearchIndex<string>(true, false);
|
||||
|
||||
const commands: Map<string, {userId: number, command: BotCommand}> = new Map();
|
||||
const commands: Map<string, {peerId: number, name: string, description: string}> = new Map();
|
||||
botInfos.forEach(botInfo => {
|
||||
botInfo.commands.forEach(botCommand => {
|
||||
commands.set(botCommand.command, {userId: botInfo.user_id, command: botCommand});
|
||||
index.indexObject(botCommand.command, '/' + botCommand.command);
|
||||
const c = '/' + botCommand.command;
|
||||
commands.set(botCommand.command, {
|
||||
peerId: botInfo.user_id,
|
||||
name: c,
|
||||
description: botCommand.description
|
||||
});
|
||||
|
||||
index.indexObject(botCommand.command, c);
|
||||
});
|
||||
});
|
||||
|
||||
const found = index.search(matches[2]);
|
||||
const found = index.search(query);
|
||||
const filtered = Array.from(found).map(command => commands.get(command));
|
||||
this.commandsHelper.render(filtered);
|
||||
// console.log('found commands', found, filtered);
|
||||
@ -1307,9 +1293,9 @@ export default class ChatInput {
|
||||
if(!value.match(/^\s*:(.+):\s*$/)) {
|
||||
foundHelper = this.emojiHelper;
|
||||
this.appEmojiManager.getBothEmojiKeywords().then(() => {
|
||||
const q = matches[2].replace(/^:/, '');
|
||||
const q = query.replace(/^:/, '');
|
||||
const emojis = this.appEmojiManager.searchEmojis(q);
|
||||
this.emojiHelper.render(emojis, matches[2][0] !== ':');
|
||||
this.emojiHelper.render(emojis, firstChar !== ':');
|
||||
//console.log(emojis);
|
||||
});
|
||||
}
|
||||
|
24
src/components/chat/mentionsHelper.ts
Normal file
24
src/components/chat/mentionsHelper.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import type ChatInput from "./input";
|
||||
import AutocompleteHelperController from "./autocompleteHelperController";
|
||||
import AutocompletePeerHelper from "./autocompletePeerHelper";
|
||||
import placeCaretAtEnd from "../../helpers/dom/placeCaretAtEnd";
|
||||
|
||||
export default class MentionsHelper extends AutocompletePeerHelper {
|
||||
constructor(appendTo: HTMLElement, controller: AutocompleteHelperController, private chatInput: ChatInput) {
|
||||
super(appendTo,
|
||||
controller,
|
||||
'mentions-helper',
|
||||
(target) => {
|
||||
const innerHTML = target.querySelector(`.${AutocompletePeerHelper.BASE_CLASS_LIST_ELEMENT}-description`).innerHTML;
|
||||
chatInput.messageInputField.value = innerHTML + ' ';
|
||||
placeCaretAtEnd(chatInput.messageInput);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import mediaSizes from "../../helpers/mediaSizes";
|
||||
import { clamp } from "../../helpers/number";
|
||||
import { MyDocument } from "../../lib/appManagers/appDocsManager";
|
||||
import { CHAT_ANIMATION_GROUP } from "../../lib/appManagers/appImManager";
|
||||
import appStickersManager from "../../lib/appManagers/appStickersManager";
|
||||
@ -18,6 +20,7 @@ export default class StickersHelper extends AutocompleteHelper {
|
||||
private scrollable: Scrollable;
|
||||
private superStickerRenderer: SuperStickerRenderer;
|
||||
private lazyLoadQueue: LazyLoadQueue;
|
||||
private onChangeScreen: () => void;
|
||||
|
||||
constructor(appendTo: HTMLElement, controller: AutocompleteHelperController) {
|
||||
super({
|
||||
@ -37,6 +40,13 @@ export default class StickersHelper extends AutocompleteHelper {
|
||||
this.scrollable.container.scrollTop = 0;
|
||||
}, 0);
|
||||
});
|
||||
|
||||
this.addEventListener('hidden', () => {
|
||||
if(this.onChangeScreen) {
|
||||
mediaSizes.removeEventListener('changeScreen', this.onChangeScreen);
|
||||
this.onChangeScreen = undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public checkEmoticon(emoticon: string) {
|
||||
@ -79,6 +89,15 @@ export default class StickersHelper extends AutocompleteHelper {
|
||||
this.list.replaceWith(container);
|
||||
this.list = container;
|
||||
|
||||
if(!this.onChangeScreen) {
|
||||
this.onChangeScreen = () => {
|
||||
this.list.style.width = this.list.childElementCount * mediaSizes.active.esgSticker.width + 'px';
|
||||
};
|
||||
mediaSizes.addEventListener('changeScreen', this.onChangeScreen);
|
||||
}
|
||||
|
||||
this.onChangeScreen();
|
||||
|
||||
this.toggle(!stickers.length);
|
||||
this.scrollable.scrollTop = 0;
|
||||
});
|
||||
|
@ -29,7 +29,7 @@ export function appendEmoji(emoji: string, container: HTMLElement, prepend = fal
|
||||
spanEmoji.classList.add('super-emoji');
|
||||
|
||||
let kek: string;
|
||||
if(unify) {
|
||||
if(unify && !RichTextProcessor.emojiSupported) {
|
||||
kek = RichTextProcessor.wrapSingleEmoji(emoji);
|
||||
} else {
|
||||
emoji = RichTextProcessor.fixEmoji(emoji);
|
||||
|
@ -19,6 +19,7 @@ import { ChannelParticipantsFilter, ChannelsChannelParticipants, Chat, ChatFull,
|
||||
import apiManager from '../mtproto/mtprotoworker';
|
||||
import { RichTextProcessor } from "../richtextprocessor";
|
||||
import rootScope from "../rootScope";
|
||||
import SearchIndex from "../searchIndex";
|
||||
import apiUpdatesManager from "./apiUpdatesManager";
|
||||
import appChatsManager from "./appChatsManager";
|
||||
import appDownloadManager from "./appDownloadManager";
|
||||
@ -387,6 +388,17 @@ export class AppProfileManager {
|
||||
}) as any;
|
||||
}
|
||||
|
||||
public getMentions(chatId: number, query: string): Promise<number[]> {
|
||||
return (this.getChatFull(chatId) as Promise<ChatFull.chatFull>).then(chatFull => {
|
||||
const index = new SearchIndex<number>(true, true);
|
||||
(chatFull.participants as ChatParticipants.chatParticipants).participants.forEach(participant => {
|
||||
index.indexObject(participant.user_id, appUsersManager.getUserSearchText(participant.user_id));
|
||||
});
|
||||
|
||||
return Array.from(index.search(query));
|
||||
});
|
||||
}
|
||||
|
||||
public invalidateChannelParticipants(id: number) {
|
||||
delete this.chatsFull[id];
|
||||
delete this.fullPromises[-id];
|
||||
|
@ -413,7 +413,7 @@ namespace RichTextProcessor {
|
||||
fromBot: boolean,
|
||||
noTextFormat: true,
|
||||
passEntities: Partial<{
|
||||
[_ in MessageEntity['_']]: true
|
||||
[_ in MessageEntity['_']]: boolean
|
||||
}>,
|
||||
|
||||
contextHashtag?: string
|
||||
@ -513,7 +513,8 @@ namespace RichTextProcessor {
|
||||
}
|
||||
|
||||
case 'messageEntityBotCommand': {
|
||||
if(!(options.noLinks || options.noCommands || contextExternal) && !entity.unsafe) {
|
||||
// if(!(options.noLinks || options.noCommands || contextExternal)/* && !entity.unsafe */) {
|
||||
if(!options.noLinks && passEntities[entity._]) {
|
||||
const entityText = text.substr(entity.offset, entity.length);
|
||||
let command = entityText.substr(1);
|
||||
let bot: string | boolean;
|
||||
@ -525,7 +526,7 @@ namespace RichTextProcessor {
|
||||
bot = options.fromBot;
|
||||
}
|
||||
|
||||
insertPart(entity, `<a href="${encodeEntities('tg://bot_command?command=' + encodeURIComponent(command) + (bot ? '&bot=' + encodeURIComponent(bot) : ''))}" onclick="execBotCommand(this)">`, `</a>`);
|
||||
insertPart(entity, `<a href="${encodeEntities('tg://bot_command?command=' + encodeURIComponent(command) + (bot ? '&bot=' + encodeURIComponent(bot) : ''))}" ${contextExternal ? '' : 'onclick="execBotCommand(this)"'}>`, `</a>`);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -24,7 +24,7 @@ export default class SearchIndex<SearchWhat> {
|
||||
} */
|
||||
|
||||
if(searchText.trim() && this.cleanText) {
|
||||
searchText = cleanSearchText(searchText);
|
||||
searchText = cleanSearchText(searchText, this.latinize);
|
||||
}
|
||||
|
||||
if(!searchText) {
|
||||
@ -59,9 +59,11 @@ export default class SearchIndex<SearchWhat> {
|
||||
|
||||
const newFoundObjs: Array<{fullText: string, what: SearchWhat}> = [];
|
||||
const queryWords = query.split(' ');
|
||||
const queryWordsLength = queryWords.length;
|
||||
fullTexts.forEach((fullText, what) => {
|
||||
let found = true;
|
||||
for(const word of queryWords) { // * verify that all words are found
|
||||
for(let i = 0; i < queryWordsLength; ++i) { // * verify that all words are found
|
||||
const word = queryWords[i];
|
||||
const idx = fullText.indexOf(word);
|
||||
if(idx === -1 || (idx !== 0 && fullText[idx - 1] !== ' ')) { // * search only from word beginning
|
||||
found = false;
|
||||
|
@ -11,6 +11,9 @@
|
||||
overflow: hidden;
|
||||
padding: 0 !important;
|
||||
border-radius: var(--border-radius) !important;
|
||||
max-width: 100%;
|
||||
left: 0;
|
||||
width: auto !important;
|
||||
|
||||
&:not(.is-visible) {
|
||||
display: none;
|
||||
@ -21,7 +24,7 @@
|
||||
animation: fade-out-opacity .2s ease-in-out forwards;
|
||||
|
||||
&:not(.backwards) {
|
||||
animation: fade-in-opacity .2s ease-in-out forwards;
|
||||
animation-name: fade-in-opacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
44
src/scss/partials/_autocompletePeerHelper.scss
Normal file
44
src/scss/partials/_autocompletePeerHelper.scss
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
.autocomplete-peer-helper {
|
||||
.scrollable {
|
||||
position: relative;
|
||||
max-height: 232px;
|
||||
}
|
||||
|
||||
&-list {
|
||||
padding: .5rem 0;
|
||||
|
||||
&-element {
|
||||
height: 3.125rem;
|
||||
display: flex;
|
||||
// padding: 0 .75rem;
|
||||
padding: 0 2.125rem 0px 0.75rem;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
line-height: var(--line-height);
|
||||
|
||||
@include hover();
|
||||
|
||||
&-name {
|
||||
margin-left: .875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&-description {
|
||||
margin-left: .5625rem;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* .mentions-helper {
|
||||
width: 320px !important;
|
||||
} */
|
@ -1,33 +0,0 @@
|
||||
.commands-helper {
|
||||
left: 0;
|
||||
//width: 320px !important;
|
||||
|
||||
.scrollable {
|
||||
position: relative;
|
||||
max-height: 232px;
|
||||
}
|
||||
|
||||
&-commands {
|
||||
padding: .5rem 0;
|
||||
}
|
||||
|
||||
&-command {
|
||||
height: 3.125rem;
|
||||
display: flex;
|
||||
padding: 0 .75rem;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
|
||||
@include hover();
|
||||
|
||||
&-name {
|
||||
margin-left: .875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&-description {
|
||||
margin-left: .5625rem;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
.emoji-helper {
|
||||
height: 50px;
|
||||
padding: .25rem 0 !important;
|
||||
//transition: width .15s ease-in-out;
|
||||
|
||||
> .scrollable {
|
||||
position: relative;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.super-emojis {
|
||||
|
@ -13,8 +13,9 @@
|
||||
}
|
||||
|
||||
&-stickers {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
max-width: 100%;
|
||||
/* display: flex !important;
|
||||
flex-wrap: wrap; */
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
@ -23,4 +24,10 @@
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* .super-sticker {
|
||||
width: var(--esg-sticker-size);
|
||||
height: var(--esg-sticker-size);
|
||||
padding: 0;
|
||||
} */
|
||||
}
|
||||
|
@ -226,6 +226,7 @@ html.night {
|
||||
@import "partials/button";
|
||||
@import "partials/animatedIcon";
|
||||
@import "partials/autocompleteHelper";
|
||||
@import "partials/autocompletePeerHelper";
|
||||
@import "partials/badge";
|
||||
@import "partials/checkbox";
|
||||
@import "partials/chatlist";
|
||||
@ -236,7 +237,6 @@ html.night {
|
||||
@import "partials/chatMarkupTooltip";
|
||||
@import "partials/chatStickersHelper";
|
||||
@import "partials/chatEmojiHelper";
|
||||
@import "partials/chatCommandsHelper";
|
||||
@import "partials/chatSearch";
|
||||
@import "partials/chatDrop";
|
||||
@import "partials/crop";
|
||||
|
Loading…
Reference in New Issue
Block a user