Fix autocomplete regex
Increase download chunks limit
This commit is contained in:
parent
699da948e5
commit
0f7522e32a
@ -823,7 +823,7 @@ export default class AppSearchSuper {
|
||||
};
|
||||
|
||||
return Promise.all([
|
||||
appUsersManager.getTopPeers().then(peers => {
|
||||
appUsersManager.getTopPeers('correspondents').then(peers => {
|
||||
if(!middleware()) return;
|
||||
|
||||
const idx = peers.indexOf(rootScope.myId);
|
||||
|
@ -173,7 +173,7 @@ export default class Chat extends EventListenerBase<{
|
||||
|
||||
this.topbar = new ChatTopbar(this, appSidebarRight, this.appMessagesManager, this.appPeersManager, this.appChatsManager, this.appNotificationsManager);
|
||||
this.bubbles = new ChatBubbles(this, this.appMessagesManager, this.appStickersManager, this.appUsersManager, this.appInlineBotsManager, this.appPhotosManager, this.appPeersManager, this.appProfileManager);
|
||||
this.input = new ChatInput(this, this.appMessagesManager, this.appDocsManager, this.appChatsManager, this.appPeersManager, this.appWebPagesManager, this.appImManager, this.appDraftsManager, this.serverTimeManager, this.appNotificationsManager, this.appEmojiManager);
|
||||
this.input = new ChatInput(this, this.appMessagesManager, this.appDocsManager, this.appChatsManager, this.appPeersManager, this.appWebPagesManager, this.appImManager, this.appDraftsManager, this.serverTimeManager, this.appNotificationsManager, this.appEmojiManager, this.appUsersManager);
|
||||
this.selection = new ChatSelection(this, this.bubbles, this.input, this.appMessagesManager);
|
||||
this.contextMenu = new ChatContextMenu(this.bubbles.bubblesContainer, this, this.appMessagesManager, this.appPeersManager, this.appPollsManager, this.appDocsManager);
|
||||
|
||||
|
@ -41,7 +41,9 @@ export default class CommandsHelper extends AutocompletePeerHelper {
|
||||
}
|
||||
|
||||
const botInfos: BotInfo.botInfo[] = [].concat(full.bot_info);
|
||||
const index = new SearchIndex<string>(false, false);
|
||||
const index = new SearchIndex<string>({
|
||||
ignoreCase: true
|
||||
});
|
||||
|
||||
const commands: Map<string, {peerId: number, name: string, description: string}> = new Map();
|
||||
botInfos.forEach(botInfo => {
|
||||
|
@ -14,6 +14,7 @@ import type { AppImManager } from '../../lib/appManagers/appImManager';
|
||||
import type { AppDraftsManager, MyDraftMessage } from '../../lib/appManagers/appDraftsManager';
|
||||
import type { AppEmojiManager } from '../../lib/appManagers/appEmojiManager';
|
||||
import type { ServerTimeManager } from '../../lib/mtproto/serverTimeManager';
|
||||
import type { AppUsersManager } from '../../lib/appManagers/appUsersManager';
|
||||
import type Chat from './chat';
|
||||
import Recorder from '../../../public/recorder.min';
|
||||
import { isTouchSupported } from "../../helpers/touchSupport";
|
||||
@ -75,7 +76,7 @@ type ChatInputHelperType = 'edit' | 'webpage' | 'forward' | 'reply';
|
||||
|
||||
export default class ChatInput {
|
||||
// private static AUTO_COMPLETE_REG_EXP = /(\s|^)((?::|.)(?!.*[:@]).*|(?:[@\/]\S*))$/;
|
||||
private static AUTO_COMPLETE_REG_EXP = /(\s|^)((?:(?:@|^\/)\S*)|(?::|[^:@\/])(?!.*[:@\/]).*)$/;
|
||||
private static AUTO_COMPLETE_REG_EXP = /(\s|^)((?:(?:@|^\/)\S*)|(?::|^[^:@\/])(?!.*[:@\/]).*)$/;
|
||||
public messageInput: HTMLElement;
|
||||
public messageInputField: InputField;
|
||||
private fileInput: HTMLInputElement;
|
||||
@ -169,7 +170,8 @@ export default class ChatInput {
|
||||
private appDraftsManager: AppDraftsManager,
|
||||
private serverTimeManager: ServerTimeManager,
|
||||
private appNotificationsManager: AppNotificationsManager,
|
||||
private appEmojiManager: AppEmojiManager
|
||||
private appEmojiManager: AppEmojiManager,
|
||||
private appUsersManager: AppUsersManager
|
||||
) {
|
||||
this.listenerSetter = new ListenerSetter();
|
||||
}
|
||||
@ -448,7 +450,8 @@ export default class ChatInput {
|
||||
|
||||
this.listenerSetter.add(rootScope)('settings_updated', () => {
|
||||
if(this.stickersHelper || this.emojiHelper) {
|
||||
this.previousQuery = undefined;
|
||||
// this.previousQuery = undefined;
|
||||
this.previousQuery = '';
|
||||
this.checkAutocomplete();
|
||||
/* if(!rootScope.settings.stickers.suggest) {
|
||||
this.stickersHelper.checkEmoticon('');
|
||||
@ -1242,20 +1245,27 @@ export default class ChatInput {
|
||||
|
||||
value = value.substr(0, caretPos);
|
||||
|
||||
const matches = value.match(ChatInput.AUTO_COMPLETE_REG_EXP);
|
||||
if(!matches) {
|
||||
this.previousQuery = undefined;
|
||||
this.autocompleteHelperController.hideOtherHelpers();
|
||||
if(this.previousQuery === value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.previousQuery === matches[0]) {
|
||||
this.previousQuery = value;
|
||||
|
||||
const matches = value.match(ChatInput.AUTO_COMPLETE_REG_EXP);
|
||||
let foundHelper: AutocompleteHelper;
|
||||
if(!matches) {
|
||||
foundHelper = this.checkInlineAutocomplete(value);
|
||||
// this.previousQuery = undefined;
|
||||
this.autocompleteHelperController.hideOtherHelpers(foundHelper);
|
||||
return;
|
||||
}
|
||||
|
||||
/* if(this.previousQuery === matches[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.previousQuery = matches[0];
|
||||
this.previousQuery = matches[0]; */
|
||||
|
||||
let foundHelper: AutocompleteHelper;
|
||||
const entity = entities[0];
|
||||
|
||||
const query = matches[2];
|
||||
@ -1267,14 +1277,9 @@ export default class ChatInput {
|
||||
entity?._ === 'messageEntityEmoji' && entity.length === value.length && !entity.offset) {
|
||||
foundHelper = this.stickersHelper;
|
||||
this.stickersHelper.checkEmoticon(value);
|
||||
} else
|
||||
//let query = cleanSearchText(query);
|
||||
|
||||
//console.log('autocomplete matches', matches);
|
||||
|
||||
if(firstChar === '@') { // mentions
|
||||
} else if(firstChar === '@') { // mentions
|
||||
const topMsgId = this.chat.threadId ? this.appMessagesManager.getServerMessageId(this.chat.threadId) : undefined;
|
||||
if(this.mentionsHelper.checkQuery(query, this.chat.peerId, topMsgId)) {
|
||||
if(this.mentionsHelper.checkQuery(query, this.chat.peerId > 0 ? 0 : this.chat.peerId, topMsgId)) {
|
||||
foundHelper = this.mentionsHelper;
|
||||
}
|
||||
} else if(!matches[1] && firstChar === '/') { // commands
|
||||
@ -1286,11 +1291,33 @@ export default class ChatInput {
|
||||
foundHelper = this.emojiHelper;
|
||||
this.emojiHelper.checkQuery(query, firstChar);
|
||||
}
|
||||
} else {
|
||||
foundHelper = this.checkInlineAutocomplete(value);
|
||||
}
|
||||
|
||||
this.autocompleteHelperController.hideOtherHelpers(foundHelper);
|
||||
}
|
||||
|
||||
private checkInlineAutocomplete(value: string): AutocompleteHelper {
|
||||
return;
|
||||
|
||||
const inlineMatch = value.match(/^@([a-zA-Z\\d_]{3,32})\s/);
|
||||
if(inlineMatch) {
|
||||
const username = inlineMatch[1];
|
||||
console.log('inline match username', username);
|
||||
this.appUsersManager.resolveUsername(username).then(peer => {
|
||||
if(peer._ === 'user') {
|
||||
if(peer.bot_inline_placeholder) {
|
||||
this.messageInput.dataset.inlinePlaceholder = peer.bot_inline_placeholder;
|
||||
}
|
||||
|
||||
console.log(peer);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private onBtnSendClick = (e: Event) => {
|
||||
cancelEvent(e);
|
||||
|
||||
|
@ -43,9 +43,9 @@ export default class MentionsHelper extends AutocompletePeerHelper {
|
||||
|
||||
public checkQuery(query: string, peerId: number, topMsgId: number) {
|
||||
const trimmed = query.trim(); // check that there is no whitespace
|
||||
if(peerId > 0 || query.length !== trimmed.length) return false;
|
||||
if(query.length !== trimmed.length) return false;
|
||||
|
||||
this.appProfileManager.getMentions(-peerId, trimmed, topMsgId).then(peerIds => {
|
||||
this.appProfileManager.getMentions(peerId ? -peerId : 0, trimmed, topMsgId).then(peerIds => {
|
||||
const username = trimmed.slice(1).toLowerCase();
|
||||
this.render(peerIds.map(peerId => {
|
||||
const user = this.appUsersManager.getUser(peerId);
|
||||
|
@ -246,7 +246,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
this.archivedCount.classList.toggle('hide', !e.count);
|
||||
});
|
||||
|
||||
appUsersManager.getTopPeers();
|
||||
appUsersManager.getTopPeers('correspondents');
|
||||
|
||||
appStateManager.getState().then(state => {
|
||||
const recentSearch = state.recentSearch || [];
|
||||
|
@ -14,20 +14,40 @@ import Config from "../lib/config";
|
||||
const badCharsRe = /[`~!@#$%^&*()\-_=+\[\]\\|{}'";:\/?.>,<]+/g;
|
||||
const trimRe = /^\s+|\s$/g;
|
||||
|
||||
export function clearBadCharsAndTrim(text: string) {
|
||||
return text.replace(badCharsRe, '').replace(trimRe, '');
|
||||
}
|
||||
|
||||
export function latinizeString(text: string) {
|
||||
return text.replace(/[^A-Za-z0-9]/g, (ch) => {
|
||||
const latinizeCh = Config.LatinizeMap[ch];
|
||||
return latinizeCh !== undefined ? latinizeCh : ch;
|
||||
});
|
||||
}
|
||||
|
||||
export default function cleanSearchText(text: string, latinize = true) {
|
||||
const hasTag = text.charAt(0) === '%';
|
||||
text = text.replace(badCharsRe, '').replace(trimRe, '');
|
||||
if(latinize) {
|
||||
text = text.replace(/[^A-Za-z0-9]/g, (ch) => {
|
||||
const latinizeCh = Config.LatinizeMap[ch];
|
||||
return latinizeCh !== undefined ? latinizeCh : ch;
|
||||
});
|
||||
}
|
||||
text = clearBadCharsAndTrim(text);
|
||||
if(latinize) text = latinizeString(text);
|
||||
|
||||
text = text.toLowerCase();
|
||||
if(hasTag) {
|
||||
text = '%' + text;
|
||||
}
|
||||
if(hasTag) text = '%' + text;
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
export type ProcessSearchTextOptions = Partial<{
|
||||
clearBadChars: boolean,
|
||||
latinize: boolean,
|
||||
ignoreCase: boolean,
|
||||
includeTag: boolean
|
||||
}>;
|
||||
|
||||
export function processSearchText(text: string, options: ProcessSearchTextOptions = {}) {
|
||||
const hasTag = options.includeTag && text.charAt(0) === '%';
|
||||
if(options.clearBadChars) text = clearBadCharsAndTrim(text);
|
||||
if(options.latinize) text = latinizeString(text);
|
||||
if(options.ignoreCase) text = text.toLowerCase();
|
||||
if(hasTag) text = '%' + text;
|
||||
return text;
|
||||
}
|
||||
|
@ -834,7 +834,7 @@ export class AppDialogsManager {
|
||||
appUsersManager.getContacts().then(users => {
|
||||
let key: LangPackKey, args: FormatterArguments;
|
||||
|
||||
if(users.length) {
|
||||
if(users.length/* && false */) {
|
||||
key = 'ChatList.Main.EmptyPlaceholder.Subtitle';
|
||||
args = [i18n('Contacts.Count', [users.length])];
|
||||
} else {
|
||||
|
@ -166,7 +166,7 @@ export class AppEmojiManager {
|
||||
|
||||
public indexEmojis() {
|
||||
if(!this.index) {
|
||||
this.index = new SearchIndex(false, false, 2);
|
||||
this.index = new SearchIndex(undefined, 2);
|
||||
}
|
||||
|
||||
for(const langCode in this.keywordLangPacks) {
|
||||
|
@ -397,11 +397,15 @@ export class AppProfileManager {
|
||||
|
||||
public getMentions(chatId: number, query: string, threadId?: number): Promise<number[]> {
|
||||
const processUserIds = (userIds: number[]) => {
|
||||
const startsWithAt = query.charAt(0) === '@';
|
||||
if(startsWithAt) query = query.slice(1);
|
||||
/* const startsWithAt = query.charAt(0) === '@';
|
||||
if(startsWithAt) query = query.slice(1);
|
||||
|
||||
const index = new SearchIndex<number>(!startsWithAt, !startsWithAt); */
|
||||
const index = new SearchIndex<number>(true, true);
|
||||
const index = new SearchIndex<number>({
|
||||
ignoreCase: true
|
||||
});
|
||||
userIds.forEach(userId => {
|
||||
index.indexObject(userId, appUsersManager.getUserSearchText(userId));
|
||||
});
|
||||
@ -409,19 +413,31 @@ export class AppProfileManager {
|
||||
return Array.from(index.search(query));
|
||||
};
|
||||
|
||||
let promise: Promise<number[]>;
|
||||
if(appChatsManager.isChannel(chatId)) {
|
||||
return this.getChannelParticipants(chatId, {
|
||||
promise = this.getChannelParticipants(chatId, {
|
||||
_: 'channelParticipantsMentions',
|
||||
q: query,
|
||||
top_msg_id: threadId
|
||||
}, 50, 0).then(cP => {
|
||||
return processUserIds(cP.participants.map(p => appChatsManager.getParticipantPeerId(p)));
|
||||
return cP.participants.map(p => appChatsManager.getParticipantPeerId(p));
|
||||
});
|
||||
} else if(chatId) {
|
||||
promise = (this.getChatFull(chatId) as Promise<ChatFull.chatFull>).then(chatFull => {
|
||||
return (chatFull.participants as ChatParticipants.chatParticipants).participants.map(p => p.user_id);
|
||||
});
|
||||
} else {
|
||||
return (this.getChatFull(chatId) as Promise<ChatFull.chatFull>).then(chatFull => {
|
||||
return processUserIds((chatFull.participants as ChatParticipants.chatParticipants).participants.map(p => p.user_id));
|
||||
});
|
||||
promise = Promise.resolve([]);
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
[],// appUsersManager.getTopPeers('bots_inline').catch(() => []),
|
||||
promise
|
||||
]).then(results => {
|
||||
const peerIds = results[0].concat(results[1]);
|
||||
|
||||
return processUserIds(peerIds);
|
||||
});
|
||||
}
|
||||
|
||||
public invalidateChannelParticipants(id: number) {
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
import type { Dialog } from './appMessagesManager';
|
||||
import type { UserAuth } from '../mtproto/mtproto_config';
|
||||
import type { User } from './appUsersManager';
|
||||
import type { TopPeerType, User } from './appUsersManager';
|
||||
import type { AuthState } from '../../types';
|
||||
import type FiltersStorage from '../storages/filters';
|
||||
import type DialogsStorage from '../storages/dialogs';
|
||||
@ -54,7 +54,12 @@ export type State = {
|
||||
maxSeenMsgId: number,
|
||||
stateCreatedTime: number,
|
||||
recentEmoji: string[],
|
||||
topPeers: number[],
|
||||
topPeersCache: {
|
||||
[type in TopPeerType]?: {
|
||||
peerIds: number[],
|
||||
cachedTime: number
|
||||
}
|
||||
},
|
||||
recentSearch: number[],
|
||||
version: typeof STATE_VERSION,
|
||||
authState: AuthState,
|
||||
@ -103,7 +108,7 @@ export const STATE_INIT: State = {
|
||||
maxSeenMsgId: 0,
|
||||
stateCreatedTime: Date.now(),
|
||||
recentEmoji: [],
|
||||
topPeers: [],
|
||||
topPeersCache: {},
|
||||
recentSearch: [],
|
||||
version: STATE_VERSION,
|
||||
authState: {
|
||||
|
@ -16,7 +16,7 @@ import cleanSearchText from "../../helpers/cleanSearchText";
|
||||
import cleanUsername from "../../helpers/cleanUsername";
|
||||
import { tsNow } from "../../helpers/date";
|
||||
import { safeReplaceObject, isObject } from "../../helpers/object";
|
||||
import { InputUser, User as MTUser, UserProfilePhoto, UserStatus } from "../../layer";
|
||||
import { Chat, InputUser, User as MTUser, UserProfilePhoto, UserStatus } from "../../layer";
|
||||
import I18n, { i18n, LangPackKey } from "../langPack";
|
||||
//import apiManager from '../mtproto/apiManager';
|
||||
import apiManager from '../mtproto/mtprotoworker';
|
||||
@ -33,6 +33,7 @@ import appStateManager from "./appStateManager";
|
||||
// TODO: updateUserBlocked
|
||||
|
||||
export type User = MTUser.user;
|
||||
export type TopPeerType = 'correspondents' | 'bots_inline';
|
||||
|
||||
export class AppUsersManager {
|
||||
private storage = appStateManager.storages.users;
|
||||
@ -44,7 +45,7 @@ export class AppUsersManager {
|
||||
private contactsList: Set<number>;
|
||||
private updatedContactsList: boolean;
|
||||
|
||||
private getTopPeersPromise: Promise<number[]>;
|
||||
private getTopPeersPromises: {[type in TopPeerType]?: Promise<number[]>};
|
||||
|
||||
constructor() {
|
||||
this.clear(true);
|
||||
@ -182,7 +183,8 @@ export class AppUsersManager {
|
||||
this.usernames = {};
|
||||
}
|
||||
|
||||
this.contactsIndex = new SearchIndex();
|
||||
this.getTopPeersPromises = {};
|
||||
this.contactsIndex = this.createSearchIndex();
|
||||
this.contactsFillPromise = undefined;
|
||||
this.contactsList = new Set();
|
||||
this.updatedContactsList = false;
|
||||
@ -219,7 +221,7 @@ export class AppUsersManager {
|
||||
return this.contactsFillPromise || (this.contactsFillPromise = promise);
|
||||
}
|
||||
|
||||
public resolveUsername(username: string) {
|
||||
public resolveUsername(username: string): Promise<Chat | User> {
|
||||
if(username[0] === '@') {
|
||||
username = username.slice(1);
|
||||
}
|
||||
@ -314,11 +316,20 @@ export class AppUsersManager {
|
||||
|
||||
public testSelfSearch(query: string) {
|
||||
const user = this.getSelf();
|
||||
const index = new SearchIndex();
|
||||
const index = this.createSearchIndex();
|
||||
index.indexObject(user.id, this.getUserSearchText(user.id));
|
||||
return index.search(query).has(user.id);
|
||||
}
|
||||
|
||||
private createSearchIndex() {
|
||||
return new SearchIndex<number>({
|
||||
clearBadChars: true,
|
||||
ignoreCase: true,
|
||||
latinize: true,
|
||||
includeTag: true
|
||||
});
|
||||
}
|
||||
|
||||
public saveApiUsers(apiUsers: any[], override?: boolean) {
|
||||
apiUsers.forEach((user) => this.saveApiUser(user, override));
|
||||
}
|
||||
@ -721,19 +732,20 @@ export class AppUsersManager {
|
||||
});
|
||||
} */
|
||||
|
||||
public getTopPeers(): Promise<number[]> {
|
||||
if(this.getTopPeersPromise) return this.getTopPeersPromise;
|
||||
public getTopPeers(type: TopPeerType): Promise<number[]> {
|
||||
if(this.getTopPeersPromises[type]) return this.getTopPeersPromises[type];
|
||||
|
||||
return this.getTopPeersPromise = appStateManager.getState().then((state) => {
|
||||
if(state?.topPeers?.length) {
|
||||
return state.topPeers;
|
||||
return this.getTopPeersPromises[type] = appStateManager.getState().then((state) => {
|
||||
const cached = state.topPeersCache[type];
|
||||
if(cached?.peerIds?.length) {
|
||||
return cached.peerIds;
|
||||
}
|
||||
|
||||
return apiManager.invokeApi('contacts.getTopPeers', {
|
||||
correspondents: true,
|
||||
[type]: true,
|
||||
offset: 0,
|
||||
limit: 15,
|
||||
hash: 0,
|
||||
hash: 0
|
||||
}).then((result) => {
|
||||
let peerIds: number[] = [];
|
||||
if(result._ === 'contacts.topPeers') {
|
||||
@ -750,7 +762,11 @@ export class AppUsersManager {
|
||||
}
|
||||
}
|
||||
|
||||
appStateManager.pushToState('topPeers', peerIds);
|
||||
state.topPeersCache[type] = {
|
||||
peerIds,
|
||||
cachedTime: Date.now()
|
||||
};
|
||||
appStateManager.pushToState('topPeersCache', state.topPeersCache);
|
||||
|
||||
return peerIds;
|
||||
});
|
||||
|
@ -133,7 +133,7 @@ export class ApiFileManager {
|
||||
|
||||
private downloadCheck(dcId: string | number) {
|
||||
const downloadPull = this.downloadPulls[dcId];
|
||||
const downloadLimit = dcId === 'upload' ? 24 : 24;
|
||||
const downloadLimit = dcId === 'upload' ? 24 : 36;
|
||||
//const downloadLimit = Infinity;
|
||||
|
||||
if(this.downloadActives[dcId] >= downloadLimit || !downloadPull || !downloadPull.length) {
|
||||
|
@ -9,14 +9,13 @@
|
||||
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import cleanSearchText from '../helpers/cleanSearchText';
|
||||
import { processSearchText, ProcessSearchTextOptions } from '../helpers/cleanSearchText';
|
||||
|
||||
export default class SearchIndex<SearchWhat> {
|
||||
private fullTexts: Map<SearchWhat, string> = new Map();
|
||||
|
||||
// minChars can be 0 because it requires at least one word (one symbol) to be found
|
||||
constructor(private cleanText = true, private latinize = true, private minChars: number = 0) {
|
||||
|
||||
constructor(private options?: ProcessSearchTextOptions, private minChars = 0) {
|
||||
}
|
||||
|
||||
public indexObject(id: SearchWhat, searchText: string) {
|
||||
@ -24,8 +23,8 @@ export default class SearchIndex<SearchWhat> {
|
||||
return false;
|
||||
} */
|
||||
|
||||
if(searchText.trim() && this.cleanText) {
|
||||
searchText = cleanSearchText(searchText, this.latinize);
|
||||
if(this.options && searchText.trim()) {
|
||||
searchText = processSearchText(searchText, this.options);
|
||||
}
|
||||
|
||||
if(!searchText) {
|
||||
@ -54,8 +53,8 @@ export default class SearchIndex<SearchWhat> {
|
||||
const fullTexts = this.fullTexts;
|
||||
//const shortIndexes = searchIndex.shortIndexes;
|
||||
|
||||
if(this.cleanText) {
|
||||
query = cleanSearchText(query, this.latinize);
|
||||
if(this.options) {
|
||||
query = processSearchText(query, this.options);
|
||||
}
|
||||
|
||||
const newFoundObjs: Array<{fullText: string, fullTextLength: number, what: SearchWhat, foundChars: number}> = [];
|
||||
|
@ -133,7 +133,12 @@ export default class DialogsStorage {
|
||||
1: []
|
||||
};
|
||||
this.dialogsNum = 0;
|
||||
this.dialogsIndex = new SearchIndex<number>();
|
||||
this.dialogsIndex = new SearchIndex<number>({
|
||||
clearBadChars: true,
|
||||
ignoreCase: true,
|
||||
latinize: true,
|
||||
includeTag: true
|
||||
});
|
||||
this.cachedResults = {
|
||||
query: '',
|
||||
count: 0,
|
||||
|
@ -142,6 +142,12 @@ $chat-helper-size: 39px;
|
||||
@include respond-to(handhelds) {
|
||||
max-height: 10rem;
|
||||
}
|
||||
|
||||
&[data-inline-placeholder]:after {
|
||||
content: attr(data-inline-placeholder);
|
||||
color: #a2acb4;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.toggle-emoticons {
|
||||
|
Loading…
Reference in New Issue
Block a user