diff --git a/src/components/appMediaViewer.ts b/src/components/appMediaViewer.ts index 05909054..a60fe0a1 100644 --- a/src/components/appMediaViewer.ts +++ b/src/components/appMediaViewer.ts @@ -11,7 +11,7 @@ import { logger } from "../lib/logger"; import VideoPlayer from "../lib/mediaPlayer"; import { RichTextProcessor } from "../lib/richtextprocessor"; import rootScope from "../lib/rootScope"; -import { cancelEvent, fillPropertyValue, findUpClassName, generatePathData } from "../helpers/dom"; +import { cancelEvent, fillPropertyValue, generatePathData } from "../helpers/dom"; import animationIntersector from "./animationIntersector"; import appMediaPlaybackController from "./appMediaPlaybackController"; import AvatarElement from "./avatar"; @@ -19,7 +19,6 @@ import ButtonIcon from "./buttonIcon"; import { ButtonMenuItemOptions } from "./buttonMenu"; import ButtonMenuToggle from "./buttonMenuToggle"; import { LazyLoadQueueBase } from "./lazyLoadQueue"; -import { renderImageFromUrl } from "./misc"; import PopupForward from "./popups/forward"; import ProgressivePreloader from "./preloader"; import Scrollable from "./scrollable"; @@ -32,6 +31,8 @@ import appNavigationController from "./appNavigationController"; import { Message } from "../layer"; import { forEachReverse } from "../helpers/array"; import AppSharedMediaTab from "./sidebarRight/tabs/sharedMedia"; +import findUpClassName from "../helpers/dom/findUpClassName"; +import renderImageFromUrl from "../helpers/dom/renderImageFromUrl"; // TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию // TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода) @@ -1199,7 +1200,7 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet onClick: this.onForwardClick }, { icon: 'download', - text: 'Download', + text: 'MediaViewer.Context.Download', onClick: this.onDownloadClick }, { icon: 'delete danger btn-disabled', @@ -1436,7 +1437,7 @@ export class AppMediaViewerAvatar extends AppMediaViewerBase<'', 'delete', AppMe this.setBtnMenuToggle([{ icon: 'download', - text: 'Download', + text: 'MediaViewer.Context.Download', onClick: this.onDownloadClick }, { icon: 'delete danger btn-disabled', diff --git a/src/components/appMediaViewerNew.ts b/src/components/appMediaViewerNew.ts index 843f3f3a..4aa6e4aa 100644 --- a/src/components/appMediaViewerNew.ts +++ b/src/components/appMediaViewerNew.ts @@ -11,7 +11,7 @@ import { logger } from "../lib/logger"; import VideoPlayer from "../lib/mediaPlayer"; import { RichTextProcessor } from "../lib/richtextprocessor"; import rootScope from "../lib/rootScope"; -import { cancelEvent, fillPropertyValue, findUpClassName, generatePathData } from "../helpers/dom"; +import { cancelEvent, fillPropertyValue, generatePathData } from "../helpers/dom"; import animationIntersector from "./animationIntersector"; import appMediaPlaybackController from "./appMediaPlaybackController"; import AvatarElement from "./avatar"; @@ -19,7 +19,6 @@ import ButtonIcon from "./buttonIcon"; import { ButtonMenuItemOptions } from "./buttonMenu"; import ButtonMenuToggle from "./buttonMenuToggle"; import { LazyLoadQueueBase } from "./lazyLoadQueue"; -import { renderImageFromUrl } from "./misc"; import PopupForward from "./popups/forward"; import ProgressivePreloader from "./preloader"; import Scrollable from "./scrollable"; @@ -30,6 +29,8 @@ import { SearchSuperContext } from "./appSearchSuper."; import { Message, PhotoSize } from "../layer"; import { forEachReverse } from "../helpers/array"; import AppSharedMediaTab from "./sidebarRight/tabs/sharedMedia"; +import findUpClassName from "../helpers/dom/findUpClassName"; +import renderImageFromUrl from "../helpers/dom/renderImageFromUrl"; // TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию // TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода) @@ -1101,7 +1102,7 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet onClick: this.onForwardClick }, { icon: 'download', - text: 'Download', + text: 'MediaViewer.Context.Download', onClick: this.onDownloadClick }, { icon: 'delete danger btn-disabled', @@ -1338,7 +1339,7 @@ export class AppMediaViewerAvatar extends AppMediaViewerBase<'', 'delete', AppMe this.setBtnMenuToggle([{ icon: 'download', - text: 'Download', + text: 'MediaViewer.Context.Download', onClick: this.onDownloadClick }, { icon: 'delete danger btn-disabled', diff --git a/src/components/appSearchSuper..ts b/src/components/appSearchSuper..ts index 1cec9496..1564d883 100644 --- a/src/components/appSearchSuper..ts +++ b/src/components/appSearchSuper..ts @@ -1,5 +1,5 @@ import { formatDateAccordingToToday, months } from "../helpers/date"; -import { findUpClassName, positionElementByIndex } from "../helpers/dom"; +import { positionElementByIndex } from "../helpers/dom"; import { copy, getObjectKeysAndSort } from "../helpers/object"; import { escapeRegExp, limitSymbols } from "../helpers/string"; import appChatsManager from "../lib/appManagers/appChatsManager"; @@ -17,13 +17,15 @@ import AppMediaViewer from "./appMediaViewer"; import { SearchGroup, SearchGroupType } from "./appSearch"; import { horizontalMenu } from "./horizontalMenu"; import LazyLoadQueue from "./lazyLoadQueue"; -import { renderImageFromUrl, putPreloader, formatPhoneNumber } from "./misc"; +import { putPreloader, formatPhoneNumber } from "./misc"; import { ripple } from "./ripple"; import Scrollable, { ScrollableX } from "./scrollable"; import { wrapDocument, wrapPhoto, wrapVideo } from "./wrappers"; import useHeavyAnimationCheck, { getHeavyAnimationPromise } from "../hooks/useHeavyAnimationCheck"; import { isSafari } from "../helpers/userAgent"; import { LangPackKey, i18n } from "../lib/langPack"; +import findUpClassName from "../helpers/dom/findUpClassName"; +import renderImageFromUrl from "../helpers/dom/renderImageFromUrl"; //const testScroll = false; diff --git a/src/components/appSelectPeers.ts b/src/components/appSelectPeers.ts index 5fc17918..e9b867ff 100644 --- a/src/components/appSelectPeers.ts +++ b/src/components/appSelectPeers.ts @@ -5,13 +5,15 @@ import appPeersManager from "../lib/appManagers/appPeersManager"; import appPhotosManager from "../lib/appManagers/appPhotosManager"; import appUsersManager from "../lib/appManagers/appUsersManager"; import rootScope from "../lib/rootScope"; -import { cancelEvent, findUpAttribute, findUpClassName } from "../helpers/dom"; +import { cancelEvent } from "../helpers/dom"; import Scrollable from "./scrollable"; import { FocusDirection } from "../helpers/fastSmoothScroll"; import CheckboxField from "./checkboxField"; import appProfileManager from "../lib/appManagers/appProfileManager"; import { safeAssign } from "../helpers/object"; import { i18n, LangPackKey, _i18n } from "../lib/langPack"; +import findUpAttribute from "../helpers/dom/findUpAttribute"; +import findUpClassName from "../helpers/dom/findUpClassName"; type PeerType = 'contacts' | 'dialogs' | 'channelParticipants'; diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index 6f016bf0..c66025bb 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -8,7 +8,7 @@ import type { AppDocsManager } from "../../lib/appManagers/appDocsManager"; import type { AppPeersManager } from "../../lib/appManagers/appPeersManager"; import type sessionStorage from '../../lib/sessionStorage'; import type Chat from "./chat"; -import { findUpClassName, cancelEvent, findUpTag, whichChild, getElementByPoint, attachClickEvent, positionElementByIndex, reflowScrollableElement } from "../../helpers/dom"; +import { cancelEvent, whichChild, getElementByPoint, attachClickEvent, positionElementByIndex, reflowScrollableElement } from "../../helpers/dom"; import { getObjectKeysAndSort } from "../../helpers/object"; import { isTouchSupported } from "../../helpers/touchSupport"; import { logger } from "../../lib/logger"; @@ -49,6 +49,8 @@ import { SliceEnd } from "../../helpers/slicedArray"; import serverTimeManager from "../../lib/mtproto/serverTimeManager"; import PeerTitle from "../peerTitle"; import { forEachReverse } from "../../helpers/array"; +import findUpClassName from "../../helpers/dom/findUpClassName"; +import findUpTag from "../../helpers/dom/findUpTag"; const USE_MEDIA_TAILS = false; const IGNORE_ACTIONS: Message.messageService['action']['_'][] = [/* 'messageActionHistoryClear' */]; diff --git a/src/components/chat/chat.ts b/src/components/chat/chat.ts index ed989552..af6f582f 100644 --- a/src/components/chat/chat.ts +++ b/src/components/chat/chat.ts @@ -18,18 +18,18 @@ import type sessionStorage from '../../lib/sessionStorage'; import EventListenerBase from "../../helpers/eventListenerBase"; import { logger, LogLevels } from "../../lib/logger"; import rootScope from "../../lib/rootScope"; -import appSidebarRight, { AppSidebarRight } from "../sidebarRight"; +import appSidebarRight from "../sidebarRight"; import ChatBubbles from "./bubbles"; import ChatContextMenu from "./contextMenu"; import ChatInput from "./input"; import ChatSelection from "./selection"; import ChatTopbar from "./topbar"; import { REPLIES_PEER_ID } from "../../lib/mtproto/mtproto_config"; -import { renderImageFromUrl } from "../misc"; import SetTransition from "../singleTransition"; import { fastRaf } from "../../helpers/schedulers"; import AppPrivateSearchTab from "../sidebarRight/tabs/search"; import type { State } from "../../lib/appManagers/appStateManager"; +import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl"; export type ChatType = 'chat' | 'pinned' | 'replies' | 'discussion' | 'scheduled'; diff --git a/src/components/chat/contextMenu.ts b/src/components/chat/contextMenu.ts index b02f3e2e..7c8a7798 100644 --- a/src/components/chat/contextMenu.ts +++ b/src/components/chat/contextMenu.ts @@ -4,7 +4,7 @@ import type { AppPeersManager } from "../../lib/appManagers/appPeersManager"; import type { AppPollsManager, Poll } from "../../lib/appManagers/appPollsManager"; import type Chat from "./chat"; import { isTouchSupported } from "../../helpers/touchSupport"; -import { attachClickEvent, cancelEvent, cancelSelection, findUpClassName, isSelectionEmpty } from "../../helpers/dom"; +import { attachClickEvent, cancelEvent, cancelSelection, isSelectionEmpty } from "../../helpers/dom"; import ButtonMenu, { ButtonMenuItemOptions } from "../buttonMenu"; import { attachContextMenuListener, openBtnMenu, positionMenu } from "../misc"; import PopupDeleteMessages from "../popups/deleteMessages"; @@ -14,6 +14,7 @@ import { copyTextToClipboard } from "../../helpers/clipboard"; import PopupSendNow from "../popups/sendNow"; import { toast } from "../toast"; import I18n, { LangPackKey } from "../../lib/langPack"; +import findUpClassName from "../../helpers/dom/findUpClassName"; export default class ChatContextMenu { private buttons: (ButtonMenuItemOptions & {verify: () => boolean, notDirect?: () => boolean, withSelection?: true})[]; diff --git a/src/components/chat/input.ts b/src/components/chat/input.ts index da94ab19..195475eb 100644 --- a/src/components/chat/input.ts +++ b/src/components/chat/input.ts @@ -14,7 +14,7 @@ import apiManager from "../../lib/mtproto/mtprotoworker"; //import Recorder from '../opus-recorder/dist/recorder.min'; import opusDecodeController from "../../lib/opusDecodeController"; import RichTextProcessor from "../../lib/richtextprocessor"; -import { attachClickEvent, blurActiveElement, cancelEvent, cancelSelection, findUpClassName, getRichValue, isInputEmpty, markdownTags, MarkdownType, placeCaretAtEnd, isSendShortcutPressed } from "../../helpers/dom"; +import { attachClickEvent, blurActiveElement, cancelEvent, cancelSelection, getRichValue, isInputEmpty, markdownTags, MarkdownType, placeCaretAtEnd, isSendShortcutPressed } from "../../helpers/dom"; import { ButtonMenuItemOptions } from '../buttonMenu'; import emoticonsDropdown from "../emoticonsDropdown"; import PopupCreatePoll from "../popups/createPoll"; @@ -40,6 +40,7 @@ import appNavigationController from '../appNavigationController'; import { isMobile } from '../../helpers/userAgent'; import { i18n } from '../../lib/langPack'; import { generateTail } from './bubbles'; +import findUpClassName from '../../helpers/dom/findUpClassName'; const RECORD_MIN_TIME = 500; const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.'; diff --git a/src/components/chat/markupTooltip.ts b/src/components/chat/markupTooltip.ts index 30652b22..b0b8ec92 100644 --- a/src/components/chat/markupTooltip.ts +++ b/src/components/chat/markupTooltip.ts @@ -1,5 +1,5 @@ import type { AppImManager } from "../../lib/appManagers/appImManager"; -import { MarkdownType, cancelEvent, getSelectedNodes, markdownTags, findUpClassName, attachClickEvent, cancelSelection, isSelectionEmpty } from "../../helpers/dom"; +import { MarkdownType, cancelEvent, getSelectedNodes, markdownTags, attachClickEvent, isSelectionEmpty } from "../../helpers/dom"; import RichTextProcessor from "../../lib/richtextprocessor"; import ButtonIcon from "../buttonIcon"; import { clamp } from "../../helpers/number"; diff --git a/src/components/chat/replyContainer.ts b/src/components/chat/replyContainer.ts index 32e8d7b3..2752efeb 100644 --- a/src/components/chat/replyContainer.ts +++ b/src/components/chat/replyContainer.ts @@ -1,10 +1,10 @@ +import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl"; import { limitSymbols } from "../../helpers/string"; import appImManager, { CHAT_ANIMATION_GROUP } from "../../lib/appManagers/appImManager"; import appMessagesManager from "../../lib/appManagers/appMessagesManager"; import appPhotosManager from "../../lib/appManagers/appPhotosManager"; import { RichTextProcessor } from "../../lib/richtextprocessor"; import DivAndCaption from "../divAndCaption"; -import { renderImageFromUrl } from "../misc"; import { wrapSticker } from "../wrappers"; export function wrapReplyDivAndCaption(options: { diff --git a/src/components/chat/search.ts b/src/components/chat/search.ts index f969e950..a3dd4774 100644 --- a/src/components/chat/search.ts +++ b/src/components/chat/search.ts @@ -1,10 +1,11 @@ import type ChatTopbar from "./topbar"; -import { cancelEvent, whichChild, findUpTag } from "../../helpers/dom"; +import { cancelEvent, whichChild } from "../../helpers/dom"; import AppSearch, { SearchGroup } from "../appSearch"; import PopupDatePicker from "../popups/datePicker"; import { ripple } from "../ripple"; import InputSearch from "../inputSearch"; import type Chat from "./chat"; +import findUpTag from "../../helpers/dom/findUpTag"; export default class ChatSearch { private element: HTMLElement; diff --git a/src/components/chat/selection.ts b/src/components/chat/selection.ts index 6825a7cc..f3414853 100644 --- a/src/components/chat/selection.ts +++ b/src/components/chat/selection.ts @@ -3,7 +3,7 @@ import type ChatBubbles from "./bubbles"; import type ChatInput from "./input"; import type Chat from "./chat"; import { isTouchSupported } from "../../helpers/touchSupport"; -import { blurActiveElement, cancelEvent, cancelSelection, findUpClassName, getSelectedText } from "../../helpers/dom"; +import { blurActiveElement, cancelEvent, cancelSelection, getSelectedText } from "../../helpers/dom"; import Button from "../button"; import ButtonIcon from "../buttonIcon"; import CheckboxField from "../checkboxField"; @@ -16,6 +16,7 @@ import PopupSendNow from "../popups/sendNow"; import appNavigationController from "../appNavigationController"; import { isMobileSafari } from "../../helpers/userAgent"; import I18n, { i18n, _i18n } from "../../lib/langPack"; +import findUpClassName from "../../helpers/dom/findUpClassName"; const MAX_SELECTION_LENGTH = 100; //const MIN_CLICK_MOVE = 32; // minimum bubble height diff --git a/src/components/chat/stickersHelper.ts b/src/components/chat/stickersHelper.ts index ec633b4c..92adcf75 100644 --- a/src/components/chat/stickersHelper.ts +++ b/src/components/chat/stickersHelper.ts @@ -1,6 +1,6 @@ -import { findUpClassName } from "../../helpers/dom"; +import findUpClassName from "../../helpers/dom/findUpClassName"; import { MyDocument } from "../../lib/appManagers/appDocsManager"; -import appImManager, { CHAT_ANIMATION_GROUP } from "../../lib/appManagers/appImManager"; +import { CHAT_ANIMATION_GROUP } from "../../lib/appManagers/appImManager"; import appStickersManager from "../../lib/appManagers/appStickersManager"; import { EmoticonsDropdown } from "../emoticonsDropdown"; import { SuperStickerRenderer } from "../emoticonsDropdown/tabs/stickers"; diff --git a/src/components/chat/topbar.ts b/src/components/chat/topbar.ts index 4b9c4461..6faf09d2 100644 --- a/src/components/chat/topbar.ts +++ b/src/components/chat/topbar.ts @@ -4,7 +4,7 @@ import type { AppMessagesManager } from "../../lib/appManagers/appMessagesManage import type { AppPeersManager } from "../../lib/appManagers/appPeersManager"; import type { AppSidebarRight } from "../sidebarRight"; import type Chat from "./chat"; -import { findUpClassName, cancelEvent, attachClickEvent, blurActiveElement } from "../../helpers/dom"; +import { cancelEvent, attachClickEvent, blurActiveElement } from "../../helpers/dom"; import mediaSizes, { ScreenSize } from "../../helpers/mediaSizes"; import { isSafari } from "../../helpers/userAgent"; import rootScope from "../../lib/rootScope"; @@ -24,6 +24,7 @@ import { LEFT_COLUMN_ACTIVE_CLASSNAME } from "../sidebarLeft"; import AppPrivateSearchTab from "../sidebarRight/tabs/search"; import PeerTitle from "../peerTitle"; import { i18n } from "../../lib/langPack"; +import findUpClassName from "../../helpers/dom/findUpClassName"; export default class ChatTopbar { container: HTMLDivElement; diff --git a/src/components/codeInputField.ts b/src/components/codeInputField.ts index 102c6e65..d3c141a3 100644 --- a/src/components/codeInputField.ts +++ b/src/components/codeInputField.ts @@ -1,9 +1,7 @@ -import InputField from "./inputField"; +import InputField, { InputFieldOptions } from "./inputField"; export default class CodeInputField extends InputField { - constructor(options: { - label?: string, - name?: string, + constructor(options: InputFieldOptions & { length: number, onFill: (code: number) => void }) { diff --git a/src/components/dialogsContextMenu.ts b/src/components/dialogsContextMenu.ts index 17912225..82564338 100644 --- a/src/components/dialogsContextMenu.ts +++ b/src/components/dialogsContextMenu.ts @@ -2,11 +2,11 @@ import appDialogsManager from "../lib/appManagers/appDialogsManager"; import appMessagesManager, {Dialog} from "../lib/appManagers/appMessagesManager"; import appPeersManager from "../lib/appManagers/appPeersManager"; import rootScope from "../lib/rootScope"; -import { findUpTag } from "../helpers/dom"; import { positionMenu, openBtnMenu } from "./misc"; import ButtonMenu, { ButtonMenuItemOptions } from "./buttonMenu"; import PopupDeleteDialog from "./popups/deleteDialog"; import { i18n } from "../lib/langPack"; +import findUpTag from "../helpers/dom/findUpTag"; export default class DialogsContextMenu { private element: HTMLElement; diff --git a/src/components/emoticonsDropdown/index.ts b/src/components/emoticonsDropdown/index.ts index 1736ff23..3982e17e 100644 --- a/src/components/emoticonsDropdown/index.ts +++ b/src/components/emoticonsDropdown/index.ts @@ -2,7 +2,7 @@ import { isTouchSupported } from "../../helpers/touchSupport"; import appChatsManager from "../../lib/appManagers/appChatsManager"; import appImManager from "../../lib/appManagers/appImManager"; import rootScope from "../../lib/rootScope"; -import { blurActiveElement, findUpClassName, findUpTag, whichChild } from "../../helpers/dom"; +import { blurActiveElement, whichChild } from "../../helpers/dom"; import animationIntersector from "../animationIntersector"; import { horizontalMenu } from "../horizontalMenu"; import LazyLoadQueue, { LazyLoadQueueIntersector } from "../lazyLoadQueue"; @@ -16,6 +16,8 @@ import { pause } from "../../helpers/schedulers"; import { MOUNT_CLASS_TO } from "../../config/debug"; import AppGifsTab from "../sidebarRight/tabs/gifs"; import AppStickersTab from "../sidebarRight/tabs/stickers"; +import findUpClassName from "../../helpers/dom/findUpClassName"; +import findUpTag from "../../helpers/dom/findUpTag"; export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown'; diff --git a/src/components/emoticonsDropdown/tabs/stickers.ts b/src/components/emoticonsDropdown/tabs/stickers.ts index 3922a164..07845f08 100644 --- a/src/components/emoticonsDropdown/tabs/stickers.ts +++ b/src/components/emoticonsDropdown/tabs/stickers.ts @@ -1,5 +1,6 @@ import emoticonsDropdown, { EmoticonsDropdown, EMOTICONSSTICKERGROUP, EmoticonsTab } from ".."; import { readBlobAsText } from "../../../helpers/blob"; +import renderImageFromUrl from "../../../helpers/dom/renderImageFromUrl"; import mediaSizes from "../../../helpers/mediaSizes"; import { MessagesAllStickers, StickerSet } from "../../../layer"; import appDocsManager, { MyDocument } from "../../../lib/appManagers/appDocsManager"; @@ -10,7 +11,7 @@ import { RichTextProcessor } from "../../../lib/richtextprocessor"; import rootScope from "../../../lib/rootScope"; import animationIntersector from "../../animationIntersector"; import LazyLoadQueue, { LazyLoadQueueRepeat } from "../../lazyLoadQueue"; -import { putPreloader, renderImageFromUrl } from "../../misc"; +import { putPreloader } from "../../misc"; import Scrollable, { ScrollableX } from "../../scrollable"; import StickyIntersector from "../../stickyIntersector"; import { wrapSticker } from "../../wrappers"; diff --git a/src/components/gifsMasonry.ts b/src/components/gifsMasonry.ts index af953a59..edc86e47 100644 --- a/src/components/gifsMasonry.ts +++ b/src/components/gifsMasonry.ts @@ -1,11 +1,11 @@ import { calcImageInBox } from "../helpers/dom"; import appDocsManager, {MyDocument} from "../lib/appManagers/appDocsManager"; import { wrapVideo } from "./wrappers"; -import { renderImageFromUrl } from "./misc"; import { LazyLoadQueueRepeat2 } from "./lazyLoadQueue"; import animationIntersector from "./animationIntersector"; import Scrollable from "./scrollable"; import { CancellablePromise, deferredPromise } from "../helpers/cancellablePromise"; +import renderImageFromUrl from "../helpers/dom/renderImageFromUrl"; const width = 400; const maxSingleWidth = width - 100; @@ -209,4 +209,4 @@ export default class GifsMasonry { (gotThumb?.thumb?.url ? renderImageFromUrl(img, gotThumb.thumb.url, afterRender) : afterRender()); } -} \ No newline at end of file +} diff --git a/src/components/horizontalMenu.ts b/src/components/horizontalMenu.ts index 766e32b8..b77384e7 100644 --- a/src/components/horizontalMenu.ts +++ b/src/components/horizontalMenu.ts @@ -1,9 +1,10 @@ -import { whichChild, findUpAsChild } from "../helpers/dom"; +import { whichChild } from "../helpers/dom"; import { TransitionSlider } from "./transition"; import { ScrollableX } from "./scrollable"; import rootScope from "../lib/rootScope"; import { fastRaf } from "../helpers/schedulers"; import { FocusDirection } from "../helpers/fastSmoothScroll"; +import findUpAsChild from "../helpers/dom/findUpAsChild"; export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?: (id: number, tabContent: HTMLDivElement) => void, onTransitionEnd?: () => void, transitionTime = 250, scrollableX?: ScrollableX) { const selectTab = TransitionSlider(content, tabs || content.dataset.animation === 'tabs' ? 'tabs' : 'navigation', transitionTime, onTransitionEnd); diff --git a/src/components/misc.ts b/src/components/misc.ts index 35946427..991cced0 100644 --- a/src/components/misc.ts +++ b/src/components/misc.ts @@ -7,54 +7,6 @@ import { isTouchSupported } from "../helpers/touchSupport"; import { isApple, isMobileSafari } from "../helpers/userAgent"; import appNavigationController from "./appNavigationController"; -export const loadedURLs: {[url: string]: boolean} = {}; -const set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string) => { - if(elem instanceof HTMLImageElement || elem instanceof HTMLVideoElement) elem.src = url; - else if(elem instanceof SVGImageElement) elem.setAttributeNS(null, 'href', url); - else elem.style.backgroundImage = 'url(' + url + ')'; -}; - -// проблема функции в том, что она не подходит для ссылок, пригодна только для blob'ов, потому что обычным ссылкам нужен 'load' каждый раз. -export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string, callback?: (err?: Event) => void, useCache = false): boolean { - if(((loadedURLs[url]/* && false */) && useCache) || elem instanceof HTMLVideoElement) { - if(elem) { - set(elem, url); - } - - callback && callback(); - return true; - } else { - const isImage = elem instanceof HTMLImageElement; - const loader = isImage ? elem as HTMLImageElement : new Image(); - //const loader = new Image(); - loader.src = url; - //let perf = performance.now(); - loader.addEventListener('load', () => { - if(!isImage && elem) { - set(elem, url); - } - - loadedURLs[url] = true; - //console.log('onload:', url, performance.now() - perf); - if(callback) { - // TODO: переделать прогрузки аватаров до начала анимации, иначе с этим ожиданием они неприятно появляются - /* getHeavyAnimationPromise().then(() => { - callback(); - }); */ - callback(); - } - - //callback && callback(); - }); - - if(callback) { - loader.addEventListener('error', callback); - } - - return false; - } -} - export function putPreloader(elem: Element, returnDiv = false): HTMLElement { const html = ` diff --git a/src/components/passwordInputField.ts b/src/components/passwordInputField.ts index f677107c..1b262fe7 100644 --- a/src/components/passwordInputField.ts +++ b/src/components/passwordInputField.ts @@ -1,16 +1,12 @@ import { cancelEvent } from "../helpers/dom"; -import InputField from "./inputField"; +import InputField, { InputFieldOptions } from "./inputField"; export default class PasswordInputField extends InputField { public passwordVisible = false; public toggleVisible: HTMLElement; public onVisibilityClickAdditional: () => void; - constructor(options: { - label?: string, - name?: string, - labelText?: string, - } = {}) { + constructor(options: InputFieldOptions = {}) { super({ plainText: true, ...options diff --git a/src/components/poll.ts b/src/components/poll.ts index d9d96be5..c556290c 100644 --- a/src/components/poll.ts +++ b/src/components/poll.ts @@ -5,13 +5,14 @@ import appPollsManager, { Poll, PollResults } from "../lib/appManagers/appPollsM import serverTimeManager from "../lib/mtproto/serverTimeManager"; import { RichTextProcessor } from "../lib/richtextprocessor"; import rootScope from "../lib/rootScope"; -import { attachClickEvent, cancelEvent, detachClickEvent, findUpClassName, replaceContent } from "../helpers/dom"; +import { attachClickEvent, cancelEvent, detachClickEvent, replaceContent } from "../helpers/dom"; import { ripple } from "./ripple"; import appSidebarRight from "./sidebarRight"; import AppPollResultsTab from "./sidebarRight/tabs/pollResults"; import { i18n, LangPackKey } from "../lib/langPack"; import { fastRaf } from "../helpers/schedulers"; import SetTransition from "./singleTransition"; +import findUpClassName from "../helpers/dom/findUpClassName"; let lineTotalLength = 0; const tailLength = 9; @@ -203,7 +204,7 @@ export default class PollElement extends HTMLElement { //console.log('pollElement poll:', poll, results); - let descKey: LangPackKey = ''; + let descKey: LangPackKey; if(poll.pFlags) { this.isPublic = !!poll.pFlags.public_voters; this.isQuiz = !!poll.pFlags.quiz; diff --git a/src/components/popups/createPoll.ts b/src/components/popups/createPoll.ts index 411e113b..6c647421 100644 --- a/src/components/popups/createPoll.ts +++ b/src/components/popups/createPoll.ts @@ -1,15 +1,15 @@ import type { Poll } from "../../lib/appManagers/appPollsManager"; import type Chat from "../chat/chat"; import PopupElement from "."; -import { cancelEvent, findUpTag, getRichValue, isInputEmpty, whichChild } from "../../helpers/dom"; +import { cancelEvent, getRichValue, isInputEmpty, whichChild } from "../../helpers/dom"; import CheckboxField from "../checkboxField"; import InputField from "../inputField"; import RadioField from "../radioField"; import Scrollable from "../scrollable"; -import { toast } from "../toast"; import SendContextMenu from "../chat/sendContextMenu"; import { MessageEntity } from "../../layer"; import I18n, { _i18n, i18n } from "../../lib/langPack"; +import findUpTag from "../../helpers/dom/findUpTag"; const MAX_LENGTH_QUESTION = 255; const MAX_LENGTH_OPTION = 100; diff --git a/src/components/popups/index.ts b/src/components/popups/index.ts index 4a7bdf71..7736fee1 100644 --- a/src/components/popups/index.ts +++ b/src/components/popups/index.ts @@ -1,9 +1,10 @@ import rootScope from "../../lib/rootScope"; -import { blurActiveElement, findUpClassName } from "../../helpers/dom"; +import { blurActiveElement } from "../../helpers/dom"; import { ripple } from "../ripple"; import animationIntersector from "../animationIntersector"; import appNavigationController, { NavigationItem } from "../appNavigationController"; import { i18n, LangPackKey } from "../../lib/langPack"; +import findUpClassName from "../../helpers/dom/findUpClassName"; export type PopupButton = { text?: string, @@ -17,7 +18,7 @@ export type PopupButton = { export type PopupOptions = Partial<{ closable: true, overlayClosable: true, - withConfirm: LangPackKey, + withConfirm: LangPackKey | true, body: true }>; @@ -69,7 +70,9 @@ export default class PopupElement { if(options.withConfirm) { this.btnConfirm = document.createElement('button'); this.btnConfirm.classList.add('btn-primary', 'btn-color-primary'); - this.btnConfirm.append(i18n(options.withConfirm)); + if(options.withConfirm !== true) { + this.btnConfirm.append(i18n(options.withConfirm)); + } this.header.append(this.btnConfirm); ripple(this.btnConfirm); } diff --git a/src/components/popups/peer.ts b/src/components/popups/peer.ts index 836d70fa..2e786623 100644 --- a/src/components/popups/peer.ts +++ b/src/components/popups/peer.ts @@ -3,7 +3,7 @@ import PopupElement, { addCancelButton, PopupButton, PopupOptions } from "."; import { i18n, LangPackKey } from "../../lib/langPack"; import CheckboxField, { CheckboxFieldOptions } from "../checkboxField"; -export type PopupPeerButtonCallbackCheckboxes = {[text in LangPackKey]: boolean}; +export type PopupPeerButtonCallbackCheckboxes = Partial<{[text in LangPackKey]: boolean}>; export type PopupPeerButtonCallback = (checkboxes?: PopupPeerButtonCallbackCheckboxes) => void; export type PopupPeerOptions = PopupOptions & Partial<{ diff --git a/src/components/popups/schedule.ts b/src/components/popups/schedule.ts index 491da839..78e90be9 100644 --- a/src/components/popups/schedule.ts +++ b/src/components/popups/schedule.ts @@ -13,7 +13,7 @@ export default class PopupSchedule extends PopupDatePicker { noButtons: true, noTitle: true, closable: true, - withConfirm: 'Send Today', + withConfirm: true, minDate: getMinDate(), maxDate: (() => { const date = new Date(); @@ -30,4 +30,4 @@ export default class PopupSchedule extends PopupDatePicker { this.title.replaceWith(this.monthTitle); this.body.append(this.btnConfirm); } -} \ No newline at end of file +} diff --git a/src/components/popups/stickers.ts b/src/components/popups/stickers.ts index be394b73..2f1f4752 100644 --- a/src/components/popups/stickers.ts +++ b/src/components/popups/stickers.ts @@ -6,12 +6,13 @@ import { wrapSticker } from "../wrappers"; import LazyLoadQueue from "../lazyLoadQueue"; import { putPreloader } from "../misc"; import animationIntersector from "../animationIntersector"; -import { findUpClassName, toggleDisability } from "../../helpers/dom"; +import { toggleDisability } from "../../helpers/dom"; import appImManager from "../../lib/appManagers/appImManager"; import { StickerSet } from "../../layer"; import mediaSizes from "../../helpers/mediaSizes"; import { i18n } from "../../lib/langPack"; import Button from "../button"; +import findUpClassName from "../../helpers/dom/findUpClassName"; const ANIMATION_GROUP = 'STICKERS-POPUP'; diff --git a/src/components/popups/unpinMessage.ts b/src/components/popups/unpinMessage.ts index 117afbce..cb13e676 100644 --- a/src/components/popups/unpinMessage.ts +++ b/src/components/popups/unpinMessage.ts @@ -9,7 +9,7 @@ import PeerTitle from "../peerTitle"; export default class PopupPinMessage { constructor(peerId: number, mid: number, unpin?: true, onConfirm?: () => void) { - let title: LangPackKey, description: string, buttons: PopupButton[] = []; + let title: LangPackKey, description: LangPackKey, buttons: PopupButton[] = []; const canUnpin = appPeersManager.canPinMessage(peerId); diff --git a/src/components/ripple.ts b/src/components/ripple.ts index 50968677..a21ff124 100644 --- a/src/components/ripple.ts +++ b/src/components/ripple.ts @@ -1,5 +1,5 @@ +import findUpClassName from "../helpers/dom/findUpClassName"; import {isTouchSupported} from "../helpers/touchSupport"; -import { findUpClassName } from "../helpers/dom"; import rootScope from "../lib/rootScope"; let rippleClickId = 0; diff --git a/src/components/sidebarLeft/index.ts b/src/components/sidebarLeft/index.ts index e845cdf1..44f00b69 100644 --- a/src/components/sidebarLeft/index.ts +++ b/src/components/sidebarLeft/index.ts @@ -5,7 +5,6 @@ import appPeersManager from "../../lib/appManagers/appPeersManager"; import appStateManager from "../../lib/appManagers/appStateManager"; import appUsersManager from "../../lib/appManagers/appUsersManager"; import rootScope from "../../lib/rootScope"; -import { attachClickEvent, findUpClassName, findUpTag } from "../../helpers/dom"; import { SearchGroup } from "../appSearch"; import "../avatar"; import Scrollable, { ScrollableX } from "../scrollable"; @@ -27,6 +26,8 @@ import ButtonMenu, { ButtonMenuItemOptions } from "../buttonMenu"; import CheckboxField from "../checkboxField"; import { isMobileSafari } from "../../helpers/userAgent"; import appNavigationController from "../appNavigationController"; +import findUpClassName from "../../helpers/dom/findUpClassName"; +import findUpTag from "../../helpers/dom/findUpTag"; export const LEFT_COLUMN_ACTIVE_CLASSNAME = 'is-left-column-shown'; diff --git a/src/components/sidebarLeft/tabs/2fa/email.ts b/src/components/sidebarLeft/tabs/2fa/email.ts index 1b659548..b2c82f3a 100644 --- a/src/components/sidebarLeft/tabs/2fa/email.ts +++ b/src/components/sidebarLeft/tabs/2fa/email.ts @@ -26,7 +26,7 @@ export default class AppTwoStepVerificationEmailTab extends SliderSuperTab { this.setTitle('RecoveryEmailTitle'); const section = new SettingSection({ - caption: '', + caption: true, noDelimiter: true }); diff --git a/src/components/sidebarLeft/tabs/2fa/index.ts b/src/components/sidebarLeft/tabs/2fa/index.ts index 71d0c7cd..83fb578b 100644 --- a/src/components/sidebarLeft/tabs/2fa/index.ts +++ b/src/components/sidebarLeft/tabs/2fa/index.ts @@ -21,7 +21,7 @@ export default class AppTwoStepVerificationTab extends SliderSuperTab { this.setTitle('TwoStepVerificationTitle'); const section = new SettingSection({ - caption: ' ', + caption: true, noDelimiter: true }); diff --git a/src/components/sidebarLeft/tabs/activeSessions.ts b/src/components/sidebarLeft/tabs/activeSessions.ts index 35fe8099..2f3ef488 100644 --- a/src/components/sidebarLeft/tabs/activeSessions.ts +++ b/src/components/sidebarLeft/tabs/activeSessions.ts @@ -5,13 +5,14 @@ import Row from "../../row"; import { Authorization } from "../../../layer"; import { formatDateAccordingToToday } from "../../../helpers/date"; import { attachContextMenuListener, openBtnMenu, positionMenu } from "../../misc"; -import { attachClickEvent, findUpClassName, toggleDisability } from "../../../helpers/dom"; +import { attachClickEvent, toggleDisability } from "../../../helpers/dom"; import ButtonMenu from "../../buttonMenu"; import apiManager from "../../../lib/mtproto/mtprotoworker"; import { toast } from "../../toast"; import AppPrivacyAndSecurityTab from "./privacyAndSecurity"; import I18n from "../../../lib/langPack"; import PopupPeer from "../../popups/peer"; +import findUpClassName from "../../../helpers/dom/findUpClassName"; export default class AppActiveSessionsTab extends SliderSuperTab { public privacyTab: AppPrivacyAndSecurityTab; diff --git a/src/components/sidebarLeft/tabs/background.ts b/src/components/sidebarLeft/tabs/background.ts index 9c6094cf..1598452a 100644 --- a/src/components/sidebarLeft/tabs/background.ts +++ b/src/components/sidebarLeft/tabs/background.ts @@ -2,8 +2,9 @@ import { generateSection } from ".."; import { averageColor } from "../../../helpers/averageColor"; import blur from "../../../helpers/blur"; import { deferredPromise } from "../../../helpers/cancellablePromise"; -import { highlightningColor, rgbToHsl } from "../../../helpers/color"; -import { attachClickEvent, findUpClassName } from "../../../helpers/dom"; +import { highlightningColor } from "../../../helpers/color"; +import { attachClickEvent } from "../../../helpers/dom"; +import findUpClassName from "../../../helpers/dom/findUpClassName"; import { AccountWallPapers, WallPaper } from "../../../layer"; import appDocsManager, { MyDocument } from "../../../lib/appManagers/appDocsManager"; import appDownloadManager from "../../../lib/appManagers/appDownloadManager"; diff --git a/src/components/sidebarLeft/tabs/blockedUsers.ts b/src/components/sidebarLeft/tabs/blockedUsers.ts index 0d7579cd..46bd92fc 100644 --- a/src/components/sidebarLeft/tabs/blockedUsers.ts +++ b/src/components/sidebarLeft/tabs/blockedUsers.ts @@ -1,13 +1,14 @@ import { SliderSuperTab } from "../../slider"; import { SettingSection } from ".."; import { attachContextMenuListener, openBtnMenu, positionMenu } from "../../misc"; -import { attachClickEvent, findUpTag } from "../../../helpers/dom"; +import { attachClickEvent } from "../../../helpers/dom"; import ButtonMenu from "../../buttonMenu"; import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; import appUsersManager from "../../../lib/appManagers/appUsersManager"; import Button from "../../button"; import PopupPickUser from "../../popups/pickUser"; import rootScope from "../../../lib/rootScope"; +import findUpTag from "../../../helpers/dom/findUpTag"; export default class AppBlockedUsersTab extends SliderSuperTab { public peerIds: number[]; diff --git a/src/components/sidebarRight/tabs/editGroup.ts b/src/components/sidebarRight/tabs/editGroup.ts index 7b7aad1d..54d86fd6 100644 --- a/src/components/sidebarRight/tabs/editGroup.ts +++ b/src/components/sidebarRight/tabs/editGroup.ts @@ -167,7 +167,7 @@ export default class AppEditGroupTab extends SliderSuperTab { }, {listenerSetter: this.listenerSetter}); } - { + /* { const section = new SettingSection({ }); @@ -195,7 +195,7 @@ export default class AppEditGroupTab extends SliderSuperTab { } this.scrollable.append(section.container); - } + } */ if(appChatsManager.hasRights(this.chatId, 'delete_chat')) { const section = new SettingSection({}); diff --git a/src/components/sidebarRight/tabs/gifs.ts b/src/components/sidebarRight/tabs/gifs.ts index 9e9b2963..91a364b6 100644 --- a/src/components/sidebarRight/tabs/gifs.ts +++ b/src/components/sidebarRight/tabs/gifs.ts @@ -5,10 +5,11 @@ import appSidebarRight from ".."; import appUsersManager from "../../../lib/appManagers/appUsersManager"; import appInlineBotsManager, { AppInlineBotsManager } from "../../../lib/appManagers/appInlineBotsManager"; import GifsMasonry from "../../gifsMasonry"; -import { findUpClassName, attachClickEvent } from "../../../helpers/dom"; +import { attachClickEvent } from "../../../helpers/dom"; import appImManager from "../../../lib/appManagers/appImManager"; import type { MyDocument } from "../../../lib/appManagers/appDocsManager"; import mediaSizes from "../../../helpers/mediaSizes"; +import findUpClassName from "../../../helpers/dom/findUpClassName"; const ANIMATIONGROUP = 'GIFS-SEARCH'; diff --git a/src/components/sidebarRight/tabs/groupPermissions.ts b/src/components/sidebarRight/tabs/groupPermissions.ts index 31ac84ae..f1e9fee3 100644 --- a/src/components/sidebarRight/tabs/groupPermissions.ts +++ b/src/components/sidebarRight/tabs/groupPermissions.ts @@ -1,11 +1,12 @@ -import { attachClickEvent, findUpTag } from "../../../helpers/dom"; +import { attachClickEvent } from "../../../helpers/dom"; +import findUpTag from "../../../helpers/dom/findUpTag"; import ListenerSetter from "../../../helpers/listenerSetter"; import ScrollableLoader from "../../../helpers/listLoader"; import { ChannelParticipant, Chat, ChatBannedRights, Update } from "../../../layer"; import appChatsManager, { ChatRights } from "../../../lib/appManagers/appChatsManager"; import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; import appProfileManager from "../../../lib/appManagers/appProfileManager"; -import I18n, { i18n } from "../../../lib/langPack"; +import I18n, { i18n, LangPackKey } from "../../../lib/langPack"; import rootScope from "../../../lib/rootScope"; import CheckboxField from "../../checkboxField"; import PopupPickUser from "../../popups/pickUser"; @@ -18,7 +19,7 @@ import AppUserPermissionsTab from "./userPermissions"; export class ChatPermissions { public v: Array<{ flags: ChatRights[], - text: string, + text: LangPackKey, checkboxField?: CheckboxField }>; private toggleWith: Partial<{[chatRight in ChatRights]: ChatRights[]}>; diff --git a/src/components/sidebarRight/tabs/groupType.ts b/src/components/sidebarRight/tabs/groupType.ts index 000da12c..7b7651a6 100644 --- a/src/components/sidebarRight/tabs/groupType.ts +++ b/src/components/sidebarRight/tabs/groupType.ts @@ -116,7 +116,7 @@ export default class AppGroupTypeTab extends SliderSuperTabEventable { plainText: true, listenerSetter: this.listenerSetter, availableText: 'Link.Available', - invalidText: 'Link is invalid', + invalidText: 'Link.Invalid', takenText: 'Link.Taken', onChange: onChange, peerId: this.peerId, diff --git a/src/components/sidebarRight/tabs/sharedMedia.ts b/src/components/sidebarRight/tabs/sharedMedia.ts index 739beb60..1ba1d9e5 100644 --- a/src/components/sidebarRight/tabs/sharedMedia.ts +++ b/src/components/sidebarRight/tabs/sharedMedia.ts @@ -92,9 +92,9 @@ export default class AppSharedMediaTab extends SliderSuperTab { this.title.append(i18n('Telegram.PeerInfoController')); this.editBtn = ButtonIcon('edit'); - const moreBtn = ButtonIcon('more'); + //const moreBtn = ButtonIcon('more'); - transitionFirstItem.append(this.title, this.editBtn, moreBtn); + transitionFirstItem.append(this.title, this.editBtn/* , moreBtn */); const transitionLastItem = document.createElement('div'); transitionLastItem.classList.add('transition-item'); diff --git a/src/components/sidebarRight/tabs/stickers.ts b/src/components/sidebarRight/tabs/stickers.ts index 1ab40690..8722c963 100644 --- a/src/components/sidebarRight/tabs/stickers.ts +++ b/src/components/sidebarRight/tabs/stickers.ts @@ -1,7 +1,7 @@ import { SliderSuperTab } from "../../slider"; import InputSearch from "../../inputSearch"; import LazyLoadQueue from "../../lazyLoadQueue"; -import { findUpClassName, attachClickEvent } from "../../../helpers/dom"; +import { attachClickEvent } from "../../../helpers/dom"; import appImManager from "../../../lib/appManagers/appImManager"; import appStickersManager from "../../../lib/appManagers/appStickersManager"; import PopupStickers from "../../popups/stickers"; @@ -12,6 +12,7 @@ import appSidebarRight from ".."; import { StickerSet, StickerSetCovered } from "../../../layer"; import { forEachReverse } from "../../../helpers/array"; import { i18n } from "../../../lib/langPack"; +import findUpClassName from "../../../helpers/dom/findUpClassName"; export default class AppStickersTab extends SliderSuperTab { private inputSearch: InputSearch; diff --git a/src/components/wrappers.ts b/src/components/wrappers.ts index 76fe6a39..f6f04434 100644 --- a/src/components/wrappers.ts +++ b/src/components/wrappers.ts @@ -19,7 +19,6 @@ import AudioElement from './audio'; import ReplyContainer from './chat/replyContainer'; import { Layouter, RectPart } from './groupedLayout'; import LazyLoadQueue from './lazyLoadQueue'; -import { renderImageFromUrl } from './misc'; import PollElement from './poll'; import ProgressivePreloader from './preloader'; import './middleEllipsis'; @@ -30,6 +29,7 @@ import { SearchSuperContext } from './appSearchSuper.'; import rootScope from '../lib/rootScope'; import { onVideoLoad } from '../helpers/files'; import { animateSingle } from '../helpers/animation'; +import renderImageFromUrl from '../helpers/dom/renderImageFromUrl'; const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB diff --git a/src/config/app.ts b/src/config/app.ts index d2327c4d..bd2fd52b 100644 --- a/src/config/app.ts +++ b/src/config/app.ts @@ -2,7 +2,7 @@ const App = { id: 1025907, hash: '452b0359b988148995f22ff0f4229750', version: '0.4.0', - langPackVersion: '0.0.5', + langPackVersion: '0.0.8', langPack: 'macos', langPackCode: 'en', domains: [] as string[], diff --git a/src/helpers/averageColor.ts b/src/helpers/averageColor.ts index c056d870..3a1d3118 100644 --- a/src/helpers/averageColor.ts +++ b/src/helpers/averageColor.ts @@ -1,4 +1,4 @@ -import { renderImageFromUrl } from "../components/misc"; +import renderImageFromUrl from "./dom/renderImageFromUrl"; export const averageColor = (imageUrl: string): Promise => { const img = document.createElement('img'); diff --git a/src/helpers/dom.ts b/src/helpers/dom.ts index 39862ba2..efa4a5c4 100644 --- a/src/helpers/dom.ts +++ b/src/helpers/dom.ts @@ -338,56 +338,6 @@ export function generatePathData(x: number, y: number, width: number, height: nu MOUNT_CLASS_TO.generatePathData = generatePathData; -//export function findUpClassName(el: any, className: string): T; -export function findUpClassName(el: any, className: string): HTMLElement { - return el.closest('.' + className); - /* if(el.classList.contains(className)) return el; // 03.02.2020 - - while(el.parentElement) { - el = el.parentElement; - if(el.classList.contains(className)) - return el; - } - return null; */ -} - -export function findUpTag(el: any, tag: string): HTMLElement { - return el.closest(tag); - /* if(el.tagName === tag) return el; // 03.02.2020 - - while(el.parentElement) { - el = el.parentElement; - if(el.tagName === tag) - return el; - } - return null; */ -} - -export function findUpAttribute(el: any, attribute: string): HTMLElement { - return el.closest(`[${attribute}]`); - /* if(el.getAttribute(attribute) !== null) return el; // 03.02.2020 - - while(el.parentElement) { - el = el.parentElement; - if(el.getAttribute(attribute) !== null) - return el; - } - return null; */ -} - -export function findUpAsChild(el: any, parent: any) { - if(el.parentElement === parent) return el; - - while(el.parentElement) { - el = el.parentElement; - if(el.parentElement === parent) { - return el; - } - } - - return null; -} - export function whichChild(elem: Node) { if(!elem.parentNode) { return -1; @@ -499,26 +449,6 @@ export function blurActiveElement() { return false; } -export function fixSafariStickyInput(input: HTMLElement) { - input.style.transform = 'translateY(-99999px)'; - /* input.style.position = 'fixed'; - input.style.top = '-99999px'; - input.style.left = '0'; */ - input.focus(); - - setTimeout(() => { - //fastSmoothScroll(findUpClassName(input, 'scrollable-y') || window as any, document.activeElement as HTMLElement, 'start', 4, undefined, FocusDirection.Static); - /* input.style.position = ''; - input.style.top = ''; */ - input.style.transform = ''; - //fastSmoothScroll(findUpClassName(input, 'scrollable-y') || window as any, document.activeElement as HTMLElement, 'start', 4, undefined, FocusDirection.Static); - - /* setTimeout(() => { - fastSmoothScroll(findUpClassName(input, 'scrollable-y') || window as any, document.activeElement as HTMLElement, 'start', 4); - }, 50); */ - }, 0); -} - export const CLICK_EVENT_NAME: 'mousedown' | 'touchend' | 'click' = (isTouchSupported ? 'mousedown' : 'click') as any; export type AttachClickOptions = AddEventListenerOptions & Partial<{listenerSetter: ListenerSetter, touchMouseDown: true}>; export const attachClickEvent = (elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options: AttachClickOptions = {}) => { diff --git a/src/helpers/dom/findUpAsChild.ts b/src/helpers/dom/findUpAsChild.ts new file mode 100644 index 00000000..8f4e06b1 --- /dev/null +++ b/src/helpers/dom/findUpAsChild.ts @@ -0,0 +1,12 @@ +export default function findUpAsChild(el: any, parent: any) { + if(el.parentElement === parent) return el; + + while(el.parentElement) { + el = el.parentElement; + if(el.parentElement === parent) { + return el; + } + } + + return null; +} diff --git a/src/helpers/dom/findUpAttribute.ts b/src/helpers/dom/findUpAttribute.ts new file mode 100644 index 00000000..3eead47a --- /dev/null +++ b/src/helpers/dom/findUpAttribute.ts @@ -0,0 +1,11 @@ +export default function findUpAttribute(el: any, attribute: string): HTMLElement { + return el.closest(`[${attribute}]`); + /* if(el.getAttribute(attribute) !== null) return el; // 03.02.2020 + + while(el.parentElement) { + el = el.parentElement; + if(el.getAttribute(attribute) !== null) + return el; + } + return null; */ +} diff --git a/src/helpers/dom/findUpClassName.ts b/src/helpers/dom/findUpClassName.ts new file mode 100644 index 00000000..5bd5476c --- /dev/null +++ b/src/helpers/dom/findUpClassName.ts @@ -0,0 +1,12 @@ +//export function findUpClassName(el: any, className: string): T; +export default function findUpClassName(el: any, className: string): HTMLElement { + return el.closest('.' + className); + /* if(el.classList.contains(className)) return el; // 03.02.2020 + + while(el.parentElement) { + el = el.parentElement; + if(el.classList.contains(className)) + return el; + } + return null; */ +} diff --git a/src/helpers/dom/findUpTag.ts b/src/helpers/dom/findUpTag.ts new file mode 100644 index 00000000..7d450117 --- /dev/null +++ b/src/helpers/dom/findUpTag.ts @@ -0,0 +1,11 @@ +export default function findUpTag(el: any, tag: string): HTMLElement { + return el.closest(tag); + /* if(el.tagName === tag) return el; // 03.02.2020 + + while(el.parentElement) { + el = el.parentElement; + if(el.tagName === tag) + return el; + } + return null; */ +} diff --git a/src/helpers/dom/fixSafariStickyInput.ts b/src/helpers/dom/fixSafariStickyInput.ts new file mode 100644 index 00000000..64a810c0 --- /dev/null +++ b/src/helpers/dom/fixSafariStickyInput.ts @@ -0,0 +1,19 @@ +export default function fixSafariStickyInput(input: HTMLElement) { + input.style.transform = 'translateY(-99999px)'; + /* input.style.position = 'fixed'; + input.style.top = '-99999px'; + input.style.left = '0'; */ + input.focus(); + + setTimeout(() => { + //fastSmoothScroll(findUpClassName(input, 'scrollable-y') || window as any, document.activeElement as HTMLElement, 'start', 4, undefined, FocusDirection.Static); + /* input.style.position = ''; + input.style.top = ''; */ + input.style.transform = ''; + //fastSmoothScroll(findUpClassName(input, 'scrollable-y') || window as any, document.activeElement as HTMLElement, 'start', 4, undefined, FocusDirection.Static); + + /* setTimeout(() => { + fastSmoothScroll(findUpClassName(input, 'scrollable-y') || window as any, document.activeElement as HTMLElement, 'start', 4); + }, 50); */ + }, 0); +} diff --git a/src/helpers/dom/renderImageFromUrl.ts b/src/helpers/dom/renderImageFromUrl.ts new file mode 100644 index 00000000..334a6278 --- /dev/null +++ b/src/helpers/dom/renderImageFromUrl.ts @@ -0,0 +1,47 @@ +export const loadedURLs: {[url: string]: boolean} = {}; +const set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string) => { + if(elem instanceof HTMLImageElement || elem instanceof HTMLVideoElement) elem.src = url; + else if(elem instanceof SVGImageElement) elem.setAttributeNS(null, 'href', url); + else elem.style.backgroundImage = 'url(' + url + ')'; +}; + +// проблема функции в том, что она не подходит для ссылок, пригодна только для blob'ов, потому что обычным ссылкам нужен 'load' каждый раз. +export default function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLVideoElement, url: string, callback?: (err?: Event) => void, useCache = false): boolean { + if(((loadedURLs[url]/* && false */) && useCache) || elem instanceof HTMLVideoElement) { + if(elem) { + set(elem, url); + } + + callback && callback(); + return true; + } else { + const isImage = elem instanceof HTMLImageElement; + const loader = isImage ? elem as HTMLImageElement : new Image(); + //const loader = new Image(); + loader.src = url; + //let perf = performance.now(); + loader.addEventListener('load', () => { + if(!isImage && elem) { + set(elem, url); + } + + loadedURLs[url] = true; + //console.log('onload:', url, performance.now() - perf); + if(callback) { + // TODO: переделать прогрузки аватаров до начала анимации, иначе с этим ожиданием они неприятно появляются + /* getHeavyAnimationPromise().then(() => { + callback(); + }); */ + callback(); + } + + //callback && callback(); + }); + + if(callback) { + loader.addEventListener('error', callback); + } + + return false; + } +} diff --git a/src/index.hbs b/src/index.hbs index d3ec4271..abc2cdae 100644 --- a/src/index.hbs +++ b/src/index.hbs @@ -55,24 +55,8 @@
-
-
-
-

