Fix conflicting placeholder class name
This commit is contained in:
parent
81964d4bbb
commit
c3fcca8af9
@ -3148,14 +3148,15 @@ export default class ChatBubbles {
|
||||
}
|
||||
|
||||
private renderEmptyPlaceholder(type: 'group' | 'saved' | 'noMessages' | 'noScheduledMessages' | 'greeting', bubble: HTMLElement, message: any, elements: (Node | string)[]) {
|
||||
bubble.classList.add('empty-placeholder', 'empty-placeholder-' + type);
|
||||
const BASE_CLASS = 'empty-bubble-placeholder';
|
||||
bubble.classList.add(BASE_CLASS, BASE_CLASS + '-' + type);
|
||||
|
||||
let title: HTMLElement;
|
||||
if(type === 'group') title = i18n('GroupEmptyTitle1');
|
||||
else if(type === 'saved') title = i18n('ChatYourSelfTitle');
|
||||
else if(type === 'noMessages' || type === 'greeting') title = i18n('NoMessages');
|
||||
else if(type === 'noScheduledMessages') title = i18n('NoScheduledMessages');
|
||||
title.classList.add('center', 'empty-placeholder-title');
|
||||
title.classList.add('center', BASE_CLASS + '-title');
|
||||
|
||||
elements.push(title);
|
||||
|
||||
@ -3177,12 +3178,12 @@ export default class ChatBubbles {
|
||||
];
|
||||
} else if(type === 'greeting') {
|
||||
const subtitle = i18n('NoMessagesGreetingsDescription');
|
||||
subtitle.classList.add('center', 'empty-placeholder-subtitle');
|
||||
subtitle.classList.add('center', BASE_CLASS + '-subtitle');
|
||||
|
||||
this.messagesQueue.findAndSplice(q => q.bubble === bubble);
|
||||
|
||||
const stickerDiv = document.createElement('div');
|
||||
stickerDiv.classList.add('empty-placeholder-sticker');
|
||||
stickerDiv.classList.add(BASE_CLASS + '-sticker');
|
||||
|
||||
const middleware = this.getMiddleware();
|
||||
|
||||
@ -3221,7 +3222,7 @@ export default class ChatBubbles {
|
||||
elements.push(
|
||||
...listElements.map(elem => {
|
||||
const span = document.createElement('span');
|
||||
span.classList.add('empty-placeholder-list-item');
|
||||
span.classList.add(BASE_CLASS + '-list-item');
|
||||
span.append(elem);
|
||||
return span;
|
||||
})
|
||||
@ -3236,7 +3237,7 @@ export default class ChatBubbles {
|
||||
} else if(type === 'saved') {
|
||||
listElements.forEach(elem => {
|
||||
const i = document.createElement('span');
|
||||
i.classList.add('empty-placeholder-list-bullet');
|
||||
i.classList.add(BASE_CLASS + '-list-bullet');
|
||||
i.innerText = '•';
|
||||
elem.prepend(i);
|
||||
});
|
||||
@ -3247,7 +3248,7 @@ export default class ChatBubbles {
|
||||
bubble.classList.add('has-description');
|
||||
}
|
||||
|
||||
elements.forEach((element: any) => element.classList.add('empty-placeholder-line'));
|
||||
elements.forEach((element: any) => element.classList.add(BASE_CLASS + '-line'));
|
||||
}
|
||||
|
||||
private processLocalMessageRender(message: Message.message | Message.messageService) {
|
||||
|
@ -17,7 +17,7 @@ const App = {
|
||||
id: 1025907,
|
||||
hash: '452b0359b988148995f22ff0f4229750',
|
||||
version: '0.6.1',
|
||||
langPackVersion: '0.3.1',
|
||||
langPackVersion: '0.3.2',
|
||||
langPack: 'macos',
|
||||
langPackCode: 'en',
|
||||
domains: [MAIN_DOMAIN] as string[],
|
||||
|
@ -12,7 +12,8 @@ const set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoE
|
||||
};
|
||||
|
||||
// проблема функции в том, что она не подходит для ссылок, пригодна только для blob'ов, потому что обычным ссылкам нужен 'load' каждый раз.
|
||||
export default async function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string, callback?: (err?: Event) => void, useCache = true) {
|
||||
export default function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement,
|
||||
url: string, callback?: (err?: Event) => void, useCache = true) {
|
||||
if(!url) {
|
||||
console.error('renderImageFromUrl: no url?', elem, url);
|
||||
callback && callback();
|
||||
@ -54,3 +55,9 @@ export default async function renderImageFromUrl(elem: HTMLElement | HTMLImageEl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function renderImageFromUrlPromise(elem: Parameters<typeof renderImageFromUrl>[0], url: string, useCache?: boolean) {
|
||||
return new Promise((resolve) => {
|
||||
renderImageFromUrl(elem, url, resolve, useCache);
|
||||
});
|
||||
}
|
||||
|
@ -43,6 +43,9 @@ const lang = {
|
||||
},
|
||||
"Chat.Search.NoMessagesFound": "No messages found",
|
||||
"Chat.Search.PrivateSearch": "Private Search",
|
||||
"ChatList.Main.EmptyPlaceholder.Title": "Your chats will appear here",
|
||||
"ChatList.Main.EmptyPlaceholder.Subtitle": "You have %s on Telegram",
|
||||
"ChatList.Main.EmptyPlaceholder.SubtitleNoContacts": "Use Telegram app on your [Android](https://telegram.org/android) or [iOS](https://telegram.org/dl/ios) device to sync your contacts",
|
||||
//"ChatList.Menu.Archived": "Archived",
|
||||
"ChatList.Menu.SwitchTo.Webogram": "Switch to Old Version",
|
||||
"ChatList.Menu.SwitchTo.Z": "Switch to Z version",
|
||||
@ -54,6 +57,10 @@ const lang = {
|
||||
"ConnectionStatus.Reconnecting": "Reconnecting...",
|
||||
"ConnectionStatus.TimedOut": "Request timed out, %s",
|
||||
"ConnectionStatus.Waiting": "Waiting for network...",
|
||||
"Contacts.Count": {
|
||||
"one_value": "%d contact",
|
||||
"other_value": "%d contacts",
|
||||
},
|
||||
"Deactivated.Title": "Too many tabs...",
|
||||
"Deactivated.Subtitle": "Telegram supports only one active tab with the app.\nClick anywhere to continue using this tab.",
|
||||
/* "Drafts": {
|
||||
|
@ -4,7 +4,7 @@
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl";
|
||||
import renderImageFromUrl, { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
|
||||
import replaceContent from "../../helpers/dom/replaceContent";
|
||||
import sequentialDom from "../../helpers/sequentialDom";
|
||||
import { UserProfilePhoto, ChatPhoto, InputFileLocation } from "../../layer";
|
||||
@ -103,7 +103,7 @@ export class AppAvatarsManager {
|
||||
thumbImage.classList.add('avatar-photo', 'avatar-photo-thumbnail');
|
||||
img.classList.add('avatar-photo');
|
||||
const url = appPhotosManager.getPreviewURLFromBytes(photo.stripped_thumb);
|
||||
renderThumbPromise = renderImageFromUrl(thumbImage, url).then(() => {
|
||||
renderThumbPromise = renderImageFromUrlPromise(thumbImage, url).then(() => {
|
||||
replaceContent(div, thumbImage);
|
||||
});
|
||||
}
|
||||
@ -134,7 +134,7 @@ export class AppAvatarsManager {
|
||||
}
|
||||
|
||||
const renderPromise = loadPromise
|
||||
.then((url) => renderImageFromUrl(img, url/* , false */))
|
||||
.then((url) => renderImageFromUrlPromise(img, url/* , false */))
|
||||
.then(() => callback());
|
||||
|
||||
return {cached, loadPromise: renderThumbPromise || renderPromise};
|
||||
|
@ -29,7 +29,7 @@ import appDraftsManager, { MyDraftMessage } from "./appDraftsManager";
|
||||
import DEBUG, { MOUNT_CLASS_TO } from "../../config/debug";
|
||||
import appNotificationsManager from "./appNotificationsManager";
|
||||
import PeerTitle from "../../components/peerTitle";
|
||||
import { i18n, LangPackKey, _i18n } from "../langPack";
|
||||
import I18n, { FormatterArguments, i18n, LangPackKey, _i18n } from "../langPack";
|
||||
import findUpTag from "../../helpers/dom/findUpTag";
|
||||
import { LazyLoadQueueIntersector } from "../../components/lazyLoadQueue";
|
||||
import lottieLoader from "../lottieLoader";
|
||||
@ -41,6 +41,8 @@ import positionElementByIndex from "../../helpers/dom/positionElementByIndex";
|
||||
import replaceContent from "../../helpers/dom/replaceContent";
|
||||
import ConnectionStatusComponent from "../../components/connectionStatus";
|
||||
import appChatsManager from "./appChatsManager";
|
||||
import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
|
||||
import { fastRafPromise } from "../../helpers/schedulers";
|
||||
|
||||
export type DialogDom = {
|
||||
avatarEl: AvatarElement,
|
||||
@ -754,12 +756,13 @@ export class AppDialogsManager {
|
||||
|
||||
private generateEmptyPlaceholder(options: {
|
||||
title: LangPackKey,
|
||||
subtitle: LangPackKey,
|
||||
subtitle?: LangPackKey,
|
||||
subtitleArgs?: FormatterArguments,
|
||||
classNameType: string
|
||||
}) {
|
||||
const BASE_CLASS = 'empty-placeholder';
|
||||
const div = document.createElement('div');
|
||||
div.classList.add(BASE_CLASS, BASE_CLASS + '-' + options.classNameType);
|
||||
const container = document.createElement('div');
|
||||
container.classList.add(BASE_CLASS, BASE_CLASS + '-' + options.classNameType);
|
||||
|
||||
const header = document.createElement('div');
|
||||
header.classList.add(BASE_CLASS + '-header');
|
||||
@ -767,31 +770,82 @@ export class AppDialogsManager {
|
||||
|
||||
const subtitle = document.createElement('div');
|
||||
subtitle.classList.add(BASE_CLASS + '-subtitle');
|
||||
_i18n(subtitle, options.subtitle);
|
||||
if(options.subtitle) {
|
||||
_i18n(subtitle, options.subtitle, options.subtitleArgs);
|
||||
}
|
||||
|
||||
div.append(header, subtitle);
|
||||
container.append(header, subtitle);
|
||||
|
||||
return div;
|
||||
return {container, header, subtitle};
|
||||
}
|
||||
|
||||
private onListLengthChange = () => {
|
||||
//return;
|
||||
if(this.filterId === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.filterId < 2) return;
|
||||
let placeholderContainer = (Array.from(this.chatList.parentElement.children) as HTMLElement[]).find(el => el.matches('.empty-placeholder'));
|
||||
const needPlaceholder = this.scroll.loadedAll.bottom && !this.chatList.childElementCount/* || true */;
|
||||
// this.chatList.style.display = 'none';
|
||||
|
||||
const emptyPlaceholder = this.chatList.parentElement.querySelector('.empty-placeholder');
|
||||
if(this.scroll.loadedAll.bottom && !this.chatList.childElementCount) {
|
||||
if(emptyPlaceholder) {
|
||||
return;
|
||||
if(needPlaceholder && placeholderContainer) {
|
||||
return;
|
||||
} else if(!needPlaceholder) {
|
||||
if(placeholderContainer) {
|
||||
placeholderContainer.remove();
|
||||
}
|
||||
|
||||
const d = this.generateEmptyPlaceholder({
|
||||
return;
|
||||
}
|
||||
|
||||
let placeholder: ReturnType<AppDialogsManager['generateEmptyPlaceholder']>;
|
||||
if(!this.filterId) {
|
||||
placeholder = this.generateEmptyPlaceholder({
|
||||
title: 'ChatList.Main.EmptyPlaceholder.Title',
|
||||
classNameType: 'dialogs'
|
||||
});
|
||||
|
||||
placeholderContainer = placeholder.container;
|
||||
|
||||
const img = document.createElement('img');
|
||||
img.classList.add('empty-placeholder-dialogs-icon');
|
||||
|
||||
Promise.all([
|
||||
appUsersManager.getContacts().then(users => {
|
||||
let key: LangPackKey, args: FormatterArguments;
|
||||
|
||||
if(users.length) {
|
||||
key = 'ChatList.Main.EmptyPlaceholder.Subtitle';
|
||||
args = [i18n('Contacts.Count', [users.length])];
|
||||
} else {
|
||||
key = 'ChatList.Main.EmptyPlaceholder.SubtitleNoContacts';
|
||||
args = [];
|
||||
}
|
||||
|
||||
const subtitleEl = new I18n.IntlElement({
|
||||
key,
|
||||
args,
|
||||
element: placeholder.subtitle
|
||||
});
|
||||
}),
|
||||
renderImageFromUrlPromise(img, 'assets/img/EmptyChats.svg'),
|
||||
fastRafPromise()
|
||||
]).then(() => {
|
||||
placeholderContainer.classList.add('visible');
|
||||
});
|
||||
|
||||
placeholderContainer.prepend(img);
|
||||
} else {
|
||||
placeholder = this.generateEmptyPlaceholder({
|
||||
title: 'FilterNoChatsToDisplay',
|
||||
subtitle: 'FilterNoChatsToDisplayInfo',
|
||||
classNameType: 'folder'
|
||||
});
|
||||
|
||||
d.prepend(wrapLocalSticker({
|
||||
placeholderContainer = placeholder.container;
|
||||
|
||||
placeholderContainer.prepend(wrapLocalSticker({
|
||||
emoji: '📂',
|
||||
width: 128,
|
||||
height: 128
|
||||
@ -806,12 +860,10 @@ export class AppDialogsManager {
|
||||
new AppEditFolderTab(appSidebarLeft).open(appMessagesManager.filtersStorage.filters[this.filterId]);
|
||||
});
|
||||
|
||||
d.append(button);
|
||||
|
||||
this.chatList.parentElement.append(d);
|
||||
} else if(emptyPlaceholder) {
|
||||
emptyPlaceholder.remove();
|
||||
placeholderContainer.append(button);
|
||||
}
|
||||
|
||||
this.chatList.parentElement.append(placeholderContainer);
|
||||
};
|
||||
|
||||
public onChatsRegularScroll = () => {
|
||||
|
@ -23,7 +23,7 @@ import appDownloadManager, { ThumbCache } from "./appDownloadManager";
|
||||
import appUsersManager from "./appUsersManager";
|
||||
import blur from "../../helpers/blur";
|
||||
import { MOUNT_CLASS_TO } from "../../config/debug";
|
||||
import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl";
|
||||
import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
|
||||
import calcImageInBox from "../../helpers/calcImageInBox";
|
||||
import { makeMediaSize, MediaSize } from "../../helpers/mediaSizes";
|
||||
|
||||
@ -208,9 +208,7 @@ export class AppPhotosManager {
|
||||
image.classList.add('thumbnail');
|
||||
|
||||
const loadPromise = (useBlur ? blur(url) : Promise.resolve(url)).then(url => {
|
||||
return new Promise<any>((resolve) => {
|
||||
renderImageFromUrl(image, url, resolve);
|
||||
});
|
||||
return renderImageFromUrlPromise(image, url);
|
||||
});
|
||||
|
||||
return {image, loadPromise};
|
||||
|
@ -14,6 +14,7 @@ import apiManager from "./mtproto/mtprotoworker";
|
||||
import stateStorage from "./stateStorage";
|
||||
import App from "../config/app";
|
||||
import rootScope from "./rootScope";
|
||||
import RichTextProcessor from "./richtextprocessor";
|
||||
|
||||
export const langPack: {[actionType: string]: LangPackKey} = {
|
||||
"messageActionChatCreate": "ActionCreateGroup",
|
||||
@ -59,6 +60,9 @@ export const langPack: {[actionType: string]: LangPackKey} = {
|
||||
|
||||
export type LangPackKey = /* string | */keyof typeof lang | keyof typeof langSign;
|
||||
|
||||
export type FormatterArgument = string | Node;
|
||||
export type FormatterArguments = FormatterArgument[];
|
||||
|
||||
namespace I18n {
|
||||
export const strings: Map<LangPackKey, LangPackString> = new Map();
|
||||
let pluralRules: Intl.PluralRules;
|
||||
@ -230,12 +234,12 @@ namespace I18n {
|
||||
});
|
||||
}
|
||||
|
||||
export function superFormatter(input: string, args?: any[], indexHolder = {i: 0}) {
|
||||
let out: (string | HTMLElement)[] = [];
|
||||
const regExp = /(\*\*)(.+?)\1|(\n)|un\d|%\d\$.|%./g;
|
||||
export function superFormatter(input: string, args?: FormatterArguments, indexHolder = {i: 0}) {
|
||||
let out: FormatterArguments = [];
|
||||
const regExp = /(\*\*)(.+?)\1|(\n)|(\[.+?\]\(.*?\))|un\d|%\d\$.|%./g;
|
||||
|
||||
let lastIndex = 0;
|
||||
input.replace(regExp, (match, p1: any, p2: any, p3: any, offset: number, string: string) => {
|
||||
input.replace(regExp, (match, p1: any, p2: any, p3: any, p4: string, offset: number, string: string) => {
|
||||
//console.table({match, p1, p2, offset, string});
|
||||
|
||||
out.push(string.slice(lastIndex, offset));
|
||||
@ -252,6 +256,23 @@ namespace I18n {
|
||||
}
|
||||
} else if(p3) {
|
||||
out.push(document.createElement('br'));
|
||||
} else if(p4) {
|
||||
const a = document.createElement('a');
|
||||
|
||||
const idx = p4.lastIndexOf(']');
|
||||
const text = p4.slice(1, idx);
|
||||
a.append(...superFormatter(text, args, indexHolder));
|
||||
|
||||
const url = p4.slice(idx + 2, p4.length - 1);
|
||||
if(url) {
|
||||
const wrappedUrl = RichTextProcessor.wrapUrl(url);
|
||||
a.href = wrappedUrl.url;
|
||||
if(wrappedUrl.onclick) a.setAttribute('onclick', wrappedUrl.onclick);
|
||||
a.target = '_blank';
|
||||
}
|
||||
|
||||
out.push(a);
|
||||
console.log('p4', p4);
|
||||
} else if(args) {
|
||||
out.push(args[indexHolder.i++]);
|
||||
}
|
||||
@ -268,8 +289,8 @@ namespace I18n {
|
||||
}
|
||||
|
||||
export function format(key: LangPackKey, plain: true, args?: any[]): string;
|
||||
export function format(key: LangPackKey, plain?: false, args?: any[]): (string | HTMLElement)[];
|
||||
export function format(key: LangPackKey, plain = false, args?: any[]): (string | HTMLElement)[] | string {
|
||||
export function format(key: LangPackKey, plain?: false, args?: any[]): FormatterArguments;
|
||||
export function format(key: LangPackKey, plain = false, args?: any[]): FormatterArguments | string {
|
||||
const str = strings.get(key);
|
||||
let input: string;
|
||||
if(str) {
|
||||
@ -329,7 +350,7 @@ namespace I18n {
|
||||
|
||||
export type IntlElementOptions = IntlElementBaseOptions & {
|
||||
key: LangPackKey,
|
||||
args?: any[]
|
||||
args?: FormatterArguments
|
||||
};
|
||||
export class IntlElement extends IntlElementBase<IntlElementOptions> {
|
||||
public key: IntlElementOptions['key'];
|
||||
|
@ -733,7 +733,7 @@ $bubble-margin: .25rem;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
&.empty-placeholder {
|
||||
&.empty-bubble-placeholder {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
@ -750,7 +750,7 @@ $bubble-margin: .25rem;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.empty-placeholder-title {
|
||||
.empty-bubble-placeholder-title {
|
||||
font-weight: 500;
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
@ -760,7 +760,11 @@ $bubble-margin: .25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-placeholder-line + .empty-placeholder-line {
|
||||
.empty-bubble-placeholder-line {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.empty-bubble-placeholder-line + .empty-bubble-placeholder-line {
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
@ -771,7 +775,7 @@ $bubble-margin: .25rem;
|
||||
margin-left: -.1875rem;
|
||||
}
|
||||
|
||||
.empty-placeholder-list-bullet {
|
||||
.empty-bubble-placeholder-list-bullet {
|
||||
margin-right: .3125rem;
|
||||
}
|
||||
|
||||
@ -784,23 +788,23 @@ $bubble-margin: .25rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.empty-placeholder-group {
|
||||
.empty-placeholder-list-item {
|
||||
&.empty-bubble-placeholder-group {
|
||||
.empty-bubble-placeholder-list-item {
|
||||
margin-top: .4375rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.empty-placeholder-greeting {
|
||||
&.empty-bubble-placeholder-greeting {
|
||||
.service-msg {
|
||||
max-width: 232px;
|
||||
}
|
||||
|
||||
.empty-placeholder-subtitle {
|
||||
.empty-bubble-placeholder-subtitle {
|
||||
margin-top: .25rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-placeholder-sticker {
|
||||
.empty-bubble-placeholder-sticker {
|
||||
margin-top: .75rem !important;
|
||||
position: relative;
|
||||
width: 200px;
|
||||
|
@ -1187,6 +1187,9 @@
|
||||
text-align: center;
|
||||
line-height: var(--line-height);
|
||||
user-select: none;
|
||||
width: 21rem !important;
|
||||
margin: 0 auto;
|
||||
padding: 0 1rem;
|
||||
|
||||
.media-sticker-wrapper {
|
||||
width: 128px;
|
||||
@ -1203,7 +1206,7 @@
|
||||
&-subtitle {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: .875rem;
|
||||
margin-top: .3125rem;
|
||||
margin-top: .375rem;
|
||||
}
|
||||
|
||||
.btn-control {
|
||||
@ -1214,4 +1217,20 @@
|
||||
margin-right: .625rem;
|
||||
}
|
||||
}
|
||||
|
||||
&-dialogs {
|
||||
opacity: 0;
|
||||
|
||||
@include animation-level(2) {
|
||||
transition: opacity .2s ease-in-out;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
margin-bottom: 1.0625rem;
|
||||
}
|
||||
|
||||
&.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user