Respect read comments position

Fix bluring keyboard on Android
Fix reading messages when page was blured
Fix instant reading messages if there only one page of them
Split dom functions
This commit is contained in:
Eduard Kuzmenko 2021-05-08 21:46:50 +04:00
parent 52a7e4d34f
commit 40c266cd08
111 changed files with 1048 additions and 732 deletions

View File

@ -4,11 +4,11 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { isInDOM } from "../helpers/dom";
import { RLottiePlayer } from "../lib/lottieLoader";
import rootScope from "../lib/rootScope";
import { isSafari } from "../helpers/userAgent";
import { MOUNT_CLASS_TO } from "../config/debug";
import isInDOM from "../helpers/dom/isInDOM";
export interface AnimationItem {
el: HTMLElement,

View File

@ -17,7 +17,6 @@ import { logger } from "../lib/logger";
import VideoPlayer from "../lib/mediaPlayer";
import { RichTextProcessor } from "../lib/richtextprocessor";
import rootScope from "../lib/rootScope";
import { cancelEvent, fillPropertyValue, generatePathData } from "../helpers/dom";
import animationIntersector from "./animationIntersector";
import appMediaPlaybackController from "./appMediaPlaybackController";
import AvatarElement from "./avatar";
@ -42,6 +41,9 @@ import renderImageFromUrl from "../helpers/dom/renderImageFromUrl";
import findUpAsChild from "../helpers/dom/findUpAsChild";
import getVisibleRect from "../helpers/dom/getVisibleRect";
import appDownloadManager from "../lib/appManagers/appDownloadManager";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import fillPropertyValue from "../helpers/fillPropertyValue";
import generatePathData from "../helpers/generatePathData";
// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию
// TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)

View File

@ -6,9 +6,10 @@
import { MOUNT_CLASS_TO } from "../config/debug";
import { isMobileSafari } from "../helpers/userAgent";
import { blurActiveElement, cancelEvent } from "../helpers/dom";
import { logger } from "../lib/logger";
import { doubleRaf } from "../helpers/schedulers";
import blurActiveElement from "../helpers/dom/blurActiveElement";
import { cancelEvent } from "../helpers/dom/cancelEvent";
export type NavigationItem = {
type: 'left' | 'right' | 'im' | 'chat' | 'popup' | 'media' | 'menu' | 'esg' | 'multiselect' | 'input-helper' | 'markup' | 'global-search',

View File

@ -5,11 +5,10 @@
*/
import { formatDateAccordingToToday, months } from "../helpers/date";
import { positionElementByIndex } from "../helpers/dom";
import { copy, getObjectKeysAndSort, safeAssign } from "../helpers/object";
import { escapeRegExp, limitSymbols } from "../helpers/string";
import appChatsManager from "../lib/appManagers/appChatsManager";
import appDialogsManager, { DialogDom } from "../lib/appManagers/appDialogsManager";
import appDialogsManager from "../lib/appManagers/appDialogsManager";
import appMessagesManager, { MyInputMessagesFilter, MyMessage } from "../lib/appManagers/appMessagesManager";
import appPeersManager from "../lib/appManagers/appPeersManager";
import appPhotosManager from "../lib/appManagers/appPhotosManager";
@ -39,6 +38,7 @@ import findUpTag from "../helpers/dom/findUpTag";
import appSidebarRight from "./sidebarRight";
import mediaSizes from "../helpers/mediaSizes";
import appImManager from "../lib/appManagers/appImManager";
import positionElementByIndex from "../helpers/dom/positionElementByIndex";
//const testScroll = false;

View File

@ -10,7 +10,6 @@ import appMessagesManager, { Dialog } from "../lib/appManagers/appMessagesManage
import appPhotosManager from "../lib/appManagers/appPhotosManager";
import appUsersManager from "../lib/appManagers/appUsersManager";
import rootScope from "../lib/rootScope";
import { cancelEvent, replaceContent } from "../helpers/dom";
import Scrollable from "./scrollable";
import { FocusDirection } from "../helpers/fastSmoothScroll";
import CheckboxField from "./checkboxField";
@ -20,6 +19,8 @@ import { i18n, LangPackKey, _i18n } from "../lib/langPack";
import findUpAttribute from "../helpers/dom/findUpAttribute";
import findUpClassName from "../helpers/dom/findUpClassName";
import PeerTitle from "./peerTitle";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import replaceContent from "../helpers/dom/replaceContent";
type PeerType = 'contacts' | 'dialogs' | 'channelParticipants';

View File

@ -16,9 +16,10 @@ import { isSafari } from "../helpers/userAgent";
import appMessagesManager from "../lib/appManagers/appMessagesManager";
import rootScope from "../lib/rootScope";
import './middleEllipsis';
import { attachClickEvent, cancelEvent, detachClickEvent } from "../helpers/dom";
import { SearchSuperContext } from "./appSearchSuper.";
import { formatDateAccordingToToday } from "../helpers/date";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import { attachClickEvent, detachClickEvent } from "../helpers/dom/clickEvent";
rootScope.on('messages_media_read', e => {
const {mids, peerId} = e;

View File

@ -7,12 +7,13 @@
import appMessagesManager from "../lib/appManagers/appMessagesManager";
import appProfileManager from "../lib/appManagers/appProfileManager";
import rootScope from "../lib/rootScope";
import { attachClickEvent, cancelEvent } from "../helpers/dom";
import AppMediaViewer, { AppMediaViewerAvatar } from "./appMediaViewer";
import { Message } from "../layer";
import appPeersManager from "../lib/appManagers/appPeersManager";
import appPhotosManager from "../lib/appManagers/appPhotosManager";
import type { LazyLoadQueueIntersector } from "./lazyLoadQueue";
import { attachClickEvent } from "../helpers/dom/clickEvent";
import { cancelEvent } from "../helpers/dom/cancelEvent";
const onAvatarUpdate = (peerId: number) => {
appProfileManager.removeFromAvatarsCache(peerId);

View File

@ -4,7 +4,8 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { attachClickEvent, AttachClickOptions, cancelEvent, CLICK_EVENT_NAME } from "../helpers/dom";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import { AttachClickOptions, attachClickEvent, CLICK_EVENT_NAME } from "../helpers/dom/clickEvent";
import ListenerSetter from "../helpers/listenerSetter";
import { i18n, LangPackKey } from "../lib/langPack";
import CheckboxField from "./checkboxField";

View File

@ -4,7 +4,8 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { AttachClickOptions, cancelEvent, CLICK_EVENT_NAME } from "../helpers/dom";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import { AttachClickOptions, CLICK_EVENT_NAME } from "../helpers/dom/clickEvent";
import ListenerSetter from "../helpers/listenerSetter";
import ButtonIcon from "./buttonIcon";
import ButtonMenu, { ButtonMenuItemOptions } from "./buttonMenu";

View File

@ -9,12 +9,13 @@ import type { AppPeersManager } from "../../lib/appManagers/appPeersManager";
import type ChatTopbar from "./topbar";
import { RichTextProcessor } from "../../lib/richtextprocessor";
import rootScope from "../../lib/rootScope";
import { attachClickEvent, cancelEvent } from "../../helpers/dom";
import appMediaPlaybackController from "../appMediaPlaybackController";
import DivAndCaption from "../divAndCaption";
import { formatDate } from "../wrappers";
import PinnedContainer from "./pinnedContainer";
import Chat from "./chat";
import { cancelEvent } from "../../helpers/dom/cancelEvent";
import { attachClickEvent } from "../../helpers/dom/clickEvent";
export default class ChatAudio extends PinnedContainer {
private toggleEl: HTMLElement;

View File

@ -5,7 +5,7 @@
*/
import type { AppImManager } from "../../lib/appManagers/appImManager";
import type { AppMessagesManager, HistoryResult, MyMessage } from "../../lib/appManagers/appMessagesManager";
import type { AppMessagesManager, HistoryResult, HistoryStorage, MyMessage } from "../../lib/appManagers/appMessagesManager";
import type { AppStickersManager } from "../../lib/appManagers/appStickersManager";
import type { AppUsersManager } from "../../lib/appManagers/appUsersManager";
import type { AppInlineBotsManager } from "../../lib/appManagers/appInlineBotsManager";
@ -15,7 +15,6 @@ import type { AppPeersManager } from "../../lib/appManagers/appPeersManager";
import type sessionStorage from '../../lib/sessionStorage';
import type Chat from "./chat";
import { CHAT_ANIMATION_GROUP } from "../../lib/appManagers/appImManager";
import { cancelEvent, whichChild, attachClickEvent, positionElementByIndex, reflowScrollableElement, replaceContent, htmlToDocumentFragment, setInnerHTML } from "../../helpers/dom";
import { getObjectKeysAndSort } from "../../helpers/object";
import { isTouchSupported } from "../../helpers/touchSupport";
import { logger } from "../../lib/logger";
@ -60,6 +59,14 @@ import findUpTag from "../../helpers/dom/findUpTag";
import { toast } from "../toast";
import { getElementByPoint } from "../../helpers/dom/getElementByPoint";
import { getMiddleware } from "../../helpers/middleware";
import { cancelEvent } from "../../helpers/dom/cancelEvent";
import { attachClickEvent } from "../../helpers/dom/clickEvent";
import htmlToDocumentFragment from "../../helpers/dom/htmlToDocumentFragment";
import positionElementByIndex from "../../helpers/dom/positionElementByIndex";
import reflowScrollableElement from "../../helpers/dom/reflowScrollableElement";
import replaceContent from "../../helpers/dom/replaceContent";
import setInnerHTML from "../../helpers/dom/setInnerHTML";
import whichChild from "../../helpers/dom/whichChild";
const USE_MEDIA_TAILS = false;
const IGNORE_ACTIONS: Message.messageService['action']['_'][] = [/* 'messageActionHistoryClear' */];
@ -97,7 +104,9 @@ export default class ChatBubbles {
private stickyIntersector: StickyIntersector;
private unreadedObserver: IntersectionObserver;
private unreaded: number[] = [];
private unreaded: Map<HTMLElement, number> = new Map();
private unreadedSeen: Set<number> = new Set();
private readPromise: Promise<void>;
public bubbleGroups: BubbleGroups;
@ -131,6 +140,7 @@ export default class ChatBubbles {
private needReflowScroll: boolean;
private fetchNewPromise: Promise<void>;
private historyStorage: HistoryStorage;
constructor(private chat: Chat, private appMessagesManager: AppMessagesManager, private appStickersManager: AppStickersManager, private appUsersManager: AppUsersManager, private appInlineBotsManager: AppInlineBotsManager, private appPhotosManager: AppPhotosManager, private appDocsManager: AppDocsManager, private appPeersManager: AppPeersManager, private appChatsManager: AppChatsManager, private storage: typeof sessionStorage) {
//this.chat.log.error('Bubbles construction');
@ -492,48 +502,13 @@ export default class ChatBubbles {
});
this.unreadedObserver = new IntersectionObserver((entries) => {
if(this.chat.appImManager.offline) { // ! but you can scroll the page without triggering 'focus', need something now
return;
}
const readed: number[] = [];
entries.forEach(entry => {
if(entry.isIntersecting) {
const target = entry.target as HTMLElement;
const mid = +target.dataset.mid;
readed.push(mid);
this.unreadedObserver.unobserve(target);
const mid = this.unreaded.get(target as HTMLElement);
this.onUnreadedInViewport(target, mid);
}
});
if(readed.length) {
let maxId = Math.max(...readed);
if(this.scrollable.loadedAll.bottom) {
const bubblesMaxId = Math.max(...Object.keys(this.bubbles).map(i => +i));
if(maxId >= bubblesMaxId) {
maxId = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId).maxId || maxId;
}
}
let length = readed.length;
for(let i = this.unreaded.length - 1; i >= 0; --i) {
if(this.unreaded[i] <= maxId) {
length++;
this.unreaded.splice(i, 1);
}
}
if(DEBUG) {
this.log('will readHistory by ids:', maxId, length);
}
/* false && */ this.appMessagesManager.readHistory(this.peerId, maxId, this.chat.threadId).catch((err: any) => {
this.log.error('readHistory err:', err);
this.appMessagesManager.readHistory(this.peerId, maxId, this.chat.threadId);
});
}
});
if('ResizeObserver' in window) {
@ -635,6 +610,55 @@ export default class ChatBubbles {
}
}
private onUnreadedInViewport(target: HTMLElement, mid: number) {
this.unreadedSeen.add(mid);
this.unreadedObserver.unobserve(target);
this.unreaded.delete(target);
this.readUnreaded();
}
private readUnreaded() {
if(this.readPromise) return;
const middleware = this.getMiddleware();
this.readPromise = rootScope.idle.focusPromise.then(() => {
if(!middleware()) return;
let maxId = Math.max(...Array.from(this.unreadedSeen));
// ? if message with maxId is not rendered ?
if(this.scrollable.loadedAll.bottom) {
const bubblesMaxId = Math.max(...Object.keys(this.bubbles).map(i => +i));
if(maxId >= bubblesMaxId) {
maxId = Math.max(this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId).maxId || 0, maxId);
}
}
this.unreaded.forEach((mid, target) => {
if(mid <= maxId) {
this.onUnreadedInViewport(target, mid);
}
});
this.unreadedSeen.clear();
if(DEBUG) {
this.log('will readHistory by maxId:', maxId);
}
return this.appMessagesManager.readHistory(this.peerId, maxId, this.chat.threadId).catch((err: any) => {
this.log.error('readHistory err:', err);
this.appMessagesManager.readHistory(this.peerId, maxId, this.chat.threadId);
}).finally(() => {
if(!middleware()) return;
this.readPromise = undefined;
if(this.unreadedSeen.size) {
this.readUnreaded();
}
});
});
}
public constructPinnedHelpers() {
this.listenerSetter.add(rootScope, 'peer_pinned_messages', (e) => {
const {peerId, mids, pinned} = e;
@ -1170,6 +1194,7 @@ export default class ChatBubbles {
this.bubbleGroups.removeBubble(bubble);
if(this.unreadedObserver) {
this.unreadedObserver.unobserve(bubble);
this.unreaded.delete(bubble);
}
//this.unreaded.findAndSplice(mid => mid === id);
bubble.remove();
@ -1409,7 +1434,9 @@ export default class ChatBubbles {
if(this.unreadedObserver) {
this.unreadedObserver.disconnect();
this.unreaded.length = 0;
this.unreaded.clear();
this.unreadedSeen.clear();
this.readPromise = undefined;
}
this.loadedTopTimes = this.loadedBottomTimes = 0;
@ -1435,8 +1462,8 @@ export default class ChatBubbles {
return {cached: true, promise: this.chat.setPeerPromise};
} */
const historyStorage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);
let topMessage = this.chat.type === 'pinned' ? this.appMessagesManager.pinnedMessages[peerId].maxId : historyStorage.maxId ?? 0;
this.historyStorage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);
let topMessage = this.chat.type === 'pinned' ? this.appMessagesManager.pinnedMessages[peerId].maxId : this.historyStorage.maxId ?? 0;
const isTarget = lastMsgId !== undefined;
// * this one will fix topMessage for null message in history (e.g. channel comments with only 1 comment and it is a topMessage)
@ -1491,7 +1518,7 @@ export default class ChatBubbles {
}
if(DEBUG) {
this.log('setPeer peerId:', this.peerId, historyStorage, lastMsgId, topMessage);
this.log('setPeer peerId:', this.peerId, this.historyStorage, lastMsgId, topMessage);
}
// add last message, bc in getHistory will load < max_id
@ -1666,7 +1693,11 @@ export default class ChatBubbles {
});
};
f();
if(samePeer) {
setTimeout(f, 30e3);
} else {
f();
}
}
});
}
@ -1674,7 +1705,7 @@ export default class ChatBubbles {
this.log('scrolledAllDown:', this.scrollable.loadedAll.bottom);
//if(!this.unreaded.length && dialog) { // lol
if(this.scrollable.loadedAll.bottom && topMessage) { // lol
if(this.scrollable.loadedAll.bottom && topMessage && !this.unreaded.size) { // lol
this.onScrolledAllDown();
}
@ -1874,13 +1905,12 @@ export default class ChatBubbles {
contentWrapper.appendChild(bubbleContainer);
bubble.appendChild(contentWrapper);
if(!our && !message.pFlags.out) {
if(!our && !message.pFlags.out && this.unreadedObserver) {
//this.log('not our message', message, message.pFlags.unread);
if(message.pFlags.unread && this.unreadedObserver) {
const isUnread = message.pFlags.unread || (this.historyStorage.readMaxId !== undefined && this.historyStorage.readMaxId < message.mid);
if(isUnread) {
this.unreadedObserver.observe(bubble);
if(!this.unreaded.indexOf(message.mid)) {
this.unreaded.push(message.mid);
}
this.unreaded.set(bubble, message.mid);
}
}
} else {

View File

@ -10,7 +10,6 @@ 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, isSelectionEmpty } from "../../helpers/dom";
import ButtonMenu, { ButtonMenuItemOptions } from "../buttonMenu";
import { attachContextMenuListener, openBtnMenu, positionMenu } from "../misc";
import PopupDeleteMessages from "../popups/deleteMessages";
@ -21,6 +20,10 @@ import PopupSendNow from "../popups/sendNow";
import { toast } from "../toast";
import I18n, { LangPackKey } from "../../lib/langPack";
import findUpClassName from "../../helpers/dom/findUpClassName";
import { cancelEvent } from "../../helpers/dom/cancelEvent";
import cancelSelection from "../../helpers/dom/cancelSelection";
import { attachClickEvent } from "../../helpers/dom/clickEvent";
import isSelectionEmpty from "../../helpers/dom/isSelectionEmpty";
export default class ChatContextMenu {
private buttons: (ButtonMenuItemOptions & {verify: () => boolean, notDirect?: () => boolean, withSelection?: true})[];

View File

@ -4,7 +4,7 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { generatePathData } from "../../helpers/dom";
import generatePathData from "../../helpers/generatePathData";
import { i18n, LangPackKey } from "../../lib/langPack";
export default class ChatDragAndDrop {
@ -90,4 +90,4 @@ export default class ChatDragAndDrop {
const d = generatePathData(pos, pos, sizeX, sizeY, radius, radius, radius, radius);
this.path.setAttributeNS(null, 'd', d);
}
}
}

View File

@ -20,7 +20,6 @@ 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, getRichValue, isInputEmpty, markdownTags, MarkdownType, placeCaretAtEnd, isSendShortcutPressed } from "../../helpers/dom";
import { ButtonMenuItemOptions } from '../buttonMenu';
import emoticonsDropdown from "../emoticonsDropdown";
import PopupCreatePoll from "../popups/createPoll";
@ -48,6 +47,14 @@ import { i18n } from '../../lib/langPack';
import { generateTail } from './bubbles';
import findUpClassName from '../../helpers/dom/findUpClassName';
import ButtonCorner from '../buttonCorner';
import blurActiveElement from '../../helpers/dom/blurActiveElement';
import { cancelEvent } from '../../helpers/dom/cancelEvent';
import cancelSelection from '../../helpers/dom/cancelSelection';
import { attachClickEvent } from '../../helpers/dom/clickEvent';
import getRichValue, { MarkdownType, markdownTags } from '../../helpers/dom/getRichValue';
import isInputEmpty from '../../helpers/dom/isInputEmpty';
import isSendShortcutPressed from '../../helpers/dom/isSendShortcutPressed';
import placeCaretAtEnd from '../../helpers/dom/placeCaretAtEnd';
const RECORD_MIN_TIME = 500;
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';

View File

@ -5,7 +5,6 @@
*/
import type { AppImManager } from "../../lib/appManagers/appImManager";
import { MarkdownType, cancelEvent, getSelectedNodes, markdownTags, attachClickEvent, isSelectionEmpty } from "../../helpers/dom";
import RichTextProcessor from "../../lib/richtextprocessor";
import ButtonIcon from "../buttonIcon";
import { clamp } from "../../helpers/number";
@ -13,6 +12,11 @@ import { isTouchSupported } from "../../helpers/touchSupport";
import { isApple, isMobile } from "../../helpers/userAgent";
import appNavigationController from "../appNavigationController";
import { _i18n } from "../../lib/langPack";
import { cancelEvent } from "../../helpers/dom/cancelEvent";
import { attachClickEvent } from "../../helpers/dom/clickEvent";
import { MarkdownType, markdownTags } from "../../helpers/dom/getRichValue";
import getSelectedNodes from "../../helpers/dom/getSelectedNodes";
import isSelectionEmpty from "../../helpers/dom/isSelectionEmpty";
//import { logger } from "../../lib/logger";
export default class MarkupTooltip {

View File

@ -7,10 +7,11 @@
import type Chat from "./chat";
import type ChatTopbar from "./topbar";
import mediaSizes from "../../helpers/mediaSizes";
import { attachClickEvent, cancelEvent } from "../../helpers/dom";
import DivAndCaption from "../divAndCaption";
import { ripple } from "../ripple";
import ListenerSetter from "../../helpers/listenerSetter";
import { cancelEvent } from "../../helpers/dom/cancelEvent";
import { attachClickEvent } from "../../helpers/dom/clickEvent";
//const classNames: string[] = [];
const classNames: string[] = ['is-pinned-message-shown', 'is-pinned-audio-shown'];

View File

@ -12,13 +12,15 @@ import PinnedContainer from "./pinnedContainer";
import PinnedMessageBorder from "./pinnedMessageBorder";
import ReplyContainer, { wrapReplyDivAndCaption } from "./replyContainer";
import rootScope from "../../lib/rootScope";
import { attachClickEvent, cancelEvent, handleScrollSideEvent } from "../../helpers/dom";
import Chat from "./chat";
import ListenerSetter from "../../helpers/listenerSetter";
import ButtonIcon from "../buttonIcon";
import { debounce } from "../../helpers/schedulers";
import { getHeavyAnimationPromise } from "../../hooks/useHeavyAnimationCheck";
import { i18n } from "../../lib/langPack";
import { cancelEvent } from "../../helpers/dom/cancelEvent";
import { attachClickEvent } from "../../helpers/dom/clickEvent";
import handleScrollSideEvent from "../../helpers/dom/handleScrollSideEvent";
class AnimatedSuper {
static DURATION = 200;

View File

@ -5,13 +5,14 @@
*/
import type ChatTopbar from "./topbar";
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";
import { cancelEvent } from "../../helpers/dom/cancelEvent";
import whichChild from "../../helpers/dom/whichChild";
export default class ChatSearch {
private element: HTMLElement;

View File

@ -9,7 +9,6 @@ import type ChatBubbles from "./bubbles";
import type ChatInput from "./input";
import type Chat from "./chat";
import { isTouchSupported } from "../../helpers/touchSupport";
import { blurActiveElement, cancelEvent, cancelSelection, getSelectedText } from "../../helpers/dom";
import Button from "../button";
import ButtonIcon from "../buttonIcon";
import CheckboxField from "../checkboxField";
@ -23,6 +22,10 @@ import appNavigationController from "../appNavigationController";
import { isMobileSafari } from "../../helpers/userAgent";
import I18n, { i18n, _i18n } from "../../lib/langPack";
import findUpClassName from "../../helpers/dom/findUpClassName";
import blurActiveElement from "../../helpers/dom/blurActiveElement";
import { cancelEvent } from "../../helpers/dom/cancelEvent";
import cancelSelection from "../../helpers/dom/cancelSelection";
import getSelectedText from "../../helpers/dom/getSelectedText";
const MAX_SELECTION_LENGTH = 100;
//const MIN_CLICK_MOVE = 32; // minimum bubble height

View File

@ -4,7 +4,7 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { cancelEvent } from "../../helpers/dom";
import { cancelEvent } from "../../helpers/dom/cancelEvent";
import ListenerSetter from "../../helpers/listenerSetter";
import rootScope from "../../lib/rootScope";
import ButtonMenu, { ButtonMenuItemOptions } from "../buttonMenu";

View File

@ -10,7 +10,6 @@ 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 { cancelEvent, attachClickEvent, blurActiveElement, replaceContent } from "../../helpers/dom";
import mediaSizes, { ScreenSize } from "../../helpers/mediaSizes";
import { isSafari } from "../../helpers/userAgent";
import rootScope from "../../lib/rootScope";
@ -31,6 +30,9 @@ import AppPrivateSearchTab from "../sidebarRight/tabs/search";
import PeerTitle from "../peerTitle";
import { i18n } from "../../lib/langPack";
import findUpClassName from "../../helpers/dom/findUpClassName";
import blurActiveElement from "../../helpers/dom/blurActiveElement";
import { cancelEvent } from "../../helpers/dom/cancelEvent";
import { attachClickEvent } from "../../helpers/dom/clickEvent";
export default class ChatTopbar {
container: HTMLDivElement;

View File

@ -8,7 +8,6 @@ import { isTouchSupported } from "../../helpers/touchSupport";
import appChatsManager from "../../lib/appManagers/appChatsManager";
import appImManager from "../../lib/appManagers/appImManager";
import rootScope from "../../lib/rootScope";
import { attachClickEvent, blurActiveElement, whichChild } from "../../helpers/dom";
import animationIntersector from "../animationIntersector";
import { horizontalMenu } from "../horizontalMenu";
import LazyLoadQueue, { LazyLoadQueueIntersector } from "../lazyLoadQueue";
@ -25,6 +24,9 @@ import AppStickersTab from "../sidebarRight/tabs/stickers";
import findUpClassName from "../../helpers/dom/findUpClassName";
import findUpTag from "../../helpers/dom/findUpTag";
import ListenerSetter from "../../helpers/listenerSetter";
import blurActiveElement from "../../helpers/dom/blurActiveElement";
import { attachClickEvent } from "../../helpers/dom/clickEvent";
import whichChild from "../../helpers/dom/whichChild";
export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';

View File

@ -4,7 +4,6 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { calcImageInBox } from "../helpers/dom";
import appDocsManager, {MyDocument} from "../lib/appManagers/appDocsManager";
import { wrapVideo } from "./wrappers";
import { LazyLoadQueueRepeat2 } from "./lazyLoadQueue";
@ -12,6 +11,7 @@ import animationIntersector from "./animationIntersector";
import Scrollable from "./scrollable";
import { CancellablePromise, deferredPromise } from "../helpers/cancellablePromise";
import renderImageFromUrl from "../helpers/dom/renderImageFromUrl";
import calcImageInBox from "../helpers/calcImageInBox";
const width = 400;
const maxSingleWidth = width - 100;

View File

@ -4,13 +4,13 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
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";
import whichChild from "../helpers/dom/whichChild";
export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?: (id: number, tabContent: HTMLDivElement, animate: boolean) => void | boolean, onTransitionEnd?: () => void, transitionTime = 250, scrollableX?: ScrollableX) {
const selectTab = TransitionSlider(content, tabs || content.dataset.animation === 'tabs' ? 'tabs' : 'navigation', transitionTime, onTransitionEnd);

View File

@ -4,9 +4,9 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { getRichValue, isInputEmpty } from "../helpers/dom";
import getRichValue from "../helpers/dom/getRichValue";
import isInputEmpty from "../helpers/dom/isInputEmpty";
import { debounce } from "../helpers/schedulers";
import { checkRTL } from "../helpers/string";
import { i18n, LangPackKey, _i18n } from "../lib/langPack";
import RichTextProcessor from "../lib/richtextprocessor";

View File

@ -1,4 +1,11 @@
import { attachClickEvent, cancelEvent } from "../helpers/dom";
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { cancelEvent } from "../helpers/dom/cancelEvent";
import { attachClickEvent } from "../helpers/dom/clickEvent";
import { Config, LangPackDifference, LangPackString } from "../layer";
import I18n, { LangPackKey } from "../lib/langPack";
import apiManager from "../lib/mtproto/mtprotoworker";

View File

@ -6,7 +6,8 @@
import { MOUNT_CLASS_TO } from "../config/debug";
import Countries, { Country, PhoneCodesMain } from "../countries";
import { cancelEvent, CLICK_EVENT_NAME } from "../helpers/dom";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import { CLICK_EVENT_NAME } from "../helpers/dom/clickEvent";
import ListenerSetter from "../helpers/listenerSetter";
import mediaSizes from "../helpers/mediaSizes";
import { isTouchSupported } from "../helpers/touchSupport";

View File

@ -4,7 +4,7 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { cancelEvent } from "../helpers/dom";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import InputField, { InputFieldOptions } from "./inputField";
export default class PasswordInputField extends InputField {

View File

@ -7,8 +7,8 @@
import { MOUNT_CLASS_TO } from "../config/debug";
import appPeersManager from "../lib/appManagers/appPeersManager";
import rootScope from "../lib/rootScope";
import { replaceContent } from "../helpers/dom";
import { i18n } from "../lib/langPack";
import replaceContent from "../helpers/dom/replaceContent";
export type PeerTitleOptions = {
peerId: number,

View File

@ -11,7 +11,6 @@ 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, replaceContent } from "../helpers/dom";
import { ripple } from "./ripple";
import appSidebarRight from "./sidebarRight";
import AppPollResultsTab from "./sidebarRight/tabs/pollResults";
@ -19,6 +18,9 @@ import { i18n, LangPackKey } from "../lib/langPack";
import { fastRaf } from "../helpers/schedulers";
import SetTransition from "./singleTransition";
import findUpClassName from "../helpers/dom/findUpClassName";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import { attachClickEvent, detachClickEvent } from "../helpers/dom/clickEvent";
import replaceContent from "../helpers/dom/replaceContent";
let lineTotalLength = 0;
//const tailLength = 9;

View File

@ -7,7 +7,6 @@
import type { Poll } from "../../lib/appManagers/appPollsManager";
import type Chat from "../chat/chat";
import PopupElement from ".";
import { cancelEvent, getRichValue, isInputEmpty, whichChild } from "../../helpers/dom";
import CheckboxField from "../checkboxField";
import InputField from "../inputField";
import RadioField from "../radioField";
@ -16,6 +15,10 @@ import SendContextMenu from "../chat/sendContextMenu";
import { MessageEntity } from "../../layer";
import I18n, { _i18n, i18n } from "../../lib/langPack";
import findUpTag from "../../helpers/dom/findUpTag";
import { cancelEvent } from "../../helpers/dom/cancelEvent";
import getRichValue from "../../helpers/dom/getRichValue";
import isInputEmpty from "../../helpers/dom/isInputEmpty";
import whichChild from "../../helpers/dom/whichChild";
const MAX_LENGTH_QUESTION = 255;
const MAX_LENGTH_OPTION = 100;

View File

@ -5,12 +5,12 @@
*/
import rootScope from "../../lib/rootScope";
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";
import blurActiveElement from "../../helpers/dom/blurActiveElement";
export type PopupButton = {
text?: string,

View File

@ -5,7 +5,6 @@
*/
import type Chat from "../chat/chat";
import { calcImageInBox, placeCaretAtEnd, isSendShortcutPressed } from "../../helpers/dom";
import InputField from "../inputField";
import PopupElement from ".";
import Scrollable from "../scrollable";
@ -17,6 +16,9 @@ import { createPosterFromVideo, onVideoLoad } from "../../helpers/files";
import { MyDocument } from "../../lib/appManagers/appDocsManager";
import I18n, { i18n, LangPackKey } from "../../lib/langPack";
import appDownloadManager from "../../lib/appManagers/appDownloadManager";
import calcImageInBox from "../../helpers/calcImageInBox";
import isSendShortcutPressed from "../../helpers/dom/isSendShortcutPressed";
import placeCaretAtEnd from "../../helpers/dom/placeCaretAtEnd";
type SendFileParams = Partial<{
file: File,

View File

@ -12,13 +12,13 @@ import { wrapSticker } from "../wrappers";
import LazyLoadQueue from "../lazyLoadQueue";
import { putPreloader } from "../misc";
import animationIntersector from "../animationIntersector";
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";
import toggleDisability from "../../helpers/dom/toggleDisability";
const ANIMATION_GROUP = 'STICKERS-POPUP';

View File

@ -4,11 +4,13 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { isInDOM, cancelEvent, attachClickEvent } from "../helpers/dom";
import { CancellablePromise } from "../helpers/cancellablePromise";
import SetTransition from "./singleTransition";
import { fastRaf } from "../helpers/schedulers";
import { safeAssign } from "../helpers/object";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import { attachClickEvent } from "../helpers/dom/clickEvent";
import isInDOM from "../helpers/dom/isInDOM";
const TRANSITION_TIME = 200;

View File

@ -10,7 +10,7 @@ import { ripple } from "./ripple";
import { SliderSuperTab } from "./slider";
import RadioForm from "./radioForm";
import { i18n, LangPackKey } from "../lib/langPack";
import { replaceContent } from "../helpers/dom";
import replaceContent from "../helpers/dom/replaceContent";
export default class Row {
public container: HTMLElement;

View File

@ -8,7 +8,7 @@ import { isTouchSupported } from "../helpers/touchSupport";
import { logger, LogTypes } from "../lib/logger";
import fastSmoothScroll, { FocusDirection } from "../helpers/fastSmoothScroll";
import useHeavyAnimationCheck from "../hooks/useHeavyAnimationCheck";
import { cancelEvent } from "../helpers/dom";
import { cancelEvent } from "../helpers/dom/cancelEvent";
/*
var el = $0;
var height = 0;

View File

@ -34,7 +34,6 @@ import appNavigationController from "../appNavigationController";
import findUpClassName from "../../helpers/dom/findUpClassName";
import findUpTag from "../../helpers/dom/findUpTag";
import PeerTitle from "../peerTitle";
import { replaceContent } from "../../helpers/dom";
import App from "../../config/app";
import ButtonMenuToggle from "../buttonMenuToggle";
@ -607,3 +606,7 @@ export const generateSection = (appendTo: Scrollable, name?: LangPackKey, captio
const appSidebarLeft = new AppSidebarLeft();
MOUNT_CLASS_TO.appSidebarLeft = appSidebarLeft;
export default appSidebarLeft;
function replaceContent(div: HTMLDivElement, title: HTMLElement) {
throw new Error("Function not implemented.");
}

View File

@ -11,13 +11,15 @@ import Button from "../../../button";
import { SliderSuperTab } from "../../../slider";
import { wrapSticker } from "../../../wrappers";
import InputField from "../../../inputField";
import { attachClickEvent, cancelEvent, canFocus } from "../../../../helpers/dom";
import { putPreloader } from "../../../misc";
import passwordManager from "../../../../lib/mtproto/passwordManager";
import AppTwoStepVerificationSetTab from "./passwordSet";
import AppTwoStepVerificationEmailConfirmationTab from "./emailConfirmation";
import RichTextProcessor from "../../../../lib/richtextprocessor";
import PopupPeer from "../../../popups/peer";
import { cancelEvent } from "../../../../helpers/dom/cancelEvent";
import { canFocus } from "../../../../helpers/dom/canFocus";
import { attachClickEvent } from "../../../../helpers/dom/clickEvent";
export default class AppTwoStepVerificationEmailTab extends SliderSuperTab {
public inputField: InputField;

View File

@ -10,13 +10,16 @@ import appStickersManager from "../../../../lib/appManagers/appStickersManager";
import Button from "../../../button";
import { SliderSuperTab } from "../../../slider";
import { wrapSticker } from "../../../wrappers";
import { attachClickEvent, canFocus, replaceContent, toggleDisability } from "../../../../helpers/dom";
import passwordManager from "../../../../lib/mtproto/passwordManager";
import AppTwoStepVerificationSetTab from "./passwordSet";
import CodeInputField from "../../../codeInputField";
import AppTwoStepVerificationEmailTab from "./email";
import { putPreloader } from "../../../misc";
import { i18n, _i18n } from "../../../../lib/langPack";
import { canFocus } from "../../../../helpers/dom/canFocus";
import { attachClickEvent } from "../../../../helpers/dom/clickEvent";
import replaceContent from "../../../../helpers/dom/replaceContent";
import toggleDisability from "../../../../helpers/dom/toggleDisability";
export default class AppTwoStepVerificationEmailConfirmationTab extends SliderSuperTab {
public codeInputField: CodeInputField;

View File

@ -6,7 +6,10 @@
import AppTwoStepVerificationTab from ".";
import { SettingSection } from "../..";
import { attachClickEvent, cancelEvent, canFocus, replaceContent } from "../../../../helpers/dom";
import { cancelEvent } from "../../../../helpers/dom/cancelEvent";
import { canFocus } from "../../../../helpers/dom/canFocus";
import { attachClickEvent } from "../../../../helpers/dom/clickEvent";
import replaceContent from "../../../../helpers/dom/replaceContent";
import { AccountPassword } from "../../../../layer";
import I18n, { i18n } from "../../../../lib/langPack";
import passwordManager from "../../../../lib/mtproto/passwordManager";

View File

@ -12,9 +12,10 @@ import { SliderSuperTab } from "../../../slider";
import { wrapSticker } from "../../../wrappers";
import InputField from "../../../inputField";
import AppTwoStepVerificationEmailTab from "./email";
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
import { toast } from "../../../toast";
import I18n from "../../../../lib/langPack";
import { cancelEvent } from "../../../../helpers/dom/cancelEvent";
import { attachClickEvent } from "../../../../helpers/dom/clickEvent";
export default class AppTwoStepVerificationHintTab extends SliderSuperTab {
public inputField: InputField;

View File

@ -5,7 +5,7 @@
*/
import { SettingSection } from "../..";
import { attachClickEvent } from "../../../../helpers/dom";
import { attachClickEvent } from "../../../../helpers/dom/clickEvent";
import { AccountPassword } from "../../../../layer";
import appStickersManager from "../../../../lib/appManagers/appStickersManager";
import { _i18n } from "../../../../lib/langPack";

View File

@ -5,7 +5,7 @@
*/
import { SettingSection } from "../..";
import { attachClickEvent } from "../../../../helpers/dom";
import { attachClickEvent } from "../../../../helpers/dom/clickEvent";
import appStickersManager from "../../../../lib/appManagers/appStickersManager";
import Button from "../../../button";
import { SliderSuperTab } from "../../../slider";

View File

@ -5,7 +5,6 @@
*/
import { SettingSection } from "../..";
import { attachClickEvent, cancelEvent } from "../../../../helpers/dom";
import { AccountPassword } from "../../../../layer";
import Button from "../../../button";
import PasswordInputField from "../../../passwordInputField";
@ -13,6 +12,8 @@ import { SliderSuperTab } from "../../../slider";
import TrackingMonkey from "../../../monkeys/tracking";
import AppTwoStepVerificationHintTab from "./hint";
import { InputState } from "../../../inputField";
import { cancelEvent } from "../../../../helpers/dom/cancelEvent";
import { attachClickEvent } from "../../../../helpers/dom/clickEvent";
export default class AppTwoStepVerificationReEnterPasswordTab extends SliderSuperTab {
public state: AccountPassword;

View File

@ -11,7 +11,6 @@ import Row from "../../row";
import { Authorization } from "../../../layer";
import { formatDateAccordingToToday } from "../../../helpers/date";
import { attachContextMenuListener, openBtnMenu, positionMenu } from "../../misc";
import { attachClickEvent, toggleDisability } from "../../../helpers/dom";
import ButtonMenu from "../../buttonMenu";
import apiManager from "../../../lib/mtproto/mtprotoworker";
import { toast } from "../../toast";
@ -19,6 +18,8 @@ import AppPrivacyAndSecurityTab from "./privacyAndSecurity";
import I18n from "../../../lib/langPack";
import PopupPeer from "../../popups/peer";
import findUpClassName from "../../../helpers/dom/findUpClassName";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
import toggleDisability from "../../../helpers/dom/toggleDisability";
export default class AppActiveSessionsTab extends SliderSuperTab {
public privacyTab: AppPrivacyAndSecurityTab;

View File

@ -8,7 +8,7 @@ import { generateSection } from "..";
import { averageColor } from "../../../helpers/averageColor";
import blur from "../../../helpers/blur";
import { deferredPromise } from "../../../helpers/cancellablePromise";
import { attachClickEvent } from "../../../helpers/dom";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
import findUpClassName from "../../../helpers/dom/findUpClassName";
import { requestFile } from "../../../helpers/files";
import highlightningColor from "../../../helpers/highlightningColor";

View File

@ -1,6 +1,5 @@
import { SettingSection } from "..";
import { hexaToRgba } from "../../../helpers/color";
import { attachClickEvent } from "../../../helpers/dom";
import findUpClassName from "../../../helpers/dom/findUpClassName";
import highlightningColor from "../../../helpers/highlightningColor";
import { throttle } from "../../../helpers/schedulers";
@ -143,3 +142,7 @@ export default class AppBackgroundColorTab extends SliderSuperTab {
return super.onCloseAfterTimeout();
}
}
function attachClickEvent(grid: HTMLDivElement, arg1: (e: any) => void, arg2: { listenerSetter: import("../../../helpers/listenerSetter").default; }) {
throw new Error("Function not implemented.");
}

View File

@ -7,7 +7,6 @@
import { SliderSuperTab } from "../../slider";
import { SettingSection } from "..";
import { attachContextMenuListener, openBtnMenu, positionMenu } from "../../misc";
import { attachClickEvent } from "../../../helpers/dom";
import ButtonMenu from "../../buttonMenu";
import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
import appUsersManager from "../../../lib/appManagers/appUsersManager";
@ -157,3 +156,7 @@ export default class AppBlockedUsersTab extends SliderSuperTab {
return super.onCloseAfterTimeout();
}
}
function attachClickEvent(btnAdd: HTMLButtonElement, arg1: (e: any) => void, arg2: { listenerSetter: import("../../../helpers/listenerSetter").default; }) {
throw new Error("Function not implemented.");
}

View File

@ -7,7 +7,6 @@
import { SliderSuperTab } from "../../slider";
import lottieLoader, { RLottiePlayer } from "../../../lib/lottieLoader";
import { RichTextProcessor } from "../../../lib/richtextprocessor";
import { attachClickEvent, cancelEvent, positionElementByIndex } from "../../../helpers/dom";
import { toast } from "../../toast";
import type { MyDialogFilter } from "../../../lib/storages/filters";
import type { DialogFilterSuggested, DialogFilter } from "../../../layer";
@ -22,6 +21,9 @@ import AppEditFolderTab from "./editFolder";
import Row from "../../row";
import { SettingSection } from "..";
import { i18n, i18n_, LangPackKey, join } from "../../../lib/langPack";
import { cancelEvent } from "../../../helpers/dom/cancelEvent";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
import positionElementByIndex from "../../../helpers/dom/positionElementByIndex";
export default class AppChatFoldersTab extends SliderSuperTab {
private createFolderBtn: HTMLElement;

View File

@ -10,8 +10,8 @@ import appUsersManager from "../../../lib/appManagers/appUsersManager";
import appPhotosManager from "../../../lib/appManagers/appPhotosManager";
import rootScope from "../../../lib/rootScope";
import InputSearch from "../../inputSearch";
import { canFocus } from "../../../helpers/dom";
import { isMobile } from "../../../helpers/userAgent";
import { canFocus } from "../../../helpers/dom/canFocus";
// TODO: поиск по людям глобальный, если не нашло в контактах никого

View File

@ -8,7 +8,6 @@ import { deepEqual, copy } from "../../../helpers/object";
import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
import { MyDialogFilter as DialogFilter } from "../../../lib/storages/filters";
import lottieLoader, { RLottiePlayer } from "../../../lib/lottieLoader";
import { ripple } from "../../ripple";
import { SliderSuperTab } from "../../slider";
import { toast } from "../../toast";
import appMessagesManager from "../../../lib/appManagers/appMessagesManager";

View File

@ -8,10 +8,10 @@ import appProfileManager from "../../../lib/appManagers/appProfileManager";
import appUsersManager from "../../../lib/appManagers/appUsersManager";
import InputField from "../../inputField";
import { SliderSuperTab } from "../../slider";
import { attachClickEvent } from "../../../helpers/dom";
import EditPeer from "../../editPeer";
import { UsernameInputField } from "../../usernameInputField";
import { i18n, i18n_ } from "../../../lib/langPack";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
// TODO: аватарка не поменяется в этой вкладке после изменения почему-то (если поставить в другом клиенте, и потом тут проверить, для этого ещё вышел в чатлист)

View File

@ -14,9 +14,9 @@ import appStateManager from "../../../lib/appManagers/appStateManager";
import rootScope from "../../../lib/rootScope";
import { isApple } from "../../../helpers/userAgent";
import Row from "../../row";
import { attachClickEvent } from "../../../helpers/dom";
import AppBackgroundTab from "./background";
import { LangPackKey, _i18n } from "../../../lib/langPack";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
export class RangeSettingSelector {
public container: HTMLDivElement;

View File

@ -26,7 +26,7 @@ import appUsersManager from "../../../lib/appManagers/appUsersManager";
import rootScope from "../../../lib/rootScope";
import { convertKeyToInputKey } from "../../../helpers/string";
import { i18n, LangPackKey, _i18n } from "../../../lib/langPack";
import { replaceContent } from "../../../helpers/dom";
import replaceContent from "../../../helpers/dom/replaceContent";
export default class AppPrivacyAndSecurityTab extends SliderSuperTab {
private activeSessionsRow: Row;

View File

@ -5,7 +5,6 @@
*/
import { copyTextToClipboard } from "../../../helpers/clipboard";
import { attachClickEvent, toggleDisability } from "../../../helpers/dom";
import { randomLong } from "../../../helpers/random";
import { Chat, ChatFull, ExportedChatInvite } from "../../../layer";
import appChatsManager from "../../../lib/appManagers/appChatsManager";
@ -21,6 +20,8 @@ import { SliderSuperTabEventable } from "../../sliderTab";
import I18n from "../../../lib/langPack";
import PopupPeer from "../../popups/peer";
import ButtonCorner from "../../buttonCorner";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
import toggleDisability from "../../../helpers/dom/toggleDisability";
export default class AppChatTypeTab extends SliderSuperTabEventable {
public chatId: number;

View File

@ -12,7 +12,6 @@ import Row from "../../row";
import Button from "../../button";
import appChatsManager, { ChatRights } from "../../../lib/appManagers/appChatsManager";
import appProfileManager from "../../../lib/appManagers/appProfileManager";
import { attachClickEvent, toggleDisability } from "../../../helpers/dom";
import { Chat } from "../../../layer";
import AppChatTypeTab from "./chatType";
import rootScope from "../../../lib/rootScope";
@ -21,6 +20,8 @@ import { i18n, LangPackKey } from "../../../lib/langPack";
import PopupDeleteDialog from "../../popups/deleteDialog";
import { addCancelButton } from "../../popups";
import PopupPeer from "../../popups/peer";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
import toggleDisability from "../../../helpers/dom/toggleDisability";
export default class AppEditChatTab extends SliderSuperTab {
private chatNameInputField: InputField;

View File

@ -11,7 +11,6 @@ import { SettingSection } from "../../sidebarLeft";
import Row from "../../row";
import CheckboxField from "../../checkboxField";
import Button from "../../button";
import { attachClickEvent, toggleDisability } from "../../../helpers/dom";
import appUsersManager from "../../../lib/appManagers/appUsersManager";
import appNotificationsManager from "../../../lib/appManagers/appNotificationsManager";
import PeerTitle from "../../peerTitle";
@ -21,6 +20,8 @@ import appPeersManager from "../../../lib/appManagers/appPeersManager";
import PopupPeer from "../../popups/peer";
import { addCancelButton } from "../../popups";
import { i18n } from "../../../lib/langPack";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
import toggleDisability from "../../../helpers/dom/toggleDisability";
export default class AppEditContactTab extends SliderSuperTab {
private nameInputField: InputField;

View File

@ -11,11 +11,11 @@ import appSidebarRight from "..";
import appUsersManager from "../../../lib/appManagers/appUsersManager";
import appInlineBotsManager, { AppInlineBotsManager } from "../../../lib/appManagers/appInlineBotsManager";
import GifsMasonry from "../../gifsMasonry";
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";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
const ANIMATIONGROUP = 'GIFS-SEARCH';

View File

@ -4,8 +4,9 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { attachClickEvent, replaceContent } from "../../../helpers/dom";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
import findUpTag from "../../../helpers/dom/findUpTag";
import replaceContent from "../../../helpers/dom/replaceContent";
import ListenerSetter from "../../../helpers/listenerSetter";
import ScrollableLoader from "../../../helpers/listLoader";
import { ChannelParticipant, Chat, ChatBannedRights, Update } from "../../../layer";

View File

@ -15,7 +15,6 @@ import AppSearchSuper, { SearchSuperType } from "../../appSearchSuper.";
import AvatarElement, { openAvatarViewer } from "../../avatar";
import SidebarSlider, { SliderSuperTab } from "../../slider";
import CheckboxField from "../../checkboxField";
import { attachClickEvent, replaceContent, cancelEvent } from "../../../helpers/dom";
import appSidebarRight from "..";
import { TransitionSlider } from "../../transition";
import appNotificationsManager from "../../../lib/appManagers/appNotificationsManager";
@ -46,6 +45,9 @@ import { isTouchSupported } from "../../../helpers/touchSupport";
import { isFirefox } from "../../../helpers/userAgent";
import appDownloadManager from "../../../lib/appManagers/appDownloadManager";
import ButtonCorner from "../../buttonCorner";
import { cancelEvent } from "../../../helpers/dom/cancelEvent";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
import replaceContent from "../../../helpers/dom/replaceContent";
let setText = (text: string, row: Row) => {
//fastRaf(() => {

View File

@ -7,7 +7,6 @@
import { SliderSuperTab } from "../../slider";
import InputSearch from "../../inputSearch";
import LazyLoadQueue from "../../lazyLoadQueue";
import { attachClickEvent } from "../../../helpers/dom";
import appImManager from "../../../lib/appManagers/appImManager";
import appStickersManager from "../../../lib/appManagers/appStickersManager";
import PopupStickers from "../../popups/stickers";
@ -19,6 +18,7 @@ import { StickerSet, StickerSetCovered } from "../../../layer";
import { forEachReverse } from "../../../helpers/array";
import { i18n } from "../../../lib/langPack";
import findUpClassName from "../../../helpers/dom/findUpClassName";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
export default class AppStickersTab extends SliderSuperTab {
private inputSearch: InputSearch;

View File

@ -4,16 +4,14 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { attachClickEvent, toggleDisability } from "../../../helpers/dom";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
import toggleDisability from "../../../helpers/dom/toggleDisability";
import { deepEqual } from "../../../helpers/object";
import { ChannelParticipant } from "../../../layer";
import appChatsManager from "../../../lib/appManagers/appChatsManager";
import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
import appPeersManager from "../../../lib/appManagers/appPeersManager";
import appUsersManager from "../../../lib/appManagers/appUsersManager";
import Button from "../../button";
import { addCancelButton } from "../../popups";
import PopupPeer from "../../popups/peer";
import { SettingSection } from "../../sidebarLeft";
import { SliderSuperTabEventable } from "../../sliderTab";
import { ChatPermissions } from "./groupPermissions";

View File

@ -4,12 +4,12 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { attachClickEvent } from "../helpers/dom";
import { horizontalMenu } from "./horizontalMenu";
import { TransitionSlider } from "./transition";
import appNavigationController, { NavigationItem } from "./appNavigationController";
import SliderSuperTab, { SliderSuperTabConstructable, SliderTab } from "./sliderTab";
import { safeAssign } from "../helpers/object";
import { attachClickEvent } from "../helpers/dom/clickEvent";
const TRANSITION_TIME = 250;

View File

@ -6,10 +6,12 @@
import type { LazyLoadQueueIntersector } from "./lazyLoadQueue";
import appDialogsManager, { DialogDom } from "../lib/appManagers/appDialogsManager";
import { isInDOM, positionElementByIndex, replaceContent } from "../helpers/dom";
import { getHeavyAnimationPromise } from "../hooks/useHeavyAnimationCheck";
import appUsersManager from "../lib/appManagers/appUsersManager";
import { insertInDescendSortedArray } from "../helpers/array";
import isInDOM from "../helpers/dom/isInDOM";
import positionElementByIndex from "../helpers/dom/positionElementByIndex";
import replaceContent from "../helpers/dom/replaceContent";
type SortedUser = {
peerId: number,

View File

@ -4,7 +4,7 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { cancelEvent } from "../helpers/dom";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import { safeAssign } from "../helpers/object";
import { isTouchSupported } from "../helpers/touchSupport";

View File

@ -4,10 +4,10 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { whichChild } from "../helpers/dom";
import rootScope from "../lib/rootScope";
import { CancellablePromise, deferredPromise } from "../helpers/cancellablePromise";
import { dispatchHeavyAnimationEvent } from "../hooks/useHeavyAnimationCheck";
import whichChild from "../helpers/dom/whichChild";
function slideNavigation(tabContent: HTMLElement, prevTabContent: HTMLElement, toRight: boolean) {
const width = prevTabContent.getBoundingClientRect().width;

View File

@ -17,7 +17,6 @@ import appDocsManager, { MyDocument } from "../lib/appManagers/appDocsManager";
import appMessagesManager from '../lib/appManagers/appMessagesManager';
import appPhotosManager, { MyPhoto } from '../lib/appManagers/appPhotosManager';
import LottieLoader from '../lib/lottieLoader';
import { attachClickEvent, cancelEvent, isInDOM } from "../helpers/dom";
import webpWorkerController from '../lib/webp/webpWorkerController';
import animationIntersector from './animationIntersector';
import appMediaPlaybackController from './appMediaPlaybackController';
@ -40,6 +39,9 @@ import sequentialDom from '../helpers/sequentialDom';
import { fastRaf } from '../helpers/schedulers';
import appDownloadManager from '../lib/appManagers/appDownloadManager';
import appStickersManager from '../lib/appManagers/appStickersManager';
import { cancelEvent } from '../helpers/dom/cancelEvent';
import { attachClickEvent } from '../helpers/dom/clickEvent';
import isInDOM from '../helpers/dom/isInDOM';
const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB

View File

@ -0,0 +1,45 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*
* Originally from:
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
import { MOUNT_CLASS_TO } from "../config/debug";
export default function calcImageInBox(imageW: number, imageH: number, boxW: number, boxH: number, noZoom = true) {
if(imageW < boxW && imageH < boxH && noZoom) {
return {w: imageW, h: imageH};
}
let boxedImageW = boxW;
let boxedImageH = boxH;
if((imageW / imageH) > (boxW / boxH)) {
boxedImageH = (imageH * boxW / imageW) | 0;
} else {
boxedImageW = (imageW * boxH / imageH) | 0;
if(boxedImageW > boxW) {
boxedImageH = (boxedImageH * boxW / boxedImageW) | 0;
boxedImageW = boxW;
}
}
// if (Config.Navigator.retina) {
// imageW = Math.floor(imageW / 2)
// imageH = Math.floor(imageH / 2)
// }
if(noZoom && boxedImageW >= imageW && boxedImageH >= imageH) {
boxedImageW = imageW;
boxedImageH = imageH;
}
return {w: boxedImageW, h: boxedImageH};
}
MOUNT_CLASS_TO.calcImageInBox = calcImageInBox;

View File

@ -9,30 +9,6 @@
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
import { MessageEntity } from "../layer";
import RichTextProcessor from "../lib/richtextprocessor";
import ListenerSetter from "./listenerSetter";
import { isTouchSupported } from "./touchSupport";
import { isApple, isMobile, isMobileSafari } from "./userAgent";
import rootScope from "../lib/rootScope";
import { MOUNT_CLASS_TO } from "../config/debug";
import { doubleRaf } from "./schedulers";
/* export function isInDOM(element: Element, parentNode?: HTMLElement): boolean {
if(!element) {
return false;
}
parentNode = parentNode || document.body;
if(element === parentNode) {
return true;
}
return isInDOM(element.parentNode as HTMLElement, parentNode);
} */
export function isInDOM(element: Element): boolean {
return element?.isConnected;
}
/* export function checkDragEvent(e: any) {
if(!e || e.target && (e.target.tagName === 'IMG' || e.target.tagName === 'A')) return false
if(e.dataTransfer && e.dataTransfer.types) {
@ -48,46 +24,6 @@ export function isInDOM(element: Element): boolean {
return false;
} */
export function cancelEvent(event: Event) {
event = event || window.event;
if(event) {
// @ts-ignore
event = event.originalEvent || event;
try {
if(event.stopPropagation) event.stopPropagation();
if(event.preventDefault) event.preventDefault();
event.returnValue = false;
event.cancelBubble = true;
} catch(err) {}
}
return false;
}
export function placeCaretAtEnd(el: HTMLElement) {
if(isTouchSupported) {
return;
}
el.focus();
if(typeof window.getSelection !== "undefined" && typeof document.createRange !== "undefined") {
var range = document.createRange();
range.selectNodeContents(el);
range.collapse(false);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
// @ts-ignore
} else if(typeof document.body.createTextRange !== "undefined") {
// @ts-ignore
var textRange = document.body.createTextRange();
textRange.moveToElementText(el);
textRange.collapse(false);
textRange.select();
}
}
/* export function getFieldSelection(field: any) {
if(field.selectionStart) {
return field.selectionStart;
@ -120,154 +56,6 @@ export function placeCaretAtEnd(el: HTMLElement) {
return len;
} */
export function getRichValue(field: HTMLElement, entities?: MessageEntity[]) {
if(!field) {
return '';
}
const lines: string[] = [];
const line: string[] = [];
getRichElementValue(field, lines, line, undefined, undefined, entities);
if(line.length) {
lines.push(line.join(''));
}
let value = lines.join('\n');
value = value.replace(/\u00A0/g, ' ');
if(entities) {
RichTextProcessor.combineSameEntities(entities);
}
//console.log('getRichValue:', value, entities);
return value;
}
MOUNT_CLASS_TO.getRichValue = getRichValue;
export type MarkdownType = 'bold' | 'italic' | 'underline' | 'strikethrough' | 'monospace' | 'link';
export type MarkdownTag = {
match: string,
entityName: 'messageEntityBold' | 'messageEntityUnderline' | 'messageEntityItalic' | 'messageEntityPre' | 'messageEntityStrike' | 'messageEntityTextUrl';
};
export const markdownTags: {[type in MarkdownType]: MarkdownTag} = {
bold: {
match: '[style*="font-weight"], b',
entityName: 'messageEntityBold'
},
underline: {
match: '[style*="underline"], u',
entityName: 'messageEntityUnderline'
},
italic: {
match: '[style*="italic"], i',
entityName: 'messageEntityItalic'
},
monospace: {
match: '[style*="monospace"], [face="monospace"]',
entityName: 'messageEntityPre'
},
strikethrough: {
match: '[style*="line-through"], strike',
entityName: 'messageEntityStrike'
},
link: {
match: 'A',
entityName: 'messageEntityTextUrl'
}
};
export function getRichElementValue(node: HTMLElement, lines: string[], line: string[], selNode?: Node, selOffset?: number, entities?: MessageEntity[], offset = {offset: 0}) {
if(node.nodeType === 3) { // TEXT
if(selNode === node) {
const value = node.nodeValue;
line.push(value.substr(0, selOffset) + '\x01' + value.substr(selOffset));
} else {
const nodeValue = node.nodeValue;
line.push(nodeValue);
if(entities && nodeValue.trim()) {
if(node.parentNode) {
const parentElement = node.parentElement;
for(const type in markdownTags) {
const tag = markdownTags[type as MarkdownType];
const closest = parentElement.closest(tag.match + ', [contenteditable]');
if(closest && closest.getAttribute('contenteditable') === null) {
if(tag.entityName === 'messageEntityTextUrl') {
entities.push({
_: tag.entityName as any,
url: (parentElement as HTMLAnchorElement).href,
offset: offset.offset,
length: nodeValue.length
});
} else {
entities.push({
_: tag.entityName as any,
offset: offset.offset,
length: nodeValue.length
});
}
}
}
}
}
offset.offset += nodeValue.length;
}
return;
}
if(node.nodeType !== 1) { // NON-ELEMENT
return;
}
const isSelected = (selNode === node);
const isBlock = node.tagName === 'DIV' || node.tagName === 'P';
if(isBlock && line.length || node.tagName === 'BR') {
lines.push(line.join(''));
line.splice(0, line.length);
} else if(node.tagName === 'IMG') {
const alt = (node as HTMLImageElement).alt;
if(alt) {
line.push(alt);
offset.offset += alt.length;
}
}
if(isSelected && !selOffset) {
line.push('\x01');
}
let curChild = node.firstChild as HTMLElement;
while(curChild) {
getRichElementValue(curChild, lines, line, selNode, selOffset, entities, offset);
curChild = curChild.nextSibling as any;
}
if(isSelected && selOffset) {
line.push('\x01');
}
if(isBlock && line.length) {
lines.push(line.join(''));
line.splice(0, line.length);
}
}
export function isInputEmpty(element: HTMLElement) {
if(element.hasAttribute('contenteditable') || element.tagName !== 'INPUT') {
/* const value = element.innerText;
return !value.trim() && !serializeNodes(Array.from(element.childNodes)).trim(); */
return !getRichValue(element).trim();
} else {
return !(element as HTMLInputElement).value.trim();
}
}
/* export function serializeNodes(nodes: Node[]): string {
return nodes.reduce((str, child: any) => {
//console.log('childNode', str, child, typeof(child), typeof(child) === 'string', child.innerText);
@ -293,242 +81,6 @@ export function isInputEmpty(element: HTMLElement) {
}
} */
// generate a path's arc data parameter
// http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
var arcParameter = function(rx: number, ry: number, xAxisRotation: number, largeArcFlag: number, sweepFlag: number, x: number, y: number) {
return [rx, ',', ry, ' ',
xAxisRotation, ' ',
largeArcFlag, ',',
sweepFlag, ' ',
x, ',', y ].join('');
};
export function generatePathData(x: number, y: number, width: number, height: number, tl: number, tr: number, br: number, bl: number) {
const data: string[] = [];
// start point in top-middle of the rectangle
data.push('M' + (x + width / 2) + ',' + y);
// next we go to the right
data.push('H' + (x + width - tr));
if(tr > 0) {
// now we draw the arc in the top-right corner
data.push('A' + arcParameter(tr, tr, 0, 0, 1, (x + width), (y + tr)));
}
// next we go down
data.push('V' + (y + height - br));
if(br > 0) {
// now we draw the arc in the lower-right corner
data.push('A' + arcParameter(br, br, 0, 0, 1, (x + width - br), (y + height)));
}
// now we go to the left
data.push('H' + (x + bl));
if(bl > 0) {
// now we draw the arc in the lower-left corner
data.push('A' + arcParameter(bl, bl, 0, 0, 1, (x + 0), (y + height - bl)));
}
// next we go up
data.push('V' + (y + tl));
if(tl > 0) {
// now we draw the arc in the top-left corner
data.push('A' + arcParameter(tl, tl, 0, 0, 1, (x + tl), (y + 0)));
}
// and we close the path
data.push('Z');
return data.join(' ');
};
MOUNT_CLASS_TO.generatePathData = generatePathData;
export function whichChild(elem: Node) {
if(!elem.parentNode) {
return -1;
}
let i = 0;
// @ts-ignore
while((elem = elem.previousElementSibling) !== null) ++i;
return i;
};
export function fillPropertyValue(str: string) {
let splitted = str.split(' ');
if(splitted.length !== 4) {
if(!splitted[0]) splitted[0] = '0px';
for(let i = splitted.length; i < 4; ++i) {
splitted[i] = splitted[i % 2] || splitted[0] || '0px';
}
}
return splitted;
}
export function calcImageInBox(imageW: number, imageH: number, boxW: number, boxH: number, noZoom = true) {
if(imageW < boxW && imageH < boxH && noZoom) {
return {w: imageW, h: imageH};
}
let boxedImageW = boxW;
let boxedImageH = boxH;
if((imageW / imageH) > (boxW / boxH)) {
boxedImageH = (imageH * boxW / imageW) | 0;
} else {
boxedImageW = (imageW * boxH / imageH) | 0;
if(boxedImageW > boxW) {
boxedImageH = (boxedImageH * boxW / boxedImageW) | 0;
boxedImageW = boxW;
}
}
// if (Config.Navigator.retina) {
// imageW = Math.floor(imageW / 2)
// imageH = Math.floor(imageH / 2)
// }
if(noZoom && boxedImageW >= imageW && boxedImageH >= imageH) {
boxedImageW = imageW;
boxedImageH = imageH;
}
return {w: boxedImageW, h: boxedImageH};
}
MOUNT_CLASS_TO.calcImageInBox = calcImageInBox;
export function positionElementByIndex(element: HTMLElement, container: HTMLElement, pos: number, prevPos?: number) {
if(prevPos === undefined) {
prevPos = element.parentElement === container ? whichChild(element) : -1;
}
if(prevPos === pos) {
return false;
} else if(prevPos !== -1 && prevPos < pos) { // was higher
pos += 1;
}
if(container.childElementCount > pos) {
container.insertBefore(element, container.children[pos]);
} else {
container.append(element);
}
return true;
}
export function cancelSelection() {
if(window.getSelection) {
if(window.getSelection().empty) { // Chrome
window.getSelection().empty();
} else if(window.getSelection().removeAllRanges) { // Firefox
window.getSelection().removeAllRanges();
}
// @ts-ignore
} else if(document.selection) { // IE?
// @ts-ignore
document.selection.empty();
}
}
//(window as any).splitStringByLength = splitStringByLength;
export function getSelectedText(): string {
if(window.getSelection) {
return window.getSelection().toString();
// @ts-ignore
} else if(document.selection) {
// @ts-ignore
return document.selection.createRange().text;
}
return '';
}
export function blurActiveElement() {
if(document.activeElement && (document.activeElement as HTMLInputElement).blur) {
(document.activeElement as HTMLInputElement).blur();
return true;
}
return false;
}
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 = {}) => {
const add = options.listenerSetter ? options.listenerSetter.add.bind(options.listenerSetter, elem) : elem.addEventListener.bind(elem);
const remove = options.listenerSetter ? options.listenerSetter.removeManual.bind(options.listenerSetter, elem) : elem.removeEventListener.bind(elem);
options.touchMouseDown = true;
/* if(options.touchMouseDown && CLICK_EVENT_NAME === 'touchend') {
add('mousedown', callback, options);
} else if(CLICK_EVENT_NAME === 'touchend') {
const o = {...options, once: true};
const onTouchStart = (e: TouchEvent) => {
const onTouchMove = (e: TouchEvent) => {
remove('touchmove', onTouchMove, o);
remove('touchend', onTouchEnd, o);
};
const onTouchEnd = (e: TouchEvent) => {
remove('touchmove', onTouchMove, o);
callback(e);
if(options.once) {
remove('touchstart', onTouchStart);
}
};
add('touchend', onTouchEnd, o);
add('touchmove', onTouchMove, o);
};
add('touchstart', onTouchStart);
} else {
add(CLICK_EVENT_NAME, callback, options);
} */
add(CLICK_EVENT_NAME, callback, options);
};
export const detachClickEvent = (elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options?: AddEventListenerOptions) => {
if(CLICK_EVENT_NAME === 'touchend') {
elem.removeEventListener('touchstart', callback, options);
} else {
elem.removeEventListener(CLICK_EVENT_NAME, callback, options);
}
};
export const getSelectedNodes = () => {
const nodes: Node[] = [];
const selection = window.getSelection();
for(let i = 0; i < selection.rangeCount; ++i) {
const range = selection.getRangeAt(i);
let {startContainer, endContainer} = range;
if(endContainer.nodeType !== 3) endContainer = endContainer.firstChild;
while(startContainer && startContainer !== endContainer) {
nodes.push(startContainer.nodeType === 3 ? startContainer : startContainer.firstChild);
startContainer = startContainer.nextSibling;
}
if(nodes[nodes.length - 1] !== endContainer) {
nodes.push(endContainer);
}
}
// * filter null's due to <br>
return nodes.filter(node => !!node);
};
/* export const isSelectionSingle = (input: Element = document.activeElement) => {
const nodes = getSelectedNodes();
const parents = [...new Set(nodes.map(node => node.parentNode))];
@ -547,46 +99,6 @@ export const getSelectedNodes = () => {
return single;
}; */
export const handleScrollSideEvent = (elem: HTMLElement, side: 'top' | 'bottom', callback: () => void, listenerSetter: ListenerSetter) => {
if(isTouchSupported) {
let lastY: number;
const options = {passive: true};
listenerSetter.add(elem, 'touchstart', (e) => {
if(e.touches.length > 1) {
onTouchEnd();
return;
}
lastY = e.touches[0].clientY;
listenerSetter.add(elem, 'touchmove', onTouchMove, options);
listenerSetter.add(elem, 'touchend', onTouchEnd, options);
}, options);
const onTouchMove = (e: TouchEvent) => {
const clientY = e.touches[0].clientY;
const isDown = clientY < lastY;
if(side === 'bottom' && isDown) callback();
else if(side === 'top' && !isDown) callback();
lastY = clientY;
//alert('isDown: ' + !!isDown);
};
const onTouchEnd = () => {
listenerSetter.removeManual(elem, 'touchmove', onTouchMove, options);
listenerSetter.removeManual(elem, 'touchend', onTouchEnd, options);
};
} else {
listenerSetter.add(elem, 'wheel', (e) => {
const isDown = e.deltaY > 0;
//this.log('wheel', e, isDown);
if(side === 'bottom' && isDown) callback();
else if(side === 'top' && !isDown) callback();
}, {passive: true});
}
};
/* export function radiosHandleChange(inputs: HTMLInputElement[], onChange: (value: string) => void) {
inputs.forEach(input => {
input.addEventListener('change', () => {
@ -597,105 +109,4 @@ export const handleScrollSideEvent = (elem: HTMLElement, side: 'top' | 'bottom',
});
} */
export function isSendShortcutPressed(e: KeyboardEvent) {
if(e.key === 'Enter' && !isMobile && !e.isComposing) {
/* if(e.ctrlKey || e.metaKey) {
this.messageInput.innerHTML += '<br>';
placeCaretAtEnd(this.message)
return;
} */
if(rootScope.settings.sendShortcut === 'enter') {
if(e.shiftKey || e.ctrlKey || e.metaKey) {
return;
}
return true;
} else {
const secondaryKey = isApple ? e.metaKey : e.ctrlKey;
if(e.shiftKey || (isApple ? e.ctrlKey : e.metaKey)) {
return;
}
if(secondaryKey) {
return true;
}
}
}
return false;
}
export function reflowScrollableElement(element: HTMLElement) {
element.style.display = 'none';
void element.offsetLeft; // reflow
element.style.display = '';
}
export function isSelectionEmpty(selection = window.getSelection()) {
if(!selection || !selection.rangeCount) {
return true;
}
const selectionRange = selection.getRangeAt(0);
if(!selectionRange.toString() || !selectionRange.START_TO_END) {
return true;
}
return false;
}
export function disableTransition(elements: HTMLElement[]) {
elements.forEach(el => el.classList.add('no-transition'));
doubleRaf().then(() => {
elements.forEach(el => el.classList.remove('no-transition'));
});
}
export function toggleDisability(elements: HTMLElement[], disable: boolean) {
if(disable) {
elements.forEach(el => el.setAttribute('disabled', 'true'));
} else {
elements.forEach(el => el.removeAttribute('disabled'));
}
return () => toggleDisability(elements, !disable);
}
export function canFocus(isFirstInput: boolean) {
return !isMobileSafari || !isFirstInput;
}
export function htmlToDocumentFragment(html: string) {
var template = document.createElement('template');
html = html.trim(); // Never return a text node of whitespace as the result
template.innerHTML = html;
return template.content;
}
export function htmlToSpan(html: string) {
const span = document.createElement('span');
span.innerHTML = html;
return span;
}
export function replaceContent(elem: HTMLElement, node: string | Node) {
// * children.length doesn't count text nodes
const firstChild = elem.firstChild;
if(firstChild) {
if(elem.lastChild === firstChild) {
firstChild.replaceWith(node);
} else {
elem.textContent = '';
elem.append(node);
}
} else {
elem.append(node);
}
}
export function setInnerHTML(elem: HTMLElement, html: string) {
elem.setAttribute('dir', 'auto');
elem.innerHTML = html;
}
export default {};

View File

@ -0,0 +1,14 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function blurActiveElement() {
if(document.activeElement && (document.activeElement as HTMLInputElement).blur) {
(document.activeElement as HTMLInputElement).blur();
return true;
}
return false;
}

View File

@ -0,0 +1,11 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { isMobileSafari } from "../userAgent";
export function canFocus(isFirstInput: boolean) {
return !isMobileSafari || !isFirstInput;
}

View File

@ -0,0 +1,27 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*
* Originally from:
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
export function cancelEvent(event: Event) {
event = event || window.event;
if(event) {
// @ts-ignore
event = event.originalEvent || event;
try {
if(event.stopPropagation) event.stopPropagation();
if(event.preventDefault) event.preventDefault();
event.returnValue = false;
event.cancelBubble = true;
} catch(err) {}
}
return false;
}

View File

@ -0,0 +1,19 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function cancelSelection() {
if(window.getSelection) {
if(window.getSelection().empty) { // Chrome
window.getSelection().empty();
} else if(window.getSelection().removeAllRanges) { // Firefox
window.getSelection().removeAllRanges();
}
// @ts-ignore
} else if(document.selection) { // IE?
// @ts-ignore
document.selection.empty();
}
}

View File

@ -0,0 +1,53 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import type ListenerSetter from "../listenerSetter";
import { isTouchSupported } from "../touchSupport";
export const CLICK_EVENT_NAME: 'mousedown' | 'touchend' | 'click' = (isTouchSupported ? 'mousedown' : 'click') as any;
export type AttachClickOptions = AddEventListenerOptions & Partial<{listenerSetter: ListenerSetter, touchMouseDown: true}>;
export function attachClickEvent(elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options: AttachClickOptions = {}) {
const add = options.listenerSetter ? options.listenerSetter.add.bind(options.listenerSetter, elem) : elem.addEventListener.bind(elem);
const remove = options.listenerSetter ? options.listenerSetter.removeManual.bind(options.listenerSetter, elem) : elem.removeEventListener.bind(elem);
options.touchMouseDown = true;
/* if(options.touchMouseDown && CLICK_EVENT_NAME === 'touchend') {
add('mousedown', callback, options);
} else if(CLICK_EVENT_NAME === 'touchend') {
const o = {...options, once: true};
const onTouchStart = (e: TouchEvent) => {
const onTouchMove = (e: TouchEvent) => {
remove('touchmove', onTouchMove, o);
remove('touchend', onTouchEnd, o);
};
const onTouchEnd = (e: TouchEvent) => {
remove('touchmove', onTouchMove, o);
callback(e);
if(options.once) {
remove('touchstart', onTouchStart);
}
};
add('touchend', onTouchEnd, o);
add('touchmove', onTouchMove, o);
};
add('touchstart', onTouchStart);
} else {
add(CLICK_EVENT_NAME, callback, options);
} */
add(CLICK_EVENT_NAME, callback, options);
}
export function detachClickEvent(elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options?: AddEventListenerOptions) {
if(CLICK_EVENT_NAME === 'touchend') {
elem.removeEventListener('touchstart', callback, options);
} else {
elem.removeEventListener(CLICK_EVENT_NAME, callback, options);
}
}

View File

@ -0,0 +1,15 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { doubleRaf } from "../schedulers";
export default function disableTransition(elements: HTMLElement[]) {
elements.forEach(el => el.classList.add('no-transition'));
doubleRaf().then(() => {
elements.forEach(el => el.classList.remove('no-transition'));
});
}

View File

@ -0,0 +1,152 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*
* Originally from:
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
import { MOUNT_CLASS_TO } from "../../config/debug";
import { MessageEntity } from "../../layer";
import RichTextProcessor from "../../lib/richtextprocessor";
export default function getRichValue(field: HTMLElement, entities?: MessageEntity[]) {
if(!field) {
return '';
}
const lines: string[] = [];
const line: string[] = [];
getRichElementValue(field, lines, line, undefined, undefined, entities);
if(line.length) {
lines.push(line.join(''));
}
let value = lines.join('\n');
value = value.replace(/\u00A0/g, ' ');
if(entities) {
RichTextProcessor.combineSameEntities(entities);
}
//console.log('getRichValue:', value, entities);
return value;
}
MOUNT_CLASS_TO.getRichValue = getRichValue;
export type MarkdownType = 'bold' | 'italic' | 'underline' | 'strikethrough' | 'monospace' | 'link';
export type MarkdownTag = {
match: string,
entityName: 'messageEntityBold' | 'messageEntityUnderline' | 'messageEntityItalic' | 'messageEntityPre' | 'messageEntityStrike' | 'messageEntityTextUrl';
};
export const markdownTags: {[type in MarkdownType]: MarkdownTag} = {
bold: {
match: '[style*="font-weight"], b',
entityName: 'messageEntityBold'
},
underline: {
match: '[style*="underline"], u',
entityName: 'messageEntityUnderline'
},
italic: {
match: '[style*="italic"], i',
entityName: 'messageEntityItalic'
},
monospace: {
match: '[style*="monospace"], [face="monospace"]',
entityName: 'messageEntityPre'
},
strikethrough: {
match: '[style*="line-through"], strike',
entityName: 'messageEntityStrike'
},
link: {
match: 'A',
entityName: 'messageEntityTextUrl'
}
};
function getRichElementValue(node: HTMLElement, lines: string[], line: string[], selNode?: Node, selOffset?: number, entities?: MessageEntity[], offset = {offset: 0}) {
if(node.nodeType === 3) { // TEXT
if(selNode === node) {
const value = node.nodeValue;
line.push(value.substr(0, selOffset) + '\x01' + value.substr(selOffset));
} else {
const nodeValue = node.nodeValue;
line.push(nodeValue);
if(entities && nodeValue.trim()) {
if(node.parentNode) {
const parentElement = node.parentElement;
for(const type in markdownTags) {
const tag = markdownTags[type as MarkdownType];
const closest = parentElement.closest(tag.match + ', [contenteditable]');
if(closest && closest.getAttribute('contenteditable') === null) {
if(tag.entityName === 'messageEntityTextUrl') {
entities.push({
_: tag.entityName as any,
url: (parentElement as HTMLAnchorElement).href,
offset: offset.offset,
length: nodeValue.length
});
} else {
entities.push({
_: tag.entityName as any,
offset: offset.offset,
length: nodeValue.length
});
}
}
}
}
}
offset.offset += nodeValue.length;
}
return;
}
if(node.nodeType !== 1) { // NON-ELEMENT
return;
}
const isSelected = (selNode === node);
const isBlock = node.tagName === 'DIV' || node.tagName === 'P';
if(isBlock && line.length || node.tagName === 'BR') {
lines.push(line.join(''));
line.splice(0, line.length);
} else if(node.tagName === 'IMG') {
const alt = (node as HTMLImageElement).alt;
if(alt) {
line.push(alt);
offset.offset += alt.length;
}
}
if(isSelected && !selOffset) {
line.push('\x01');
}
let curChild = node.firstChild as HTMLElement;
while(curChild) {
getRichElementValue(curChild, lines, line, selNode, selOffset, entities, offset);
curChild = curChild.nextSibling as any;
}
if(isSelected && selOffset) {
line.push('\x01');
}
if(isBlock && line.length) {
lines.push(line.join(''));
line.splice(0, line.length);
}
}

View File

@ -0,0 +1,27 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function getSelectedNodes() {
const nodes: Node[] = [];
const selection = window.getSelection();
for(let i = 0; i < selection.rangeCount; ++i) {
const range = selection.getRangeAt(i);
let {startContainer, endContainer} = range;
if(endContainer.nodeType !== 3) endContainer = endContainer.firstChild;
while(startContainer && startContainer !== endContainer) {
nodes.push(startContainer.nodeType === 3 ? startContainer : startContainer.firstChild);
startContainer = startContainer.nextSibling;
}
if(nodes[nodes.length - 1] !== endContainer) {
nodes.push(endContainer);
}
}
// * filter null's due to <br>
return nodes.filter(node => !!node);
}

View File

@ -0,0 +1,17 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function getSelectedText(): string {
if(window.getSelection) {
return window.getSelection().toString();
// @ts-ignore
} else if(document.selection) {
// @ts-ignore
return document.selection.createRange().text;
}
return '';
}

View File

@ -0,0 +1,48 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import type ListenerSetter from "../listenerSetter";
import { isTouchSupported } from "../touchSupport";
export default function handleScrollSideEvent(elem: HTMLElement, side: 'top' | 'bottom', callback: () => void, listenerSetter: ListenerSetter) {
if(isTouchSupported) {
let lastY: number;
const options = {passive: true};
listenerSetter.add(elem, 'touchstart', (e) => {
if(e.touches.length > 1) {
onTouchEnd();
return;
}
lastY = e.touches[0].clientY;
listenerSetter.add(elem, 'touchmove', onTouchMove, options);
listenerSetter.add(elem, 'touchend', onTouchEnd, options);
}, options);
const onTouchMove = (e: TouchEvent) => {
const clientY = e.touches[0].clientY;
const isDown = clientY < lastY;
if(side === 'bottom' && isDown) callback();
else if(side === 'top' && !isDown) callback();
lastY = clientY;
//alert('isDown: ' + !!isDown);
};
const onTouchEnd = () => {
listenerSetter.removeManual(elem, 'touchmove', onTouchMove, options);
listenerSetter.removeManual(elem, 'touchend', onTouchEnd, options);
};
} else {
listenerSetter.add(elem, 'wheel', (e) => {
const isDown = e.deltaY > 0;
//this.log('wheel', e, isDown);
if(side === 'bottom' && isDown) callback();
else if(side === 'top' && !isDown) callback();
}, {passive: true});
}
}

View File

@ -0,0 +1,12 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function htmlToDocumentFragment(html: string) {
var template = document.createElement('template');
html = html.trim(); // Never return a text node of whitespace as the result
template.innerHTML = html;
return template.content;
}

View File

@ -0,0 +1,11 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function htmlToSpan(html: string) {
const span = document.createElement('span');
span.innerHTML = html;
return span;
}

View File

@ -0,0 +1,25 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*
* Originally from:
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
/* export function isInDOM(element: Element, parentNode?: HTMLElement): boolean {
if(!element) {
return false;
}
parentNode = parentNode || document.body;
if(element === parentNode) {
return true;
}
return isInDOM(element.parentNode as HTMLElement, parentNode);
} */
export default function isInDOM(element: Element): boolean {
return element?.isConnected;
}

View File

@ -0,0 +1,18 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import getRichValue from "./getRichValue";
export default function isInputEmpty(element: HTMLElement) {
if(element.hasAttribute('contenteditable') || element.tagName !== 'INPUT') {
/* const value = element.innerText;
return !value.trim() && !serializeNodes(Array.from(element.childNodes)).trim(); */
return !getRichValue(element).trim();
} else {
return !(element as HTMLInputElement).value.trim();
}
}

View File

@ -0,0 +1,18 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function isSelectionEmpty(selection = window.getSelection()) {
if(!selection || !selection.rangeCount) {
return true;
}
const selectionRange = selection.getRangeAt(0);
if(!selectionRange.toString() || !selectionRange.START_TO_END) {
return true;
}
return false;
}

View File

@ -0,0 +1,37 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import rootScope from "../../lib/rootScope";
import { isMobile, isApple } from "../userAgent";
export default function isSendShortcutPressed(e: KeyboardEvent) {
if(e.key === 'Enter' && !isMobile && !e.isComposing) {
/* if(e.ctrlKey || e.metaKey) {
this.messageInput.innerHTML += '<br>';
placeCaretAtEnd(this.message)
return;
} */
if(rootScope.settings.sendShortcut === 'enter') {
if(e.shiftKey || e.ctrlKey || e.metaKey) {
return;
}
return true;
} else {
const secondaryKey = isApple ? e.metaKey : e.ctrlKey;
if(e.shiftKey || (isApple ? e.ctrlKey : e.metaKey)) {
return;
}
if(secondaryKey) {
return true;
}
}
}
return false;
}

View File

@ -0,0 +1,35 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*
* Originally from:
* https://github.com/zhukov/webogram
* Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>
* https://github.com/zhukov/webogram/blob/master/LICENSE
*/
import { isTouchSupported } from "../touchSupport";
export default function placeCaretAtEnd(el: HTMLElement) {
if(isTouchSupported) {
return;
}
el.focus();
if(typeof window.getSelection !== "undefined" && typeof document.createRange !== "undefined") {
var range = document.createRange();
range.selectNodeContents(el);
range.collapse(false);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
// @ts-ignore
} else if(typeof document.body.createTextRange !== "undefined") {
// @ts-ignore
var textRange = document.body.createTextRange();
textRange.moveToElementText(el);
textRange.collapse(false);
textRange.select();
}
}

View File

@ -0,0 +1,27 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import whichChild from "./whichChild";
export default function positionElementByIndex(element: HTMLElement, container: HTMLElement, pos: number, prevPos?: number) {
if(prevPos === undefined) {
prevPos = element.parentElement === container ? whichChild(element) : -1;
}
if(prevPos === pos) {
return false;
} else if(prevPos !== -1 && prevPos < pos) { // was higher
pos += 1;
}
if(container.childElementCount > pos) {
container.insertBefore(element, container.children[pos]);
} else {
container.append(element);
}
return true;
}

View File

@ -0,0 +1,11 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function reflowScrollableElement(element: HTMLElement) {
element.style.display = 'none';
void element.offsetLeft; // reflow
element.style.display = '';
}

View File

@ -0,0 +1,20 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function replaceContent(elem: HTMLElement, node: string | Node) {
// * children.length doesn't count text nodes
const firstChild = elem.firstChild;
if(firstChild) {
if(elem.lastChild === firstChild) {
firstChild.replaceWith(node);
} else {
elem.textContent = '';
elem.append(node);
}
} else {
elem.append(node);
}
}

View File

@ -0,0 +1,10 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function setInnerHTML(elem: HTMLElement, html: string) {
elem.setAttribute('dir', 'auto');
elem.innerHTML = html;
}

View File

@ -0,0 +1,15 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function toggleDisability(elements: HTMLElement[], disable: boolean) {
if(disable) {
elements.forEach(el => el.setAttribute('disabled', 'true'));
} else {
elements.forEach(el => el.removeAttribute('disabled'));
}
return () => toggleDisability(elements, !disable);
}

View File

@ -0,0 +1,16 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function whichChild(elem: Node) {
if(!elem.parentNode) {
return -1;
}
let i = 0;
// @ts-ignore
while((elem = elem.previousElementSibling) !== null) ++i;
return i;
}

View File

@ -10,7 +10,7 @@ import { dispatchHeavyAnimationEvent } from '../hooks/useHeavyAnimationCheck';
import { fastRaf } from './schedulers';
import { animateSingle, cancelAnimationByKey } from './animation';
import rootScope from '../lib/rootScope';
import { isInDOM } from './dom';
import isInDOM from './dom/isInDOM';
const MAX_DISTANCE = 1500;
const MIN_JS_DURATION = 250;

View File

@ -0,0 +1,17 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
export default function fillPropertyValue(str: string) {
let splitted = str.split(' ');
if(splitted.length !== 4) {
if(!splitted[0]) splitted[0] = '0px';
for(let i = splitted.length; i < 4; ++i) {
splitted[i] = splitted[i % 2] || splitted[0] || '0px';
}
}
return splitted;
}

View File

@ -0,0 +1,64 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
// generate a path's arc data parameter
import { MOUNT_CLASS_TO } from "../config/debug";
// http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
function arcParameter(rx: number, ry: number, xAxisRotation: number, largeArcFlag: number, sweepFlag: number, x: number, y: number) {
return [rx, ',', ry, ' ',
xAxisRotation, ' ',
largeArcFlag, ',',
sweepFlag, ' ',
x, ',', y ].join('');
}
export default function generatePathData(x: number, y: number, width: number, height: number, tl: number, tr: number, br: number, bl: number) {
const data: string[] = [];
// start point in top-middle of the rectangle
data.push('M' + (x + width / 2) + ',' + y);
// next we go to the right
data.push('H' + (x + width - tr));
if(tr > 0) {
// now we draw the arc in the top-right corner
data.push('A' + arcParameter(tr, tr, 0, 0, 1, (x + width), (y + tr)));
}
// next we go down
data.push('V' + (y + height - br));
if(br > 0) {
// now we draw the arc in the lower-right corner
data.push('A' + arcParameter(br, br, 0, 0, 1, (x + width - br), (y + height)));
}
// now we go to the left
data.push('H' + (x + bl));
if(bl > 0) {
// now we draw the arc in the lower-left corner
data.push('A' + arcParameter(bl, bl, 0, 0, 1, (x + 0), (y + height - bl)));
}
// next we go up
data.push('V' + (y + tl));
if(tl > 0) {
// now we draw the arc in the top-left corner
data.push('A' + arcParameter(tl, tl, 0, 0, 1, (x + tl), (y + 0)));
}
// and we close the path
data.push('Z');
return data.join(' ');
}
MOUNT_CLASS_TO.generatePathData = generatePathData;

View File

@ -1,7 +1,7 @@
import { fastRaf } from "./schedulers";
import { CancellablePromise, deferredPromise } from "./cancellablePromise";
import { isInDOM } from "./dom";
import { MOUNT_CLASS_TO } from "../config/debug";
import isInDOM from "./dom/isInDOM";
class SequentialDom {
private promises: Partial<{

View File

@ -5,6 +5,7 @@
*/
import App from './config/app';
import blurActiveElement from './helpers/dom/blurActiveElement';
import findUpClassName from './helpers/dom/findUpClassName';
import fixSafariStickyInput from './helpers/dom/fixSafariStickyInput';
import { isMobileSafari } from './helpers/userAgent';
@ -64,6 +65,8 @@ console.timeEnd('get storage1'); */
const vh = (setViewportVH && !rootScope.default.overlayIsActive ? w.height || w.innerHeight : window.innerHeight) * 0.01;
if(lastVH === vh) {
return;
} else if(lastVH < vh) {
blurActiveElement(); // (Android) fix blur when keyboard is being closed
}
lastVH = vh;

View File

@ -16,7 +16,6 @@ import { isSafari } from "../../helpers/userAgent";
import { logger, LogTypes } from "../logger";
import { RichTextProcessor } from "../richtextprocessor";
import rootScope from "../rootScope";
import { attachClickEvent, positionElementByIndex, replaceContent } from "../../helpers/dom";
import apiUpdatesManager from "./apiUpdatesManager";
import appPeersManager from './appPeersManager';
import appImManager from "./appImManager";
@ -40,6 +39,9 @@ import lottieLoader from "../lottieLoader";
import { wrapLocalSticker } from "../../components/wrappers";
import AppEditFolderTab from "../../components/sidebarLeft/tabs/editFolder";
import appSidebarLeft from "../../components/sidebarLeft";
import { attachClickEvent } from "../../helpers/dom/clickEvent";
import positionElementByIndex from "../../helpers/dom/positionElementByIndex";
import replaceContent from "../../helpers/dom/replaceContent";
export type DialogDom = {
avatarEl: AvatarElement,

View File

@ -24,7 +24,6 @@ import appPhotosManager from './appPhotosManager';
import appProfileManager from './appProfileManager';
import appStickersManager from './appStickersManager';
import appWebPagesManager from './appWebPagesManager';
import { blurActiveElement, cancelEvent, disableTransition, placeCaretAtEnd, replaceContent, whichChild } from '../../helpers/dom';
import PopupNewMedia from '../../components/popups/newMedia';
import MarkupTooltip from '../../components/chat/markupTooltip';
import { isTouchSupported } from '../../helpers/touchSupport';
@ -51,6 +50,12 @@ import { getFilesFromEvent } from '../../helpers/files';
import PeerTitle from '../../components/peerTitle';
import PopupPeer from '../../components/popups/peer';
import { SliceEnd } from '../../helpers/slicedArray';
import blurActiveElement from '../../helpers/dom/blurActiveElement';
import { cancelEvent } from '../../helpers/dom/cancelEvent';
import disableTransition from '../../helpers/dom/disableTransition';
import placeCaretAtEnd from '../../helpers/dom/placeCaretAtEnd';
import replaceContent from '../../helpers/dom/replaceContent';
import whichChild from '../../helpers/dom/whichChild';
//console.log('appImManager included33!');

Some files were not shown because too many files have changed in this diff Show More