Enter Your Password

-

Your account is protected with
an additional password

-
-
-
-
-
-
- - -
-

Your Name

-

Enter your name and add
a profile picture

-
-
+
+
diff --git a/src/lang.ts b/src/lang.ts index ae3e2f01..c4903ff5 100644 --- a/src/lang.ts +++ b/src/lang.ts @@ -87,8 +87,8 @@ const lang = { "Popup.Unpin.Hide": "Hide", "TwoStepAuth.InvalidPassword": "Invalid password", "TwoStepAuth.EmailCodeChangeEmail": "Change Email", - "PleaseWait": "Please wait...", "MarkupTooltip.LinkPlaceholder": "Enter URL...", + "MediaViewer.Context.Download": "Download", // * android "ActionCreateChannel": "Channel created", @@ -358,7 +358,6 @@ const lang = { "PleaseEnterCurrentPassword": "Enter your password", "PleaseEnterFirstPassword": "Enter a password", "PleaseReEnterPassword": "Re-enter your password", - "LoginPassword": "Password", "Continue": "Continue", "YourEmailSkip": "Skip", "YourEmailSkipWarning": "Warning", @@ -391,6 +390,8 @@ const lang = { "Channel.UsernameAboutGroup": "People can share this link with others and find your group using Telegram search.", "Chat.CopySelectedText": "Copy Selected Text", "Chat.Confirm.Unpin": "Would you like to unpin this message?", + "Chat.Context.Scheduled.SendNow": "Send Now", + "Chat.Context.Scheduled.Reschedule": "Re-schedule", "Chat.Date.ScheduledFor": "Scheduled for %@", //"Chat.Date.ScheduledUntilOnline": "Scheduled until online", "Chat.Date.ScheduledForToday": "Scheduled for today", @@ -483,6 +484,7 @@ const lang = { "Telegram.InstalledStickerPacksController": "Stickers", "Telegram.NotificationSettingsViewController": "Notifications", "Telegram.PeerInfoController": "Info", + "Telegram.LanguageViewController": "Language", "Stickers.SearchAdd": "Add", "Stickers.SearchAdded": "Added", "Stickers.SuggestStickers": "Suggest Stickers by Emoji", @@ -596,8 +598,7 @@ const lang = { "TwoStepAuth.RecoveryCodeInvalid": "Invalid code. Please try again.", "TwoStepAuth.RecoveryCodeExpired": "Code Expired", "TwoStepAuth.SetupHintTitle": "Password Hint", - "TwoStepAuth.SetupHintPlaceholder": "Hint", - "PHONE_CODE_INVALID": "Invalid code", + "TwoStepAuth.SetupHintPlaceholder": "Hint" }; export default lang; diff --git a/src/langSign.ts b/src/langSign.ts index c8c2e0fb..80e1d5e0 100644 --- a/src/langSign.ts +++ b/src/langSign.ts @@ -5,9 +5,22 @@ const lang = { "Login.PhoneLabelInvalid": "Phone Number Invalid", "Login.KeepSigned": "Keep me signed in", "Login.StartText": "Please confirm your country and\nenter your phone number.", + "Login.Code.SentSms": "We have sent you an SMS\nwith the code.", + "Login.Code.SentInApp": "We have sent you a message in Telegram\nwith the code.", + "Login.Code.SentCall": "We will call you and voice\nthe code.", + "Login.Code.SentUnknown": "Please check everything\nfor a code (type: %s)", + "Login.Password.Title": "Enter Your Password", + "Login.Password.Subtitle": "Your account is protected with\nan additional password", + "Login.Register.Subtitle": "Enter your name and add\na profile picture", + "PleaseWait": "Please wait...", // * android - + "Code": "Code", + "LoginPassword": "Password", + "YourName": "Your Name", + "FirstName": "First name (required)", + "LastName": "Last name (optional)", + "StartMessaging": "Start Messaging", // * macos "Login.Next": "Next", @@ -18,6 +31,9 @@ const lang = { "Login.QR.Help3": "Point your phone at this screen to confirm login", "Login.QR.Cancel": "Log in by phone Number", "Login.QR.Login": "Log in by QR Code", + "PHONE_CODE_INVALID": "Invalid code", + "PHONE_CODE_EXPIRED": "Code expired", + "PASSWORD_HASH_INVALID": "Incorrect password" }; export default lang; diff --git a/src/layer.d.ts b/src/layer.d.ts index 8cb51715..ecdd017a 100644 --- a/src/layer.d.ts +++ b/src/layer.d.ts @@ -6043,7 +6043,9 @@ export namespace LangPackDifference { lang_code: string, from_version: number, version: number, - strings: Array + strings: Array, + local?: boolean, + appVersion?: string }; } diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index 384decb9..bcb450b8 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -11,7 +11,7 @@ import { isSafari } from "../../helpers/userAgent"; import { logger, LogLevels } from "../logger"; import { RichTextProcessor } from "../richtextprocessor"; import rootScope from "../rootScope"; -import { findUpTag, positionElementByIndex } from "../../helpers/dom"; +import { positionElementByIndex } from "../../helpers/dom"; import appImManager from "./appImManager"; import appMessagesManager, { Dialog } from "./appMessagesManager"; import {MyDialogFilter as DialogFilter} from "../storages/filters"; @@ -30,6 +30,7 @@ import appNotificationsManager from "./appNotificationsManager"; import { InputNotifyPeer } from "../../layer"; import PeerTitle from "../../components/peerTitle"; import { i18n } from "../langPack"; +import findUpTag from "../../helpers/dom/findUpTag"; type DialogDom = { avatarEl: AvatarElement, diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 1c1cd0e6..0eda8b22 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -2690,7 +2690,7 @@ export class AppMessagesManager { } else { let _ = action._; //let suffix = ''; - let langPackKey: LangPackKey = ''; + let langPackKey: LangPackKey; let args: any[]; const getNameDivHTML = (peerId: number, plain: boolean) => { @@ -2789,14 +2789,14 @@ export class AppMessagesManager { } default: - langPackKey = langPack[_] || `[${action._}]`; + langPackKey = (langPack[_] || `[${action._}]`) as any; break; } if(!langPackKey) { langPackKey = langPack[_]; if(langPackKey === undefined) { - langPackKey = '[' + _ + ']'; + langPackKey = '[' + _ + ']' as any; } } diff --git a/src/lib/appManagers/appPhotosManager.ts b/src/lib/appManagers/appPhotosManager.ts index 20f73217..0b9cb2b8 100644 --- a/src/lib/appManagers/appPhotosManager.ts +++ b/src/lib/appManagers/appPhotosManager.ts @@ -11,8 +11,8 @@ import { MyDocument } from "./appDocsManager"; import appDownloadManager from "./appDownloadManager"; import appUsersManager from "./appUsersManager"; import blur from "../../helpers/blur"; -import { renderImageFromUrl } from "../../components/misc"; import { MOUNT_CLASS_TO } from "../../config/debug"; +import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl"; export type MyPhoto = Photo.photo; diff --git a/src/lib/appManagers/appUsersManager.ts b/src/lib/appManagers/appUsersManager.ts index 066bb699..0cfe74ca 100644 --- a/src/lib/appManagers/appUsersManager.ts +++ b/src/lib/appManagers/appUsersManager.ts @@ -406,7 +406,7 @@ export class AppUsersManager { const user = this.getUser(userId); if(!user) { - key = ''; + key = '' as any; break; } @@ -432,8 +432,6 @@ export class AppUsersManager { } case 'userStatusOffline': { - key = 'last seen '; - const date = user.status.was_online; const now = Date.now() / 1000; diff --git a/src/lib/langPack.ts b/src/lib/langPack.ts index 39625946..55a4b65f 100644 --- a/src/lib/langPack.ts +++ b/src/lib/langPack.ts @@ -42,7 +42,7 @@ export const langPack: {[actionType: string]: LangPackKey} = { "messageActionBotAllowed": "Chat.Service.BotPermissionAllowed" }; -export type LangPackKey = string | keyof typeof lang | keyof typeof langSign; +export type LangPackKey = /* string | */keyof typeof lang | keyof typeof langSign; namespace I18n { export const strings: Map = new Map(); @@ -50,10 +50,11 @@ namespace I18n { let cacheLangPackPromise: Promise; export let lastRequestedLangCode: string; + export let requestedServerLanguage = false; export function getCacheLangPack(): Promise { if(cacheLangPackPromise) return cacheLangPackPromise; return cacheLangPackPromise = Promise.all([ - sessionStorage.get('langPack'), + sessionStorage.get('langPack') as Promise, polyfillPromise ]).then(([langPack]) => { if(!langPack/* || true */) { @@ -91,13 +92,15 @@ namespace I18n { from_version: 0, lang_code: defaultCode, strings, - version: 0 + version: 0, + local: true }; return saveLangPack(langPack); }); } export function loadLangPack(langCode: string) { + requestedServerLanguage = true; return Promise.all([ apiManager.invokeApiCacheable('langpack.getLangPack', { lang_code: langCode, @@ -164,7 +167,6 @@ namespace I18n { } export function saveLangPack(langPack: LangPackDifference) { - // @ts-ignore langPack.appVersion = App.langPackVersion; return sessionStorage.set({langPack}).then(() => { diff --git a/src/pages/loginPage.ts b/src/pages/loginPage.ts new file mode 100644 index 00000000..09607904 --- /dev/null +++ b/src/pages/loginPage.ts @@ -0,0 +1,48 @@ +import { LangPackKey, i18n } from "../lib/langPack"; + +export default class LoginPage { + public element: HTMLElement; + public container: HTMLElement; + public imageDiv: HTMLElement; + public inputWrapper: HTMLElement; + public title: HTMLElement; + public subtitle: HTMLParagraphElement; + + constructor(options: { + className: string, + withInputWrapper?: boolean, + titleLangKey?: LangPackKey, + subtitleLangKey?: LangPackKey, + }) { + this.element = document.body.querySelector('.' + options.className) as HTMLDivElement; + //this.element = document.createElement('div'); + //this.element.className = 'page-' + options.className; + + this.container = document.createElement('div'); + this.container.className = 'container center-align'; + + this.imageDiv = document.createElement('div'); + this.imageDiv.className = 'auth-image'; + + this.title = document.createElement('h4'); + if(options.titleLangKey) { + this.title.append(i18n(options.titleLangKey)); + } + + this.subtitle = document.createElement('p'); + this.subtitle.className = 'subtitle'; + if(options.subtitleLangKey) { + this.subtitle.append(i18n(options.subtitleLangKey)); + } + + this.container.append(this.imageDiv, this.title, this.subtitle); + + if(options.withInputWrapper) { + this.inputWrapper = document.createElement('div'); + this.inputWrapper.className = 'input-wrapper'; + this.container.append(this.inputWrapper); + } + + this.element.append(this.container); + } +} diff --git a/src/pages/page.ts b/src/pages/page.ts index ddffd547..3700794c 100644 --- a/src/pages/page.ts +++ b/src/pages/page.ts @@ -32,4 +32,4 @@ export default class Page { pagesManager.setPage(this); } -} \ No newline at end of file +} diff --git a/src/pages/pageAuthCode.ts b/src/pages/pageAuthCode.ts index f7417fb8..63c35442 100644 --- a/src/pages/pageAuthCode.ts +++ b/src/pages/pageAuthCode.ts @@ -9,6 +9,8 @@ import pageSignIn from './pageSignIn'; import pageSignUp from './pageSignUp'; import TrackingMonkey from '../components/monkeys/tracking'; import CodeInputField from '../components/codeInputField'; +import { replaceContent } from '../helpers/dom'; +import { i18n, LangPackKey } from '../lib/langPack'; let authCode: AuthSentCode.authSentCode = null; @@ -89,12 +91,12 @@ let onFirstMount = (): Promise => { break; case 'PHONE_CODE_EXPIRED': codeInput.classList.add('error'); - codeInputField.label.innerText = 'Code expired'; + replaceContent(codeInputField.label, i18n('PHONE_CODE_EXPIRED')); break; case 'PHONE_CODE_EMPTY': case 'PHONE_CODE_INVALID': codeInput.classList.add('error'); - codeInputField.label.innerText = 'Invalid Code'; + replaceContent(codeInputField.label, i18n('PHONE_CODE_INVALID')); break; default: codeInputField.label.innerText = err.type; @@ -127,21 +129,25 @@ const page = new Page('page-authCode', true, onFirstMount, (_authCode: typeof au } headerElement.innerText = authCode.phone_number; + let key: LangPackKey, args: any[]; switch(authCode.type._) { case 'auth.sentCodeTypeSms': - sentTypeElement.innerHTML = 'We have sent you an SMS
with the code.'; + key = 'Login.Code.SentSms'; break; case 'auth.sentCodeTypeApp': - sentTypeElement.innerHTML = 'We have sent you a message in Telegram
with the code.'; + key = 'Login.Code.SentInApp'; break; case 'auth.sentCodeTypeCall': - sentTypeElement.innerHTML = 'We will call you and voice
the code.'; + key = 'Login.Code.SentCall'; break; default: - sentTypeElement.innerHTML = `Please check everything
for a code (type: ${authCode.type._})`; + key = 'Login.Code.SentUnknown'; + args = [authCode.type._]; break; } + replaceContent(sentTypeElement, i18n(key, args)); + appStateManager.pushToState('authState', {_: 'authStateAuthCode', sentCode: _authCode}); appStateManager.saveState(); }, () => { diff --git a/src/pages/pageIm.ts b/src/pages/pageIm.ts index 04064849..9622cbdb 100644 --- a/src/pages/pageIm.ts +++ b/src/pages/pageIm.ts @@ -2,6 +2,7 @@ //import appStateManager from "../lib/appManagers/appStateManager"; import { blurActiveElement } from "../helpers/dom"; import appStateManager from "../lib/appManagers/appStateManager"; +import I18n from "../lib/langPack"; import Page from "./page"; let onFirstMount = () => { @@ -14,6 +15,14 @@ let onFirstMount = () => { m.default.broadcast('im_mount'); }); + if(!I18n.requestedServerLanguage) { + I18n.getCacheLangPack().then(langPack => { + if(langPack.local) { + I18n.getLangPack(langPack.lang_code); + } + }); + } + blurActiveElement(); return new Promise((resolve) => { window.requestAnimationFrame(() => { diff --git a/src/pages/pagePassword.ts b/src/pages/pagePassword.ts index 1a01fe48..ab7fc994 100644 --- a/src/pages/pagePassword.ts +++ b/src/pages/pagePassword.ts @@ -8,23 +8,35 @@ import pageIm from './pageIm'; import Button from '../components/button'; import PasswordInputField from '../components/passwordInputField'; import PasswordMonkey from '../components/monkeys/password'; -import { ripple } from '../components/ripple'; import RichTextProcessor from '../lib/richtextprocessor'; +import I18n from '../lib/langPack'; +import LoginPage from './loginPage'; +import { replaceContent } from '../helpers/dom'; const TEST = false; let passwordInput: HTMLInputElement; let onFirstMount = (): Promise => { - const btnNext = Button('btn-primary btn-color-primary', {text: 'NEXT'}); + const page = new LoginPage({ + className: 'page-password', + withInputWrapper: true, + titleLangKey: 'Login.Password.Title', + subtitleLangKey: 'Login.Password.Subtitle' + }); + + const btnNext = Button('btn-primary btn-color-primary'); + const btnNextI18n = new I18n.IntlElement({key: 'Login.Next'}); + + btnNext.append(btnNextI18n.element); const passwordInputField = new PasswordInputField({ - label: 'Password', + label: 'LoginPassword', name: 'password' }); passwordInput = passwordInputField.input as HTMLInputElement; - page.pageEl.querySelector('.input-wrapper').append(passwordInputField.container, btnNext); + page.inputWrapper.append(passwordInputField.container, btnNext); let getStateInterval: number; @@ -37,24 +49,14 @@ let onFirstMount = (): Promise => { return !TEST && passwordManager.getState().then(_state => { state = _state; - passwordInputField.label.innerHTML = state.hint ? RichTextProcessor.wrapEmojiText(state.hint) : 'Password'; + if(state.hint) { + replaceContent(passwordInputField.label, RichTextProcessor.wrapEmojiText(state.hint)); + } else { + passwordInputField.setLabel(); + } }); }; - let handleError = (err: any) => { - btnNext.removeAttribute('disabled'); - passwordInputField.input.classList.add('error'); - - switch(err.type) { - default: - //btnNext.innerText = err.type; - btnNext.innerText = 'INVALID PASSWORD'; - break; - } - - getState(); - }; - let state: AccountPassword; btnNext.addEventListener('click', function(this, e) { @@ -66,8 +68,8 @@ let onFirstMount = (): Promise => { this.setAttribute('disabled', 'true'); let value = passwordInput.value; - this.textContent = 'PLEASE WAIT...'; - putPreloader(this); + btnNextI18n.update({key: 'PleaseWait'}); + const preloader = putPreloader(this); passwordManager.check(value, state).then((response) => { //console.log('passwordManager response:', response); @@ -80,17 +82,30 @@ let onFirstMount = (): Promise => { break; default: btnNext.removeAttribute('disabled'); - btnNext.innerText = response._; - ripple(btnNext); + btnNextI18n.update({key: response._ as any}); + preloader.remove(); + break; + } + }).catch((err: any) => { + btnNext.removeAttribute('disabled'); + passwordInputField.input.classList.add('error'); + + switch(err.type) { + default: + //btnNext.innerText = err.type; + btnNextI18n.update({key: 'PASSWORD_HASH_INVALID'}); break; } - }).catch(handleError); + + preloader.remove(); + + getState(); + }); }); passwordInput.addEventListener('keypress', function(this, e) { this.classList.remove('error'); - btnNext.innerText = 'NEXT'; - ripple(btnNext); + btnNextI18n.update({key: 'Login.Next'}); if(e.key === 'Enter') { return btnNext.click(); @@ -99,7 +114,7 @@ let onFirstMount = (): Promise => { const size = mediaSizes.isMobile ? 100 : 166; const monkey = new PasswordMonkey(passwordInputField, size); - page.pageEl.querySelector('.auth-image').append(monkey.container); + page.imageDiv.append(monkey.container); return Promise.all([ monkey.load(), getState() diff --git a/src/pages/pageSignIn.ts b/src/pages/pageSignIn.ts index 73ec8df8..dbf7adce 100644 --- a/src/pages/pageSignIn.ts +++ b/src/pages/pageSignIn.ts @@ -4,7 +4,7 @@ import Countries, { Country as _Country } from "../countries"; import appStateManager from "../lib/appManagers/appStateManager"; import apiManager from "../lib/mtproto/mtprotoworker"; import { RichTextProcessor } from '../lib/richtextprocessor'; -import { findUpTag, attachClickEvent, cancelEvent, replaceContent } from "../helpers/dom"; +import { attachClickEvent, cancelEvent, replaceContent } from "../helpers/dom"; import Page from "./page"; import pageAuthCode from "./pageAuthCode"; import InputField from "../components/inputField"; @@ -15,9 +15,11 @@ import fastSmoothScroll from "../helpers/fastSmoothScroll"; import { isTouchSupported } from "../helpers/touchSupport"; import App from "../config/app"; import Modes from "../config/modes"; -import I18n, { _i18n, i18n } from "../lib/langPack"; +import I18n, { _i18n, i18n, LangPackKey } from "../lib/langPack"; import { LangPackString } from "../layer"; import lottieLoader from "../lib/lottieLoader"; +import { ripple } from "../components/ripple"; +import findUpTag from "../helpers/dom/findUpTag"; type Country = _Country & { li?: HTMLLIElement[] @@ -370,7 +372,9 @@ let onFirstMount = () => { setTimeout(() => { btnQr.removeAttribute('disabled'); - preloaderDiv.remove(); + if(preloaderDiv) { + preloaderDiv.remove(); + } }, 200); }); }); @@ -442,20 +446,20 @@ let onFirstMount = () => { ]).then(res => { const backup: LangPackString[] = []; res[0].forEach(string => { - const backupString = I18n.strings.get(string.key); + const backupString = I18n.strings.get(string.key as LangPackKey); if(!backupString) { return; } backup.push(backupString); - I18n.strings.set(string.key, string); + I18n.strings.set(string.key as LangPackKey, string); }); const btnChangeLanguage = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'Login.ContinueOnLanguage'}); inputWrapper.append(btnChangeLanguage); backup.forEach(string => { - I18n.strings.set(string.key, string); + I18n.strings.set(string.key as LangPackKey, string); }); attachClickEvent(btnChangeLanguage, (e) => { @@ -478,6 +482,7 @@ let onFirstMount = () => { const page = new Page('page-sign', true, onFirstMount, () => { if(btnNext) { replaceContent(btnNext, i18n('Login.Next')); + ripple(btnNext, undefined, undefined, true); btnNext.removeAttribute('disabled'); } diff --git a/src/pages/pageSignQR.ts b/src/pages/pageSignQR.ts index fabb62eb..3040714c 100644 --- a/src/pages/pageSignQR.ts +++ b/src/pages/pageSignQR.ts @@ -10,7 +10,7 @@ import { bytesCmp, bytesToBase64 } from '../helpers/bytes'; import { pause } from '../helpers/schedulers'; import App from '../config/app'; import Button from '../components/button'; -import { _i18n, i18n } from '../lib/langPack'; +import { _i18n, i18n, LangPackKey } from '../lib/langPack'; let onFirstMount = async() => { const pageElement = page.pageEl; @@ -29,7 +29,7 @@ let onFirstMount = async() => { const helpList = document.createElement('ol'); helpList.classList.add('qr-description'); - ['Login.QR.Help1', 'Login.QR.Help2', 'Login.QR.Help3'].forEach((key) => { + (['Login.QR.Help1', 'Login.QR.Help2', 'Login.QR.Help3'] as LangPackKey[]).forEach((key) => { const li = document.createElement('li'); li.append(i18n(key)); helpList.append(li); diff --git a/src/pages/pageSignUp.ts b/src/pages/pageSignUp.ts index e3823529..4bb97509 100644 --- a/src/pages/pageSignUp.ts +++ b/src/pages/pageSignUp.ts @@ -1,40 +1,62 @@ +import type { CancellablePromise } from '../helpers/cancellablePromise'; +import type { InputFile } from '../layer'; +import type { AuthState } from '../types'; import Button from '../components/button'; import InputField from '../components/inputField'; import { putPreloader } from '../components/misc'; import PopupAvatar from '../components/popups/avatar'; +import { replaceContent } from '../helpers/dom'; import appStateManager from '../lib/appManagers/appStateManager'; +import I18n, { i18n } from '../lib/langPack'; //import apiManager from '../lib/mtproto/apiManager'; import apiManager from '../lib/mtproto/mtprotoworker'; import RichTextProcessor from '../lib/richtextprocessor'; -import { AuthState } from '../types'; +import LoginPage from './loginPage'; import Page from './page'; import pageIm from './pageIm'; let authCode: AuthState.signUp['authCode'] = null; const onFirstMount = () => import('../lib/appManagers/appProfileManager').then(imported => { - const pageElement = page.pageEl; - const avatarPreview = pageElement.querySelector('#canvas-avatar') as HTMLCanvasElement; + const page = new LoginPage({ + className: 'page-signUp', + withInputWrapper: true, + titleLangKey: 'YourName', + subtitleLangKey: 'Login.Register.Subtitle' + }); + + page.imageDiv.classList.add('avatar-edit'); + + page.title.classList.add('fullName'); + + const avatarPreview = document.createElement('canvas'); + avatarPreview.id = 'canvas-avatar'; + avatarPreview.className = 'avatar-edit-canvas'; + + const addIco = document.createElement('span'); + addIco.className = 'tgico tgico-cameraadd'; + + page.imageDiv.append(avatarPreview, addIco); + const appProfileManager = imported.default; - let uploadAvatar: () => Promise; - pageElement.querySelector('.auth-image').addEventListener('click', () => { + let uploadAvatar: () => CancellablePromise; + page.imageDiv.addEventListener('click', () => { new PopupAvatar().open(avatarPreview, (_uploadAvatar) => { uploadAvatar = _uploadAvatar; }); }); - const headerName = pageElement.getElementsByClassName('fullName')[0] as HTMLHeadingElement; - const handleInput = (e: Event) => { const name = nameInputField.value || ''; const lastName = lastNameInputField.value || ''; const fullName = name || lastName ? (name + ' ' + lastName).trim() - : 'Your Name'; + : ''; - if(headerName.innerHTML !== fullName) headerName.innerHTML = RichTextProcessor.wrapEmojiText(fullName); + if(fullName) replaceContent(page.title, RichTextProcessor.wrapEmojiText(fullName)); + else replaceContent(page.title, i18n('YourName')); }; let sendAvatar = () => new Promise((resolve, reject) => { @@ -44,32 +66,28 @@ const onFirstMount = () => import('../lib/appManagers/appProfileManager').then(i } //console.log('invoking uploadFile...'); - uploadAvatar().then((inputFile: any) => { + uploadAvatar().then((inputFile) => { //console.log('uploaded smthn', inputFile); appProfileManager.uploadProfilePhoto(inputFile).then(resolve, reject); }, reject); }); - const inputWrapper = document.createElement('div'); - inputWrapper.classList.add('input-wrapper'); - const nameInputField = new InputField({ - label: 'Name', + label: 'FirstName', maxLength: 70 }); const lastNameInputField = new InputField({ - label: 'Last Name (optional)', + label: 'LastName', maxLength: 64 }); const btnSignUp = Button('btn-primary btn-color-primary'); - btnSignUp.append('START MESSAGING'); - - inputWrapper.append(nameInputField.container, lastNameInputField.container, btnSignUp); + const btnI18n = new I18n.IntlElement({key: 'StartMessaging'}); + btnSignUp.append(btnI18n.element); - headerName.parentElement.append(inputWrapper); + page.inputWrapper.append(nameInputField.container, lastNameInputField.container, btnSignUp); nameInputField.input.addEventListener('input', handleInput); lastNameInputField.input.addEventListener('input', handleInput); @@ -84,7 +102,7 @@ const onFirstMount = () => import('../lib/appManagers/appProfileManager').then(i return false; } - this.setAttribute('disabled', 'true'); + this.disabled = true; const name = nameInputField.value.trim(); const lastName = lastNameInputField.value.trim(); @@ -98,8 +116,8 @@ const onFirstMount = () => import('../lib/appManagers/appProfileManager').then(i //console.log('invoking auth.signUp with params:', params); - this.textContent = 'PLEASE WAIT...'; - putPreloader(this); + btnI18n.update({key: 'PleaseWait'}); + const preloader = putPreloader(this); apiManager.invokeApi('auth.signUp', params) .then((response) => { @@ -115,7 +133,9 @@ const onFirstMount = () => import('../lib/appManagers/appProfileManager').then(i break; default: - this.innerText = response._; + btnI18n.update({key: response._ as any}); + this.removeAttribute('disabled'); + preloader.remove(); break; } @@ -123,10 +143,11 @@ const onFirstMount = () => import('../lib/appManagers/appProfileManager').then(i pageAuthCode(Object.assign(code, {phoneNumber})); */ }).catch(err => { this.removeAttribute('disabled'); + preloader.remove(); switch(err.type) { default: - this.innerText = err.type; + btnI18n.update({key: err.type}); break; } }); diff --git a/src/scripts/in/schema_additional_params.json b/src/scripts/in/schema_additional_params.json index 21bc4263..eac89a44 100644 --- a/src/scripts/in/schema_additional_params.json +++ b/src/scripts/in/schema_additional_params.json @@ -208,4 +208,10 @@ {"name": "users", "type": "Array"} ], "type": "MessageAction" +}, { + "predicate": "langPackDifference", + "params": [ + {"name": "local", "type": "boolean"}, + {"name": "appVersion", "type": "string"} + ] }] \ No newline at end of file diff --git a/src/scss/partials/_chatBubble.scss b/src/scss/partials/_chatBubble.scss index 5e537b16..f2a734d5 100644 --- a/src/scss/partials/_chatBubble.scss +++ b/src/scss/partials/_chatBubble.scss @@ -102,7 +102,7 @@ $bubble-margin: .25rem; margin-left: -50%; margin-right: -50%; text-align: center; - color: var(--primary-text-color); + color: var(--primary-color); line-height: 2.1; font-weight: 500; font-size: 15px;