tweb/public/15.1a3e11966cccf1381885.chu...

1 line
2.1 MiB
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{"version":3,"sources":["webpack:///./src/components/monkeys/tracking.ts","webpack:///./src/components/codeInputField.ts","webpack:///./src/environment/movSupport.ts","webpack:///./src/environment/mediaMimeTypesSupport.ts","webpack:///./src/helpers/dom/setInnerHTML.ts","webpack:///./src/helpers/filterChatPhotosMessages.ts","webpack:///./src/helpers/listLoader.ts","webpack:///./src/helpers/searchListLoader.ts","webpack:///./src/components/appSearch.ts","webpack:///./src/components/inputSearch.ts","webpack:///./src/components/buttonIcon.ts","webpack:///./src/components/sliderTab.ts","webpack:///./src/components/slider.ts","webpack:///./src/components/avatarEdit.ts","webpack:///./src/components/buttonCorner.ts","webpack:///./src/components/sidebarLeft/tabs/newGroup.ts","webpack:///./src/components/appMediaPlaybackController.ts","webpack:///./src/helpers/dom/attachGrabListeners.ts","webpack:///./src/components/rangeSelector.ts","webpack:///./src/components/buttonMenu.ts","webpack:///./src/components/buttonMenuToggle.ts","webpack:///./src/lib/mediaPlayer.ts","webpack:///./src/helpers/schedulers/throttleWithRaf.ts","webpack:///./src/helpers/schedulers/throttleWith.ts","webpack:///./src/components/audio.ts","webpack:///./src/components/divAndCaption.ts","webpack:///./src/components/chat/replyContainer.ts","webpack:///./src/components/groupedLayout.ts","webpack:///./src/components/editPeer.ts","webpack:///./src/components/row.ts","webpack:///./src/components/radioForm.ts","webpack:///./src/helpers/clipboard.ts","webpack:///./src/components/radioField.ts","webpack:///./src/components/toast.ts","webpack:///./src/helpers/schedulers/debounce.ts","webpack:///./src/components/usernameInputField.ts","webpack:///./src/components/popups/peer.ts","webpack:///./src/components/sidebarRight/tabs/chatType.ts","webpack:///./src/helpers/scrollableLoader.ts","webpack:///./src/components/appSelectPeers.ts","webpack:///./src/components/popups/pickUser.ts","webpack:///./src/components/sidebarRight/tabs/userPermissions.ts","webpack:///./src/components/sidebarRight/tabs/groupPermissions.ts","webpack:///./src/components/popups/deleteDialog.ts","webpack:///./src/components/sidebarRight/tabs/editChat.ts","webpack:///./src/components/sidebarRight/tabs/editContact.ts","webpack:///./src/components/sidebarLeft/tabs/addMembers.ts","webpack:///./src/environment/parallaxSupport.ts","webpack:///./src/components/generateVerifiedIcon.ts","webpack:///./src/components/swipeHandler.ts","webpack:///./src/components/peerProfileAvatars.ts","webpack:///./src/components/peerProfile.ts","webpack:///./src/components/sidebarRight/tabs/sharedMedia.ts","webpack:///./src/components/sidebarRight/index.ts","webpack:///./src/components/sidebarRight/tabs/pollResults.ts","webpack:///./src/components/poll.ts","webpack:///./src/lib/appManagers/appStickersManager.ts","webpack:///./src/components/wrappers.ts","webpack:///./src/helpers/dom/positionElementByIndex.ts","webpack:///./src/helpers/sortedList.ts","webpack:///./src/components/sortedUserList.ts","webpack:///./src/helpers/dom/handleTabSwipe.ts","webpack:///./src/components/popups/forward.ts","webpack:///./src/components/popups/deleteMessages.ts","webpack:///./src/components/popups/sendNow.ts","webpack:///./src/helpers/dom/cancelSelection.ts","webpack:///./src/components/chat/selection.ts","webpack:///./src/helpers/dom/getSelectedText.ts","webpack:///./src/components/appSearchSuper..ts","webpack:///./src/lib/appManagers/appPrivacyManager.ts","webpack:///./src/components/privacySection.ts","webpack:///./src/components/sidebarLeft/tabs/privacy/phoneNumber.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/passwordSet.ts","webpack:///./src/helpers/dom/canFocus.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/emailConfirmation.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/email.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/hint.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/reEnterPassword.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/enterPassword.ts","webpack:///./src/components/sidebarLeft/tabs/2fa/index.ts","webpack:///./src/components/sidebarLeft/tabs/privacy/lastSeen.ts","webpack:///./src/components/sidebarLeft/tabs/privacy/profilePhoto.ts","webpack:///./src/components/sidebarLeft/tabs/privacy/forwardMessages.ts","webpack:///./src/components/sidebarLeft/tabs/privacy/addToGroups.ts","webpack:///./src/components/sidebarLeft/tabs/privacy/calls.ts","webpack:///./src/components/sidebarLeft/tabs/activeSessions.ts","webpack:///./src/components/sidebarLeft/tabs/blockedUsers.ts","webpack:///./src/components/sidebarLeft/tabs/privacyAndSecurity.ts","webpack:///./src/helpers/color.ts","webpack:///./src/helpers/highlightningColor.ts","webpack:///./src/components/colorPicker.ts","webpack:///./src/components/sidebarLeft/tabs/backgroundColor.ts","webpack:///./src/components/sidebarLeft/tabs/background.ts","webpack:///./src/helpers/averageColor.ts","webpack:///./src/components/popups/stickers.ts","webpack:///./src/components/sidebarLeft/tabs/generalSettings.ts","webpack:///./src/components/sidebarLeft/tabs/editProfile.ts","webpack:///./src/components/sidebarLeft/tabs/includedChats.ts","webpack:///./src/components/sidebarLeft/tabs/editFolder.ts","webpack:///./src/components/sidebarLeft/tabs/chatFolders.ts","webpack:///./src/components/sidebarLeft/tabs/notifications.ts","webpack:///./src/components/sidebarLeft/tabs/language.ts","webpack:///./src/components/sidebarLeft/tabs/settings.ts","webpack:///./src/components/sidebarLeft/tabs/newChannel.ts","webpack:///./src/components/popups/createContact.ts","webpack:///./src/components/sidebarLeft/tabs/contacts.ts","webpack:///./src/components/sidebarLeft/tabs/archivedTab.ts","webpack:///./src/components/sidebarLeft/index.ts","webpack:///./src/components/chat/bubbleGroups.ts","webpack:///./src/components/popups/datePicker.ts","webpack:///./src/components/stickyIntersector.ts","webpack:///./src/components/chat/replies.ts","webpack:///./src/components/chat/messageRender.ts","webpack:///./src/helpers/dom/getElementByPoint.ts","webpack:///./src/helpers/dom/reflowScrollableElement.ts","webpack:///./src/lib/appManagers/appEmojiManager.ts","webpack:///./src/components/emoticonsDropdown/tabs/emoji.ts","webpack:///./src/components/gifsMasonry.ts","webpack:///./src/components/emoticonsDropdown/tabs/gifs.ts","webpack:///./src/components/emoticonsDropdown/tabs/stickers.ts","webpack:///./src/lib/appManagers/appInlineBotsManager.ts","webpack:///./src/components/sidebarRight/tabs/gifs.ts","webpack:///./src/components/sidebarRight/tabs/stickers.ts","webpack:///./src/helpers/dropdownHover.ts","webpack:///./src/components/emoticonsDropdown/index.ts","webpack:///./src/components/chat/bubbles.ts","webpack:///./src/lib/mtproto/constants.ts","webpack:///./src/components/popups/unpinMessage.ts","webpack:///./src/helpers/dom/isSelectionEmpty.ts","webpack:///./src/components/popups/reportMessagesConfirm.ts","webpack:///./src/components/popups/reportMessages.ts","webpack:///./src/components/chat/contextMenu.ts","webpack:///./src/components/chat/sendContextMenu.ts","webpack:///./src/components/popups/createPoll.ts","webpack:///./src/components/popups/newMedia.ts","webpack:///./src/helpers/dom/attachListNavigation.ts","webpack:///./src/components/chat/autocompleteHelper.ts","webpack:///./src/components/chat/stickersHelper.ts","webpack:///./src/components/popups/schedule.ts","webpack:///./src/helpers/dom/getRichValueWithCaret.ts","webpack:///./src/components/chat/emojiHelper.ts","webpack:///./src/components/chat/autocompletePeerHelper.ts","webpack:///./src/components/chat/commandsHelper.ts","webpack:///./src/components/chat/autocompleteHelperController.ts","webpack:///./src/components/chat/mentionsHelper.ts","webpack:///./src/components/chat/replyKeyboard.ts","webpack:///./src/components/chat/inlineHelper.ts","webpack:///./src/components/chat/input.ts","webpack:///./src/helpers/dom/setRichFocus.ts","webpack:///./src/components/chat/pinnedContainer.ts","webpack:///./src/components/chat/audio.ts","webpack:///./src/components/chat/pinnedMessageBorder.ts","webpack:///./src/components/chat/pinnedMessage.ts","webpack:///./src/helpers/dom/handleScrollSideEvent.ts","webpack:///./src/components/chat/topbar.ts","webpack:///./src/components/sidebarRight/tabs/search.ts","webpack:///./src/components/chat/search.ts","webpack:///./src/components/chat/chat.ts","webpack:///./src/components/chat/markupTooltip.ts","webpack:///./src/helpers/dom/getSelectedNodes.ts","webpack:///./src/helpers/generatePathData.ts","webpack:///./src/components/chat/dragAndDrop.ts","webpack:///./src/helpers/dom/disableTransition.ts","webpack:///./src/lib/appManagers/internalLink.ts","webpack:///./src/components/popups/joinChatInvite.ts","webpack:///./src/lib/appManagers/appImManager.ts","webpack:///./src/components/appMediaViewerBase.ts","webpack:///./src/helpers/dom/getVisibleRect.ts","webpack:///./src/helpers/fillPropertyValue.ts","webpack:///./src/components/appMediaViewer.ts","webpack:///./src/helpers/avatarListLoader.ts","webpack:///./src/components/appMediaViewerAvatar.ts","webpack:///./src/components/avatar.ts","webpack:///./src/components/dialogsContextMenu.ts","webpack:///./src/lib/mtproto/connectionStatus.ts","webpack:///./src/components/sendingStatus.ts","webpack:///./src/components/connectionStatus.ts","webpack:///./src/lib/appManagers/appDialogsManager.ts","webpack:///./public/recorder.min.js","webpack:///./src/components/ripple.ts","webpack:///./src/helpers/dom/clickEvent.ts","webpack:///./src/components/button.ts","webpack:///./src/components/misc.ts","webpack:///./src/components/appNavigationController.ts","webpack:///./src/helpers/dom/dispatchEvent.ts","webpack:///./src/helpers/sequentialDom.ts","webpack:///./src/lib/mtproto/passwordManager.ts","webpack:///./src/components/passwordInputField.ts","webpack:///./src/components/monkeys/password.ts"],"names":["TrackingMonkey","inputField","size","max","needFrame","this","container","document","createElement","classList","add","input","addEventListener","playAnimation","e","value","length","animation","frame","Math","min","round","idleAnimation","stop","canvas","style","display","direction","setDirection","setSpeed","play","loadPromise","Promise","all","loadAnimationFromURL","loop","autoplay","width","height","then","waitForFirstFrame","_animation","currentFrame","pause","remove","CodeInputField","options","super","plainText","type","setAttribute","autocomplete","lastLength","setLabel","replace","slice","setValueSilently","onFill","canPlayType","MEDIA_MIME_TYPES_SUPPORTED","Set","setInnerHTML","elem","html","innerHTML","filterChatPhotosMessages","history","message","idx","arr","action","photo","splice","undefined","count","previous","next","reverse","loadCount","loadWhenLeft","loadedAllUp","loadedAllDown","loadedAll","current","loadPromiseUp","loadPromiseDown","dispatchJump","items","item","pop","push","shift","unshift","load","onJump","older","resolve","anchor","promise","loadMore","result","forEach","bind","processed","processItem","onLoadedMore","backLimit","maxId","mid","incrementMessageId","getSearch","searchContext","peerId","limit","inputFilter","_","next_rate","nextRate","filterMids","onHistoryDelete","msgs","shouldBeDeleted","has","filter","onEmptied","onHistoryMultiappend","obj","folderId","mids","sorted","Array","from","sort","a","b","targets","map","Boolean","onMessageSent","rootScope","storage","isScheduled","getScheduledMessagesStorage","getMessagesStorage","filterMessagesByInputFilter","context","useSearch","reset","removeEventListener","name","clearable","className","clickable","autonomous","onFound","list","createChatList","nameEl","append","setListClickListener","childElementCount","setActive","clear","searchInput","searchGroups","onSearch","minMsgId","loadedCount","foundCount","searchPromise","searchTimeout","query","listsContainer","threadId","scrollable","i","messages","setVirtualContainer","onChange","searchMore","onScrolledBottom","trim","window","setTimeout","focus","res","searchGroup","fromId","dialog","dom","addDialogNew","drawStatus","avatarSize","meAsSaved","listEl","dataset","setLastMessage","toggle","replaceContent","catch","err","console","error","placeholder","prevValue","timeout","onInput","clearTimeout","onClearClick","onClear","searchIcon","clearBtn","icon","slider","destroyable","_constructor","header","closeBtn","noRipple","title","content","addTab","listenerSetter","closeTab","args","init","selectTab","tabs","delete","removeAll","key","eventListener","dispatchEvent","cleanup","onCloseAfterTimeout","historyTabIds","canHideFirst","onCloseBtnClick","appNavigationController","findItemByType","navigationType","back","id","animate","isNavigation","closingId","onCloseTab","tab","_selectTab","Map","tabsContainer","sidebarEl","querySelector","querySelectorAll","el","get","onOpen","onOpenAfterTimeout","pushItem","onPop","canAnimate","findAndSplice","tabConstructor","preserveTab","removeTabFromHistory","find","t","getTab","removeByType","onClose","parentElement","open","getContext","clearRect","uploadAvatar","setTitle","avatarEdit","_upload","inputWrapper","groupNameInputField","label","maxLength","nextBtn","contains","disabled","createChat","userIds","chatId","inputFile","editPhoto","chatsContainer","userId","rippleEnabled","lastMessageSpan","getUserStatusString","textContent","SHOULD_USE_SAFARI_FIX","navigator","userAgent","match","appMediaPlaybackController","media","scheduled","mediaDetails","waitingMediaForLoad","waitingScheduledMediaForLoad","waitingDocumentsForLoad","_volume","_muted","_playbackRate","seekBackward","details","playingMedia","currentTime","seekOffset","seekForward","duration","seekTo","seekTime","onMediaDocumentLoad","doc","getDoc","docId","supportsStreaming","handleSafariStreamable","cacheContext","appDownloadManager","getCacheContext","src","url","set","onPlay","target","getMessageByMedia","verify","element","listLoader","jumpLength","findIndex","go","setTargets","setMedia","getMediaFromMessage","onPause","onEnded","isTrusted","paused","clean","s","playItem","getMedia","resolveWaitingForLoadMedia","lockedSwitchers","cssText","body","mediaSession","actions","seekbackward","seekforward","seekto","previoustrack","nexttrack","setActionHandler","warn","properties","_key","dispatchPlaybackParams","Object","defineProperties","volume","muted","playbackRate","autoload","pFlags","is_scheduled","media_unread","myId","readMessages","once","deferred","w","waitingStorage","downloadDoc","safariBuffering","artwork","isVoice","artist","thumbs","bytes","sizes","h","preloadPhoto","setNewMediadata","peerPhoto","getPeerPhoto","appAvatarsManager","loadAvatar","cached","getPeerTitle","format","attribute","attributes","file_name","performer","metadata","MediaMetadata","getScheduledMessageByPeer","getMessageByPeer","willBePlayedMedia","prev","addMedia","setSearchContext","wasPlaying","willBePlayed","toggleSwitchers","enabled","attachGrabListeners","onStart","onMove","onEnd","onMouseMove","event","x","pageX","y","pageY","onMouseUp","onMouseDown","button","onTouchMove","preventDefault","touches","clientX","clientY","isTouch","onTouchEnd","onTouchStart","passive","mousedown","events","withTransition","useTransform","vertical","scrub","rect","getBoundingClientRect","seek","setFilled","onScrub","filled","step","setProgress","stepStr","index","indexOf","decimals","_removeListeners","percents","transform","rectMax","offsetAxisValue","bottom","left","toFixed","ButtonMenuItem","text","onClick","ripple","regularText","checkboxField","checked","keepOpen","cancelEvent","buttons","ButtonMenuToggleHandler","openedMenu","asDiv","btnMenu","streamable","progressRAF","onLoadedData","r","requestAnimationFrame","cancelAnimationFrame","setLoadProgress","onTimeUpdate","onProgress","removeListeners","filledLoad","prepend","setSeekMax","setListeners","setHandlers","scrubTime","isSafariBuffering","buf","buffered","numRanges","nearestStart","end","start","onMuteClick","setVolume","d","volumeSvg","btn","firstElementChild","video","showControlsTimeout","hideControls","isShown","wrapper","controlsLocked","showControls","setHideTimeout","toggleControls","show","onFullScreen","webkitFullscreenElement","parentNode","insertBefore","appendChild","skin","stylePlayer","controls","progress","finally","initDuration","player","buildControls","timeDuration","insertAdjacentHTML","fullScreenButton","timeElapsed","String","toHHMMSS","volumeSelector","togglePlay","findUpClassName","relatedTarget","overlaysActive","good","code","toggleFullScreen","altKey","split","eventName","visible","rate","settingsButton","fullscreenElement","mozFullScreenElement","msFullscreenElement","webkitEnterFullscreen","enterFullscreen","isFullScreen","cancelFullScreen","mozCancelFullScreen","webkitCancelFullScreen","msExitFullscreen","requestFullscreen","mozRequestFullScreen","webkitRequestFullscreen","msRequestFullscreen","throttleWithRaf","fn","schedulerFn","waiting","_args","throttleWith","wrapVoiceMessage","audioEl","out","barHeightMax","mediaSizes","isMobile","svg","createElementNS","setAttributeNS","timeDiv","waveform","Uint8Array","valueCount","dataView","DataView","buffer","byteIndex","bitShift","getUint16","decodeWaveform","normValue","wfSize","barCount","maxValue","maxDelta","barX","sumI","bar_value","barWidth","rects","children","audio","lastIndex","ceil","node","throttledTimeUpdate","addAudioListener","readyPromise","mousemove","offsetX","MouseEvent","targetTouches","noop","constructDownloadPreloader","tryAgainOnFail","preloader","cancelable","construct","circle","totalLength","attr","findAudioTargets","justAudioSelector","selector","matches","elements","mediaItems","HTMLElement","withTime","voiceAsMusic","showSender","isRealVoice","isOutgoing","is_outgoing","uploading","durationStr","downloadDiv","onTypeLoad","descriptionEl","parts","audioPerformer","htmlToSpan","date","wrapSenderToPeer","titleEl","middleEllipsisEl","fontWeight","audioTitle","fileName","wrapSentTime","subtitleDiv","launched","progressLine","lastChild","replaceWith","wrapAudio","audioTimeDiv","onLoad","readyState","HAVE_CURRENT_DATA","onTypeDisconnect","getTimeStr","innerText","attach","noAutoDownload","imgs","wrapped","wrapPhoto","boxWidth","boxHeight","loadPromises","withoutPreloader","lazyLoadQueue","images","thumb","full","img","shouldPlay","onDownloadInit","pauseListener","notifyAll","done","total","cancel","Error","reject","playListener","download","setDownloadFunction","capture","isConnected","customElements","define","DivAndCaption","fill","border","subtitle","wrapReplyDivAndCaption","subtitleEl","mediaEl","wrapEmojiText","isRound","mediaChildren","middleware","wrapMessageForReply","webpage","chat","bubbles","getMiddleware","wrapSticker","div","group","CHAT_ANIMATION_GROUP","choosePhotoSize","noBlur","child","isMediaSet","RectPart","maxWidth","minWidth","spacing","maxHeight","ratios","countRatios","proportions","countProportions","averageRatio","maxSizeRatio","layout","layoutTwo","layoutThree","layoutFour","layoutTwoTopBottom","layoutTwoLeftRightEqual","layoutTwoLeftRight","layoutThreeLeftAndOther","layoutThreeTopAndOther","layoutFourTopAndOther","layoutFourLeftAndOther","geometry","sides","minimalWidth","secondWidth","firstWidth","firstHeight","thirdHeight","secondHeight","rightWidth","leftWidth","thirdWidth","h0","w0","w2","w1","h1","h2","ratio","join","cropRatios","attempts","multiHeight","offset","sum","pushAttempt","lineCounts","heights","first","second","third","fourth","optimalAttempt","optimalDiff","attempt","counts","lineCount","totalHeight","minLineHeight","bad1","bad2","line","diff","abs","optimalCounts","optimalHeights","rowCount","row","colCount","lineHeight","col","_disabled","isChanged","validLength","requiredLength","requiredValidLength","inputFields","isValid","required","handleChange","toggleAttribute","withoutAvatar","avatarElem","doNotEditAvatar","unlockOnSuccess","freezed","radioField","subtitleLangKey","subtitleLangArgs","havePadding","isToggle","titleRight","noCheckboxSubtitle","titleLangKey","c","navigationTab","RadioFormFromRows","rows","radios","form","RadioForm","copyTextToClipboard","clipboard","writeText","textArea","top","position","select","execCommand","removeChild","fallbackCopyTextToClipboard","stateKey","appStateManager","getState","state","setByKey","main","langKey","Event","toastEl","toast","toastNew","langPackKey","debounce","ms","shouldRunFirst","shouldRunLast","waitingTimeout","waitingPromise","hadNewCall","_resolve","_reject","checkUsernameDebounced","checkUsername","getValue","originalValue","setState","Neutral","isUsernameValid","setError","invalidText","head","username","checkUsernamePromise","invokeApi","channel","getChannelInput","available","Valid","availableText","takenText","overlayClosable","avatarEl","noTitle","titleLangArgs","fragment","createDocumentFragment","descriptionLangKey","description","p","descriptionLangArgs","checkboxes","o","withRipple","callback","original","nextElementSibling","isBroadcast","section","random","privateRow","publicRow","privateSection","publicSection","getChat","linkRow","chatFull","exported_invite","link","btnRevoke","toggleDisability","getChatInviteLink","caption","noDelimiter","changed","linkInputField","applyBtn","migrateChat","channelId","updateUsername","close","setOriginalValue","loading","loaded","getPromise","checkForTriggers","loadAllDialogsPromise","loadedAllDialogs","selected","offsetIndex","loadedWhat","renderedPeerIds","peerType","multiSelect","tempIds","selfPresence","needSwitchList","includes","cachedContacts","getMoreResults","f","renderResultsFunc","renderResults","peerIds","splitUp","notRendered","topContainer","selectedContainer","selectedScrollable","delimiter","li","click","findUpAttribute","checkbox","debouncedInput","appendTo","getResultsPromise","onFirstRender","testSelfSearch","dialogs","archived","pageCount","windowSize","windowH","tempId","getTempId","getConversations","newOffsetIndex","chatRightsAction","filterByRights","renderSaved","isEnd","getMoreDialogs","contacts","getMoreContacts","canSendToUser","hasRights","getContacts","searchContacts","searchResult","resultPeerIds","my_results","concat","results","channelParticipants","getChannelParticipants","q","participants","participant","getParticipantPeerId","u","promises","getConversationsAll","getMoreChannelParticipants","isNonContactUser","containerEl","getChatMembersString","scroll","insertAdjacentElement","scrollIntoViewNew","offsetWidth","onAnimationEnd","settings","animationsEnabled","values","Static","closable","getSelected","onSelect","hide","peerTypes","destroyListener","new","rights","takeOut","banned_rights","editBanned","btnDeleteException","clearChannelParticipantBannedRights","btnDelete","kickFromChannel","v","flags","exceptionText","toggleWith","defaultBannedRights","default_banned_rights","combineParticipantBannedRights","info","mainFlag","restriction","until_date","flag","chatPermissions","editChatDefaultBannedRights","addExceptionRow","openPermissions","getChannelParticipant","generateContentElement","findUpTag","setSubtitle","bannedRights","cantWhat","getPeerId","peer","update","needAdd","new_participant","view_messages","user_id","prev_participant","exceptionsCount","setLength","loader","setLoader","isChannel","migrateFrom","migrateTo","onScroll","getDialogType","peerTitleElement","callbackLeave","flush","leave","flushHistory","callbackDelete","descriptionArgs","deleteChannel","isDanger","textArgs","getChatFull","chatUpdateListeners","addChatUpdateListener","chatNameInputField","descriptionInputField","about","editPeer","chatTypeRow","setChatTypeSubtitle","permissionsRow","setPermissionsLength","reduce","acc","editTitle","editAbout","race","removeAttribute","signMessagesCheckboxField","signatures","toggleSignatures","showChatHistoryCheckboxField","togglePreHistoryHidden","onChatUpdate","hidden_prehistory","_init","isNew","isContact","nameInputField","lastNameInputField","user","getUser","setDraftValue","first_name","last_name","notificationsCheckboxField","mutePeer","isMuted","notify_settings","profileNameDiv","profileSubtitleDiv","phoneRow","phone","formatUserPhone","notificationsRow","isPeerLocalMuted","addContact","deleteContacts","skippable","attachToPromise","removeLoader","ret","selectedPeerIds","addInitial","generateVerifiedIcon","use","use2","getEvent","attachGlobalListenerTo","RESET_GLOBAL","cursor","hadMove","xDown","yDown","handleMove","onReset","handleStart","_e","verifyTouchTarget","xUp","yUp","xDiff","yDiff","setProperty","onFirstSwipe","onSwipeResult","onSwipe","photoId","avatar","BASE_CLASS","getPhoto","Image","draggable","renderImageFromUrl","putAvatar","avatars","gradient","arrowPrevious","arrowNext","checkScrollTop","scrollTop","freeze","clickX","prevTargets","nextTargets","openAvatarViewer","toRight","right","distance","offsetLeft","cancelNextClick","lastDiffX","minX","lastX","SCALE","TRANSLATE_TEMPLATE","addIndex","getUserPhotos","photos","Number","MAX_SAFE_INTEGER","m","chat_photo","generateFakeAvatarMessage","activeTab","photo_id","setText","setPeerStatus","needClear","bio","tagName","getProfileByPeerId","getPeer","notifications","generateDelimiter","setBio","self","setPeerStatusInterval","setInterval","setBioTimeout","oldAvatars","setPeer","cleaned","cleanupHTML","setAvatar","getPeerUsername","verified","override","getProfile","userFull","rAbout","wrapRichText","canSetNext","historiesStorage","newCloseBtn","animatedCloseIcon","transitionContainer","transitionFirstItem","editBtn","transitionLastItem","secondTitle","cloneNode","profile","onAdditionalScroll","searchSuper","nav","isSharedMedia","transition","cleanScrollPositions","isHeavyAnimationInProgress","toggleEditBtn","msgIdsByPeer","renderNewMessages","deleteDeletedMessages","mediaTabs","onChangeTab","mediaTab","btnAddMembers","showConfirmation","onError","inviteToChannel","addChatUser","filtered","filterMessagesByType","usedFromHistory","performSearchResult","selection","isSelecting","toggleByElement","canViewMembers","loadMutex","peerChanged","setQuery","historyStorage","fillProfileElements","single","justLoad","getElementById","isColumnProportionSet","to","medium","mobile","toggleSidebar","setColumnProportion","sharedMediaTab","proportion","scrollWidth","previousElementSibling","documentElement","enable","active","willChange","animationPromise","appSidebarRight","resultsDiv","poll","getPoll","quiz","rQuestion","voters","total_voters","roundPercents","hr","answer","answers","answerEl","answerTitle","answerPercents","minHeight","getVotes","option","votesList","votes","vote","showMore","lastElementChild","next_offset","down","lineTotalLength","minIndex","minRemainder","k","remainder","maxRemainder","pollElement","isClosed","closed","performResults","chosenIndexes","prevQuizHint","hideQuizHint","prevQuizHintOnHide","prevQuizHintTimeout","setMaxLength","resizePolls","onHide","isQuiz","isRetracted","isPublic","isMultiple","chosingIndexes","sentVote","windowW","MAX_LENGTH","MAX_OFFSET","svgLines","setLineProgress","getTotalLength","pollId","descKey","public_voters","multiple_choice","multipleSelect","descDiv","typeDiv","avatarsDiv","close_period","close_date","timeLeftDiv","quizTimer","strokeWidth","radius","circumference","PI","period","closeTime","serverTimeOffset","quizInterval","time","Date","now","timeLeft","color","stroke","strokeDashoffset","strokeDasharray","clearInterval","getResults","answerDivs","numberDivs","footerDiv","viewResults","votersCountDiv","isTabExists","sendVoteBtn","sendVotes","canVote","setVotersCount","clickHandler","solution","solution_entities","toggleHint","textEl","entities","bubblesContainer","setQuizHint","correctResult","correct","chosen","answerIndex","foundIndex","indexes","sendVotePromise","sendVote","initQuizHint","timeEl","setResults","recent_voters","isVoted","hideSendVoteBtn","hideViewResultsBtn","maxPercents","cb","getPercentValue","iterate","fullTime","times","votersCount","multiplier","getStickerSetPromises","getStickersByEmoticonsPromises","getAnimatedEmojiStickerSet","addMultipleEventsListeners","updateNewStickerSet","saveStickerSet","stickerset","getGreetingStickersTimeout","getGreetingSticker","justPreload","getGreetingStickersPromise","getStickersByEmoticon","docs","greetingStickers","saveDoc","params","overwrite","cachedSet","documents","refreshTime","useCache","saveStickers","stickerSet","getStickerSetInput","saveById","getStickerSet","invokeApiHashable","stickers","emoji","getFromCache","pack","packs","emoticon","getAnimatedEmojiSticker","newSet","assign","setToCache","needSave","installed_date","dcId","thumb_dc_id","isAnimated","animated","location","thumb_version","mimeType","access_hash","short_name","sets","covered","excludeFeatured","exclude_featured","foundSaved","cache","getCache","toLowerCase","cover","getAllStickers","allStickers","includeOurStickers","preloadStickerSets","getRecentStickers","messagesStickers","installedSets","recentStickers","foundStickers","sticker","cachedStickersAnimated","cachedStickersStatic","iteratePacks","appStickersManager","roundVideoCircumference","wrapVideo","withTail","isOut","noInfo","onlyPreview","noPlayButton","isAlbumItem","canAutoplay","autoPlay","gifs","videos","spanTime","spanPlay","needPlayButton","mime_type","photoRes","divRound","halfSize","ctx","globalVideo","setPeerPromise","isInDOM","onPaused","onFrame","drawImage","detached","foreignObject","getAttributeNS","gotThumb","getThumb","poster","aspecter","isUpload","downloaded","attachMethod","renderDeferred","detach","isFulfilled","animationIntersector","addAnimation","loadPhotoThumbFunc","loadFunc","setManual","queueId","render","wrapDocument","audioElement","extSplitted","ext","isArray","docDiv","icoDiv","descriptionParts","nameDiv","_downloadDiv","save","saveDocFile","downloading","noThumb","noFadeIn","blurAfter","setAttachmentSize","regular","thumbImage","image","isFit","loadThumbPromise","photoSize","getStrippedThumbIfNeeded","needFadeIn","renderOnLoad","renderImageWithFadeIn","canAttachPreloader","renderPromise","sequentialDom","mutateElement","mutate","onlyThumb","withThumb","stickerType","loadLottieWorkers","toneIndex","haveThumbCached","stickerCachedThumbs","afterRender","getPathFromPhotoPathSize","stickerThumbConverted","getPreviewURLFromThumb","webpWorkerController","convert","getThumbURL","json","loadAnimationWorker","animationData","saveLottiePreview","getAnimation","restart","wrapStickerSetThumb","downloadOptions","getStickerSetThumbDownloadOptions","lottieLoader","needUpscale","blob","URL","createObjectURL","wrapReply","replyContainer","prepareAlbum","widthItem","heightItem","borderTopLeftRadius","borderBottomLeftRadius","borderTopRightRadius","borderBottomRightRadius","forMedia","mediaDiv","wrapAlbum","groupId","attachmentDiv","getMidsByAlbum","getMessage","album","positionElementByIndex","pos","prevPos","whichChild","updateElementWith","updateListWith","onSort","canUpdate","_updateList","batch","updateBatch","base","onElementCreate","noScheduler","onDelete","getIndex","onUpdate","getUserStatusForSort","status","doTimeout","updateList","SORT_INTERVAL","handleTabSwipe","peerIdMids","overrideOnSelect","setInnerPeer","initMessagesForward","onConfirm","revoke","deleteScheduledMessages","deleteMessages","titleArgs","isMegagroup","canRevoke","sendScheduledMessages","cancelSelection","getSelection","empty","removeAllRanges","accumulateMapSet","selectedMids","onCancelSelection","toggleSelection","listenElement","selectedText","toString","createRange","verifyTouchLongPress","getElementFromTarget","getElementsBetween","last","firstRect","lastRect","isHigher","parent","lookupBetweenParentClassName","lookupBetweenElementsQuery","firstIndex","targetLookupClassName","verifyTarget","seen","selecting","firstTarget","processElement","checkBetween","seenSet","isSelected","isMidSelected","seenLength","findUpAsChild","elementsBetween","toggleByMid","canceledSelection","verifyMouseMoveTarget","removeManual","documentListenerOptions","hasCheckbox","getCheckboxInputFromElement","isElementShouldBeSelected","appendCheckbox","forceSelection","cantForward","cantDelete","cantSend","appMessagesManager","getMessageFromStorage","canDeleteMessage","onUpdateContainer","toggleCheckboxes","wasSelecting","blurActiveElement","forwards","onToggleSelection","updateContainer","toggleElementCheckbox","unselect","config","forwarded_count_max","toggleMid","updateElementSelection","contentTab","selectionCountEl","selectionGotoBtn","selectionForwardBtn","selectionDeleteBtn","navScrollableContainer","selectionContainer","btnCancel","attachClickOptions","keys","fromPeerId","isPrivate","transitionElement","opacity","recording","bubble","canSelectBubble","isGroupedBubbleSelected","getMidsByMid","getBubbleGroupedItems","groupContainer","isGroupedSelected","isGroupedMidsSelected","mounted","getMountedBubble","borderRadius","rowsWrapper","fakeSelectionWrapper","fakeRowsWrapper","fakeSelectionRect","fakeRowsRect","widthFrom","widthTo","scale","initTranslateX","br","selectionInputWrapper","selectionSendNowBtn","isGrouped","groupedCheckboxInput","attachTo","onGotoClick","onForwardClick","onSelectClick","onClearSelectionClick","onDeleteClick","onContextMenu","cancelBubble","withSelection","prevTabId","urlsToRevoke","nextRates","loadedChats","firstLoad","log","logger","monthContainers","mediaTabsMap","asChatList","groupByMonth","hideEmptyTabs","onTransitionStart","onTransitionEnd","searchContextMenu","navScrollable","tabsMenu","menuTab","span","prevId","searchGroupMedia","horizontalMenu","tabContent","skipScroll","newMediaTab","fromMediaTab","offsetTop","scrollHeight","rect2","onMediaClick","targetClassName","copySearchContext","openMedia","inputMessagesFilterPhotoVideo","inputMessagesFilterDocument","useHeavyAnimationCheck","lock","unlockAndRefresh","elemsToAppend","sharedMediaDiv","entity","totalEntities","display_url","sliced","matchUrl","same","hostname","rDescription","previewDiv","getAbbreviation","rTitle","subtitleFragment","htmlToDocumentFragment","HTMLAnchorElement","decodeURIComponent","href","firstChild","wrapPlainText","method","monthContainer","getMonthContainerByTimestamp","afterPerforming","inputMessagesFilterEmpty","showMembersCount","participants_count","regExp","RegExp","cleanSearchText","titleSpan","formatPhoneNumber","formatted","arg","globalContacts","isShort","minDate","renderRecentSearch","recent","recentSearch","getTopPeers","peers","people","onlyFirstName","renderParticipants","membersList","deleted","LOAD_COUNT","loadMembers","loadChats","logStr","used","slicedLength","ids","filters","counters","getSearchCounters","firstMediaTab","counter","membersTab","toLoad","loadType","timestamp","setHours","setDate","dateTimestamp","getTime","containers","month","getFullYear","year","dateElement","IntlDateElement","haveTimestamps","goFirst","revokeObjectURL","newInputFilter","maxDate","PrivacyType","appPrivacyManager","privacy","updatePrivacy","rules","inputKey","privacyRules","saveApiUsers","users","saveApiChats","chats","apiUpdatesManager","processLocalUpdate","inputRule","rule","privacyKey","types","allowPeers","disallowPeers","onRadioChange","captions","captionElement","radioSection","exceptions","Everybody","Nobody","radioRows","Contacts","skipTypes","noExceptions","generateSection","exceptionTexts","exception","_peerIds","newPeerIds","generateStr","splitPeersByType","getPrivacy","getPrivacyRulesDetails","setRadio","chatKey","usersKey","splitted","getUserInput","setPrivacy","phoneSection","nextSibling","stickerContainer","inputContent","btnReturn","sliceTabsUntilTab","canFocus","isFirstInput","isFirst","email","codeInputField","passwordManager","confirmPasswordEmail","goNext","btnChange","btnResend","disable","cancelPasswordEmail","resendPasswordEmail","onContinueClick","btnContinue","btnSkip","matchEmail","toggleButtons","updateSettings","hint","currentPassword","plainPassword","newPassword","symbols","isCancel","onSkipClick","saveHint","passwordInputField","monkey","verifyInput","has_password","labelText","IntlElement","getStateInterval","_state","check","auth","btnChangePassword","btnDisablePassword","btnSetRecoveryEmail","has_recovery","btnSetPassword","Session","app_name","app_version","ip","country","date_active","date_created","hash","midtitle","device_model","system_version","platform","authorizations","session","btnTerminate","otherSection","privacyTab","updateActiveSessions","onTerminateClick","menuElement","btnAdd","toggleBlock","bot","blocked","getBlocked","blockedPeerIds","blockedUsersRow","passwordState","twoFactorRow","email_unconfirmed_pattern","activeSessionsRow","setBlockedCount","updateBlocked","rowsByKeys","numberVisibilityRow","lastSeenTimeRow","photoVisibilityRow","callRow","linkAccountRow","groupChatsAddRow","updatePrivacyRow","disallowLength","allowLength","sensitive_can_change","sensitive_enabled","sensitiveRow","_enabled","deleteButton","clearAllDrafts","auths","rgbaToHsla","g","l","hslaToRgba","hue2rgb","hexaToRgba","hexa","parseInt","rgbaToHexa","rgba","hslaStringToHexa","hsla","alpha","val","endsWith","hslaStringToRgba","highlightningColor","hue","saturation","lightness","onGrabStart","boxDragger","onGrabEnd","box","sliders","hueDragger","hexInputField","rgbInputField","inputs","valid","setColor","rgbRegExp","attachBoxListeners","attachHueListeners","boxRect","saturationHandler","hueRect","hueHandler","updateHexInput","updateRgbInput","hexaToHsla","rgb","boxX","percentY","boxY","percentHue","hueX","updatePicker","rgbaArray","hex","hsl","getCurrentColor","maxX","maxY","posX","posY","lightnessX","lightnessY","_applyColor","updateColorPicker","colorPicker","background","theme","pushToState","applyCurrentTheme","onColorChange","applyColor","getTheme","grid","backgroundColor","throttle","uploadTempId","clicked","onUploadClick","file","dc_id","file_reference","wallpaper","slug","upload","addNotifyListener","_wallpaper","newDoc","newCacheContext","setBackgroundDocument","addWallPaper","onResetClick","defaultTheme","themes","blurCheckboxField","blur","onGridClick","saveToCache","fetch","response","cacheStorage","_tempId","onReady","imageUrl","naturalWidth","naturalHeight","pixel","pixels","getImageData","data","pixelsLength","outPixel","Uint8ClampedArray","averageColor","uploadButton","colorButton","resetButton","accountWallpapers","wallpapers","pattern","stickerSetInput","onStickersClick","fileId","sendMessageWithDocument","h6","setOnlyOnePlayableGroup","stickersDiv","stickersFooter","loadStickerSet","toggleStickerSet","esgSticker","initialValue","minValue","valueDiv","range","messagesTextSize","chatBackgroundButton","animationsCheckboxField","enterRow","ctrlEnterRow","contactsCheckboxField","privateCheckboxField","groupsCheckboxField","channelsCheckboxField","gifsCheckboxField","videosCheckboxField","suggestCheckboxField","bigCheckboxField","loopCheckboxField","stickerSets","renderStickerSet","assumeType","firstNameInputField","bioInputField","getSelf","usernameInputField","setProfileUrl","profileUrlContainer","profileUrlAnchor","updateProfile","uploadProfilePhoto","foundInFilters","dialogsByFilters","onSelectChange","confirmBtn","pinned_peers","other","editFolderTab","setFilter","filtersStorage","getDialogFilters","dialogsStorage","getFolder","categoriesSection","exclude_muted","ico","exclude_archived","exclude_read","non_contacts","groups","broadcasts","bots","chatsSection","selectedPeers","include_peers","exclude_peers","addedInitial","_add","hasOwnProperty","originalFilter","deleteFolderButton","updateDialogFilter","bool","menuBtn","generateList","h2Text","categories","includedFlagsContainer","excludedFlagsContainer","include","createDialogFilter","editCheckForChange","loadAnimationPromise","wrapDraftText","ul","renderMore","_length","firstTime","onEditOpen","onCreateOpen","filtersRendered","dialogFilter","folder","channels","isAnyGroup","filterId","getFilter","orderIndex","createFolderBtn","foldersSection","suggestedSection","onFiltersContainerUpdate","renderFolder","getSuggestedFilters","suggestedFilters","NotifySection","enabledRow","typeText","previewEnabledRow","inputNotifyPeer","getNotifySettings","notifySettings","applySettings","show_previews","mute","showPreviews","inputSettings","mute_until","updateNotifySettings","contactsSignUpRow","soundRow","sound","getContactSignUpNotification","setContactSignUpNotification","invokeApiCacheable","lang_pack","languages","language","lang_code","native_name","getLangPack","getCacheLangPack","langPack","logOut","phoneDiv","buttonsDiv","edit","folders","general","fillElements","channelNameInputField","channelDescriptionInputField","onLengthChange","createChannel","withConfirm","btnConfirm","importContact","telInputField","lockWithPromise","validate","country_code","inputSearch","openContacts","sortedUserList","createList","renderPage","sortedLists","chatList","generateScrollable","scrollables","wasFilterId","setFilterId","onTabChange","fakeGradientDelimiter","appSidebarLeft","sidebarHeader","onContactsClick","backBtn","btnArchive","themeCheckboxField","menuButtons","openUsername","sessionStorage","kz_version","isMainDomain","toolsBtn","btnMenuFooter","rel","stopPropagation","suffix","versionFull","newBtnMenu","initSearch","archivedCount","requestPeer","searchContainer","pickedElements","selectedPeerId","selectedMinDate","selectedMaxDate","updatePicked","removeProperty","helper","unselectEntity","renderEntity","dates","dateData","getAttribute","peopleContainer","hideNewBtnMenuTimeout","onFocus","clearRecentSearchBtn","detailsMap","newGroupDiff","updateGroup","viaBotId","fwdFromId","removeBubble","insertObject","foundBubble","foundAtIndex","foundMidOnSameTimestamp","_timestamp","_mid","bubbleGroup","insertIndex","initDate","onPick","noButtons","selectedDate","onPrevClick","selectedMonth","setMonth","getMonth","minMonth","prevBtn","onNextClick","maxMonth","onDateClick","selectedEl","setTimeTitle","setFullYear","getDate","controlsDiv","monthTitle","monthsContainer","handleTimeInput","onOverflow","maxString","hoursInputField","minutesInputField","number","setMinutes","getMinutes","getHours","popupCenterer","timeOptions","minute","hour","sendDate","dateOptions","day","weekday","firstDate","weekStartDate","getDay","renderElement","dayIndex","clonedDate","showOverflowMonths","lines","StickyIntersector","handler","observeHeaders","observeElements","headersObserver","IntersectionObserver","entries","entry","targetInfo","boundingClientRect","stickyTarget","rootBoundsInfo","rootBounds","threshold","root","elementsObserver","isIntersecting","sentinel","headerSentinel","addSentinel","observe","disconnect","unobserve","updated","postKey","replies","leftPart","recent_repliers","getHistoryStorage","channel_id","isUnread","read_max_id","max_id","readMaxId","textSpan","iconSpan","rippleContainer","subscribeRepliesThread","updateMessage","MessageRender","setTime","bubbleContainer","messageDiv","views","postAuthor","post_author","fwd_from","saved_from_msg_id","forward","edit_date","edit_hide","pinned","timeSpan","renderReplies","isFooter","repliesFooter","setReply","isReplacing","currentReplyDiv","reply_to_mid","replyToPeerId","reply_to","reply_to_peer_id","appPeersManager","originalPeerTitle","originalMessage","wrapSingleMessage","needUpdate","replyMid","getElementByPoint","verticalSide","horizontalSide","floor","elementFromPoint","reflowScrollableElement","EMOJI_LANG_PACK","keywords","version","langCode","langPackCode","keywordLangPacks","indexedLangPacks","getKeywordsPromises","storageKey","stateStorage","from_version","keywordsDifference","packKeywords","keyword","emoticons","getEmojiKeywords","lastRequestedLangCode","getRecentEmojis","indexObject","emojis","indexEmojis","search","POPULAR_EMOJI","getRecentEmojisPromise","recentEmoji","fixEmoji","appEmojiManager","loadedURLs","appendEmoji","unify","spanEmoji","kek","wrapSingleEmoji","getEmojiFromElement","nodeType","nodeValue","closeScrollTop","onContentClick","messageInput","inputHTML","inserted","savedRange","getSavedRange","sel","addRange","getRangeAt","rangeCount","deleteContents","insertNode","setStart","setStartAfter","collapse","divs","Emoji","category","titleDiv","itemsDiv","unified","menu","emojiScroll","hasRecent","activeId","menuOnClick","stickyIntersector","setMenuActive","recentItemsDiv","observeStickyHeaderChanges","scrollPromise","processInvisibleDiv","intersector","isVisible","getAnimations","checkAnimation","processVisibleDiv","gifWidth","gifHeight","willUseWidth","calcImageInBox","gifsContainer","masonry","EMOTICONSSTICKERGROUP","addLazyLoadQueueRepeat","regularLazyLoadQueue","animatedDivs","checkAnimationContainer","renderSticker","observeAnimatedDiv","queueCategoryPush","categoryDiv","categoryTitle","superStickerRenderer","recentDiv","categoryPush","menuWrapper","menuScroll","inlineResults","setHash","geo","lat","long","accuracy_radius","botId","getInputPeerById","geo_point","getGeoInput","stopTime","noErrorBox","botResults","queryId","query_id","savePhoto","generateQId","resultId","topPeers","topPeer","rating","setKeyValueToStorage","startParam","startBot","bot_inline_placeholder","peerData","setDraft","msg_id","getServerMessageId","callbackAnswer","noLinks","noLinebreaks","queryAndResultIds","inlineResult","pushPopularBot","queryID","resultID","send_message","reply_markup","replyMarkup","sendText","inputMedia","sendMessage","getMediaInput","geoPoint","address","provider","venue_id","venue_type","phone_number","vcard","percent","sendOther","appInlineBotsManager","nextOffset","onGifsClick","gifsDiv","checkAnimations","newSearch","gifBotPeerId","resolveUsername","getInlineResults","setsDiv","countDiv","stickerDiv","renderFeatured","getFeaturedStickers","coveredSets","filterRendered","renderSet","searchStickerSets","forceClose","inited","onMouseOut","displayTimeout","isActive","toElement","willBeActive","onmouseout","onmouseover","tabId","onSelectTabClick","searchButton","deleteBtn","checkRights","tabsEl","tabsElements","canSendStickers","canSendToPeer","canSendGifs","chatInput","getGoodRange","lockIntersectionGroup","unlockIntersectionGroup","unlock","refresh","emojiTab","stickersTab","gifsTab","0","1","2","getVisible","clearVisible","activeElement","jumpedTo","stuck","which","scrollLeft","clearDraft","emoticonsDropdown","IGNORE_ACTIONS","TEST_SCROLL","appUsersManager","appPhotosManager","appProfileManager","appDraftsManager","appMessagesIdsManager","unreadOut","skippedMids","dateMessages","scrolledDown","isScrollingTimeout","unreaded","unreadedSeen","loadedTopTimes","loadedBottomTimes","messagesQueuePromise","messagesQueue","messagesQueueOnRender","messagesQueueOnRenderAdditional","firstUnreadBubble","replyFollowHistory","isFirstLoad","passEntities","viewsMids","onBubblesClick","chatInner","onDatePick","contactDiv","appImManager","bubbleMid","reply_to_top_id","lastMsgId","openThread","filterMessages","getDiscussionMessage","savedFrom","msgId","isVideoComponentElement","messageId","documentDiv","isMediaCompatibleForDocumentViewer","parents","hasAspecter","albumItem","getMidsByMessage","isReplyClick","replyToMid","reply_to_msg_id","getDistanceToEnd","topbar","pinnedMessage","setCorrectIndex","lastScrollDirection","requestHistory","setMessageId","setScroll","bubbleGroups","setBubblePosition","scrollingToBubble","scrollToBubbleEnd","deleteMessagesByIds","tempMessage","repliesElement","grouped_id","newPoll","safeRenderMessage","scrollToBubbleIfLast","getGroupedBubble","updatePosition","deleteEmptyDateGroups","deletedMids","renderedId","renderMaxId","groupedMessagesStorage","highlightBubble","initMessageReply","dateMessage","renderNewMessagesByIds","msgIds","setUnreadCount","updateUnreadByDialog","finishPeerChange","updateMessageInput","isScrolledDown","setMessagesQueuePromise","performHistoryResult","postViewsElements","str","different","postViews","unreadedObserver","onUnreadedInViewport","viewsObserver","sendViewCountersDebounced","incrementMessageViews","wasHeight","offsetHeight","resizing","skip","scrolled","part","rAF","onResizeEnd","setEndRAF","ResizeObserver","contentRect","realDiff","_part","needScrollTop","readUnreaded","readPromise","idle","focusPromise","bubblesMaxId","readContents","isMentionUnread","readHistory","bad","getHistoryTopPromise","getHistoryBottomPromise","getHistory","setLoaded","onScrolledTop","loadMoreHistory","readOutboxMaxId","permanent","emptyPlaceholderMid","deleteSelectedMids","replyTo","getLastBubble","lastDateGroup","getLastDateGroup","forceDirection","forceDuration","dateGroup","scrollToBubble","lastElem","lastTime","firstTimestamp","datasetKey","today","bubbleContent","serviceMsg","bubblesToo","attachedUnreadBubble","fetchNewPromise","onAnimateLadder","resolveLadderAnimation","samePeer","topMessage","pinnedMessages","isTarget","savedPosition","getChatSavedPosition","getReadMaxIdIfUnread","isJump","apiManager","setQueueId","messageEntityBotCommand","isBot","additionMsgId","maxBubbleId","getBubbleByPoint","oldChatInner","lockGroup","lastScrollTop","unlockGroup","fromUp","followingUnread","mountedByLastMsgId","findNextMountedBubbleByMsgId","afterSetPromise","needFetchInterval","isFetchIntervalNeeded","getNewHistory","isBottomEnd","Bottom","onScrolledAllDown","getDialogOnly","unread_mark","markDialogUnread","canWrite","queue","setUnreadDelimiter","getDateContainerByMessage","addBubble","multipleRender","albumMustBeRenderedFull","our","contentWrapper","wasClassNames","classNames","transitionDelay","originalMid","unread","chat_id","wrapMessageActionTextNew","renderMessagesQueue","is_single","messageMessage","messageMedia","getAlbumText","richText","canHaveTail","isStandaloneMedia","needToSetHTML","emojiEntities","strLength","curr","big","containerDiv","rowDiv","buttonEl","same_peer","checkSwitchReturn","switchInlineQuery","column","callbackButtonClick","messageWithReplies","getMessageWithReplies","withReplies","nameContainer","processingWebPage","noAutoDownloadMedia","previewResizer","preview","quote","quoteTextDiv","site_name","textDiv","isSquare","emojiSticker","animatedSticker","staticSticker","newNameContainer","wrapGroupedDocuments","lastContainer","texts","wrapPoll","needName","isForwardFromChannel","from_id","isHidden","from_name","getPeerColorById","goto","generateTail","renderMessage","isBackLimit","previousScrollHeightMinusTop","needReflowScroll","processLocalMessageRender","firstSlice","lastSlice","Top","newScrollTop","getScheduledMessages","additionMsgIds","isAdditionRender","animateAsLadder","targetMid","sortedMids","topIds","middleIds","bottomIds","setBubbles","delay","lastMsDelay","topRes","middleRes","bottomRes","delays","listElements","creator","renderEmptyPlaceholder","service","generateMessageId","peer_id","getOutputPeer","saveMessages","side","checkPlaceholders","bot_info","checkIfEmptyPlaceholderNeeded","generateLocalFirstMessage","getRenderedLength","realLoadCount","Both","resultPromise","isFirstMessageRender","processResult","historyResult","serviceStartMessageId","threadsServiceMessagesIdsStorage","sup","processPromise","waitPromise","safeCount","mustBeCount","unpin","canUnpin","canPinMessage","oneSide","silent","unpinAllMessages","hidePinnedMessages","updatePinnedMessage","buttonText","pinButtonText","isSelectionEmpty","selectionRange","START_TO_END","reason","reportMessages","STICKER_EMOJI","preloadStickerPromise","preloadAnimatedEmojiSticker","margin","marginTop","appPollsManager","appDocsManager","onSendScheduledClick","onReplyClick","onEditClick","initMessageEditing","onCopyClick","onCopyAnchorLinkClick","onCopyLinkClick","threadMessage","channel_post","onPinClick","onUnpinClick","onRetractVote","onStopPoll","stopPoll","isTargetAGroupedItem","isSelectable","isTextSelected","isAnchorTarget","isUsernameTarget","selectedMid","groupedItem","hasAttribute","notDirect","scheduleSending","editMessage","scheduleDate","canEditMessage","hasTarget","isGoodType","sendMenuButtons","onSilentClick","onScheduleClick","sendMenu","openSide","onContextElement","onSubmitClick","send","radioLabel","isEmpty","isInputEmpty","questions","appendMoreField","correctAnswers","optionInputFields","labelOptions","weakMap","questionInputField","sendSilent","setPeerId","dd","settingsCaption","anonymousCheckboxField","multipleCheckboxField","quizCheckboxField","quizSolutionField","quizElements","quizSolutionCaption","quizHr","quizSolutionContainer","quizSolutionSubtitle","onEscape","getFilledAnswers","HTMLInputElement","getRichValue","question","quizSolution","force","quizSolutionEntities","inputMediaPoll","getInputMediaPoll","replyToMsgId","helperType","clearHelper","questionField","files","willAttachType","confirmShortcutIsSendShortcut","wasInputValue","willAttach","sendFileDetails","onKeyDown","placeCaretAtEnd","attachFile","itemDiv","isVideo","source","objectURL","videoWidth","videoHeight","audioDecodedByteCount","webkitAudioDecodedByteCount","noSound","onload","isPhoto","isAudio","finish","onerror","mediaContainer","caption_length_max","showLengthOn","messageInputField","groupCheckboxField","attachFiles","isMedia","firstType","sendAlbum","sendFile","foundPhotos","foundVideos","albumsLength","albumContainer","AXIS_Y_KEYS","AXIS_X_KEYS","attachListNavigation","waitForKey","keyNames","getCurrentTarget","setCurrentTarget","_target","scrollTo","hadTarget","fastSmoothScroll","getNextTargetX","currentTarget","isNext","nextTarget","handleArrowKey","property","endProperty","currentRect","targetRect","getNextTargetY","fireSelect","canContinue","resetTarget","_onKeyDown","hidden","onVisible","listType","navigationItem","noBlurOnPop","removeItem","attachNavigation","controller","addHelper","fromController","hideOtherHelpers","onChangeScreen","ready","getMinDate","getMaxDate","canSendWhenOnline","btnSendWhenOnline","getRichValueWithCaret","field","withEntities","selNode","selOffset","startContainer","endContainer","startOffset","endOffset","getRichElementValue","caretPos","substr","combineSameEntities","onEmojiSelected","firstChar","getBothEmojiKeywords","searchEmojis","listElement","BASE","BASE_CLASS_LIST_ELEMENT","getReadyToSend","botInfos","ignoreCase","commands","botInfo","botCommand","command","found","helpers","preserveHelper","insertAtCaret","topMsgId","trimmed","getMentions","onBodyTouchStart","btnHover","attachButtonListener","checkAvailability","checkForceReply","touchListener","getReplyMarkup","sendInlineResult","_checkQuery","gifsMasonry","isGallery","gallery","noCommands","separator","dataURL","switch_pm","btnSwitchToPM","switchToPM","start_param","checkQuery","appChatsManager","appWebPagesManager","serverTimeManager","appNotificationsManager","lastUrl","lastTimeType","replyElements","willSendWebPage","recordCanceled","recordStartTime","lockRedo","canRedoFromHTML","undoHistory","executedHistory","canUndoFromHTML","onCancelRecordClick","recorder","opusDecodeController","setKeepAlive","onEmoticonsOpen","toggleClass","btnToggleEmoticons","onEmoticonsClose","isUserOnlineVisible","openScheduled","prepareDocumentExecute","undoRedo","needHTML","sameHTMLTimes","currentHTML","handleMarkdownShortcut","formatKeys","markupTooltip","showLinkEditor","applyMarkdown","shiftKey","onMessageInput","richValue","markdownEntities","parseMarkdown","mergeEntities","parseEntities","urlEntities","getWebPagePromise","saveWebPage","setTopInfo","noWebPage","onHelperCancel","helperFunc","setTyping","editMsgId","saveDraftDebounced","checkAutocomplete","updateSendBtn","getEmojiEntityFromEmoji","onBtnSendClick","forwarding","releaseMediaPlayback","setSingleMedia","showDiscardPopup","btnCancelRecord","recordingOverlayListener","recordingNavigationItem","sourceNode","analyser","createAnalyser","connect","fftSize","frequencyData","frequencyBinCount","getByteFrequencyData","recordRippleEl","recordTimeEl","needReturn","onHelperClick","helperWaitingForward","inputContainer","tail","goDownBtn","onGoDownClick","cancelBtn","newMessageWrapper","inputMessageContainer","goDownUnreadBadge","goMentionBtn","goMentionUnreadBadge","goToNextMention","btnScheduled","btnToggleReplyMarkup","replyKeyboard","attachMenuButtons","fileInput","accept","attachMenu","multiple","autocompleteHelperController","stickersHelper","emojiHelper","commandsHelper","mentionsHelper","inlineHelper","btnSendContainer","btnSend","attachMessageInputField","previousQuery","onFakeInput","draft","saveDraft","encoderSampleRate","monitorGain","numberOfChannels","recordingGain","reuseWorker","touchMouseDown","onstop","ondataavailable","typedArray","dataBlob","Blob","decode","isVoiceMessage","pinnedControlBtn","fakeContainer","fakePinnedControlBtn","originalChat","pinnedMessageContainer","unread_count","hasMentions","unread_mentions_count","no_webpage","syncDraft","helperToo","clearInput","fromUpdate","getDraft","rMessage","setInputValue","isAnonymousSending","oldInputField","inputFake","attachMessageInputListeners","fixSafariStickyInputFocusing","isSendShortcutPressed","ctrlKey","metaKey","childNodes","readAllHistory","commandsMap","bold","italic","underline","strikethrough","monospace","saveExecuted","executed","haveThisType","isCollapsed","tag","commonAncestorContainer","setActiveMarkupButton","insertText","insertEntity","isHelper","fullValue","prefix","AUTO_COMPLETE_REG_EXP","matchIndex","newValue","hadEntities","insertLength","addEntities","caret","selectNode","noCollapse","selectNodeContents","setRichFocus","_value","foundHelper","suggest","checkEmoticon","checkInlineAutocomplete","needPlaceholder","inlineMatch","btnPreloader","inlinePlaceholder","canSetDraft","fireEvent","clearValue","fixSafariStickyInput","clearReply","unicode","pushRecentEmoji","webPage","forwardMessages","pushRecentSticker","replyFragment","fromPeerIdsMids","fromPeerIds","smth","peerTitles","firstMessage","usingFullAlbum","albumMids","peerTitleEl","callerFunc","replyParent","floating","divAndCaption","CLASSNAME_BASE","btnClose","wrapperUtils","attachOnCloseEvent","needClose","isFloating","maxActive","setFloating","setUtilsWidth","prevEl","nextEl","attachClick","toggleEl","volumeProgressLineContainer","tunnel","progressWrapper","BAR_HEIGHTS","PinnedMessageBorder","drawRect","getClipPath","barHeight","GAP","clipPath","path","getBarHeight","ONE","TWO","THREE","FOUR","MORE","getMarkHeight","markHeight","getMarkTranslateY","getTrackTranslateY","trackHeight","getTrackHeight","clipPathId","markTranslateY","trackTranslateY","defs","mark","AnimatedSuper","animateFirst","currentIndex","clearRow","DURATION","reflow","clearRows","previousIndex","fromTop","ignorePrevious","setNewRow","previousRow","AnimatedCounter","previousNumber","animatedSuper","decimal","previousDecimalNumber","getRow","EMPTY_INDEX","previousByDecimal","n","decimalNumber","getDecimal","hideLeft","pinnedMaxMid","pinnedMid","pinnedIndex","wasPinnedIndex","wasPinnedMediaIndex","locked","waitForScrollBottom","loadedBottom","loadedTop","scrollDownListenerSetter","getCurrentIndexPromise","isStatic","debug","dAC","pinnedMessageBorder","animatedSubtitle","animatedMedia","animatedCounter","btnOpen","openPinned","setPinnedMessage","_setPinnedMessage","unsetScrollDownListener","testMid","isNeededMore","getCurrentIndex","LOAD_OFFSET","correctAfter","gotRest","getPinnedMessage","backLimited","offset_id_offset","lastY","isDown","deltaY","handleScrollSideEvent","refreshPosition","setScrollDownListener","handleFollowingPinnedMessage","isLast","setCount","writeTo","writeMediaTo","onResize","resize","setUtilsRAF","chatUtils","chatInfo","chatAudio","btnBack","person","avatarElement","btnMore","getDeleteButtonText","btnJoin","btnPinned","btnMute","btnSearch","followPinnedMessage","getSearchContext","activeScreen","onBtnBackClick","isFirstChat","getChannelFull","channelFull","linked_chat_id","chatsFull","chatContextMenuHintWasShown","contactPeerId","getContactMediaInput","usersFull","joinChannel","setMutedState","isTopMessage","hiddenPinnedMessages","byCurrent","destroy","wasPeerId","newPinnedMessage","appSearch","beginSearch","btnPickDate","selectedIndex","selectResult","upBtn","downBtn","foundCountEl","renderedCount","onResultsClick","onFooterClick","onUpClick","onDownClick","footer","dateBtn","wasAlreadyUsed","backgroundEl","Log","Warn","Debug","_item","backgroundImage","contextMenu","constructUtils","constructPeerHelpers","constructPinnedHelpers","constructDiscussionHelpers","constructScheduledHelpers","searchTab","setAutoDownloadMedia","setLoadMutex","loadSidebarMedia","autoDownload","setPrefix","addedListener","waitingForMouseUp","mouseUpCounter","onMouseUpSingle","resetSelection","tools1","tools2","cancelClosening","linkBackButton","linkInput","applyLink","isLinkValid","setTooltipPosition","linkApplyButton","applyDiv","delimiter1","delimiter2","delimiter3","matchUrlProtocol","hideTimeout","nodes","getSelectedNodes","currentMarkups","closest","activeButtons","getActiveMarkupButton","isLinkToggle","bodyRect","selectionRect","inputRect","selectionTop","sizesRect","containerRect","isFirstShow","setMouseUpEvent","arcParameter","rx","ry","xAxisRotation","largeArcFlag","sweepFlag","generatePathData","tl","tr","bl","onDragOver","onDragLeave","onDrop","outlineWrapper","dropIcon","dropHeader","dropSubtitle","disableTransition","INTERNAL_LINK_TYPE","chatInvite","broadcast","updates","processUpdateMessage","putPhoto","peopleCount","FOCUS_EVENT_NAME","columnEl","offline","updateStatusInterval","backgroundPromises","onHashChange","parseUriParams","tgaddr","replaceState","onclick","wrapUrl","postId","post","setSettings","chatsSelectTabDebounced","setLoop","onDocumentPaste","attachType","canDrag","DragEvent","_types","dataTransfer","isIDLE","updateStatus","createNewChat","chatsSelectTab","saveChatPosition","popup","singleInstance","activateInstance","addAnchorListener","uriParams","hashtag","pathnameParams","STICKER_SET","processInternalLink","JOIN_CHAT","invite","PRIVATE_POST","thread","comment","MESSAGE","domain","protocol","makeLink","attachKeydownListener","IGNORE_KEYS","isOverlayActive","goodMid","nextDialog","commentId","resolveChannel","saveApiChat","noPathnameParams","pathname","noUriParams","uri","openComment","generateThreadServiceStartMessage","broadcastEvent","STATE_INIT","getBackground","setBackground","getFile","chatBubbles","chatPositions","themeColor","hslaStringToHex","backgroundUrl","applyHighlightningColor","setTheme","setCurrentBackground","prevTab","prevIdx","attachDragAndDropListeners","handleSelection","drops","mount","isFiles","foundMedia","foundDocuments","dropsContainer","drop","setPath","transitionTime","setUserStatus","invokeApiSingle","fromIndex","justReturn","spliced","beforeDestroy","chatIndex","spliceChats","existingIndex","setType","dot","typings","getPeerTypings","typing","langPackKeys","private","multi","mapa","typingElement","getTypingElement","descriptionElement","getPeerTyping","useWhitespace","typingContainer","getPeerStatus","topButtons","author","preloaderStreamable","isFirstOpen","pageEl","zoomElements","zoomSwipeStartX","zoomSwipeStartY","zoomSwipeX","zoomSwipeY","setZoomValue","rangeSelector","moversContainer","btnOut","btnIn","toggleZoom","setMoverAnimationPromise","highlightSwitchersTimeout","wholeDiv","isZooming","mover","ctrlKeyDown","changeZoom","onKeyUp","onWheel","scrollingUp","MEDIA_VIEWER_CLASSNAME","overlaysDiv","mainDiv","topbarLeft","onlyMobile","authorRight","zoom","setNewMover","onDownloadClick","moveLength","setMoverPromise","evt","zoomValue","videoPlayer","lockControls","zoomSwipeHandler","lastDiffY","addProgress","btnMenuToggle","setMoverToTarget","appMediaViewer","closing","fromRight","removeCenterFromMover","wasActive","realParent","SVGImageElement","SVGForeignObjectElement","needOpacity","visibleRect","overflowElement","overflowRect","overflowTop","overflowBottom","sticky","overflow","horizontal","visualViewport","windowHeight","innerWidth","innerHeight","getVisibleRect","HTMLImageElement","HTMLVideoElement","setFullAspect","scaleX","scaleY","getComputedStyle","getPropertyValue","brSplitted","fillPropertyValue","willBeLeft","willBeTop","isRejected","SVGSVGElement","sizeTailPath","mediaElement","clipId","newClipId","newSvg","outerHTML","SVGUseElement","sX","sY","upscale","_br","toLeft","newTransform","p1","newMover","oldAvatar","replaceChild","setAuthorInfo","isDocument","useContainerAsTarget","moveTheMover","mainColumns","padding","thumbPromise","useController","moverVideo","canPlayThrough","createPlayer","ckin","overlay","HAVE_FUTURE_DATA","attachCanPlay","networkState","NETWORK_LOADING","isntEnoughData","rollback","updateMediaSource","cancellablePromise","attachPromise","haveImage","captionTimeout","isForDocument","onAuthorClick","savePhotoFile","setCaptionTimeout","setBtnMenuToggle","btnMenuDelete","onCaptionClick","setCaption","_openMedia","onAvatarUpdate","removeFromAvatarsCache","getFullPhoto","getTarget","hadMessage","isAvatarCached","believeMe","isDialog","addedToQueue","oldValue","getPeerMigratedTo","peerTitle","onArchiveClick","selectedId","editPeerFolders","folder_id","toggleDialogPin","pinned_dialogs_count_max","onUnmuteClick","onUnreadClick","top_message","ConnectionStatus","SENDING_STATUS","hadConnect","connecting","timedOut","updating","setConnectionStatus","baseDcId","setFirstConnectionTimeout","connectionStatus","online","Connected","forceGetDifference","TimedOut","retryAt","setStatusText","currentLangPackKey","statusEl","statusPreloader","CHANGE_STATE_DELAY","getA","forceReconnect","timerSpan","interval","forceReconnectTimeout","setStateTimeout","statusContainer","constructContainer","indexKey","appDialogsManager","onListLengthChange","willChangeLength","addListDialog","isBatch","menuScrollContainer","lastActiveElements","offsets","loadDialogsPromise","sortedList","onChatsScroll","_onListLengthChange","checkIfPlaceholderNeeded","hasContacts","loadContacts","processContact","verifyUserIdForContacts","added","onChatsRegularScroll","sliceTimeout","perf","performance","scrollTopWas","rectContainer","rectTarget","firstY","firstElement","lastElement","elementOverflow","sliceFromStart","sliceFromEnd","deleteDialog","setOffsets","onChatsScrollTop","loadDialogs","chatsPreloader","allUnreadCount","bottomPart","addFilter","getDialogDom","validateDialogForFilter","setFiltersUnreadCount","updateDialog","setUnreadMessages","validateListForFilter","order","containerToAppend","renderedFilter","getDialogIndexKey","unsetTyping","onStateLoaded","foldersScrollable","isLoadedMain","isDialogsLoaded","isLoadedArchive","wasLoaded","accumulateArchivedUnread","updatesState","syncLoading","refreshConversations","getNotifyPeerTypeSettings","renderFiltersPromise","showFiltersPromise","storagesResults","addMissedDialogs","migratedTo","testDialogForFilter","topOffset","getOffsetIndex","bottomOffset","isDialogMustBeInViewport","unreadSpan","mutedCount","notMutedCount","setFilterUnreadCount","getAll","sortedDialogList","currentOffsetIndex","needIndex","getConversationsResult","isTopEnd","callbacks","cccc","offsetDialog","classNameType","subtitleArgs","placeholderContainer","generateEmptyPlaceholder","wrapLocalSticker","firstDialog","getDialogFromElement","lastDialog","withContext","openInner","lastActiveListElement","setPeerFunc","sameElement","getDialogByPeerId","lastMessage","highlightWord","setUnread","draftMessage","lastTimeSpan","playIcon","withoutMediaType","sender","senderBold","setStatusMessage","disableAnimationIfRippleFound","iconClassName","setSendingStatus","statusSpan","isPinned","hasUnreadBadge","isUnreadBadgeMounted","unreadBadge","hasMentionsBadge","isMentionBadgeMounted","mentionsBadge","transitionDuration","isMention","accumulateArchivedTimeout","originalDialog","getDialog","addDialog","_dialog","captionDiv","titleSpanContainer","titleP","rightSpan","module","exports","call","defineProperty","enumerable","Symbol","toStringTag","__esModule","create","default","prototype","AudioContext","webkitAudioContext","isRecordingSupported","bufferLength","encoderApplication","encoderFrameSize","encoderPath","maxFramesPerPage","mediaTrackConstraints","resampleQuality","streamPages","wavBitDepth","encodedSamplePosition","mediaDevices","getUserMedia","WebAssembly","clearStream","stream","getTracks","audioContext","closeAudioContext","encodeBuffers","getChannelData","encoder","postMessage","buffers","initAudioContext","initAudioGraph","scriptProcessorNode","createScriptProcessor","destination","onaudioprocess","inputBuffer","monitorGainNode","createGain","setMonitorGain","recordingGainNode","setRecordingGain","initSourceNode","createMediaStreamSource","loadWorker","Worker","initWorker","streamPage","storePage","recordedPages","samplePosition","page","originalSampleRate","sampleRate","wavSampleRate","onpause","resume","onresume","gain","setTargetAtTime","onstart","destroyWorker","Function","rippleClickId","drawRipple","startTime","clickId","elapsedTime","touchStartFired","clickY","sqrt","isRippleUnneeded","touchEnd","CLICK_EVENT_NAME","attachClickEvent","detachClickEvent","simulateClickEvent","rippleSquare","putPreloader","returnDiv","setButtonLoader","diffX","diffY","closeBtnMenu","menuOverlay","openedMenuOnClose","openBtnMenu","positionMenu","menuWidth","menuHeight","windowWidth","intermediateX","intermediateY","possibleSides","_cancelContextMenuOpening","_cancelContextMenuOpeningTimeout","cancelContextMenuOpening","attachContextMenuListener","onCancel","navigations","manual","currentHash","isPossibleSwipe","pushState","handleItem","moved","scrollRestoration","noHistory","origin","simulateEvent","raf","kind","scheduleFlush","do","read","write","currentHashPromise","newHashPromise","password","new_settings","invokeCrypto","newAlgo","new_algo","salt1","randomize","hashes","new_password_hash","inputCheckPassword","saveApiUser","setUserAuth","PasswordInputField","passwordVisible","onVisibilityClick","toggleVisible","onVisibilityClickAdditional","stealthy","tabIndex","PasswordMonkey","noCache","curFrame"],"mappings":"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","file":"15.1a3e11966cccf1381885.chunk.js","sourcesContent":["/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport InputField from \"../inputField\";\r\nimport lottieLoader, { RLottiePlayer } from \"../../lib/lottieLoader\";\r\n\r\nexport default class TrackingMonkey {\r\n public container: HTMLElement;\r\n\r\n protected max = 45;\r\n protected needFrame = 0;\r\n\r\n protected animation: RLottiePlayer;\r\n protected idleAnimation: RLottiePlayer;\r\n\r\n protected loadPromise: Promise<any>;\r\n\r\n constructor(protected inputField: InputField, protected size: number) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('media-sticker-wrapper');\r\n\r\n const input = inputField.input;\r\n\r\n input.addEventListener('blur', () => {\r\n this.playAnimation(0);\r\n });\r\n\r\n input.addEventListener('input', (e) => {\r\n this.playAnimation(inputField.value.length);\r\n });\r\n\r\n /* codeInput.addEventListener('focus', () => {\r\n playAnimation(Math.max(codeInput.value.length, 1));\r\n }); */\r\n }\r\n\r\n // 1st symbol = frame 15\r\n // end symbol = frame 165\r\n public playAnimation(length: number) {\r\n if(!this.animation) return;\r\n\r\n length = Math.min(length, 30);\r\n let frame: number;\r\n if(length) {\r\n frame = Math.round(Math.min(this.max, length) * (165 / this.max) + 11.33);\r\n\r\n if(this.idleAnimation) {\r\n this.idleAnimation.stop(true);\r\n this.idleAnimation.canvas.style.display = 'none';\r\n }\r\n \r\n this.animation.canvas.style.display = '';\r\n } else {\r\n /* const cb = (frameNo: number) => {\r\n if(frameNo <= 1) { */\r\n /* idleAnimation.play();\r\n idleAnimation.canvas.style.display = '';\r\n animation.canvas.style.display = 'none'; */\r\n /* animation.removeListener('enterFrame', cb);\r\n }\r\n };\r\n animation.addListener('enterFrame', cb); */\r\n \r\n frame = 0;\r\n }\r\n //animation.playSegments([1, 2]);\r\n\r\n const direction = this.needFrame > frame ? -1 : 1;\r\n //console.log('keydown', length, frame, direction);\r\n\r\n this.animation.setDirection(direction);\r\n if(this.needFrame !== 0 && frame === 0) {\r\n this.animation.setSpeed(7);\r\n }\r\n /* let diff = Math.abs(needFrame - frame * direction);\r\n if((diff / 20) > 1) animation.setSpeed(diff / 20 | 0); */\r\n this.needFrame = frame;\r\n \r\n this.animation.play();\r\n\r\n /* animation.goToAndStop(15, true); */\r\n //animation.goToAndStop(length / max * );\r\n }\r\n\r\n public load() {\r\n if(this.loadPromise) return this.loadPromise;\r\n return this.loadPromise = Promise.all([\r\n lottieLoader.loadAnimationFromURL({\r\n container: this.container,\r\n loop: true,\r\n autoplay: true,\r\n width: this.size,\r\n height: this.size\r\n }, 'assets/img/TwoFactorSetupMonkeyIdle.tgs').then(animation => {\r\n this.idleAnimation = animation;\r\n\r\n // ! animationIntersector will stop animation instantly\r\n if(!this.inputField.value.length) {\r\n animation.play();\r\n }\r\n\r\n return lottieLoader.waitForFirstFrame(animation);\r\n }),\r\n\r\n lottieLoader.loadAnimationFromURL({\r\n container: this.container,\r\n loop: false,\r\n autoplay: false,\r\n width: this.size,\r\n height: this.size\r\n }, 'assets/img/TwoFactorSetupMonkeyTracking.tgs').then(_animation => {\r\n this.animation = _animation;\r\n\r\n if(!this.inputField.value.length) {\r\n this.animation.canvas.style.display = 'none';\r\n }\r\n\r\n this.animation.addEventListener('enterFrame', currentFrame => {\r\n //console.log('enterFrame', currentFrame, needFrame);\r\n //let currentFrame = Math.round(e.currentTime);\r\n \r\n if((this.animation.direction === 1 && currentFrame >= this.needFrame) ||\r\n (this.animation.direction === -1 && currentFrame <= this.needFrame)) {\r\n this.animation.setSpeed(1);\r\n this.animation.pause();\r\n }\r\n\r\n if(currentFrame === 0 && this.needFrame === 0) {\r\n //animation.curFrame = 0;\r\n \r\n if(this.idleAnimation) {\r\n this.idleAnimation.canvas.style.display = '';\r\n this.idleAnimation.play();\r\n this.animation.canvas.style.display = 'none';\r\n }\r\n }\r\n });\r\n //console.log(animation.getDuration(), animation.getDuration(true));\r\n\r\n return lottieLoader.waitForFirstFrame(_animation);\r\n })\r\n ]);\r\n }\r\n\r\n public remove() {\r\n if(this.animation) this.animation.remove();\r\n if(this.idleAnimation) this.idleAnimation.remove();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport InputField, { InputFieldOptions } from \"./inputField\";\r\n\r\nexport default class CodeInputField extends InputField {\r\n constructor(options: InputFieldOptions & {\r\n length: number,\r\n onFill: (code: string) => void\r\n }) {\r\n super({\r\n plainText: true,\r\n ...options\r\n });\r\n\r\n const input = this.input as HTMLInputElement;\r\n input.type = 'tel';\r\n input.setAttribute('required', '');\r\n input.autocomplete = 'off';\r\n\r\n let lastLength = 0;\r\n this.input.addEventListener('input', (e) => {\r\n this.input.classList.remove('error');\r\n this.setLabel();\r\n \r\n const value = this.value.replace(/\\D/g, '').slice(0, options.length);\r\n this.setValueSilently(value);\r\n \r\n const length = this.value.length;\r\n if(length === options.length) { // submit code\r\n options.onFill(this.value);\r\n } else if(length === lastLength) {\r\n return;\r\n }\r\n \r\n lastLength = length;\r\n });\r\n }\r\n}\r\n","import { IS_APPLE_MOBILE, IS_SAFARI } from \"./userAgent\";\n\n// mov is not supported in Chrome on macOS\nconst IS_MOV_SUPPORTED = !!document.createElement('video').canPlayType('video/quicktime') || IS_SAFARI || IS_APPLE_MOBILE;\n\nexport default IS_MOV_SUPPORTED;\n","import IS_MOV_SUPPORTED from \"./movSupport\";\nimport IS_WEBP_SUPPORTED from \"./webpSupport\";\n\nconst MEDIA_MIME_TYPES_SUPPORTED = new Set([\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/bmp',\n 'video/mp4',\n 'video/webm'\n]);\n\nif(IS_MOV_SUPPORTED) {\n MEDIA_MIME_TYPES_SUPPORTED.add('video/quicktime');\n}\n\nif(IS_WEBP_SUPPORTED) {\n MEDIA_MIME_TYPES_SUPPORTED.add('image/webp');\n}\n\nexport default MEDIA_MIME_TYPES_SUPPORTED;\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function setInnerHTML(elem: Element, html: string) {\r\n elem.setAttribute('dir', 'auto');\r\n elem.innerHTML = html;\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { Message, MessageAction } from \"../layer\";\nimport type { MyMessage } from \"../lib/appManagers/appMessagesManager\";\nimport { forEachReverse } from \"./array\";\n\nexport default function filterChatPhotosMessages(value: {\n count: number;\n next_rate: number;\n offset_id_offset: number;\n history: MyMessage[];\n}) {\n forEachReverse(value.history, (message, idx, arr) => {\n if(!((message as Message.messageService).action as MessageAction.messageActionChatEditPhoto).photo) {\n arr.splice(idx, 1);\n if(value.count !== undefined) {\n --value.count;\n }\n }\n });\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { forEachReverse } from \"./array\";\nimport { safeAssign } from \"./object\";\n\nexport type ListLoaderOptions<T extends {}, P extends {}> = {\n loadMore: ListLoader<T, P>['loadMore'],\n loadCount?: ListLoader<T, P>['loadCount'],\n loadWhenLeft?: ListLoader<T, P>['loadWhenLeft'],\n processItem?: ListLoader<T, P>['processItem'],\n onJump?: ListLoader<T, P>['onJump'],\n onLoadedMore?: ListLoader<T, P>['onLoadedMore']\n};\n\nexport type ListLoaderResult<T extends {}> = {count: number, items: any[]};\nexport default class ListLoader<T extends {}, P extends {}> {\n public current: T;\n public previous: T[] = [];\n public next: T[] = [];\n public count: number;\n public reverse = false; // reverse means next = higher msgid\n\n protected loadMore: (anchor: T, older: boolean, loadCount: number) => Promise<ListLoaderResult<T>>;\n protected processItem: (item: P) => T;\n protected loadCount = 50;\n protected loadWhenLeft = 20;\n \n public onJump: (item: T, older: boolean) => void;\n public onLoadedMore: () => void;\n\n protected loadedAllUp = false;\n protected loadedAllDown = false;\n protected loadPromiseUp: Promise<void>;\n protected loadPromiseDown: Promise<void>;\n\n constructor(options: ListLoaderOptions<T, P>) {\n safeAssign(this, options);\n }\n\n public setTargets(previous: T[], next: T[], reverse: boolean) {\n this.previous = previous;\n this.next = next;\n this.reverse = reverse;\n }\n\n public get index() {\n return this.count !== undefined ? this.previous.length : -1;\n }\n\n public reset(loadedAll = false) {\n this.current = undefined;\n this.previous = [];\n this.next = [];\n this.loadedAllUp = this.loadedAllDown = loadedAll;\n this.loadPromiseUp = this.loadPromiseDown = null;\n }\n\n public go(length: number, dispatchJump = true) {\n let items: T[], item: T;\n if(length > 0) {\n items = this.next.splice(0, length);\n item = items.pop();\n if(!item) {\n return;\n }\n\n this.previous.push(this.current, ...items);\n } else {\n items = this.previous.splice(this.previous.length + length, -length);\n item = items.shift();\n if(!item) {\n return;\n }\n\n this.next.unshift(...items, this.current);\n }\n\n if(this.next.length < this.loadWhenLeft) {\n this.load(!this.reverse);\n }\n\n if(this.previous.length < this.loadWhenLeft) {\n this.load(this.reverse);\n }\n\n this.current = item;\n dispatchJump && this.onJump && this.onJump(item, length > 0);\n return this.current;\n }\n\n // нет смысла делать проверку для reverse и loadMediaPromise\n public load(older: boolean) {\n if(older && this.loadedAllDown) return Promise.resolve();\n else if(!older && this.loadedAllUp) return Promise.resolve();\n\n if(older && this.loadPromiseDown) return this.loadPromiseDown;\n else if(!older && this.loadPromiseUp) return this.loadPromiseUp;\n\n let anchor: T;\n if(older) {\n anchor = this.reverse ? this.previous[0] : this.next[this.next.length - 1];\n } else {\n anchor = this.reverse ? this.next[this.next.length - 1] : this.previous[0];\n }\n\n const promise = this.loadMore(anchor, older, this.loadCount).then(result => {\n if((older && this.loadPromiseDown !== promise) || (!older && this.loadPromiseUp !== promise)) {\n return;\n }\n\n if(result.items.length < this.loadCount) {\n if(older) this.loadedAllDown = true;\n else this.loadedAllUp = true;\n }\n\n if(this.count === undefined) {\n this.count = result.count || result.items.length;\n }\n\n const method = older ? result.items.forEach.bind(result.items) : forEachReverse.bind(null, result.items);\n method((item: any) => {\n const processed = this.processItem ? this.processItem(item) : item;\n\n if(!processed) return;\n\n if(older) {\n if(this.reverse) this.previous.unshift(processed);\n else this.next.push(processed);\n } else {\n if(this.reverse) this.next.push(processed);\n else this.previous.unshift(processed);\n }\n });\n\n this.onLoadedMore && this.onLoadedMore();\n }, () => {}).then(() => {\n if(older) this.loadPromiseDown = null;\n else this.loadPromiseUp = null;\n });\n\n if(older) this.loadPromiseDown = promise;\n else this.loadPromiseUp = promise;\n\n return promise;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { MediaSearchContext } from \"../components/appMediaPlaybackController\";\nimport type { SearchSuperContext } from \"../components/appSearchSuper.\";\nimport type { Message } from \"../layer\";\nimport appMessagesIdsManager from \"../lib/appManagers/appMessagesIdsManager\";\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\nimport rootScope from \"../lib/rootScope\";\nimport { forEachReverse } from \"./array\";\nimport filterChatPhotosMessages from \"./filterChatPhotosMessages\";\nimport ListLoader, { ListLoaderOptions } from \"./listLoader\";\n\nexport default class SearchListLoader<Item extends {mid: number, peerId: number}> extends ListLoader<Item, Message.message> {\n public searchContext: MediaSearchContext;\n public onEmptied: () => void;\n\n constructor(options: Omit<ListLoaderOptions<Item, Message.message>, 'loadMore'> & {onEmptied?: () => void} = {}) {\n super({\n ...options,\n loadMore: (anchor, older, loadCount) => {\n const backLimit = older ? 0 : loadCount;\n let maxId = this.current?.mid;\n\n if(anchor) maxId = anchor.mid;\n if(!older) maxId = appMessagesIdsManager.incrementMessageId(maxId, 1);\n\n return appMessagesManager.getSearch({\n ...this.searchContext,\n peerId: this.searchContext.peerId || anchor?.peerId,\n maxId,\n limit: backLimit ? 0 : loadCount,\n backLimit\n }).then(value => {\n /* if(DEBUG) {\n this.log('loaded more media by maxId:', maxId, value, older, this.reverse);\n } */\n\n if(this.searchContext.inputFilter._ === 'inputMessagesFilterChatPhotos') {\n filterChatPhotosMessages(value);\n }\n\n if(value.next_rate) {\n this.searchContext.nextRate = value.next_rate;\n }\n\n return {count: value.count, items: value.history};\n });\n },\n processItem: (message) => {\n const filtered = this.filterMids([message.mid]);\n if(!filtered.length) {\n return;\n }\n\n return options.processItem(message);\n }\n });\n\n rootScope.addEventListener('history_delete', this.onHistoryDelete);\n rootScope.addEventListener('history_multiappend', this.onHistoryMultiappend);\n rootScope.addEventListener('message_sent', this.onMessageSent);\n }\n\n protected filterMids(mids: number[]) {\n const storage = this.searchContext.isScheduled ? \n appMessagesManager.getScheduledMessagesStorage(this.searchContext.peerId) : \n appMessagesManager.getMessagesStorage(this.searchContext.peerId);\n const filtered = appMessagesManager.filterMessagesByInputFilter(this.searchContext.inputFilter._, mids, storage, mids.length) as Message.message[];\n return filtered;\n }\n\n protected onHistoryDelete = ({peerId, msgs}: {peerId: number, msgs: Set<number>}) => {\n const shouldBeDeleted = (item: Item) => item.peerId === peerId && msgs.has(item.mid);\n const filter = (item: Item, idx: number, arr: Item[]) => {\n if(shouldBeDeleted(item)) {\n arr.splice(idx, 1);\n }\n };\n\n forEachReverse(this.previous, filter);\n forEachReverse(this.next, filter);\n\n if(this.current && shouldBeDeleted(this.current)) {\n /* if(this.go(1)) {\n this.previous.splice(this.previous.length - 1, 1);\n } else if(this.go(-1)) {\n this.next.splice(0, 1);\n } else */if(this.onEmptied) {\n this.onEmptied();\n }\n }\n };\n\n protected onHistoryMultiappend = (obj: {\n [peerId: string]: Set<number>;\n }) => {\n if(this.searchContext.folderId !== undefined) {\n return;\n }\n\n // because it's reversed\n if(!this.loadedAllUp || this.loadPromiseUp) {\n return;\n }\n\n const mids = obj[this.searchContext.peerId];\n if(!mids) {\n return;\n }\n\n const sorted = Array.from(mids).sort((a, b) => a - b);\n const filtered = this.filterMids(sorted);\n const targets = filtered.map(message => this.processItem(message)).filter(Boolean);\n if(targets.length) {\n this.next.push(...targets);\n }\n };\n\n protected onMessageSent = ({message}: {message: Message.message}) => {\n this.onHistoryMultiappend({\n [message.peerId]: new Set([message.mid])\n });\n };\n\n public setSearchContext(context: SearchSuperContext) {\n this.searchContext = context;\n\n if(this.searchContext.folderId !== undefined) {\n this.loadedAllUp = true;\n\n if(this.searchContext.nextRate === undefined) {\n this.loadedAllDown = true;\n }\n }\n\n if(this.searchContext.inputFilter._ === 'inputMessagesFilterChatPhotos') {\n this.loadedAllUp = true;\n }\n\n if(!this.searchContext.useSearch) {\n this.loadedAllDown = this.loadedAllUp = true;\n }\n }\n\n public reset() {\n super.reset();\n this.searchContext = undefined;\n }\n\n public cleanup() {\n this.reset();\n rootScope.removeEventListener('history_delete', this.onHistoryDelete);\n rootScope.removeEventListener('history_multiappend', this.onHistoryMultiappend);\n rootScope.removeEventListener('message_sent', this.onMessageSent);\n this.onEmptied = undefined;\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appDialogsManager from \"../lib/appManagers/appDialogsManager\";\r\nimport Scrollable from \"./scrollable\";\r\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\r\nimport InputSearch from \"./inputSearch\";\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport { i18n, LangPackKey } from \"../lib/langPack\";\r\n\r\nexport class SearchGroup {\r\n container: HTMLDivElement;\r\n nameEl: HTMLDivElement;\r\n list: HTMLUListElement;\r\n\r\n constructor(public name: LangPackKey | boolean, public type: string, private clearable = true, className?: string, clickable = true, public autonomous = true, public onFound?: () => void) {\r\n this.list = appDialogsManager.createChatList();\r\n this.container = document.createElement('div');\r\n if(className) this.container.className = className;\r\n \r\n if(name) {\r\n this.nameEl = document.createElement('div');\r\n this.nameEl.classList.add('search-group__name');\r\n if(typeof(name) === 'string') {\r\n this.nameEl.append(i18n(name));\r\n }\r\n this.container.append(this.nameEl);\r\n }\r\n \r\n this.container.classList.add('search-group', 'search-group-' + type);\r\n this.container.append(this.list);\r\n this.container.style.display = 'none';\r\n\r\n if(clickable) {\r\n appDialogsManager.setListClickListener(this.list, onFound, undefined, autonomous);\r\n }\r\n }\r\n\r\n clear() {\r\n this.container.style.display = 'none';\r\n\r\n if(this.clearable) {\r\n this.list.innerHTML = '';\r\n }\r\n }\r\n\r\n setActive() {\r\n this.container.style.display = '';\r\n }\r\n\r\n toggle() {\r\n if(this.list.childElementCount) {\r\n this.setActive();\r\n } else {\r\n this.clear();\r\n }\r\n }\r\n}\r\n\r\nexport type SearchGroupType = 'contacts' | 'globalContacts' | 'messages' | string;\r\n\r\nexport default class AppSearch {\r\n private minMsgId = 0;\r\n private loadedCount = -1;\r\n private foundCount = -1;\r\n\r\n private searchPromise: Promise<void> = null;\r\n private searchTimeout: number = 0;\r\n\r\n private query = '';\r\n\r\n private listsContainer: HTMLDivElement = null;\r\n\r\n private peerId = 0; // 0 - means global\r\n private threadId = 0;\r\n\r\n private scrollable: Scrollable;\r\n\r\n constructor(public container: HTMLElement, public searchInput: InputSearch, public searchGroups: {[group in SearchGroupType]: SearchGroup}, public onSearch?: (count: number) => void) {\r\n this.scrollable = new Scrollable(this.container);\r\n this.listsContainer = this.scrollable.container as HTMLDivElement;\r\n for(let i in this.searchGroups) {\r\n this.listsContainer.append(this.searchGroups[i as SearchGroupType].container);\r\n }\r\n\r\n if(this.searchGroups.messages) {\r\n this.scrollable.setVirtualContainer(this.searchGroups.messages.list);\r\n }\r\n\r\n this.searchInput.onChange = (value) => {\r\n /* if(!value.trim()) {\r\n //this.peerId = 0;\r\n return;\r\n } */\r\n \r\n this.query = value;\r\n this.reset(false);\r\n this.searchMore();\r\n };\r\n\r\n this.scrollable.onScrolledBottom = () => {\r\n if(!this.query.trim()) return;\r\n \r\n if(!this.searchTimeout) {\r\n this.searchTimeout = window.setTimeout(() => {\r\n this.searchMore();\r\n this.searchTimeout = 0;\r\n }, 0);\r\n }\r\n };\r\n }\r\n\r\n public reset(all = true) {\r\n if(all) {\r\n this.searchInput.value = '';\r\n this.query = '';\r\n this.peerId = 0;\r\n this.threadId = 0;\r\n }\r\n\r\n this.minMsgId = 0;\r\n this.loadedCount = -1;\r\n this.foundCount = -1;\r\n\r\n for(let i in this.searchGroups) {\r\n this.searchGroups[i as SearchGroupType].clear();\r\n }\r\n \r\n this.searchPromise = null;\r\n }\r\n\r\n public beginSearch(peerId = 0, threadId = 0, query = '') {\r\n this.peerId = peerId;\r\n this.threadId = threadId;\r\n\r\n if(this.query !== query) {\r\n this.searchInput.inputField.value = query;\r\n }\r\n\r\n this.searchInput.input.focus();\r\n }\r\n\r\n public searchMore() {\r\n if(this.searchPromise) return this.searchPromise;\r\n \r\n const query = this.query;\r\n \r\n if(!query.trim()) {\r\n this.onSearch && this.onSearch(0);\r\n return;\r\n }\r\n \r\n if(this.foundCount !== -1 && this.loadedCount >= this.foundCount) {\r\n return Promise.resolve();\r\n }\r\n \r\n const maxId = this.minMsgId || 0;\r\n\r\n return this.searchPromise = appMessagesManager.getSearch({\r\n peerId: this.peerId, \r\n query, \r\n inputFilter: {_: 'inputMessagesFilterEmpty'}, \r\n maxId, \r\n limit: 20,\r\n threadId: this.threadId\r\n }).then(res => {\r\n this.searchPromise = null;\r\n \r\n if(this.searchInput.value !== query) {\r\n return;\r\n }\r\n \r\n //console.log('input search result:', this.peerId, query, null, maxId, 20, res);\r\n \r\n const {count, history} = res;\r\n \r\n if(history.length && history[0].mid === this.minMsgId) {\r\n history.shift();\r\n }\r\n \r\n const searchGroup = this.searchGroups.messages;\r\n\r\n history.forEach((message) => {\r\n const peerId = this.peerId ? message.fromId : message.peerId;\r\n const {dialog, dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId, \r\n container: this.scrollable/* searchGroup.list */, \r\n drawStatus: false,\r\n avatarSize: 54,\r\n meAsSaved: false\r\n });\r\n\r\n if(message.peerId !== peerId) {\r\n dom.listEl.dataset.peerId = '' + message.peerId;\r\n }\r\n\r\n appDialogsManager.setLastMessage(dialog, message, dom, query);\r\n });\r\n\r\n searchGroup.toggle();\r\n \r\n this.minMsgId = history.length && history[history.length - 1].mid;\r\n \r\n if(this.loadedCount === -1) {\r\n this.loadedCount = 0;\r\n }\r\n this.loadedCount += history.length;\r\n \r\n if(this.foundCount === -1) {\r\n this.foundCount = count;\r\n\r\n if(searchGroup.nameEl) {\r\n replaceContent(searchGroup.nameEl, i18n(count ? 'Chat.Search.MessagesFound' : 'Chat.Search.NoMessagesFound', [count]));\r\n }\r\n \r\n this.onSearch && this.onSearch(this.foundCount);\r\n }\r\n }).catch(err => {\r\n console.error('search error', err);\r\n this.searchPromise = null;\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\n//import { getRichValue } from \"../helpers/dom\";\r\nimport { LangPackKey } from \"../lib/langPack\";\r\nimport InputField from \"./inputField\";\r\n\r\nexport default class InputSearch {\r\n public container: HTMLElement;\r\n public input: HTMLElement;\r\n public inputField: InputField;\r\n public clearBtn: HTMLElement;\r\n\r\n public prevValue = '';\r\n public timeout = 0;\r\n public onChange: (value: string) => void;\r\n public onClear: () => void;\r\n\r\n constructor(placeholder: LangPackKey, onChange?: (value: string) => void) {\r\n this.inputField = new InputField({\r\n placeholder,\r\n plainText: true\r\n });\r\n\r\n this.container = this.inputField.container;\r\n this.container.classList.remove('input-field');\r\n this.container.classList.add('input-search');\r\n\r\n this.onChange = onChange;\r\n\r\n this.input = this.inputField.input;\r\n this.input.classList.add('input-search-input');\r\n\r\n const searchIcon = document.createElement('i');\r\n searchIcon.classList.add('tgico', 'tgico-search');\r\n\r\n this.clearBtn = document.createElement('i');\r\n this.clearBtn.classList.add('tgico', 'btn-icon', 'tgico-close');\r\n\r\n this.input.addEventListener('input', this.onInput);\r\n this.clearBtn.addEventListener('click', this.onClearClick);\r\n\r\n this.container.append(searchIcon, this.clearBtn);\r\n }\r\n \r\n onInput = () => {\r\n if(!this.onChange) return;\r\n\r\n let value = this.value;\r\n\r\n //this.input.classList.toggle('is-empty', !value.trim());\r\n\r\n if(value !== this.prevValue) {\r\n this.prevValue = value;\r\n clearTimeout(this.timeout);\r\n this.timeout = window.setTimeout(() => {\r\n this.onChange(value);\r\n }, 200);\r\n }\r\n };\r\n\r\n onClearClick = () => {\r\n this.value = '';\r\n this.onChange && this.onChange('');\r\n this.onClear && this.onClear();\r\n };\r\n\r\n get value() {\r\n return this.inputField.value;\r\n }\r\n\r\n set value(value: string) {\r\n this.prevValue = value;\r\n clearTimeout(this.timeout);\r\n this.inputField.value = value;\r\n }\r\n\r\n public remove() {\r\n clearTimeout(this.timeout);\r\n this.input.removeEventListener('input', this.onInput);\r\n this.clearBtn.removeEventListener('click', this.onClearClick);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport Button from \"./button\";\r\n\r\nconst ButtonIcon = (className?: string, options: Partial<{noRipple: true, onlyMobile: true, asDiv: boolean}> = {}) => {\r\n const button = Button('btn-icon', {\r\n icon: className || undefined, \r\n ...options\r\n });\r\n\r\n return button;\r\n};\r\n\r\nexport default ButtonIcon;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport EventListenerBase from \"../helpers/eventListenerBase\";\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\nimport { i18n, LangPackKey } from \"../lib/langPack\";\r\nimport ButtonIcon from \"./buttonIcon\";\r\nimport Scrollable from \"./scrollable\";\r\nimport SidebarSlider from \"./slider\";\r\n\r\nexport interface SliderTab {\r\n onOpen?: () => void,\r\n onOpenAfterTimeout?: () => void,\r\n onClose?: () => void,\r\n onCloseAfterTimeout?: () => void\r\n}\r\n\r\nexport interface SliderSuperTabConstructable {\r\n new(slider: SidebarSlider, destroyable: boolean): SliderSuperTab;\r\n}\r\n\r\nexport default class SliderSuperTab implements SliderTab {\r\n public container: HTMLElement;\r\n\r\n public header: HTMLElement;\r\n public closeBtn: HTMLElement;\r\n public title: HTMLElement;\r\n\r\n public content: HTMLElement;\r\n public scrollable: Scrollable;\r\n\r\n public slider: SidebarSlider;\r\n public destroyable: boolean;\r\n public listenerSetter: ListenerSetter;\r\n\r\n constructor(slider: SidebarSlider, destroyable?: boolean) {\r\n this._constructor(slider, destroyable);\r\n }\r\n\r\n public _constructor(slider: SidebarSlider, destroyable = true): any {\r\n this.slider = slider;\r\n this.destroyable = destroyable;\r\n\r\n this.container = document.createElement('div');\r\n this.container.classList.add('tabs-tab', 'sidebar-slider-item');\r\n\r\n // * Header\r\n this.header = document.createElement('div');\r\n this.header.classList.add('sidebar-header');\r\n\r\n this.closeBtn = ButtonIcon('left sidebar-close-button', {noRipple: true});\r\n this.title = document.createElement('div');\r\n this.title.classList.add('sidebar-header__title');\r\n this.header.append(this.closeBtn, this.title);\r\n\r\n // * Content\r\n this.content = document.createElement('div');\r\n this.content.classList.add('sidebar-content');\r\n\r\n this.scrollable = new Scrollable(this.content, undefined, undefined, true);\r\n\r\n this.container.append(this.header, this.content);\r\n\r\n this.slider.addTab(this);\r\n \r\n this.listenerSetter = new ListenerSetter();\r\n }\r\n\r\n public close() {\r\n return this.slider.closeTab(this);\r\n }\r\n\r\n public async open(...args: any[]) {\r\n if(this.init) {\r\n try {\r\n const result = this.init();\r\n this.init = null;\r\n\r\n if(result instanceof Promise) {\r\n await result;\r\n }\r\n } catch(err) {\r\n console.error('open tab error', err);\r\n }\r\n }\r\n\r\n return this.slider.selectTab(this);\r\n }\r\n\r\n protected init(): Promise<any> | any {\r\n\r\n }\r\n\r\n public onCloseAfterTimeout() {\r\n if(this.destroyable) { // ! WARNING, пока что это будет работать только с самой последней внутренней вкладкой !\r\n this.slider.tabs.delete(this);\r\n this.container.remove();\r\n }\r\n\r\n if(this.listenerSetter) {\r\n this.listenerSetter.removeAll();\r\n }\r\n }\r\n\r\n protected setTitle(key: LangPackKey) {\r\n this.title.innerHTML = '';\r\n this.title.append(i18n(key));\r\n }\r\n}\r\n\r\nexport class SliderSuperTabEventable extends SliderSuperTab {\r\n public eventListener: EventListenerBase<{\r\n destroy: () => void\r\n }>;\r\n\r\n constructor(slider: SidebarSlider) {\r\n super(slider);\r\n this.eventListener = new EventListenerBase();\r\n }\r\n\r\n onCloseAfterTimeout() {\r\n this.eventListener.dispatchEvent('destroy');\r\n this.eventListener.cleanup();\r\n return super.onCloseAfterTimeout();\r\n }\r\n}\r\n\r\n/* // @ts-ignore\r\ninterface SliderSuperEventsTab extends SliderSuperTab, EventListenerBase<{}> {\r\n superConstructor: (...args: any[]) => any;\r\n}\r\nclass SliderSuperEventsTab implements SliderSuperEventsTab {\r\n constructor(slider: SidebarSlider) {\r\n this.superConstructor([slider, true]);\r\n }\r\n}\r\napplyMixins(SliderSuperEventsTab, [SliderSuperTab, EventListenerBase]);\r\n\r\n(window as any).lol = SliderSuperEventsTab\r\n\r\nexport {SliderSuperEventsTab}; */\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { horizontalMenu } from \"./horizontalMenu\";\r\nimport { TransitionSlider } from \"./transition\";\r\nimport appNavigationController, { NavigationItem } from \"./appNavigationController\";\r\nimport SliderSuperTab, { SliderSuperTabConstructable, SliderTab } from \"./sliderTab\";\r\nimport { safeAssign } from \"../helpers/object\";\r\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\r\n\r\nconst TRANSITION_TIME = 250;\r\n\r\nexport type {SliderTab};\r\nexport {SliderSuperTab};\r\n\r\nexport default class SidebarSlider {\r\n protected _selectTab: ReturnType<typeof horizontalMenu>;\r\n public historyTabIds: (number | SliderSuperTab)[] = []; // * key is any, since right sidebar is ugly nowz\r\n public tabsContainer: HTMLElement;\r\n public sidebarEl: HTMLElement;\r\n public tabs: Map<any, SliderTab>; // * key is any, since right sidebar is ugly now\r\n private canHideFirst = false;\r\n private navigationType: NavigationItem['type']\r\n\r\n constructor(options: {\r\n sidebarEl: SidebarSlider['sidebarEl'],\r\n tabs?: SidebarSlider['tabs'],\r\n canHideFirst?: SidebarSlider['canHideFirst'],\r\n navigationType: SidebarSlider['navigationType']\r\n }) {\r\n safeAssign(this, options);\r\n\r\n if(!this.tabs) {\r\n this.tabs = new Map();\r\n }\r\n\r\n this.tabsContainer = this.sidebarEl.querySelector('.sidebar-slider');\r\n this._selectTab = TransitionSlider(this.tabsContainer, 'navigation', TRANSITION_TIME);\r\n if(!this.canHideFirst) {\r\n this._selectTab(0);\r\n }\r\n\r\n Array.from(this.sidebarEl.querySelectorAll('.sidebar-close-button') as any as HTMLElement[]).forEach(el => {\r\n attachClickEvent(el, this.onCloseBtnClick);\r\n });\r\n }\r\n\r\n public onCloseBtnClick = () => {\r\n const item = appNavigationController.findItemByType(this.navigationType);\r\n if(item) {\r\n appNavigationController.back(this.navigationType);\r\n } else if(this.historyTabIds.length) {\r\n this.closeTab(this.historyTabIds[this.historyTabIds.length - 1]);\r\n }\r\n // this.closeTab();\r\n };\r\n\r\n public closeTab = (id?: number | SliderSuperTab, animate?: boolean, isNavigation?: boolean) => {\r\n if(id !== undefined && this.historyTabIds[this.historyTabIds.length - 1] !== id) {\r\n return false;\r\n }\r\n\r\n //console.log('sidebar-close-button click:', this.historyTabIDs);\r\n const closingId = this.historyTabIds.pop(); // pop current\r\n this.onCloseTab(closingId, animate, isNavigation);\r\n\r\n const tab = this.historyTabIds[this.historyTabIds.length - 1];\r\n this._selectTab(tab !== undefined ? (tab instanceof SliderSuperTab ? tab.container : tab) : (this.canHideFirst ? -1 : 0), animate);\r\n return true;\r\n };\r\n\r\n public selectTab(id: number | SliderSuperTab): boolean {\r\n /* if(id instanceof SliderSuperTab) {\r\n id = id.id;\r\n } */\r\n\r\n if(this.historyTabIds[this.historyTabIds.length - 1] === id) {\r\n return false;\r\n }\r\n\r\n const tab: SliderTab = id instanceof SliderSuperTab ? id : this.tabs.get(id);\r\n if(tab) {\r\n if(tab.onOpen) {\r\n tab.onOpen();\r\n }\r\n \r\n if(tab.onOpenAfterTimeout) {\r\n setTimeout(() => {\r\n tab.onOpenAfterTimeout();\r\n }, TRANSITION_TIME);\r\n }\r\n }\r\n\r\n //if(!this.canHideFirst || this.historyTabIds.length) {\r\n appNavigationController.pushItem({\r\n type: this.navigationType, \r\n onPop: (canAnimate) => {\r\n this.closeTab(undefined, canAnimate, true);\r\n return true;\r\n }\r\n });\r\n //}\r\n \r\n this.historyTabIds.push(id);\r\n this._selectTab(id instanceof SliderSuperTab ? id.container : id);\r\n return true;\r\n }\r\n\r\n public removeTabFromHistory(id: number | SliderSuperTab) {\r\n this.historyTabIds.findAndSplice(i => i === id);\r\n this.onCloseTab(id, undefined);\r\n }\r\n\r\n public sliceTabsUntilTab(tabConstructor: SliderSuperTabConstructable, preserveTab: SliderSuperTab) {\r\n for(let i = this.historyTabIds.length - 1; i >= 0; --i) {\r\n const tab = this.historyTabIds[i];\r\n if(tab === preserveTab) continue;\r\n else if(tab instanceof tabConstructor) {\r\n break;\r\n }\r\n\r\n this.removeTabFromHistory(tab);\r\n //appNavigationController.removeByType(this.navigationType, true);\r\n }\r\n }\r\n\r\n public getTab(tabConstructor: SliderSuperTabConstructable) {\r\n return this.historyTabIds.find(t => t instanceof tabConstructor) as SliderSuperTab;\r\n }\r\n\r\n public isTabExists(tabConstructor: SliderSuperTabConstructable) {\r\n return !!this.getTab(tabConstructor);\r\n }\r\n\r\n protected onCloseTab(id: number | SliderSuperTab, animate: boolean, isNavigation?: boolean) {\r\n if(!isNavigation) {\r\n appNavigationController.removeByType(this.navigationType, true);\r\n }\r\n\r\n const tab: SliderTab = id instanceof SliderSuperTab ? id : this.tabs.get(id);\r\n if(tab) {\r\n if(tab.onClose) {\r\n tab.onClose();\r\n }\r\n\r\n if(tab.onCloseAfterTimeout) {\r\n setTimeout(() => {\r\n tab.onCloseAfterTimeout();\r\n }, TRANSITION_TIME);\r\n }\r\n }\r\n }\r\n\r\n public addTab(tab: SliderSuperTab) {\r\n if(!tab.container.parentElement) {\r\n this.tabsContainer.append(tab.container);\r\n\r\n if(tab.closeBtn) {\r\n tab.closeBtn.addEventListener('click', this.onCloseBtnClick);\r\n }\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { CancellablePromise } from \"../helpers/cancellablePromise\";\r\nimport type { InputFile } from \"../layer\";\r\nimport PopupAvatar from \"./popups/avatar\";\r\n\r\nexport default class AvatarEdit {\r\n public container: HTMLElement;\r\n private canvas: HTMLCanvasElement;\r\n private icon: HTMLSpanElement;\r\n\r\n constructor(onChange: (uploadAvatar: () => CancellablePromise<InputFile>) => void) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('avatar-edit');\r\n\r\n this.canvas = document.createElement('canvas');\r\n this.canvas.classList.add('avatar-edit-canvas');\r\n\r\n this.icon = document.createElement('span');\r\n this.icon.classList.add('tgico', 'tgico-cameraadd');\r\n\r\n this.container.append(this.canvas, this.icon);\r\n\r\n this.container.addEventListener('click', () => {\r\n new PopupAvatar().open(this.canvas, onChange);\r\n });\r\n }\r\n\r\n public clear() {\r\n const ctx = this.canvas.getContext('2d');\r\n ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport Button from \"./button\";\r\n\r\nconst ButtonCorner = (options: Partial<{className: string, icon: string, noRipple: true, onlyMobile: true, asDiv: boolean}> = {}) => {\r\n const button = Button('btn-circle btn-corner z-depth-1' + (options.className ? ' ' + options.className : ''), options);\r\n return button;\r\n};\r\n\r\nexport default ButtonCorner;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appSidebarLeft from \"..\";\r\nimport { InputFile } from \"../../../layer\";\r\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport { SearchGroup } from \"../../appSearch\";\r\nimport InputField from \"../../inputField\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport AvatarEdit from \"../../avatarEdit\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\nimport ButtonCorner from \"../../buttonCorner\";\r\n\r\nexport default class AppNewGroupTab extends SliderSuperTab {\r\n private searchGroup = new SearchGroup(true, 'contacts', true, 'new-group-members disable-hover', false);\r\n private avatarEdit: AvatarEdit;\r\n private uploadAvatar: () => Promise<InputFile> = null;\r\n private userIds: number[];\r\n private nextBtn: HTMLButtonElement;\r\n private groupNameInputField: InputField;\r\n\r\n protected init() {\r\n this.container.classList.add('new-group-container');\r\n this.setTitle('NewGroup');\r\n\r\n this.avatarEdit = new AvatarEdit((_upload) => {\r\n this.uploadAvatar = _upload;\r\n });\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n this.groupNameInputField = new InputField({\r\n label: 'CreateGroup.NameHolder',\r\n maxLength: 128\r\n });\r\n\r\n inputWrapper.append(this.groupNameInputField.container);\r\n\r\n this.groupNameInputField.input.addEventListener('input', () => {\r\n const value = this.groupNameInputField.value;\r\n this.nextBtn.classList.toggle('is-visible', !!value.length && !this.groupNameInputField.input.classList.contains('error'));\r\n });\r\n\r\n this.nextBtn = ButtonCorner({icon: 'arrow_next'});\r\n\r\n this.nextBtn.addEventListener('click', () => {\r\n const title = this.groupNameInputField.value;\r\n\r\n this.nextBtn.disabled = true;\r\n appChatsManager.createChat(title, this.userIds).then((chatId) => {\r\n if(this.uploadAvatar) {\r\n this.uploadAvatar().then((inputFile) => {\r\n appChatsManager.editPhoto(chatId, inputFile);\r\n });\r\n }\r\n \r\n appSidebarLeft.removeTabFromHistory(this);\r\n appSidebarLeft.selectTab(0);\r\n });\r\n });\r\n\r\n const chatsContainer = document.createElement('div');\r\n chatsContainer.classList.add('chatlist-container');\r\n chatsContainer.append(this.searchGroup.container);\r\n\r\n this.content.append(this.nextBtn);\r\n this.scrollable.append(this.avatarEdit.container, inputWrapper, chatsContainer);\r\n }\r\n\r\n public onCloseAfterTimeout() {\r\n this.searchGroup.clear();\r\n this.avatarEdit.clear();\r\n this.uploadAvatar = null;\r\n this.groupNameInputField.value = '';\r\n this.nextBtn.disabled = false;\r\n }\r\n\r\n public open(userIds: number[]) {\r\n const result = super.open();\r\n result.then(() => {\r\n this.userIds = userIds;\r\n\r\n this.userIds.forEach(userId => {\r\n let {dom} = appDialogsManager.addDialogNew({\r\n dialog: userId,\r\n container: this.searchGroup.list,\r\n drawStatus: false,\r\n rippleEnabled: false,\r\n avatarSize: 48\r\n });\r\n\r\n dom.lastMessageSpan.append(appUsersManager.getUserStatusString(userId));\r\n });\r\n\r\n this.searchGroup.nameEl.textContent = '';\r\n this.searchGroup.nameEl.append(i18n('Members', [this.userIds.length]));\r\n this.searchGroup.setActive();\r\n });\r\n \r\n return result;\r\n }\r\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport rootScope from \"../lib/rootScope\";\r\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\r\nimport appDocsManager, {MyDocument} from \"../lib/appManagers/appDocsManager\";\r\nimport { CancellablePromise, deferredPromise } from \"../helpers/cancellablePromise\";\r\nimport { IS_APPLE, IS_SAFARI } from \"../environment/userAgent\";\r\nimport { MOUNT_CLASS_TO } from \"../config/debug\";\r\nimport appDownloadManager from \"../lib/appManagers/appDownloadManager\";\r\nimport simulateEvent from \"../helpers/dom/dispatchEvent\";\r\nimport type { SearchSuperContext } from \"./appSearchSuper.\";\r\nimport { copy, deepEqual } from \"../helpers/object\";\r\nimport { DocumentAttribute, Message, MessageMedia, PhotoSize } from \"../layer\";\r\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\r\nimport appAvatarsManager from \"../lib/appManagers/appAvatarsManager\";\r\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport I18n from \"../lib/langPack\";\r\nimport SearchListLoader from \"../helpers/searchListLoader\";\r\nimport { onMediaLoad } from \"../helpers/files\";\r\n\r\n// TODO: Safari: проверить стрим, включить его и сразу попробовать включить видео или другую песню\r\n// TODO: Safari: попробовать замаскировать подгрузку последнего чанка\r\n// TODO: Safari: пофиксить момент, когда заканчивается песня и пытаешься включить её заново - прогресс сразу в конце\r\n\r\nexport type MediaItem = {mid: number, peerId: number};\r\n\r\ntype HTMLMediaElement = HTMLAudioElement | HTMLVideoElement;\r\n\r\nconst SHOULD_USE_SAFARI_FIX = (() => {\r\n try {\r\n return IS_SAFARI && +navigator.userAgent.match(/ Version\\/(\\d+)/)[1] < 14;\r\n } catch(err) {\r\n return false;\r\n }\r\n})();\r\n\r\nconst SEEK_OFFSET = 10;\r\n\r\nexport type MediaSearchContext = SearchSuperContext & Partial<{\r\n isScheduled: boolean,\r\n useSearch: boolean\r\n}>;\r\n\r\ntype MediaDetails = {\r\n peerId: number, \r\n mid: number, \r\n docId: string, \r\n clean?: boolean,\r\n isScheduled?: boolean, \r\n isSingle?: boolean\r\n};\r\n\r\nclass AppMediaPlaybackController {\r\n private container: HTMLElement;\r\n private media: Map<number, Map<number, HTMLMediaElement>> = new Map();\r\n private scheduled: AppMediaPlaybackController['media'] = new Map();\r\n private mediaDetails: Map<HTMLMediaElement, MediaDetails> = new Map();\r\n private playingMedia: HTMLMediaElement;\r\n\r\n private waitingMediaForLoad: Map<number, Map<number, CancellablePromise<void>>> = new Map();\r\n private waitingScheduledMediaForLoad: AppMediaPlaybackController['waitingMediaForLoad'] = new Map();\r\n private waitingDocumentsForLoad: {[docId: string]: Set<HTMLMediaElement>} = {};\r\n \r\n public willBePlayedMedia: HTMLMediaElement;\r\n private searchContext: MediaSearchContext;\r\n\r\n private listLoader: SearchListLoader<MediaItem>;\r\n\r\n public volume: number;\r\n public muted: boolean;\r\n public playbackRate: number;\r\n private _volume = 1;\r\n private _muted = false;\r\n private _playbackRate = 1;\r\n private lockedSwitchers: boolean;\r\n\r\n constructor() {\r\n this.container = document.createElement('div');\r\n //this.container.style.cssText = 'position: absolute; top: -10000px; left: -10000px;';\r\n this.container.style.cssText = 'display: none;';\r\n document.body.append(this.container);\r\n\r\n if(navigator.mediaSession) {\r\n const actions: {[action in MediaSessionAction]?: MediaSessionActionHandler} = {\r\n play: this.play,\r\n pause: this.pause,\r\n stop: this.stop,\r\n seekbackward: this.seekBackward,\r\n seekforward: this.seekForward,\r\n seekto: this.seekTo,\r\n previoustrack: this.previous,\r\n nexttrack: this.next\r\n };\r\n\r\n for(const action in actions) {\r\n try {\r\n navigator.mediaSession.setActionHandler(action as MediaSessionAction, actions[action as MediaSessionAction]);\r\n } catch(err) {\r\n console.warn('MediaSession action is not supported:', action);\r\n }\r\n }\r\n }\r\n\r\n rootScope.addEventListener('document_downloaded', (doc) => {\r\n const set = this.waitingDocumentsForLoad[doc.id];\r\n if(set) {\r\n for(const media of set) {\r\n this.onMediaDocumentLoad(media);\r\n }\r\n }\r\n });\r\n\r\n const properties: {[key: PropertyKey]: PropertyDescriptor} = {};\r\n const keys = [\r\n 'volume' as const, \r\n 'muted' as const, \r\n 'playbackRate' as const\r\n ];\r\n keys.forEach(key => {\r\n const _key = ('_' + key) as `_${typeof key}`;\r\n properties[key] = {\r\n get: () => this[_key],\r\n set: (value: number | boolean) => {\r\n if(this[_key] === value) {\r\n return;\r\n }\r\n\r\n // @ts-ignore\r\n this[_key] = value;\r\n if(this.playingMedia) {\r\n // @ts-ignore\r\n this.playingMedia[key] = value;\r\n }\r\n\r\n this.dispatchPlaybackParams();\r\n }\r\n };\r\n });\r\n Object.defineProperties(this, properties);\r\n }\r\n\r\n private dispatchPlaybackParams() {\r\n const {volume, muted, playbackRate} = this;\r\n rootScope.dispatchEvent('media_playback_params', {\r\n volume, muted, playbackRate\r\n });\r\n }\r\n\r\n public seekBackward = (details: MediaSessionActionDetails) => {\r\n const media = this.playingMedia;\r\n if(media) {\r\n media.currentTime = Math.max(0, media.currentTime - (details.seekOffset || SEEK_OFFSET));\r\n }\r\n };\r\n\r\n public seekForward = (details: MediaSessionActionDetails) => {\r\n const media = this.playingMedia;\r\n if(media) {\r\n media.currentTime = Math.min(media.duration, media.currentTime + (details.seekOffset || SEEK_OFFSET));\r\n }\r\n };\r\n\r\n public seekTo = (details: MediaSessionActionDetails) => {\r\n const media = this.playingMedia;\r\n if(media) {\r\n media.currentTime = details.seekTime;\r\n }\r\n };\r\n\r\n public addMedia(message: Message.message, autoload: boolean, clean?: boolean): HTMLMediaElement {\r\n const {peerId, mid} = message;\r\n\r\n const isScheduled = !!message.pFlags.is_scheduled;\r\n const s = isScheduled ? this.scheduled : this.media;\r\n let storage = s.get(message.peerId);\r\n if(!storage) {\r\n s.set(message.peerId, storage = new Map());\r\n }\r\n\r\n let media = storage.get(mid);\r\n if(media) {\r\n return media;\r\n }\r\n\r\n const doc: MyDocument = appMessagesManager.getMediaFromMessage(message);\r\n storage.set(mid, media = document.createElement(doc.type === 'round' || doc.type === 'video' ? 'video' : 'audio'));\r\n //const source = document.createElement('source');\r\n //source.type = doc.type === 'voice' && !opusDecodeController.isPlaySupported() ? 'audio/wav' : doc.mime_type;\r\n\r\n if(doc.type === 'round') {\r\n media.setAttribute('playsinline', 'true');\r\n //media.muted = true;\r\n }\r\n\r\n const details: MediaDetails = {\r\n peerId,\r\n mid,\r\n docId: doc.id,\r\n clean,\r\n isScheduled: message.pFlags.is_scheduled\r\n };\r\n\r\n this.mediaDetails.set(media, details);\r\n\r\n //media.autoplay = true;\r\n media.volume = 1;\r\n //media.append(source);\r\n\r\n this.container.append(media);\r\n\r\n media.addEventListener('play', this.onPlay);\r\n media.addEventListener('pause', this.onPause);\r\n media.addEventListener('ended', this.onEnded);\r\n\r\n if(doc.type !== 'audio' && message?.pFlags.media_unread && message.fromId !== rootScope.myId) {\r\n media.addEventListener('timeupdate', () => {\r\n appMessagesManager.readMessages(peerId, [mid]);\r\n }, {once: true});\r\n }\r\n \r\n /* const onError = (e: Event) => {\r\n //console.log('appMediaPlaybackController: video onError', e);\r\n\r\n if(this.nextMid === mid) {\r\n this.loadSiblingsMedia(peerId, doc.type as MediaType, mid).then(() => {\r\n if(this.nextMid && storage[this.nextMid]) {\r\n storage[this.nextMid].play();\r\n }\r\n });\r\n }\r\n };\r\n\r\n media.addEventListener('error', onError); */\r\n\r\n const deferred = deferredPromise<void>();\r\n if(autoload) {\r\n deferred.resolve();\r\n } else {\r\n const w = message.pFlags.is_scheduled ? this.waitingScheduledMediaForLoad : this.waitingMediaForLoad;\r\n let waitingStorage = w.get(peerId);\r\n if(!waitingStorage) {\r\n w.set(peerId, waitingStorage = new Map());\r\n }\r\n\r\n waitingStorage.set(mid, deferred);\r\n }\r\n\r\n deferred.then(() => {\r\n //media.autoplay = true;\r\n //console.log('will set media url:', media, doc, doc.type, doc.url);\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n if(doc.supportsStreaming || cacheContext.url) {\r\n this.onMediaDocumentLoad(media);\r\n } else {\r\n let set = this.waitingDocumentsForLoad[doc.id];\r\n if(!set) {\r\n set = this.waitingDocumentsForLoad[doc.id] = new Set();\r\n }\r\n\r\n set.add(media);\r\n appDocsManager.downloadDoc(doc);\r\n }\r\n }/* , onError */);\r\n \r\n return media;\r\n }\r\n\r\n public getMedia(peerId: number, mid: number, isScheduled?: boolean) {\r\n const s = (isScheduled ? this.scheduled : this.media).get(peerId);\r\n return s?.get(mid);\r\n }\r\n\r\n private onMediaDocumentLoad = (media: HTMLMediaElement) => {\r\n const details = this.mediaDetails.get(media);\r\n const doc = appDocsManager.getDoc(details.docId);\r\n if(doc.type === 'audio' && doc.supportsStreaming && SHOULD_USE_SAFARI_FIX) {\r\n this.handleSafariStreamable(media);\r\n }\r\n\r\n // setTimeout(() => {\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n media.src = cacheContext.url;\r\n // }, doc.supportsStreaming ? 500e3 : 0);\r\n\r\n const set = this.waitingDocumentsForLoad[doc.id];\r\n if(set) {\r\n set.delete(media);\r\n\r\n if(!set.size) {\r\n delete this.waitingDocumentsForLoad[doc.id];\r\n }\r\n }\r\n };\r\n\r\n // safari подгрузит последний чанк и песня включится,\r\n // при этом этот чанк нельзя руками отдать из SW, потому что браузер тогда теряется\r\n private handleSafariStreamable(media: HTMLMediaElement) {\r\n media.addEventListener('play', () => {\r\n /* if(media.readyState === 4) { // https://developer.mozilla.org/ru/docs/Web/API/XMLHttpRequest/readyState\r\n return;\r\n } */\r\n\r\n //media.volume = 0;\r\n const currentTime = media.currentTime;\r\n //this.setSafariBuffering(media, true);\r\n\r\n media.addEventListener('progress', () => {\r\n media.currentTime = media.duration - 1;\r\n\r\n media.addEventListener('progress', () => {\r\n media.currentTime = currentTime;\r\n //media.volume = 1;\r\n //this.setSafariBuffering(media, false);\r\n\r\n if(!media.paused) {\r\n media.play()/* .catch(() => {}) */;\r\n }\r\n }, {once: true});\r\n }, {once: true});\r\n }/* , {once: true} */);\r\n }\r\n\r\n public resolveWaitingForLoadMedia(peerId: number, mid: number, isScheduled?: boolean) {\r\n const w = isScheduled ? this.waitingScheduledMediaForLoad : this.waitingMediaForLoad;\r\n const storage = w.get(peerId);\r\n if(!storage) {\r\n return;\r\n }\r\n\r\n const promise = storage.get(mid);\r\n if(promise) {\r\n promise.resolve();\r\n storage.delete(mid);\r\n\r\n if(!storage.size) {\r\n w.delete(peerId);\r\n }\r\n }\r\n }\r\n \r\n /**\r\n * Only for audio\r\n */\r\n public isSafariBuffering(media: HTMLMediaElement) {\r\n /// @ts-ignore\r\n return !!media.safariBuffering;\r\n }\r\n\r\n private setSafariBuffering(media: HTMLMediaElement, value: boolean) {\r\n // @ts-ignore\r\n media.safariBuffering = value;\r\n }\r\n\r\n private async setNewMediadata(message: Message.message, playingMedia = this.playingMedia) {\r\n await onMediaLoad(playingMedia, undefined, false); // have to wait for load, otherwise on macOS won't set\r\n\r\n const doc = (message.media as MessageMedia.messageMediaDocument).document as MyDocument;\r\n \r\n const artwork: MediaImage[] = [];\r\n\r\n const isVoice = doc.type === 'voice' || doc.type === 'round';\r\n let title = '', artist = '';\r\n\r\n if(doc.thumbs?.length) {\r\n const size = doc.thumbs[doc.thumbs.length - 1];\r\n if(!(size as PhotoSize.photoStrippedSize).bytes) {\r\n const cacheContext = appDownloadManager.getCacheContext(doc, size.type);\r\n\r\n if(cacheContext.url) {\r\n artwork.push({\r\n src: cacheContext.url,\r\n sizes: `${(size as PhotoSize.photoSize).w}x${(size as PhotoSize.photoSize).h}`,\r\n type: 'image/jpeg'\r\n });\r\n } else {\r\n const download = appPhotosManager.preloadPhoto(doc, size);\r\n download.then(() => {\r\n if(this.playingMedia !== playingMedia || !cacheContext.url) {\r\n return;\r\n }\r\n\r\n this.setNewMediadata(message);\r\n });\r\n }\r\n }\r\n } else if(isVoice) {\r\n const peerId = message.fromId || message.peerId;\r\n const peerPhoto = appPeersManager.getPeerPhoto(peerId);\r\n if(peerPhoto) {\r\n const result = appAvatarsManager.loadAvatar(peerId, peerPhoto, 'photo_small');\r\n if(result.cached) {\r\n const url = await result.loadPromise;\r\n artwork.push({\r\n src: url,\r\n sizes: '160x160',\r\n type: 'image/jpeg'\r\n });\r\n } else {\r\n result.loadPromise.then((url) => {\r\n if(this.playingMedia !== playingMedia || !url) {\r\n return;\r\n }\r\n \r\n this.setNewMediadata(message);\r\n });\r\n }\r\n }\r\n\r\n title = appPeersManager.getPeerTitle(peerId, true, false);\r\n artist = I18n.format(doc.type === 'voice' ? 'AttachAudio' : 'AttachRound', true);\r\n }\r\n\r\n if(!isVoice) {\r\n const attribute = doc.attributes.find(attribute => attribute._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio;\r\n title = attribute && attribute.title || doc.file_name;\r\n artist = attribute && attribute.performer;\r\n }\r\n\r\n if(!artwork.length) {\r\n if(IS_APPLE) {\r\n if(IS_TOUCH_SUPPORTED) {\r\n artwork.push({\r\n src: `assets/img/apple-touch-icon-precomposed.png`,\r\n sizes: '180x180',\r\n type: 'image/png'\r\n });\r\n } else {\r\n artwork.push({\r\n src: `assets/img/apple-touch-icon.png`,\r\n sizes: '180x180',\r\n type: 'image/png'\r\n });\r\n }\r\n } else {\r\n [72, 96, 144, 192, 256, 384, 512].forEach(size => {\r\n const sizes = `${size}x${size}`;\r\n artwork.push({\r\n src: `assets/img/android-chrome-${sizes}.png`,\r\n sizes,\r\n type: 'image/png'\r\n });\r\n });\r\n }\r\n }\r\n\r\n const metadata = new MediaMetadata({\r\n title,\r\n artist,\r\n artwork\r\n });\r\n\r\n navigator.mediaSession.metadata = metadata;\r\n }\r\n\r\n private getMessageByMedia(media: HTMLMediaElement) {\r\n const details = this.mediaDetails.get(media);\r\n const {peerId, mid} = details;\r\n const message = details.isScheduled ? appMessagesManager.getScheduledMessageByPeer(peerId, mid) : appMessagesManager.getMessageByPeer(peerId, mid);\r\n return message;\r\n }\r\n\r\n private onPlay = (e?: Event) => {\r\n const media = e.target as HTMLMediaElement;\r\n const details = this.mediaDetails.get(media);\r\n const {peerId, mid} = details;\r\n\r\n //console.log('appMediaPlaybackController: video playing', this.currentPeerId, this.playingMedia, media);\r\n\r\n const message = this.getMessageByMedia(media);\r\n\r\n const previousMedia = this.playingMedia;\r\n if(previousMedia !== media) {\r\n this.stop();\r\n\r\n const verify = (element: MediaItem) => element.mid === mid && element.peerId === peerId;\r\n if(!this.listLoader.current || !verify(this.listLoader.current)) {\r\n let idx = this.listLoader.previous.findIndex(verify);\r\n let jumpLength: number;\r\n if(idx !== -1) {\r\n jumpLength = -(this.listLoader.previous.length - idx);\r\n } else {\r\n idx = this.listLoader.next.findIndex(verify);\r\n if(idx !== -1) {\r\n jumpLength = idx + 1;\r\n }\r\n }\r\n \r\n if(idx !== -1) {\r\n if(jumpLength) {\r\n this.listLoader.go(jumpLength, false);\r\n }\r\n } else {\r\n this.setTargets({peerId, mid});\r\n }\r\n }\r\n\r\n this.setMedia(media, message);\r\n }\r\n\r\n // audio_pause не успеет сработать без таймаута\r\n setTimeout(() => {\r\n rootScope.dispatchEvent('media_play', {doc: appMessagesManager.getMediaFromMessage(message), message, media});\r\n }, 0);\r\n };\r\n\r\n private onPause = (e?: Event) => {\r\n /* const target = e.target as HTMLMediaElement;\r\n if(!isInDOM(target)) {\r\n this.container.append(target);\r\n target.play();\r\n return;\r\n } */\r\n\r\n rootScope.dispatchEvent('media_pause');\r\n };\r\n\r\n private onEnded = (e?: Event) => {\r\n if(!e.isTrusted) {\r\n return;\r\n }\r\n\r\n this.onPause(e);\r\n\r\n //console.log('on media end');\r\n\r\n if(!this.next()) {\r\n this.stop();\r\n rootScope.dispatchEvent('media_stop');\r\n }\r\n };\r\n\r\n public toggle(play?: boolean) {\r\n if(!this.playingMedia) {\r\n return false;\r\n }\r\n\r\n if(play === undefined) {\r\n play = this.playingMedia.paused;\r\n }\r\n\r\n if(this.playingMedia.paused !== play) {\r\n return false;\r\n }\r\n\r\n if(play) {\r\n this.playingMedia.play();\r\n } else {\r\n this.playingMedia.pause();\r\n }\r\n\r\n return true;\r\n }\r\n\r\n public play = () => {\r\n return this.toggle(true);\r\n };\r\n\r\n public pause = () => {\r\n return this.toggle(false);\r\n };\r\n\r\n public stop = () => {\r\n const media = this.playingMedia;\r\n if(!media) {\r\n return false;\r\n }\r\n\r\n if(!media.paused) {\r\n media.pause();\r\n }\r\n\r\n media.currentTime = 0;\r\n simulateEvent(media, 'ended');\r\n\r\n const details = this.mediaDetails.get(media);\r\n if(details?.clean) {\r\n media.src = '';\r\n const peerId = details.peerId;\r\n const s = details.isScheduled ? this.scheduled : this.media;\r\n const storage = s.get(peerId);\r\n if(storage) {\r\n storage.delete(details.mid);\r\n \r\n if(!storage.size) {\r\n s.delete(peerId);\r\n }\r\n }\r\n \r\n media.remove();\r\n\r\n this.mediaDetails.delete(media);\r\n }\r\n\r\n this.playingMedia = undefined;\r\n\r\n return true;\r\n };\r\n\r\n public playItem = (item: MediaItem) => {\r\n const {peerId, mid} = item;\r\n const isScheduled = this.searchContext.isScheduled;\r\n const media = this.getMedia(peerId, mid, isScheduled);\r\n\r\n /* if(isSafari) {\r\n media.autoplay = true;\r\n } */\r\n\r\n media.play();\r\n \r\n setTimeout(() => {\r\n this.resolveWaitingForLoadMedia(peerId, mid, isScheduled);\r\n }, 0);\r\n };\r\n\r\n public next = () => {\r\n return !this.lockedSwitchers && this.listLoader.go(1);\r\n };\r\n\r\n public previous = () => {\r\n const media = this.playingMedia;\r\n if(media && media.currentTime > 5) {\r\n media.currentTime = 0;\r\n this.toggle(true);\r\n return;\r\n }\r\n\r\n return !this.lockedSwitchers && this.listLoader.go(-1);\r\n };\r\n\r\n public willBePlayed(media: HTMLMediaElement) {\r\n this.willBePlayedMedia = media;\r\n }\r\n\r\n public setSearchContext(context: MediaSearchContext) {\r\n if(deepEqual(this.searchContext, context)) {\r\n return false;\r\n }\r\n\r\n this.searchContext = copy(context); // {_: type === 'audio' ? 'inputMessagesFilterMusic' : 'inputMessagesFilterRoundVoice'}\r\n return true;\r\n }\r\n\r\n public getSearchContext() {\r\n return this.searchContext;\r\n }\r\n\r\n public setTargets(current: MediaItem, prev?: MediaItem[], next?: MediaItem[]) {\r\n if(!this.listLoader) {\r\n this.listLoader = new SearchListLoader({\r\n loadCount: 10,\r\n loadWhenLeft: 5,\r\n processItem: (message: Message.message) => {\r\n this.addMedia(message, false);\r\n return {peerId: message.peerId, mid: message.mid};\r\n },\r\n onJump: (item, older) => {\r\n this.playItem(item);\r\n },\r\n onEmptied: () => {\r\n rootScope.dispatchEvent('media_stop');\r\n this.stop();\r\n }\r\n });\r\n } else {\r\n this.listLoader.reset();\r\n }\r\n\r\n const reverse = this.searchContext.folderId !== undefined ? false : true;\r\n if(prev) {\r\n this.listLoader.setTargets(prev, next, reverse);\r\n } else {\r\n this.listLoader.reverse = reverse;\r\n }\r\n\r\n this.listLoader.setSearchContext(this.searchContext);\r\n this.listLoader.current = current;\r\n\r\n this.listLoader.load(true);\r\n this.listLoader.load(false);\r\n }\r\n\r\n public setMedia(media: HTMLMediaElement, message: Message.message) {\r\n this.playingMedia = media;\r\n this.playingMedia.volume = this.volume;\r\n this.playingMedia.muted = this.muted;\r\n this.playingMedia.playbackRate = this.playbackRate;\r\n\r\n if('mediaSession' in navigator) {\r\n this.setNewMediadata(message);\r\n }\r\n }\r\n\r\n public setSingleMedia(media?: HTMLMediaElement, message?: Message.message) {\r\n const playingMedia = this.playingMedia;\r\n\r\n const wasPlaying = this.pause();\r\n\r\n this.willBePlayed(undefined);\r\n if(media) this.setMedia(media, message);\r\n else this.playingMedia = undefined;\r\n this.toggleSwitchers(false);\r\n\r\n return () => {\r\n this.toggleSwitchers(true);\r\n\r\n if(playingMedia) {\r\n if(this.mediaDetails.get(playingMedia)) {\r\n this.setMedia(playingMedia, this.getMessageByMedia(playingMedia));\r\n } else {\r\n this.next() || this.previous();\r\n }\r\n }\r\n\r\n if(media && this.playingMedia === media) {\r\n this.stop();\r\n }\r\n\r\n if(wasPlaying) {\r\n this.play();\r\n }\r\n };\r\n }\r\n\r\n public toggleSwitchers(enabled: boolean) {\r\n this.lockedSwitchers = !enabled;\r\n }\r\n}\r\n\r\nconst appMediaPlaybackController = new AppMediaPlaybackController();\r\nMOUNT_CLASS_TO.appMediaPlaybackController = appMediaPlaybackController;\r\nexport default appMediaPlaybackController;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport type GrabEvent = {x: number, y: number, isTouch?: boolean, event: TouchEvent | MouseEvent};\r\n\r\nexport default function attachGrabListeners(element: HTMLElement, \r\n onStart: (position: GrabEvent) => void, \r\n onMove: (position: GrabEvent) => void, \r\n onEnd?: (position: GrabEvent) => void) {\r\n // * Mouse\r\n const onMouseMove = (event: MouseEvent) => {\r\n onMove({x: event.pageX, y: event.pageY, event});\r\n };\r\n\r\n const onMouseUp = (event: MouseEvent) => {\r\n document.removeEventListener('mousemove', onMouseMove);\r\n element.addEventListener('mousedown', onMouseDown, {once: true});\r\n onEnd && onEnd({x: event.pageX, y: event.pageY, event});\r\n };\r\n\r\n const onMouseDown = (event: MouseEvent) => {\r\n if(event.button !== 0) {\r\n element.addEventListener('mousedown', onMouseDown, {once: true});\r\n return;\r\n }\r\n\r\n onStart({x: event.pageX, y: event.pageY, event});\r\n onMouseMove(event);\r\n\r\n document.addEventListener('mousemove', onMouseMove);\r\n document.addEventListener('mouseup', onMouseUp, {once: true});\r\n };\r\n\r\n element.addEventListener('mousedown', onMouseDown, {once: true});\r\n\r\n // * Touch\r\n const onTouchMove = (event: TouchEvent) => {\r\n event.preventDefault();\r\n onMove({x: event.touches[0].clientX, y: event.touches[0].clientY, isTouch: true, event});\r\n };\r\n\r\n const onTouchEnd = (event: TouchEvent) => {\r\n document.removeEventListener('touchmove', onTouchMove);\r\n element.addEventListener('touchstart', onTouchStart, {passive: false, once: true});\r\n onEnd && onEnd({x: event.touches[0].clientX, y: event.touches[0].clientY, isTouch: true, event});\r\n };\r\n\r\n const onTouchStart = (event: TouchEvent) => {\r\n onStart({x: event.touches[0].clientX, y: event.touches[0].clientY, isTouch: true, event});\r\n onTouchMove(event);\r\n\r\n document.addEventListener('touchmove', onTouchMove, {passive: false});\r\n document.addEventListener('touchend', onTouchEnd, {passive: false, once: true});\r\n };\r\n\r\n element.addEventListener('touchstart', onTouchStart, {passive: false, once: true});\r\n\r\n return () => {\r\n element.removeEventListener('mousedown', onMouseDown);\r\n document.removeEventListener('mousemove', onMouseMove);\r\n document.removeEventListener('mouseup', onMouseUp);\r\n\r\n element.removeEventListener('touchstart', onTouchStart);\r\n document.removeEventListener('touchmove', onTouchMove);\r\n document.removeEventListener('touchend', onTouchEnd);\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { clamp } from \"../helpers/number\";\r\nimport attachGrabListeners, { GrabEvent } from \"../helpers/dom/attachGrabListeners\";\r\nimport { safeAssign } from \"../helpers/object\";\r\n\r\nexport default class RangeSelector {\r\n public container: HTMLDivElement;\r\n protected filled: HTMLDivElement;\r\n protected seek: HTMLInputElement;\r\n\r\n public mousedown = false;\r\n protected rect: DOMRect;\r\n protected _removeListeners: () => void;\r\n\r\n private events: Partial<{\r\n //onMouseMove: ProgressLine['onMouseMove'],\r\n onMouseDown: RangeSelector['onMouseDown'],\r\n onMouseUp: RangeSelector['onMouseUp'],\r\n onScrub: (value: number) => void\r\n }> = {};\r\n\r\n protected decimals: number;\r\n\r\n protected step: number;\r\n protected min: number;\r\n protected max: number;\r\n protected withTransition = false;\r\n protected useTransform = false;\r\n protected vertical = false;\r\n\r\n constructor(\r\n options: {\r\n step: RangeSelector['step'],\r\n min: RangeSelector['min'],\r\n max: RangeSelector['max'],\r\n withTransition?: RangeSelector['withTransition'],\r\n useTransform?: RangeSelector['useTransform'],\r\n vertical?: RangeSelector['vertical']\r\n }, \r\n value = 0\r\n ) {\r\n safeAssign(this, options);\r\n\r\n this.container = document.createElement('div');\r\n this.container.classList.add('progress-line');\r\n\r\n // there is no sense in using transition with transform, because it is updating every frame\r\n if(this.useTransform) {\r\n this.container.classList.add('use-transform');\r\n } else if(this.withTransition) {\r\n this.container.classList.add('with-transition');\r\n }\r\n\r\n this.filled = document.createElement('div');\r\n this.filled.classList.add('progress-line__filled');\r\n\r\n const seek = this.seek = document.createElement('input');\r\n seek.classList.add('progress-line__seek');\r\n //seek.setAttribute('max', '0');\r\n seek.type = 'range';\r\n seek.step = '' + this.step;\r\n seek.min = '' + this.min;\r\n seek.max = '' + this.max;\r\n seek.value = '' + value;\r\n\r\n if(value) {\r\n this.setProgress(value);\r\n }\r\n\r\n const stepStr = '' + this.step;\r\n const index = stepStr.indexOf('.');\r\n this.decimals = index === -1 ? 0 : stepStr.length - index - 1;\r\n\r\n //this.setListeners();\r\n\r\n this.container.append(this.filled, seek);\r\n }\r\n\r\n get value() {\r\n return +this.seek.value;\r\n }\r\n\r\n public setHandlers(events: RangeSelector['events']) {\r\n this.events = events;\r\n }\r\n\r\n protected onMouseMove = (event: GrabEvent) => {\r\n this.scrub(event);\r\n };\r\n\r\n protected onMouseDown = (event: GrabEvent) => {\r\n this.rect = this.container.getBoundingClientRect();\r\n this.mousedown = true;\r\n this.scrub(event);\r\n this.container.classList.add('is-focused');\r\n this.events?.onMouseDown && this.events.onMouseDown(event);\r\n };\r\n\r\n protected onMouseUp = (event: GrabEvent) => {\r\n this.mousedown = false;\r\n this.container.classList.remove('is-focused');\r\n this.events?.onMouseUp && this.events.onMouseUp(event);\r\n };\r\n\r\n public setListeners() {\r\n this.seek.addEventListener('input', this.onInput);\r\n this._removeListeners = attachGrabListeners(this.container, this.onMouseDown, this.onMouseMove, this.onMouseUp);\r\n }\r\n\r\n public onInput = () => {\r\n const value = +this.seek.value;\r\n this.setFilled(value);\r\n this.events?.onScrub && this.events.onScrub(value);\r\n };\r\n\r\n public setProgress(value: number) {\r\n this.seek.value = '' + value;\r\n this.setFilled(+this.seek.value); // clamp\r\n }\r\n\r\n public addProgress(value: number) {\r\n this.seek.value = '' + (+this.seek.value + value);\r\n this.setFilled(+this.seek.value); // clamp\r\n }\r\n\r\n public setFilled(value: number) {\r\n let percents = (value - this.min) / (this.max - this.min);\r\n percents = clamp(percents, 0, 1);\r\n \r\n // using scaleX and width even with vertical because it will be rotated\r\n if(this.useTransform) {\r\n this.filled.style.transform = `scaleX(${percents})`;\r\n } else {\r\n this.filled.style.width = (percents * 100) + '%';\r\n }\r\n }\r\n\r\n protected scrub(event: GrabEvent) {\r\n const rectMax = this.vertical ? this.rect.height : this.rect.width;\r\n const offsetAxisValue = clamp(this.vertical ? -(event.y - this.rect.bottom) : event.x - this.rect.left, 0, rectMax);\r\n\r\n let value = this.min + (offsetAxisValue / rectMax * (this.max - this.min));\r\n\r\n if((value - this.min) < ((this.max - this.min) / 2)) {\r\n value -= this.step / 10;\r\n }\r\n \r\n value = +value.toFixed(this.decimals);\r\n value = clamp(value, this.min, this.max);\r\n\r\n //this.seek.value = '' + value;\r\n //this.onInput();\r\n\r\n this.setProgress(value);\r\n this.events?.onScrub && this.events.onScrub(value);\r\n\r\n return value;\r\n }\r\n\r\n public removeListeners() {\r\n if(this._removeListeners) {\r\n this._removeListeners();\r\n this._removeListeners = null;\r\n }\r\n\r\n this.seek.removeEventListener('input', this.onInput);\r\n \r\n this.events = {};\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\nimport { AttachClickOptions, attachClickEvent, CLICK_EVENT_NAME } from \"../helpers/dom/clickEvent\";\nimport ListenerSetter from \"../helpers/listenerSetter\";\nimport { i18n, LangPackKey } from \"../lib/langPack\";\nimport CheckboxField from \"./checkboxField\";\nimport { closeBtnMenu } from \"./misc\";\nimport { ripple } from \"./ripple\";\n\nexport type ButtonMenuItemOptions = {\n icon?: string, \n text?: LangPackKey, \n regularText?: string, \n onClick: (e: MouseEvent | TouchEvent) => void, \n element?: HTMLElement,\n options?: AttachClickOptions,\n checkboxField?: CheckboxField,\n keepOpen?: boolean\n /* , cancelEvent?: true */\n};\n\nconst ButtonMenuItem = (options: ButtonMenuItemOptions) => {\n if(options.element) return options.element;\n\n const {icon, text, onClick} = options;\n const el = document.createElement('div');\n el.className = 'btn-menu-item' + (icon ? ' tgico-' + icon : '');\n ripple(el);\n\n const t = text ? i18n(text) : document.createElement('span');\n if(options.regularText) t.innerHTML = options.regularText;\n t.classList.add('btn-menu-item-text');\n el.append(t);\n\n if(options.checkboxField) {\n el.append(options.checkboxField.label);\n attachClickEvent(el, () => {\n options.checkboxField.checked = !options.checkboxField.checked;\n }, options.options);\n }\n\n const keepOpen = !!options.checkboxField || !!options.keepOpen;\n\n // * cancel mobile keyboard close\n attachClickEvent(el, CLICK_EVENT_NAME !== 'click' || keepOpen ? (e) => {\n cancelEvent(e);\n onClick(e);\n\n if(!keepOpen) {\n closeBtnMenu();\n }\n } : onClick, options.options);\n\n return options.element = el;\n};\n\nconst ButtonMenu = (buttons: ButtonMenuItemOptions[], listenerSetter?: ListenerSetter) => {\n const el = document.createElement('div');\n el.classList.add('btn-menu');\n\n if(listenerSetter) {\n buttons.forEach(b => {\n if(b.options) {\n b.options.listenerSetter = listenerSetter;\n } else {\n b.options = {listenerSetter};\n }\n });\n }\n\n const items = buttons.map(ButtonMenuItem);\n\n el.append(...items);\n\n return el;\n};\n\nexport default ButtonMenu;\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport { AttachClickOptions, CLICK_EVENT_NAME } from \"../helpers/dom/clickEvent\";\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\nimport ButtonIcon from \"./buttonIcon\";\r\nimport ButtonMenu, { ButtonMenuItemOptions } from \"./buttonMenu\";\r\nimport { closeBtnMenu, openBtnMenu } from \"./misc\";\r\n\r\nconst ButtonMenuToggle = (options: Partial<{noRipple: true, onlyMobile: true, listenerSetter: ListenerSetter, asDiv: boolean}> = {}, direction: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right', buttons: ButtonMenuItemOptions[], onOpen?: (e: Event) => void) => {\r\n options.asDiv = true;\r\n const button = ButtonIcon('more btn-menu-toggle', options);\r\n\r\n const btnMenu = ButtonMenu(buttons, options.listenerSetter);\r\n btnMenu.classList.add(direction);\r\n ButtonMenuToggleHandler(button, onOpen, options);\r\n button.append(btnMenu);\r\n return button;\r\n};\r\n\r\n// TODO: refactor for attachClickEvent, because if move finger after touchstart, it will start anyway\r\nconst ButtonMenuToggleHandler = (el: HTMLElement, onOpen?: (e: Event) => void, options?: AttachClickOptions) => {\r\n const add = options?.listenerSetter ? options.listenerSetter.add(el) : el.addEventListener.bind(el);\r\n\r\n //console.trace('ButtonMenuToggleHandler attach', el, onOpen, options);\r\n add(CLICK_EVENT_NAME, (e: Event) => {\r\n //console.log('ButtonMenuToggleHandler click', e);\r\n if(!el.classList.contains('btn-menu-toggle')) return false;\r\n\r\n //window.removeEventListener('mousemove', onMouseMove);\r\n const openedMenu = el.querySelector('.btn-menu') as HTMLDivElement;\r\n cancelEvent(e);\r\n\r\n if(el.classList.contains('menu-open')) {\r\n closeBtnMenu();\r\n } else {\r\n onOpen && onOpen(e);\r\n openBtnMenu(openedMenu);\r\n }\r\n });\r\n};\r\n\r\nexport { ButtonMenuToggleHandler };\r\nexport default ButtonMenuToggle;\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appMediaPlaybackController from \"../components/appMediaPlaybackController\";\nimport { IS_APPLE_MOBILE } from \"../environment/userAgent\";\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\nimport RangeSelector from \"../components/rangeSelector\";\nimport { onMediaLoad } from \"../helpers/files\";\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\nimport ListenerSetter from \"../helpers/listenerSetter\";\nimport ButtonMenu from \"../components/buttonMenu\";\nimport { ButtonMenuToggleHandler } from \"../components/buttonMenuToggle\";\nimport EventListenerBase from \"../helpers/eventListenerBase\";\nimport rootScope from \"./rootScope\";\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\nimport { GrabEvent } from \"../helpers/dom/attachGrabListeners\";\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\n\nexport class MediaProgressLine extends RangeSelector {\n protected filledLoad: HTMLDivElement;\n\n protected progressRAF = 0;\n\n protected media: HTMLMediaElement;\n protected streamable: boolean;\n\n constructor(media?: HTMLAudioElement | HTMLVideoElement, streamable?: boolean, withTransition?: boolean, useTransform?: boolean) {\n super({\n step: 1000 / 60 / 1000, \n min: 0, \n max: 1, \n withTransition, \n useTransform\n }, 0);\n\n if(media) {\n this.setMedia(media, streamable);\n }\n }\n\n public setMedia(media: HTMLMediaElement, streamable = false) {\n if(this.media) {\n this.removeListeners();\n }\n\n if(streamable && !this.filledLoad) {\n this.filledLoad = document.createElement('div');\n this.filledLoad.classList.add('progress-line__filled', 'progress-line__loaded');\n this.container.prepend(this.filledLoad);\n //this.setLoadProgress();\n } else if(this.filledLoad) {\n this.filledLoad.classList.toggle('hide', !streamable);\n }\n\n this.media = media;\n this.streamable = streamable;\n if(!media.paused || media.currentTime > 0) {\n this.onPlay();\n }\n\n let wasPlaying = false;\n this.setSeekMax();\n this.setListeners();\n this.setHandlers({\n onMouseDown: () => {\n wasPlaying = !this.media.paused;\n wasPlaying && this.media.pause();\n },\n\n onMouseUp: (e) => {\n // cancelEvent(e.event);\n wasPlaying && this.media.play();\n }\n });\n }\n\n protected onLoadedData = () => {\n this.max = this.media.duration;\n this.seek.setAttribute('max', '' + this.max);\n };\n\n protected onEnded = () => {\n this.setProgress();\n };\n\n protected onPlay = () => {\n let r = () => {\n this.setProgress();\n\n this.progressRAF = this.media.paused ? 0 : window.requestAnimationFrame(r);\n };\n\n if(this.progressRAF) {\n window.cancelAnimationFrame(this.progressRAF);\n }\n\n if(this.streamable) {\n this.setLoadProgress();\n }\n\n this.progressRAF = window.requestAnimationFrame(r);\n };\n\n protected onTimeUpdate = () => {\n if(this.media.paused) {\n this.setProgress();\n\n if(this.streamable) {\n this.setLoadProgress();\n }\n }\n };\n\n protected onProgress = (e: Event) => {\n this.setLoadProgress();\n };\n\n protected scrub(e: GrabEvent) {\n const scrubTime = super.scrub(e);\n this.media.currentTime = scrubTime;\n return scrubTime;\n }\n\n protected setLoadProgress() {\n if(appMediaPlaybackController.isSafariBuffering(this.media)) return;\n const buf = this.media.buffered;\n const numRanges = buf.length;\n\n const currentTime = this.media.currentTime;\n let nearestStart = 0, end = 0;\n for(let i = 0; i < numRanges; ++i) {\n const start = buf.start(i);\n if(currentTime >= start && start >= nearestStart) {\n nearestStart = start;\n end = buf.end(i);\n }\n\n //console.log('onProgress range:', i, buf.start(i), buf.end(i), this.media);\n }\n\n //console.log('onProgress correct range:', nearestStart, end, this.media);\n\n const percents = this.media.duration ? end / this.media.duration : 0;\n this.filledLoad.style.width = (percents * 100) + '%';\n //this.filledLoad.style.transform = 'scaleX(' + percents + ')';\n }\n\n protected setSeekMax() {\n this.max = this.media.duration || 0;\n if(this.max > 0) {\n this.onLoadedData();\n } else {\n this.media.addEventListener('loadeddata', this.onLoadedData);\n }\n }\n\n public setProgress() {\n if(appMediaPlaybackController.isSafariBuffering(this.media)) return;\n const currentTime = this.media.currentTime;\n\n super.setProgress(currentTime);\n }\n\n public setListeners() {\n super.setListeners();\n this.media.addEventListener('ended', this.onEnded);\n this.media.addEventListener('play', this.onPlay);\n this.media.addEventListener('timeupdate', this.onTimeUpdate);\n this.streamable && this.media.addEventListener('progress', this.onProgress);\n }\n\n public removeListeners() {\n super.removeListeners();\n\n this.media.removeEventListener('loadeddata', this.onLoadedData);\n this.media.removeEventListener('ended', this.onEnded);\n this.media.removeEventListener('play', this.onPlay);\n this.media.removeEventListener('timeupdate', this.onTimeUpdate);\n this.streamable && this.media.removeEventListener('progress', this.onProgress);\n\n if(this.progressRAF) {\n window.cancelAnimationFrame(this.progressRAF);\n this.progressRAF = 0;\n }\n }\n}\n\nexport class VolumeSelector extends RangeSelector {\n public btn: HTMLElement;\n protected volumeSvg: HTMLElement;\n\n constructor(protected listenerSetter: ListenerSetter, protected vertical = false) {\n super({\n step: 0.01, \n min: 0, \n max: 1,\n vertical\n }, 1);\n\n this.setListeners();\n this.setHandlers({\n onScrub: currentTime => {\n const value = Math.max(Math.min(currentTime, 1), 0);\n\n //console.log('volume scrub:', currentTime, value);\n\n appMediaPlaybackController.muted = false;\n appMediaPlaybackController.volume = value;\n },\n\n /* onMouseUp: (e) => {\n cancelEvent(e.event);\n } */\n });\n\n this.btn = document.createElement('div');\n this.btn.classList.add('player-volume');\n\n this.btn.innerHTML = `\n <svg class=\"player-volume__icon\" focusable=\"false\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"></svg>\n `;\n this.btn.classList.add('btn-icon');\n this.volumeSvg = this.btn.firstElementChild as HTMLElement;\n\n this.btn.append(this.container);\n\n attachClickEvent(this.volumeSvg, this.onMuteClick, {listenerSetter: this.listenerSetter});\n this.listenerSetter.add(rootScope)('media_playback_params', this.setVolume);\n\n this.setVolume();\n }\n\n private onMuteClick = (e?: Event) => {\n e && cancelEvent(e);\n appMediaPlaybackController.muted = !appMediaPlaybackController.muted;\n };\n\n private setVolume = () => {\n // const volume = video.volume;\n const {volume, muted} = appMediaPlaybackController;\n let d: string;\n if(!volume || muted) {\n d = `M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z`;\n } else if(volume > .5) {\n d = `M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z`;\n } else if(volume > 0 && volume < .25) {\n d = `M7 9v6h4l5 5V4l-5 5H7z`;\n } else {\n d = `M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z`;\n }\n\n try {\n this.volumeSvg.innerHTML = `<path d=\"${d}\"></path>`;\n } catch(err) {}\n\n if(!this.mousedown) {\n this.setProgress(muted ? 0 : volume);\n }\n };\n}\n\nexport default class VideoPlayer extends EventListenerBase<{\n toggleControls: (show: boolean) => void\n}> {\n private wrapper: HTMLDivElement;\n private progress: MediaProgressLine;\n private skin: 'default';\n\n private listenerSetter: ListenerSetter;\n\n private showControlsTimeout = 0;\n\n private controlsLocked: boolean;\n\n /* private videoParent: HTMLElement;\n private videoWhichChild: number; */\n\n constructor(private video: HTMLVideoElement, play = false, streamable = false, duration?: number) {\n super(false);\n\n this.wrapper = document.createElement('div');\n this.wrapper.classList.add('ckin__player');\n\n this.listenerSetter = new ListenerSetter();\n\n video.parentNode.insertBefore(this.wrapper, video);\n this.wrapper.appendChild(video);\n\n this.skin = 'default';\n\n this.stylePlayer(duration);\n // this.setBtnMenuToggle();\n\n if(this.skin === 'default') {\n const controls = this.wrapper.querySelector('.default__controls.ckin__controls') as HTMLDivElement;\n this.progress = new MediaProgressLine(video, streamable);\n controls.prepend(this.progress.container);\n }\n\n if(play/* && video.paused */) {\n const promise = video.play();\n promise.catch((err: Error) => {\n if(err.name === 'NotAllowedError') {\n video.muted = true;\n video.autoplay = true;\n video.play();\n }\n }).finally(() => { // due to autoplay, play will not call\n this.wrapper.classList.toggle('is-playing', !this.video.paused);\n });\n //(this.wrapper.querySelector('.toggle') as HTMLButtonElement).click();\n }\n }\n\n private stylePlayer(initDuration: number) {\n const {wrapper: player, video, skin} = this;\n\n player.classList.add(skin);\n \n const html = this.buildControls();\n player.insertAdjacentHTML('beforeend', html);\n let timeDuration: HTMLElement;\n \n if(skin === 'default') {\n const toggle = player.querySelectorAll('.toggle') as NodeListOf<HTMLElement>;\n const fullScreenButton = player.querySelector('.fullscreen') as HTMLElement;\n const timeElapsed = player.querySelector('#time-elapsed');\n timeDuration = player.querySelector('#time-duration') as HTMLElement;\n timeDuration.innerHTML = String(video.duration | 0).toHHMMSS();\n\n const volumeSelector = new VolumeSelector(this.listenerSetter);\n\n const leftControls = player.querySelector('.left-controls');\n leftControls.insertBefore(volumeSelector.btn, timeElapsed.parentElement);\n\n Array.from(toggle).forEach((button) => {\n this.listenerSetter.add(button)('click', () => {\n this.togglePlay();\n });\n });\n\n this.listenerSetter.add(video)('click', () => {\n if(!IS_TOUCH_SUPPORTED) {\n this.togglePlay();\n }\n });\n\n if(IS_TOUCH_SUPPORTED) {\n this.listenerSetter.add(player)('click', () => {\n this.toggleControls();\n });\n\n /* this.listenerSetter.add(player)('touchstart', () => {\n showControls(false);\n });\n\n this.listenerSetter.add(player)('touchend', () => {\n if(player.classList.contains('is-playing')) {\n showControls();\n }\n }); */\n } else {\n this.listenerSetter.add(this.wrapper)('mousemove', () => {\n this.showControls();\n });\n\n this.listenerSetter.add(this.wrapper)('mouseenter', () => {\n this.showControls(false);\n });\n\n this.listenerSetter.add(this.wrapper)('mouseleave', (e) => {\n if(findUpClassName(e.relatedTarget, 'media-viewer-caption')) {\n this.showControls(false);\n return;\n }\n \n this.hideControls();\n });\n\n this.listenerSetter.add(document)('keydown', (e: KeyboardEvent) => {\n if(rootScope.overlaysActive > 1) { // forward popup is active, etc\n return;\n }\n\n let good = true;\n if(e.code === 'KeyF') {\n this.toggleFullScreen(fullScreenButton);\n } else if(e.code === 'KeyM') {\n appMediaPlaybackController.muted = !appMediaPlaybackController.muted;\n } else if(e.code === 'Space') {\n this.togglePlay();\n } else if(e.altKey && e.code === 'Equal') {\n appMediaPlaybackController.playbackRate += .25;\n } else if(e.altKey && e.code === 'Minus') {\n appMediaPlaybackController.playbackRate -= .25;\n } else {\n good = false;\n }\n\n if(good) {\n cancelEvent(e);\n return false;\n }\n });\n }\n \n /* player.addEventListener('click', (e) => {\n if(e.target !== player) {\n return;\n }\n\n this.togglePlay();\n }); */\n \n /* video.addEventListener('play', () => {\n }); */\n\n this.listenerSetter.add(video)('dblclick', () => {\n if(!IS_TOUCH_SUPPORTED) {\n this.toggleFullScreen(fullScreenButton);\n }\n });\n\n this.listenerSetter.add(fullScreenButton)('click', (e) => {\n this.toggleFullScreen(fullScreenButton);\n });\n\n 'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange'.split(' ').forEach(eventName => {\n this.listenerSetter.add(player)(eventName, this.onFullScreen, false);\n });\n\n this.listenerSetter.add(video)('timeupdate', () => {\n timeElapsed.innerHTML = String(video.currentTime | 0).toHHMMSS();\n });\n\n this.listenerSetter.add(video)('play', () => {\n this.wrapper.classList.add('played');\n }, {once: true});\n\n this.listenerSetter.add(video)('pause', () => {\n this.showControls(false);\n });\n }\n\n this.listenerSetter.add(video)('play', () => {\n this.wrapper.classList.add('is-playing');\n });\n\n this.listenerSetter.add(video)('pause', () => {\n this.wrapper.classList.remove('is-playing');\n });\n \n if(video.duration || initDuration) {\n timeDuration.innerHTML = String(Math.round(video.duration || initDuration)).toHHMMSS();\n } else {\n onMediaLoad(video).then(() => {\n timeDuration.innerHTML = String(Math.round(video.duration)).toHHMMSS();\n });\n }\n }\n\n public hideControls = () => {\n clearTimeout(this.showControlsTimeout);\n this.showControlsTimeout = 0;\n\n const isShown = this.wrapper.classList.contains('show-controls');\n if(this.controlsLocked !== false) {\n if(this.video.paused || !isShown || this.controlsLocked) {\n return;\n }\n } else if(!isShown) {\n return;\n }\n \n this.dispatchEvent('toggleControls', false);\n this.wrapper.classList.remove('show-controls');\n };\n \n public showControls = (setHideTimeout = true) => {\n if(this.showControlsTimeout) {\n clearTimeout(this.showControlsTimeout);\n this.showControlsTimeout = 0;\n } else if(!this.wrapper.classList.contains('show-controls') && this.controlsLocked !== false) {\n this.dispatchEvent('toggleControls', true);\n this.wrapper.classList.add('show-controls');\n }\n\n if(!setHideTimeout || this.controlsLocked) {\n return;\n }\n\n this.showControlsTimeout = window.setTimeout(this.hideControls, 3e3);\n };\n\n public toggleControls = (show?: boolean) => {\n const isShown = this.wrapper.classList.contains('show-controls');\n\n if(show === undefined) {\n if(isShown) this.hideControls();\n else this.showControls();\n } else if(show === isShown) return;\n else if(show === false) this.hideControls();\n else this.showControls();\n };\n\n public lockControls(visible: boolean) {\n this.controlsLocked = visible;\n\n this.wrapper.classList.toggle('disable-hover', visible === false);\n this.toggleControls(visible);\n }\n\n protected togglePlay() {\n this.video[this.video.paused ? 'play' : 'pause']();\n }\n\n private buildControls() {\n const skin = this.skin;\n if(skin === 'default') {\n return `\n <button class=\"${skin}__button--big toggle tgico\" title=\"Toggle Play\"></button>\n <div class=\"${skin}__gradient-bottom ckin__controls\"></div>\n <div class=\"${skin}__controls ckin__controls\">\n <div class=\"bottom-controls\">\n <div class=\"left-controls\">\n <button class=\"btn-icon ${skin}__button toggle tgico\" title=\"Toggle Video\"></button>\n <div class=\"time\">\n <time id=\"time-elapsed\">0:00</time>\n <span> / </span>\n <time id=\"time-duration\">0:00</time>\n </div>\n </div>\n <div class=\"right-controls\">\n <button class=\"btn-icon ${skin}__button btn-menu-toggle settings tgico-settings hide\" title=\"Playback Rate\"></button>\n <button class=\"btn-icon ${skin}__button fullscreen tgico-fullscreen\" title=\"Full Screen\"></button>\n </div>\n </div>\n </div>`;\n }\n }\n\n protected setBtnMenuToggle() {\n const buttons: Parameters<typeof ButtonMenu>[0] = [0.25, 0.5, 1, 1.25, 1.5, 2].map((rate) => {\n return { \n regularText: rate === 1 ? 'Normal' : '' + rate, \n onClick: () => this.video.playbackRate = rate\n };\n });\n const btnMenu = ButtonMenu(buttons);\n const settingsButton = this.wrapper.querySelector('.settings') as HTMLElement;\n btnMenu.classList.add('top-left');\n ButtonMenuToggleHandler(settingsButton);\n settingsButton.append(btnMenu);\n }\n\n public static isFullScreen(): boolean {\n // @ts-ignore\n return !!(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement);\n }\n \n protected toggleFullScreen(fullScreenButton: HTMLElement) {\n // alternative standard method\n const player = this.wrapper;\n\n // * https://caniuse.com/#feat=fullscreen\n if(IS_APPLE_MOBILE) {\n const video = this.video as any;\n video.webkitEnterFullscreen();\n video.enterFullscreen();\n return;\n }\n \n if(!VideoPlayer.isFullScreen()) {\n player.classList.add('ckin__fullscreen');\n\n /* const videoParent = this.video.parentElement;\n const videoWhichChild = whichChild(this.video);\n const needVideoRemount = videoParent !== player;\n\n if(needVideoRemount) {\n this.videoParent = videoParent;\n this.videoWhichChild = videoWhichChild;\n player.prepend(this.video);\n } */\n \n if(player.requestFullscreen) {\n player.requestFullscreen();\n // @ts-ignore\n } else if(player.mozRequestFullScreen) {\n // @ts-ignore\n player.mozRequestFullScreen(); // Firefox\n // @ts-ignore\n } else if(player.webkitRequestFullscreen) {\n // @ts-ignore\n player.webkitRequestFullscreen(); // Chrome and Safari\n // @ts-ignore\n } else if(player.msRequestFullscreen) {\n // @ts-ignore\n player.msRequestFullscreen();\n }\n \n fullScreenButton.classList.remove('tgico-fullscreen');\n fullScreenButton.classList.add('tgico-smallscreen');\n fullScreenButton.setAttribute('title', 'Exit Full Screen');\n } else {\n player.classList.remove('ckin__fullscreen');\n\n /* if(this.videoParent) {\n const {videoWhichChild, videoParent} = this;\n if(!videoWhichChild) {\n videoParent.prepend(this.video);\n } else {\n videoParent.insertBefore(this.video, videoParent.children[videoWhichChild]);\n }\n\n this.videoParent = null;\n this.videoWhichChild = -1;\n } */\n \n // @ts-ignore\n if(document.cancelFullScreen) {\n // @ts-ignore\n document.cancelFullScreen();\n // @ts-ignore\n } else if(document.mozCancelFullScreen) {\n // @ts-ignore\n document.mozCancelFullScreen();\n // @ts-ignore\n } else if(document.webkitCancelFullScreen) {\n // @ts-ignore\n document.webkitCancelFullScreen();\n // @ts-ignore\n } else if(document.msExitFullscreen) {\n // @ts-ignore\n document.msExitFullscreen();\n }\n \n fullScreenButton.classList.remove('tgico-smallscreen');\n fullScreenButton.classList.add('tgico-fullscreen');\n fullScreenButton.setAttribute('title', 'Full Screen');\n }\n }\n \n protected onFullScreen = () => {\n // @ts-ignore\n const isFullscreenNow = document.webkitFullscreenElement !== null;\n if(!isFullscreenNow) {\n this.wrapper.classList.remove('ckin__fullscreen');\n }\n };\n\n public removeListeners() {\n super.cleanup();\n this.listenerSetter.removeAll();\n this.progress.removeListeners();\n }\n}\n","// * Jolly Cobra's schedulers\n\nimport { AnyToVoidFunction } from \"../../types\";\nimport { fastRaf } from \"../schedulers\";\nimport throttleWith from \"./throttleWith\";\n\nexport default function throttleWithRaf<F extends AnyToVoidFunction>(fn: F) {\n return throttleWith(fastRaf, fn);\n}\n","// * Jolly Cobra's schedulers\n\nimport { AnyToVoidFunction } from \"../../types\";\n\nexport default function throttleWith<F extends AnyToVoidFunction>(schedulerFn: AnyToVoidFunction, fn: F) {\n let waiting = false;\n let args: Parameters<F>;\n\n return (..._args: Parameters<F>) => {\n args = _args;\n\n if (!waiting) {\n waiting = true;\n\n schedulerFn(() => {\n waiting = false;\n // @ts-ignore\n fn(...args);\n });\n }\n };\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appDocsManager, {MyDocument} from \"../lib/appManagers/appDocsManager\";\nimport { wrapPhoto } from \"./wrappers\";\nimport ProgressivePreloader from \"./preloader\";\nimport { MediaProgressLine } from \"../lib/mediaPlayer\";\nimport appMediaPlaybackController, { MediaItem, MediaSearchContext } from \"./appMediaPlaybackController\";\nimport { DocumentAttribute, Message } from \"../layer\";\nimport mediaSizes from \"../helpers/mediaSizes\";\nimport { IS_SAFARI } from \"../environment/userAgent\";\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\nimport rootScope from \"../lib/rootScope\";\nimport './middleEllipsis';\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\nimport LazyLoadQueue from \"./lazyLoadQueue\";\nimport { CancellablePromise, deferredPromise } from \"../helpers/cancellablePromise\";\nimport ListenerSetter, { Listener } from \"../helpers/listenerSetter\";\nimport noop from \"../helpers/noop\";\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\nimport { joinElementsWith } from \"../lib/langPack\";\nimport { MiddleEllipsisElement } from \"./middleEllipsis\";\nimport htmlToSpan from \"../helpers/dom/htmlToSpan\";\nimport { formatFullSentTime } from \"../helpers/date\";\nimport { formatBytes } from \"../helpers/number\";\nimport throttleWithRaf from \"../helpers/schedulers/throttleWithRaf\";\n\nrootScope.addEventListener('messages_media_read', ({mids, peerId}) => {\n mids.forEach(mid => {\n const attr = `[data-mid=\"${mid}\"][data-peer-id=\"${peerId}\"]`;\n (Array.from(document.querySelectorAll(`audio-element.is-unread${attr}, .media-round.is-unread${attr}`)) as AudioElement[]).forEach(elem => {\n elem.classList.remove('is-unread');\n });\n });\n});\n\n// https://github.com/LonamiWebs/Telethon/blob/4393ec0b83d511b6a20d8a20334138730f084375/telethon/utils.py#L1285\nexport function decodeWaveform(waveform: Uint8Array | number[]) {\n if(!(waveform instanceof Uint8Array)) {\n waveform = new Uint8Array(waveform);\n }\n\n const bitCount = waveform.length * 8;\n const valueCount = bitCount / 5 | 0;\n if(!valueCount) {\n return new Uint8Array([]);\n }\n\n let result: Uint8Array;\n try {\n const dataView = new DataView(waveform.buffer);\n result = new Uint8Array(valueCount);\n for(let i = 0; i < valueCount; i++) {\n const byteIndex = i * 5 / 8 | 0;\n const bitShift = i * 5 % 8;\n const value = dataView.getUint16(byteIndex, true);\n result[i] = (value >> bitShift) & 0b00011111;\n }\n } catch(err) {\n result = new Uint8Array([]);\n }\n\n /* var byteIndex = (valueCount - 1) / 8 | 0;\n var bitShift = (valueCount - 1) % 8;\n if(byteIndex === waveform.length - 1) {\n var value = waveform[byteIndex];\n } else {\n var value = dataView.getUint16(byteIndex, true);\n }\n console.log('decoded waveform, setting last value:', value, byteIndex, bitShift);\n result[valueCount - 1] = (value >> bitShift) & 0b00011111; */\n return result;\n}\n\nfunction wrapVoiceMessage(audioEl: AudioElement) {\n audioEl.classList.add('is-voice');\n\n const message = audioEl.message;\n const doc = appMessagesManager.getMediaFromMessage(message) as MyDocument;\n\n if(message.pFlags.out) {\n audioEl.classList.add('is-out');\n }\n\n const barWidth = 2;\n const barMargin = 2; //mediaSizes.isMobile ? 2 : 1;\n const barHeightMin = 4; //mediaSizes.isMobile ? 3 : 2;\n const barHeightMax = mediaSizes.isMobile ? 16 : 23;\n const availW = 150; //mediaSizes.isMobile ? 152 : 190;\n\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n svg.classList.add('audio-waveform');\n svg.setAttributeNS(null, 'width', '' + availW);\n svg.setAttributeNS(null, 'height', '' + barHeightMax);\n svg.setAttributeNS(null, 'viewBox', `0 0 ${availW} ${barHeightMax}`);\n\n const timeDiv = document.createElement('div');\n timeDiv.classList.add('audio-time');\n audioEl.append(svg, timeDiv);\n\n let waveform = (doc.attributes.find(attribute => attribute._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio).waveform || new Uint8Array([]);\n waveform = decodeWaveform(waveform.slice(0, 63));\n\n //console.log('decoded waveform:', waveform);\n\n const normValue = Math.max(...waveform);\n const wfSize = waveform.length ? waveform.length : 100;\n const barCount = Math.min((availW / (barWidth + barMargin)) | 0, wfSize);\n\n let maxValue = 0;\n const maxDelta = barHeightMax - barHeightMin;\n\n let html = '';\n for(let i = 0, barX = 0, sumI = 0; i < wfSize; ++i) {\n const value = waveform[i] || 0;\n if((sumI + barCount) >= wfSize) { // draw bar\n sumI = sumI + barCount - wfSize;\n\t\t\tif(sumI < (barCount + 1) / 2) {\n\t\t\t\tif(maxValue < value) maxValue = value;\n }\n \n const bar_value = Math.max(((maxValue * maxDelta) + ((normValue + 1) / 2)) / (normValue + 1), barHeightMin);\n \n const h = `\n <rect x=\"${barX}\" y=\"${barHeightMax - bar_value}\" width=\"${barWidth}\" height=\"${bar_value}\" rx=\"1\" ry=\"1\"></rect>\n `;\n html += h;\n\n barX += barWidth + barMargin;\n\n if(sumI < (barCount + 1) / 2) {\n maxValue = 0;\n } else {\n maxValue = value;\n }\n } else {\n if(maxValue < value) maxValue = value;\n\n sumI += barCount;\n }\n }\n\n svg.insertAdjacentHTML('beforeend', html);\n const rects = Array.from(svg.children) as HTMLElement[];\n\n let progress = audioEl.querySelector('.audio-waveform') as HTMLDivElement;\n \n const onLoad = () => {\n let audio = audioEl.audio;\n\n const onTimeUpdate = () => {\n const lastIndex = audio.currentTime === audio.duration ? 0 : Math.ceil(audio.currentTime / audio.duration * barCount);\n \n //svg.children[lastIndex].setAttributeNS(null, 'fill', '#000');\n //svg.children[lastIndex].classList.add('active'); #Иногда пропускает полоски..\n rects.forEach((node, idx) => node.classList.toggle('active', idx < lastIndex));\n //++lastIndex;\n //console.log('lastIndex:', lastIndex, audio.currentTime);\n //}, duration * 1000 / svg.childElementCount | 0/* 63 * duration / 10 */);\n };\n\n if(!audio.paused || (audio.currentTime > 0 && audio.currentTime !== audio.duration)) {\n onTimeUpdate();\n }\n\n const throttledTimeUpdate = throttleWithRaf(onTimeUpdate);\n audioEl.addAudioListener('timeupdate', throttledTimeUpdate);\n audioEl.addAudioListener('ended', throttledTimeUpdate);\n\n audioEl.readyPromise.then(() => {\n let mousedown = false, mousemove = false;\n progress.addEventListener('mouseleave', (e) => {\n if(mousedown) {\n audio.play();\n mousedown = false;\n }\n mousemove = false;\n })\n progress.addEventListener('mousemove', (e) => {\n mousemove = true;\n if(mousedown) scrub(e);\n });\n progress.addEventListener('mousedown', (e) => {\n e.preventDefault();\n if(e.button !== 0) return;\n if(!audio.paused) {\n audio.pause();\n }\n \n scrub(e);\n mousedown = true;\n });\n progress.addEventListener('mouseup', (e) => {\n if(mousemove && mousedown) {\n audio.play();\n mousedown = false;\n }\n });\n attachClickEvent(progress, (e) => {\n cancelEvent(e);\n if(!audio.paused) scrub(e);\n });\n \n function scrub(e: MouseEvent | TouchEvent) {\n let offsetX: number;\n if(e instanceof MouseEvent) {\n offsetX = e.offsetX;\n } else { // touch\n const rect = (e.target as HTMLElement).getBoundingClientRect();\n offsetX = e.targetTouches[0].pageX - rect.left;\n }\n \n const scrubTime = offsetX / availW /* width */ * audio.duration;\n audio.currentTime = scrubTime;\n }\n }, noop);\n \n return () => {\n progress.remove();\n progress = null;\n audio = null;\n };\n };\n\n return onLoad;\n}\n\nfunction wrapAudio(audioEl: AudioElement) {\n const withTime = audioEl.withTime;\n\n const message = audioEl.message;\n const doc: MyDocument = appMessagesManager.getMediaFromMessage(message);\n\n const isVoice = doc.type === 'voice' || doc.type === 'round';\n const descriptionEl = document.createElement('div');\n descriptionEl.classList.add('audio-description');\n \n if(!isVoice) {\n const parts: (Node | string)[] = [];\n if(doc.audioPerformer) {\n parts.push(htmlToSpan(doc.audioPerformer));\n }\n\n if(withTime) {\n parts.push(formatFullSentTime(message.date));\n } else if(!parts.length) {\n parts.push(formatBytes(doc.size));\n }\n\n if(audioEl.showSender) {\n parts.push(appMessagesManager.wrapSenderToPeer(message));\n }\n\n descriptionEl.append(...joinElementsWith(parts, ' • '));\n }\n\n const html = `\n <div class=\"audio-details\">\n <div class=\"audio-title\"></div>\n <div class=\"audio-subtitle\"><div class=\"audio-time\"></div></div>\n </div>`;\n audioEl.insertAdjacentHTML('beforeend', html);\n\n const titleEl = audioEl.querySelector('.audio-title') as HTMLElement;\n\n const middleEllipsisEl = new MiddleEllipsisElement();\n middleEllipsisEl.dataset.fontWeight = audioEl.dataset.fontWeight;\n if(isVoice) {\n middleEllipsisEl.append(appMessagesManager.wrapSenderToPeer(message));\n } else {\n middleEllipsisEl.innerHTML = doc.audioTitle || doc.fileName;\n }\n\n titleEl.append(middleEllipsisEl);\n\n if(audioEl.showSender) {\n titleEl.append(appMessagesManager.wrapSentTime(message));\n }\n \n const subtitleDiv = audioEl.querySelector('.audio-subtitle') as HTMLDivElement;\n subtitleDiv.append(descriptionEl);\n\n const onLoad = () => {\n let launched = false;\n\n let progressLine = new MediaProgressLine(audioEl.audio, doc.supportsStreaming);\n\n audioEl.addAudioListener('ended', () => {\n audioEl.classList.remove('audio-show-progress');\n // Reset subtitle\n subtitleDiv.lastChild.replaceWith(descriptionEl);\n launched = false;\n });\n\n const onPlay = () => {\n if(!launched) {\n audioEl.classList.add('audio-show-progress');\n launched = true;\n\n if(progressLine) {\n subtitleDiv.lastChild.replaceWith(progressLine.container);\n }\n }\n };\n\n audioEl.addAudioListener('play', onPlay);\n\n if(!audioEl.audio.paused || audioEl.audio.currentTime > 0) {\n onPlay();\n }\n\n return () => {\n progressLine.removeListeners();\n progressLine.container.remove();\n progressLine = null;\n };\n };\n\n return onLoad;\n}\n\nfunction constructDownloadPreloader(tryAgainOnFail = true) {\n const preloader = new ProgressivePreloader({cancelable: true, tryAgainOnFail});\n preloader.construct();\n\n if(!tryAgainOnFail) {\n preloader.circle.setAttributeNS(null, 'r', '23');\n preloader.totalLength = 143.58203125;\n }\n\n return preloader;\n}\n\nexport const findAudioTargets = (anchor: HTMLElement, useSearch: boolean) => {\n let prev: MediaItem[], next: MediaItem[];\n // if(anchor.classList.contains('search-super-item') || !useSearch) {\n const container = findUpClassName(anchor, anchor.classList.contains('search-super-item') ? 'tabs-tab' : 'bubbles-inner');\n if(container) {\n const attr = `:not([data-is-outgoing=\"1\"])`;\n const justAudioSelector = `.audio:not(.is-voice)${attr}`;\n let selector: string;\n if(!anchor.matches(justAudioSelector)) {\n selector = `.audio.is-voice${attr}, .media-round${attr}`;\n } else {\n selector = justAudioSelector;\n }\n\n const elements = Array.from(container.querySelectorAll(selector)) as HTMLElement[];\n const idx = elements.indexOf(anchor);\n\n const mediaItems: MediaItem[] = elements.map(element => ({peerId: +element.dataset.peerId, mid: +element.dataset.mid}));\n\n prev = mediaItems.slice(0, idx);\n next = mediaItems.slice(idx + 1);\n }\n // }\n\n return [prev, next];\n};\n\nexport default class AudioElement extends HTMLElement {\n public audio: HTMLAudioElement;\n public preloader: ProgressivePreloader;\n public message: Message.message;\n public withTime = false;\n public voiceAsMusic = false;\n public searchContext: MediaSearchContext;\n public showSender = false;\n public noAutoDownload: boolean;\n public lazyLoadQueue: LazyLoadQueue;\n public loadPromises: Promise<any>[];\n\n private listenerSetter = new ListenerSetter();\n private onTypeDisconnect: () => void;\n public onLoad: (autoload?: boolean) => void;\n public readyPromise: CancellablePromise<void>;\n\n public render() {\n this.classList.add('audio');\n\n this.dataset.mid = '' + this.message.mid;\n this.dataset.peerId = '' + this.message.peerId;\n\n const doc: MyDocument = appMessagesManager.getMediaFromMessage(this.message);\n const isRealVoice = doc.type === 'voice';\n const isVoice = !this.voiceAsMusic && isRealVoice;\n const isOutgoing = this.message.pFlags.is_outgoing;\n const uploading = isOutgoing && this.preloader;\n\n const durationStr = String(doc.duration | 0).toHHMMSS();\n\n this.innerHTML = `\n <div class=\"audio-toggle audio-ico\">\n <div class=\"audio-play-icon\">\n <div class=\"part one\" x=\"0\" y=\"0\" fill=\"#fff\"></div>\n <div class=\"part two\" x=\"0\" y=\"0\" fill=\"#fff\"></div>\n </div>\n </div>`;\n\n const toggle = this.firstElementChild as HTMLElement;\n\n const downloadDiv = document.createElement('div');\n downloadDiv.classList.add('audio-download');\n\n const isUnread = doc.type !== 'audio' && this.message && this.message.pFlags.media_unread;\n if(isUnread) {\n this.classList.add('is-unread');\n }\n\n if(uploading) {\n this.classList.add('is-outgoing');\n this.append(downloadDiv);\n }\n\n const onTypeLoad = isVoice ? wrapVoiceMessage(this) : wrapAudio(this);\n \n const audioTimeDiv = this.querySelector('.audio-time') as HTMLDivElement;\n audioTimeDiv.innerHTML = durationStr;\n\n const onLoad = this.onLoad = (autoload: boolean) => {\n this.onLoad = undefined;\n\n const audio = this.audio = appMediaPlaybackController.addMedia(this.message, autoload);\n\n const readyPromise = this.readyPromise = deferredPromise<void>();\n if(this.audio.readyState >= this.audio.HAVE_CURRENT_DATA) readyPromise.resolve();\n else {\n this.addAudioListener('canplay', () => readyPromise.resolve(), {once: true});\n }\n\n this.onTypeDisconnect = onTypeLoad();\n \n const getTimeStr = () => String(audio.currentTime | 0).toHHMMSS() + (isVoice ? (' / ' + durationStr) : '');\n\n const onPlay = () => {\n audioTimeDiv.innerText = getTimeStr();\n toggle.classList.toggle('playing', !audio.paused);\n };\n\n if(!audio.paused || (audio.currentTime > 0 && audio.currentTime !== audio.duration)) {\n onPlay();\n }\n\n const togglePlay = (e?: Event, paused = audio.paused) => {\n e && cancelEvent(e);\n\n if(paused) {\n if(appMediaPlaybackController.setSearchContext(this.searchContext)) {\n const [prev, next] = findAudioTargets(this, this.searchContext.useSearch);\n appMediaPlaybackController.setTargets({peerId: this.message.peerId, mid: this.message.mid}, prev, next);\n }\n\n audio.play().catch(() => {});\n } else {\n audio.pause();\n }\n };\n\n attachClickEvent(toggle, (e) => togglePlay(e), {listenerSetter: this.listenerSetter});\n\n this.addAudioListener('ended', () => {\n toggle.classList.remove('playing');\n audioTimeDiv.innerText = durationStr;\n });\n\n this.addAudioListener('timeupdate', () => {\n if((!audio.currentTime && audio.paused) || appMediaPlaybackController.isSafariBuffering(audio)) return;\n audioTimeDiv.innerText = getTimeStr();\n });\n\n this.addAudioListener('pause', () => {\n toggle.classList.remove('playing');\n });\n\n this.addAudioListener('play', onPlay);\n\n return togglePlay;\n };\n\n if(!isOutgoing) {\n let preloader: ProgressivePreloader = this.preloader;\n\n onLoad(doc.type !== 'audio' && !this.noAutoDownload);\n\n if(doc.thumbs) {\n const imgs: HTMLImageElement[] = [];\n const wrapped = wrapPhoto({\n photo: doc, \n message: null, \n container: toggle, \n boxWidth: 48, \n boxHeight: 48,\n loadPromises: this.loadPromises,\n withoutPreloader: true,\n lazyLoadQueue: this.lazyLoadQueue\n });\n toggle.style.width = toggle.style.height = '';\n if(wrapped.images.thumb) imgs.push(wrapped.images.thumb);\n if(wrapped.images.full) imgs.push(wrapped.images.full);\n\n this.classList.add('audio-with-thumb');\n imgs.forEach(img => img.classList.add('audio-thumb'));\n }\n\n const r = (shouldPlay: boolean) => {\n if(this.audio.src) {\n return;\n }\n\n appMediaPlaybackController.resolveWaitingForLoadMedia(this.message.peerId, this.message.mid, this.message.pFlags.is_scheduled);\n\n const onDownloadInit = () => {\n if(shouldPlay) {\n appMediaPlaybackController.willBePlayed(this.audio); // prepare for loading audio\n \n if(IS_SAFARI && !this.audio.autoplay) {\n this.audio.autoplay = true;\n }\n }\n };\n\n onDownloadInit();\n\n if(!preloader) {\n if(doc.supportsStreaming) {\n this.classList.add('corner-download');\n\n let pauseListener: Listener;\n const onPlay = () => {\n const preloader = constructDownloadPreloader(false);\n const deferred = deferredPromise<void>();\n deferred.notifyAll({done: 75, total: 100});\n deferred.catch(() => {\n this.audio.pause();\n appMediaPlaybackController.willBePlayed(undefined);\n });\n deferred.cancel = () => {\n deferred.cancel = noop;\n const err = new Error();\n (err as any).type = 'CANCELED';\n deferred.reject(err);\n };\n preloader.attach(downloadDiv, false, deferred);\n\n pauseListener = this.addAudioListener('pause', () => {\n deferred.cancel();\n }, {once: true}) as any;\n\n onDownloadInit();\n };\n\n /* if(!this.audio.paused) {\n onPlay();\n } */\n\n const playListener: any = this.addAudioListener('play', onPlay);\n this.readyPromise.then(() => {\n this.listenerSetter.remove(playListener);\n this.listenerSetter.remove(pauseListener);\n });\n } else {\n preloader = constructDownloadPreloader();\n\n if(!shouldPlay) {\n this.readyPromise = deferredPromise();\n }\n\n const load = () => {\n onDownloadInit();\n\n const download = appDocsManager.downloadDoc(doc);\n \n if(!shouldPlay) {\n download.then(() => {\n this.readyPromise.resolve();\n });\n }\n\n preloader.attach(downloadDiv, false, download);\n return {download};\n };\n\n preloader.setDownloadFunction(load);\n load();\n }\n }\n\n this.append(downloadDiv);\n\n this.classList.add('downloading');\n\n this.readyPromise.then(() => {\n this.classList.remove('downloading');\n downloadDiv.classList.add('downloaded');\n setTimeout(() => {\n downloadDiv.remove();\n }, 200);\n \n //setTimeout(() => {\n // release loaded audio\n if(appMediaPlaybackController.willBePlayedMedia === this.audio) {\n this.audio.play();\n appMediaPlaybackController.willBePlayed(undefined);\n }\n //}, 10e3);\n });\n };\n\n if(!this.audio?.src) {\n if(doc.type !== 'audio' && !this.noAutoDownload) {\n r(false);\n } else {\n attachClickEvent(toggle, () => {\n r(true);\n }, {once: true, capture: true, passive: false, listenerSetter: this.listenerSetter});\n }\n }\n } else if(uploading) {\n this.dataset.isOutgoing = '1';\n this.preloader.attach(downloadDiv, false);\n //onLoad();\n }\n }\n\n get addAudioListener() {\n return this.listenerSetter.add(this.audio);\n }\n\n disconnectedCallback() {\n if(this.isConnected) {\n return;\n }\n \n if(this.onTypeDisconnect) {\n this.onTypeDisconnect();\n this.onTypeDisconnect = null;\n }\n\n if(this.readyPromise) {\n this.readyPromise.reject();\n }\n\n this.listenerSetter.removeAll();\n this.listenerSetter = null;\n\n this.preloader = null;\n }\n}\n\ncustomElements.define(\"audio-element\", AudioElement);\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default class DivAndCaption<T> {\r\n public container: HTMLElement;\r\n public border: HTMLElement;\r\n public content: HTMLElement;\r\n public title: HTMLElement;\r\n public subtitle: HTMLElement;\r\n\r\n constructor(protected className: string, public fill?: T) {\r\n this.container = document.createElement('div');\r\n this.container.className = className;\r\n\r\n this.border = document.createElement('div');\r\n this.border.classList.add(className + '-border');\r\n \r\n this.content = document.createElement('div');\r\n this.content.classList.add(className + '-content');\r\n\r\n this.title = document.createElement('div');\r\n this.title.classList.add(className + '-title');\r\n this.title.setAttribute('dir', 'auto');\r\n\r\n this.subtitle = document.createElement('div');\r\n this.subtitle.classList.add(className + '-subtitle');\r\n this.subtitle.setAttribute('dir', 'auto');\r\n\r\n this.content.append(this.title, this.subtitle);\r\n this.container.append(this.border, this.content);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\nimport { limitSymbols } from \"../../helpers/string\";\r\nimport appImManager, { CHAT_ANIMATION_GROUP } from \"../../lib/appManagers/appImManager\";\r\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport appPhotosManager from \"../../lib/appManagers/appPhotosManager\";\r\nimport { RichTextProcessor } from \"../../lib/richtextprocessor\";\r\nimport DivAndCaption from \"../divAndCaption\";\r\nimport { wrapPhoto, wrapSticker } from \"../wrappers\";\r\n\r\nconst MEDIA_SIZE = 32;\r\n\r\nexport function wrapReplyDivAndCaption(options: {\r\n title: string | HTMLElement | DocumentFragment,\r\n titleEl: HTMLElement,\r\n subtitle: string | HTMLElement | DocumentFragment,\r\n subtitleEl: HTMLElement,\r\n message: any,\r\n mediaEl: HTMLElement,\r\n loadPromises?: Promise<any>[]\r\n}) {\r\n let {title, titleEl, subtitle, subtitleEl, mediaEl, message, loadPromises} = options;\r\n if(title !== undefined) {\r\n if(typeof(title) === 'string') {\r\n title = limitSymbols(title, 140);\r\n title = RichTextProcessor.wrapEmojiText(title);\r\n }\r\n\r\n replaceContent(titleEl, title);\r\n }\r\n\r\n if(!loadPromises) {\r\n loadPromises = [];\r\n }\r\n\r\n let media = message && message.media;\r\n let setMedia = false, isRound = false;\r\n const mediaChildren = mediaEl ? Array.from(mediaEl.children).slice() : [];\r\n let middleware: () => boolean;\r\n if(media && mediaEl) {\r\n subtitleEl.textContent = '';\r\n subtitleEl.append(appMessagesManager.wrapMessageForReply(message));\r\n\r\n //console.log('wrap reply', media);\r\n\r\n if(media.webpage) {\r\n media = media.webpage;\r\n }\r\n \r\n if(media.photo || (media.document && ['video', 'sticker', 'gif', 'round', 'photo'].indexOf(media.document.type) !== -1)) {\r\n middleware = appImManager.chat.bubbles.getMiddleware();\r\n const lazyLoadQueue = appImManager.chat.bubbles.lazyLoadQueue;\r\n\r\n if(media.document?.type === 'sticker') {\r\n setMedia = true;\r\n wrapSticker({\r\n doc: media.document,\r\n div: mediaEl,\r\n lazyLoadQueue,\r\n group: CHAT_ANIMATION_GROUP,\r\n //onlyThumb: media.document.sticker === 2,\r\n width: MEDIA_SIZE,\r\n height: MEDIA_SIZE,\r\n middleware,\r\n loadPromises\r\n });\r\n } else {\r\n const photo = media.photo || media.document;\r\n\r\n isRound = photo.type === 'round';\r\n\r\n try {\r\n wrapPhoto({\r\n photo,\r\n container: mediaEl,\r\n boxWidth: MEDIA_SIZE,\r\n boxHeight: MEDIA_SIZE,\r\n size: appPhotosManager.choosePhotoSize(photo, MEDIA_SIZE, MEDIA_SIZE),\r\n middleware,\r\n lazyLoadQueue,\r\n noBlur: true,\r\n withoutPreloader: true,\r\n loadPromises\r\n });\r\n setMedia = true;\r\n } catch(err) {\r\n\r\n }\r\n }\r\n }\r\n } else {\r\n if(message) {\r\n subtitleEl.textContent = '';\r\n subtitleEl.append(appMessagesManager.wrapMessageForReply(message, message.message && limitSymbols(message.message, 140)));\r\n } else {\r\n if(typeof(subtitle) === 'string') {\r\n subtitle = limitSymbols(subtitle, 140);\r\n subtitle = RichTextProcessor.wrapEmojiText(subtitle);\r\n }\r\n\r\n replaceContent(subtitleEl, subtitle || '');\r\n }\r\n }\r\n\r\n Promise.all(loadPromises).then(() => {\r\n if(middleware && !middleware()) return;\r\n mediaChildren.forEach(child => child.remove());\r\n\r\n if(mediaEl) {\r\n mediaEl.classList.toggle('is-round', isRound);\r\n }\r\n });\r\n\r\n return setMedia;\r\n}\r\n\r\nexport default class ReplyContainer extends DivAndCaption<(title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment, message?: any) => void> {\r\n private mediaEl: HTMLElement;\r\n\r\n constructor(protected className: string) {\r\n super(className, (title, subtitle = '', message?) => {\r\n if(!this.mediaEl) {\r\n this.mediaEl = document.createElement('div');\r\n this.mediaEl.classList.add(this.className + '-media');\r\n }\r\n\r\n const isMediaSet = wrapReplyDivAndCaption({\r\n title,\r\n titleEl: this.title,\r\n subtitle,\r\n subtitleEl: this.subtitle,\r\n mediaEl: this.mediaEl,\r\n message\r\n });\r\n \r\n this.container.classList.toggle('is-media', isMediaSet);\r\n if(isMediaSet) {\r\n this.content.prepend(this.mediaEl);\r\n } else {\r\n this.mediaEl.remove();\r\n }\r\n });\r\n }\r\n}\r\n","/*\r\nThis file is part of Telegram Desktop,\r\nthe official desktop application for the Telegram messaging service.\r\nFor license and copyright information please follow this link:\r\nhttps://github.com/telegramdesktop/tdesktop/blob/master/LEGAL\r\n*/\r\n\r\nimport { accumulate } from \"../helpers/array\";\r\nimport { clamp } from \"../helpers/number\";\r\n\r\ntype Size = {w: number, h: number};\r\nexport type GroupMediaLayout = {\r\n geometry: {\r\n x: number,\r\n y: number,\r\n width: number,\r\n height: number\r\n },\r\n sides: number\r\n};\r\ntype Attempt = {\r\n lineCounts: number[],\r\n heights: number[]\r\n};\r\nexport const RectPart = {\r\n None: 0,\r\n Top: 1,\r\n Right: 2,\r\n Bottom: 4,\r\n Left: 8\r\n};\r\n\r\n// https://github.com/telegramdesktop/tdesktop/blob/4669c07dc5335cbf4795bbbe5b0ab7c007b9aee2/Telegram/SourceFiles/ui/grouped_layout.cpp\r\nexport class Layouter {\r\n private count: number;\r\n private ratios: number[];\r\n private proportions: string;\r\n private averageRatio: number;\r\n private maxSizeRatio: number;\r\n\r\n constructor(private sizes: Size[], private maxWidth: number, private minWidth: number, private spacing: number, private maxHeight = maxWidth) {\r\n this.count = sizes.length;\r\n this.ratios = Layouter.countRatios(sizes);\r\n this.proportions = Layouter.countProportions(this.ratios);\r\n this.averageRatio = accumulate(this.ratios, 1) / this.count; // warn\r\n this.maxSizeRatio = maxWidth / this.maxHeight;\r\n }\r\n\r\n public layout(): GroupMediaLayout[] {\r\n if(!this.count) return [];\r\n //else if(this.count === 1) return this.layoutOne();\r\n\r\n if(this.count >= 5 || this.ratios.find(r => r > 2)) {\r\n return new ComplexLayouter(this.ratios, this.averageRatio, this.maxWidth, this.minWidth, this.spacing).layout();\r\n }\r\n\r\n if(this.count === 2) return this.layoutTwo();\r\n else if(this.count === 3) return this.layoutThree();\r\n return this.layoutFour();\r\n }\r\n\r\n private layoutTwo(): ReturnType<Layouter['layout']> {\r\n if((this.proportions === \"ww\")\r\n && (this.averageRatio > 1.4 * this.maxSizeRatio)\r\n && (this.ratios[1] - this.ratios[0] < 0.2)) {\r\n return this.layoutTwoTopBottom();\r\n } else if(this.proportions === \"ww\" || this.proportions === \"qq\") {\r\n return this.layoutTwoLeftRightEqual();\r\n }\r\n return this.layoutTwoLeftRight();\r\n }\r\n\r\n private layoutThree(): ReturnType<Layouter['layout']> {\r\n //console.log('layoutThree:', this);\r\n if(this.proportions[0] === 'n') {\r\n return this.layoutThreeLeftAndOther();\r\n }\r\n return this.layoutThreeTopAndOther();\r\n }\r\n\r\n private layoutFour(): ReturnType<Layouter['layout']> {\r\n if(this.proportions[0] === 'w') {\r\n return this.layoutFourTopAndOther();\r\n }\r\n return this.layoutFourLeftAndOther();\r\n }\r\n\r\n private layoutTwoTopBottom(): ReturnType<Layouter['layout']> {\r\n const width = this.maxWidth;\r\n const height = Math.round(Math.min(\r\n width / this.ratios[0],\r\n Math.min(\r\n width / this.ratios[1],\r\n (this.maxHeight - this.spacing) / 2)));\r\n \r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width, height},\r\n sides: RectPart.Left | RectPart.Top | RectPart.Right\r\n },\r\n {\r\n geometry: {x: 0, y: height + this.spacing, width, height},\r\n sides: RectPart.Left | RectPart.Bottom | RectPart.Right\r\n },\r\n ];\r\n }\r\n\r\n private layoutTwoLeftRightEqual(): ReturnType<Layouter['layout']> {\r\n const width = (this.maxWidth - this.spacing) / 2;\r\n const height = Math.round(Math.min(\r\n width / this.ratios[0],\r\n Math.min(width / this.ratios[1], this.maxHeight * 1)));\r\n \r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width, height},\r\n sides: RectPart.Top | RectPart.Left | RectPart.Bottom\r\n },\r\n {\r\n geometry: {x: width + this.spacing, y: 0, width, height},\r\n sides: RectPart.Top | RectPart.Right | RectPart.Bottom\r\n },\r\n ];\r\n }\r\n\r\n private layoutTwoLeftRight(): ReturnType<Layouter['layout']> {\r\n const minimalWidth = Math.round(this.minWidth * 1.5);\r\n const secondWidth = Math.min(\r\n Math.round(Math.max(\r\n 0.4 * (this.maxWidth - this.spacing),\r\n (this.maxWidth - this.spacing) / this.ratios[0]\r\n / (1 / this.ratios[0] + 1 / this.ratios[1]))),\r\n this.maxWidth - this.spacing - minimalWidth);\r\n const firstWidth = this.maxWidth\r\n - secondWidth\r\n - this.spacing;\r\n const height = Math.min(\r\n this.maxHeight,\r\n Math.round(Math.min(\r\n firstWidth / this.ratios[0],\r\n secondWidth / this.ratios[1])));\r\n \r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width: firstWidth, height},\r\n sides: RectPart.Top | RectPart.Left | RectPart.Bottom\r\n },\r\n {\r\n geometry: {x: firstWidth + this.spacing, y: 0, width: secondWidth, height},\r\n sides: RectPart.Top | RectPart.Right | RectPart.Bottom\r\n },\r\n ];\r\n }\r\n\r\n private layoutThreeLeftAndOther(): ReturnType<Layouter['layout']> {\r\n const firstHeight = this.maxHeight;\r\n const thirdHeight = Math.round(Math.min(\r\n (this.maxHeight - this.spacing) / 2.,\r\n (this.ratios[1] * (this.maxWidth - this.spacing)\r\n / (this.ratios[2] + this.ratios[1]))));\r\n const secondHeight = firstHeight\r\n - thirdHeight\r\n - this.spacing;\r\n const rightWidth = Math.max(\r\n this.minWidth,\r\n Math.round(Math.min(\r\n (this.maxWidth - this.spacing) / 2.,\r\n Math.min(\r\n thirdHeight * this.ratios[2],\r\n secondHeight * this.ratios[1]))));\r\n const leftWidth = Math.min(\r\n Math.round(firstHeight * this.ratios[0]),\r\n this.maxWidth - this.spacing - rightWidth);\r\n\r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width: leftWidth, height: firstHeight},\r\n sides: RectPart.Top | RectPart.Left | RectPart.Bottom\r\n },\r\n {\r\n geometry: {x: leftWidth + this.spacing, y: 0, width: rightWidth, height: secondHeight},\r\n sides: RectPart.Top | RectPart.Right\r\n },\r\n {\r\n geometry: {x: leftWidth + this.spacing, y: secondHeight + this.spacing, width: rightWidth, height: thirdHeight},\r\n sides: RectPart.Bottom | RectPart.Right\r\n },\r\n ];\r\n }\r\n \r\n private layoutThreeTopAndOther(): ReturnType<Layouter['layout']> {\r\n const firstWidth = this.maxWidth;\r\n const firstHeight = Math.round(Math.min(\r\n firstWidth / this.ratios[0],\r\n (this.maxHeight - this.spacing) * 0.66));\r\n const secondWidth = (this.maxWidth - this.spacing) / 2;\r\n const secondHeight = Math.min(\r\n this.maxHeight - firstHeight - this.spacing,\r\n Math.round(Math.min(\r\n secondWidth / this.ratios[1],\r\n secondWidth / this.ratios[2])));\r\n const thirdWidth = firstWidth - secondWidth - this.spacing;\r\n \r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width: firstWidth, height: firstHeight},\r\n sides: RectPart.Left | RectPart.Top | RectPart.Right\r\n },\r\n {\r\n geometry: {x: 0, y: firstHeight + this.spacing, width: secondWidth, height: secondHeight},\r\n sides: RectPart.Bottom | RectPart.Left\r\n },\r\n {\r\n geometry: {x: secondWidth + this.spacing, y: firstHeight + this.spacing, width: thirdWidth, height: secondHeight},\r\n sides: RectPart.Bottom | RectPart.Right\r\n },\r\n ];\r\n }\r\n\r\n private layoutFourTopAndOther(): ReturnType<Layouter['layout']> {\r\n const w = this.maxWidth;\r\n const h0 = Math.round(Math.min(\r\n w / this.ratios[0],\r\n (this.maxHeight - this.spacing) * 0.66));\r\n const h = Math.round(\r\n (this.maxWidth - 2 * this.spacing)\r\n / (this.ratios[1] + this.ratios[2] + this.ratios[3]));\r\n const w0 = Math.max(\r\n this.minWidth,\r\n Math.round(Math.min(\r\n (this.maxWidth - 2 * this.spacing) * 0.4,\r\n h * this.ratios[1])));\r\n const w2 = Math.round(Math.max(\r\n Math.max(\r\n this.minWidth * 1.,\r\n (this.maxWidth - 2 * this.spacing) * 0.33),\r\n h * this.ratios[3]));\r\n const w1 = w - w0 - w2 - 2 * this.spacing;\r\n const h1 = Math.min(\r\n this.maxHeight - h0 - this.spacing,\r\n h);\r\n \r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width: w, height: h0},\r\n sides: RectPart.Left | RectPart.Top | RectPart.Right\r\n },\r\n {\r\n geometry: {x: 0, y: h0 + this.spacing, width: w0, height: h1},\r\n sides: RectPart.Bottom | RectPart.Left\r\n },\r\n {\r\n geometry: {x: w0 + this.spacing, y: h0 + this.spacing, width: w1, height: h1},\r\n sides: RectPart.Bottom,\r\n },\r\n {\r\n geometry: {x: w0 + this.spacing + w1 + this.spacing, y: h0 + this.spacing, width: w2, height: h1},\r\n sides: RectPart.Right | RectPart.Bottom\r\n },\r\n ];\r\n }\r\n\r\n private layoutFourLeftAndOther(): ReturnType<Layouter['layout']> {\r\n const h = this.maxHeight;\r\n const w0 = Math.round(Math.min(\r\n h * this.ratios[0],\r\n (this.maxWidth - this.spacing) * 0.6));\r\n \r\n const w = Math.round(\r\n (this.maxHeight - 2 * this.spacing)\r\n / (1. / this.ratios[1] + 1. / this.ratios[2] + 1. / this.ratios[3])\r\n );\r\n const h0 = Math.round(w / this.ratios[1]);\r\n const h1 = Math.round(w / this.ratios[2]);\r\n const h2 = h - h0 - h1 - 2 * this.spacing;\r\n const w1 = Math.max(\r\n this.minWidth,\r\n Math.min(this.maxWidth - w0 - this.spacing, w));\r\n \r\n return [\r\n {\r\n geometry: {x: 0, y: 0, width: w0, height: h},\r\n sides: RectPart.Top | RectPart.Left | RectPart.Bottom\r\n },\r\n {\r\n geometry: {x: w0 + this.spacing, y: 0, width: w1, height: h0},\r\n sides: RectPart.Top | RectPart.Right\r\n },\r\n {\r\n geometry: {x: w0 + this.spacing, y: h0 + this.spacing, width: w1, height: h1},\r\n sides: RectPart.Right\r\n },\r\n {\r\n geometry: {x: w0 + this.spacing, y: h0 + h1 + 2 * this.spacing, width: w1, height: h2},\r\n sides: RectPart.Bottom | RectPart.Right\r\n },\r\n ];\r\n }\r\n\r\n private static countRatios(sizes: Size[]) {\r\n return sizes.map(size => size.w / size.h);\r\n }\r\n\r\n private static countProportions(ratios: number[]) {\r\n return ratios.map(ratio => (ratio > 1.2) ? 'w' : (ratio < 0.8) ? 'n' : 'q').join('');\r\n }\r\n}\r\n\r\nclass ComplexLayouter {\r\n private ratios: number[];\r\n private count: number;\r\n\r\n constructor(ratios: number[], private averageRatio: number, private maxWidth: number, private minWidth: number, private spacing: number, private maxHeight = maxWidth * 4 / 3) {\r\n this.ratios = ComplexLayouter.cropRatios(ratios, averageRatio);\r\n this.count = ratios.length;\r\n }\r\n\r\n private static cropRatios(ratios: number[], averageRatio: number) {\r\n const kMaxRatio = 2.75;\r\n const kMinRatio = 0.6667;\r\n return ratios.map(ratio => {\r\n return averageRatio > 1.1\r\n\t\t\t ? clamp(ratio, 1., kMaxRatio)\r\n\t\t\t : clamp(ratio, kMinRatio, 1.);\r\n });\r\n }\r\n\r\n public layout(): GroupMediaLayout[] {\r\n let result = new Array<GroupMediaLayout>(this.count);\r\n\r\n let attempts: Attempt[] = [];\r\n const multiHeight = (offset: number, count: number) => {\r\n const ratios = this.ratios.slice(offset, offset + count); // warn\r\n const sum = accumulate(ratios, 0);\r\n return (this.maxWidth - (count - 1) * this.spacing) / sum;\r\n };\r\n const pushAttempt = (lineCounts: number[]) => {\r\n let heights: number[] = [];\r\n let offset = 0;\r\n for(let count of lineCounts) {\r\n heights.push(multiHeight(offset, count));\r\n offset += count;\r\n }\r\n attempts.push({lineCounts, heights}); // warn\r\n };\r\n\r\n for(let first = 1; first !== this.count; ++first) {\r\n const second = this.count - first;\r\n if(first > 3 || second > 3) {\r\n continue;\r\n }\r\n pushAttempt([first, second]);\r\n }\r\n for(let first = 1; first !== this.count - 1; ++first) {\r\n for(let second = 1; second !== this.count - first; ++second) {\r\n const third = this.count - first - second;\r\n if((first > 3)\r\n || (second > ((this.averageRatio < 0.85) ? 4 : 3))\r\n || (third > 3)) {\r\n continue;\r\n }\r\n pushAttempt([first, second, third]);\r\n }\r\n }\r\n for(let first = 1; first !== this.count - 1; ++first) {\r\n for(let second = 1; second !== this.count - first; ++second) {\r\n for(let third = 1; third !== this.count - first - second; ++third) {\r\n const fourth = this.count - first - second - third;\r\n if(first > 3 || second > 3 || third > 3 || fourth > 3) {\r\n continue;\r\n }\r\n pushAttempt([first, second, third, fourth]);\r\n }\r\n }\r\n }\r\n\r\n let optimalAttempt: Attempt = null;\r\n let optimalDiff = 0;\r\n for(const attempt of attempts) {\r\n const {heights, lineCounts: counts} = attempt;\r\n const lineCount = counts.length;\r\n const totalHeight = accumulate(heights, 0) \r\n + this.spacing * (lineCount - 1);\r\n const minLineHeight = Math.min(...heights);\r\n const maxLineHeight = Math.max(...heights);\r\n const bad1 = (minLineHeight < this.minWidth) ? 1.5 : 1;\r\n const bad2 = (() => {\r\n for(let line = 1; line !== lineCount; ++line) {\r\n if(counts[line - 1] > counts[line]) {\r\n return 1.5;\r\n }\r\n }\r\n return 1.;\r\n })();\r\n const diff = Math.abs(totalHeight - this.maxHeight) * bad1 * bad2;\r\n if(!optimalAttempt || diff < optimalDiff) {\r\n optimalAttempt = attempt;\r\n optimalDiff = diff;\r\n }\r\n }\r\n\r\n const optimalCounts = optimalAttempt.lineCounts;\r\n\t const optimalHeights = optimalAttempt.heights;\r\n const rowCount = optimalCounts.length;\r\n \r\n let index = 0;\r\n let y = 0;\r\n for(let row = 0; row !== rowCount; ++row) {\r\n const colCount = optimalCounts[row];\r\n const lineHeight = optimalHeights[row];\r\n const height = Math.round(lineHeight);\r\n\r\n let x = 0;\r\n for(let col = 0; col !== colCount; ++col) {\r\n const sides = RectPart.None\r\n | (row === 0 ? RectPart.Top : RectPart.None)\r\n | (row === rowCount - 1 ? RectPart.Bottom : RectPart.None)\r\n | (col === 0 ? RectPart.Left : RectPart.None)\r\n | (col === colCount - 1 ? RectPart.Right : RectPart.None);\r\n\r\n const ratio = this.ratios[index];\r\n const width = (col === colCount - 1)\r\n ? (this.maxWidth - x)\r\n : Math.round(ratio * lineHeight);\r\n result[index] = {\r\n geometry: {x, y, width, height},\r\n sides\r\n };\r\n\r\n x += width + this.spacing;\r\n ++index;\r\n }\r\n y += height + this.spacing;\r\n }\r\n\r\n return result;\r\n }\r\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { InputFile } from \"../layer\";\r\nimport AvatarEdit from \"./avatarEdit\";\r\nimport AvatarElement from \"./avatar\";\r\nimport InputField from \"./inputField\";\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\nimport { safeAssign } from \"../helpers/object\";\r\nimport ButtonCorner from \"./buttonCorner\";\r\n\r\nexport default class EditPeer {\r\n public nextBtn: HTMLButtonElement;\r\n\r\n public uploadAvatar: () => Promise<InputFile>;\r\n public avatarEdit: AvatarEdit;\r\n public avatarElem: AvatarElement;\r\n\r\n private inputFields: InputField[];\r\n private listenerSetter: ListenerSetter;\r\n\r\n private peerId: number;\r\n\r\n private _disabled = false;\r\n private avatarSize = 120;\r\n\r\n constructor(options: {\r\n peerId?: number,\r\n inputFields: EditPeer['inputFields'],\r\n listenerSetter: ListenerSetter,\r\n doNotEditAvatar?: boolean,\r\n withoutAvatar?: boolean,\r\n nextBtn?: HTMLButtonElement,\r\n avatarSize?: number\r\n }) {\r\n safeAssign(this, options);\r\n\r\n if(!this.nextBtn) {\r\n this.nextBtn = ButtonCorner({icon: 'check'});\r\n } else if(!this.nextBtn.classList.contains('btn-corner')) {\r\n this.handleChange = () => {\r\n this.nextBtn.toggleAttribute('disabled', !this.isChanged() || this.disabled);\r\n };\r\n }\r\n\r\n if(!options.withoutAvatar) {\r\n this.avatarElem = document.createElement('avatar-element') as AvatarElement;\r\n this.avatarElem.classList.add('avatar-placeholder', 'avatar-' + this.avatarSize);\r\n this.avatarElem.setAttribute('peer', '' + this.peerId);\r\n \r\n if(!options.doNotEditAvatar) {\r\n this.avatarEdit = new AvatarEdit((_upload) => {\r\n this.uploadAvatar = _upload;\r\n this.handleChange();\r\n this.avatarElem.remove();\r\n });\r\n \r\n this.avatarEdit.container.append(this.avatarElem);\r\n }\r\n }\r\n\r\n this.inputFields.forEach(inputField => {\r\n this.listenerSetter.add(inputField.input)('input', this.handleChange);\r\n });\r\n\r\n this.handleChange();\r\n }\r\n\r\n public get disabled() {\r\n return this._disabled;\r\n }\r\n\r\n public set disabled(value) {\r\n this._disabled = value;\r\n this.inputFields.forEach(inputField => inputField.input.toggleAttribute('disabled', value));\r\n this.handleChange();\r\n }\r\n\r\n public lockWithPromise(promise: Promise<any>, unlockOnSuccess = false) {\r\n this.disabled = true;\r\n promise.then(() => {\r\n if(unlockOnSuccess) {\r\n this.disabled = false;\r\n }\r\n }, () => {\r\n this.disabled = false;\r\n });\r\n }\r\n\r\n public isChanged = () => {\r\n if(this.uploadAvatar) {\r\n return true;\r\n }\r\n\r\n let validLength = 0, requiredLength = 0, requiredValidLength = 0;\r\n this.inputFields.forEach(inputField => {\r\n const isValid = inputField.isValid();\r\n if(isValid) {\r\n ++validLength;\r\n\r\n if(inputField.required) {\r\n ++requiredValidLength;\r\n }\r\n }\r\n\r\n if(inputField.required) {\r\n ++requiredLength;\r\n }\r\n });\r\n\r\n return requiredLength === requiredValidLength && validLength > 0;\r\n };\r\n\r\n public handleChange = () => {\r\n this.nextBtn.classList.toggle('is-visible', this.isChanged());\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport CheckboxField from \"./checkboxField\";\r\nimport RadioField from \"./radioField\";\r\nimport { ripple } from \"./ripple\";\r\nimport { SliderSuperTab } from \"./slider\";\r\nimport RadioForm from \"./radioForm\";\r\nimport { i18n, LangPackKey } from \"../lib/langPack\";\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport setInnerHTML from \"../helpers/dom/setInnerHTML\";\r\n\r\nexport default class Row {\r\n public container: HTMLElement;\r\n public title: HTMLDivElement;\r\n public subtitle: HTMLElement;\r\n\r\n public checkboxField: CheckboxField;\r\n public radioField: RadioField;\r\n\r\n public freezed = false;\r\n\r\n constructor(options: Partial<{\r\n icon: string,\r\n subtitle: string | HTMLElement | DocumentFragment,\r\n subtitleLangKey: LangPackKey,\r\n subtitleLangArgs: any[],\r\n radioField: Row['radioField'],\r\n checkboxField: Row['checkboxField'],\r\n noCheckboxSubtitle: boolean,\r\n title: string,\r\n titleLangKey: LangPackKey,\r\n titleRight: string | HTMLElement,\r\n clickable: boolean | ((e: Event) => void),\r\n navigationTab: SliderSuperTab,\r\n havePadding: boolean,\r\n noRipple: boolean\r\n }> = {}) {\r\n this.container = document.createElement(options.radioField || options.checkboxField ? 'label' : 'div');\r\n this.container.classList.add('row');\r\n\r\n this.subtitle = document.createElement('div');\r\n this.subtitle.classList.add('row-subtitle');\r\n this.subtitle.setAttribute('dir', 'auto');\r\n if(options.subtitle) {\r\n if(typeof(options.subtitle) === 'string') {\r\n setInnerHTML(this.subtitle, options.subtitle);\r\n } else {\r\n this.subtitle.append(options.subtitle);\r\n }\r\n } else if(options.subtitleLangKey) {\r\n this.subtitle.append(i18n(options.subtitleLangKey, options.subtitleLangArgs));\r\n }\r\n this.container.append(this.subtitle);\r\n\r\n let havePadding = !!options.havePadding;\r\n if(options.radioField || options.checkboxField) {\r\n havePadding = true;\r\n if(options.radioField) {\r\n this.radioField = options.radioField;\r\n this.container.append(this.radioField.label);\r\n }\r\n\r\n if(options.checkboxField) {\r\n this.checkboxField = options.checkboxField;\r\n \r\n const isToggle = options.checkboxField.label.classList.contains('checkbox-field-toggle');\r\n if(isToggle) {\r\n this.container.classList.add('row-with-toggle');\r\n options.titleRight = this.checkboxField.label;\r\n } else {\r\n this.container.append(this.checkboxField.label);\r\n }\r\n\r\n if(!options.noCheckboxSubtitle && !isToggle) {\r\n this.checkboxField.input.addEventListener('change', () => {\r\n replaceContent(this.subtitle, i18n(this.checkboxField.input.checked ? 'Checkbox.Enabled' : 'Checkbox.Disabled'));\r\n });\r\n }\r\n }\r\n\r\n const i = options.radioField || options.checkboxField;\r\n i.label.classList.add('disable-hover');\r\n } \r\n \r\n if(options.title || options.titleLangKey) {\r\n let c: HTMLElement;\r\n if(options.titleRight) {\r\n c = document.createElement('div');\r\n c.classList.add('row-title-row');\r\n this.container.append(c);\r\n } else {\r\n c = this.container;\r\n }\r\n\r\n this.title = document.createElement('div');\r\n this.title.classList.add('row-title');\r\n this.title.setAttribute('dir', 'auto');\r\n if(options.title) {\r\n this.title.innerHTML = options.title;\r\n } else {\r\n this.title.append(i18n(options.titleLangKey));\r\n }\r\n c.append(this.title);\r\n\r\n if(options.titleRight) {\r\n const titleRight = document.createElement('div');\r\n titleRight.classList.add('row-title', 'row-title-right');\r\n\r\n if(typeof(options.titleRight) === 'string') {\r\n titleRight.innerHTML = options.titleRight;\r\n } else {\r\n titleRight.append(options.titleRight);\r\n }\r\n\r\n c.append(titleRight);\r\n }\r\n }\r\n\r\n if(options.icon) {\r\n havePadding = true;\r\n this.title.classList.add('tgico', 'tgico-' + options.icon);\r\n this.container.classList.add('row-with-icon');\r\n }\r\n\r\n if(havePadding) {\r\n this.container.classList.add('row-with-padding');\r\n }\r\n\r\n if(options.navigationTab) {\r\n options.clickable = () => options.navigationTab.open();\r\n }\r\n\r\n if(options.clickable || options.radioField || options.checkboxField) {\r\n if(typeof(options.clickable) === 'function') {\r\n this.container.addEventListener('click', (e) => {\r\n if(this.freezed) return;\r\n (options.clickable as any)(e);\r\n });\r\n }\r\n\r\n this.container.classList.add('row-clickable', 'hover-effect');\r\n\r\n if(!options.noRipple) {\r\n ripple(this.container, undefined, undefined, true);\r\n }\r\n\r\n /* if(options.radioField || options.checkboxField) {\r\n this.container.prepend(this.container.lastElementChild);\r\n } */\r\n }\r\n }\r\n\r\n\r\n}\r\n\r\nexport const RadioFormFromRows = (rows: Row[], onChange: (value: string) => void) => {\r\n return RadioForm(rows.map(r => ({container: r.container, input: r.radioField.input})), onChange);\r\n};\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function RadioForm(radios: {container: HTMLElement, input: HTMLInputElement}[], onChange: (value: string) => void) {\r\n const form = document.createElement('form');\r\n\r\n radios.forEach(r => {\r\n const {container, input} = r;\r\n form.append(container);\r\n input.addEventListener('change', () => {\r\n if(input.checked) {\r\n onChange(input.value);\r\n }\r\n });\r\n });\r\n\r\n return form;\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\n// https://stackoverflow.com/a/30810322\r\nfunction fallbackCopyTextToClipboard(text: string) {\r\n var textArea = document.createElement(\"textarea\");\r\n textArea.value = text;\r\n \r\n // Avoid scrolling to bottom\r\n textArea.style.top = \"0\";\r\n textArea.style.left = \"0\";\r\n textArea.style.position = \"fixed\";\r\n\r\n document.body.appendChild(textArea);\r\n textArea.focus();\r\n textArea.select();\r\n\r\n try {\r\n document.execCommand('copy');\r\n //const successful = document.execCommand('copy');\r\n //const msg = successful ? 'successful' : 'unsuccessful';\r\n //console.log('Fallback: Copying text command was ' + msg);\r\n } catch(err) {\r\n //console.error('Fallback: Oops, unable to copy', err);\r\n }\r\n\r\n document.body.removeChild(textArea);\r\n}\r\n\r\nexport function copyTextToClipboard(text: string) {\r\n if(!navigator.clipboard) {\r\n fallbackCopyTextToClipboard(text);\r\n return;\r\n }\r\n \r\n navigator.clipboard.writeText(text);/* .then(function() {\r\n console.log('Async: Copying to clipboard was successful!');\r\n }, function(err) {\r\n console.error('Async: Could not copy text: ', err);\r\n }); */\r\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appStateManager from \"../lib/appManagers/appStateManager\";\r\nimport { getDeepProperty } from \"../helpers/object\";\r\nimport { LangPackKey, _i18n } from \"../lib/langPack\";\r\n\r\nexport default class RadioField {\r\n public input: HTMLInputElement;\r\n public label: HTMLLabelElement;\r\n public main: HTMLElement;\r\n\r\n constructor(options: {\r\n text?: string, \r\n langKey?: LangPackKey,\r\n name: string, \r\n value?: string, \r\n stateKey?: string\r\n }) {\r\n const label = this.label = document.createElement('label');\r\n label.classList.add('radio-field');\r\n \r\n const input = this.input = document.createElement('input');\r\n input.type = 'radio';\r\n /* input.id = */input.name = 'input-radio-' + options.name;\r\n \r\n if(options.value) {\r\n input.value = options.value;\r\n \r\n if(options.stateKey) {\r\n appStateManager.getState().then(state => {\r\n input.checked = getDeepProperty(state, options.stateKey) === options.value;\r\n });\r\n \r\n input.addEventListener('change', () => {\r\n appStateManager.setByKey(options.stateKey, options.value);\r\n });\r\n }\r\n }\r\n \r\n const main = this.main = document.createElement('div');\r\n main.classList.add('radio-field-main');\r\n \r\n if(options.text) {\r\n main.innerHTML = options.text;\r\n /* const caption = document.createElement('div');\r\n caption.classList.add('radio-field-main-caption');\r\n caption.innerHTML = text;\r\n \r\n if(subtitle) {\r\n label.classList.add('radio-field-with-subtitle');\r\n caption.insertAdjacentHTML('beforeend', `<div class=\"radio-field-main-subtitle\">${subtitle}</div>`);\r\n }\r\n \r\n main.append(caption); */\r\n } else if(options.langKey) {\r\n _i18n(main, options.langKey);\r\n }\r\n \r\n label.append(input, main);\r\n }\r\n\r\n get checked() {\r\n return this.input.checked;\r\n }\r\n\r\n set checked(checked: boolean) {\r\n this.setValueSilently(checked);\r\n\r\n const event = new Event('change', {bubbles: true, cancelable: true});\r\n this.input.dispatchEvent(event);\r\n }\r\n\r\n public setValueSilently(checked: boolean) {\r\n this.input.checked = checked;\r\n }\r\n};\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport { i18n, LangPackKey } from \"../lib/langPack\";\r\n\r\nconst toastEl = document.createElement('div');\r\ntoastEl.classList.add('toast');\r\nexport function toast(content: string | Node) {\r\n replaceContent(toastEl, content);\r\n document.body.append(toastEl);\r\n\r\n if(toastEl.dataset.timeout) clearTimeout(+toastEl.dataset.timeout);\r\n toastEl.dataset.timeout = '' + setTimeout(() => {\r\n toastEl.remove();\r\n delete toastEl.dataset.timeout;\r\n }, 3000);\r\n}\r\n\r\nexport function toastNew(options: Partial<{\r\n langPackKey: LangPackKey\r\n}>) {\r\n toast(i18n(options.langPackKey));\r\n}\r\n","// * Jolly Cobra's schedulers\r\n\r\nimport { AnyFunction, Awaited } from \"../../types\";\r\n\r\nexport default function debounce<F extends AnyFunction>(\r\n fn: F,\r\n ms: number,\r\n shouldRunFirst = true,\r\n shouldRunLast = true,\r\n) {\r\n let waitingTimeout: number;\r\n let waitingPromise: Promise<Awaited<ReturnType<F>>>, resolve: (result: any) => void, reject: () => void;\r\n let hadNewCall = false;\r\n\r\n return (...args: Parameters<F>): typeof waitingPromise => {\r\n if(!waitingPromise) waitingPromise = new Promise((_resolve, _reject) => (resolve = _resolve, reject = _reject));\r\n\r\n if(waitingTimeout) {\r\n clearTimeout(waitingTimeout);\r\n hadNewCall = true;\r\n reject();\r\n waitingPromise = new Promise((_resolve, _reject) => (resolve = _resolve, reject = _reject));\r\n } else if(shouldRunFirst) {\r\n // @ts-ignore\r\n resolve(fn(...args));\r\n hadNewCall = false;\r\n }\r\n\r\n waitingTimeout = setTimeout(() => {\r\n // will run if should run last or first but with new call\r\n if(shouldRunLast && (!shouldRunFirst || hadNewCall)) {\r\n // @ts-ignore\r\n resolve(fn(...args));\r\n }\r\n\r\n waitingTimeout = waitingPromise = resolve = reject = undefined;\r\n hadNewCall = false;\r\n }, ms) as any;\r\n\r\n waitingPromise.catch(() => {});\r\n return waitingPromise;\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\nimport debounce from \"../helpers/schedulers/debounce\";\r\nimport appChatsManager from \"../lib/appManagers/appChatsManager\";\r\nimport { LangPackKey } from \"../lib/langPack\";\r\nimport apiManager from \"../lib/mtproto/mtprotoworker\";\r\nimport RichTextProcessor from \"../lib/richtextprocessor\";\r\nimport InputField, { InputFieldOptions, InputState } from \"./inputField\";\r\n\r\nexport class UsernameInputField extends InputField {\r\n private checkUsernamePromise: Promise<any>;\r\n private checkUsernameDebounced: (username: string) => void;\r\n public options: InputFieldOptions & {\r\n peerId: number,\r\n listenerSetter: ListenerSetter,\r\n onChange?: () => void,\r\n invalidText: LangPackKey,\r\n takenText: LangPackKey,\r\n availableText: LangPackKey,\r\n head?: string\r\n };\r\n\r\n constructor(options: UsernameInputField['options']) {\r\n super(options);\r\n\r\n this.checkUsernameDebounced = debounce(this.checkUsername.bind(this), 150, false, true);\r\n\r\n options.listenerSetter.add(this.input)('input', () => {\r\n const value = this.getValue();\r\n\r\n //console.log('userNameInput:', value);\r\n if(value === this.originalValue || !value.length) {\r\n this.setState(InputState.Neutral, this.options.label);\r\n this.options.onChange && this.options.onChange();\r\n return;\r\n } else if(!RichTextProcessor.isUsernameValid(value)) { // does not check the last underscore\r\n this.setError(this.options.invalidText);\r\n } else {\r\n this.setState(InputState.Neutral);\r\n }\r\n\r\n if(this.input.classList.contains('error')) {\r\n this.options.onChange && this.options.onChange();\r\n return;\r\n }\r\n\r\n this.checkUsernameDebounced(value);\r\n });\r\n }\r\n\r\n public getValue() {\r\n let value = this.value;\r\n if(this.options.head) {\r\n value = value.slice(this.options.head.length);\r\n this.setValueSilently(this.options.head + value);\r\n }\r\n\r\n return value;\r\n }\r\n\r\n private checkUsername(username: string) {\r\n if(this.checkUsernamePromise) return;\r\n\r\n if(this.options.peerId) {\r\n this.checkUsernamePromise = apiManager.invokeApi('channels.checkUsername', {\r\n channel: appChatsManager.getChannelInput(-this.options.peerId),\r\n username\r\n });\r\n } else {\r\n this.checkUsernamePromise = apiManager.invokeApi('account.checkUsername', {username});\r\n }\r\n\r\n this.checkUsernamePromise.then(available => {\r\n if(this.getValue() !== username) return;\r\n\r\n if(available) {\r\n this.setState(InputState.Valid, this.options.availableText);\r\n } else {\r\n this.setError(this.options.takenText);\r\n }\r\n }, (err) => {\r\n if(this.getValue() !== username) return;\r\n\r\n switch(err.type) {\r\n case 'USERNAME_INVALID': {\r\n this.setError(this.options.invalidText);\r\n break;\r\n }\r\n }\r\n }).then(() => {\r\n this.checkUsernamePromise = undefined;\r\n this.options.onChange && this.options.onChange();\r\n\r\n const value = this.getValue();\r\n if(value !== username && this.isValid() && RichTextProcessor.isUsernameValid(value)) {\r\n this.checkUsername(value);\r\n }\r\n });\r\n };\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport AvatarElement from \"../avatar\";\nimport PopupElement, { addCancelButton, PopupButton, PopupOptions } from \".\";\nimport { i18n, LangPackKey } from \"../../lib/langPack\";\nimport CheckboxField, { CheckboxFieldOptions } from \"../checkboxField\";\n\nexport type PopupPeerButtonCallbackCheckboxes = Set<LangPackKey>;\nexport type PopupPeerButtonCallback = (checkboxes?: PopupPeerButtonCallbackCheckboxes) => void;\nexport type PopupPeerCheckboxOptions = CheckboxFieldOptions & {checkboxField?: CheckboxField};\n\nexport type PopupPeerOptions = PopupOptions & Partial<{\n peerId: number,\n title: string,\n titleLangKey?: LangPackKey,\n titleLangArgs?: any[],\n noTitle?: boolean,\n description: string,\n descriptionLangKey?: LangPackKey,\n descriptionLangArgs?: any[],\n buttons?: Array<Omit<PopupButton, 'callback'> & Partial<{callback: PopupPeerButtonCallback}>>,\n checkboxes: Array<PopupPeerCheckboxOptions>\n}>;\nexport default class PopupPeer extends PopupElement {\n constructor(private className: string, options: PopupPeerOptions = {}) {\n super('popup-peer' + (className ? ' ' + className : ''), options.buttons && addCancelButton(options.buttons), {overlayClosable: true, ...options});\n\n if(options.peerId) {\n let avatarEl = new AvatarElement();\n avatarEl.setAttribute('dialog', '1');\n avatarEl.setAttribute('peer', '' + options.peerId);\n avatarEl.classList.add('avatar-32');\n this.header.prepend(avatarEl);\n }\n\n if(!options.noTitle) {\n if(options.titleLangKey || !options.title) this.title.append(i18n(options.titleLangKey || 'AppName', options.titleLangArgs));\n else this.title.innerText = options.title || '';\n }\n\n const fragment = document.createDocumentFragment();\n\n if(options.descriptionLangKey || options.description) {\n const p = document.createElement('p');\n p.classList.add('popup-description');\n if(options.descriptionLangKey) p.append(i18n(options.descriptionLangKey, options.descriptionLangArgs));\n else if(options.description) p.innerHTML = options.description;\n \n fragment.append(p);\n }\n\n if(options.checkboxes) {\n this.container.classList.add('have-checkbox');\n \n options.checkboxes.forEach(o => {\n o.withRipple = false;\n const checkboxField = new CheckboxField(o);\n o.checkboxField = checkboxField;\n fragment.append(checkboxField.label);\n });\n\n options.buttons.forEach(button => {\n if(button.callback) {\n const original = button.callback;\n button.callback = () => {\n const c: Set<LangPackKey> = new Set();\n options.checkboxes.forEach(o => {\n if(o.checkboxField.checked) {\n c.add(o.text);\n }\n });\n original(c);\n };\n }\n });\n }\n\n this.container.insertBefore(fragment, this.header.nextElementSibling);\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { copyTextToClipboard } from \"../../../helpers/clipboard\";\r\nimport { randomLong } from \"../../../helpers/random\";\r\nimport { Chat, ChatFull, ExportedChatInvite } from \"../../../layer\";\r\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport Button from \"../../button\";\r\nimport { setButtonLoader } from \"../../misc\";\r\nimport RadioField from \"../../radioField\";\r\nimport Row, { RadioFormFromRows } from \"../../row\";\r\nimport { SettingSection } from \"../../sidebarLeft\";\r\nimport { toast } from \"../../toast\";\r\nimport { UsernameInputField } from \"../../usernameInputField\";\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport I18n from \"../../../lib/langPack\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport ButtonCorner from \"../../buttonCorner\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\r\n\r\nexport default class AppChatTypeTab extends SliderSuperTabEventable {\r\n public chatId: number;\r\n public chatFull: ChatFull;\r\n\r\n protected init() {\r\n this.container.classList.add('edit-peer-container', 'group-type-container');\r\n\r\n const isBroadcast = appChatsManager.isBroadcast(this.chatId);\r\n\r\n this.setTitle(isBroadcast ? 'ChannelType' : 'GroupType');\r\n\r\n const section = new SettingSection({\r\n name: isBroadcast ? 'ChannelType' : 'GroupType'\r\n });\r\n\r\n const random = randomLong();\r\n const privateRow = new Row({\r\n radioField: new RadioField({\r\n langKey: isBroadcast ? 'ChannelPrivate' : 'MegaPrivate', \r\n name: random, \r\n value: 'private'\r\n }),\r\n subtitleLangKey: isBroadcast ? 'ChannelPrivateInfo' : 'MegaPrivateInfo'\r\n });\r\n const publicRow = new Row({\r\n radioField: new RadioField({\r\n langKey: isBroadcast ? 'ChannelPublic' : 'MegaPublic', \r\n name: random, \r\n value: 'public'\r\n }),\r\n subtitleLangKey: isBroadcast ? 'ChannelPublicInfo' : 'MegaPublicInfo'\r\n });\r\n const form = RadioFormFromRows([privateRow, publicRow], (value) => {\r\n const a = [privateSection, publicSection];\r\n if(value === 'public') a.reverse();\r\n\r\n a[0].container.classList.remove('hide');\r\n a[1].container.classList.add('hide');\r\n\r\n onChange();\r\n });\r\n\r\n const chat: Chat = appChatsManager.getChat(this.chatId);\r\n\r\n section.content.append(form);\r\n\r\n const privateSection = new SettingSection({});\r\n\r\n //let revoked = false;\r\n const linkRow = new Row({\r\n title: (this.chatFull.exported_invite as ExportedChatInvite.chatInviteExported).link,\r\n subtitleLangKey: isBroadcast ? 'ChannelPrivateLinkHelp' : 'MegaPrivateLinkHelp',\r\n clickable: () => {\r\n copyTextToClipboard((this.chatFull.exported_invite as ExportedChatInvite.chatInviteExported).link);\r\n toast(I18n.format('LinkCopied', true));\r\n }\r\n });\r\n\r\n const btnRevoke = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'RevokeLink'});\r\n\r\n attachClickEvent(btnRevoke, () => {\r\n new PopupPeer('revoke-link', {\r\n buttons: [{\r\n langKey: 'RevokeButton',\r\n callback: () => {\r\n const toggle = toggleDisability([btnRevoke], true);\r\n \r\n appProfileManager.getChatInviteLink(this.chatId, true).then(link => {\r\n toggle();\r\n linkRow.title.innerHTML = link;\r\n //revoked = true;\r\n //onChange();\r\n });\r\n }\r\n }],\r\n titleLangKey: 'RevokeLink',\r\n descriptionLangKey: 'RevokeAlert'\r\n }).show();\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n privateSection.content.append(linkRow.container, btnRevoke);\r\n\r\n const publicSection = new SettingSection({\r\n caption: isBroadcast ? 'Channel.UsernameAboutChannel' : 'Channel.UsernameAboutGroup',\r\n noDelimiter: true\r\n });\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const placeholder = 't.me/';\r\n\r\n const onChange = () => {\r\n const changed = (privateRow.radioField.checked && (originalValue !== placeholder/* || revoked */)) \r\n || (linkInputField.isValid() && linkInputField.input.classList.contains('valid'));\r\n applyBtn.classList.toggle('is-visible', changed);\r\n };\r\n\r\n const linkInputField = new UsernameInputField({\r\n label: 'SetUrlPlaceholder',\r\n name: 'group-public-link',\r\n plainText: true,\r\n listenerSetter: this.listenerSetter,\r\n availableText: 'Link.Available',\r\n invalidText: 'Link.Invalid',\r\n takenText: 'Link.Taken',\r\n onChange: onChange,\r\n peerId: -this.chatId,\r\n head: placeholder\r\n });\r\n\r\n const originalValue = placeholder + ((chat as Chat.channel).username || '');\r\n\r\n inputWrapper.append(linkInputField.container)\r\n publicSection.content.append(inputWrapper);\r\n\r\n const applyBtn = ButtonCorner({icon: 'check', className: 'is-visible'});\r\n this.content.append(applyBtn);\r\n\r\n attachClickEvent(applyBtn, () => {\r\n /* const unsetLoader = */setButtonLoader(applyBtn);\r\n const username = publicRow.radioField.checked ? linkInputField.getValue() : '';\r\n appChatsManager.migrateChat(this.chatId).then(channelId => {\r\n return appChatsManager.updateUsername(channelId, username);\r\n }).then(() => {\r\n //unsetLoader();\r\n this.close();\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n (originalValue !== placeholder ? publicRow : privateRow).radioField.checked = true;\r\n linkInputField.setOriginalValue(originalValue);\r\n\r\n this.scrollable.append(section.container, privateSection.container, publicSection.container);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport Scrollable from \"../components/scrollable\";\r\nimport { safeAssign } from \"./object\";\r\n\r\nexport default class ScrollableLoader {\r\n public loading = false;\r\n private scrollable: Scrollable;\r\n private getPromise: () => Promise<any>;\r\n private promise: Promise<any>;\r\n private loaded = false;\r\n\r\n constructor(options: {\r\n scrollable: ScrollableLoader['scrollable'],\r\n getPromise: ScrollableLoader['getPromise']\r\n }) {\r\n safeAssign(this, options);\r\n\r\n options.scrollable.onScrolledBottom = () => {\r\n this.load();\r\n };\r\n }\r\n \r\n public load() {\r\n if(this.loaded) {\r\n return Promise.resolve();\r\n }\r\n \r\n if(this.loading) {\r\n return this.promise;\r\n }\r\n\r\n this.loading = true;\r\n this.promise = this.getPromise().then(done => {\r\n this.loading = false;\r\n this.promise = undefined;\r\n\r\n if(done) {\r\n this.loaded = true;\r\n this.scrollable.onScrolledBottom = null;\r\n } else {\r\n this.scrollable.checkForTriggers();\r\n }\r\n }, () => {\r\n this.promise = undefined;\r\n this.loading = false;\r\n });\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appChatsManager, { ChatRights } from \"../lib/appManagers/appChatsManager\";\nimport appDialogsManager from \"../lib/appManagers/appDialogsManager\";\nimport appMessagesManager, { Dialog } from \"../lib/appManagers/appMessagesManager\";\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\nimport rootScope from \"../lib/rootScope\";\nimport Scrollable from \"./scrollable\";\nimport { FocusDirection } from \"../helpers/fastSmoothScroll\";\nimport CheckboxField from \"./checkboxField\";\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\nimport { safeAssign } from \"../helpers/object\";\nimport { i18n, LangPackKey, _i18n } from \"../lib/langPack\";\nimport findUpAttribute from \"../helpers/dom/findUpAttribute\";\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\nimport PeerTitle from \"./peerTitle\";\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\nimport replaceContent from \"../helpers/dom/replaceContent\";\nimport { filterUnique } from \"../helpers/array\";\nimport debounce from \"../helpers/schedulers/debounce\";\nimport windowSize from \"../helpers/windowSize\";\n\ntype PeerType = 'contacts' | 'dialogs' | 'channelParticipants';\n\n// TODO: правильная сортировка для addMembers, т.е. для peerType: 'contacts', потому что там идут сначала контакты - потом неконтакты, а должно всё сортироваться по имени\n\nlet loadedAllDialogs = false, loadAllDialogsPromise: Promise<any>;\nexport default class AppSelectPeers {\n public container = document.createElement('div');\n public list = appDialogsManager.createChatList(/* {\n handheldsSize: 66,\n avatarSize: 48\n } */);\n public chatsContainer = document.createElement('div');\n public scrollable: Scrollable;\n public selectedScrollable: Scrollable;\n \n public selectedContainer: HTMLElement;\n public input: HTMLInputElement;\n \n //public selected: {[peerId: number]: HTMLElement} = {};\n public selected = new Set<any>();\n\n public freezed = false;\n\n private folderId = 0;\n private offsetIndex = 0;\n private promise: Promise<any>;\n\n private query = '';\n private cachedContacts: number[];\n\n private loadedWhat: Partial<{[k in 'dialogs' | 'archived' | 'contacts' | 'channelParticipants']: true}> = {};\n\n private renderedPeerIds: Set<number> = new Set();\n\n private appendTo: HTMLElement;\n private onChange: (length: number) => void;\n private peerType: PeerType[] = ['dialogs'];\n private renderResultsFunc: (peerIds: number[]) => void;\n private chatRightsAction: ChatRights;\n private multiSelect = true;\n private rippleEnabled = true;\n private avatarSize = 48;\n\n private tempIds: {[k in keyof AppSelectPeers['loadedWhat']]: number} = {};\n private peerId = 0;\n\n private placeholder: LangPackKey;\n\n private selfPresence: LangPackKey = 'Presence.YourChat';\n \n private needSwitchList = false;\n \n constructor(options: {\n appendTo: AppSelectPeers['appendTo'], \n onChange?: AppSelectPeers['onChange'], \n peerType?: AppSelectPeers['peerType'], \n peerId?: number,\n onFirstRender?: () => void, \n renderResultsFunc?: AppSelectPeers['renderResultsFunc'], \n chatRightsAction?: AppSelectPeers['chatRightsAction'], \n multiSelect?: AppSelectPeers['multiSelect'],\n rippleEnabled?: boolean,\n avatarSize?: AppSelectPeers['avatarSize'],\n placeholder?: LangPackKey,\n selfPresence?: LangPackKey\n }) {\n safeAssign(this, options);\n\n this.container.classList.add('selector');\n\n const f = (this.renderResultsFunc || this.renderResults).bind(this);\n this.renderResultsFunc = (peerIds: number[]) => {\n if(this.needSwitchList) {\n this.scrollable.splitUp.replaceWith(this.list);\n this.scrollable.setVirtualContainer(this.list);\n this.needSwitchList = false;\n }\n \n peerIds = peerIds.filter(peerId => {\n const notRendered = !this.renderedPeerIds.has(peerId);\n if(notRendered) this.renderedPeerIds.add(peerId);\n return notRendered;\n });\n\n return f(peerIds);\n };\n\n this.input = document.createElement('input');\n this.input.classList.add('selector-search-input');\n if(this.placeholder) {\n _i18n(this.input, this.placeholder, undefined, 'placeholder');\n } else {\n _i18n(this.input, 'SendMessageTo', undefined, 'placeholder');\n }\n\n this.input.type = 'text';\n\n if(this.multiSelect) {\n let topContainer = document.createElement('div');\n topContainer.classList.add('selector-search-container');\n \n this.selectedContainer = document.createElement('div');\n this.selectedContainer.classList.add('selector-search');\n \n this.selectedContainer.append(this.input);\n topContainer.append(this.selectedContainer);\n this.selectedScrollable = new Scrollable(topContainer);\n \n let delimiter = document.createElement('hr');\n\n this.selectedContainer.addEventListener('click', (e) => {\n if(this.freezed) return;\n let target = e.target as HTMLElement;\n target = findUpClassName(target, 'selector-user');\n \n if(!target) return;\n \n const peerId = target.dataset.key;\n const li = this.chatsContainer.querySelector('[data-peer-id=\"' + peerId + '\"]') as HTMLElement;\n if(!li) {\n this.remove(+peerId || peerId);\n } else {\n li.click();\n }\n });\n\n this.container.append(topContainer, delimiter);\n }\n\n this.chatsContainer.classList.add('chatlist-container');\n this.chatsContainer.append(this.list);\n this.scrollable = new Scrollable(this.chatsContainer);\n this.scrollable.setVirtualContainer(this.list);\n\n this.chatsContainer.addEventListener('click', (e) => {\n const target = findUpAttribute(e.target, 'data-peer-id') as HTMLElement;\n cancelEvent(e);\n\n if(!target) return;\n if(this.freezed) return;\n\n let key: any = target.dataset.peerId;\n key = +key || key;\n\n if(!this.multiSelect) {\n this.add(key);\n return;\n }\n\n //target.classList.toggle('active');\n if(this.selected.has(key)) {\n this.remove(key);\n } else {\n this.add(key);\n }\n\n const checkbox = target.querySelector('input') as HTMLInputElement;\n checkbox.checked = !checkbox.checked;\n });\n\n const debouncedInput = debounce(this.onInput, 200, false, true);\n this.input.addEventListener('input', debouncedInput);\n\n this.scrollable.onScrolledBottom = () => {\n this.getMoreResults();\n };\n\n this.container.append(this.chatsContainer);\n this.appendTo.append(this.container);\n\n // WARNING TIMEOUT\n setTimeout(() => {\n let getResultsPromise = this.getMoreResults() as Promise<any>;\n if(options.onFirstRender) {\n getResultsPromise.then(() => {\n options.onFirstRender();\n });\n }\n }, 0);\n }\n\n private onInput = () => {\n const value = this.input.value;\n if(this.query !== value) {\n if(this.peerType.includes('contacts')) {\n this.cachedContacts = null;\n }\n \n if(this.peerType.includes('dialogs')) {\n this.folderId = 0;\n this.offsetIndex = 0;\n }\n\n for(let i in this.tempIds) {\n // @ts-ignore\n ++this.tempIds[i];\n }\n\n this.list = appDialogsManager.createChatList();\n\n this.promise = null;\n this.loadedWhat = {};\n this.query = value;\n this.renderedPeerIds.clear();\n this.needSwitchList = true;\n \n //console.log('selectPeers input:', this.query);\n this.getMoreResults();\n }\n };\n\n private renderSaved() {\n if(!this.offsetIndex && this.folderId === 0 && this.peerType.includes('dialogs') && (!this.query || appUsersManager.testSelfSearch(this.query))) {\n this.renderResultsFunc([rootScope.myId]);\n }\n }\n\n private getTempId(type: keyof AppSelectPeers['tempIds']) {\n if(this.tempIds[type] === undefined) {\n this.tempIds[type] = 0;\n }\n\n return ++this.tempIds[type];\n }\n\n private async getMoreDialogs(): Promise<any> {\n if(this.promise) return this.promise;\n\n if(this.loadedWhat.dialogs && this.loadedWhat.archived) {\n return;\n }\n \n // в десктопе - сначала без группы, потом архивные, потом контакты без сообщений\n const pageCount = windowSize.windowH / 72 * 1.25 | 0;\n\n const tempId = this.getTempId('dialogs');\n const promise = appMessagesManager.getConversations(this.query, this.offsetIndex, pageCount, this.folderId, true).promise;\n this.promise = promise;\n const value = await promise;\n if(this.tempIds.dialogs !== tempId) {\n return;\n }\n\n this.promise = null;\n\n let dialogs = value.dialogs as Dialog[];\n if(dialogs.length) {\n const newOffsetIndex = dialogs[dialogs.length - 1].index || 0;\n\n dialogs = dialogs.slice();\n dialogs.findAndSplice(d => d.peerId === rootScope.myId); // no my account\n\n if(this.chatRightsAction) {\n dialogs = dialogs.filter(d => this.filterByRights(d.peerId));\n }\n\n this.renderSaved();\n\n this.offsetIndex = newOffsetIndex;\n\n this.renderResultsFunc(dialogs.map(dialog => dialog.peerId));\n }\n \n if(value.isEnd) {\n if(!this.loadedWhat.dialogs) {\n this.renderSaved();\n\n this.loadedWhat.dialogs = true;\n this.offsetIndex = 0;\n this.folderId = 1;\n\n return this.getMoreDialogs();\n } else {\n this.loadedWhat.archived = true;\n\n if(!this.loadedWhat.contacts && this.peerType.includes('contacts')) {\n return this.getMoreContacts();\n }\n }\n }\n }\n\n private filterByRights(peerId: number) {\n return (\n peerId > 0 && \n (this.chatRightsAction !== 'send_messages' || appUsersManager.canSendToUser(peerId))\n ) || appChatsManager.hasRights(-peerId, this.chatRightsAction);\n }\n\n private async getMoreContacts() {\n if(this.promise) return this.promise;\n\n if(this.loadedWhat.contacts) {\n return;\n }\n\n if(!this.cachedContacts) {\n /* const promises: Promise<any>[] = [appUsersManager.getContacts(this.query)];\n if(!this.peerType.includes('dialogs')) {\n promises.push(appMessagesManager.getConversationsAll());\n }\n\n this.promise = Promise.all(promises);\n this.cachedContacts = (await this.promise)[0].slice(); */\n const tempId = this.getTempId('contacts');\n const promise = Promise.all([\n appUsersManager.getContacts(this.query),\n this.query ? appUsersManager.searchContacts(this.query) : undefined\n ]);\n\n this.promise = promise;\n const [cachedContacts, searchResult] = await promise;\n if(this.tempIds.contacts !== tempId) {\n return;\n }\n\n if(searchResult) {\n let resultPeerIds = searchResult.my_results.concat(searchResult.results);\n\n if(this.chatRightsAction) {\n resultPeerIds = resultPeerIds.filter(peerId => this.filterByRights(peerId));\n }\n\n if(!this.peerType.includes('dialogs')) {\n resultPeerIds = resultPeerIds.filter(peerId => peerId > 0);\n }\n\n this.cachedContacts = filterUnique(cachedContacts.concat(resultPeerIds));\n } else this.cachedContacts = cachedContacts.slice();\n\n this.cachedContacts.findAndSplice(userId => userId === rootScope.myId); // no my account\n this.promise = null;\n }\n\n if(this.cachedContacts.length) {\n const pageCount = windowSize.windowH / 72 * 1.25 | 0;\n const arr = this.cachedContacts.splice(0, pageCount);\n this.renderResultsFunc(arr);\n }\n \n if(!this.cachedContacts.length) {\n this.loadedWhat.contacts = true;\n\n // need to load non-contacts\n /* if(!this.peerType.includes('dialogs')) {\n return this.getMoreDialogs();\n } */\n }\n }\n\n private async getMoreChannelParticipants() {\n if(this.promise) return this.promise;\n\n if(this.loadedWhat.channelParticipants) {\n return;\n }\n\n const pageCount = 50; // same as in group permissions to use cache\n\n const tempId = this.getTempId('channelParticipants');\n const promise = appProfileManager.getChannelParticipants(-this.peerId, {_: 'channelParticipantsSearch', q: this.query}, pageCount, this.list.childElementCount);\n const participants = await promise;\n if(this.tempIds.channelParticipants !== tempId) {\n return;\n }\n \n const peerIds = participants.participants.map(participant => {\n return appChatsManager.getParticipantPeerId(participant);\n });\n peerIds.findAndSplice(u => u === rootScope.myId);\n this.renderResultsFunc(peerIds);\n\n if(this.list.childElementCount >= participants.count || participants.participants.length < pageCount) {\n this.loadedWhat.channelParticipants = true;\n }\n }\n\n checkForTriggers = () => {\n this.scrollable.checkForTriggers();\n };\n\n private getMoreResults() {\n const get = () => {\n const promises: Promise<any>[] = [];\n\n if(!loadedAllDialogs && (this.peerType.includes('dialogs')/* || this.peerType.includes('contacts') */)) {\n if(!loadAllDialogsPromise) {\n loadAllDialogsPromise = appMessagesManager.getConversationsAll()\n .then(() => {\n loadedAllDialogs = true;\n }).finally(() => {\n loadAllDialogsPromise = null;\n });\n }\n\n promises.push(loadAllDialogsPromise);\n }\n \n if((this.peerType.includes('dialogs')/* || this.loadedWhat.contacts */) && !this.loadedWhat.archived) { // to load non-contacts\n promises.push(this.getMoreDialogs());\n \n if(!this.loadedWhat.archived) {\n return promises;\n }\n }\n \n if(this.peerType.includes('contacts') && !this.loadedWhat.contacts) {\n promises.push(this.getMoreContacts());\n }\n\n if(this.peerType.includes('channelParticipants') && !this.loadedWhat.channelParticipants) {\n promises.push(this.getMoreChannelParticipants());\n }\n \n return promises;\n };\n \n const promises = get();\n const promise = Promise.all(promises);\n if(promises.length) {\n promise.then(this.checkForTriggers);\n }\n\n return promise;\n }\n\n private renderResults(peerIds: number[]) {\n //console.log('will renderResults:', peerIds);\n\n // оставим только неконтакты с диалогов\n if(!this.peerType.includes('dialogs') && this.loadedWhat.contacts) {\n peerIds = peerIds.filter(peerId => {\n return appUsersManager.isNonContactUser(peerId);\n });\n }\n\n peerIds.forEach(peerId => {\n const {dom} = appDialogsManager.addDialogNew({\n dialog: peerId,\n container: this.scrollable,\n drawStatus: false,\n rippleEnabled: this.rippleEnabled,\n avatarSize: this.avatarSize\n });\n\n if(this.multiSelect) {\n const selected = this.selected.has(peerId);\n const checkboxField = new CheckboxField();\n\n if(selected) {\n //dom.listEl.classList.add('active');\n checkboxField.input.checked = true;\n }\n\n dom.containerEl.prepend(checkboxField.label);\n }\n\n let subtitleEl: HTMLElement;\n if(peerId < 0) {\n subtitleEl = appProfileManager.getChatMembersString(-peerId);\n } else if(peerId === rootScope.myId) {\n subtitleEl = i18n(this.selfPresence);\n } else {\n subtitleEl = appUsersManager.getUserStatusString(peerId);\n }\n\n dom.lastMessageSpan.append(subtitleEl);\n });\n }\n\n public add(peerId: any, title?: string | HTMLElement, scroll = true) {\n //console.trace('add');\n this.selected.add(peerId);\n\n if(!this.multiSelect) {\n this.onChange(this.selected.size);\n return;\n }\n\n if(this.query.trim()) {\n this.input.value = '';\n this.onInput();\n }\n\n const div = document.createElement('div');\n div.classList.add('selector-user', 'scale-in');\n\n const avatarEl = document.createElement('avatar-element');\n avatarEl.classList.add('selector-user-avatar', 'tgico');\n avatarEl.setAttribute('dialog', '1');\n avatarEl.classList.add('avatar-32');\n\n div.dataset.key = '' + peerId;\n if(typeof(peerId) === 'number') {\n if(title === undefined) {\n title = new PeerTitle({peerId, dialog: true}).element;\n }\n\n avatarEl.setAttribute('peer', '' + peerId);\n }\n\n if(title) {\n if(typeof(title) === 'string') {\n div.innerHTML = title;\n } else {\n replaceContent(div, title);\n div.append(title);\n }\n }\n\n div.insertAdjacentElement('afterbegin', avatarEl);\n\n this.selectedContainer.insertBefore(div, this.input);\n //this.selectedScrollable.scrollTop = this.selectedScrollable.scrollHeight;\n this.onChange && this.onChange(this.selected.size);\n \n if(scroll) {\n this.selectedScrollable.scrollIntoViewNew(this.input, 'center');\n }\n \n return div;\n }\n\n public remove(key: any) {\n if(!this.multiSelect) return;\n //const div = this.selected[peerId];\n const div = this.selectedContainer.querySelector(`[data-key=\"${key}\"]`) as HTMLElement;\n div.classList.remove('scale-in');\n void div.offsetWidth;\n div.classList.add('scale-out');\n\n const onAnimationEnd = () => {\n this.selected.delete(key);\n div.remove();\n this.onChange && this.onChange(this.selected.size);\n };\n\n if(rootScope.settings.animationsEnabled) {\n div.addEventListener('animationend', onAnimationEnd, {once: true});\n } else {\n onAnimationEnd();\n }\n }\n\n public getSelected() {\n return [...this.selected];\n }\n\n public addInitial(values: any[]) {\n values.forEach(value => {\n this.add(value, undefined, false);\n });\n\n window.requestAnimationFrame(() => { // ! not the best place for this raf though it works\n this.selectedScrollable.scrollIntoViewNew(this.input, 'center', undefined, undefined, FocusDirection.Static);\n });\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport AppSelectPeers from \"../appSelectPeers\";\r\nimport PopupElement from \".\";\r\nimport { LangPackKey, _i18n } from \"../../lib/langPack\";\r\n\r\nexport default class PopupPickUser extends PopupElement {\r\n protected selector: AppSelectPeers;\r\n \r\n constructor(options: {\r\n peerTypes: AppSelectPeers['peerType'], \r\n onSelect?: (peerId: number) => Promise<void> | void, \r\n onClose?: () => void,\r\n placeholder: LangPackKey,\r\n chatRightsAction?: AppSelectPeers['chatRightsAction'],\r\n peerId?: number,\r\n selfPresence?: LangPackKey\r\n }) {\r\n super('popup-forward', null, {closable: true, overlayClosable: true, body: true});\r\n\r\n if(options.onClose) this.onClose = options.onClose;\r\n\r\n this.selector = new AppSelectPeers({\r\n appendTo: this.body, \r\n onChange: async() => {\r\n const selected = this.selector.getSelected();\r\n const peerId = selected[selected.length - 1];\r\n \r\n if(options.onSelect) {\r\n const res = options.onSelect(peerId);\r\n if(res instanceof Promise) {\r\n try {\r\n await res;\r\n } catch(err) {\r\n return;\r\n }\r\n }\r\n }\r\n\r\n this.selector = null;\r\n this.hide();\r\n }, \r\n peerType: options.peerTypes, \r\n onFirstRender: () => {\r\n this.show();\r\n this.selector.checkForTriggers(); // ! due to zero height before mounting\r\n\r\n if(!IS_TOUCH_SUPPORTED) {\r\n this.selector.input.focus();\r\n }\r\n }, \r\n chatRightsAction: options.chatRightsAction, \r\n multiSelect: false,\r\n rippleEnabled: false,\r\n avatarSize: 46,\r\n peerId: options.peerId,\r\n placeholder: options.placeholder,\r\n selfPresence: options.selfPresence\r\n });\r\n\r\n //this.scrollable = new Scrollable(this.body);\r\n\r\n this.title.append(this.selector.input);\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\nimport { deepEqual } from \"../../../helpers/object\";\nimport { ChannelParticipant } from \"../../../layer\";\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\nimport Button from \"../../button\";\nimport { SettingSection } from \"../../sidebarLeft\";\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\nimport { ChatPermissions } from \"./groupPermissions\";\n\nexport default class AppUserPermissionsTab extends SliderSuperTabEventable {\n public participant: ChannelParticipant;\n public chatId: number;\n public userId: number;\n\n protected init() {\n this.container.classList.add('edit-peer-container', 'user-permissions-container');\n this.setTitle('UserRestrictions');\n\n let destroyListener: () => void;\n\n {\n const section = new SettingSection({\n name: 'UserRestrictionsCanDo',\n });\n \n const div = document.createElement('div');\n div.classList.add('chatlist-container');\n section.content.insertBefore(div, section.title);\n\n const list = appDialogsManager.createChatList({new: true});\n div.append(list);\n\n const {dom} = appDialogsManager.addDialogNew({\n dialog: this.userId,\n container: list,\n drawStatus: false,\n rippleEnabled: true,\n avatarSize: 48\n });\n\n dom.lastMessageSpan.append(appUsersManager.getUserStatusString(this.userId));\n\n const p = new ChatPermissions({\n chatId: this.chatId,\n listenerSetter: this.listenerSetter,\n appendTo: section.content,\n participant: this.participant._ === 'channelParticipantBanned' ? this.participant : undefined\n });\n\n destroyListener = () => {\n //appChatsManager.editChatDefaultBannedRights(this.chatId, p.takeOut());\n const rights = p.takeOut();\n if(this.participant._ === 'channelParticipantBanned' && deepEqual(this.participant.banned_rights.pFlags, rights.pFlags)) {\n return;\n }\n\n appChatsManager.editBanned(this.chatId, this.participant, rights);\n };\n\n this.eventListener.addEventListener('destroy', destroyListener, {once: true});\n\n this.scrollable.append(section.container);\n }\n \n {\n const section = new SettingSection({});\n\n if(this.participant._ === 'channelParticipantBanned') {\n const btnDeleteException = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'GroupPermission.Delete'});\n\n attachClickEvent(btnDeleteException, () => {\n const toggle = toggleDisability([btnDeleteException], true);\n appChatsManager.clearChannelParticipantBannedRights(this.chatId, this.participant).then(() => {\n this.eventListener.removeEventListener('destroy', destroyListener);\n this.close();\n }, () => {\n toggle();\n });\n }, {listenerSetter: this.listenerSetter});\n \n section.content.append(btnDeleteException);\n }\n\n const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'deleteuser', text: 'UserRestrictionsBlock'});\n\n attachClickEvent(btnDelete, () => {\n const toggle = toggleDisability([btnDelete], true);\n appChatsManager.kickFromChannel(this.chatId, this.participant).then(() => {\n this.eventListener.removeEventListener('destroy', destroyListener);\n this.close();\n });\n /* new PopupPeer('popup-group-kick-user', {\n peerId: -this.chatId,\n title: 'Ban User?',\n description: `Are you sure you want to ban <b>${appPeersManager.getPeerTitle(this.userId)}</b>`,\n buttons: addCancelButton([{\n text: 'BAN',\n callback: () => {\n const toggle = toggleDisability([btnDelete], true);\n\n appChatsManager.kickFromChannel(this.chatId, this.participant).then(() => {\n this.eventListener.removeEventListener('destroy', destroyListener);\n this.close();\n }, () => {\n toggle();\n });\n },\n isDanger: true\n }])\n }).show(); */\n }, {listenerSetter: this.listenerSetter});\n\n section.content.append(btnDelete);\n\n this.scrollable.append(section.container);\n }\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\nimport findUpTag from \"../../../helpers/dom/findUpTag\";\nimport replaceContent from \"../../../helpers/dom/replaceContent\";\nimport ListenerSetter from \"../../../helpers/listenerSetter\";\nimport ScrollableLoader from \"../../../helpers/scrollableLoader\";\nimport { ChannelParticipant, Chat, ChatBannedRights, Update } from \"../../../layer\";\nimport appChatsManager, { ChatRights } from \"../../../lib/appManagers/appChatsManager\";\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\nimport appPeersManager from \"../../../lib/appManagers/appPeersManager\";\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\nimport I18n, { i18n, join, LangPackKey } from \"../../../lib/langPack\";\nimport rootScope from \"../../../lib/rootScope\";\nimport CheckboxField from \"../../checkboxField\";\nimport PopupPickUser from \"../../popups/pickUser\";\nimport Row from \"../../row\";\nimport { SettingSection } from \"../../sidebarLeft\";\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\nimport { toast } from \"../../toast\";\nimport AppUserPermissionsTab from \"./userPermissions\";\n\nexport class ChatPermissions {\n public v: Array<{\n flags: ChatRights[],\n text: LangPackKey,\n exceptionText: LangPackKey,\n checkboxField?: CheckboxField,\n }>;\n private toggleWith: Partial<{[chatRight in ChatRights]: ChatRights[]}>;\n\n constructor(options: {\n chatId: number,\n listenerSetter: ListenerSetter,\n appendTo: HTMLElement,\n participant?: ChannelParticipant.channelParticipantBanned\n }) {\n this.v = [\n {flags: ['send_messages'], text: 'UserRestrictionsSend', exceptionText: 'UserRestrictionsNoSend'},\n {flags: ['send_media'], text: 'UserRestrictionsSendMedia', exceptionText: 'UserRestrictionsNoSendMedia'},\n {flags: ['send_stickers', 'send_gifs'], text: 'UserRestrictionsSendStickers', exceptionText: 'UserRestrictionsNoSendStickers'},\n {flags: ['send_polls'], text: 'UserRestrictionsSendPolls', exceptionText: 'UserRestrictionsNoSendPolls'},\n {flags: ['embed_links'], text: 'UserRestrictionsEmbedLinks', exceptionText: 'UserRestrictionsNoEmbedLinks'},\n {flags: ['invite_users'], text: 'UserRestrictionsInviteUsers', exceptionText: 'UserRestrictionsNoInviteUsers'},\n {flags: ['pin_messages'], text: 'UserRestrictionsPinMessages', exceptionText: 'UserRestrictionsNoPinMessages'},\n {flags: ['change_info'], text: 'UserRestrictionsChangeInfo', exceptionText: 'UserRestrictionsNoChangeInfo'}\n ];\n\n this.toggleWith = {\n 'send_messages': ['send_media', 'send_stickers', 'send_polls', 'embed_links']\n };\n\n const chat: Chat.chat = appChatsManager.getChat(options.chatId);\n const defaultBannedRights = chat.default_banned_rights;\n const rights = options.participant ? appChatsManager.combineParticipantBannedRights(options.chatId, options.participant.banned_rights) : defaultBannedRights;\n \n for(const info of this.v) {\n const mainFlag = info.flags[0];\n info.checkboxField = new CheckboxField({\n text: info.text,\n checked: appChatsManager.hasRights(options.chatId, mainFlag, rights),\n restriction: true,\n withRipple: true\n });\n\n // @ts-ignore\n if(options.participant && defaultBannedRights.pFlags[mainFlag]) {\n info.checkboxField.input.disabled = true;\n \n /* options.listenerSetter.add(info.checkboxField.input)('change', (e) => {\n if(!e.isTrusted) {\n return;\n }\n\n cancelEvent(e);\n toast('This option is disabled for all members in Group Permissions.');\n info.checkboxField.checked = false;\n }); */\n\n attachClickEvent(info.checkboxField.label, (e) => {\n toast(I18n.format('UserRestrictionsDisabled', true));\n }, {listenerSetter: options.listenerSetter});\n }\n\n if(this.toggleWith[mainFlag]) {\n options.listenerSetter.add(info.checkboxField.input)('change', () => {\n if(!info.checkboxField.checked) {\n const other = this.v.filter(i => this.toggleWith[mainFlag].includes(i.flags[0]));\n other.forEach(info => {\n info.checkboxField.checked = false;\n });\n }\n });\n }\n\n options.appendTo.append(info.checkboxField.label);\n }\n }\n\n public takeOut() {\n const rights: ChatBannedRights = {\n _: 'chatBannedRights',\n until_date: 0x7FFFFFFF,\n pFlags: {}\n };\n\n for(const info of this.v) {\n const banned = !info.checkboxField.checked;\n if(banned) {\n info.flags.forEach(flag => {\n // @ts-ignore\n rights.pFlags[flag] = true;\n });\n }\n }\n\n return rights;\n }\n}\n\nexport default class AppGroupPermissionsTab extends SliderSuperTabEventable {\n public chatId: number;\n\n protected async init() {\n this.container.classList.add('edit-peer-container', 'group-permissions-container');\n this.setTitle('ChannelPermissions');\n\n let chatPermissions: ChatPermissions;\n {\n const section = new SettingSection({\n name: 'ChannelPermissionsHeader',\n });\n\n chatPermissions = new ChatPermissions({\n chatId: this.chatId,\n listenerSetter: this.listenerSetter,\n appendTo: section.content,\n });\n\n this.eventListener.addEventListener('destroy', () => {\n appChatsManager.editChatDefaultBannedRights(this.chatId, chatPermissions.takeOut());\n }, {once: true});\n\n this.scrollable.append(section.container);\n }\n \n {\n const section = new SettingSection({\n name: 'PrivacyExceptions'\n });\n\n const addExceptionRow = new Row({\n titleLangKey: 'ChannelAddException',\n subtitleLangKey: 'Loading',\n icon: 'adduser',\n clickable: () => {\n new PopupPickUser({\n peerTypes: ['channelParticipants'],\n onSelect: (peerId) => {\n setTimeout(() => {\n openPermissions(peerId);\n }, 0);\n },\n placeholder: 'ExceptionModal.Search.Placeholder',\n peerId: -this.chatId,\n });\n }\n });\n\n const openPermissions = async(peerId: number) => {\n let participant: AppUserPermissionsTab['participant'];\n try {\n participant = await appProfileManager.getChannelParticipant(this.chatId, peerId) as any;\n } catch(err) {\n toast('User is no longer participant');\n return;\n }\n\n const tab = new AppUserPermissionsTab(this.slider);\n tab.participant = participant;\n tab.chatId = this.chatId;\n tab.userId = peerId;\n tab.open();\n };\n\n section.content.append(addExceptionRow.container);\n\n /* const removedUsersRow = new Row({\n titleLangKey: 'ChannelBlockedUsers',\n subtitleLangKey: 'NoBlockedUsers',\n icon: 'deleteuser',\n clickable: true\n });\n\n section.content.append(removedUsersRow.container); */\n\n const c = section.generateContentElement();\n c.classList.add('chatlist-container');\n \n const list = appDialogsManager.createChatList({new: true});\n c.append(list);\n\n attachClickEvent(list, (e) => {\n const target = findUpTag(e.target, 'LI');\n if(!target) return;\n\n const peerId = +target.dataset.peerId;\n openPermissions(peerId);\n }, {listenerSetter: this.listenerSetter});\n\n const setSubtitle = (li: Element, participant: ChannelParticipant.channelParticipantBanned) => {\n const bannedRights = participant.banned_rights;//appChatsManager.combineParticipantBannedRights(this.chatId, participant.banned_rights);\n const defaultBannedRights = (appChatsManager.getChat(this.chatId) as Chat.channel).default_banned_rights;\n //const combinedRights = appChatsManager.combineParticipantBannedRights(this.chatId, bannedRights);\n\n const cantWhat: LangPackKey[] = []/* , canWhat: LangPackKey[] = [] */;\n chatPermissions.v.forEach(info => {\n const mainFlag = info.flags[0];\n // @ts-ignore\n if(bannedRights.pFlags[mainFlag] && !defaultBannedRights.pFlags[mainFlag]) {\n cantWhat.push(info.exceptionText);\n // @ts-ignore\n }/* else if(!combinedRights.pFlags[mainFlag]) {\n canWhat.push(info.exceptionText);\n } */\n });\n\n const el = li.querySelector('.user-last-message') as HTMLElement;\n\n if(cantWhat.length) {\n el.innerHTML = '';\n el.append(...join(cantWhat.map(t => i18n(t)), false));\n }/* else if(canWhat.length) {\n str = 'Can ' + canWhat.join(canWhat.length === 2 ? ' and ' : ', ');\n } */\n \n el.classList.toggle('hide', !cantWhat.length);\n };\n\n const add = (participant: ChannelParticipant.channelParticipantBanned, append: boolean) => {\n const {dom} = appDialogsManager.addDialogNew({\n dialog: appPeersManager.getPeerId(participant.peer),\n container: list,\n drawStatus: false,\n rippleEnabled: true,\n avatarSize: 48,\n append\n });\n\n setSubtitle(dom.listEl, participant);\n\n //dom.titleSpan.innerHTML = 'Chinaza Akachi';\n //dom.lastMessageSpan.innerHTML = 'Can Add Users and Pin Messages';\n };\n\n this.listenerSetter.add(rootScope)('updateChannelParticipant', (update: Update.updateChannelParticipant) => {\n const needAdd = update.new_participant?._ === 'channelParticipantBanned' && !update.new_participant.banned_rights.pFlags.view_messages;\n const li = list.querySelector(`[data-peer-id=\"${update.user_id}\"]`);\n if(needAdd) {\n if(!li) {\n add(update.new_participant as ChannelParticipant.channelParticipantBanned, false);\n } else {\n setSubtitle(li, update.new_participant as ChannelParticipant.channelParticipantBanned);\n }\n\n if(update.prev_participant?._ !== 'channelParticipantBanned') {\n ++exceptionsCount;\n }\n } else {\n if(li) {\n li.remove();\n }\n\n if(update.prev_participant?._ === 'channelParticipantBanned') {\n --exceptionsCount;\n }\n }\n\n setLength();\n });\n\n const setLength = () => {\n replaceContent(addExceptionRow.subtitle, i18n(exceptionsCount ? 'Permissions.ExceptionsCount' : 'Permissions.NoExceptions', [exceptionsCount]));\n };\n\n let exceptionsCount = 0;\n let loader: ScrollableLoader;\n const setLoader = () => {\n const LOAD_COUNT = 50;\n loader = new ScrollableLoader({\n scrollable: this.scrollable,\n getPromise: () => {\n return appProfileManager.getChannelParticipants(this.chatId, {_: 'channelParticipantsBanned', q: ''}, LOAD_COUNT, list.childElementCount).then(res => {\n for(const participant of res.participants) {\n add(participant as ChannelParticipant.channelParticipantBanned, true);\n }\n \n exceptionsCount = res.count;\n setLength();\n \n return res.participants.length < LOAD_COUNT || res.count === list.childElementCount;\n });\n }\n });\n\n return loader.load();\n };\n\n this.scrollable.append(section.container);\n\n if(appChatsManager.isChannel(this.chatId)) {\n await setLoader();\n } else {\n setLength();\n \n this.listenerSetter.add(rootScope)('dialog_migrate', ({migrateFrom, migrateTo}) => {\n if(this.chatId === migrateFrom) {\n this.chatId = migrateTo;\n setLoader();\n }\n });\n }\n }\n }\n\n onOpenAfterTimeout() {\n this.scrollable.onScroll();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appChatsManager from \"../../lib/appManagers/appChatsManager\";\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport appPeersManager, { PeerType } from \"../../lib/appManagers/appPeersManager\";\nimport { LangPackKey } from \"../../lib/langPack\";\nimport PeerTitle from \"../peerTitle\";\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerOptions } from \"./peer\";\n\nexport default class PopupDeleteDialog {\n constructor(\n peerId: number, \n // actionType: 'leave' | 'delete', \n peerType: PeerType = appPeersManager.getDialogType(peerId), \n onSelect?: (promise: Promise<any>) => void\n ) {\n const peerTitleElement = new PeerTitle({peerId}).element;\n\n /* const callbackFlush = (checked: PopupPeerButtonCallbackCheckboxes) => {\n const promise = appMessagesManager.flushHistory(peerId, checkboxes ? !checked[checkboxes[0].text] : undefined);\n onSelect && onSelect(promise);\n }; */\n\n const callbackLeave = (checked: PopupPeerButtonCallbackCheckboxes, flush = checkboxes && !!checked.size) => {\n let promise = appChatsManager.leave(-peerId);\n \n if(flush) {\n promise = promise.finally(() => {\n return appMessagesManager.flushHistory(peerId);\n }) as any;\n }\n \n onSelect && onSelect(promise);\n };\n\n const callbackDelete = (checked: PopupPeerButtonCallbackCheckboxes) => {\n let promise: Promise<any>;\n\n if(peerId > 0) {\n promise = appMessagesManager.flushHistory(peerId, false, checkboxes ? !!checked.size : undefined);\n } else {\n if(checked.size) {\n promise = appChatsManager.delete(-peerId);\n } else {\n return callbackLeave(checked);\n }\n }\n \n onSelect && onSelect(promise);\n };\n\n let title: LangPackKey, description: LangPackKey, descriptionArgs: any[], buttons: PopupPeerOptions['buttons'], checkboxes: PopupPeerOptions['checkboxes'];\n switch(peerType) {\n case 'channel': {\n if(/* actionType === 'delete' && */appChatsManager.hasRights(-peerId, 'delete_chat')) {\n appChatsManager.deleteChannel\n title = 'ChannelDeleteMenu';\n description = 'AreYouSureDeleteAndExitChannel';\n buttons = [{\n langKey: 'ChannelDeleteMenu',\n isDanger: true,\n callback: callbackDelete\n }];\n\n checkboxes = [{\n text: 'DeleteChannelForAll'\n }];\n } else {\n title = 'LeaveChannelMenu';\n description = 'ChannelLeaveAlertWithName';\n descriptionArgs = [peerTitleElement];\n buttons = [{\n langKey: 'LeaveChannel',\n isDanger: true,\n callback: callbackLeave\n }];\n }\n\n break;\n }\n\n /* case 'megagroup': {\n title = 'Leave Group?';\n description = `Are you sure you want to leave this group?`;\n buttons = [{\n text: 'LEAVE ' + peerTitleElement,\n isDanger: true,\n callback: callbackLeave\n }];\n\n break;\n } */\n\n case 'chat': {\n title = 'DeleteChatUser';\n description = 'AreYouSureDeleteThisChatWithUser';\n descriptionArgs = [peerTitleElement];\n\n buttons = [{\n langKey: 'DeleteChatUser',\n isDanger: true,\n callback: callbackDelete\n }];\n\n checkboxes = [{\n text: 'DeleteMessagesOptionAlso',\n textArgs: [\n new PeerTitle({peerId}).element\n ]\n }];\n\n break;\n }\n\n case 'saved': {\n title = 'DeleteChatUser';\n description = 'AreYouSureDeleteThisChatSavedMessages';\n buttons = [{\n langKey: 'DeleteChatUser',\n isDanger: true,\n callback: callbackDelete\n }];\n\n break;\n }\n\n case 'megagroup':\n case 'group': {\n if(/* actionType === 'delete' && */appChatsManager.hasRights(-peerId, 'delete_chat')) {\n title = 'DeleteMegaMenu';\n description = 'AreYouSureDeleteAndExit';\n buttons = [{\n langKey: 'DeleteMegaMenu',\n isDanger: true,\n callback: callbackDelete\n }];\n\n checkboxes = [{\n text: 'DeleteChat.DeleteGroupForAll'\n }];\n } else {\n title = 'LeaveMegaMenu';\n description = 'AreYouSureDeleteAndExitName';\n descriptionArgs = [peerTitleElement];\n buttons = [{\n langKey: 'DeleteChatUser',\n isDanger: true,\n callback: (checkboxes) => callbackLeave(checkboxes, true)\n }];\n }\n\n break;\n }\n }\n\n new PopupPeer('popup-delete-chat', {\n peerId,\n titleLangKey: title,\n descriptionLangKey: description,\n descriptionLangArgs: descriptionArgs,\n buttons,\n checkboxes\n }).show();\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\"\r\nimport InputField from \"../../inputField\";\r\nimport EditPeer from \"../../editPeer\";\r\nimport { SettingSection } from \"../../sidebarLeft\";\r\nimport Row from \"../../row\";\r\nimport Button from \"../../button\";\r\nimport appChatsManager, { ChatRights } from \"../../../lib/appManagers/appChatsManager\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport { Chat, ChatFull } from \"../../../layer\";\r\nimport AppChatTypeTab from \"./chatType\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport AppGroupPermissionsTab from \"./groupPermissions\";\r\nimport { i18n, LangPackKey } from \"../../../lib/langPack\";\r\nimport PopupDeleteDialog from \"../../popups/deleteDialog\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\r\nimport CheckboxField from \"../../checkboxField\";\r\n\r\nexport default class AppEditChatTab extends SliderSuperTab {\r\n private chatNameInputField: InputField;\r\n private descriptionInputField: InputField;\r\n private editPeer: EditPeer;\r\n public chatId: number;\r\n\r\n protected async _init() {\r\n // * cleanup prev\r\n this.listenerSetter.removeAll();\r\n this.scrollable.container.innerHTML = '';\r\n\r\n this.container.classList.add('edit-peer-container', 'edit-group-container');\r\n this.setTitle('Edit');\r\n \r\n const chatFull = await appProfileManager.getChatFull(this.chatId, true);\r\n\r\n const chat: Chat.chat | Chat.channel = appChatsManager.getChat(this.chatId);\r\n const isBroadcast = appChatsManager.isBroadcast(this.chatId);\r\n const isChannel = appChatsManager.isChannel(this.chatId);\r\n\r\n const chatUpdateListeners: (() => void)[] = [];\r\n const addChatUpdateListener = (callback: () => void) => {\r\n chatUpdateListeners.push(callback);\r\n };\r\n\r\n this.listenerSetter.add(rootScope)('chat_update', (chatId) => {\r\n if(this.chatId === chatId) {\r\n chatUpdateListeners.forEach(callback => callback());\r\n }\r\n });\r\n\r\n {\r\n const section = new SettingSection({noDelimiter: true});\r\n const inputFields: InputField[] = [];\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n \r\n this.chatNameInputField = new InputField({\r\n label: isBroadcast ? 'EnterChannelName' : 'CreateGroup.NameHolder',\r\n name: 'chat-name',\r\n maxLength: 255,\r\n required: true\r\n });\r\n this.descriptionInputField = new InputField({\r\n label: 'DescriptionPlaceholder',\r\n name: 'chat-description',\r\n maxLength: 255\r\n });\r\n \r\n this.chatNameInputField.setOriginalValue(chat.title);\r\n this.descriptionInputField.setOriginalValue(chatFull.about);\r\n\r\n inputWrapper.append(this.chatNameInputField.container, this.descriptionInputField.container);\r\n \r\n inputFields.push(this.chatNameInputField, this.descriptionInputField);\r\n\r\n this.editPeer = new EditPeer({\r\n peerId: -this.chatId,\r\n inputFields,\r\n listenerSetter: this.listenerSetter\r\n });\r\n this.content.append(this.editPeer.nextBtn);\r\n\r\n section.content.append(this.editPeer.avatarEdit.container, inputWrapper);\r\n\r\n if(appChatsManager.hasRights(this.chatId, 'change_type')) {\r\n const chatTypeRow = new Row({\r\n titleLangKey: isBroadcast ? 'ChannelType' : 'GroupType',\r\n clickable: () => {\r\n const tab = new AppChatTypeTab(this.slider);\r\n tab.chatId = this.chatId;\r\n tab.chatFull = chatFull;\r\n tab.open();\r\n\r\n this.listenerSetter.add(tab.eventListener)('destroy', setChatTypeSubtitle);\r\n },\r\n icon: 'lock'\r\n });\r\n\r\n const setChatTypeSubtitle = () => {\r\n chatTypeRow.subtitle.textContent = '';\r\n\r\n let key: LangPackKey;\r\n if(isBroadcast) {\r\n key = (chat as Chat.channel).username ? 'TypePublic' : 'TypePrivate';\r\n } else {\r\n key = (chat as Chat.channel).username ? 'TypePublicGroup' : 'TypePrivateGroup';\r\n }\r\n\r\n chatTypeRow.subtitle.append(i18n(key));\r\n };\r\n\r\n setChatTypeSubtitle();\r\n section.content.append(chatTypeRow.container);\r\n }\r\n\r\n if(appChatsManager.hasRights(this.chatId, 'change_permissions') && !isBroadcast) {\r\n const flags = [\r\n 'send_messages',\r\n 'send_media',\r\n 'send_stickers',\r\n 'send_polls',\r\n 'embed_links',\r\n 'invite_users',\r\n 'pin_messages',\r\n 'change_info'\r\n ] as ChatRights[];\r\n\r\n const permissionsRow = new Row({\r\n titleLangKey: 'ChannelPermissions',\r\n clickable: () => {\r\n const tab = new AppGroupPermissionsTab(this.slider);\r\n tab.chatId = this.chatId;\r\n tab.open();\r\n },\r\n icon: 'permissions',\r\n });\r\n\r\n const setPermissionsLength = () => {\r\n permissionsRow.subtitle.innerHTML = flags.reduce((acc, f) => acc + +appChatsManager.hasRights(this.chatId, f, chat.default_banned_rights), 0) + '/' + flags.length;\r\n };\r\n\r\n setPermissionsLength(); \r\n section.content.append(permissionsRow.container);\r\n\r\n this.listenerSetter.add(rootScope)('chat_update', (chatId) => {\r\n if(this.chatId === chatId) {\r\n setPermissionsLength();\r\n }\r\n });\r\n }\r\n\r\n /* const administratorsRow = new Row({\r\n titleLangKey: 'PeerInfo.Administrators',\r\n subtitle: '' + ((chatFull as ChatFull.channelFull).admins_count || 1),\r\n icon: 'admin',\r\n clickable: true\r\n });\r\n\r\n section.content.append(administratorsRow.container); */\r\n\r\n this.scrollable.append(section.container);\r\n\r\n attachClickEvent(this.editPeer.nextBtn, () => {\r\n this.editPeer.nextBtn.disabled = true;\r\n \r\n let promises: Promise<any>[] = [];\r\n\r\n const id = this.chatId;\r\n if(this.chatNameInputField.isValid()) {\r\n promises.push(appChatsManager.editTitle(id, this.chatNameInputField.value));\r\n }\r\n\r\n if(this.descriptionInputField.isValid()) {\r\n promises.push(appChatsManager.editAbout(id, this.descriptionInputField.value));\r\n }\r\n\r\n if(this.editPeer.uploadAvatar) {\r\n promises.push(this.editPeer.uploadAvatar().then(inputFile => {\r\n return appChatsManager.editPhoto(id, inputFile);\r\n }));\r\n }\r\n \r\n Promise.race(promises).finally(() => {\r\n this.editPeer.nextBtn.removeAttribute('disabled');\r\n this.close();\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n \r\n /* if(appChatsManager.hasRights(-this.peerId, 'change_info')) {\r\n const discussionRow = new Row({\r\n titleLangKey: 'PeerInfo.Discussion',\r\n subtitleLangKey: 'PeerInfo.Discussion.Add',\r\n clickable: true,\r\n icon: 'message'\r\n });\r\n\r\n section.content.append(discussionRow.container);\r\n }\r\n\r\n const administratorsRow = new Row({\r\n titleLangKey: 'PeerInfo.Administrators',\r\n subtitle: '' + chatFull.admins_count,\r\n icon: 'admin',\r\n clickable: true\r\n });\r\n\r\n section.content.append(administratorsRow.container); */\r\n\r\n if(isBroadcast && appChatsManager.hasRights(this.chatId, 'change_info')) {\r\n const signMessagesCheckboxField = new CheckboxField({\r\n text: 'PeerInfo.SignMessages',\r\n checked: !!(chat as Chat.channel).pFlags.signatures,\r\n withRipple: true\r\n });\r\n\r\n this.listenerSetter.add(signMessagesCheckboxField.input)('change', () => {\r\n const toggle = signMessagesCheckboxField.toggleDisability(true);\r\n appChatsManager.toggleSignatures(this.chatId, signMessagesCheckboxField.checked).then(() => {\r\n toggle();\r\n });\r\n });\r\n\r\n addChatUpdateListener(() => {\r\n signMessagesCheckboxField.setValueSilently(!!(chat as Chat.channel).pFlags.signatures);\r\n });\r\n\r\n section.content.append(signMessagesCheckboxField.label);\r\n }\r\n }\r\n\r\n if(!isBroadcast) {\r\n const section = new SettingSection({\r\n\r\n });\r\n\r\n /* const membersRow = new Row({\r\n titleLangKey: isBroadcast ? 'PeerInfo.Subscribers' : 'GroupMembers',\r\n icon: 'newgroup',\r\n clickable: true\r\n });\r\n\r\n membersRow.subtitle.append(i18n('Subscribers', [numberThousandSplitter(335356)]));\r\n\r\n section.content.append(membersRow.container); */\r\n\r\n if(!isBroadcast && appChatsManager.hasRights(this.chatId, 'change_permissions')) {\r\n const showChatHistoryCheckboxField = new CheckboxField({\r\n text: 'ChatHistory',\r\n withRipple: true\r\n });\r\n\r\n this.listenerSetter.add(showChatHistoryCheckboxField.input)('change', () => {\r\n const toggle = showChatHistoryCheckboxField.toggleDisability(true);\r\n appChatsManager.togglePreHistoryHidden(this.chatId, !showChatHistoryCheckboxField.checked).then(() => {\r\n toggle();\r\n });\r\n });\r\n\r\n const onChatUpdate = () => {\r\n showChatHistoryCheckboxField.setValueSilently(isChannel && !(chatFull as ChatFull.channelFull).pFlags.hidden_prehistory);\r\n };\r\n\r\n onChatUpdate();\r\n addChatUpdateListener(onChatUpdate);\r\n \r\n section.content.append(showChatHistoryCheckboxField.label);\r\n }\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n if(appChatsManager.hasRights(this.chatId, 'delete_chat')) {\r\n const section = new SettingSection({});\r\n\r\n const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'delete', text: isBroadcast ? 'PeerInfo.DeleteChannel' : 'DeleteAndExitButton'});\r\n\r\n attachClickEvent(btnDelete, () => {\r\n new PopupDeleteDialog(-this.chatId/* , 'delete' */, undefined, (promise) => {\r\n const toggle = toggleDisability([btnDelete], true);\r\n promise.then(() => {\r\n this.close();\r\n }, () => {\r\n toggle();\r\n });\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n section.content.append(btnDelete);\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n if(!isChannel) {\r\n // ! this one will fire earlier than tab's closeAfterTimeout (destroy) event and listeners will be erased, so destroy won't fire\r\n this.listenerSetter.add(rootScope)('dialog_migrate', ({migrateFrom, migrateTo}) => {\r\n if(-this.chatId === migrateFrom) {\r\n this.chatId = -migrateTo;\r\n this._init();\r\n }\r\n });\r\n }\r\n }\r\n\r\n protected init() {\r\n return this._init();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\"\r\nimport InputField from \"../../inputField\";\r\nimport EditPeer from \"../../editPeer\";\r\nimport { SettingSection } from \"../../sidebarLeft\";\r\nimport Row from \"../../row\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport Button from \"../../button\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport appNotificationsManager from \"../../../lib/appManagers/appNotificationsManager\";\r\nimport PeerTitle from \"../../peerTitle\";\r\nimport appMessagesManager from \"../../../lib/appManagers/appMessagesManager\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport appPeersManager from \"../../../lib/appManagers/appPeersManager\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport { addCancelButton } from \"../../popups\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\r\n\r\nexport default class AppEditContactTab extends SliderSuperTab {\r\n private nameInputField: InputField;\r\n private lastNameInputField: InputField;\r\n private editPeer: EditPeer;\r\n public peerId: number;\r\n\r\n protected init() {\r\n this.container.classList.add('edit-peer-container', 'edit-contact-container');\r\n const isNew = !appUsersManager.isContact(this.peerId);\r\n this.setTitle(isNew ? 'AddContactTitle' : 'Edit');\r\n\r\n {\r\n const section = new SettingSection({noDelimiter: true});\r\n const inputFields: InputField[] = [];\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n \r\n this.nameInputField = new InputField({\r\n label: 'FirstName',\r\n name: 'contact-name',\r\n maxLength: 70,\r\n required: true\r\n });\r\n this.lastNameInputField = new InputField({\r\n label: 'LastName',\r\n name: 'contact-lastname',\r\n maxLength: 70\r\n });\r\n\r\n if(this.peerId) {\r\n const user = appUsersManager.getUser(this.peerId);\r\n\r\n if(isNew) {\r\n this.nameInputField.setDraftValue(user.first_name);\r\n this.lastNameInputField.setDraftValue(user.last_name);\r\n } else {\r\n this.nameInputField.setOriginalValue(user.first_name);\r\n this.lastNameInputField.setOriginalValue(user.last_name);\r\n }\r\n }\r\n \r\n inputWrapper.append(this.nameInputField.container, this.lastNameInputField.container);\r\n inputFields.push(this.nameInputField, this.lastNameInputField);\r\n\r\n this.editPeer = new EditPeer({\r\n peerId: this.peerId,\r\n inputFields,\r\n listenerSetter: this.listenerSetter,\r\n doNotEditAvatar: true\r\n });\r\n this.content.append(this.editPeer.nextBtn);\r\n\r\n if(this.peerId) {\r\n const div = document.createElement('div');\r\n div.classList.add('avatar-edit');\r\n div.append(this.editPeer.avatarElem);\r\n \r\n const notificationsCheckboxField = new CheckboxField({\r\n text: 'Notifications'\r\n });\r\n \r\n notificationsCheckboxField.input.addEventListener('change', (e) => {\r\n if(!e.isTrusted) {\r\n return;\r\n }\r\n \r\n appMessagesManager.mutePeer(this.peerId);\r\n });\r\n \r\n this.listenerSetter.add(rootScope)('notify_settings', (update) => {\r\n if(update.peer._ !== 'notifyPeer') return;\r\n const peerId = appPeersManager.getPeerId(update.peer.peer);\r\n if(this.peerId === peerId) {\r\n const enabled = !appNotificationsManager.isMuted(update.notify_settings);\r\n if(enabled !== notificationsCheckboxField.checked) {\r\n notificationsCheckboxField.checked = enabled;\r\n }\r\n }\r\n });\r\n \r\n const profileNameDiv = document.createElement('div');\r\n profileNameDiv.classList.add('profile-name');\r\n profileNameDiv.append(new PeerTitle({\r\n peerId: this.peerId\r\n }).element);\r\n //profileNameDiv.innerHTML = 'Karen Stanford';\r\n \r\n const profileSubtitleDiv = document.createElement('div');\r\n profileSubtitleDiv.classList.add('profile-subtitle');\r\n profileSubtitleDiv.append(i18n('EditContact.OriginalName'));\r\n\r\n section.content.append(div, profileNameDiv, profileSubtitleDiv, inputWrapper);\r\n\r\n if(!isNew) {\r\n const notificationsRow = new Row({\r\n checkboxField: notificationsCheckboxField\r\n });\r\n \r\n const enabled = !appNotificationsManager.isPeerLocalMuted(this.peerId, false);\r\n notificationsCheckboxField.checked = enabled;\r\n\r\n section.content.append(notificationsRow.container);\r\n } else {\r\n const user = appUsersManager.getUser(this.peerId);\r\n\r\n const phoneRow = new Row({\r\n icon: 'phone',\r\n titleLangKey: user.phone ? undefined : 'MobileHidden',\r\n title: user.phone ? appUsersManager.formatUserPhone(user.phone) : undefined,\r\n subtitleLangKey: user.phone ? 'Phone' : 'MobileHiddenExceptionInfo',\r\n subtitleLangArgs: user.phone ? undefined : [new PeerTitle({peerId: this.peerId}).element]\r\n });\r\n\r\n section.content.append(phoneRow.container);\r\n }\r\n } else {\r\n section.content.append(inputWrapper);\r\n }\r\n\r\n this.scrollable.append(section.container);\r\n\r\n attachClickEvent(this.editPeer.nextBtn, () => {\r\n this.editPeer.nextBtn.disabled = true;\r\n\r\n appUsersManager.addContact(this.peerId, this.nameInputField.value, this.lastNameInputField.value, appUsersManager.getUser(this.peerId).phone)\r\n .finally(() => {\r\n this.editPeer.nextBtn.removeAttribute('disabled');\r\n this.close();\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n if(!isNew) {\r\n const section = new SettingSection({\r\n \r\n });\r\n\r\n const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'PeerInfo.DeleteContact'});\r\n\r\n attachClickEvent(btnDelete, () => {\r\n new PopupPeer('popup-delete-contact', {\r\n peerId: this.peerId,\r\n titleLangKey: 'DeleteContact',\r\n descriptionLangKey: 'AreYouSureDeleteContact',\r\n buttons: addCancelButton([{\r\n langKey: 'Delete',\r\n callback: () => {\r\n const toggle = toggleDisability([btnDelete], true);\r\n\r\n appUsersManager.deleteContacts([this.peerId]).then(() => {\r\n this.close();\r\n }, () => {\r\n toggle();\r\n });\r\n },\r\n isDanger: true\r\n }])\r\n }).show();\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n section.content.append(btnDelete);\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport AppSelectPeers from \"../../appSelectPeers\";\r\nimport { putPreloader, setButtonLoader } from \"../../misc\";\r\nimport { LangPackKey, _i18n } from \"../../../lib/langPack\";\r\nimport ButtonCorner from \"../../buttonCorner\";\r\n\r\nexport default class AppAddMembersTab extends SliderSuperTab {\r\n private nextBtn: HTMLButtonElement;\r\n private selector: AppSelectPeers;\r\n private peerType: 'channel' | 'chat' | 'privacy';\r\n private takeOut: (peerIds: number[]) => Promise<any> | false | void;\r\n private skippable: boolean;\r\n\r\n protected init() {\r\n this.nextBtn = ButtonCorner({icon: 'arrow_next'});\r\n this.content.append(this.nextBtn);\r\n this.scrollable.container.remove();\r\n \r\n this.nextBtn.addEventListener('click', () => {\r\n const peerIds = this.selector.getSelected();\r\n\r\n if(this.skippable) {\r\n this.takeOut(peerIds);\r\n this.close();\r\n } else {\r\n const promise = this.takeOut(peerIds);\r\n\r\n if(promise instanceof Promise) {\r\n this.attachToPromise(promise);\r\n } else if(promise === undefined) {\r\n this.close();\r\n }\r\n }\r\n });\r\n }\r\n\r\n public attachToPromise(promise: Promise<any>) {\r\n const removeLoader = setButtonLoader(this.nextBtn, 'arrow_next');\r\n\r\n promise.then(() => {\r\n this.close();\r\n }, () => {\r\n removeLoader();\r\n });\r\n }\r\n\r\n public open(options: {\r\n title: LangPackKey,\r\n placeholder: LangPackKey,\r\n peerId?: number, \r\n type: AppAddMembersTab['peerType'], \r\n takeOut?: AppAddMembersTab['takeOut'],\r\n skippable: boolean,\r\n selectedPeerIds?: number[]\r\n }) {\r\n const ret = super.open();\r\n\r\n this.setTitle(options.title);\r\n this.peerType = options.type;\r\n this.takeOut = options.takeOut;\r\n this.skippable = options.skippable;\r\n\r\n this.selector = new AppSelectPeers({\r\n appendTo: this.content, \r\n onChange: this.skippable ? null : (length) => {\r\n this.nextBtn.classList.toggle('is-visible', !!length);\r\n }, \r\n peerType: ['contacts'],\r\n placeholder: options.placeholder\r\n });\r\n\r\n if(options.selectedPeerIds) {\r\n this.selector.addInitial(options.selectedPeerIds);\r\n }\r\n\r\n this.nextBtn.classList.add('tgico-arrow_next');\r\n this.nextBtn.innerHTML = '';\r\n this.nextBtn.disabled = false;\r\n this.nextBtn.classList.toggle('is-visible', this.skippable);\r\n\r\n return ret;\r\n }\r\n}","import { IS_FIREFOX } from \"./userAgent\";\n\nconst PARALLAX_SUPPORTED = !IS_FIREFOX && false;\n\nexport default PARALLAX_SUPPORTED;","export default function generateVerifiedIcon() {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttributeNS(null, 'viewBox', '0 0 24 24');\n svg.setAttributeNS(null, 'width', '24');\n svg.setAttributeNS(null, 'height', '24');\n svg.classList.add('verified-icon');\n\n const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');\n use.setAttributeNS(null, 'href', '#verified-background');\n use.classList.add('verified-background');\n\n const use2 = document.createElementNS('http://www.w3.org/2000/svg', 'use');\n use2.setAttributeNS(null, 'href', '#verified-check');\n use2.classList.add('verified-check');\n\n svg.append(use, use2);\n\n return svg;\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport { safeAssign } from \"../helpers/object\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\r\nimport rootScope from \"../lib/rootScope\";\r\n\r\nconst getEvent = (e: TouchEvent | MouseEvent) => {\r\n return (e as TouchEvent).touches ? (e as TouchEvent).touches[0] : e as MouseEvent;\r\n};\r\n\r\nconst attachGlobalListenerTo = window;\r\n\r\nlet RESET_GLOBAL = false;\r\nrootScope.addEventListener('context_menu_toggle', (visible) => {\r\n RESET_GLOBAL = visible;\r\n});\r\n\r\nexport default class SwipeHandler {\r\n private element: HTMLElement;\r\n private onSwipe: (xDiff: number, yDiff: number, e: TouchEvent | MouseEvent) => boolean | void;\r\n private verifyTouchTarget: (evt: TouchEvent | MouseEvent) => boolean;\r\n private onFirstSwipe: () => void;\r\n private onReset: () => void;\r\n private cursor: 'grabbing' | 'move' = 'grabbing';\r\n private cancelEvent = true;\r\n\r\n private hadMove = false;\r\n private xDown: number = null;\r\n private yDown: number = null;\r\n\r\n constructor(options: {\r\n element: SwipeHandler['element'],\r\n onSwipe: SwipeHandler['onSwipe'],\r\n verifyTouchTarget?: SwipeHandler['verifyTouchTarget'],\r\n onFirstSwipe?: SwipeHandler['onFirstSwipe'],\r\n onReset?: SwipeHandler['onReset'],\r\n cursor?: SwipeHandler['cursor'],\r\n cancelEvent?: SwipeHandler['cancelEvent']\r\n }) {\r\n safeAssign(this, options);\r\n\r\n this.setListeners();\r\n }\r\n\r\n public setListeners() {\r\n if(!IS_TOUCH_SUPPORTED) {\r\n this.element.addEventListener('mousedown', this.handleStart, false);\r\n attachGlobalListenerTo.addEventListener('mouseup', this.reset);\r\n } else {\r\n this.element.addEventListener('touchstart', this.handleStart, false);\r\n attachGlobalListenerTo.addEventListener('touchend', this.reset);\r\n }\r\n }\r\n\r\n public removeListeners() {\r\n if(!IS_TOUCH_SUPPORTED) {\r\n this.element.removeEventListener('mousedown', this.handleStart, false);\r\n attachGlobalListenerTo.removeEventListener('mouseup', this.reset);\r\n } else {\r\n this.element.removeEventListener('touchstart', this.handleStart, false);\r\n attachGlobalListenerTo.removeEventListener('touchend', this.reset);\r\n }\r\n }\r\n\r\n reset = (e?: Event) => {\r\n /* if(e) {\r\n cancelEvent(e);\r\n } */\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n attachGlobalListenerTo.removeEventListener('touchmove', this.handleMove, {capture: true});\r\n } else {\r\n attachGlobalListenerTo.removeEventListener('mousemove', this.handleMove);\r\n this.element.style.cursor = '';\r\n }\r\n\r\n if(this.onReset && this.hadMove) {\r\n this.onReset();\r\n }\r\n\r\n this.xDown = this.yDown = null;\r\n this.hadMove = false;\r\n };\r\n\r\n handleStart = (_e: TouchEvent | MouseEvent) => {\r\n const e = getEvent(_e);\r\n if(this.verifyTouchTarget && !this.verifyTouchTarget(_e)) {\r\n return this.reset();\r\n }\r\n\r\n this.xDown = e.clientX;\r\n this.yDown = e.clientY;\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n attachGlobalListenerTo.addEventListener('touchmove', this.handleMove, {passive: false, capture: true});\r\n } else {\r\n attachGlobalListenerTo.addEventListener('mousemove', this.handleMove, false);\r\n }\r\n };\r\n\r\n handleMove = (_e: TouchEvent | MouseEvent) => {\r\n if(this.xDown === null || this.yDown === null || RESET_GLOBAL) {\r\n this.reset();\r\n return;\r\n }\r\n\r\n if(this.cancelEvent) {\r\n cancelEvent(_e);\r\n }\r\n\r\n const e = getEvent(_e);\r\n const xUp = e.clientX;\r\n const yUp = e.clientY;\r\n\r\n const xDiff = this.xDown - xUp;\r\n const yDiff = this.yDown - yUp;\r\n\r\n if(!this.hadMove) {\r\n if(!xDiff && !yDiff) {\r\n return;\r\n }\r\n\r\n this.hadMove = true;\r\n\r\n if(!IS_TOUCH_SUPPORTED) {\r\n this.element.style.setProperty('cursor', this.cursor, 'important');\r\n }\r\n\r\n if(this.onFirstSwipe) {\r\n this.onFirstSwipe();\r\n }\r\n }\r\n\r\n // if(Math.abs(xDiff) > Math.abs(yDiff)) { /*most significant*/\r\n // if(xDiff > 0) { /* left swipe */ \r\n\r\n // } else { /* right swipe */\r\n\r\n // } \r\n // } else {\r\n // if(yDiff > 0) { /* up swipe */ \r\n \r\n // } else { /* down swipe */\r\n \r\n // }\r\n // }\r\n\r\n /* reset values */\r\n const onSwipeResult = this.onSwipe(xDiff, yDiff, _e);\r\n if(onSwipeResult !== undefined && onSwipeResult) {\r\n this.reset();\r\n }\r\n };\r\n}\r\n","import PARALLAX_SUPPORTED from \"../environment/parallaxSupport\";\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\nimport renderImageFromUrl from \"../helpers/dom/renderImageFromUrl\";\nimport filterChatPhotosMessages from \"../helpers/filterChatPhotosMessages\";\nimport ListLoader from \"../helpers/listLoader\";\nimport { fastRaf } from \"../helpers/schedulers\";\nimport { Message, ChatFull, MessageAction, Photo } from \"../layer\";\nimport appAvatarsManager from \"../lib/appManagers/appAvatarsManager\";\nimport appDownloadManager from \"../lib/appManagers/appDownloadManager\";\nimport appMessagesManager, { AppMessagesManager } from \"../lib/appManagers/appMessagesManager\";\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\nimport { openAvatarViewer } from \"./avatar\";\nimport Scrollable from \"./scrollable\";\nimport SwipeHandler from \"./swipeHandler\";\n\nexport default class PeerProfileAvatars {\n private static BASE_CLASS = 'profile-avatars';\n private static SCALE = PARALLAX_SUPPORTED ? 2 : 1;\n private static TRANSLATE_TEMPLATE = PARALLAX_SUPPORTED ? `translate3d({x}, 0, -1px) scale(${PeerProfileAvatars.SCALE})` : 'translate({x}, 0)';\n public container: HTMLElement;\n public avatars: HTMLElement;\n public gradient: HTMLElement;\n public info: HTMLElement;\n public arrowPrevious: HTMLElement;\n public arrowNext: HTMLElement;\n private tabs: HTMLDivElement;\n private listLoader: ListLoader<string | Message.messageService, string | Message.messageService>;\n private peerId: number;\n\n constructor(public scrollable: Scrollable) {\n this.container = document.createElement('div');\n this.container.classList.add(PeerProfileAvatars.BASE_CLASS + '-container');\n\n this.avatars = document.createElement('div');\n this.avatars.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatars');\n\n this.gradient = document.createElement('div');\n this.gradient.classList.add(PeerProfileAvatars.BASE_CLASS + '-gradient');\n\n this.info = document.createElement('div');\n this.info.classList.add(PeerProfileAvatars.BASE_CLASS + '-info');\n\n this.tabs = document.createElement('div');\n this.tabs.classList.add(PeerProfileAvatars.BASE_CLASS + '-tabs');\n\n this.arrowPrevious = document.createElement('div');\n this.arrowPrevious.classList.add(PeerProfileAvatars.BASE_CLASS + '-arrow');\n\n /* const previousIcon = document.createElement('i');\n previousIcon.classList.add(PeerProfileAvatars.BASE_CLASS + '-arrow-icon', 'tgico-previous');\n this.arrowBack.append(previousIcon); */\n \n this.arrowNext = document.createElement('div');\n this.arrowNext.classList.add(PeerProfileAvatars.BASE_CLASS + '-arrow', PeerProfileAvatars.BASE_CLASS + '-arrow-next');\n\n /* const nextIcon = document.createElement('i');\n nextIcon.classList.add(PeerProfileAvatars.BASE_CLASS + '-arrow-icon', 'tgico-next');\n this.arrowNext.append(nextIcon); */\n\n this.container.append(this.avatars, this.gradient, this.info, this.tabs, this.arrowPrevious, this.arrowNext);\n\n const checkScrollTop = () => {\n if(this.scrollable.scrollTop !== 0) {\n this.scrollable.scrollIntoViewNew(this.scrollable.container.firstElementChild as HTMLElement, 'start');\n return false;\n }\n\n return true;\n };\n\n const SWITCH_ZONE = 1 / 3;\n let cancel = false;\n let freeze = false;\n attachClickEvent(this.container, async(_e) => {\n if(freeze) {\n cancelEvent(_e);\n return;\n }\n\n if(cancel) {\n cancel = false;\n return;\n }\n\n if(!checkScrollTop()) {\n return;\n }\n\n const rect = this.container.getBoundingClientRect();\n\n // const e = (_e as TouchEvent).touches ? (_e as TouchEvent).touches[0] : _e as MouseEvent;\n const e = _e;\n const x = e.pageX;\n\n const clickX = x - rect.left;\n if((!this.listLoader.previous.length && !this.listLoader.next.length) \n || (clickX > (rect.width * SWITCH_ZONE) && clickX < (rect.width - rect.width * SWITCH_ZONE))) {\n const peerId = this.peerId;\n\n const targets: {element: HTMLElement, item: string | Message.messageService}[] = [];\n this.listLoader.previous.concat(this.listLoader.current, this.listLoader.next).forEach((item, idx) => {\n targets.push({\n element: /* null */this.avatars.children[idx] as HTMLElement,\n item\n });\n });\n\n const prevTargets = targets.slice(0, this.listLoader.previous.length);\n const nextTargets = targets.slice(this.listLoader.previous.length + 1);\n\n const target = this.avatars.children[this.listLoader.previous.length] as HTMLElement;\n freeze = true;\n openAvatarViewer(target, peerId, () => peerId === this.peerId, this.listLoader.current, prevTargets, nextTargets);\n freeze = false;\n } else {\n const centerX = rect.right - (rect.width / 2);\n const toRight = x > centerX;\n \n // this.avatars.classList.remove('no-transition');\n // fastRaf(() => {\n this.avatars.classList.add('no-transition');\n void this.avatars.offsetLeft; // reflow\n\n let distance: number;\n if(this.listLoader.index === 0 && !toRight) distance = this.listLoader.count - 1;\n else if(this.listLoader.index === (this.listLoader.count - 1) && toRight) distance = -(this.listLoader.count - 1);\n else distance = toRight ? 1 : -1;\n this.listLoader.go(distance);\n\n fastRaf(() => {\n this.avatars.classList.remove('no-transition');\n });\n // });\n }\n });\n\n const cancelNextClick = () => {\n cancel = true;\n document.body.addEventListener(IS_TOUCH_SUPPORTED ? 'touchend' : 'click', (e) => {\n cancel = false;\n }, {once: true});\n };\n\n let width = 0, x = 0, lastDiffX = 0, lastIndex = 0, minX = 0;\n const swipeHandler = new SwipeHandler({\n element: this.avatars, \n onSwipe: (xDiff, yDiff) => {\n lastDiffX = xDiff;\n let lastX = x + xDiff * -PeerProfileAvatars.SCALE;\n if(lastX > 0) lastX = 0;\n else if(lastX < minX) lastX = minX;\n\n this.avatars.style.transform = PeerProfileAvatars.TRANSLATE_TEMPLATE.replace('{x}', lastX + 'px');\n //console.log(xDiff, yDiff);\n return false;\n }, \n verifyTouchTarget: (e) => {\n if(!checkScrollTop()) {\n cancelNextClick();\n cancelEvent(e);\n return false;\n } else if(this.container.classList.contains('is-single') || freeze) {\n return false;\n }\n\n return true;\n }, \n onFirstSwipe: () => {\n const rect = this.avatars.getBoundingClientRect();\n width = rect.width;\n minX = -width * (this.tabs.childElementCount - 1);\n\n /* lastIndex = whichChild(this.tabs.querySelector('.active'));\n x = -width * lastIndex; */\n x = rect.left - this.container.getBoundingClientRect().left;\n \n this.avatars.style.transform = PeerProfileAvatars.TRANSLATE_TEMPLATE.replace('{x}', x + 'px');\n\n this.container.classList.add('is-swiping');\n this.avatars.classList.add('no-transition');\n void this.avatars.offsetLeft; // reflow\n },\n onReset: () => {\n const addIndex = Math.ceil(Math.abs(lastDiffX) / (width / PeerProfileAvatars.SCALE)) * (lastDiffX >= 0 ? 1 : -1);\n cancelNextClick();\n \n //console.log(addIndex);\n\n this.avatars.classList.remove('no-transition');\n fastRaf(() => {\n this.listLoader.go(addIndex);\n this.container.classList.remove('is-swiping');\n });\n }\n });\n }\n\n public setPeer(peerId: number) {\n this.peerId = peerId;\n\n const photo = appPeersManager.getPeerPhoto(peerId);\n if(!photo) {\n return;\n }\n\n const listLoader: PeerProfileAvatars['listLoader'] = this.listLoader = new ListLoader({\n loadCount: 50,\n loadMore: (anchor, older, loadCount) => {\n if(!older) return Promise.resolve({count: undefined, items: []});\n\n if(peerId > 0) {\n const maxId: string = (anchor || listLoader.current) as any;\n return appPhotosManager.getUserPhotos(peerId, maxId, loadCount).then(value => {\n return {\n count: value.count,\n items: value.photos\n };\n });\n } else {\n const promises: [Promise<ChatFull>, ReturnType<AppMessagesManager['getSearch']>] = [] as any;\n if(!listLoader.current) {\n promises.push(appProfileManager.getChatFull(-peerId));\n }\n \n promises.push(appMessagesManager.getSearch({\n peerId,\n maxId: Number.MAX_SAFE_INTEGER,\n inputFilter: {\n _: 'inputMessagesFilterChatPhotos'\n },\n limit: loadCount,\n backLimit: 0\n }));\n\n return Promise.all(promises).then((result) => {\n const value = result.pop() as typeof result[1];\n\n filterChatPhotosMessages(value);\n\n if(!listLoader.current) {\n const chatFull = result[0];\n const message = value.history.findAndSplice(m => {\n return ((m as Message.messageService).action as MessageAction.messageActionChannelEditPhoto).photo.id === chatFull.chat_photo.id;\n }) as Message.messageService;\n \n listLoader.current = message || appMessagesManager.generateFakeAvatarMessage(this.peerId, chatFull.chat_photo);\n }\n\n //console.log('avatars loaded:', value);\n return {\n count: value.count,\n items: value.history\n };\n });\n }\n },\n processItem: this.processItem,\n onJump: (item, older) => {\n const id = this.listLoader.index;\n //const nextId = Math.max(0, id);\n const x = 100 * PeerProfileAvatars.SCALE * id;\n this.avatars.style.transform = PeerProfileAvatars.TRANSLATE_TEMPLATE.replace('{x}', `-${x}%`);\n\n const activeTab = this.tabs.querySelector('.active');\n if(activeTab) activeTab.classList.remove('active');\n\n const tab = this.tabs.children[id] as HTMLElement;\n tab.classList.add('active');\n }\n });\n\n if(photo._ === 'userProfilePhoto') {\n listLoader.current = photo.photo_id;\n }\n\n this.processItem(listLoader.current);\n\n // listLoader.loaded\n listLoader.load(true);\n }\n\n public addTab() {\n const tab = document.createElement('div');\n tab.classList.add(PeerProfileAvatars.BASE_CLASS + '-tab');\n this.tabs.append(tab);\n\n if(this.tabs.childElementCount === 1) {\n tab.classList.add('active');\n }\n\n this.container.classList.toggle('is-single', this.tabs.childElementCount <= 1);\n }\n\n public processItem = (photoId: string | Message.messageService) => {\n const avatar = document.createElement('div');\n avatar.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatar');\n\n let photo: Photo.photo;\n if(photoId) {\n photo = typeof(photoId) === 'string' ? \n appPhotosManager.getPhoto(photoId) : \n (photoId.action as MessageAction.messageActionChannelEditPhoto).photo as Photo.photo;\n }\n\n const img = new Image();\n img.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatar-image');\n img.draggable = false;\n\n if(photo) {\n const size = appPhotosManager.choosePhotoSize(photo, 420, 420, false);\n appPhotosManager.preloadPhoto(photo, size).then(() => {\n const cacheContext = appDownloadManager.getCacheContext(photo, size.type);\n renderImageFromUrl(img, cacheContext.url, () => {\n avatar.append(img);\n });\n });\n } else {\n const photo = appPeersManager.getPeerPhoto(this.peerId);\n appAvatarsManager.putAvatar(avatar, this.peerId, photo, 'photo_big', img);\n }\n\n this.avatars.append(avatar);\n\n this.addTab();\n\n return photoId;\n };\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport PARALLAX_SUPPORTED from \"../environment/parallaxSupport\";\nimport { copyTextToClipboard } from \"../helpers/clipboard\";\nimport replaceContent from \"../helpers/dom/replaceContent\";\nimport { fastRaf } from \"../helpers/schedulers\";\nimport { User } from \"../layer\";\nimport { Channel } from \"../lib/appManagers/appChatsManager\";\nimport appImManager from \"../lib/appManagers/appImManager\";\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\nimport appNotificationsManager from \"../lib/appManagers/appNotificationsManager\";\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\nimport I18n from \"../lib/langPack\";\nimport RichTextProcessor from \"../lib/richtextprocessor\";\nimport rootScope from \"../lib/rootScope\";\nimport AvatarElement from \"./avatar\";\nimport CheckboxField from \"./checkboxField\";\nimport generateVerifiedIcon from \"./generateVerifiedIcon\";\nimport PeerProfileAvatars from \"./peerProfileAvatars\";\nimport PeerTitle from \"./peerTitle\";\nimport Row from \"./row\";\nimport Scrollable from \"./scrollable\";\nimport { SettingSection, generateDelimiter } from \"./sidebarLeft\";\nimport { toast } from \"./toast\";\n\nlet setText = (text: string, row: Row) => {\n //fastRaf(() => {\n row.title.innerHTML = text;\n row.container.style.display = '';\n //});\n};\n\nexport default class PeerProfile {\n public element: HTMLElement;\n public avatars: PeerProfileAvatars;\n private avatar: AvatarElement;\n private section: SettingSection;\n private name: HTMLDivElement;\n private subtitle: HTMLDivElement;\n private bio: Row;\n private username: Row;\n private phone: Row;\n private notifications: Row;\n \n private cleaned: boolean;\n private setBioTimeout: number;\n private setPeerStatusInterval: number;\n\n private peerId = 0;\n private threadId: number;\n\n constructor(public scrollable: Scrollable) {\n if(!PARALLAX_SUPPORTED) {\n this.scrollable.container.classList.add('no-parallax');\n }\n }\n\n public init() {\n this.init = null;\n\n this.element = document.createElement('div');\n this.element.classList.add('profile-content');\n\n this.section = new SettingSection({\n noDelimiter: true\n });\n\n this.avatar = new AvatarElement();\n this.avatar.classList.add('profile-avatar', 'avatar-120');\n this.avatar.setAttribute('dialog', '1');\n this.avatar.setAttribute('clickable', '');\n\n this.name = document.createElement('div');\n this.name.classList.add('profile-name');\n\n this.subtitle = document.createElement('div');\n this.subtitle.classList.add('profile-subtitle');\n\n this.bio = new Row({\n title: ' ',\n subtitleLangKey: 'UserBio',\n icon: 'info',\n clickable: (e) => {\n if((e.target as HTMLElement).tagName === 'A') {\n return;\n }\n \n appProfileManager.getProfileByPeerId(this.peerId).then(full => {\n copyTextToClipboard(full.about);\n toast(I18n.format('BioCopied', true));\n });\n }\n });\n\n this.bio.title.classList.add('pre-wrap');\n\n this.username = new Row({\n title: ' ',\n subtitleLangKey: 'Username',\n icon: 'username',\n clickable: () => {\n const peer: Channel | User.user = appPeersManager.getPeer(this.peerId);\n copyTextToClipboard('@' + peer.username);\n toast(I18n.format('UsernameCopied', true));\n }\n });\n\n this.phone = new Row({\n title: ' ',\n subtitleLangKey: 'Phone',\n icon: 'phone',\n clickable: () => {\n const peer: User = appUsersManager.getUser(this.peerId);\n copyTextToClipboard('+' + peer.phone);\n toast(I18n.format('PhoneCopied', true));\n }\n });\n\n this.notifications = new Row({\n checkboxField: new CheckboxField({toggle: true}),\n titleLangKey: 'Notifications',\n icon: 'unmute'\n });\n \n this.section.content.append(this.phone.container, this.username.container, this.bio.container, this.notifications.container);\n\n this.element.append(this.section.container, generateDelimiter());\n\n this.notifications.checkboxField.input.addEventListener('change', (e) => {\n if(!e.isTrusted) {\n return;\n }\n\n //let checked = this.notificationsCheckbox.checked;\n appMessagesManager.mutePeer(this.peerId);\n });\n\n rootScope.addEventListener('dialog_notify_settings', (dialog) => {\n if(this.peerId === dialog.peerId) {\n const muted = appNotificationsManager.isPeerLocalMuted(this.peerId, false);\n this.notifications.checkboxField.checked = !muted;\n }\n });\n\n rootScope.addEventListener('peer_typings', ({peerId}) => {\n if(this.peerId === peerId) {\n this.setPeerStatus();\n }\n });\n\n rootScope.addEventListener('peer_bio_edit', (peerId) => {\n if(peerId === this.peerId) {\n this.setBio(true);\n }\n });\n\n rootScope.addEventListener('user_update', (userId) => {\n if(this.peerId === userId) {\n this.setPeerStatus();\n }\n });\n\n rootScope.addEventListener('contacts_update', (userId) => {\n if(this.peerId === userId) {\n const user = appUsersManager.getUser(userId);\n if(!user.pFlags.self) {\n if(user.phone) {\n setText(appUsersManager.formatUserPhone(user.phone), this.phone);\n } else {\n this.phone.container.style.display = 'none';\n }\n }\n }\n });\n\n this.setPeerStatusInterval = window.setInterval(this.setPeerStatus, 60e3);\n }\n\n public setPeerStatus = (needClear = false) => {\n if(!this.peerId) return;\n\n const peerId = this.peerId;\n appImManager.setPeerStatus(this.peerId, this.subtitle, needClear, true, () => peerId === this.peerId);\n };\n\n public cleanupHTML() {\n this.bio.container.style.display = 'none';\n this.phone.container.style.display = 'none';\n this.username.container.style.display = 'none';\n this.notifications.container.style.display = '';\n this.notifications.checkboxField.checked = true;\n if(this.setBioTimeout) {\n window.clearTimeout(this.setBioTimeout);\n this.setBioTimeout = 0;\n }\n }\n\n public setAvatar() {\n if(this.peerId !== rootScope.myId) {\n const photo = appPeersManager.getPeerPhoto(this.peerId);\n\n if(photo) {\n const oldAvatars = this.avatars;\n this.avatars = new PeerProfileAvatars(this.scrollable);\n this.avatars.setPeer(this.peerId);\n this.avatars.info.append(this.name, this.subtitle);\n \n this.avatar.remove();\n \n if(oldAvatars) oldAvatars.container.replaceWith(this.avatars.container);\n else this.element.prepend(this.avatars.container);\n\n if(PARALLAX_SUPPORTED) {\n this.scrollable.container.classList.add('parallax');\n }\n\n return;\n }\n }\n\n if(PARALLAX_SUPPORTED) {\n this.scrollable.container.classList.remove('parallax');\n }\n\n if(this.avatars) {\n this.avatars.container.remove();\n this.avatars = undefined;\n }\n\n this.avatar.setAttribute('peer', '' + this.peerId);\n\n this.section.content.prepend(this.avatar, this.name, this.subtitle);\n }\n\n public fillProfileElements() {\n if(!this.cleaned) return;\n this.cleaned = false;\n \n const peerId = this.peerId;\n\n this.cleanupHTML();\n\n this.setAvatar();\n\n // username\n if(peerId !== rootScope.myId) {\n let username = appPeersManager.getPeerUsername(peerId);\n if(username) {\n setText(appPeersManager.getPeerUsername(peerId), this.username);\n }\n \n const muted = appNotificationsManager.isPeerLocalMuted(peerId, false);\n this.notifications.checkboxField.checked = !muted;\n } else {\n fastRaf(() => {\n this.notifications.container.style.display = 'none';\n });\n }\n \n //let membersLi = this.profileTabs.firstElementChild.children[0] as HTMLLIElement;\n if(peerId > 0) {\n //membersLi.style.display = 'none';\n\n let user = appUsersManager.getUser(peerId);\n if(user.phone && peerId !== rootScope.myId) {\n setText(appUsersManager.formatUserPhone(user.phone), this.phone);\n }\n }/* else {\n //membersLi.style.display = appPeersManager.isBroadcast(peerId) ? 'none' : '';\n } */\n\n this.setBio();\n\n replaceContent(this.name, new PeerTitle({\n peerId,\n dialog: true,\n }).element);\n\n const peer = appPeersManager.getPeer(peerId);\n if(peer?.pFlags?.verified) {\n this.name.append(generateVerifiedIcon());\n }\n\n this.setPeerStatus(true);\n }\n\n public setBio(override?: true) {\n if(this.setBioTimeout) {\n window.clearTimeout(this.setBioTimeout);\n this.setBioTimeout = 0;\n }\n\n const peerId = this.peerId;\n const threadId = this.threadId;\n\n if(!peerId) {\n return;\n }\n\n let promise: Promise<boolean>;\n if(peerId > 0) {\n promise = appProfileManager.getProfile(peerId, override).then(userFull => {\n if(this.peerId !== peerId || this.threadId !== threadId) {\n //this.log.warn('peer changed');\n return false;\n }\n \n if(userFull.rAbout && peerId !== rootScope.myId) {\n setText(userFull.rAbout, this.bio);\n }\n \n //this.log('userFull', userFull);\n return true;\n });\n } else {\n promise = appProfileManager.getChatFull(-peerId, override).then((chatFull) => {\n if(this.peerId !== peerId || this.threadId !== threadId) {\n //this.log.warn('peer changed');\n return false;\n }\n \n //this.log('chatInfo res 2:', chatFull);\n \n if(chatFull.about) {\n setText(RichTextProcessor.wrapRichText(chatFull.about), this.bio);\n }\n\n return true;\n });\n }\n\n promise.then((canSetNext) => {\n if(canSetNext) {\n this.setBioTimeout = window.setTimeout(() => this.setBio(true), 60e3);\n }\n });\n }\n\n public setPeer(peerId: number, threadId = 0) {\n if(this.peerId === peerId && this.threadId === peerId) return;\n\n if(this.init) {\n this.init();\n }\n\n this.peerId = peerId;\n this.threadId = threadId;\n \n this.cleaned = true;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appMessagesManager from \"../../../lib/appManagers/appMessagesManager\";\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\nimport rootScope from \"../../../lib/rootScope\";\nimport AppSearchSuper, { SearchSuperType } from \"../../appSearchSuper.\";\nimport SidebarSlider, { SliderSuperTab } from \"../../slider\";\nimport { TransitionSlider } from \"../../transition\";\nimport AppEditChatTab from \"./editChat\";\nimport PeerTitle from \"../../peerTitle\";\nimport AppEditContactTab from \"./editContact\";\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\nimport Button from \"../../button\";\nimport ButtonIcon from \"../../buttonIcon\";\nimport { i18n, LangPackKey } from \"../../../lib/langPack\";\nimport { toastNew } from \"../../toast\";\nimport AppAddMembersTab from \"../../sidebarLeft/tabs/addMembers\";\nimport PopupPickUser from \"../../popups/pickUser\";\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerCheckboxOptions } from \"../../popups/peer\";\nimport ButtonCorner from \"../../buttonCorner\";\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\nimport PeerProfile from \"../../peerProfile\";\n\n// TODO: отредактированное сообщение не изменится\nexport default class AppSharedMediaTab extends SliderSuperTab {\n private editBtn: HTMLElement;\n\n private peerId = 0;\n private threadId = 0;\n\n private historiesStorage: {\n [peerId: number]: Partial<{\n [type in SearchSuperType]: {mid: number, peerId: number}[]\n }>\n } = {};\n\n private searchSuper: AppSearchSuper;\n\n private profile: PeerProfile;\n private peerChanged: boolean;\n\n constructor(slider: SidebarSlider) {\n super(slider, false);\n }\n\n public init() {\n //const perf = performance.now();\n\n this.container.classList.add('shared-media-container', 'profile-container');\n\n // * header\n const newCloseBtn = Button('btn-icon sidebar-close-button', {noRipple: true});\n this.closeBtn.replaceWith(newCloseBtn);\n this.closeBtn = newCloseBtn;\n\n const animatedCloseIcon = document.createElement('div');\n animatedCloseIcon.classList.add('animated-close-icon');\n newCloseBtn.append(animatedCloseIcon);\n\n const transitionContainer = document.createElement('div');\n transitionContainer.className = 'transition slide-fade';\n \n const transitionFirstItem = document.createElement('div');\n transitionFirstItem.classList.add('transition-item');\n\n this.title.append(i18n('Profile'));\n this.editBtn = ButtonIcon('edit');\n //const moreBtn = ButtonIcon('more');\n\n transitionFirstItem.append(this.title, this.editBtn/* , moreBtn */);\n\n const transitionLastItem = document.createElement('div');\n transitionLastItem.classList.add('transition-item');\n\n const secondTitle: HTMLElement = this.title.cloneNode() as any;\n secondTitle.append(i18n('PeerInfo.SharedMedia'));\n\n transitionLastItem.append(secondTitle);\n\n transitionContainer.append(transitionFirstItem, transitionLastItem);\n\n this.header.append(transitionContainer);\n\n // * body\n\n this.profile = new PeerProfile(this.scrollable);\n this.profile.init();\n \n this.scrollable.append(this.profile.element);\n\n const HEADER_HEIGHT = 56;\n this.scrollable.onAdditionalScroll = () => {\n const rect = this.searchSuper.nav.getBoundingClientRect(); \n if(!rect.width) return;\n\n const top = rect.top - 1;\n const isSharedMedia = top <= HEADER_HEIGHT;\n animatedCloseIcon.classList.toggle('state-back', isSharedMedia);\n this.searchSuper.container.classList.toggle('is-full-viewport', isSharedMedia);\n transition(+isSharedMedia);\n\n if(!isSharedMedia) {\n this.searchSuper.cleanScrollPositions();\n }\n };\n\n const transition = TransitionSlider(transitionContainer, 'slide-fade', 400, null, false);\n\n transition(0);\n\n attachClickEvent(this.closeBtn, (e) => {\n if(this.closeBtn.firstElementChild.classList.contains('state-back')) {\n this.scrollable.scrollIntoViewNew(this.scrollable.container.firstElementChild as HTMLElement, 'start');\n transition(0);\n animatedCloseIcon.classList.remove('state-back');\n } else if(!this.scrollable.isHeavyAnimationInProgress) {\n this.slider.onCloseBtnClick();\n }\n });\n\n attachClickEvent(this.editBtn, (e) => {\n let tab: AppEditChatTab | AppEditContactTab;\n if(this.peerId < 0) {\n tab = new AppEditChatTab(this.slider);\n } else {\n tab = new AppEditContactTab(this.slider);\n }\n\n if(tab) {\n if(tab instanceof AppEditChatTab) {\n tab.chatId = -this.peerId;\n } else {\n tab.peerId = this.peerId;\n }\n \n tab.open();\n }\n });\n\n rootScope.addEventListener('contacts_update', (userId) => {\n if(this.peerId === userId) {\n this.toggleEditBtn();\n }\n });\n\n rootScope.addEventListener('chat_update', (chatId) => {\n if(this.peerId === -chatId) {\n this.toggleEditBtn();\n }\n });\n\n rootScope.addEventListener('history_multiappend', (msgIdsByPeer) => {\n for(const peerId in msgIdsByPeer) {\n this.renderNewMessages(+peerId, Array.from(msgIdsByPeer[peerId]));\n }\n });\n \n rootScope.addEventListener('history_delete', ({peerId, msgs}) => {\n this.deleteDeletedMessages(peerId, Array.from(msgs));\n });\n\n // Calls when message successfully sent and we have an id\n rootScope.addEventListener('message_sent', ({message}) => {\n this.renderNewMessages(message.peerId, [message.mid]);\n });\n\n //this.container.prepend(this.closeBtn.parentElement);\n\n this.searchSuper = new AppSearchSuper({\n mediaTabs: [{\n inputFilter: 'inputMessagesFilterEmpty',\n name: 'PeerMedia.Members',\n type: 'members'\n }, {\n inputFilter: 'inputMessagesFilterPhotoVideo',\n name: 'SharedMediaTab2',\n type: 'media'\n }, {\n inputFilter: 'inputMessagesFilterDocument',\n name: 'SharedFilesTab2',\n type: 'files'\n }, {\n inputFilter: 'inputMessagesFilterUrl',\n name: 'SharedLinksTab2',\n type: 'links'\n }, {\n inputFilter: 'inputMessagesFilterMusic',\n name: 'SharedMusicTab2',\n type: 'music'\n }, {\n inputFilter: 'inputMessagesFilterRoundVoice',\n name: 'SharedVoiceTab2',\n type: 'voice'\n }], \n scrollable: this.scrollable,\n onChangeTab: (mediaTab) => {\n let timeout = mediaTab.type === 'members' && rootScope.settings.animationsEnabled ? 250 : 0;\n setTimeout(() => {\n btnAddMembers.classList.toggle('is-hidden', mediaTab.type !== 'members');\n }, timeout);\n }\n });\n\n this.profile.element.append(this.searchSuper.container);\n\n const btnAddMembers = ButtonCorner({icon: 'addmember_filled'});\n this.content.append(btnAddMembers);\n\n btnAddMembers.addEventListener('click', () => {\n const id = -this.peerId;\n const isChannel = appChatsManager.isChannel(id);\n\n const showConfirmation = (peerIds: number[], callback: (checked: PopupPeerButtonCallbackCheckboxes) => void) => {\n let titleLangKey: LangPackKey, titleLangArgs: any[],\n descriptionLangKey: LangPackKey, descriptionLangArgs: any[],\n checkboxes: PopupPeerCheckboxOptions[];\n\n if(peerIds.length > 1) {\n titleLangKey = 'AddMembersAlertTitle';\n titleLangArgs = [i18n('Members', [peerIds.length])];\n descriptionLangKey = 'AddMembersAlertCountText';\n descriptionLangArgs = peerIds.map(peerId => {\n const b = document.createElement('b');\n b.append(new PeerTitle({peerId}).element);\n return b;\n });\n\n if(!isChannel) {\n checkboxes = [{\n text: 'AddMembersForwardMessages',\n checked: true\n }];\n }\n } else {\n titleLangKey = 'AddOneMemberAlertTitle';\n descriptionLangKey = 'AddMembersAlertNamesText';\n const b = document.createElement('b');\n b.append(new PeerTitle({\n peerId: peerIds[0]\n }).element);\n descriptionLangArgs = [b];\n\n if(!isChannel) {\n checkboxes = [{\n text: 'AddOneMemberForwardMessages',\n textArgs: [new PeerTitle({peerId: peerIds[0]}).element],\n checked: true\n }];\n }\n }\n\n descriptionLangArgs.push(new PeerTitle({\n peerId: -id\n }).element);\n\n new PopupPeer('popup-add-members', {\n peerId: -id,\n titleLangKey,\n descriptionLangKey,\n descriptionLangArgs,\n buttons: [{\n langKey: 'Add',\n callback\n }],\n checkboxes\n }).show();\n };\n\n const onError = (err: any) => {\n if(err.type === 'USER_PRIVACY_RESTRICTED') {\n toastNew({langPackKey: 'InviteToGroupError'});\n }\n };\n \n if(isChannel) {\n const tab = new AppAddMembersTab(this.slider);\n tab.open({\n peerId: this.peerId,\n type: 'channel',\n skippable: false,\n takeOut: (peerIds) => {\n showConfirmation(peerIds, () => {\n const promise = appChatsManager.inviteToChannel(id, peerIds);\n promise.catch(onError);\n tab.attachToPromise(promise);\n });\n\n return false;\n },\n title: 'GroupAddMembers',\n placeholder: 'SendMessageTo'\n });\n } else {\n new PopupPickUser({\n peerTypes: ['contacts'],\n placeholder: 'Search',\n onSelect: (peerId) => {\n setTimeout(() => {\n showConfirmation([peerId], (checked) => {\n appChatsManager.addChatUser(id, peerId, checked.size ? undefined : 0)\n .catch(onError);\n });\n }, 0);\n },\n });\n }\n });\n\n //console.log('construct shared media time:', performance.now() - perf);\n }\n\n public renderNewMessages(peerId: number, mids: number[]) {\n if(this.init) return; // * not inited yet\n\n if(!this.historiesStorage[peerId]) return;\n \n mids = mids.slice().reverse(); // ! because it will be ascend sorted array\n for(const mediaTab of this.searchSuper.mediaTabs) {\n const inputFilter = mediaTab.inputFilter;\n const filtered = this.searchSuper.filterMessagesByType(mids.map(mid => appMessagesManager.getMessageByPeer(peerId, mid)), inputFilter);\n if(filtered.length) {\n const history = this.historiesStorage[peerId][inputFilter];\n if(history) {\n history.unshift(...filtered.map(message => ({mid: message.mid, peerId: message.peerId})));\n }\n\n if(this.peerId === peerId && this.searchSuper.usedFromHistory[inputFilter] !== -1) {\n this.searchSuper.usedFromHistory[inputFilter] += filtered.length;\n this.searchSuper.performSearchResult(filtered, mediaTab, false);\n }\n }\n }\n }\n\n public deleteDeletedMessages(peerId: number, mids: number[]) {\n if(this.init) return; // * not inited yet\n\n if(!this.historiesStorage[peerId]) return;\n\n for(const mid of mids) {\n for(const type of this.searchSuper.mediaTabs) {\n const inputFilter = type.inputFilter;\n\n const history = this.historiesStorage[peerId][inputFilter];\n if(!history) continue;\n\n const idx = history.findIndex(m => m.mid === mid);\n if(idx !== -1) {\n history.splice(idx, 1);\n\n if(this.peerId === peerId) {\n const container = this.searchSuper.tabs[inputFilter];\n const div = container.querySelector(`div[data-mid=\"${mid}\"][data-peer-id=\"${peerId}\"]`) as HTMLElement;\n if(div) {\n if(this.searchSuper.selection.isSelecting) {\n this.searchSuper.selection.toggleByElement(div);\n }\n\n div.remove();\n }\n \n if(this.searchSuper.usedFromHistory[inputFilter] >= (idx + 1)) {\n this.searchSuper.usedFromHistory[inputFilter]--;\n }\n }\n\n break;\n }\n }\n }\n\n this.scrollable.onScroll();\n }\n\n public cleanupHTML() {\n // const perf = performance.now();\n this.profile.cleanupHTML();\n \n this.editBtn.classList.add('hide');\n\n this.searchSuper.cleanupHTML(true);\n\n this.container.classList.toggle('can-add-members', this.searchSuper.canViewMembers() && appChatsManager.hasRights(-this.peerId, 'invite_users'));\n\n // console.log('cleanupHTML shared media time:', performance.now() - perf);\n }\n\n public setLoadMutex(promise: Promise<any>) {\n this.searchSuper.loadMutex = promise;\n }\n\n public setPeer(peerId: number, threadId = 0) {\n if(this.peerId === peerId && this.threadId === threadId) return false;\n\n this.peerId = peerId;\n this.threadId = threadId;\n this.peerChanged = true;\n\n if(this.init) {\n this.init();\n this.init = null;\n }\n\n this.searchSuper.setQuery({\n peerId, \n //threadId, \n historyStorage: this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {})\n });\n\n this.profile.setPeer(peerId, threadId);\n \n return true;\n }\n\n public fillProfileElements() {\n if(!this.peerChanged) {\n return;\n }\n\n this.peerChanged = false;\n\n this.cleanupHTML();\n\n this.profile.fillProfileElements();\n\n this.toggleEditBtn();\n }\n\n private toggleEditBtn() {\n let show: boolean;\n if(this.peerId > 0) {\n show = this.peerId !== rootScope.myId && appUsersManager.isContact(this.peerId);\n } else {\n show = appChatsManager.hasRights(-this.peerId, 'change_info');\n }\n\n this.editBtn.classList.toggle('hide', !show);\n }\n\n public loadSidebarMedia(single: boolean, justLoad = false) {\n this.searchSuper.load(single, justLoad);\n }\n\n onOpenAfterTimeout() {\n this.scrollable.onScroll();\n }\n}\n\n// MOUNT_CLASS_TO && (MOUNT_CLASS_TO.AppSharedMediaTab = AppSharedMediaTab);\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appImManager from \"../../lib/appManagers/appImManager\";\r\nimport SidebarSlider from \"../slider\";\r\nimport mediaSizes, { ScreenSize } from \"../../helpers/mediaSizes\";\r\nimport AppSharedMediaTab from \"./tabs/sharedMedia\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\n\r\nexport const RIGHT_COLUMN_ACTIVE_CLASSNAME = 'is-right-column-shown';\r\n\r\nexport class AppSidebarRight extends SidebarSlider {\r\n public sharedMediaTab: AppSharedMediaTab;\r\n private isColumnProportionSet = false;\r\n\r\n constructor() {\r\n super({\r\n sidebarEl: document.getElementById('column-right') as HTMLElement,\r\n canHideFirst: true,\r\n navigationType: 'right'\r\n });\r\n\r\n mediaSizes.addEventListener('changeScreen', (from, to) => {\r\n if(to === ScreenSize.medium && from !== ScreenSize.mobile) {\r\n this.toggleSidebar(false);\r\n }\r\n });\r\n\r\n mediaSizes.addEventListener('resize', () => {\r\n this.setColumnProportion();\r\n });\r\n\r\n this.sharedMediaTab = new AppSharedMediaTab(this);\r\n }\r\n\r\n public onCloseTab(id: number, animate: boolean, isNavigation?: boolean) {\r\n if(!this.historyTabIds.length) {\r\n this.toggleSidebar(false, animate);\r\n }\r\n\r\n super.onCloseTab(id, animate, isNavigation);\r\n }\r\n\r\n /* public selectTab(id: number) {\r\n const res = super.selectTab(id);\r\n\r\n if(id !== -1) {\r\n this.toggleSidebar(true);\r\n }\r\n\r\n return res;\r\n } */\r\n\r\n private setColumnProportion() {\r\n const proportion = this.sidebarEl.scrollWidth / this.sidebarEl.previousElementSibling.scrollWidth;\r\n document.documentElement.style.setProperty('--right-column-proportion', '' + proportion);\r\n }\r\n\r\n public toggleSidebar(enable?: boolean, animate?: boolean) {\r\n /////this.log('sidebarEl', this.sidebarEl, enable, isElementInViewport(this.sidebarEl));\r\n\r\n const active = document.body.classList.contains(RIGHT_COLUMN_ACTIVE_CLASSNAME);\r\n let willChange: boolean;\r\n if(enable !== undefined) {\r\n if(enable) {\r\n if(!active) {\r\n willChange = true;\r\n }\r\n } else if(active) {\r\n willChange = true;\r\n }\r\n } else {\r\n willChange = true;\r\n }\r\n\r\n if(!willChange) return Promise.resolve();\r\n\r\n if(!active && !this.historyTabIds.length) {\r\n this.sharedMediaTab.open();\r\n //this.selectTab(this.sharedMediaTab);\r\n }\r\n\r\n if(!this.isColumnProportionSet) {\r\n this.setColumnProportion();\r\n this.isColumnProportionSet = true;\r\n }\r\n\r\n const animationPromise = appImManager.selectTab(active ? 1 : 2, animate);\r\n document.body.classList.toggle(RIGHT_COLUMN_ACTIVE_CLASSNAME, enable);\r\n return animationPromise;\r\n\r\n /* return new Promise((resolve, reject) => {\r\n const hidden: {element: HTMLDivElement, height: number}[] = [];\r\n const observer = new IntersectionObserver((entries) => {\r\n for(const entry of entries) {\r\n const bubble = entry.target as HTMLDivElement;\r\n if(!entry.isIntersecting) {\r\n hidden.push({element: bubble, height: bubble.scrollHeight});\r\n }\r\n }\r\n \r\n for(const item of hidden) {\r\n item.element.style.minHeight = item.height + 'px';\r\n (item.element.firstElementChild as HTMLElement).style.display = 'none';\r\n item.element.style.width = '1px';\r\n }\r\n \r\n //console.log('hidden', hidden);\r\n observer.disconnect();\r\n \r\n set();\r\n \r\n setTimeout(() => {\r\n for(const item of hidden) {\r\n item.element.style.minHeight = '';\r\n item.element.style.width = '';\r\n (item.element.firstElementChild as HTMLElement).style.display = '';\r\n }\r\n\r\n resolve();\r\n }, 200);\r\n });\r\n \r\n const length = Object.keys(appImManager.bubbles).length;\r\n if(length) {\r\n for(const i in appImManager.bubbles) {\r\n observer.observe(appImManager.bubbles[i]);\r\n }\r\n } else {\r\n set();\r\n setTimeout(resolve, 200);\r\n }\r\n }); */\r\n }\r\n}\r\n\r\nconst appSidebarRight = new AppSidebarRight();\r\nMOUNT_CLASS_TO.appSidebarRight = appSidebarRight;\r\nexport default appSidebarRight;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport appSidebarRight from \"..\";\r\nimport appPollsManager from \"../../../lib/appManagers/appPollsManager\";\r\nimport { roundPercents } from \"../../poll\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport { ripple } from \"../../ripple\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\n\r\nexport default class AppPollResultsTab extends SliderSuperTab {\r\n private resultsDiv: HTMLElement;\r\n\r\n protected init() {\r\n this.container.id = 'poll-results-container';\r\n this.container.classList.add('chatlist-container');\r\n\r\n this.resultsDiv = document.createElement('div');\r\n this.resultsDiv.classList.add('poll-results');\r\n this.scrollable.append(this.resultsDiv);\r\n }\r\n\r\n public open(message: any) {\r\n const ret = super.open();\r\n const poll = appPollsManager.getPoll(message.media.poll.id);\r\n\r\n this.setTitle(poll.poll.pFlags.quiz ? 'PollResults.Title.Quiz' : 'PollResults.Title.Poll');\r\n\r\n const title = document.createElement('h3');\r\n title.innerHTML = poll.poll.rQuestion;\r\n\r\n const percents = poll.results.results.map(v => v.voters / poll.results.total_voters * 100);\r\n roundPercents(percents);\r\n\r\n const fragment = document.createDocumentFragment();\r\n poll.results.results.forEach((result, idx) => {\r\n if(!result.voters) return;\r\n\r\n const hr = document.createElement('hr');\r\n\r\n const answer = poll.poll.answers[idx];\r\n\r\n // Head\r\n const answerEl = document.createElement('div');\r\n answerEl.classList.add('poll-results-answer');\r\n\r\n const answerTitle = document.createElement('div');\r\n answerTitle.innerHTML = RichTextProcessor.wrapEmojiText(answer.text);\r\n\r\n const answerPercents = document.createElement('div');\r\n answerPercents.innerText = Math.round(percents[idx]) + '%';\r\n\r\n answerEl.append(answerTitle, answerPercents);\r\n\r\n // Humans\r\n const list = appDialogsManager.createChatList();\r\n list.classList.add('poll-results-voters');\r\n\r\n appDialogsManager.setListClickListener(list, () => {\r\n appSidebarRight.onCloseBtnClick();\r\n }, undefined, true);\r\n\r\n list.style.minHeight = Math.min(result.voters, 4) * 50 + 'px';\r\n\r\n fragment.append(hr, answerEl, list);\r\n\r\n let offset: string, limit = 4, loading = false, left = result.voters - 4;\r\n const load = () => {\r\n if(loading) return;\r\n loading = true;\r\n\r\n appPollsManager.getVotes(message, answer.option, offset, limit).then(votesList => {\r\n votesList.votes.forEach(vote => {\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: vote.user_id,\r\n container: list,\r\n drawStatus: false,\r\n rippleEnabled: false, \r\n meAsSaved: false,\r\n avatarSize: 32\r\n });\r\n dom.lastMessageSpan.parentElement.remove();\r\n });\r\n\r\n if(offset) {\r\n left -= votesList.votes.length;\r\n (showMore.lastElementChild as HTMLElement).replaceWith(i18n('PollResults.LoadMore', [Math.min(20, left)]));\r\n }\r\n \r\n offset = votesList.next_offset;\r\n limit = 20;\r\n\r\n if(!left || !votesList.votes.length) {\r\n showMore.remove();\r\n }\r\n }).finally(() => {\r\n loading = false;\r\n });\r\n };\r\n\r\n load();\r\n\r\n if(left <= 0) return;\r\n\r\n const showMore = document.createElement('div');\r\n showMore.classList.add('poll-results-more', 'show-more', 'rp-overflow');\r\n showMore.addEventListener('click', load);\r\n ripple(showMore);\r\n const down = document.createElement('div');\r\n down.classList.add('tgico-down');\r\n showMore.append(down, i18n('PollResults.LoadMore', [Math.min(20, left)]));\r\n\r\n fragment.append(showMore);\r\n });\r\n\r\n this.resultsDiv.append(title, fragment);\r\n\r\n appSidebarRight.toggleSidebar(true).then(() => {\r\n /* appPollsManager.getVotes(mid).then(votes => {\r\n console.log('gOt VotEs', votes);\r\n }); */\r\n });\r\n\r\n return ret;\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport mediaSizes from \"../helpers/mediaSizes\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\r\nimport appImManager from \"../lib/appManagers/appImManager\";\r\nimport appPollsManager, { Poll, PollResults } from \"../lib/appManagers/appPollsManager\";\r\nimport serverTimeManager from \"../lib/mtproto/serverTimeManager\";\r\nimport { RichTextProcessor } from \"../lib/richtextprocessor\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport { ripple } from \"./ripple\";\r\nimport appSidebarRight from \"./sidebarRight\";\r\nimport AppPollResultsTab from \"./sidebarRight/tabs/pollResults\";\r\nimport { i18n, LangPackKey } from \"../lib/langPack\";\r\nimport { fastRaf } from \"../helpers/schedulers\";\r\nimport SetTransition from \"./singleTransition\";\r\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent, detachClickEvent } from \"../helpers/dom/clickEvent\";\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport windowSize from \"../helpers/windowSize\";\r\n\r\nlet lineTotalLength = 0;\r\nconst tailLength = 9;\r\nconst times = 10;\r\nconst fullTime = 340;\r\nconst oneTime = fullTime / times;\r\n\r\nexport const roundPercents = (percents: number[]) => {\r\n //console.log('roundPercents before percents:', percents);\r\n\r\n const sum = percents.reduce((acc, p) => acc + Math.round(p), 0);\r\n if(sum > 100) {\r\n const diff = sum - 100;\r\n const length = percents.length;\r\n for(let i = 0; i < diff; ++i) {\r\n let minIndex = -1, minRemainder = 1;\r\n for(let k = 0; k < length; ++k) {\r\n let remainder = percents[k] % 1;\r\n if(remainder >= 0.5 && remainder < minRemainder) {\r\n minRemainder = remainder;\r\n minIndex = k;\r\n }\r\n }\r\n\r\n if(minIndex === -1) {\r\n //throw new Error('lol chto');\r\n return;\r\n }\r\n\r\n percents[minIndex] -= minRemainder;\r\n }\r\n } else if(sum < 100) {\r\n const diff = 100 - sum;\r\n const length = percents.length;\r\n for(let i = 0; i < diff; ++i) {\r\n let minIndex = -1, maxRemainder = 0;\r\n for(let k = 0; k < length; ++k) {\r\n let remainder = percents[k] % 1;\r\n if(remainder < 0.5 && remainder > maxRemainder) {\r\n maxRemainder = remainder;\r\n minIndex = k;\r\n }\r\n }\r\n\r\n if(minIndex === -1) {\r\n //throw new Error('lol chto');\r\n return;\r\n }\r\n\r\n percents[minIndex] += 1 - maxRemainder;\r\n }\r\n }\r\n\r\n //console.log('roundPercents after percents:', percents);\r\n};\r\n\r\n/* const connectedPolls: {id: string, element: PollElement}[] = [];\r\nrootScope.on('poll_update', (e) => {\r\n const {poll, results} = e as {poll: Poll, results: PollResults};\r\n\r\n //console.log('poll_update', poll, results);\r\n for(const connected of connectedPolls) {\r\n if(connected.id === poll.id) {\r\n const pollElement = connected.element;\r\n pollElement.isClosed = !!poll.pFlags.closed;\r\n pollElement.performResults(results, poll.chosenIndexes);\r\n }\r\n }\r\n}); */\r\n\r\nrootScope.addEventListener('poll_update', (e) => {\r\n const {poll, results} = e as {poll: Poll, results: PollResults};\r\n\r\n const pollElements = Array.from(document.querySelectorAll(`poll-element[poll-id=\"${poll.id}\"]`)) as PollElement[];\r\n pollElements.forEach(pollElement => {\r\n //console.log('poll_update', poll, results);\r\n pollElement.isClosed = !!poll.pFlags.closed;\r\n pollElement.performResults(results, poll.chosenIndexes);\r\n });\r\n});\r\n\r\nrootScope.addEventListener('peer_changed', () => {\r\n if(prevQuizHint) {\r\n hideQuizHint(prevQuizHint, prevQuizHintOnHide, prevQuizHintTimeout);\r\n }\r\n});\r\n\r\nmediaSizes.addEventListener('resize', () => {\r\n PollElement.setMaxLength();\r\n PollElement.resizePolls();\r\n});\r\n\r\nmediaSizes.addEventListener('changeScreen', () => {\r\n PollElement.setMaxLength();\r\n});\r\n\r\nconst hideQuizHint = (element: HTMLElement, onHide: () => void, timeout: number) => {\r\n element.classList.remove('active');\r\n\r\n clearTimeout(timeout);\r\n setTimeout(() => {\r\n onHide();\r\n element.remove();\r\n\r\n if(prevQuizHint === element && prevQuizHintOnHide === onHide && prevQuizHintTimeout === timeout) {\r\n prevQuizHint = prevQuizHintOnHide = null;\r\n prevQuizHintTimeout = 0;\r\n }\r\n }, 200);\r\n};\r\n\r\nlet prevQuizHint: HTMLElement, prevQuizHintOnHide: () => void, prevQuizHintTimeout: number;\r\nconst setQuizHint = (solution: string, solution_entities: any[], onHide: () => void) => {\r\n if(prevQuizHint) {\r\n hideQuizHint(prevQuizHint, prevQuizHintOnHide, prevQuizHintTimeout);\r\n }\r\n\r\n const element = document.createElement('div');\r\n element.classList.add('quiz-hint');\r\n\r\n const container = document.createElement('div');\r\n container.classList.add('container', 'tgico');\r\n\r\n const textEl = document.createElement('div');\r\n textEl.classList.add('text');\r\n\r\n container.append(textEl);\r\n element.append(container);\r\n\r\n textEl.innerHTML = RichTextProcessor.wrapRichText(solution, {entities: solution_entities});\r\n appImManager.chat.bubbles.bubblesContainer.append(element);\r\n\r\n void element.offsetLeft; // reflow\r\n element.classList.add('active');\r\n\r\n prevQuizHint = element;\r\n prevQuizHintOnHide = onHide;\r\n prevQuizHintTimeout = window.setTimeout(() => {\r\n hideQuizHint(element, onHide, prevQuizHintTimeout);\r\n }, IS_TOUCH_SUPPORTED ? 5000 : 7000);\r\n};\r\n\r\nexport default class PollElement extends HTMLElement {\r\n public static MAX_OFFSET = -46.5;\r\n public static MAX_LENGTH = 0;\r\n public svgLines: SVGSVGElement[];\r\n private numberDivs: HTMLDivElement[];\r\n private answerDivs: HTMLDivElement[];\r\n private descDiv: HTMLElement;\r\n private typeDiv: HTMLElement;\r\n private avatarsDiv: HTMLElement;\r\n private viewResults: HTMLElement;\r\n private votersCountDiv: HTMLDivElement;\r\n\r\n // private maxLength: number;\r\n // private maxLengths: number[];\r\n private maxPercents: number[];\r\n\r\n public isClosed = false;\r\n private isQuiz = false;\r\n private isRetracted = false;\r\n private isPublic = false;\r\n private isMultiple = false;\r\n private chosenIndexes: number[] = [];\r\n private percents: number[];\r\n\r\n public message: any;\r\n\r\n private quizInterval: number;\r\n private quizTimer: SVGSVGElement;\r\n\r\n private sendVoteBtn: HTMLElement;\r\n private chosingIndexes: number[] = [];\r\n\r\n private sendVotePromise: Promise<void>;\r\n private sentVote = false;\r\n\r\n constructor() {\r\n super();\r\n // элемент создан\r\n }\r\n\r\n public static setMaxLength() {\r\n const width = windowSize.windowW <= 360 ? windowSize.windowW - 120 : mediaSizes.active.poll.width;\r\n this.MAX_LENGTH = width + tailLength + this.MAX_OFFSET + -13.7; // 13 - position left\r\n }\r\n\r\n public static resizePolls() {\r\n if(!this.MAX_LENGTH) return;\r\n const pollElements = Array.from(document.querySelectorAll('poll-element.is-voted')) as PollElement[];\r\n pollElements.forEach(pollElement => {\r\n pollElement.svgLines.forEach((svg, idx) => {\r\n //void svg.getBoundingClientRect(); // reflow\r\n pollElement.setLineProgress(idx, 1);\r\n });\r\n });\r\n }\r\n\r\n public render() {\r\n // браузер вызывает этот метод при добавлении элемента в документ\r\n // (может вызываться много раз, если элемент многократно добавляется/удаляется)\r\n\r\n if(!lineTotalLength) {\r\n lineTotalLength = (document.getElementById('poll-line') as any as SVGPathElement).getTotalLength();\r\n //console.log('line total length:', lineTotalLength);\r\n PollElement.setMaxLength();\r\n }\r\n\r\n const pollId = this.message.media.poll.id;\r\n const {poll, results} = appPollsManager.getPoll(pollId);\r\n\r\n /* const timestamp = Date.now() / 1000 | 0;\r\n if(timestamp < this.message.date) { */\r\n if(this.message.pFlags.is_scheduled) {\r\n this.classList.add('disable-hover');\r\n }\r\n\r\n //console.log('pollElement poll:', poll, results);\r\n\r\n let descKey: LangPackKey;\r\n if(poll.pFlags) {\r\n this.isPublic = !!poll.pFlags.public_voters;\r\n this.isQuiz = !!poll.pFlags.quiz;\r\n this.isClosed = !!poll.pFlags.closed;\r\n this.isMultiple = !!poll.pFlags.multiple_choice;\r\n\r\n if(this.isClosed) {\r\n descKey = 'Chat.Poll.Type.Closed';\r\n this.classList.add('is-closed');\r\n } else if(this.isQuiz) {\r\n descKey = this.isPublic ? 'Chat.Poll.Type.Quiz' : 'Chat.Poll.Type.AnonymousQuiz';\r\n } else {\r\n descKey = this.isPublic ? 'Chat.Poll.Type.Public' : 'Chat.Poll.Type.Anonymous';\r\n }\r\n }\r\n\r\n this.classList.toggle('is-multiple', this.isMultiple);\r\n\r\n const multipleSelect = this.isMultiple ? '<span class=\"poll-answer-selected tgico-check\"></span>' : '';\r\n const votes = poll.answers.map((answer, idx) => {\r\n return `\r\n <div class=\"poll-answer\" data-index=\"${idx}\">\r\n <div class=\"circle-hover\">\r\n <div class=\"animation-ring\"></div>\r\n <svg class=\"progress-ring\">\r\n <circle class=\"progress-ring__circle\" cx=\"13\" cy=\"13\" r=\"9\"></circle>\r\n </svg>\r\n ${multipleSelect}\r\n </div>\r\n <div class=\"poll-answer-percents\"></div>\r\n <div class=\"poll-answer-text\">${RichTextProcessor.wrapEmojiText(answer.text)}</div>\r\n <svg version=\"1.1\" class=\"poll-line\" style=\"display: none;\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 485.9 35\" xml:space=\"preserve\">\r\n <use href=\"#poll-line\"></use>\r\n </svg>\r\n <span class=\"poll-answer-selected tgico\"></span>\r\n </div>\r\n `;\r\n }).join('');\r\n\r\n this.innerHTML = `\r\n <div class=\"poll-title\">${poll.rQuestion}</div>\r\n <div class=\"poll-desc\">\r\n <div class=\"poll-type\"></div>\r\n <div class=\"poll-avatars\"></div>\r\n </div>\r\n ${votes}`;\r\n\r\n this.descDiv = this.firstElementChild.nextElementSibling as HTMLElement;\r\n this.typeDiv = this.descDiv.firstElementChild as HTMLElement;\r\n this.avatarsDiv = this.descDiv.lastElementChild as HTMLElement;\r\n\r\n if(descKey) {\r\n this.typeDiv.append(i18n(descKey));\r\n }\r\n\r\n if(this.isQuiz) {\r\n this.classList.add('is-quiz');\r\n\r\n if(poll.close_period && poll.close_date) {\r\n const timeLeftDiv = document.createElement('div');\r\n timeLeftDiv.classList.add('poll-time');\r\n this.descDiv.append(timeLeftDiv);\r\n\r\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n //svg.setAttributeNS(null, 'viewBox', '0 0 15 15');\r\n svg.classList.add('poll-quiz-timer');\r\n\r\n this.quizTimer = svg;\r\n\r\n const strokeWidth = 2;\r\n const radius = 7;\r\n const circumference = 2 * Math.PI * radius;\r\n\r\n const circle = document.createElementNS(\"http://www.w3.org/2000/svg\", \"circle\");\r\n circle.classList.add('poll-quiz-timer-circle');\r\n circle.setAttributeNS(null, 'cx', '16');\r\n circle.setAttributeNS(null, 'cy', '16');\r\n circle.setAttributeNS(null, 'r', '' + radius);\r\n circle.setAttributeNS(null, 'stroke-width', '' + strokeWidth);\r\n\r\n svg.append(circle);\r\n this.descDiv.append(svg);\r\n \r\n const period = poll.close_period * 1000;\r\n const closeTime = (poll.close_date - serverTimeManager.serverTimeOffset) * 1000;\r\n\r\n //console.log('closeTime:', poll.close_date, serverTimeManager.serverTimeOffset, Date.now() / 1000 | 0);\r\n\r\n // let time = Date.now();\r\n // let percents = (closeTime - time) / period;\r\n\r\n // timeLeftDiv.innerHTML = String((closeTime - time) / 1000 + 1 | 0).toHHMMSS();\r\n\r\n // // @ts-ignore\r\n // circle.style.strokeDashoffset = circumference + percents * circumference;\r\n // circle.style.strokeDasharray = ${circumference} ${circumference};\r\n\r\n this.quizInterval = window.setInterval(() => {\r\n const time = Date.now();\r\n const percents = (closeTime - time) / period;\r\n const timeLeft = (closeTime - time) / 1000 + 1 | 0;\r\n timeLeftDiv.innerHTML = String(timeLeft).toHHMMSS();\r\n \r\n if (timeLeft <= 5) {\r\n timeLeftDiv.style.color = '#ee545c';\r\n circle.style.stroke = '#ee545c';\r\n }\r\n //timeLeftDiv.style.visibility = 'visible';\r\n\r\n // @ts-ignore\r\n circle.style.strokeDashoffset = circumference + percents * circumference;\r\n circle.style.strokeDasharray = `${circumference} ${circumference}`;\r\n\r\n if(time >= closeTime) {\r\n clearInterval(this.quizInterval);\r\n timeLeftDiv.innerHTML = '';\r\n // @ts-ignore\r\n circle.style.strokeDashoffset = circumference;\r\n this.quizInterval = 0;\r\n\r\n setTimeout(() => {\r\n // нужно запросить апдейт чтобы опрос обновился\r\n appPollsManager.getResults(this.message);\r\n }, 3e3);\r\n }\r\n }, 1e3);\r\n }\r\n }\r\n \r\n this.answerDivs = Array.from(this.querySelectorAll('.poll-answer')) as HTMLDivElement[];\r\n this.svgLines = Array.from(this.querySelectorAll('.poll-line')) as SVGSVGElement[];\r\n this.numberDivs = Array.from(this.querySelectorAll('.poll-answer-percents')) as HTMLDivElement[];\r\n\r\n const footerDiv = document.createElement('div');\r\n footerDiv.classList.add('poll-footer');\r\n\r\n this.viewResults = document.createElement('div');\r\n this.viewResults.className = 'poll-footer-button poll-view-results hide';\r\n this.viewResults.append(i18n('Chat.Poll.ViewResults'));\r\n\r\n this.votersCountDiv = document.createElement('div');\r\n this.votersCountDiv.className = 'poll-votes-count';\r\n\r\n footerDiv.append(this.viewResults, this.votersCountDiv);\r\n this.append(footerDiv);\r\n\r\n this.viewResults.addEventListener('click', (e) => {\r\n cancelEvent(e);\r\n\r\n if(!appSidebarRight.isTabExists(AppPollResultsTab)) {\r\n new AppPollResultsTab(appSidebarRight).open(this.message);\r\n }\r\n });\r\n ripple(this.viewResults);\r\n\r\n if(this.isMultiple) {\r\n this.sendVoteBtn = document.createElement('div');\r\n this.sendVoteBtn.classList.add('poll-footer-button', 'poll-send-vote');\r\n this.sendVoteBtn.append(i18n('Chat.Poll.SubmitVote'));\r\n ripple(this.sendVoteBtn);\r\n\r\n if(!poll.chosenIndexes.length) {\r\n this.votersCountDiv.classList.add('hide');\r\n }\r\n\r\n attachClickEvent(this.sendVoteBtn, (e) => {\r\n cancelEvent(e);\r\n /* const indexes = this.answerDivs.filter(el => el.classList.contains('is-chosing')).map(el => +el.dataset.index);\r\n if(indexes.length) {\r\n \r\n } */\r\n if(this.chosingIndexes.length) {\r\n this.sendVotes(this.chosingIndexes).then(() => {\r\n this.chosingIndexes.length = 0;\r\n this.answerDivs.forEach(el => {\r\n el.classList.remove('is-chosing');\r\n });\r\n });\r\n }\r\n });\r\n\r\n footerDiv.append(this.sendVoteBtn);\r\n }\r\n\r\n // const width = this.getBoundingClientRect().width;\r\n // const width = mediaSizes.active.poll.width;\r\n // this.maxLength = width + tailLength + this.maxOffset + -13.7; // 13 - position left\r\n\r\n const canVote = !(poll.chosenIndexes.length || this.isClosed);\r\n if(!canVote || this.isPublic) {\r\n this.performResults(results, poll.chosenIndexes, false);\r\n }\r\n\r\n if(canVote) {\r\n this.setVotersCount(results);\r\n attachClickEvent(this, this.clickHandler);\r\n }\r\n }\r\n\r\n initQuizHint(results: PollResults) {\r\n if(results.solution && results.solution_entities) {\r\n const toggleHint = document.createElement('div');\r\n toggleHint.classList.add('tgico-tip', 'poll-hint');\r\n this.descDiv.append(toggleHint);\r\n\r\n //let active = false;\r\n attachClickEvent(toggleHint, (e) => {\r\n cancelEvent(e);\r\n\r\n //active = true;\r\n toggleHint.classList.add('active');\r\n setQuizHint(results.solution, results.solution_entities, () => {\r\n //active = false;\r\n toggleHint.classList.remove('active');\r\n });\r\n });\r\n\r\n if(this.sentVote) {\r\n const correctResult = results.results.find(r => r.pFlags.correct);\r\n if(correctResult && !correctResult.pFlags.chosen) {\r\n toggleHint.click();\r\n }\r\n }\r\n }\r\n }\r\n\r\n clickHandler(e: Event) {\r\n const target = findUpClassName(e.target, 'poll-answer') as HTMLElement;\r\n if(!target) {\r\n return;\r\n }\r\n \r\n cancelEvent(e);\r\n const answerIndex = +target.dataset.index;\r\n if(this.isMultiple) {\r\n target.classList.toggle('is-chosing');\r\n\r\n const foundIndex = this.chosingIndexes.indexOf(answerIndex);\r\n if(foundIndex !== -1) {\r\n this.chosingIndexes.splice(foundIndex, 1);\r\n } else {\r\n this.chosingIndexes.push(answerIndex);\r\n }\r\n } else {\r\n this.sendVotes([answerIndex]);\r\n }\r\n \r\n /* target.classList.add('is-voting');\r\n setTimeout(() => { // simulate\r\n this.setResults([100, 0], answerIndex);\r\n target.classList.remove('is-voting');\r\n }, 1000); */\r\n }\r\n\r\n sendVotes(indexes: number[]) {\r\n if(this.sendVotePromise) return this.sendVotePromise;\r\n\r\n const targets = this.answerDivs.filter((_, idx) => indexes.includes(idx));\r\n targets.forEach(target => {\r\n target.classList.add('is-voting');\r\n });\r\n \r\n this.classList.add('disable-hover');\r\n this.sentVote = true;\r\n return this.sendVotePromise = appPollsManager.sendVote(this.message, indexes).then(() => {\r\n targets.forEach(target => {\r\n target.classList.remove('is-voting');\r\n });\r\n\r\n this.classList.remove('disable-hover');\r\n }).catch(() => {\r\n this.sentVote = false;\r\n }).finally(() => {\r\n this.sendVotePromise = null;\r\n });\r\n }\r\n\r\n performResults(results: PollResults, chosenIndexes: number[], animate = true) {\r\n if(!rootScope.settings.animationsEnabled) {\r\n animate = false;\r\n }\r\n\r\n if(this.isQuiz && (results.results?.length || this.isClosed)) {\r\n this.answerDivs.forEach((el, idx) => {\r\n el.classList.toggle('is-correct', !!results.results[idx].pFlags.correct);\r\n });\r\n\r\n if(this.initQuizHint) {\r\n this.initQuizHint(results);\r\n this.initQuizHint = null;\r\n }\r\n\r\n if(this.quizInterval) {\r\n clearInterval(this.quizInterval);\r\n this.quizInterval = 0;\r\n }\r\n\r\n if(this.quizTimer?.parentElement) {\r\n this.quizTimer.remove();\r\n }\r\n\r\n const timeEl = this.descDiv.querySelector('.poll-time');\r\n if(timeEl) {\r\n timeEl.remove();\r\n }\r\n }\r\n\r\n if(this.isClosed) {\r\n this.classList.add('is-closed');\r\n replaceContent(this.typeDiv, i18n('Chat.Poll.Type.Closed'));\r\n }\r\n\r\n // set chosen\r\n if(this.chosenIndexes.length !== chosenIndexes.length || this.isClosed) { // if we voted\r\n this.isRetracted = this.chosenIndexes.length && !chosenIndexes.length;\r\n this.chosenIndexes = chosenIndexes.slice();\r\n\r\n if(this.isRetracted) {\r\n attachClickEvent(this, this.clickHandler);\r\n } else {\r\n detachClickEvent(this, this.clickHandler);\r\n }\r\n }\r\n \r\n // is need update\r\n if(this.chosenIndexes.length || this.isRetracted || this.isClosed) {\r\n const percents = results.results.map(v => results.total_voters ? v.voters / results.total_voters * 100 : 0);\r\n\r\n this.classList.toggle('no-transition', !animate);\r\n if(animate) {\r\n SetTransition(this, '', !this.isRetracted, 340);\r\n }\r\n\r\n fastRaf(() => {\r\n this.setResults(this.isRetracted ? this.percents : percents, this.chosenIndexes, animate);\r\n this.percents = percents;\r\n this.isRetracted = false;\r\n });\r\n }\r\n \r\n this.setVotersCount(results);\r\n\r\n if(this.isPublic) {\r\n if(!this.isMultiple) {\r\n this.viewResults.classList.toggle('hide', !results.total_voters || !this.chosenIndexes.length);\r\n this.votersCountDiv.classList.toggle('hide', !!this.chosenIndexes.length);\r\n }\r\n\r\n let html = '';\r\n /**\r\n * MACOS, ANDROID - без реверса\r\n * WINDOWS DESKTOP - реверс\r\n * все приложения накладывают аватарку первую на вторую, а в макете зато вторая на первую, ЛОЛ!\r\n */\r\n results.recent_voters/* .slice().reverse() */.forEach((userId, idx) => {\r\n const style = idx === 0 ? '' : `style=\"transform: translateX(-${idx * 3}px);\"`;\r\n html += `<avatar-element class=\"avatar-16 poll-avatar\" dialog=\"0\" peer=\"${userId}\" ${style}></avatar-element>`;\r\n });\r\n this.avatarsDiv.innerHTML = html;\r\n }\r\n\r\n if(this.isMultiple) {\r\n const isVoted = !!this.chosenIndexes.length;\r\n\r\n const hideSendVoteBtn = this.isClosed || isVoted;\r\n const hideViewResultsBtn = !this.isPublic || !results.total_voters || (!isVoted && !this.isClosed);\r\n this.sendVoteBtn.classList.toggle('hide', hideSendVoteBtn);\r\n this.viewResults.classList.toggle('hide', hideViewResultsBtn);\r\n this.votersCountDiv.classList.toggle('hide', !hideSendVoteBtn || !hideViewResultsBtn);\r\n }\r\n }\r\n\r\n setResults(percents: number[], chosenIndexes: number[], animate: boolean) {\r\n this.svgLines.forEach(svg => svg.style.display = '');\r\n\r\n this.answerDivs.forEach((el, idx) => {\r\n el.classList.toggle('is-chosen', chosenIndexes.includes(idx));\r\n });\r\n\r\n const maxValue = Math.max(...percents);\r\n // this.maxLengths = percents.map(p => p / maxValue * this.maxLength);\r\n this.maxPercents = percents.map(p => p / maxValue);\r\n\r\n // line\r\n if(this.isRetracted) {\r\n this.svgLines.forEach((svg, idx) => {\r\n this.setLineProgress(idx, -1);\r\n });\r\n } else {\r\n const cb = () => {\r\n this.svgLines.forEach((svg, idx) => {\r\n //void svg.getBoundingClientRect(); // reflow\r\n this.setLineProgress(idx, 1);\r\n });\r\n };\r\n \r\n animate ? fastRaf(cb) : cb();\r\n }\r\n\r\n percents = percents.slice();\r\n roundPercents(percents);\r\n let getPercentValue: (percents: number, index: number) => number;\r\n const iterate = (i: number) => {\r\n percents.forEach((percents, idx) => {\r\n const value = getPercentValue(percents, i);\r\n this.numberDivs[idx].innerText = value + '%';\r\n });\r\n };\r\n // numbers\r\n if(this.isRetracted) {\r\n getPercentValue = (percents, index) => Math.round(percents / times * index);\r\n\r\n if(animate) {\r\n for(let i = (times - 1), k = 0; i >= 0; --i, ++k) {\r\n setTimeout(() => {\r\n iterate(i);\r\n }, oneTime * k);\r\n }\r\n } else {\r\n iterate(0);\r\n }\r\n } else {\r\n getPercentValue = (percents, index) => Math.round(percents / times * (index + 1));\r\n\r\n if(animate) {\r\n for(let i = 0; i < times; ++i) {\r\n setTimeout(() => {\r\n iterate(i);\r\n }, oneTime * i);\r\n }\r\n } else {\r\n iterate(times - 1);\r\n }\r\n }\r\n\r\n if(this.isRetracted) {\r\n if(animate) {\r\n this.classList.add('is-retracting');\r\n }\r\n\r\n this.classList.remove('is-voted');\r\n const cb = () => {\r\n this.svgLines.forEach(svg => svg.style.display = 'none');\r\n };\r\n\r\n if(animate) {\r\n setTimeout(() => {\r\n this.classList.remove('is-retracting');\r\n cb();\r\n }, fullTime);\r\n } else {\r\n cb();\r\n }\r\n } else {\r\n this.classList.add('is-voted');\r\n }\r\n }\r\n\r\n setVotersCount(results: PollResults) {\r\n const votersCount = results.total_voters || 0;\r\n let key: LangPackKey, args = [votersCount];\r\n if(this.isClosed) {\r\n if(this.isQuiz) key = votersCount ? 'Chat.Quiz.TotalVotes' : 'Chat.Quiz.TotalVotesResultEmpty';\r\n else key = votersCount ? 'Chat.Poll.TotalVotes1' : 'Chat.Poll.TotalVotesResultEmpty';\r\n } else {\r\n if(this.isQuiz) key = votersCount ? 'Chat.Quiz.TotalVotes' : 'Chat.Quiz.TotalVotesEmpty';\r\n else key = votersCount ? 'Chat.Poll.TotalVotes1' : 'Chat.Poll.TotalVotesEmpty';\r\n }\r\n \r\n replaceContent(this.votersCountDiv, i18n(key, args));\r\n }\r\n\r\n setLineProgress(index: number, multiplier: number) {\r\n const svg = this.svgLines[index];\r\n\r\n if(multiplier === -1) {\r\n svg.style.strokeDasharray = '';\r\n svg.style.strokeDashoffset = '';\r\n } else {\r\n // svg.style.strokeDasharray = (multiplier * this.maxLengths[index]) + ', 485.9';\r\n svg.style.strokeDasharray = (multiplier * this.maxPercents[index] * PollElement.MAX_LENGTH) + ', 485.9';\r\n // svg.style.strokeDasharray = (multiplier * this.maxPercents[index] * 100) + '%, 485.9';\r\n svg.style.strokeDashoffset = '' + multiplier * PollElement.MAX_OFFSET;\r\n }\r\n }\r\n\r\n // у элемента могут быть ещё другие методы и свойства\r\n}\r\n\r\ncustomElements.define(\"poll-element\", PollElement);\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { Document, InputFileLocation, InputStickerSet, MessagesAllStickers, MessagesFeaturedStickers, MessagesFoundStickerSets, MessagesRecentStickers, MessagesStickers, MessagesStickerSet, PhotoSize, StickerPack, StickerSet, StickerSetCovered } from '../../layer';\nimport { Modify } from '../../types';\nimport apiManager from '../mtproto/mtprotoworker';\nimport rootScope from '../rootScope';\nimport appDocsManager from './appDocsManager';\nimport AppStorage from '../storage';\nimport { MOUNT_CLASS_TO } from '../../config/debug';\nimport { forEachReverse } from '../../helpers/array';\nimport DATABASE_STATE from '../../config/databases/state';\n\nconst CACHE_TIME = 3600e3;\n\nexport type MyStickerSetInput = {\n id: string,\n access_hash?: string\n};\n\nexport class AppStickersManager {\n private storage = new AppStorage<Record<string, MessagesStickerSet>, typeof DATABASE_STATE>(DATABASE_STATE, 'stickerSets');\n\n private getStickerSetPromises: {[setId: string]: Promise<MessagesStickerSet>} = {};\n private getStickersByEmoticonsPromises: {[emoticon: string]: Promise<Document[]>} = {};\n\n private greetingStickers: Document.document[];\n private getGreetingStickersTimeout: number;\n private getGreetingStickersPromise: Promise<void>;\n \n constructor() {\n this.getAnimatedEmojiStickerSet();\n\n rootScope.addMultipleEventsListeners({\n updateNewStickerSet: (update) => {\n this.saveStickerSet(update.stickerset, update.stickerset.set.id);\n rootScope.dispatchEvent('stickers_installed', update.stickerset.set);\n }\n });\n\n this.getGreetingStickersTimeout = window.setTimeout(() => {\n this.getGreetingStickersTimeout = undefined;\n this.getGreetingSticker(true);\n }, 5000);\n }\n\n public getGreetingSticker(justPreload = false) {\n if(this.getGreetingStickersTimeout) {\n clearTimeout(this.getGreetingStickersTimeout);\n this.getGreetingStickersTimeout = undefined;\n }\n\n if(!this.getGreetingStickersPromise) {\n this.getGreetingStickersPromise = this.getStickersByEmoticon('👋⭐️', false).then(docs => {\n if(!docs.length) throw 'NO_STICKERS';\n this.greetingStickers = docs.slice() as Document.document[];\n this.greetingStickers.sort((a, b) => Math.random() - Math.random());\n });\n }\n \n return this.getGreetingStickersPromise.then(() => {\n let doc: Document.document;\n if(!justPreload) {\n doc = this.greetingStickers.shift();\n this.greetingStickers.push(doc);\n }\n\n appDocsManager.downloadDoc(this.greetingStickers[0]); // preload next sticker\n\n return doc;\n });\n }\n\n public saveStickers(docs: Document[]) {\n forEachReverse(docs, (doc, idx) => {\n doc = appDocsManager.saveDoc(doc);\n\n if(!doc) docs.splice(idx, 1);\n else docs[idx] = doc;\n });\n }\n\n public async getStickerSet(set: MyStickerSetInput, params: Partial<{\n overwrite: boolean,\n useCache: boolean,\n saveById: boolean\n }> = {}): Promise<MessagesStickerSet> {\n const id = set.id;\n if(this.getStickerSetPromises[id]) {\n return this.getStickerSetPromises[id];\n }\n\n return this.getStickerSetPromises[id] = new Promise(async(resolve) => {\n if(!params.overwrite) {\n const cachedSet = await this.storage.get(id);\n if(cachedSet && cachedSet.documents?.length && ((Date.now() - cachedSet.refreshTime) < CACHE_TIME || params.useCache)) {\n this.saveStickers(cachedSet.documents);\n resolve(cachedSet);\n delete this.getStickerSetPromises[id];\n return;\n }\n }\n\n try {\n const stickerSet = await apiManager.invokeApi('messages.getStickerSet', {\n stickerset: this.getStickerSetInput(set)\n });\n \n const saveById = params.saveById ? id : stickerSet.set.id;\n this.saveStickerSet(stickerSet, saveById);\n \n resolve(stickerSet);\n } catch(err) {\n resolve(null);\n }\n \n delete this.getStickerSetPromises[id];\n });\n }\n\n public getAnimatedEmojiStickerSet() {\n return this.getStickerSet({id: 'emoji'}, {saveById: true});\n }\n\n public async getRecentStickers(): Promise<Modify<MessagesRecentStickers.messagesRecentStickers, {\n stickers: Document[]\n }>> {\n const res = await apiManager.invokeApiHashable('messages.getRecentStickers') as MessagesRecentStickers.messagesRecentStickers;\n\n this.saveStickers(res.stickers);\n\n return res;\n }\n\n public getAnimatedEmojiSticker(emoji: string) {\n const stickerSet = this.storage.getFromCache('emoji');\n if(!stickerSet || !stickerSet.documents) return undefined;\n\n emoji = emoji.replace(/\\ufe0f/g, '').replace(/🏻|🏼|🏽|🏾|🏿/g, '');\n const pack = stickerSet.packs.find(p => p.emoticon === emoji);\n return pack ? appDocsManager.getDoc(pack.documents[0]) : undefined;\n }\n\n public preloadAnimatedEmojiSticker(emoji: string) {\n return this.getAnimatedEmojiStickerSet().then(() => {\n const doc = this.getAnimatedEmojiSticker(emoji);\n if(doc) {\n return appDocsManager.downloadDoc(doc);\n }\n });\n }\n \n public saveStickerSet(res: Omit<MessagesStickerSet.messagesStickerSet, '_'>, id: string) {\n //console.log('stickers save set', res);w\n\n const newSet: MessagesStickerSet = {\n _: 'messages.stickerSet',\n set: res.set,\n packs: res.packs,\n documents: res.documents as Document[]\n };\n \n let stickerSet = this.storage.getFromCache(id);\n if(stickerSet) {\n Object.assign(stickerSet, newSet);\n } else {\n stickerSet = this.storage.setToCache(id, newSet);\n }\n\n this.saveStickers(res.documents);\n \n //console.log('stickers wrote', this.stickerSets);\n const needSave = stickerSet.set.installed_date || id === 'emoji';\n stickerSet.refreshTime = Date.now();\n this.storage.set({[id]: stickerSet}, !needSave);\n }\n\n public getStickerSetThumbDownloadOptions(stickerSet: StickerSet.stickerSet) {\n const thumb = stickerSet.thumbs.find(thumb => thumb._ === 'photoSize') as PhotoSize.photoSize;\n const dcId = stickerSet.thumb_dc_id;\n\n const isAnimated = stickerSet.pFlags?.animated;\n\n const input: InputFileLocation.inputStickerSetThumb = {\n _: 'inputStickerSetThumb',\n stickerset: this.getStickerSetInput(stickerSet),\n thumb_version: stickerSet.thumb_version\n };\n\n return {dcId, location: input, size: thumb.size, mimeType: isAnimated ? 'application/x-tgsticker' : 'image/webp'};\n }\n\n /* public getStickerSetThumbURL(stickerSet: MTStickerSet) {\n const thumb = stickerSet.thumb;\n const dcId = stickerSet.thumb_dc_id;\n\n const isAnimated = stickerSet.pFlags?.animated;\n\n const input: inputStickerSetThumb = {\n _: 'inputStickerSetThumb',\n stickerset: this.getStickerSetInput(stickerSet),\n volume_id: thumb.location.volume_id,\n local_id: thumb.location.local_id\n };\n\n const url = getFileURL('document', this.getStickerSetThumbDownloadOptions(stickerSet));\n return url;\n\n //return promise;\n } */\n\n public getStickerSetInput(set: MyStickerSetInput): InputStickerSet {\n if(set.id === 'emoji') {\n return {\n _: 'inputStickerSetAnimatedEmoji'\n };\n } else if(!set.access_hash) {\n return {\n _: 'inputStickerSetShortName',\n short_name: set.id\n };\n } else {\n return {\n _: 'inputStickerSetID',\n id: set.id,\n access_hash: set.access_hash\n };\n }\n }\n\n public async getFeaturedStickers() {\n const res = await apiManager.invokeApiHashable('messages.getFeaturedStickers') as MessagesFeaturedStickers.messagesFeaturedStickers;\n \n res.sets.forEach(covered => {\n this.saveStickerSet({set: covered.set, documents: [], packs: []}, covered.set.id);\n });\n\n return res.sets;\n }\n\n public async toggleStickerSet(set: StickerSet.stickerSet) {\n if(set.installed_date) {\n const res = await apiManager.invokeApi('messages.uninstallStickerSet', {\n stickerset: this.getStickerSetInput(set)\n });\n\n if(res) {\n delete set.installed_date;\n rootScope.dispatchEvent('stickers_deleted', set);\n this.storage.delete(set.id, true);\n return true;\n }\n } else {\n const res = await apiManager.invokeApi('messages.installStickerSet', {\n stickerset: this.getStickerSetInput(set),\n archived: false\n });\n\n if(res) {\n set.installed_date = Date.now() / 1000 | 0;\n rootScope.dispatchEvent('stickers_installed', set);\n return true;\n }\n }\n\n return false;\n }\n\n public async searchStickerSets(query: string, excludeFeatured = true) {\n const flags = excludeFeatured ? 1 : 0;\n const res = await apiManager.invokeApiHashable('messages.searchStickerSets', {\n flags,\n exclude_featured: excludeFeatured || undefined,\n q: query\n }) as MessagesFoundStickerSets.messagesFoundStickerSets;\n\n res.sets.forEach(covered => {\n this.saveStickerSet({set: covered.set, documents: [], packs: []}, covered.set.id);\n });\n\n const foundSaved: StickerSetCovered[] = [];\n const cache = this.storage.getCache();\n for(let id in cache) {\n const {set} = cache[id];\n\n if(set.title.toLowerCase().includes(query.toLowerCase()) && !res.sets.find(c => c.set.id === set.id)) {\n foundSaved.push({_: 'stickerSetCovered', set, cover: null});\n }\n }\n\n return res.sets.concat(foundSaved);\n }\n\n public getAllStickers() {\n return apiManager.invokeApiHashable('messages.getAllStickers');\n }\n\n public preloadStickerSets() {\n return this.getAllStickers().then(allStickers => {\n return Promise.all((allStickers as MessagesAllStickers.messagesAllStickers).sets.map(set => this.getStickerSet(set, {useCache: true})));\n });\n }\n\n public getStickersByEmoticon(emoticon: string, includeOurStickers = true) {\n if(this.getStickersByEmoticonsPromises[emoticon]) return this.getStickersByEmoticonsPromises[emoticon];\n\n return this.getStickersByEmoticonsPromises[emoticon] = Promise.all([\n apiManager.invokeApiHashable('messages.getStickers', {\n emoticon\n }),\n includeOurStickers ? this.preloadStickerSets() : [],\n includeOurStickers ? this.getRecentStickers().then(res => res.packs) : []\n ]).then(([messagesStickers, installedSets, recentStickers]) => {\n const foundStickers = (messagesStickers as MessagesStickers.messagesStickers).stickers.map(sticker => appDocsManager.saveDoc(sticker));\n const cachedStickersAnimated: Document.document[] = [], cachedStickersStatic: Document.document[] = [];\n\n //console.log('getStickersByEmoticon', messagesStickers, installedSets, recentStickers);\n\n const iteratePacks = (packs: StickerPack.stickerPack[]) => {\n for(const pack of packs) {\n if(pack.emoticon.includes(emoticon)) {\n for(const docId of pack.documents) {\n const doc = appDocsManager.getDoc(docId);\n (doc.animated ? cachedStickersAnimated : cachedStickersStatic).push(doc);\n }\n }\n }\n };\n\n iteratePacks(recentStickers);\n\n for(const set of installedSets) {\n iteratePacks(set.packs);\n }\n\n const stickers = [...new Set(cachedStickersAnimated.concat(cachedStickersStatic, foundStickers))]/* .filter(doc => !doc.animated) */;\n\n return stickers;\n });\n }\n}\n\nconst appStickersManager = new AppStickersManager();\nMOUNT_CLASS_TO.appStickersManager = appStickersManager;\nexport default appStickersManager;\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type Chat from './chat/chat';\r\nimport { getEmojiToneIndex } from '../vendor/emoji';\r\nimport { readBlobAsText } from '../helpers/blob';\r\nimport { deferredPromise } from '../helpers/cancellablePromise';\r\nimport { formatFullSentTime } from '../helpers/date';\r\nimport mediaSizes, { ScreenSize } from '../helpers/mediaSizes';\r\nimport { formatBytes } from '../helpers/number';\r\nimport { IS_SAFARI } from '../environment/userAgent';\r\nimport { Message, PhotoSize, StickerSet } from '../layer';\r\nimport appDocsManager, { MyDocument } from \"../lib/appManagers/appDocsManager\";\r\nimport appMessagesManager from '../lib/appManagers/appMessagesManager';\r\nimport appPhotosManager, { MyPhoto } from '../lib/appManagers/appPhotosManager';\r\nimport LottieLoader from '../lib/lottieLoader';\r\nimport webpWorkerController from '../lib/webp/webpWorkerController';\r\nimport animationIntersector from './animationIntersector';\r\nimport appMediaPlaybackController, { MediaSearchContext } from './appMediaPlaybackController';\r\nimport AudioElement, { findAudioTargets as findMediaTargets } from './audio';\r\nimport ReplyContainer from './chat/replyContainer';\r\nimport { Layouter, RectPart } from './groupedLayout';\r\nimport LazyLoadQueue from './lazyLoadQueue';\r\nimport PollElement from './poll';\r\nimport ProgressivePreloader from './preloader';\r\nimport './middleEllipsis';\r\nimport RichTextProcessor from '../lib/richtextprocessor';\r\nimport appImManager from '../lib/appManagers/appImManager';\r\nimport { SearchSuperContext } from './appSearchSuper.';\r\nimport rootScope from '../lib/rootScope';\r\nimport { onMediaLoad } from '../helpers/files';\r\nimport { animateSingle } from '../helpers/animation';\r\nimport renderImageFromUrl from '../helpers/dom/renderImageFromUrl';\r\nimport sequentialDom from '../helpers/sequentialDom';\r\nimport { fastRaf } from '../helpers/schedulers';\r\nimport appDownloadManager, { DownloadBlob, ThumbCache } from '../lib/appManagers/appDownloadManager';\r\nimport appStickersManager from '../lib/appManagers/appStickersManager';\r\nimport { cancelEvent } from '../helpers/dom/cancelEvent';\r\nimport { attachClickEvent, simulateClickEvent } from '../helpers/dom/clickEvent';\r\nimport isInDOM from '../helpers/dom/isInDOM';\r\nimport lottieLoader from '../lib/lottieLoader';\r\nimport { clearBadCharsAndTrim } from '../helpers/cleanSearchText';\r\nimport blur from '../helpers/blur';\r\nimport IS_WEBP_SUPPORTED from '../environment/webpSupport';\r\nimport MEDIA_MIME_TYPES_SUPPORTED from '../environment/mediaMimeTypesSupport';\r\nimport { MiddleEllipsisElement } from './middleEllipsis';\r\nimport { joinElementsWith } from '../lib/langPack';\r\nimport throttleWithRaf from '../helpers/schedulers/throttleWithRaf';\r\n\r\nconst MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB\r\n\r\nlet roundVideoCircumference = 0;\r\nmediaSizes.addEventListener('changeScreen', (from, to) => {\r\n if(to === ScreenSize.mobile || from === ScreenSize.mobile) {\r\n const elements = Array.from(document.querySelectorAll('.media-round .progress-ring')) as SVGSVGElement[];\r\n const width = mediaSizes.active.round.width;\r\n const halfSize = width / 2;\r\n const radius = halfSize - 7;\r\n roundVideoCircumference = 2 * Math.PI * radius;\r\n elements.forEach(element => {\r\n element.setAttributeNS(null, 'width', '' + width);\r\n element.setAttributeNS(null, 'height', '' + width);\r\n\r\n const circle = element.firstElementChild as SVGCircleElement;\r\n circle.setAttributeNS(null, 'cx', '' + halfSize);\r\n circle.setAttributeNS(null, 'cy', '' + halfSize);\r\n circle.setAttributeNS(null, 'r', '' + radius);\r\n\r\n circle.style.strokeDasharray = roundVideoCircumference + ' ' + roundVideoCircumference;\r\n circle.style.strokeDashoffset = '' + roundVideoCircumference;\r\n });\r\n }\r\n});\r\n\r\nexport function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group, onlyPreview, withoutPreloader, loadPromises, noPlayButton, noAutoDownload, size, searchContext}: {\r\n doc: MyDocument, \r\n container?: HTMLElement, \r\n message?: Message.message, \r\n boxWidth?: number, \r\n boxHeight?: number, \r\n withTail?: boolean, \r\n isOut?: boolean,\r\n middleware?: () => boolean,\r\n lazyLoadQueue?: LazyLoadQueue,\r\n noInfo?: true,\r\n noPlayButton?: boolean,\r\n group?: string,\r\n onlyPreview?: boolean,\r\n withoutPreloader?: boolean,\r\n loadPromises?: Promise<any>[],\r\n noAutoDownload?: boolean,\r\n size?: PhotoSize,\r\n searchContext?: MediaSearchContext,\r\n}) {\r\n const isAlbumItem = !(boxWidth && boxHeight);\r\n const canAutoplay = (doc.type !== 'video' || (doc.size <= MAX_VIDEO_AUTOPLAY_SIZE && !isAlbumItem)) \r\n && (doc.type === 'gif' ? rootScope.settings.autoPlay.gifs : rootScope.settings.autoPlay.videos);\r\n let spanTime: HTMLElement, spanPlay: HTMLElement;\r\n\r\n if(!noInfo) {\r\n spanTime = document.createElement('span');\r\n spanTime.classList.add('video-time');\r\n container.append(spanTime);\r\n \r\n let needPlayButton = false;\r\n if(doc.type !== 'gif') {\r\n spanTime.innerText = (doc.duration + '').toHHMMSS(false);\r\n\r\n if(!noPlayButton && doc.type !== 'round') {\r\n if(canAutoplay && !noAutoDownload) {\r\n spanTime.classList.add('tgico', 'can-autoplay');\r\n } else {\r\n needPlayButton = true;\r\n }\r\n }\r\n } else {\r\n spanTime.innerText = 'GIF';\r\n\r\n if(!canAutoplay && !noPlayButton) {\r\n needPlayButton = true;\r\n noAutoDownload = undefined;\r\n }\r\n }\r\n\r\n if(needPlayButton) {\r\n spanPlay = document.createElement('span');\r\n spanPlay.classList.add('video-play', 'tgico-largeplay', 'btn-circle', 'position-center');\r\n container.append(spanPlay);\r\n }\r\n }\r\n\r\n let res: {\r\n thumb?: typeof photoRes,\r\n loadPromise: Promise<any>\r\n } = {} as any;\r\n\r\n if(doc.mime_type === 'image/gif') {\r\n const photoRes = wrapPhoto({\r\n photo: doc, \r\n message, \r\n container, \r\n boxWidth, \r\n boxHeight, \r\n withTail, \r\n isOut, \r\n lazyLoadQueue, \r\n middleware,\r\n withoutPreloader,\r\n loadPromises,\r\n noAutoDownload,\r\n size\r\n });\r\n\r\n res.thumb = photoRes;\r\n res.loadPromise = photoRes.loadPromises.full;\r\n return res;\r\n }\r\n\r\n /* const video = doc.type === 'round' ? appMediaPlaybackController.addMedia(doc, message.mid) as HTMLVideoElement : document.createElement('video');\r\n if(video.parentElement) {\r\n video.remove();\r\n } */\r\n\r\n const video = document.createElement('video');\r\n video.classList.add('media-video');\r\n video.setAttribute('playsinline', 'true');\r\n video.muted = true;\r\n if(doc.type === 'round') {\r\n const divRound = document.createElement('div');\r\n divRound.classList.add('media-round', 'z-depth-1');\r\n divRound.dataset.mid = '' + message.mid;\r\n divRound.dataset.peerId = '' + message.peerId;\r\n (divRound as any).message = message;\r\n\r\n const size = mediaSizes.active.round;\r\n const halfSize = size.width / 2;\r\n const strokeWidth = 3.5;\r\n const radius = halfSize - (strokeWidth * 2);\r\n divRound.innerHTML = `<svg class=\"progress-ring\" width=\"${size.width}\" height=\"${size.width}\" style=\"transform: rotate(-90deg);\">\r\n <circle class=\"progress-ring__circle\" stroke=\"white\" stroke-opacity=\"0.3\" stroke-width=\"${strokeWidth}\" cx=\"${halfSize}\" cy=\"${halfSize}\" r=\"${radius}\" fill=\"transparent\"/>\r\n </svg>`;\r\n\r\n const circle = divRound.firstElementChild.firstElementChild as SVGCircleElement;\r\n if(!roundVideoCircumference) {\r\n roundVideoCircumference = 2 * Math.PI * radius;\r\n }\r\n circle.style.strokeDasharray = roundVideoCircumference + ' ' + roundVideoCircumference;\r\n circle.style.strokeDashoffset = '' + roundVideoCircumference;\r\n \r\n spanTime.classList.add('tgico');\r\n\r\n const isUnread = message.pFlags.media_unread;\r\n if(isUnread) {\r\n divRound.classList.add('is-unread');\r\n }\r\n\r\n const canvas = document.createElement('canvas');\r\n canvas.width = canvas.height = doc.w/* * window.devicePixelRatio */;\r\n\r\n divRound.prepend(canvas, spanTime);\r\n divRound.append(video);\r\n container.append(divRound);\r\n\r\n const ctx = canvas.getContext('2d');\r\n /* ctx.beginPath();\r\n ctx.arc(canvas.width / 2, canvas.height / 2, canvas.width / 2, 0, Math.PI * 2);\r\n ctx.clip(); */\r\n\r\n const onLoad = () => {\r\n const message: Message.message = (divRound as any).message;\r\n const globalVideo = appMediaPlaybackController.addMedia(message, !noAutoDownload) as HTMLVideoElement;\r\n const clear = () => {\r\n (appImManager.chat.setPeerPromise || Promise.resolve()).finally(() => {\r\n if(isInDOM(globalVideo)) {\r\n return;\r\n }\r\n \r\n globalVideo.removeEventListener('play', onPlay);\r\n globalVideo.removeEventListener('timeupdate', throttledTimeUpdate);\r\n globalVideo.removeEventListener('pause', onPaused);\r\n globalVideo.removeEventListener('ended', onEnded);\r\n });\r\n };\r\n \r\n const onFrame = () => {\r\n ctx.drawImage(globalVideo, 0, 0);\r\n \r\n const offset = roundVideoCircumference - globalVideo.currentTime / globalVideo.duration * roundVideoCircumference;\r\n circle.style.strokeDashoffset = '' + offset;\r\n \r\n return !globalVideo.paused;\r\n };\r\n\r\n const onTimeUpdate = () => {\r\n if(!globalVideo.duration) {\r\n return;\r\n }\r\n \r\n if(!isInDOM(globalVideo)) {\r\n clear();\r\n return;\r\n }\r\n\r\n if(globalVideo.paused) {\r\n onFrame();\r\n }\r\n \r\n spanTime.innerText = (globalVideo.duration - globalVideo.currentTime + '').toHHMMSS(false);\r\n };\r\n\r\n const throttledTimeUpdate = throttleWithRaf(onTimeUpdate);\r\n \r\n const onPlay = () => {\r\n video.classList.add('hide');\r\n divRound.classList.remove('is-paused');\r\n animateSingle(onFrame, canvas);\r\n \r\n if(preloader && preloader.preloader && preloader.preloader.classList.contains('manual')) {\r\n preloader.onClick();\r\n }\r\n };\r\n \r\n const onPaused = () => {\r\n if(!isInDOM(globalVideo)) {\r\n clear();\r\n return;\r\n }\r\n \r\n divRound.classList.add('is-paused');\r\n };\r\n \r\n const onEnded = () => {\r\n video.classList.remove('hide');\r\n divRound.classList.add('is-paused');\r\n \r\n video.currentTime = 0;\r\n spanTime.innerText = ('' + globalVideo.duration).toHHMMSS(false);\r\n \r\n if(globalVideo.currentTime) {\r\n globalVideo.currentTime = 0;\r\n }\r\n };\r\n \r\n globalVideo.addEventListener('play', onPlay);\r\n globalVideo.addEventListener('timeupdate', throttledTimeUpdate);\r\n globalVideo.addEventListener('pause', onPaused);\r\n globalVideo.addEventListener('ended', onEnded);\r\n \r\n attachClickEvent(canvas, (e) => {\r\n cancelEvent(e);\r\n \r\n // ! костыль\r\n if(preloader && !preloader.detached) {\r\n preloader.onClick();\r\n }\r\n \r\n // ! can't use it here. on Safari iOS video won't start.\r\n /* if(globalVideo.readyState < 2) {\r\n return;\r\n } */\r\n \r\n if(globalVideo.paused) {\r\n if(appMediaPlaybackController.setSearchContext(searchContext)) {\r\n const [prev, next] = findMediaTargets(divRound, searchContext.useSearch);\r\n appMediaPlaybackController.setTargets({peerId: message.peerId, mid: message.mid}, prev, next);\r\n }\r\n \r\n globalVideo.play();\r\n } else {\r\n globalVideo.pause();\r\n }\r\n });\r\n \r\n if(globalVideo.paused) {\r\n if(globalVideo.duration && globalVideo.currentTime !== globalVideo.duration && globalVideo.currentTime > 0) {\r\n onFrame();\r\n onTimeUpdate();\r\n video.classList.add('hide');\r\n } else {\r\n onPaused();\r\n }\r\n } else {\r\n onPlay();\r\n }\r\n };\r\n\r\n if(message.pFlags.is_outgoing) {\r\n (divRound as any).onLoad = onLoad;\r\n divRound.dataset.isOutgoing = '1';\r\n } else {\r\n onLoad();\r\n }\r\n } else {\r\n video.autoplay = true; // для safari\r\n }\r\n\r\n let photoRes: ReturnType<typeof wrapPhoto>;\r\n if(message) {\r\n photoRes = wrapPhoto({\r\n photo: doc, \r\n message, \r\n container, \r\n boxWidth, \r\n boxHeight, \r\n withTail, \r\n isOut, \r\n lazyLoadQueue, \r\n middleware,\r\n withoutPreloader: true,\r\n loadPromises,\r\n noAutoDownload,\r\n size\r\n });\r\n\r\n res.thumb = photoRes;\r\n\r\n if((!canAutoplay && doc.type !== 'gif') || onlyPreview) {\r\n res.loadPromise = photoRes.loadPromises.full;\r\n return res;\r\n }\r\n\r\n if(withTail) {\r\n const foreignObject = (photoRes.images.thumb || photoRes.images.full).parentElement;\r\n video.width = +foreignObject.getAttributeNS(null, 'width');\r\n video.height = +foreignObject.getAttributeNS(null, 'height');\r\n foreignObject.append(video);\r\n }\r\n } else { // * gifs masonry\r\n const gotThumb = appDocsManager.getThumb(doc, false);\r\n if(gotThumb) {\r\n gotThumb.promise.then(() => {\r\n video.poster = gotThumb.cacheContext.url;\r\n });\r\n }\r\n }\r\n\r\n if(!video.parentElement && container) {\r\n (photoRes?.aspecter || container).append(video);\r\n }\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n\r\n const isUpload = !!(message?.media as any)?.preloader;\r\n let preloader: ProgressivePreloader;\r\n if(isUpload) { // means upload\r\n preloader = (message.media as any).preloader as ProgressivePreloader;\r\n preloader.attach(container, false);\r\n noAutoDownload = undefined;\r\n } else if(!cacheContext.downloaded && !doc.supportsStreaming) {\r\n preloader = new ProgressivePreloader({\r\n attachMethod: 'prepend'\r\n });\r\n } else if(doc.supportsStreaming) {\r\n preloader = new ProgressivePreloader({\r\n cancelable: false,\r\n attachMethod: 'prepend'\r\n });\r\n }\r\n\r\n const renderDeferred = deferredPromise<void>();\r\n video.addEventListener('error', (e) => {\r\n if(video.error.code !== 4) {\r\n console.error(\"Error \" + video.error.code + \"; details: \" + video.error.message);\r\n }\r\n \r\n if(preloader && !isUpload) {\r\n preloader.detach();\r\n }\r\n\r\n if(!renderDeferred.isFulfilled) {\r\n renderDeferred.resolve();\r\n }\r\n }, {once: true});\r\n\r\n onMediaLoad(video).then(() => {\r\n if(group) {\r\n animationIntersector.addAnimation(video, group);\r\n }\r\n\r\n if(preloader && !isUpload) {\r\n preloader.detach();\r\n }\r\n\r\n renderDeferred.resolve();\r\n });\r\n\r\n if(doc.type === 'video') {\r\n video.addEventListener('timeupdate', () => {\r\n spanTime.innerText = (video.duration - video.currentTime + '').toHHMMSS(false);\r\n });\r\n }\r\n\r\n video.muted = true;\r\n video.loop = true;\r\n //video.play();\r\n video.autoplay = true;\r\n\r\n let loadPhotoThumbFunc = noAutoDownload && photoRes?.preloader?.loadFunc;\r\n const load = () => {\r\n if(preloader && noAutoDownload && !withoutPreloader) {\r\n preloader.construct();\r\n preloader.setManual();\r\n }\r\n\r\n let loadPromise: Promise<any> = Promise.resolve();\r\n if(preloader && !isUpload) {\r\n if(!cacheContext.downloaded && !doc.supportsStreaming) {\r\n const promise = loadPromise = appDocsManager.downloadDoc(doc, lazyLoadQueue?.queueId, noAutoDownload);\r\n preloader.attach(container, false, promise);\r\n } else if(doc.supportsStreaming) {\r\n if(noAutoDownload) {\r\n loadPromise = Promise.reject();\r\n } else if(!cacheContext.downloaded) { // * check for uploading video\r\n preloader.attach(container, false, null);\r\n video.addEventListener(IS_SAFARI ? 'timeupdate' : 'canplay', () => {\r\n preloader.detach();\r\n }, {once: true});\r\n }\r\n }\r\n }\r\n\r\n if(!noAutoDownload && loadPhotoThumbFunc) {\r\n loadPhotoThumbFunc();\r\n loadPhotoThumbFunc = null;\r\n }\r\n\r\n noAutoDownload = undefined;\r\n\r\n loadPromise.then(() => {\r\n if(middleware && !middleware()) {\r\n renderDeferred.resolve();\r\n return;\r\n }\r\n\r\n if(doc.type === 'round') {\r\n appMediaPlaybackController.resolveWaitingForLoadMedia(message.peerId, message.mid, message.pFlags.is_scheduled);\r\n }\r\n\r\n renderImageFromUrl(video, cacheContext.url);\r\n }, () => {});\r\n\r\n return {download: loadPromise, render: renderDeferred};\r\n };\r\n\r\n if(preloader && !isUpload) {\r\n preloader.setDownloadFunction(load);\r\n }\r\n\r\n /* if(doc.size >= 20e6 && !doc.downloaded) {\r\n let downloadDiv = document.createElement('div');\r\n downloadDiv.classList.add('download');\r\n\r\n let span = document.createElement('span');\r\n span.classList.add('btn-circle', 'tgico-download');\r\n downloadDiv.append(span);\r\n\r\n downloadDiv.addEventListener('click', () => {\r\n downloadDiv.remove();\r\n loadVideo();\r\n });\r\n\r\n container.prepend(downloadDiv);\r\n\r\n return;\r\n } */\r\n\r\n if(doc.type === 'gif' && !canAutoplay) {\r\n attachClickEvent(container, (e) => {\r\n cancelEvent(e);\r\n spanPlay.remove();\r\n load();\r\n }, {capture: true, once: true});\r\n } else {\r\n res.loadPromise = !lazyLoadQueue ? load().render : (lazyLoadQueue.push({div: container, load: () => load().render}), Promise.resolve());\r\n }\r\n\r\n return res;\r\n}\r\n\r\nrootScope.addEventListener('download_start', (docId) => {\r\n const elements = Array.from(document.querySelectorAll(`.document[data-doc-id=\"${docId}\"]`)) as HTMLElement[];\r\n elements.forEach(element => {\r\n if(element.querySelector('.preloader-container.manual')) {\r\n simulateClickEvent(element);\r\n }\r\n });\r\n});\r\n\r\nexport function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showSender, searchContext, loadPromises, noAutoDownload, lazyLoadQueue}: {\r\n message: any, \r\n withTime?: boolean,\r\n fontWeight?: number,\r\n voiceAsMusic?: boolean,\r\n showSender?: boolean,\r\n searchContext?: MediaSearchContext,\r\n loadPromises?: Promise<any>[],\r\n noAutoDownload?: boolean,\r\n lazyLoadQueue?: LazyLoadQueue\r\n}): HTMLElement {\r\n if(!fontWeight) fontWeight = 500;\r\n\r\n const doc = (message.media.document || message.media.webpage.document) as MyDocument;\r\n const uploading = message.pFlags.is_outgoing && message.media?.preloader;\r\n if(doc.type === 'audio' || doc.type === 'voice' || doc.type === 'round') {\r\n const audioElement = new AudioElement();\r\n audioElement.withTime = withTime;\r\n audioElement.message = message;\r\n audioElement.noAutoDownload = noAutoDownload;\r\n audioElement.lazyLoadQueue = lazyLoadQueue;\r\n audioElement.loadPromises = loadPromises;\r\n \r\n if(voiceAsMusic) audioElement.voiceAsMusic = voiceAsMusic;\r\n if(searchContext) audioElement.searchContext = searchContext;\r\n if(showSender) audioElement.showSender = showSender;\r\n if(uploading) audioElement.preloader = message.media.preloader;\r\n\r\n audioElement.dataset.fontWeight = '' + fontWeight;\r\n audioElement.render();\r\n return audioElement;\r\n }\r\n\r\n let extSplitted = doc.file_name ? doc.file_name.split('.') : '';\r\n let ext = '';\r\n ext = extSplitted.length > 1 && Array.isArray(extSplitted) ? \r\n clearBadCharsAndTrim(extSplitted.pop().split(' ', 1)[0].toLowerCase()) : \r\n 'file';\r\n\r\n let docDiv = document.createElement('div');\r\n docDiv.classList.add('document', `ext-${ext}`);\r\n docDiv.dataset.docId = doc.id;\r\n\r\n const icoDiv = document.createElement('div');\r\n icoDiv.classList.add('document-ico');\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n if((doc.thumbs?.length || (message.pFlags.is_outgoing && cacheContext.url && doc.type === 'photo')) && doc.mime_type !== 'image/gif') {\r\n docDiv.classList.add('document-with-thumb');\r\n\r\n let imgs: HTMLImageElement[] = [];\r\n if(message.pFlags.is_outgoing) {\r\n icoDiv.innerHTML = `<img src=\"${cacheContext.url}\">`;\r\n imgs.push(icoDiv.firstElementChild as HTMLImageElement);\r\n } else {\r\n const wrapped = wrapPhoto({\r\n photo: doc, \r\n message: null, \r\n container: icoDiv, \r\n boxWidth: 54, \r\n boxHeight: 54,\r\n loadPromises,\r\n withoutPreloader: true,\r\n lazyLoadQueue\r\n });\r\n icoDiv.style.width = icoDiv.style.height = '';\r\n if(wrapped.images.thumb) imgs.push(wrapped.images.thumb);\r\n if(wrapped.images.full) imgs.push(wrapped.images.full);\r\n }\r\n\r\n imgs.forEach(img => img.classList.add('document-thumb'));\r\n } else {\r\n icoDiv.innerText = ext;\r\n }\r\n\r\n //let fileName = stringMiddleOverflow(doc.file_name || 'Unknown.file', 26);\r\n let fileName = doc.fileName || 'Unknown.file';\r\n const descriptionEl = document.createElement('div');\r\n descriptionEl.classList.add('document-description');\r\n const descriptionParts: (HTMLElement | string | DocumentFragment)[] = [formatBytes(doc.size)];\r\n \r\n if(withTime) {\r\n descriptionParts.push(formatFullSentTime(message.date));\r\n }\r\n\r\n if(showSender) {\r\n descriptionParts.push(appMessagesManager.wrapSenderToPeer(message));\r\n }\r\n\r\n docDiv.innerHTML = `\r\n ${cacheContext.downloaded && !uploading ? '' : `<div class=\"document-download\"></div>`}\r\n <div class=\"document-name\"></div>\r\n <div class=\"document-size\"></div>\r\n `;\r\n\r\n const nameDiv = docDiv.querySelector('.document-name') as HTMLElement;\r\n const middleEllipsisEl = new MiddleEllipsisElement();\r\n middleEllipsisEl.dataset.fontWeight = '' + fontWeight;\r\n middleEllipsisEl.innerHTML = fileName;\r\n\r\n nameDiv.append(middleEllipsisEl);\r\n\r\n if(showSender) {\r\n nameDiv.append(appMessagesManager.wrapSentTime(message));\r\n }\r\n\r\n const sizeDiv = docDiv.querySelector('.document-size') as HTMLElement;\r\n sizeDiv.append(...joinElementsWith(descriptionParts, ' · '));\r\n\r\n docDiv.prepend(icoDiv);\r\n\r\n if(!uploading && message.pFlags.is_outgoing) {\r\n return docDiv;\r\n }\r\n\r\n let downloadDiv: HTMLElement, preloader: ProgressivePreloader = null;\r\n const onLoad = () => {\r\n if(downloadDiv) {\r\n downloadDiv.classList.add('downloaded');\r\n const _downloadDiv = downloadDiv;\r\n setTimeout(() => {\r\n _downloadDiv.remove();\r\n }, 200);\r\n downloadDiv = null;\r\n }\r\n\r\n if(preloader) {\r\n preloader = null;\r\n }\r\n };\r\n\r\n const load = (e: Event) => {\r\n const save = !e || e.isTrusted;\r\n const doc = appDocsManager.getDoc(docDiv.dataset.docId);\r\n let download: DownloadBlob;\r\n const queueId = appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : undefined;\r\n if(!save) {\r\n download = appDocsManager.downloadDoc(doc, queueId);\r\n } else if(doc.type === 'pdf') {\r\n download = appDocsManager.downloadDoc(doc, queueId);\r\n download.then(() => {\r\n setTimeout(() => { // wait for preloader animation end\r\n const url = appDownloadManager.getCacheContext(doc).url;\r\n window.open(url);\r\n }, rootScope.settings.animationsEnabled ? 250 : 0);\r\n });\r\n } else if(MEDIA_MIME_TYPES_SUPPORTED.has(doc.mime_type) && doc.thumbs?.length) {\r\n download = appDocsManager.downloadDoc(doc, queueId);\r\n } else {\r\n download = appDocsManager.saveDocFile(doc, queueId);\r\n }\r\n\r\n if(downloadDiv) {\r\n download.then(onLoad);\r\n preloader.attach(downloadDiv, true, download);\r\n }\r\n\r\n return {download};\r\n };\r\n\r\n if(appDocsManager.downloading.has(doc.id)) {\r\n downloadDiv = docDiv.querySelector('.document-download');\r\n preloader = new ProgressivePreloader();\r\n preloader.attach(downloadDiv, false, appDocsManager.downloading.get(doc.id));\r\n } else if(!(cacheContext.downloaded && !uploading)) {\r\n downloadDiv = docDiv.querySelector('.document-download');\r\n preloader = message.media.preloader as ProgressivePreloader;\r\n\r\n if(!preloader) {\r\n preloader = new ProgressivePreloader();\r\n\r\n preloader.construct();\r\n preloader.setManual();\r\n preloader.attach(downloadDiv);\r\n preloader.setDownloadFunction(load);\r\n } else {\r\n preloader.attach(downloadDiv);\r\n message.media.promise.then(onLoad);\r\n }\r\n }\r\n\r\n attachClickEvent(docDiv, (e) => {\r\n if(preloader) {\r\n preloader.onClick(e);\r\n } else {\r\n load(e);\r\n }\r\n });\r\n \r\n return docDiv;\r\n}\r\n\r\n/* function wrapMediaWithTail(photo: MyPhoto | MyDocument, message: {mid: number, message: string}, container: HTMLElement, boxWidth: number, boxHeight: number, isOut: boolean) {\r\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n svg.classList.add('bubble__media-container', isOut ? 'is-out' : 'is-in');\r\n \r\n const foreignObject = document.createElementNS(\"http://www.w3.org/2000/svg\", 'foreignObject');\r\n\r\n const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(photo, true);\r\n if(gotThumb) {\r\n foreignObject.append(gotThumb.image);\r\n }\r\n appPhotosManager.setAttachmentSize(photo, foreignObject, boxWidth, boxHeight);\r\n \r\n const width = +foreignObject.getAttributeNS(null, 'width');\r\n const height = +foreignObject.getAttributeNS(null, 'height');\r\n\r\n svg.setAttributeNS(null, 'width', '' + width);\r\n svg.setAttributeNS(null, 'height', '' + height);\r\n\r\n svg.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height);\r\n svg.setAttributeNS(null, 'preserveAspectRatio', 'none');\r\n\r\n const clipId = 'clip' + message.mid + '_' + nextRandomInt(9999);\r\n svg.dataset.clipId = clipId;\r\n \r\n const defs = document.createElementNS(\"http://www.w3.org/2000/svg\", 'defs');\r\n let clipPathHTML: string = '';\r\n \r\n if(message.message) {\r\n //clipPathHTML += `<rect width=\"${width}\" height=\"${height}\"></rect>`;\r\n } else {\r\n if(isOut) {\r\n clipPathHTML += `\r\n <use href=\"#message-tail\" transform=\"translate(${width - 2}, ${height}) scale(-1, -1)\"></use>\r\n <path />\r\n `;\r\n } else {\r\n clipPathHTML += `\r\n <use href=\"#message-tail\" transform=\"translate(2, ${height}) scale(1, -1)\"></use>\r\n <path />\r\n `;\r\n }\r\n }\r\n\r\n defs.innerHTML = `<clipPath id=\"${clipId}\">${clipPathHTML}</clipPath>`;\r\n \r\n container.style.width = parseInt(container.style.width) - 9 + 'px';\r\n container.classList.add('with-tail');\r\n\r\n svg.append(defs, foreignObject);\r\n container.append(svg);\r\n\r\n let img = foreignObject.firstElementChild as HTMLImageElement;\r\n if(!img) {\r\n foreignObject.append(img = new Image());\r\n }\r\n\r\n return img;\r\n} */\r\n\r\nexport function wrapPhoto({photo, message, container, boxWidth, boxHeight, withTail, isOut, lazyLoadQueue, middleware, size, withoutPreloader, loadPromises, noAutoDownload, noBlur, noThumb, noFadeIn, blurAfter}: {\r\n photo: MyPhoto | MyDocument, \r\n message?: any, \r\n container: HTMLElement, \r\n boxWidth?: number, \r\n boxHeight?: number, \r\n withTail?: boolean, \r\n isOut?: boolean, \r\n lazyLoadQueue?: LazyLoadQueue, \r\n middleware?: () => boolean, \r\n size?: PhotoSize,\r\n withoutPreloader?: boolean,\r\n loadPromises?: Promise<any>[],\r\n noAutoDownload?: boolean,\r\n noBlur?: boolean,\r\n noThumb?: boolean,\r\n noFadeIn?: boolean,\r\n blurAfter?: boolean,\r\n}) {\r\n if(!((photo as MyPhoto).sizes || (photo as MyDocument).thumbs)) {\r\n if(boxWidth && boxHeight && !size && photo._ === 'document') {\r\n appPhotosManager.setAttachmentSize(photo, container, boxWidth, boxHeight, undefined, message);\r\n }\r\n\r\n return {\r\n loadPromises: {\r\n thumb: Promise.resolve(),\r\n full: Promise.resolve()\r\n },\r\n images: {\r\n thumb: null,\r\n full: null\r\n },\r\n preloader: null,\r\n aspecter: null\r\n };\r\n }\r\n\r\n if(!size) {\r\n if(boxWidth === undefined) boxWidth = mediaSizes.active.regular.width;\r\n if(boxHeight === undefined) boxHeight = mediaSizes.active.regular.height;\r\n }\r\n\r\n container.classList.add('media-container');\r\n let aspecter = container;\r\n\r\n let isFit = true;\r\n let loadThumbPromise: Promise<any> = Promise.resolve();\r\n let thumbImage: HTMLImageElement;\r\n let image: HTMLImageElement;\r\n let cacheContext: ThumbCache;\r\n // if(withTail) {\r\n // image = wrapMediaWithTail(photo, message, container, boxWidth, boxHeight, isOut);\r\n // } else {\r\n image = new Image();\r\n\r\n if(boxWidth && boxHeight && !size) { // !album\r\n const set = appPhotosManager.setAttachmentSize(photo, container, boxWidth, boxHeight, undefined, message);\r\n size = set.photoSize;\r\n isFit = set.isFit;\r\n cacheContext = appDownloadManager.getCacheContext(photo, size.type);\r\n\r\n if(!isFit) {\r\n aspecter = document.createElement('div');\r\n aspecter.classList.add('media-container-aspecter');\r\n aspecter.style.width = set.size.width + 'px';\r\n aspecter.style.height = set.size.height + 'px';\r\n\r\n const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(photo, cacheContext, !noBlur, true);\r\n if(gotThumb) {\r\n loadThumbPromise = gotThumb.loadPromise;\r\n const thumbImage = gotThumb.image; // local scope\r\n thumbImage.classList.add('media-photo');\r\n container.append(thumbImage);\r\n } else {\r\n const res = wrapPhoto({\r\n container,\r\n message,\r\n photo,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n size,\r\n lazyLoadQueue,\r\n isOut,\r\n loadPromises,\r\n middleware,\r\n withoutPreloader,\r\n withTail,\r\n noAutoDownload,\r\n noBlur,\r\n noThumb: true,\r\n blurAfter: true\r\n //noFadeIn: true\r\n });\r\n const thumbImage = res.images.full;\r\n thumbImage.classList.add('media-photo', 'thumbnail');\r\n //container.append(thumbImage);\r\n }\r\n\r\n container.classList.add('media-container-fitted');\r\n container.append(aspecter);\r\n }\r\n } else {\r\n if(!size) {\r\n size = appPhotosManager.choosePhotoSize(photo, boxWidth, boxHeight, true);\r\n }\r\n \r\n cacheContext = appDownloadManager.getCacheContext(photo, size?.type);\r\n }\r\n\r\n if(!noThumb) {\r\n const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(photo, cacheContext, !noBlur);\r\n if(gotThumb) {\r\n loadThumbPromise = Promise.all([loadThumbPromise, gotThumb.loadPromise]);\r\n thumbImage = gotThumb.image;\r\n thumbImage.classList.add('media-photo');\r\n aspecter.append(thumbImage);\r\n }\r\n }\r\n // }\r\n\r\n image.classList.add('media-photo');\r\n \r\n //console.log('wrapPhoto downloaded:', photo, photo.downloaded, container);\r\n\r\n const needFadeIn = (thumbImage || !cacheContext.downloaded) && rootScope.settings.animationsEnabled && !noFadeIn;\r\n\r\n let preloader: ProgressivePreloader;\r\n if(message?.media?.preloader && !withoutPreloader) { // means upload\r\n preloader = message.media.preloader;\r\n preloader.attach(container);\r\n noAutoDownload = undefined;\r\n } else if(!cacheContext.downloaded) {\r\n preloader = new ProgressivePreloader({\r\n attachMethod: 'prepend'\r\n });\r\n }\r\n\r\n const getDownloadPromise = () => {\r\n const promise = photo._ === 'document' && photo.mime_type === 'image/gif' ? \r\n appDocsManager.downloadDoc(photo, /* undefined, */lazyLoadQueue?.queueId) : \r\n appPhotosManager.preloadPhoto(photo, size, lazyLoadQueue?.queueId, noAutoDownload);\r\n\r\n return promise;\r\n };\r\n\r\n const renderOnLoad = (url: string) => {\r\n return renderImageWithFadeIn(container, image, url, needFadeIn, aspecter, thumbImage);\r\n };\r\n\r\n const onLoad = (): Promise<void> => {\r\n if(middleware && !middleware()) return Promise.resolve();\r\n\r\n if(blurAfter) {\r\n return blur(cacheContext.url, 12).then(url => {\r\n return renderOnLoad(url);\r\n });\r\n }\r\n\r\n return renderOnLoad(cacheContext.url);\r\n };\r\n\r\n let loadPromise: Promise<any>;\r\n const canAttachPreloader = (\r\n (size as PhotoSize.photoSize).w >= 150 && \r\n (size as PhotoSize.photoSize).h >= 150\r\n ) || noAutoDownload;\r\n const load = () => {\r\n if(noAutoDownload && !withoutPreloader && preloader) {\r\n preloader.construct();\r\n preloader.setManual();\r\n }\r\n\r\n const promise = getDownloadPromise();\r\n\r\n if(preloader && \r\n !cacheContext.downloaded && \r\n !withoutPreloader && \r\n canAttachPreloader\r\n ) {\r\n preloader.attach(container, false, promise);\r\n }\r\n\r\n noAutoDownload = undefined;\r\n\r\n const renderPromise = promise.then(onLoad);\r\n renderPromise.catch(() => {});\r\n return {download: promise, render: renderPromise};\r\n };\r\n\r\n if(preloader) {\r\n preloader.setDownloadFunction(load);\r\n }\r\n \r\n if(cacheContext.downloaded) {\r\n loadThumbPromise = loadPromise = load().render;\r\n } else {\r\n if(!lazyLoadQueue) loadPromise = load().render;\r\n /* else if(noAutoDownload) {\r\n preloader.construct();\r\n preloader.setManual();\r\n preloader.attach(container);\r\n } */ else lazyLoadQueue.push({div: container, load: () => load().download});\r\n }\r\n\r\n if(loadPromises && loadThumbPromise) {\r\n loadPromises.push(loadThumbPromise);\r\n }\r\n\r\n return {\r\n loadPromises: {\r\n thumb: loadThumbPromise,\r\n full: loadPromise || Promise.resolve()\r\n },\r\n images: {\r\n thumb: thumbImage,\r\n full: image\r\n },\r\n preloader,\r\n aspecter\r\n };\r\n}\r\n\r\nexport function renderImageWithFadeIn(container: HTMLElement, \r\n image: HTMLImageElement, \r\n url: string, \r\n needFadeIn: boolean, \r\n aspecter = container,\r\n thumbImage?: HTMLImageElement\r\n) {\r\n if(needFadeIn) {\r\n image.classList.add('fade-in');\r\n }\r\n\r\n return new Promise<void>((resolve) => {\r\n /* if(photo._ === 'document') {\r\n console.error('wrapPhoto: will render document', photo, size, cacheContext);\r\n return resolve();\r\n } */\r\n\r\n renderImageFromUrl(image, url, () => {\r\n sequentialDom.mutateElement(container, () => {\r\n aspecter.append(image);\r\n\r\n fastRaf(() => {\r\n resolve();\r\n });\r\n\r\n if(needFadeIn) {\r\n image.addEventListener('animationend', () => {\r\n sequentialDom.mutate(() => {\r\n image.classList.remove('fade-in');\r\n \r\n if(thumbImage) {\r\n thumbImage.remove();\r\n }\r\n });\r\n }, {once: true});\r\n }\r\n });\r\n });\r\n });\r\n}\r\n\r\n// export function renderImageWithFadeIn(container: HTMLElement, \r\n// image: HTMLImageElement, \r\n// url: string, \r\n// needFadeIn: boolean, \r\n// aspecter = container,\r\n// thumbImage?: HTMLImageElement\r\n// ) {\r\n// if(needFadeIn) {\r\n// // image.classList.add('fade-in-new', 'not-yet');\r\n// image.classList.add('fade-in');\r\n// }\r\n\r\n// return new Promise<void>((resolve) => {\r\n// /* if(photo._ === 'document') {\r\n// console.error('wrapPhoto: will render document', photo, size, cacheContext);\r\n// return resolve();\r\n// } */\r\n\r\n// renderImageFromUrl(image, url, () => {\r\n// sequentialDom.mutateElement(container, () => {\r\n// aspecter.append(image);\r\n// // (needFadeIn ? getHeavyAnimationPromise() : Promise.resolve()).then(() => {\r\n\r\n// // fastRaf(() => {\r\n// resolve();\r\n// // });\r\n\r\n// if(needFadeIn) {\r\n// fastRaf(() => {\r\n// /* if(!image.isConnected) {\r\n// alert('aaaa');\r\n// } */\r\n// // fastRaf(() => {\r\n// image.classList.remove('not-yet');\r\n// // });\r\n// });\r\n\r\n// image.addEventListener('transitionend', () => {\r\n// sequentialDom.mutate(() => {\r\n// image.classList.remove('fade-in-new');\r\n \r\n// if(thumbImage) {\r\n// thumbImage.remove();\r\n// }\r\n// });\r\n// }, {once: true});\r\n// }\r\n// // });\r\n// });\r\n// });\r\n// });\r\n// }\r\n\r\nexport function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, onlyThumb, emoji, width, height, withThumb, loop, loadPromises, needFadeIn}: {\r\n doc: MyDocument, \r\n div: HTMLElement, \r\n middleware?: () => boolean, \r\n lazyLoadQueue?: LazyLoadQueue, \r\n group?: string, \r\n play?: boolean, \r\n onlyThumb?: boolean,\r\n emoji?: string,\r\n width?: number,\r\n height?: number,\r\n withThumb?: boolean,\r\n loop?: boolean,\r\n loadPromises?: Promise<any>[],\r\n needFadeIn?: boolean,\r\n}) {\r\n const stickerType = doc.sticker;\r\n\r\n if(!width) {\r\n width = !emoji ? 200 : undefined;\r\n }\r\n\r\n if(!height) {\r\n height = !emoji ? 200 : undefined;\r\n }\r\n\r\n if(stickerType === 2 && !LottieLoader.loaded) {\r\n //LottieLoader.loadLottie();\r\n LottieLoader.loadLottieWorkers();\r\n }\r\n \r\n if(!stickerType) {\r\n console.error('wrong doc for wrapSticker!', doc);\r\n throw new Error('wrong doc for wrapSticker!');\r\n }\r\n\r\n div.dataset.docId = doc.id;\r\n div.classList.add('media-sticker-wrapper');\r\n \r\n //console.log('wrap sticker', doc, div, onlyThumb);\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n\r\n const toneIndex = emoji ? getEmojiToneIndex(emoji) : -1;\r\n const downloaded = cacheContext.downloaded && !needFadeIn;\r\n \r\n let loadThumbPromise = deferredPromise<void>();\r\n let haveThumbCached = false;\r\n if((doc.thumbs?.length || doc.stickerCachedThumbs) && !div.firstElementChild && (!downloaded || stickerType === 2 || onlyThumb)/* && doc.thumbs[0]._ !== 'photoSizeEmpty' */) {\r\n let thumb = doc.stickerCachedThumbs && doc.stickerCachedThumbs[toneIndex] || doc.thumbs[0];\r\n \r\n //console.log('wrap sticker', thumb, div);\r\n\r\n let thumbImage: HTMLImageElement;\r\n const afterRender = () => {\r\n if(!div.childElementCount) {\r\n thumbImage.classList.add('media-sticker', 'thumbnail');\r\n \r\n sequentialDom.mutateElement(div, () => {\r\n div.append(thumbImage);\r\n loadThumbPromise.resolve();\r\n });\r\n }\r\n };\r\n\r\n if('url' in thumb) {\r\n thumbImage = new Image();\r\n renderImageFromUrl(thumbImage, thumb.url, afterRender);\r\n haveThumbCached = true;\r\n } else if('bytes' in thumb) {\r\n if(thumb._ === 'photoPathSize') {\r\n if(thumb.bytes.length) {\r\n const d = appPhotosManager.getPathFromPhotoPathSize(thumb);\r\n div.innerHTML = `<svg class=\"rlottie-vector media-sticker thumbnail\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" viewBox=\"0 0 ${doc.w || 512} ${doc.h || 512}\" xml:space=\"preserve\">\r\n <path d=\"${d}\"/>\r\n </svg>`;\r\n } else {\r\n thumb = doc.thumbs.find(t => (t as PhotoSize.photoStrippedSize).bytes?.length) || thumb;\r\n }\r\n } \r\n \r\n if(thumb && thumb._ !== 'photoPathSize' && toneIndex <= 0) {\r\n thumbImage = new Image();\r\n\r\n if((IS_WEBP_SUPPORTED || doc.pFlags.stickerThumbConverted || cacheContext.url)/* && false */) {\r\n renderImageFromUrl(thumbImage, appPhotosManager.getPreviewURLFromThumb(doc, thumb as PhotoSize.photoStrippedSize, true), afterRender);\r\n haveThumbCached = true;\r\n } else {\r\n webpWorkerController.convert(doc.id, (thumb as PhotoSize.photoStrippedSize).bytes as Uint8Array).then(bytes => {\r\n (thumb as PhotoSize.photoStrippedSize).bytes = bytes;\r\n doc.pFlags.stickerThumbConverted = true;\r\n \r\n if(middleware && !middleware()) return;\r\n \r\n if(!div.childElementCount) {\r\n renderImageFromUrl(thumbImage, appPhotosManager.getPreviewURLFromThumb(doc, thumb as PhotoSize.photoStrippedSize, true), afterRender);\r\n }\r\n }).catch(() => {});\r\n }\r\n }\r\n } else if(stickerType === 2 && (withThumb || onlyThumb) && toneIndex <= 0) {\r\n thumbImage = new Image();\r\n\r\n const load = () => {\r\n if(div.childElementCount || (middleware && !middleware())) return;\r\n\r\n const r = () => {\r\n if(div.childElementCount || (middleware && !middleware())) return;\r\n renderImageFromUrl(thumbImage, cacheContext.url, afterRender);\r\n };\r\n \r\n if(cacheContext.url) {\r\n r();\r\n return Promise.resolve();\r\n } else {\r\n return appDocsManager.getThumbURL(doc, thumb as PhotoSize.photoStrippedSize).promise.then(r);\r\n }\r\n };\r\n \r\n if(lazyLoadQueue && onlyThumb) {\r\n lazyLoadQueue.push({div, load});\r\n return Promise.resolve();\r\n } else {\r\n load();\r\n\r\n if((thumb as any).url) {\r\n haveThumbCached = true;\r\n }\r\n }\r\n }\r\n }\r\n\r\n if(loadPromises && haveThumbCached) {\r\n loadPromises.push(loadThumbPromise);\r\n }\r\n\r\n if(onlyThumb) { // for sticker panel\r\n return Promise.resolve();\r\n }\r\n \r\n const load = async() => {\r\n if(middleware && !middleware()) return;\r\n\r\n if(stickerType === 2) {\r\n /* if(doc.id === '1860749763008266301') {\r\n console.log('loaded sticker:', doc, div);\r\n } */\r\n\r\n //await new Promise((resolve) => setTimeout(resolve, 500));\r\n //return;\r\n\r\n //console.time('download sticker' + doc.id);\r\n\r\n //appDocsManager.downloadDocNew(doc.id).promise.then(res => res.json()).then(async(json) => {\r\n //fetch(doc.url).then(res => res.json()).then(async(json) => {\r\n /* return */ await appDocsManager.downloadDoc(doc, /* undefined, */lazyLoadQueue?.queueId)\r\n .then(readBlobAsText)\r\n //.then(JSON.parse)\r\n .then(async(json) => {\r\n //console.timeEnd('download sticker' + doc.id);\r\n //console.log('loaded sticker:', doc, div/* , blob */);\r\n if(middleware && !middleware()) return;\r\n\r\n let animation = await LottieLoader.loadAnimationWorker({\r\n container: div,\r\n loop: loop && !emoji,\r\n autoplay: play,\r\n animationData: json,\r\n width,\r\n height\r\n }, group, toneIndex);\r\n\r\n //const deferred = deferredPromise<void>();\r\n \r\n animation.addEventListener('firstFrame', () => {\r\n const element = div.firstElementChild;\r\n needFadeIn = (needFadeIn || !element || element.tagName === 'svg') && rootScope.settings.animationsEnabled;\r\n\r\n const cb = () => {\r\n if(element && element !== animation.canvas) {\r\n element.remove();\r\n }\r\n };\r\n\r\n if(!needFadeIn) {\r\n if(element) {\r\n sequentialDom.mutate(cb);\r\n }\r\n } else {\r\n sequentialDom.mutate(() => {\r\n animation.canvas.classList.add('fade-in');\r\n if(element) {\r\n element.classList.add('fade-out');\r\n }\r\n \r\n animation.canvas.addEventListener('animationend', () => {\r\n sequentialDom.mutate(() => {\r\n animation.canvas.classList.remove('fade-in');\r\n cb();\r\n });\r\n }, {once: true});\r\n });\r\n }\r\n\r\n appDocsManager.saveLottiePreview(doc, animation.canvas, toneIndex);\r\n\r\n //deferred.resolve();\r\n }, {once: true});\r\n \r\n if(emoji) {\r\n attachClickEvent(div, (e) => {\r\n cancelEvent(e);\r\n let animation = LottieLoader.getAnimation(div);\r\n \r\n if(animation.paused) {\r\n animation.autoplay = true;\r\n animation.restart();\r\n }\r\n });\r\n }\r\n\r\n //return deferred;\r\n //await new Promise((resolve) => setTimeout(resolve, 5e3));\r\n });\r\n\r\n //console.timeEnd('render sticker' + doc.id);\r\n } else if(stickerType === 1) {\r\n const image = new Image();\r\n const thumbImage = div.firstElementChild !== image && div.firstElementChild;\r\n needFadeIn = (needFadeIn || !downloaded || thumbImage) && rootScope.settings.animationsEnabled;\r\n\r\n image.classList.add('media-sticker');\r\n\r\n if(needFadeIn) {\r\n image.classList.add('fade-in');\r\n }\r\n\r\n return new Promise<void>((resolve, reject) => {\r\n const r = () => {\r\n if(middleware && !middleware()) return resolve();\r\n \r\n renderImageFromUrl(image, cacheContext.url, () => {\r\n sequentialDom.mutateElement(div, () => {\r\n div.append(image);\r\n if(thumbImage) {\r\n thumbImage.classList.add('fade-out');\r\n }\r\n\r\n resolve();\r\n\r\n if(needFadeIn) {\r\n image.addEventListener('animationend', () => {\r\n image.classList.remove('fade-in');\r\n if(thumbImage) {\r\n thumbImage.remove();\r\n }\r\n }, {once: true});\r\n }\r\n });\r\n });\r\n };\r\n \r\n if(cacheContext.url) r();\r\n else {\r\n appDocsManager.downloadDoc(doc, /* undefined, */lazyLoadQueue?.queueId).then(r, resolve);\r\n }\r\n });\r\n }\r\n };\r\n\r\n const loadPromise: Promise<any> = lazyLoadQueue && (!downloaded || stickerType === 2) ? \r\n (lazyLoadQueue.push({div, load}), Promise.resolve()) : \r\n load();\r\n\r\n if(downloaded && stickerType === 1) {\r\n loadThumbPromise = loadPromise;\r\n if(loadPromises) {\r\n loadPromises.push(loadThumbPromise);\r\n }\r\n }\r\n\r\n return loadPromise;\r\n}\r\n\r\nexport async function wrapStickerSetThumb({set, lazyLoadQueue, container, group, autoplay, width, height}: {\r\n set: StickerSet.stickerSet,\r\n lazyLoadQueue: LazyLoadQueue,\r\n container: HTMLElement,\r\n group: string,\r\n autoplay: boolean,\r\n width: number,\r\n height: number\r\n}) {\r\n if(set.thumbs?.length) {\r\n container.classList.add('media-sticker-wrapper');\r\n lazyLoadQueue.push({\r\n div: container,\r\n load: () => {\r\n const downloadOptions = appStickersManager.getStickerSetThumbDownloadOptions(set);\r\n const promise = appDownloadManager.download(downloadOptions);\r\n\r\n if(set.pFlags.animated) {\r\n return promise\r\n .then(readBlobAsText)\r\n //.then(JSON.parse)\r\n .then(json => {\r\n lottieLoader.loadAnimationWorker({\r\n container,\r\n loop: true,\r\n autoplay,\r\n animationData: json,\r\n width,\r\n height,\r\n needUpscale: true\r\n }, group);\r\n });\r\n } else {\r\n const image = new Image();\r\n image.classList.add('media-sticker');\r\n \r\n return promise.then(blob => {\r\n renderImageFromUrl(image, URL.createObjectURL(blob), () => {\r\n container.append(image);\r\n });\r\n });\r\n }\r\n }\r\n });\r\n\r\n return;\r\n }\r\n\r\n const promise = appStickersManager.getStickerSet(set);\r\n const stickerSet = await promise;\r\n if(stickerSet.documents[0]._ !== 'documentEmpty') { // as thumb will be used first sticker\r\n wrapSticker({\r\n doc: stickerSet.documents[0],\r\n div: container, \r\n group: group,\r\n lazyLoadQueue\r\n }); // kostil\r\n }\r\n}\r\n\r\nexport function wrapLocalSticker({emoji, width, height}: {\r\n doc?: MyDocument,\r\n url?: string,\r\n emoji?: string,\r\n width: number,\r\n height: number,\r\n}) {\r\n const container = document.createElement('div');\r\n\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: container,\r\n loop: false,\r\n play: true,\r\n width,\r\n height,\r\n emoji\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n container.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n return {container};\r\n}\r\n\r\nexport function wrapReply(title: Parameters<ReplyContainer['fill']>[0], subtitle: Parameters<ReplyContainer['fill']>[1], message?: any) {\r\n const replyContainer = new ReplyContainer('reply');\r\n replyContainer.fill(title, subtitle, message);\r\n /////////console.log('wrapReply', title, subtitle, media);\r\n return replyContainer.container;\r\n}\r\n\r\nexport function prepareAlbum(options: {\r\n container: HTMLElement,\r\n items: {w: number, h: number}[],\r\n maxWidth: number,\r\n minWidth: number,\r\n spacing: number,\r\n maxHeight?: number,\r\n forMedia?: true\r\n}) {\r\n const layouter = new Layouter(options.items, options.maxWidth, options.minWidth, options.spacing, options.maxHeight);\r\n const layout = layouter.layout();\r\n\r\n const widthItem = layout.find(item => item.sides & RectPart.Right);\r\n const width = widthItem.geometry.width + widthItem.geometry.x;\r\n\r\n const heightItem = layout.find(item => item.sides & RectPart.Bottom);\r\n const height = heightItem.geometry.height + heightItem.geometry.y;\r\n\r\n const container = options.container;\r\n container.style.width = width + 'px';\r\n container.style.height = height + 'px';\r\n const children = container.children;\r\n\r\n layout.forEach(({geometry, sides}, idx) => {\r\n let div: HTMLElement;\r\n div = children[idx] as HTMLElement;\r\n if(!div) {\r\n div = document.createElement('div');\r\n container.append(div);\r\n }\r\n\r\n div.classList.add('album-item', 'grouped-item');\r\n\r\n div.style.width = (geometry.width / width * 100) + '%';\r\n div.style.height = (geometry.height / height * 100) + '%';\r\n div.style.top = (geometry.y / height * 100) + '%';\r\n div.style.left = (geometry.x / width * 100) + '%';\r\n\r\n if(sides & RectPart.Left && sides & RectPart.Top) {\r\n div.style.borderTopLeftRadius = 'inherit';\r\n }\r\n\r\n if(sides & RectPart.Left && sides & RectPart.Bottom) {\r\n div.style.borderBottomLeftRadius = 'inherit';\r\n }\r\n\r\n if(sides & RectPart.Right && sides & RectPart.Top) {\r\n div.style.borderTopRightRadius = 'inherit';\r\n }\r\n\r\n if(sides & RectPart.Right && sides & RectPart.Bottom) {\r\n div.style.borderBottomRightRadius = 'inherit';\r\n }\r\n\r\n if(options.forMedia) {\r\n const mediaDiv = document.createElement('div');\r\n mediaDiv.classList.add('album-item-media');\r\n \r\n div.append(mediaDiv);\r\n }\r\n\r\n // @ts-ignore\r\n //div.style.backgroundColor = '#' + Math.floor(Math.random() * (2 ** 24 - 1)).toString(16).padStart(6, '0');\r\n });\r\n\r\n /* if(options.forMedia) {\r\n layout.forEach((_, i) => {\r\n const mediaDiv = document.createElement('div');\r\n mediaDiv.classList.add('album-item-media');\r\n \r\n options.container.children[i].append(mediaDiv);\r\n });\r\n } */\r\n}\r\n\r\nexport function wrapAlbum({groupId, attachmentDiv, middleware, uploading, lazyLoadQueue, isOut, chat, loadPromises, noAutoDownload}: {\r\n groupId: string, \r\n attachmentDiv: HTMLElement,\r\n middleware?: () => boolean,\r\n lazyLoadQueue?: LazyLoadQueue,\r\n uploading?: boolean,\r\n isOut: boolean,\r\n chat: Chat,\r\n loadPromises?: Promise<any>[],\r\n noAutoDownload?: boolean,\r\n}) {\r\n const items: {size: PhotoSize.photoSize, media: any, message: any}[] = [];\r\n\r\n // !lowest msgID will be the FIRST in album\r\n const storage = appMessagesManager.getMidsByAlbum(groupId);\r\n for(const mid of storage) {\r\n const m = chat.getMessage(mid);\r\n const media = m.media.photo || m.media.document;\r\n\r\n const size: any = media._ === 'photo' ? appPhotosManager.choosePhotoSize(media, 480, 480) : {w: media.w, h: media.h};\r\n items.push({size, media, message: m});\r\n }\r\n\r\n /* // * pending\r\n if(storage[0] < 0) {\r\n items.reverse();\r\n } */\r\n\r\n prepareAlbum({\r\n container: attachmentDiv,\r\n items: items.map(i => ({w: i.size.w, h: i.size.h})),\r\n maxWidth: mediaSizes.active.album.width,\r\n minWidth: 100,\r\n spacing: 2,\r\n forMedia: true\r\n });\r\n\r\n items.forEach((item, idx) => {\r\n const {size, media, message} = item;\r\n\r\n const div = attachmentDiv.children[idx] as HTMLElement;\r\n div.dataset.mid = '' + message.mid;\r\n const mediaDiv = div.firstElementChild as HTMLElement;\r\n if(media._ === 'photo') {\r\n wrapPhoto({\r\n photo: media,\r\n message,\r\n container: mediaDiv,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n isOut,\r\n lazyLoadQueue,\r\n middleware,\r\n size,\r\n loadPromises,\r\n noAutoDownload\r\n });\r\n } else {\r\n wrapVideo({\r\n doc: message.media.document,\r\n container: mediaDiv,\r\n message,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n withTail: false,\r\n isOut,\r\n lazyLoadQueue,\r\n middleware,\r\n loadPromises,\r\n noAutoDownload\r\n });\r\n }\r\n });\r\n}\r\n\r\nexport function wrapGroupedDocuments({albumMustBeRenderedFull, message, bubble, messageDiv, chat, loadPromises, noAutoDownload, lazyLoadQueue, searchContext, useSearch}: {\r\n albumMustBeRenderedFull: boolean,\r\n message: any,\r\n messageDiv: HTMLElement,\r\n bubble: HTMLElement,\r\n uploading?: boolean,\r\n chat: Chat,\r\n loadPromises?: Promise<any>[],\r\n noAutoDownload?: boolean,\r\n lazyLoadQueue?: LazyLoadQueue,\r\n searchContext?: MediaSearchContext,\r\n useSearch?: boolean,\r\n}) {\r\n let nameContainer: HTMLElement;\r\n const mids = albumMustBeRenderedFull ? chat.getMidsByMid(message.mid) : [message.mid];\r\n /* if(isPending) {\r\n mids.reverse();\r\n } */\r\n\r\n mids.forEach((mid, idx) => {\r\n const message = chat.getMessage(mid);\r\n const div = wrapDocument({\r\n message,\r\n loadPromises,\r\n noAutoDownload,\r\n lazyLoadQueue,\r\n searchContext\r\n });\r\n\r\n const container = document.createElement('div');\r\n container.classList.add('document-container');\r\n container.dataset.mid = '' + mid;\r\n container.dataset.peerId = '' + message.peerId;\r\n\r\n const wrapper = document.createElement('div');\r\n wrapper.classList.add('document-wrapper');\r\n \r\n if(message.message) {\r\n const messageDiv = document.createElement('div');\r\n messageDiv.classList.add('document-message');\r\n\r\n const richText = RichTextProcessor.wrapRichText(message.message, {\r\n entities: message.totalEntities\r\n });\r\n\r\n messageDiv.innerHTML = richText;\r\n wrapper.append(messageDiv);\r\n }\r\n\r\n if(mids.length > 1) {\r\n const selection = document.createElement('div');\r\n selection.classList.add('document-selection');\r\n container.append(selection);\r\n \r\n container.classList.add('grouped-item');\r\n\r\n if(idx === 0) {\r\n nameContainer = wrapper;\r\n }\r\n }\r\n\r\n wrapper.append(div);\r\n container.append(wrapper);\r\n messageDiv.append(container);\r\n });\r\n\r\n if(mids.length > 1) {\r\n bubble.classList.add('is-multiple-documents', 'is-grouped');\r\n }\r\n\r\n return nameContainer;\r\n}\r\n\r\nexport function wrapPoll(message: any) {\r\n const elem = new PollElement();\r\n elem.message = message;\r\n elem.setAttribute('peer-id', '' + message.peerId);\r\n elem.setAttribute('poll-id', message.media.poll.id);\r\n elem.setAttribute('message-id', '' + message.mid);\r\n elem.render();\r\n return elem;\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport whichChild from \"./whichChild\";\r\n\r\nexport default function positionElementByIndex(element: HTMLElement, container: HTMLElement, pos: number, prevPos?: number) {\r\n if(prevPos === undefined) {\r\n prevPos = element.parentElement === container ? whichChild(element) : -1;\r\n }\r\n\r\n if(prevPos === pos) {\r\n return false;\r\n } else if(prevPos !== -1 && prevPos < pos) { // was higher\r\n pos += 1;\r\n }\r\n\r\n if(!pos) {\r\n container.prepend(element);\r\n } else if(container.childElementCount > pos) {\r\n container.insertBefore(element, container.children[pos]);\r\n } else {\r\n container.append(element);\r\n }\r\n\r\n return true;\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { insertInDescendSortedArray } from \"./array\";\nimport { getMiddleware } from \"./middleware\";\nimport { safeAssign } from \"./object\";\n\nexport type SortedElementBase = {\n id: number, \n index: number\n};\n\nexport default class SortedList<SortedElement extends SortedElementBase> {\n protected elements: Map<number, SortedElement>;\n protected sorted: Array<SortedElement>;\n\n protected getIndex: (id: number) => number;\n protected onDelete: (element: SortedElement) => void;\n protected onUpdate: (element: SortedElement) => void;\n protected onSort: (element: SortedElement, idx: number) => void;\n protected onElementCreate: (base: SortedElementBase, batch: boolean) => SortedElement;\n\n protected updateElementWith = (callback: () => void) => callback();\n protected updateListWith = (callback: (canUpdate: boolean | undefined) => void) => callback(true);\n\n protected middleware = getMiddleware();\n\n constructor(options: {\n getIndex: SortedList<SortedElement>['getIndex'],\n onDelete?: SortedList<SortedElement>['onDelete'],\n onUpdate?: SortedList<SortedElement>['onUpdate'],\n onSort?: SortedList<SortedElement>['onSort'],\n onElementCreate: SortedList<SortedElement>['onElementCreate'],\n\n updateElementWith?: SortedList<SortedElement>['updateElementWith'],\n updateListWith?: SortedList<SortedElement>['updateListWith']\n }) {\n safeAssign(this, options);\n\n this.elements = new Map();\n this.sorted = [];\n }\n\n public clear() {\n this.middleware.clean();\n this.elements.clear();\n this.sorted.length = 0;\n }\n\n protected _updateList() {\n this.elements.forEach(element => {\n this.update(element.id, true);\n });\n\n if(this.onSort) {\n this.sorted.forEach((element, idx) => {\n this.onSort(element, idx);\n });\n }\n }\n\n public updateList(callback: (updated: boolean) => void) {\n const middleware = this.middleware.get();\n this.updateListWith((canUpdate) => {\n if(!middleware() || (canUpdate !== undefined && !canUpdate)) {\n return callback(false);\n }\n\n this._updateList();\n \n callback(true);\n });\n }\n\n public has(id: number) {\n return this.elements.has(id);\n }\n\n public get(id: number) {\n return this.elements.get(id);\n }\n\n public getAll() {\n return this.elements;\n }\n\n public add(id: number, batch = false, updateElementWith?: SortedList<SortedElement>['updateElementWith'], updateBatch = batch) {\n let element = this.get(id);\n if(element) {\n return element;\n }\n\n const base: SortedElementBase = {\n id,\n index: 0\n };\n\n element = this.onElementCreate(base, batch);\n this.elements.set(id, element);\n this.update(id, updateBatch, element, updateElementWith);\n\n return element;\n }\n\n public delete(id: number, noScheduler?: boolean) {\n const element = this.elements.get(id);\n if(!element) {\n return false;\n }\n \n this.elements.delete(id);\n \n const idx = this.sorted.indexOf(element);\n if(idx !== -1) {\n this.sorted.splice(idx, 1);\n }\n\n if(this.onDelete) {\n if(noScheduler) {\n this.onDelete(element);\n } else {\n const middleware = this.middleware.get();\n this.updateElementWith(() => {\n if(!middleware()) {\n return;\n }\n\n this.onDelete(element);\n });\n }\n }\n\n return true;\n }\n\n public update(id: number, batch = false, element = this.get(id), updateElementWith?: SortedList<SortedElement>['updateElementWith']) {\n if(!element) {\n return;\n }\n\n element.index = this.getIndex(id);\n this.onUpdate && this.onUpdate(element);\n\n const idx = insertInDescendSortedArray(this.sorted, element, 'index');\n if(!batch && this.onSort) {\n const middleware = this.middleware.get();\n (updateElementWith || this.updateElementWith)(() => {\n if(!middleware()) {\n return;\n }\n\n // * в случае пересортировки этого же элемента во время ожидания вызовется вторая такая же. нужно соблюдать последовательность событий\n this.onSort(element, idx);\n /* if(this.get(id) === element) {\n this.onSort(element, this.sorted.indexOf(element));\n } */\n });\n }\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { LazyLoadQueueIntersector } from \"./lazyLoadQueue\";\nimport appDialogsManager, { DialogDom } from \"../lib/appManagers/appDialogsManager\";\nimport { getHeavyAnimationPromise } from \"../hooks/useHeavyAnimationCheck\";\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\nimport isInDOM from \"../helpers/dom/isInDOM\";\nimport positionElementByIndex from \"../helpers/dom/positionElementByIndex\";\nimport replaceContent from \"../helpers/dom/replaceContent\";\nimport { safeAssign } from \"../helpers/object\";\nimport { fastRaf } from \"../helpers/schedulers\";\nimport SortedList, { SortedElementBase } from \"../helpers/sortedList\";\n\ninterface SortedUser extends SortedElementBase {\n dom: DialogDom\n}\n\nexport default class SortedUserList extends SortedList<SortedUser> {\n protected static SORT_INTERVAL = 30e3;\n public list: HTMLUListElement;\n \n protected lazyLoadQueue: LazyLoadQueueIntersector;\n protected avatarSize = 48;\n protected rippleEnabled = true;\n\n constructor(options: Partial<{\n lazyLoadQueue: SortedUserList['lazyLoadQueue'],\n avatarSize: SortedUserList['avatarSize'],\n rippleEnabled: SortedUserList['rippleEnabled'],\n new: boolean\n }> = {}) {\n super({\n getIndex: (id) => appUsersManager.getUserStatusForSort(id),\n onDelete: (element) => element.dom.listEl.remove(),\n onUpdate: (element) => {\n const status = appUsersManager.getUserStatusString(element.id);\n replaceContent(element.dom.lastMessageSpan, status);\n },\n onSort: (element, idx) => positionElementByIndex(element.dom.listEl, this.list, idx),\n onElementCreate: (base) => {\n const {dom} = appDialogsManager.addDialogNew({\n dialog: base.id,\n container: false,\n drawStatus: false,\n avatarSize: this.avatarSize,\n autonomous: true,\n meAsSaved: false,\n rippleEnabled: this.rippleEnabled,\n lazyLoadQueue: this.lazyLoadQueue\n });\n\n (base as SortedUser).dom = dom;\n return base as SortedUser;\n },\n updateElementWith: fastRaf,\n updateListWith: async(callback) => {\n if(!isInDOM(this.list)) {\n return callback(false);\n }\n \n await getHeavyAnimationPromise();\n \n if(!isInDOM(this.list)) {\n return callback(false);\n }\n\n callback(true);\n }\n });\n\n safeAssign(this, options);\n\n this.list = appDialogsManager.createChatList({new: options.new});\n\n let timeout: number;\n const doTimeout = () => {\n timeout = window.setTimeout(() => {\n this.updateList((good) => {\n if(good) {\n doTimeout();\n }\n });\n }, SortedUserList.SORT_INTERVAL);\n };\n\n doTimeout();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { cancelContextMenuOpening } from \"../../components/misc\";\nimport SwipeHandler from \"../../components/swipeHandler\";\nimport { cancelEvent } from \"./cancelEvent\";\n\nexport default function handleTabSwipe(container: HTMLElement, onSwipe: (next: boolean) => void) {\n /* let hadScroll = false;\n const onScroll = () => {\n swipeHandler.reset();\n };\n let firstSwipeChecked = false; */\n return new SwipeHandler({\n element: container, \n /* onFirstSwipe: () => {\n this.scroll.container.addEventListener('scroll', onScroll, {passive: true});\n }, */\n onSwipe: (xDiff, yDiff, e) => {\n /* if(!firstSwipeChecked) {\n firstSwipeChecked = true;\n if(yDiff !== 0) {\n return true;\n }\n }\n\n cancelEvent(e); */\n\n if(Math.abs(yDiff) > 20) {\n return true;\n }\n\n if(Math.abs(xDiff) > Math.abs(yDiff)) {\n cancelEvent(e);\n } else if(Math.abs(yDiff) > Math.abs(xDiff)/* || Math.abs(yDiff) > 20 */) {\n return true;\n }\n\n if(Math.abs(xDiff) > 50) {\n onSwipe(xDiff > 0);\n cancelContextMenuOpening();\n\n return true;\n }\n },\n /* onReset: () => {\n hadScroll = false;\n firstSwipeChecked = false;\n this.scroll.container.removeEventListener('scroll', onScroll);\n }, */\n cancelEvent: false\n });\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appImManager from \"../../lib/appManagers/appImManager\";\r\nimport PopupPickUser from \"./pickUser\";\r\n\r\nexport default class PopupForward extends PopupPickUser {\r\n constructor(\r\n peerIdMids: {[fromPeerId: number]: number[]}, \r\n onSelect?: (peerId: number) => Promise<void> | void, \r\n onClose?: () => void, \r\n overrideOnSelect = false\r\n ) {\r\n super({\r\n peerTypes: ['dialogs', 'contacts'],\r\n onSelect: overrideOnSelect ? onSelect : async(peerId) => {\r\n if(onSelect) {\r\n const res = onSelect(peerId);\r\n if(res instanceof Promise) {\r\n await res;\r\n }\r\n }\r\n\r\n appImManager.setInnerPeer(peerId);\r\n appImManager.chat.input.initMessagesForward(peerIdMids);\r\n },\r\n onClose,\r\n placeholder: 'ShareModal.Search.ForwardPlaceholder',\r\n chatRightsAction: 'send_messages',\r\n selfPresence: 'ChatYourSelf'\r\n });\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appChatsManager from \"../../lib/appManagers/appChatsManager\";\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport rootScope from \"../../lib/rootScope\";\nimport { addCancelButton } from \".\";\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerOptions } from \"./peer\";\nimport { ChatType } from \"../chat/chat\";\nimport { i18n, LangPackKey } from \"../../lib/langPack\";\nimport PeerTitle from \"../peerTitle\";\nimport appPeersManager from \"../../lib/appManagers/appPeersManager\";\n\nexport default class PopupDeleteMessages {\n constructor(peerId: number, mids: number[], type: ChatType, onConfirm?: () => void) {\n const peerTitleElement = new PeerTitle({peerId}).element;\n\n mids = mids.slice();\n const callback = (checked: PopupPeerButtonCallbackCheckboxes, revoke?: boolean) => {\n onConfirm && onConfirm();\n if(type === 'scheduled') {\n appMessagesManager.deleteScheduledMessages(peerId, mids);\n } else {\n appMessagesManager.deleteMessages(peerId, mids, !!checked.size || revoke);\n }\n };\n\n let title: LangPackKey, titleArgs: any[], description: LangPackKey, descriptionArgs: any[], buttons: PopupPeerOptions['buttons'], checkboxes: PopupPeerOptions['checkboxes'] = [];\n if(mids.length === 1) {\n title = 'DeleteSingleMessagesTitle';\n } else {\n title = 'DeleteMessagesTitle';\n titleArgs = [i18n('messages', [mids.length])];\n }\n \n if(appPeersManager.isMegagroup(peerId)) {\n description = mids.length === 1 ? 'AreYouSureDeleteSingleMessageMega' : 'AreYouSureDeleteFewMessagesMega';\n } else {\n description = mids.length === 1 ? 'AreYouSureDeleteSingleMessage' : 'AreYouSureDeleteFewMessages';\n }\n\n buttons = [{\n langKey: 'Delete',\n isDanger: true,\n callback\n }];\n\n if(peerId === rootScope.myId || type === 'scheduled') {\n \n } else {\n if(peerId > 0) {\n checkboxes.push({\n text: 'DeleteMessagesOptionAlso',\n textArgs: [peerTitleElement]\n });\n } else {\n const chat = appChatsManager.getChat(-peerId);\n\n const hasRights = appChatsManager.hasRights(-peerId, 'delete_messages');\n if(chat._ === 'chat') {\n const canRevoke = hasRights ? mids.slice() : mids.filter(mid => {\n const message = appMessagesManager.getMessageByPeer(peerId, mid);\n return message.fromId === rootScope.myId;\n });\n\n if(canRevoke.length) {\n if(canRevoke.length === mids.length) {\n checkboxes.push({\n text: 'DeleteForAll'\n });\n } else {\n checkboxes.push({\n text: 'DeleteMessagesOption'\n });\n\n description = 'DeleteMessagesTextGroup';\n descriptionArgs = [i18n('messages', [canRevoke.length])];\n //description = `You can also delete the ${canRevoke.length} message${canRevoke.length > 1 ? 's' : ''} you sent from the inboxes of other group members by pressing \"${buttonText}\".`;\n }\n }\n } else {\n buttons[0].callback = (checked) => callback(checked, true);\n }\n }\n }\n\n addCancelButton(buttons);\n\n const popup = new PopupPeer('popup-delete-chat', {\n peerId,\n titleLangKey: title,\n titleLangArgs: titleArgs,\n descriptionLangKey: description,\n descriptionLangArgs: descriptionArgs,\n buttons,\n checkboxes\n });\n\n popup.show();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport { PopupButton } from \".\";\nimport PopupPeer from \"./peer\";\n\nexport default class PopupSendNow {\n constructor(peerId: number, mids: number[], onConfirm?: () => void) {\n let title: string, description: string, buttons: PopupButton[] = [];\n\n title = `Send Message${mids.length > 1 ? 's' : ''} Now`;\n description = mids.length > 1 ? 'Send ' + mids.length + ' messages now?' : 'Send message now?';\n\n const callback = () => {\n onConfirm && onConfirm();\n appMessagesManager.sendScheduledMessages(peerId, mids);\n };\n\n buttons.push({\n langKey: 'Send',\n callback\n });\n\n const popup = new PopupPeer('popup-delete-chat', {\n peerId,\n title,\n description,\n buttons\n });\n\n popup.show();\n }\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function cancelSelection() {\r\n if(window.getSelection) {\r\n if(window.getSelection().empty) { // Chrome\r\n window.getSelection().empty();\r\n } else if(window.getSelection().removeAllRanges) { // Firefox\r\n window.getSelection().removeAllRanges();\r\n }\r\n // @ts-ignore\r\n } else if(document.selection) { // IE?\r\n // @ts-ignore\r\n document.selection.empty();\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { AppMessagesManager, MessagesStorage } from \"../../lib/appManagers/appMessagesManager\";\nimport type ChatBubbles from \"./bubbles\";\nimport type ChatInput from \"./input\";\nimport type Chat from \"./chat\";\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\nimport Button from \"../button\";\nimport ButtonIcon from \"../buttonIcon\";\nimport CheckboxField from \"../checkboxField\";\nimport PopupDeleteMessages from \"../popups/deleteMessages\";\nimport PopupForward from \"../popups/forward\";\nimport { toast } from \"../toast\";\nimport SetTransition from \"../singleTransition\";\nimport ListenerSetter from \"../../helpers/listenerSetter\";\nimport PopupSendNow from \"../popups/sendNow\";\nimport appNavigationController, { NavigationItem } from \"../appNavigationController\";\nimport { IS_MOBILE_SAFARI } from \"../../environment/userAgent\";\nimport I18n, { i18n, _i18n } from \"../../lib/langPack\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport blurActiveElement from \"../../helpers/dom/blurActiveElement\";\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\nimport cancelSelection from \"../../helpers/dom/cancelSelection\";\nimport getSelectedText from \"../../helpers/dom/getSelectedText\";\nimport rootScope from \"../../lib/rootScope\";\nimport { safeAssign } from \"../../helpers/object\";\nimport { fastRaf } from \"../../helpers/schedulers\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport AppSearchSuper from \"../appSearchSuper.\";\nimport isInDOM from \"../../helpers/dom/isInDOM\";\nimport { randomLong } from \"../../helpers/random\";\nimport { attachContextMenuListener } from \"../misc\";\nimport { attachClickEvent, AttachClickOptions } from \"../../helpers/dom/clickEvent\";\nimport findUpAsChild from \"../../helpers/dom/findUpAsChild\";\n\nconst accumulateMapSet = (map: Map<number, Set<number>>) => {\n return [...map.values()].reduce((acc, v) => acc + v.size, 0);\n};\n\n//const MIN_CLICK_MOVE = 32; // minimum bubble height\n\nclass AppSelection {\n public selectedMids: Map<number, Set<number>> = new Map();\n public isSelecting = false;\n\n public selectedText: string;\n\n protected listenerSetter: ListenerSetter;\n protected appMessagesManager: AppMessagesManager;\n protected isScheduled: boolean;\n protected listenElement: HTMLElement;\n\n protected onToggleSelection: (forwards: boolean) => void;\n protected onUpdateContainer: (cantForward: boolean, cantDelete: boolean, cantSend: boolean) => void;\n protected onCancelSelection: () => void;\n protected toggleByMid: (peerId: number, mid: number) => void;\n protected toggleByElement: (bubble: HTMLElement) => void;\n\n protected navigationType: NavigationItem['type'];\n\n protected getElementFromTarget: (target: HTMLElement) => HTMLElement;\n protected verifyTarget: (e: MouseEvent, target: HTMLElement) => boolean;\n protected verifyMouseMoveTarget: (e: MouseEvent, element: HTMLElement, selecting: boolean) => boolean;\n protected verifyTouchLongPress: () => boolean;\n protected targetLookupClassName: string;\n protected lookupBetweenParentClassName: string;\n protected lookupBetweenElementsQuery: string;\n\n constructor(options: {\n appMessagesManager: AppMessagesManager,\n listenElement: HTMLElement,\n listenerSetter: ListenerSetter,\n getElementFromTarget: AppSelection['getElementFromTarget'],\n verifyTarget?: AppSelection['verifyTarget'],\n verifyMouseMoveTarget?: AppSelection['verifyMouseMoveTarget'],\n verifyTouchLongPress?: AppSelection['verifyTouchLongPress'],\n targetLookupClassName: string,\n lookupBetweenParentClassName: string,\n lookupBetweenElementsQuery: string,\n isScheduled?: AppSelection['isScheduled']\n }) {\n safeAssign(this, options);\n\n this.navigationType = 'multiselect-' + randomLong() as any;\n\n if(IS_TOUCH_SUPPORTED) {\n this.listenerSetter.add(this.listenElement)('touchend', () => {\n if(!this.isSelecting) return;\n this.selectedText = getSelectedText();\n });\n\n attachContextMenuListener(this.listenElement, (e) => {\n if(this.isSelecting || (this.verifyTouchLongPress && !this.verifyTouchLongPress())) return;\n\n // * these two lines will fix instant text selection on iOS Safari\n document.body.classList.add('no-select'); // * need no-select on body because chat-input transforms in channels\n this.listenElement.addEventListener('touchend', (e) => {\n cancelEvent(e); // ! this one will fix propagation to document loader button, etc\n document.body.classList.remove('no-select');\n\n //this.chat.bubbles.onBubblesClick(e);\n }, {once: true, capture: true});\n\n cancelSelection();\n //cancelEvent(e as any);\n const element = this.getElementFromTarget(e.target as HTMLElement);\n if(element) {\n this.toggleByElement(element);\n }\n }, this.listenerSetter);\n\n return;\n }\n\n const getElementsBetween = (first: HTMLElement, last: HTMLElement) => { \n if(first === last) {\n return [];\n }\n\n const firstRect = first.getBoundingClientRect();\n const lastRect = last.getBoundingClientRect();\n const difference = (firstRect.top - lastRect.top) || (firstRect.left - lastRect.left);\n const isHigher = difference < 0;\n\n const parent = findUpClassName(first, this.lookupBetweenParentClassName);\n if(!parent) {\n return [];\n }\n\n const elements = Array.from(parent.querySelectorAll(this.lookupBetweenElementsQuery)) as HTMLElement[];\n let firstIndex = elements.indexOf(first);\n let lastIndex = elements.indexOf(last);\n\n if(!isHigher) {\n [lastIndex, firstIndex] = [firstIndex, lastIndex];\n }\n\n const slice = elements.slice(firstIndex + 1, lastIndex);\n\n // console.log('getElementsBetween', first, last, slice, firstIndex, lastIndex, isHigher);\n\n return slice;\n };\n\n this.listenerSetter.add(this.listenElement)('mousedown', (e) => {\n //console.log('selection mousedown', e);\n const element = findUpClassName(e.target, this.targetLookupClassName);\n if(e.button !== 0) {\n return;\n }\n\n if(this.verifyTarget && !this.verifyTarget(e, element)) {\n return;\n }\n \n const seen: Map<number, Set<number>> = new Map();\n let selecting: boolean;\n\n /* let good = false;\n const {x, y} = e; */\n\n /* const bubbles = appImManager.bubbles;\n for(const mid in bubbles) {\n const bubble = bubbles[mid];\n bubble.addEventListener('mouseover', () => {\n console.log('mouseover');\n }, {once: true});\n } */\n\n let firstTarget = element;\n\n const processElement = (element: HTMLElement, checkBetween = true) => {\n const mid = +element.dataset.mid;\n const peerId = +element.dataset.peerId;\n if(!mid || !peerId) return;\n\n if(!isInDOM(firstTarget)) {\n firstTarget = element;\n }\n\n let seenSet = seen.get(peerId);\n if(!seenSet) {\n seen.set(peerId, seenSet = new Set());\n }\n\n if(!seenSet.has(mid)) {\n const isSelected = this.isMidSelected(peerId, mid);\n if(selecting === undefined) {\n //bubblesContainer.classList.add('no-select');\n selecting = !isSelected;\n }\n\n seenSet.add(mid);\n\n if((selecting && !isSelected) || (!selecting && isSelected)) {\n const seenLength = accumulateMapSet(seen);\n if(this.toggleByElement && checkBetween) {\n if(seenLength < 2) {\n if(findUpAsChild(element, firstTarget)) {\n firstTarget = element;\n }\n }\n\n const elementsBetween = getElementsBetween(firstTarget, element);\n // console.log(elementsBetween);\n if(elementsBetween.length) {\n elementsBetween.forEach(element => {\n processElement(element, false);\n });\n }\n }\n\n if(!this.selectedMids.size) {\n if(seenLength === 2 && this.toggleByMid) {\n for(const [peerId, mids] of seen) {\n for(const mid of mids) {\n this.toggleByMid(peerId, mid);\n }\n }\n }\n } else if(this.toggleByElement) {\n this.toggleByElement(element);\n }\n }\n }\n };\n\n //const foundTargets: Map<HTMLElement, true> = new Map();\n let canceledSelection = false;\n const onMouseMove = (e: MouseEvent) => {\n if(!canceledSelection) {\n cancelSelection();\n canceledSelection = true;\n }\n /* if(!good) {\n if(Math.abs(e.x - x) > MIN_CLICK_MOVE || Math.abs(e.y - y) > MIN_CLICK_MOVE) {\n good = true;\n } else {\n return;\n }\n } */\n\n /* if(foundTargets.has(e.target as HTMLElement)) return;\n foundTargets.set(e.target as HTMLElement, true); */\n const element = this.getElementFromTarget(e.target as HTMLElement);\n if(!element) {\n //console.error('found no bubble', e);\n return;\n }\n\n if(this.verifyMouseMoveTarget && !this.verifyMouseMoveTarget(e, element, selecting)) {\n this.listenerSetter.removeManual(this.listenElement, 'mousemove', onMouseMove);\n this.listenerSetter.removeManual(document, 'mouseup', onMouseUp, documentListenerOptions);\n return;\n }\n\n processElement(element);\n };\n\n const onMouseUp = (e: MouseEvent) => {\n if(seen.size) {\n attachClickEvent(window, cancelEvent, {capture: true, once: true, passive: false});\n }\n\n this.listenerSetter.removeManual(this.listenElement, 'mousemove', onMouseMove);\n //bubblesContainer.classList.remove('no-select');\n\n // ! CANCEL USER SELECTION !\n cancelSelection();\n };\n\n const documentListenerOptions = {once: true};\n this.listenerSetter.add(this.listenElement)('mousemove', onMouseMove);\n this.listenerSetter.add(document)('mouseup', onMouseUp, documentListenerOptions);\n });\n }\n\n protected isElementShouldBeSelected(element: HTMLElement) {\n return this.isMidSelected(+element.dataset.peerId, +element.dataset.mid);\n }\n\n protected appendCheckbox(element: HTMLElement, checkboxField: CheckboxField) {\n element.prepend(checkboxField.label);\n }\n\n public toggleElementCheckbox(element: HTMLElement, show: boolean) {\n const hasCheckbox = !!this.getCheckboxInputFromElement(element);\n if(show) {\n if(hasCheckbox) {\n return false;\n }\n \n const checkboxField = new CheckboxField({\n name: element.dataset.mid, \n round: true\n });\n \n // * if it is a render of new message\n if(this.isSelecting) { // ! avoid breaking animation on start\n if(this.isElementShouldBeSelected(element)) {\n checkboxField.input.checked = true;\n element.classList.add('is-selected');\n }\n }\n \n this.appendCheckbox(element, checkboxField);\n } else if(hasCheckbox) {\n this.getCheckboxInputFromElement(element).parentElement.remove();\n }\n\n return true;\n }\n\n protected getCheckboxInputFromElement(element: HTMLElement): HTMLInputElement {\n return element.firstElementChild?.tagName === 'LABEL' && \n element.firstElementChild.firstElementChild as HTMLInputElement;\n }\n\n protected updateContainer(forceSelection = false) {\n const size = this.selectedMids.size;\n if(!size && !forceSelection) return;\n \n let cantForward = !size, \n cantDelete = !size, \n cantSend = !size;\n for(const [peerId, mids] of this.selectedMids) {\n const storage = this.isScheduled ? this.appMessagesManager.getScheduledMessagesStorage(peerId) : this.appMessagesManager.getMessagesStorage(peerId);\n for(const mid of mids) {\n const message = this.appMessagesManager.getMessageFromStorage(storage, mid);\n if(!cantForward) {\n if(message.action) {\n cantForward = true;\n }\n }\n \n if(!cantDelete) {\n const canDelete = this.appMessagesManager.canDeleteMessage(message);\n if(!canDelete) {\n cantDelete = true;\n }\n }\n\n if(cantForward && cantDelete) break;\n }\n\n if(cantForward && cantDelete) break;\n }\n \n this.onUpdateContainer && this.onUpdateContainer(cantForward, cantDelete, cantSend);\n }\n\n public toggleSelection(toggleCheckboxes = true, forceSelection = false) {\n const wasSelecting = this.isSelecting;\n const size = this.selectedMids.size;\n this.isSelecting = !!size || forceSelection;\n\n if(wasSelecting === this.isSelecting) return false;\n \n // const bubblesContainer = this.bubbles.bubblesContainer;\n //bubblesContainer.classList.toggle('is-selecting', !!size);\n\n /* if(bubblesContainer.classList.contains('is-chat-input-hidden')) {\n const scrollable = this.appImManager.scrollable;\n if(scrollable.isScrolledDown) {\n scrollable.scrollTo(scrollable.scrollHeight, 'top', true, true, 200);\n }\n } */\n\n if(!IS_TOUCH_SUPPORTED) {\n this.listenElement.classList.toggle('no-select', this.isSelecting);\n\n if(wasSelecting) {\n // ! CANCEL USER SELECTION !\n cancelSelection();\n }\n }/* else {\n if(!wasSelecting) {\n bubblesContainer.classList.add('no-select');\n setTimeout(() => {\n cancelSelection();\n bubblesContainer.classList.remove('no-select');\n cancelSelection();\n }, 100);\n }\n } */\n\n blurActiveElement();\n\n const forwards = !!size || forceSelection;\n this.onToggleSelection && this.onToggleSelection(forwards);\n\n if(!IS_MOBILE_SAFARI) {\n if(forwards) {\n appNavigationController.pushItem({\n type: this.navigationType,\n onPop: () => {\n this.cancelSelection();\n }\n });\n } else {\n appNavigationController.removeByType(this.navigationType);\n }\n }\n\n if(forceSelection) {\n this.updateContainer(forceSelection);\n }\n\n return true;\n }\n\n public cancelSelection = () => {\n this.onCancelSelection && this.onCancelSelection();\n this.selectedMids.clear();\n this.toggleSelection();\n cancelSelection();\n };\n\n public cleanup() {\n this.selectedMids.clear();\n this.toggleSelection(false);\n }\n\n protected updateElementSelection(element: HTMLElement, isSelected: boolean) {\n this.toggleElementCheckbox(element, true);\n const input = this.getCheckboxInputFromElement(element);\n input.checked = isSelected;\n\n this.toggleSelection();\n this.updateContainer();\n SetTransition(element, 'is-selected', isSelected, 200);\n }\n\n public isMidSelected(peerId: number, mid: number) {\n const set = this.selectedMids.get(peerId);\n return set?.has(mid);\n }\n\n public length() {\n return accumulateMapSet(this.selectedMids);\n }\n\n protected toggleMid(peerId: number, mid: number, unselect?: boolean) {\n let set = this.selectedMids.get(peerId);\n if(unselect || (unselect === undefined && set?.has(mid))) {\n if(set) {\n set.delete(mid);\n\n if(!set.size) {\n this.selectedMids.delete(peerId);\n }\n }\n } else {\n const diff = rootScope.config.forwarded_count_max - this.length() - 1;\n if(diff < 0) {\n toast(I18n.format('Chat.Selection.LimitToast', true));\n return false;\n /* const it = this.selectedMids.values();\n do {\n const mid = it.next().value;\n const mounted = this.appImManager.getMountedBubble(mid);\n if(mounted) {\n this.toggleByBubble(mounted.bubble);\n } else {\n const mids = this.appMessagesManager.getMidsByMid(mid);\n for(const mid of mids) {\n this.selectedMids.delete(mid);\n }\n }\n } while(this.selectedMids.size > MAX_SELECTION_LENGTH); */\n }\n\n if(!set) {\n set = new Set();\n this.selectedMids.set(peerId, set);\n }\n\n set.add(mid);\n }\n\n return true;\n }\n\n /**\n * ! Call this method only to handle deleted messages\n */\n public deleteSelectedMids(peerId: number, mids: number[]) {\n const set = this.selectedMids.get(peerId);\n if(!set) {\n return;\n }\n\n mids.forEach(mid => {\n set.delete(mid);\n });\n\n if(!set.size) {\n this.selectedMids.delete(peerId);\n }\n\n this.updateContainer();\n this.toggleSelection();\n }\n}\n\nexport class SearchSelection extends AppSelection {\n protected selectionContainer: HTMLElement;\n protected selectionCountEl: HTMLElement;\n public selectionForwardBtn: HTMLElement;\n public selectionDeleteBtn: HTMLElement;\n public selectionGotoBtn: HTMLElement;\n\n private isPrivate: boolean;\n\n constructor(private searchSuper: AppSearchSuper, appMessagesManager: AppMessagesManager) {\n super({\n appMessagesManager,\n listenElement: searchSuper.container,\n listenerSetter: new ListenerSetter(),\n verifyTarget: (e, target) => !!target && this.isSelecting,\n getElementFromTarget: (target) => findUpClassName(target, 'search-super-item'),\n targetLookupClassName: 'search-super-item',\n lookupBetweenParentClassName: 'tabs-tab',\n lookupBetweenElementsQuery: '.search-super-item'\n });\n\n this.isPrivate = !searchSuper.showSender;\n }\n\n /* public appendCheckbox(element: HTMLElement, checkboxField: CheckboxField) {\n checkboxField.label.classList.add('bubble-select-checkbox');\n\n if(element.classList.contains('document') || element.tagName === 'AUDIO-ELEMENT') {\n element.querySelector('.document, audio-element').append(checkboxField.label);\n } else {\n super.appendCheckbox(bubble, checkboxField);\n }\n } */\n\n public toggleSelection(toggleCheckboxes = true, forceSelection = false) {\n const ret = super.toggleSelection(toggleCheckboxes, forceSelection);\n\n if(ret && toggleCheckboxes) {\n const elements = Array.from(this.searchSuper.tabsContainer.querySelectorAll('.search-super-item')) as HTMLElement[];\n elements.forEach(element => {\n this.toggleElementCheckbox(element, this.isSelecting);\n });\n }\n\n return ret;\n }\n\n public toggleByElement = (element: HTMLElement) => {\n const mid = +element.dataset.mid;\n const peerId = +element.dataset.peerId;\n\n if(!this.toggleMid(peerId, mid)) {\n return;\n }\n\n this.updateElementSelection(element, this.isMidSelected(peerId, mid));\n };\n\n public toggleByMid = (peerId: number, mid: number) => {\n const element = this.searchSuper.mediaTab.contentTab.querySelector(`.search-super-item[data-peer-id=\"${peerId}\"][data-mid=\"${mid}\"]`) as HTMLElement;\n this.toggleByElement(element);\n };\n\n protected onUpdateContainer = (cantForward: boolean, cantDelete: boolean, cantSend: boolean) => {\n const length = this.length();\n replaceContent(this.selectionCountEl, i18n('messages', [length]));\n this.selectionGotoBtn.classList.toggle('hide', length !== 1);\n this.selectionForwardBtn.classList.toggle('hide', cantForward);\n this.selectionDeleteBtn && this.selectionDeleteBtn.classList.toggle('hide', cantDelete);\n };\n\n protected onToggleSelection = (forwards: boolean) => {\n SetTransition(this.searchSuper.navScrollableContainer, 'is-selecting', forwards, 200, () => {\n if(!this.isSelecting) {\n this.selectionContainer.remove();\n this.selectionContainer = \n this.selectionForwardBtn = \n this.selectionDeleteBtn = \n null;\n this.selectedText = undefined;\n }\n });\n\n SetTransition(this.searchSuper.container, 'is-selecting', forwards, 200);\n\n if(this.isSelecting) {\n if(!this.selectionContainer) {\n const BASE_CLASS = 'search-super-selection';\n this.selectionContainer = document.createElement('div');\n this.selectionContainer.classList.add(BASE_CLASS + '-container');\n\n const btnCancel = ButtonIcon(`close ${BASE_CLASS}-cancel`, {noRipple: true});\n this.listenerSetter.add(btnCancel)('click', this.cancelSelection, {once: true});\n\n this.selectionCountEl = document.createElement('div');\n this.selectionCountEl.classList.add(BASE_CLASS + '-count');\n\n this.selectionGotoBtn = ButtonIcon(`message ${BASE_CLASS}-goto`);\n\n const attachClickOptions: AttachClickOptions = {listenerSetter: this.listenerSetter};\n attachClickEvent(this.selectionGotoBtn, () => {\n const peerId = [...this.selectedMids.keys()][0];\n const mid = [...this.selectedMids.get(peerId)][0];\n this.cancelSelection();\n\n rootScope.dispatchEvent('history_focus', {\n peerId,\n mid\n });\n }, attachClickOptions);\n\n this.selectionForwardBtn = ButtonIcon(`forward ${BASE_CLASS}-forward`);\n attachClickEvent(this.selectionForwardBtn, () => {\n const obj: {[fromPeerId: number]: number[]} = {};\n for(const [fromPeerId, mids] of this.selectedMids) {\n obj[fromPeerId] = Array.from(mids);\n }\n\n new PopupForward(obj, () => {\n this.cancelSelection();\n });\n }, attachClickOptions);\n\n if(this.isPrivate) {\n this.selectionDeleteBtn = ButtonIcon(`delete danger ${BASE_CLASS}-delete`);\n attachClickEvent(this.selectionDeleteBtn, () => {\n const peerId = [...this.selectedMids.keys()][0];\n new PopupDeleteMessages(peerId, [...this.selectedMids.get(peerId)], 'chat', () => {\n this.cancelSelection();\n });\n }, attachClickOptions);\n }\n\n this.selectionContainer.append(...[\n btnCancel, \n this.selectionCountEl, \n this.selectionGotoBtn, \n this.selectionForwardBtn, \n this.selectionDeleteBtn\n ].filter(Boolean));\n\n const transitionElement = this.selectionContainer;\n transitionElement.style.opacity = '0';\n this.searchSuper.navScrollableContainer.append(transitionElement);\n\n void transitionElement.offsetLeft; // reflow\n transitionElement.style.opacity = '';\n }\n }\n };\n}\n\nexport default class ChatSelection extends AppSelection {\n protected selectionInputWrapper: HTMLElement;\n protected selectionContainer: HTMLElement;\n protected selectionCountEl: HTMLElement;\n public selectionSendNowBtn: HTMLElement;\n public selectionForwardBtn: HTMLElement;\n public selectionDeleteBtn: HTMLElement;\n\n constructor(private chat: Chat, private bubbles: ChatBubbles, private input: ChatInput, appMessagesManager: AppMessagesManager) {\n super({\n appMessagesManager,\n listenElement: bubbles.bubblesContainer,\n listenerSetter: bubbles.listenerSetter,\n getElementFromTarget: (target) => findUpClassName(target, 'grouped-item') || findUpClassName(target, 'bubble'),\n verifyTarget: (e, target) => {\n // LEFT BUTTON\n // проверка внизу нужна для того, чтобы не активировать селект если target потомок .bubble\n const bad = !this.selectedMids.size \n && !(e.target as HTMLElement).classList.contains('bubble')\n && !(e.target as HTMLElement).classList.contains('document-selection')\n && target;\n\n return !bad;\n },\n verifyMouseMoveTarget: (e, element, selecting) => {\n const bad = e.target !== element && \n !(e.target as HTMLElement).classList.contains('document-selection') && \n selecting === undefined && \n !this.selectedMids.size;\n return !bad;\n },\n verifyTouchLongPress: () => !this.chat.input.recording,\n targetLookupClassName: 'bubble',\n lookupBetweenParentClassName: 'bubbles-inner',\n lookupBetweenElementsQuery: '.bubble:not(.is-multiple-documents), .grouped-item',\n isScheduled: chat.type === 'scheduled'\n });\n }\n\n public appendCheckbox(bubble: HTMLElement, checkboxField: CheckboxField) {\n checkboxField.label.classList.add('bubble-select-checkbox');\n\n if(bubble.classList.contains('document-container')) {\n bubble.querySelector('.document, audio-element').append(checkboxField.label);\n } else {\n super.appendCheckbox(bubble, checkboxField);\n }\n }\n\n public toggleSelection(toggleCheckboxes = true, forceSelection = false) {\n const ret = super.toggleSelection(toggleCheckboxes, forceSelection);\n\n if(ret && toggleCheckboxes) {\n for(const mid in this.bubbles.bubbles) {\n const bubble = this.bubbles.bubbles[mid];\n this.toggleElementCheckbox(bubble, this.isSelecting);\n }\n }\n\n return ret;\n }\n\n public toggleElementCheckbox(bubble: HTMLElement, show: boolean) {\n if(!this.canSelectBubble(bubble)) return;\n\n const ret = super.toggleElementCheckbox(bubble, show);\n if(ret) {\n const isGrouped = bubble.classList.contains('is-grouped');\n if(isGrouped) {\n this.bubbles.getBubbleGroupedItems(bubble).forEach(item => this.toggleElementCheckbox(item, show));\n }\n }\n \n return ret;\n }\n\n public toggleByElement = (bubble: HTMLElement) => {\n if(!this.canSelectBubble(bubble)) return;\n\n const mid = +bubble.dataset.mid;\n\n const isGrouped = bubble.classList.contains('is-grouped');\n if(isGrouped) {\n if(!this.isGroupedBubbleSelected(bubble)) {\n const set = this.selectedMids.get(this.bubbles.peerId);\n if(set) {\n const mids = this.chat.getMidsByMid(mid);\n mids.forEach(mid => set.delete(mid));\n }\n }\n\n this.bubbles.getBubbleGroupedItems(bubble).forEach(this.toggleByElement);\n return;\n }\n\n if(!this.toggleMid(this.bubbles.peerId, mid)) {\n return;\n }\n\n const isGroupedItem = bubble.classList.contains('grouped-item');\n if(isGroupedItem) {\n const groupContainer = findUpClassName(bubble, 'bubble');\n const isGroupedSelected = this.isGroupedBubbleSelected(groupContainer);\n const isGroupedMidsSelected = this.isGroupedMidsSelected(mid);\n\n const willChange = isGroupedMidsSelected || isGroupedSelected;\n if(willChange) {\n this.updateElementSelection(groupContainer, isGroupedMidsSelected);\n }\n }\n\n this.updateElementSelection(bubble, this.isMidSelected(this.bubbles.peerId, mid));\n };\n\n protected toggleByMid = (peerId: number, mid: number) => {\n const mounted = this.bubbles.getMountedBubble(mid);\n if(mounted) {\n this.toggleByElement(mounted.bubble);\n }\n };\n\n public isElementShouldBeSelected(element: HTMLElement) {\n const isGrouped = element.classList.contains('is-grouped');\n return super.isElementShouldBeSelected(element) && (!isGrouped || this.isGroupedMidsSelected(+element.dataset.mid));\n }\n\n protected isGroupedBubbleSelected(bubble: HTMLElement) {\n const groupedCheckboxInput = this.getCheckboxInputFromElement(bubble);\n return groupedCheckboxInput?.checked;\n }\n\n protected isGroupedMidsSelected(mid: number) {\n const mids = this.chat.getMidsByMid(mid);\n const selectedMids = mids.filter(mid => this.isMidSelected(this.bubbles.peerId, mid));\n return mids.length === selectedMids.length;\n }\n\n protected getCheckboxInputFromElement(bubble: HTMLElement) {\n /* let perf = performance.now();\n let checkbox = bubble.firstElementChild.tagName === 'LABEL' && bubble.firstElementChild.firstElementChild as HTMLInputElement;\n console.log('getCheckboxInputFromBubble firstElementChild time:', performance.now() - perf);\n \n perf = performance.now();\n checkbox = bubble.querySelector('label input');\n console.log('getCheckboxInputFromBubble querySelector time:', performance.now() - perf); */\n /* let perf = performance.now();\n let contains = bubble.classList.contains('document-container');\n console.log('getCheckboxInputFromBubble classList time:', performance.now() - perf);\n \n perf = performance.now();\n contains = bubble.className.includes('document-container');\n console.log('getCheckboxInputFromBubble className time:', performance.now() - perf); */\n \n return bubble.classList.contains('document-container') ? \n bubble.querySelector('label input') as HTMLInputElement : \n super.getCheckboxInputFromElement(bubble);\n }\n\n public canSelectBubble(bubble: HTMLElement) {\n return !bubble.classList.contains('service') && !bubble.classList.contains('is-sending') && !bubble.classList.contains('bubble-first');\n }\n\n protected onToggleSelection = (forwards: boolean) => {\n let transform = '', borderRadius = '';\n if(forwards) {\n const p = this.input.rowsWrapper.parentElement;\n const fakeSelectionWrapper = p.querySelector('.fake-selection-wrapper');\n const fakeRowsWrapper = p.querySelector('.fake-rows-wrapper');\n const fakeSelectionRect = fakeSelectionWrapper.getBoundingClientRect();\n const fakeRowsRect = fakeRowsWrapper.getBoundingClientRect();\n const widthFrom = fakeRowsRect.width;\n const widthTo = fakeSelectionRect.width;\n\n if(widthFrom !== widthTo) {\n const scale = (widthTo/* - 8 */) / widthFrom;\n const initTranslateX = (widthFrom - widthTo) / 2;\n const needTranslateX = fakeSelectionRect.left - fakeRowsRect.left - initTranslateX;\n transform = `translateX(${needTranslateX}px) scaleX(${scale})`;\n\n if(scale < 1) {\n const br = 12;\n borderRadius = '' + (br + br * (1 - scale)) + 'px';\n }\n //scale = widthTo / widthFrom;\n }\n }\n\n SetTransition(this.input.rowsWrapper, 'is-centering', forwards, 200);\n this.input.rowsWrapper.style.transform = transform;\n this.input.rowsWrapper.style.borderRadius = borderRadius;\n SetTransition(this.listenElement, 'is-selecting', forwards, 200, () => {\n if(!this.isSelecting) {\n this.selectionInputWrapper.remove();\n this.selectionInputWrapper = \n this.selectionContainer = \n this.selectionSendNowBtn = \n this.selectionForwardBtn = \n this.selectionDeleteBtn = \n null;\n this.selectedText = undefined;\n }\n \n fastRaf(() => {\n this.bubbles.onScroll();\n });\n });\n\n //const chatInput = this.appImManager.chatInput;\n\n if(this.isSelecting) {\n if(!this.selectionContainer) {\n this.selectionInputWrapper = document.createElement('div');\n this.selectionInputWrapper.classList.add('chat-input-wrapper', 'selection-wrapper');\n\n this.selectionContainer = document.createElement('div');\n this.selectionContainer.classList.add('selection-container');\n\n const attachClickOptions: AttachClickOptions = {listenerSetter: this.listenerSetter};\n const btnCancel = ButtonIcon('close', {noRipple: true});\n attachClickEvent(btnCancel, this.cancelSelection, {once: true, listenerSetter: this.listenerSetter});\n\n this.selectionCountEl = document.createElement('div');\n this.selectionCountEl.classList.add('selection-container-count');\n\n if(this.chat.type === 'scheduled') {\n this.selectionSendNowBtn = Button('btn-primary btn-transparent btn-short text-bold selection-container-send', {icon: 'send2'});\n this.selectionSendNowBtn.append(i18n('MessageScheduleSend'));\n attachClickEvent(this.selectionSendNowBtn, () => {\n new PopupSendNow(this.bubbles.peerId, [...this.selectedMids.get(this.bubbles.peerId)], () => {\n this.cancelSelection();\n });\n }, attachClickOptions);\n } else {\n this.selectionForwardBtn = Button('btn-primary btn-transparent text-bold selection-container-forward', {icon: 'forward'});\n this.selectionForwardBtn.append(i18n('Forward'));\n attachClickEvent(this.selectionForwardBtn, () => {\n const obj: {[fromPeerId: number]: number[]} = {};\n for(const [fromPeerId, mids] of this.selectedMids) {\n obj[fromPeerId] = Array.from(mids);\n }\n\n new PopupForward(obj, () => {\n this.cancelSelection();\n });\n }, attachClickOptions);\n }\n\n this.selectionDeleteBtn = Button('btn-primary btn-transparent danger text-bold selection-container-delete', {icon: 'delete'});\n this.selectionDeleteBtn.append(i18n('Delete'));\n attachClickEvent(this.selectionDeleteBtn, () => {\n new PopupDeleteMessages(this.bubbles.peerId, [...this.selectedMids.get(this.bubbles.peerId)], this.chat.type, () => {\n this.cancelSelection();\n });\n }, attachClickOptions);\n\n this.selectionContainer.append(...[\n btnCancel, \n this.selectionCountEl, \n this.selectionSendNowBtn, \n this.selectionForwardBtn, \n this.selectionDeleteBtn\n ].filter(Boolean));\n\n this.selectionInputWrapper.style.opacity = '0';\n this.selectionInputWrapper.append(this.selectionContainer);\n this.input.rowsWrapper.parentElement.append(this.selectionInputWrapper);\n\n void this.selectionInputWrapper.offsetLeft; // reflow\n this.selectionInputWrapper.style.opacity = '';\n }\n }\n };\n\n protected onUpdateContainer = (cantForward: boolean, cantDelete: boolean, cantSend: boolean) => {\n replaceContent(this.selectionCountEl, i18n('messages', [this.length()]));\n this.selectionSendNowBtn && this.selectionSendNowBtn.toggleAttribute('disabled', cantSend);\n this.selectionForwardBtn && this.selectionForwardBtn.toggleAttribute('disabled', cantForward);\n this.selectionDeleteBtn.toggleAttribute('disabled', cantDelete);\n };\n\n protected onCancelSelection = () => {\n for(const [peerId, mids] of this.selectedMids) {\n for(const mid of mids) {\n const mounted = this.bubbles.getMountedBubble(mid);\n if(mounted) {\n //this.toggleByBubble(mounted.message.grouped_id ? mounted.bubble.querySelector(`.grouped-item[data-mid=\"${mid}\"]`) : mounted.bubble);\n this.toggleByElement(mounted.bubble);\n }\n /* const bubble = this.appImManager.bubbles[mid];\n if(bubble) {\n this.toggleByBubble(bubble);\n } */\n }\n }\n };\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function getSelectedText(): string {\r\n if(window.getSelection) {\r\n return window.getSelection().toString();\r\n // @ts-ignore\r\n } else if(document.selection) {\r\n // @ts-ignore\r\n return document.selection.createRange().text;\r\n }\r\n \r\n return '';\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { copy, getObjectKeysAndSort, safeAssign } from \"../helpers/object\";\nimport { escapeRegExp, limitSymbols } from \"../helpers/string\";\nimport appChatsManager from \"../lib/appManagers/appChatsManager\";\nimport appDialogsManager from \"../lib/appManagers/appDialogsManager\";\nimport appMessagesManager, { MyInputMessagesFilter, MyMessage } from \"../lib/appManagers/appMessagesManager\";\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\nimport appStateManager from \"../lib/appManagers/appStateManager\";\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\nimport { logger } from \"../lib/logger\";\nimport RichTextProcessor from \"../lib/richtextprocessor\";\nimport rootScope from \"../lib/rootScope\";\nimport { SearchGroup, SearchGroupType } from \"./appSearch\";\nimport { horizontalMenu } from \"./horizontalMenu\";\nimport LazyLoadQueue from \"./lazyLoadQueue\";\nimport { attachContextMenuListener, openBtnMenu, positionMenu, putPreloader } from \"./misc\";\nimport { ripple } from \"./ripple\";\nimport Scrollable, { ScrollableX } from \"./scrollable\";\nimport { wrapDocument, wrapPhoto, wrapVideo } from \"./wrappers\";\nimport useHeavyAnimationCheck, { getHeavyAnimationPromise } from \"../hooks/useHeavyAnimationCheck\";\nimport I18n, { LangPackKey, i18n } from \"../lib/langPack\";\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\nimport { getMiddleware } from \"../helpers/middleware\";\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\nimport { ChannelParticipant, ChatFull, ChatParticipant, ChatParticipants } from \"../layer\";\nimport SortedUserList from \"./sortedUserList\";\nimport findUpTag from \"../helpers/dom/findUpTag\";\nimport appSidebarRight from \"./sidebarRight\";\nimport mediaSizes from \"../helpers/mediaSizes\";\nimport appImManager from \"../lib/appManagers/appImManager\";\nimport positionElementByIndex from \"../helpers/dom/positionElementByIndex\";\nimport cleanSearchText from \"../helpers/cleanSearchText\";\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\nimport handleTabSwipe from \"../helpers/dom/handleTabSwipe\";\nimport windowSize from \"../helpers/windowSize\";\nimport { formatPhoneNumber } from \"../helpers/formatPhoneNumber\";\nimport ButtonMenu, { ButtonMenuItemOptions } from \"./buttonMenu\";\nimport PopupForward from \"./popups/forward\";\nimport PopupDeleteMessages from \"./popups/deleteMessages\";\nimport Row from \"./row\";\nimport htmlToDocumentFragment from \"../helpers/dom/htmlToDocumentFragment\";\nimport { SearchSelection } from \"./chat/selection\";\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\nimport { attachClickEvent, simulateClickEvent } from \"../helpers/dom/clickEvent\";\nimport { MyDocument } from \"../lib/appManagers/appDocsManager\";\nimport AppMediaViewer from \"./appMediaViewer\";\n\n//const testScroll = false;\n\nexport type SearchSuperType = MyInputMessagesFilter/* | 'members' */;\nexport type SearchSuperContext = {\n peerId: number,\n inputFilter: {_: MyInputMessagesFilter},\n query?: string,\n maxId?: number,\n folderId?: number,\n threadId?: number,\n date?: number,\n nextRate?: number,\n minDate?: number,\n maxDate?: number\n};\n\nexport type SearchSuperMediaType = 'members' | 'media' | 'files' | 'links' | 'music' | 'chats' | 'voice';\nexport type SearchSuperMediaTab = {\n inputFilter: SearchSuperType,\n name: LangPackKey,\n type: SearchSuperMediaType,\n contentTab?: HTMLElement,\n menuTab?: HTMLElement,\n scroll?: {scrollTop: number, scrollHeight: number}\n};\n\nclass SearchContextMenu {\n private buttons: (ButtonMenuItemOptions & {verify?: () => boolean, withSelection?: true})[];\n private element: HTMLElement;\n private target: HTMLElement;\n private peerId: number;\n private mid: number;\n private isSelected: boolean;\n\n constructor(\n private attachTo: HTMLElement,\n private searchSuper: AppSearchSuper\n ) {\n const onContextMenu = (e: MouseEvent) => {\n if(this.init) {\n this.init();\n this.init = null;\n }\n\n let item: HTMLElement;\n try {\n item = findUpClassName(e.target, 'search-super-item');\n } catch(e) {}\n\n if(!item) return;\n\n if(e instanceof MouseEvent) e.preventDefault();\n if(this.element.classList.contains('active')) {\n return false;\n }\n if(e instanceof MouseEvent) e.cancelBubble = true;\n\n this.target = item;\n this.peerId = +item.dataset.peerId;\n this.mid = +item.dataset.mid;\n this.isSelected = searchSuper.selection.isMidSelected(this.peerId, this.mid);\n\n this.buttons.forEach(button => {\n let good: boolean;\n\n if(this.isSelected && !button.withSelection) {\n good = false;\n } else {\n good = button.verify ? button.verify() : true;\n }\n\n button.element.classList.toggle('hide', !good);\n });\n\n item.classList.add('menu-open');\n\n positionMenu(e, this.element);\n openBtnMenu(this.element, () => {\n item.classList.remove('menu-open');\n });\n };\n\n if(IS_TOUCH_SUPPORTED) {\n\n } else {\n attachContextMenuListener(attachTo, onContextMenu as any);\n }\n }\n\n private init() {\n this.buttons = [{\n icon: 'forward',\n text: 'Forward',\n onClick: this.onForwardClick\n }, {\n icon: 'forward',\n text: 'Message.Context.Selection.Forward',\n onClick: this.onForwardClick,\n verify: () => this.isSelected && \n !this.searchSuper.selection.selectionForwardBtn.classList.contains('hide'),\n withSelection: true\n }, {\n icon: 'message',\n text: 'Message.Context.Goto',\n onClick: this.onGotoClick,\n withSelection: true\n }, {\n icon: 'select',\n text: 'Message.Context.Select',\n onClick: this.onSelectClick\n }, {\n icon: 'select',\n text: 'Message.Context.Selection.Clear',\n onClick: this.onClearSelectionClick,\n verify: () => this.isSelected,\n withSelection: true\n }, {\n icon: 'delete danger',\n text: 'Delete',\n onClick: this.onDeleteClick,\n verify: () => appMessagesManager.canDeleteMessage(appMessagesManager.getMessageByPeer(this.peerId, this.mid))\n }, {\n icon: 'delete danger',\n text: 'Message.Context.Selection.Delete',\n onClick: this.onDeleteClick,\n verify: () => this.isSelected && !this.searchSuper.selection.selectionDeleteBtn.classList.contains('hide'),\n withSelection: true\n }];\n\n this.element = ButtonMenu(this.buttons);\n this.element.classList.add('search-contextmenu', 'contextmenu');\n document.getElementById('page-chats').append(this.element);\n }\n\n private onGotoClick = () => {\n rootScope.dispatchEvent('history_focus', {\n peerId: this.peerId,\n mid: this.mid,\n threadId: this.searchSuper.searchContext.threadId\n });\n };\n\n private onForwardClick = () => {\n if(this.searchSuper.selection.isSelecting) {\n simulateClickEvent(this.searchSuper.selection.selectionForwardBtn);\n } else {\n new PopupForward({\n [this.peerId]: [this.mid]\n });\n }\n };\n\n private onSelectClick = () => {\n this.searchSuper.selection.toggleByElement(this.target);\n };\n\n private onClearSelectionClick = () => {\n this.searchSuper.selection.cancelSelection();\n };\n\n private onDeleteClick = () => {\n if(this.searchSuper.selection.isSelecting) {\n simulateClickEvent(this.searchSuper.selection.selectionDeleteBtn);\n } else {\n new PopupDeleteMessages(this.peerId, [this.mid], 'chat');\n }\n };\n}\n\nexport default class AppSearchSuper {\n public tabs: {[t in SearchSuperType]: HTMLDivElement} = {} as any;\n\n public mediaTab: SearchSuperMediaTab;\n\n public container: HTMLElement;\n public nav: HTMLElement;\n public navScrollableContainer: HTMLDivElement;\n public tabsContainer: HTMLElement;\n public navScrollable: ScrollableX;\n private tabsMenu: HTMLElement;\n private prevTabId = -1;\n \n private lazyLoadQueue = new LazyLoadQueue();\n public middleware = getMiddleware();\n\n public historyStorage: Partial<{[type in SearchSuperType]: {mid: number, peerId: number}[]}> = {};\n public usedFromHistory: Partial<{[type in SearchSuperType]: number}> = {};\n public urlsToRevoke: string[] = [];\n\n public searchContext: SearchSuperContext;\n public loadMutex: Promise<any> = Promise.resolve();\n\n private nextRates: Partial<{[type in SearchSuperType]: number}> = {};\n private loadPromises: Partial<{[type in SearchSuperType]: Promise<void>}> = {};\n private loaded: Partial<{[type in SearchSuperType]: boolean}> = {};\n private loadedChats = false;\n private firstLoad = true;\n\n private log = logger('SEARCH-SUPER');\n public selectTab: ReturnType<typeof horizontalMenu>;\n \n private monthContainers: Partial<{\n [type in SearchSuperType]: {\n [timestamp: number]: {\n container: HTMLElement,\n items: HTMLElement\n }\n }\n }> = {};\n\n private searchGroupMedia: SearchGroup;\n\n public mediaTabsMap: Map<SearchSuperMediaType, SearchSuperMediaTab> = new Map();\n\n private membersList: SortedUserList;\n\n private skipScroll: boolean;\n\n // * arguments\n public mediaTabs: SearchSuperMediaTab[];\n public scrollable: Scrollable;\n public searchGroups?: {[group in SearchGroupType]: SearchGroup};\n public asChatList? = false;\n public groupByMonth? = true;\n public hideEmptyTabs? = true;\n public onChangeTab?: (mediaTab: SearchSuperMediaTab) => void;\n public showSender? = false;\n\n private searchContextMenu: SearchContextMenu;\n public selection: SearchSelection;\n\n constructor(options: Pick<AppSearchSuper, 'mediaTabs' | 'scrollable' | 'searchGroups' | 'asChatList' | 'groupByMonth' | 'hideEmptyTabs' | 'onChangeTab' | 'showSender'>) {\n safeAssign(this, options);\n\n this.container = document.createElement('div');\n this.container.classList.add('search-super');\n\n this.searchContextMenu = new SearchContextMenu(this.container, this);\n this.selection = new SearchSelection(this, appMessagesManager);\n\n const navScrollableContainer = this.navScrollableContainer = document.createElement('div');\n navScrollableContainer.classList.add('search-super-tabs-scrollable', 'menu-horizontal-scrollable', 'sticky');\n\n const navScrollable = this.navScrollable = new ScrollableX(navScrollableContainer);\n navScrollable.container.classList.add('search-super-nav-scrollable');\n\n const nav = this.nav = document.createElement('nav');\n nav.classList.add('search-super-tabs', 'menu-horizontal-div');\n this.tabsMenu = nav;\n\n navScrollable.container.append(nav);\n\n for(const mediaTab of this.mediaTabs) {\n const menuTab = document.createElement('div');\n menuTab.classList.add('menu-horizontal-div-item');\n const span = document.createElement('span');\n const i = document.createElement('i');\n\n span.append(i18n(mediaTab.name));\n span.append(i);\n\n menuTab.append(span);\n\n ripple(menuTab);\n\n this.tabsMenu.append(menuTab);\n\n this.mediaTabsMap.set(mediaTab.type, mediaTab);\n\n mediaTab.menuTab = menuTab;\n }\n\n this.tabsContainer = document.createElement('div');\n this.tabsContainer.classList.add('search-super-tabs-container', 'tabs-container');\n\n if(IS_TOUCH_SUPPORTED) {\n handleTabSwipe(this.tabsContainer, (next) => {\n const prevId = this.selectTab.prevId();\n this.selectTab(next ? prevId + 1 : prevId - 1);\n });\n }\n\n for(const mediaTab of this.mediaTabs) {\n const container = document.createElement('div');\n container.classList.add('search-super-container-' + mediaTab.type, 'tabs-tab');\n\n const content = document.createElement('div');\n content.classList.add('search-super-content-' + mediaTab.type);\n\n container.append(content);\n\n this.tabsContainer.append(container);\n\n this.tabs[mediaTab.inputFilter] = content;\n\n mediaTab.contentTab = content;\n }\n\n this.container.append(navScrollableContainer, this.tabsContainer);\n\n // * construct end\n\n this.searchGroupMedia = new SearchGroup(false, 'messages', true);\n\n this.scrollable.onScrolledBottom = () => {\n if(this.mediaTab.contentTab && this.mediaTab.contentTab.childElementCount/* && false */) {\n //this.log('onScrolledBottom will load media');\n this.load(true);\n }\n };\n //this.scroll.attachSentinels(undefined, 400);\n\n this.selectTab = horizontalMenu(this.tabsMenu, this.tabsContainer, (id, tabContent, animate) => {\n if(this.prevTabId === id && !this.skipScroll) {\n this.scrollable.scrollIntoViewNew(this.container, 'start');\n return;\n }\n \n const newMediaTab = this.mediaTabs[id];\n if(this.onChangeTab) {\n this.onChangeTab(newMediaTab);\n }\n \n const fromMediaTab = this.mediaTab;\n this.mediaTab = newMediaTab;\n\n if(this.prevTabId !== -1 && animate) {\n this.onTransitionStart();\n }\n\n if(this.skipScroll) {\n this.skipScroll = false;\n } else {\n const offsetTop = this.container.offsetTop;\n let scrollTop = this.scrollable.scrollTop;\n if(scrollTop < offsetTop) {\n this.scrollable.scrollIntoViewNew(this.container, 'start');\n scrollTop = offsetTop;\n }\n \n fromMediaTab.scroll = {scrollTop: scrollTop, scrollHeight: this.scrollable.scrollHeight};\n \n if(newMediaTab.scroll === undefined) {\n const rect = this.container.getBoundingClientRect();\n const rect2 = this.container.parentElement.getBoundingClientRect();\n const diff = rect.y - rect2.y;\n \n if(scrollTop > diff) {\n newMediaTab.scroll = {scrollTop: diff, scrollHeight: 0};\n }\n }\n \n if(newMediaTab.scroll) {\n const diff = fromMediaTab.scroll.scrollTop - newMediaTab.scroll.scrollTop;\n //console.log('what you gonna do', this.goingHard, diff);\n \n //this.scrollable.scrollTop = scrollTop;\n if(diff/* && diff < 0 */) {\n /* if(diff > -(fromMediaTab.contentTab.scrollHeight + this.nav.scrollHeight)) {\n fromMediaTab.contentTab.style.transform = `translateY(${diff}px)`;\n this.scrollable.scrollTop = scrollTop - diff;\n } else { */\n newMediaTab.contentTab.style.transform = `translateY(${diff}px)`;\n //}\n }\n }\n }\n \n /* if(this.prevTabId !== -1 && nav.offsetTop) {\n this.scrollable.scrollTop -= nav.offsetTop;\n } */\n\n /* this.log('setVirtualContainer', id, this.sharedMediaSelected, this.sharedMediaSelected.childElementCount);\n this.scroll.setVirtualContainer(this.sharedMediaSelected); */\n\n if(this.prevTabId !== -1 && !newMediaTab.contentTab.childElementCount) { // quick brown fix\n //this.contentContainer.classList.remove('loaded');\n this.load(true);\n }\n\n this.prevTabId = id;\n }, () => {\n this.scrollable.onScroll();\n \n //console.log('what y', this.tabSelected.style.transform);\n if(this.mediaTab.scroll !== undefined) {\n this.mediaTab.contentTab.style.transform = '';\n this.scrollable.scrollTop = this.mediaTab.scroll.scrollTop;\n }\n\n this.onTransitionEnd();\n }, undefined, navScrollable);\n\n attachClickEvent(this.tabsContainer, (e) => {\n if(this.selection.isSelecting) {\n cancelEvent(e);\n this.selection.toggleByElement(findUpClassName(e.target, 'search-super-item'));\n }\n }, {capture: true, passive: false});\n \n const onMediaClick = (className: string, targetClassName: string, inputFilter: MyInputMessagesFilter, e: MouseEvent) => {\n const target = findUpClassName(e.target as HTMLDivElement, className);\n if(!target) return;\n \n const mid = +target.dataset.mid;\n if(!mid) {\n this.log.warn('no messageId by click on target:', target);\n return;\n }\n\n const peerId = +target.dataset.peerId;\n\n const targets = (Array.from(this.tabs[inputFilter].querySelectorAll('.' + targetClassName)) as HTMLElement[]).map(el => {\n const containerEl = findUpClassName(el, className);\n return {\n element: el, \n mid: +containerEl.dataset.mid, \n peerId: +containerEl.dataset.peerId\n };\n });\n\n //const ids = Object.keys(this.mediaDivsByIds).map(k => +k).sort((a, b) => a - b);\n const idx = targets.findIndex(item => item.mid === mid && item.peerId === peerId);\n \n const message = appMessagesManager.getMessageByPeer(peerId, mid);\n new AppMediaViewer()\n .setSearchContext(this.copySearchContext(inputFilter))\n .openMedia(message, targets[idx].element, 0, false, targets.slice(0, idx), targets.slice(idx + 1));\n };\n\n attachClickEvent(this.tabs.inputMessagesFilterPhotoVideo, onMediaClick.bind(null, 'grid-item', 'grid-item', 'inputMessagesFilterPhotoVideo'));\n attachClickEvent(this.tabs.inputMessagesFilterDocument, onMediaClick.bind(null, 'document-with-thumb', 'media-container', 'inputMessagesFilterDocument'));\n\n /* attachClickEvent(this.tabs.inputMessagesFilterUrl, (e) => {\n const target = e.target as HTMLElement;\n if(target.tagName === 'A') {\n return;\n }\n\n try {\n const a = findUpClassName(target, 'row').querySelector('.anchor-url:last-child') as HTMLAnchorElement;\n a.click();\n } catch(err) {}\n }); */\n\n this.mediaTab = this.mediaTabs[0];\n\n useHeavyAnimationCheck(() => {\n this.lazyLoadQueue.lock();\n }, () => {\n this.lazyLoadQueue.unlockAndRefresh(); // ! maybe not so efficient\n });\n }\n\n private onTransitionStart = () => {\n this.container.classList.add('sliding');\n };\n\n private onTransitionEnd = () => {\n this.container.classList.remove('sliding');\n };\n\n public filterMessagesByType(messages: any[], type: SearchSuperType): MyMessage[] {\n if(type === 'inputMessagesFilterEmpty') return messages;\n\n if(type !== 'inputMessagesFilterUrl') {\n messages = messages.filter(message => !!message.media);\n }\n\n /* if(!this.peerId) {\n messages = messages.filter(message => {\n if(message.peerId === rootScope.myId) {\n return true;\n }\n\n const dialog = appMessagesManager.getDialogByPeerId(message.fromId)[0];\n return dialog && dialog.folder_id === 0;\n });\n } */\n\n let filtered: any[] = [];\n\n switch(type) {\n case 'inputMessagesFilterPhotoVideo': {\n for(let message of messages) {\n let media = message.media.photo || message.media.document || (message.media.webpage && message.media.webpage.document);\n if(!media) {\n //this.log('no media!', message);\n continue;\n }\n \n if(media._ === 'document' && media.type !== 'video'/* && media.type !== 'gif' */) {\n //this.log('broken video', media);\n continue;\n }\n\n filtered.push(message);\n }\n \n break;\n }\n\n case 'inputMessagesFilterDocument': {\n for(let message of messages) {\n if(!message.media.document || ['voice', 'audio', 'gif', 'sticker', 'round'].includes(message.media.document.type)) {\n continue;\n }\n \n filtered.push(message);\n }\n break;\n }\n\n case 'inputMessagesFilterUrl': {\n //this.log('inputMessagesFilterUrl', messages);\n for(let message of messages) {\n //if((message.media.webpage && message.media.webpage._ !== 'webPageEmpty')) {\n filtered.push(message);\n //}\n }\n \n break;\n }\n\n case 'inputMessagesFilterMusic': {\n for(let message of messages) {\n if(!message.media.document || message.media.document.type !== 'audio') {\n continue;\n }\n\n filtered.push(message);\n }\n\n break;\n }\n\n case 'inputMessagesFilterVoice': {\n for(let message of messages) {\n if(!message.media.document || message.media.document.type !== 'voice') {\n continue;\n }\n\n filtered.push(message);\n }\n\n break;\n }\n\n case 'inputMessagesFilterRoundVoice': {\n for(let message of messages) {\n if(!message.media.document || !(['voice', 'round'] as MyDocument['type'][]).includes(message.media.document.type)) {\n continue;\n }\n\n filtered.push(message);\n }\n\n break;\n }\n\n default:\n break;\n }\n\n return filtered;\n }\n \n public async performSearchResult(messages: any[], mediaTab: SearchSuperMediaTab, append = true) {\n const elemsToAppend: {element: HTMLElement, message: any}[] = [];\n const sharedMediaDiv: HTMLElement = mediaTab.contentTab;\n const promises: Promise<any>[] = [];\n const middleware = this.middleware.get();\n let inputFilter = mediaTab.inputFilter;\n\n await getHeavyAnimationPromise();\n \n let searchGroup: SearchGroup;\n if(inputFilter === 'inputMessagesFilterPhotoVideo' && !!this.searchContext.query.trim()) {\n inputFilter = 'inputMessagesFilterEmpty';\n searchGroup = this.searchGroupMedia;\n sharedMediaDiv.append(searchGroup.container);\n } else if(inputFilter === 'inputMessagesFilterEmpty') {\n searchGroup = this.searchGroups.messages;\n }\n\n // https://core.telegram.org/type/MessagesFilter\n switch(inputFilter) {\n case 'inputMessagesFilterEmpty': {\n for(const message of messages) {\n const {dialog, dom} = appDialogsManager.addDialogNew({\n dialog: message.peerId, \n container: searchGroup.list, \n drawStatus: false,\n avatarSize: 54\n });\n appDialogsManager.setLastMessage(dialog, message, dom, this.searchContext.query);\n }\n\n if(searchGroup.list.childElementCount) {\n searchGroup.setActive();\n }\n break;\n }\n\n case 'inputMessagesFilterPhotoVideo': {\n for(const message of messages) {\n const media = message.media.photo || message.media.document || (message.media.webpage && message.media.webpage.document);\n\n const div = document.createElement('div');\n div.classList.add('grid-item');\n //this.log(message, photo);\n\n let wrapped: ReturnType<typeof wrapPhoto>;\n const size = appPhotosManager.choosePhotoSize(media, 200, 200);\n if(media._ !== 'photo') {\n wrapped = wrapVideo({\n doc: media,\n message,\n container: div,\n boxWidth: 0,\n boxHeight: 0,\n lazyLoadQueue: this.lazyLoadQueue,\n middleware,\n onlyPreview: true,\n withoutPreloader: true,\n noPlayButton: true,\n size\n }).thumb;\n } else {\n wrapped = wrapPhoto({\n photo: media,\n message,\n container: div,\n boxWidth: 0,\n boxHeight: 0,\n lazyLoadQueue: this.lazyLoadQueue,\n middleware,\n withoutPreloader: true,\n noBlur: true,\n size\n });\n }\n\n [wrapped.images.thumb, wrapped.images.full].filter(Boolean).forEach(image => {\n image.classList.add('grid-item-media');\n });\n\n promises.push(wrapped.loadPromises.thumb);\n\n elemsToAppend.push({element: div, message});\n }\n \n break;\n }\n \n case 'inputMessagesFilterVoice':\n case 'inputMessagesFilterRoundVoice':\n case 'inputMessagesFilterMusic':\n case 'inputMessagesFilterDocument': {\n for(const message of messages) {\n const showSender = this.showSender || (['voice', 'round'] as MyDocument['type'][]).includes(message.media.document.type);\n const div = wrapDocument({\n message,\n withTime: !showSender,\n fontWeight: 400,\n voiceAsMusic: true,\n showSender,\n searchContext: this.copySearchContext(inputFilter),\n lazyLoadQueue: this.lazyLoadQueue,\n noAutoDownload: true\n });\n\n if((['audio', 'voice', 'round'] as MyDocument['type'][]).includes(message.media.document.type)) {\n div.classList.add('audio-48');\n }\n\n elemsToAppend.push({element: div, message});\n }\n break;\n }\n \n case 'inputMessagesFilterUrl': {\n for(let message of messages) {\n let webpage: any;\n\n if(message.media?.webpage && message.media.webpage._ !== 'webPageEmpty') {\n webpage = message.media.webpage;\n } else {\n const entity = message.totalEntities ? message.totalEntities.find((e: any) => e._ === 'messageEntityUrl' || e._ === 'messageEntityTextUrl') : null;\n let url: string, display_url: string, sliced: string;\n\n if(!entity) {\n //this.log.error('NO ENTITY:', message);\n const match = RichTextProcessor.matchUrl(message.message);\n if(!match) {\n //this.log.error('NO ENTITY AND NO MATCH:', message);\n continue;\n }\n\n url = match[0];\n } else {\n sliced = message.message.slice(entity.offset, entity.offset + entity.length);\n }\n\n if(entity?._ === 'messageEntityTextUrl') {\n url = entity.url;\n //display_url = sliced;\n } else {\n url = url || sliced;\n }\n\n display_url = url;\n\n const same = message.message === url;\n if(!url.match(/^(ftp|http|https):\\/\\//)) {\n display_url = 'https://' + url;\n url = url.includes('@') ? url : 'https://' + url;\n }\n\n display_url = new URL(display_url).hostname;\n\n webpage = {\n url,\n display_url\n };\n\n if(!same) {\n webpage.description = message.message;\n webpage.rDescription = RichTextProcessor.wrapRichText(limitSymbols(message.message, 150, 180));\n }\n }\n\n let div = document.createElement('div');\n \n let previewDiv = document.createElement('div');\n previewDiv.classList.add('preview', 'row-media');\n \n //this.log('wrapping webpage', webpage);\n \n if(webpage.photo) {\n const res = wrapPhoto({\n container: previewDiv,\n message: null,\n photo: webpage.photo,\n boxWidth: 0,\n boxHeight: 0,\n withoutPreloader: true,\n lazyLoadQueue: this.lazyLoadQueue,\n middleware,\n size: appPhotosManager.choosePhotoSize(webpage.photo, 60, 60, false),\n loadPromises: promises,\n noBlur: true\n });\n } else {\n previewDiv.classList.add('empty');\n previewDiv.innerHTML = RichTextProcessor.getAbbreviation(webpage.title || webpage.display_url || webpage.description || webpage.url, true);\n }\n \n let title = webpage.rTitle || '';\n let subtitle = webpage.rDescription || '';\n\n const subtitleFragment = htmlToDocumentFragment(subtitle);\n const aFragment = htmlToDocumentFragment(RichTextProcessor.wrapRichText(webpage.url || ''));\n const a = aFragment.firstElementChild;\n if(a instanceof HTMLAnchorElement) {\n a.innerText = decodeURIComponent(a.href);\n }\n\n if(subtitleFragment.firstChild) {\n subtitleFragment.append('\\n');\n }\n\n subtitleFragment.append(a);\n\n if(this.showSender) {\n subtitleFragment.append('\\n', appMessagesManager.wrapSenderToPeer(message));\n }\n \n if(!title) {\n //title = new URL(webpage.url).hostname;\n title = RichTextProcessor.wrapPlainText(webpage.display_url.split('/', 1)[0]);\n }\n\n const row = new Row({\n title,\n titleRight: appMessagesManager.wrapSentTime(message),\n subtitle: subtitleFragment,\n havePadding: true,\n clickable: true,\n noRipple: true\n });\n\n /* const mediaDiv = document.createElement('div');\n mediaDiv.classList.add('row-media'); */\n\n row.container.append(previewDiv);\n \n /* ripple(div);\n div.append(previewDiv);\n div.insertAdjacentHTML('beforeend', `\n <div class=\"title\">${title}${titleAdditionHTML}</div>\n <div class=\"subtitle\">${subtitle}</div>\n <div class=\"url\">${url}</div>\n ${sender}\n `); */\n \n if(row.container.innerText.trim().length) {\n elemsToAppend.push({element: row.container, message});\n }\n }\n \n break;\n }\n\n default:\n //this.log.warn('death is my friend', messages);\n break;\n }\n\n if(this.loadMutex) {\n promises.push(this.loadMutex);\n }\n\n if(promises.length) {\n await Promise.all(promises);\n if(!middleware()) {\n //this.log.warn('peer changed');\n return;\n }\n }\n \n if(elemsToAppend.length) {\n const method = append ? 'append' : 'prepend';\n elemsToAppend.forEach(details => {\n const {element, message} = details;\n const monthContainer = this.getMonthContainerByTimestamp(this.groupByMonth ? message.date : 0, inputFilter);\n element.classList.add('search-super-item');\n element.dataset.mid = '' + message.mid;\n element.dataset.peerId = '' + message.peerId;\n monthContainer.items[method](element);\n\n if(this.selection.isSelecting) {\n this.selection.toggleElementCheckbox(element, true);\n }\n });\n }\n \n //if(type !== 'inputMessagesFilterEmpty') {\n this.afterPerforming(inputFilter === 'inputMessagesFilterEmpty' ? 1 : messages.length, sharedMediaDiv);\n //}\n }\n\n private afterPerforming(length: number, contentTab: HTMLElement) {\n if(contentTab) {\n const parent = contentTab.parentElement;\n Array.from(parent.children).slice(1).forEach(child => {\n child.remove();\n });\n\n //this.contentContainer.classList.add('loaded');\n\n if(!length && !contentTab.childElementCount) {\n const div = document.createElement('div');\n div.innerText = 'Nothing interesting here yet...';\n div.classList.add('position-center', 'text-center', 'content-empty', 'no-select');\n\n parent.append(div);\n }\n }\n }\n\n private loadChats() {\n const renderedPeerIds: Set<number> = new Set();\n const middleware = this.middleware.get();\n\n for(let i in this.searchGroups) {\n const group = this.searchGroups[i as SearchGroupType];\n this.tabs.inputMessagesFilterEmpty.append(group.container);\n group.clear();\n }\n\n const query = this.searchContext.query;\n if(query) {\n const setResults = (results: number[], group: SearchGroup, showMembersCount = false) => {\n results.forEach((peerId) => {\n if(renderedPeerIds.has(peerId)) {\n return;\n }\n \n renderedPeerIds.add(peerId);\n \n const peer = appPeersManager.getPeer(peerId);\n \n //////////this.log('contacts peer', peer);\n \n const {dom} = appDialogsManager.addDialogNew({\n dialog: peerId, \n container: group.list, \n drawStatus: false,\n avatarSize: 48,\n autonomous: group.autonomous\n });\n \n if(showMembersCount && (peer.participants_count || peer.participants)) {\n const regExp = new RegExp(`(${escapeRegExp(query)}|${escapeRegExp(cleanSearchText(query))})`, 'gi');\n dom.titleSpan.innerHTML = dom.titleSpan.innerHTML.replace(regExp, '<i>$1</i>');\n dom.lastMessageSpan.append(appProfileManager.getChatMembersString(-peerId));\n } else if(peerId === rootScope.myId) {\n dom.lastMessageSpan.append(i18n('Presence.YourChat'));\n } else {\n let username = appPeersManager.getPeerUsername(peerId);\n if(!username) {\n const user = appUsersManager.getUser(peerId);\n if(user && user.phone) {\n username = '+' + formatPhoneNumber(user.phone).formatted;\n }\n } else {\n username = '@' + username;\n }\n \n dom.lastMessageSpan.innerHTML = '<i>' + username + '</i>';\n }\n });\n \n group.toggle();\n };\n \n const onLoad = <T>(arg: T) => {\n if(!middleware()) {\n return;\n }\n \n //this.loadedContacts = true;\n \n return arg;\n };\n \n return Promise.all([\n appUsersManager.getContacts(query, true)\n .then(onLoad)\n .then((contacts) => {\n if(contacts) {\n setResults(contacts, this.searchGroups.contacts, true);\n }\n }),\n \n appUsersManager.searchContacts(query, 20)\n .then(onLoad)\n .then((contacts) => {\n if(contacts) {\n setResults(contacts.my_results, this.searchGroups.contacts, true);\n setResults(contacts.results/* .concat(contacts.results, contacts.results, contacts.results) */, this.searchGroups.globalContacts);\n\n if(this.searchGroups.globalContacts.nameEl.lastElementChild) {\n this.searchGroups.globalContacts.nameEl.lastElementChild.remove();\n }\n\n this.searchGroups.globalContacts.container.classList.add('is-short');\n \n if(this.searchGroups.globalContacts.list.childElementCount > 3) {\n const showMore = document.createElement('div');\n showMore.classList.add('search-group__show-more');\n showMore.innerText = 'Show more';\n this.searchGroups.globalContacts.nameEl.append(showMore);\n showMore.addEventListener('click', () => {\n const isShort = this.searchGroups.globalContacts.container.classList.toggle('is-short');\n showMore.innerText = isShort ? 'Show more' : 'Show less';\n });\n }\n }\n }),\n \n appMessagesManager.getConversations(query, 0, 20, 0).promise\n .then(onLoad)\n .then(value => {\n if(value) {\n setResults(value.dialogs.map(d => d.peerId), this.searchGroups.contacts, true);\n }\n })\n ]);\n } else if(!this.searchContext.peerId && !this.searchContext.minDate) {\n const renderRecentSearch = (setActive = true) => {\n return appStateManager.getState().then(state => {\n if(!middleware()) {\n return;\n }\n \n this.searchGroups.recent.list.innerHTML = '';\n \n state.recentSearch.slice(0, 20).forEach(peerId => {\n let {dialog, dom} = appDialogsManager.addDialogNew({\n dialog: peerId,\n container: this.searchGroups.recent.list,\n drawStatus: false,\n meAsSaved: true,\n avatarSize: 48,\n autonomous: true\n });\n \n dom.lastMessageSpan.append(peerId > 0 ? appUsersManager.getUserStatusString(peerId) : appProfileManager.getChatMembersString(-peerId));\n });\n \n if(!state.recentSearch.length) {\n this.searchGroups.recent.clear();\n } else if(setActive) {\n this.searchGroups.recent.setActive();\n }\n });\n };\n\n return Promise.all([\n appUsersManager.getTopPeers('correspondents').then(peers => {\n if(!middleware()) return;\n\n const idx = peers.findIndex(peer => peer.id === rootScope.myId);\n if(idx !== -1) {\n peers = peers.slice();\n peers.splice(idx, 1);\n }\n //console.log('got top categories:', categories);\n if(peers.length) {\n peers.forEach((peer) => {\n appDialogsManager.addDialogNew({\n dialog: peer.id, \n container: this.searchGroups.people.list, \n drawStatus: false,\n onlyFirstName: true,\n avatarSize: 54,\n autonomous: false\n });\n });\n }\n \n this.searchGroups.people.setActive();\n }),\n\n renderRecentSearch()\n ]);\n } else return Promise.resolve();\n }\n\n private loadMembers(mediaTab: SearchSuperMediaTab) {\n const id = -this.searchContext.peerId;\n const middleware = this.middleware.get();\n let promise: Promise<void>;\n\n const renderParticipants = async(participants: (ChatParticipant | ChannelParticipant)[]) => {\n if(this.loadMutex) {\n await this.loadMutex;\n\n if(!middleware()) {\n return;\n }\n }\n \n if(!this.membersList) {\n this.membersList = new SortedUserList({lazyLoadQueue: this.lazyLoadQueue, rippleEnabled: false});\n this.membersList.list.addEventListener('click', (e) => {\n const li = findUpTag(e.target, 'LI');\n if(!li) {\n return;\n }\n\n const peerId = +li.dataset.peerId;\n let promise: Promise<any> = Promise.resolve();\n if(mediaSizes.isMobile) {\n promise = appSidebarRight.toggleSidebar(false);\n }\n \n promise.then(() => {\n appImManager.setInnerPeer(peerId);\n });\n });\n mediaTab.contentTab.append(this.membersList.list);\n this.afterPerforming(1, mediaTab.contentTab);\n }\n\n participants.forEach(participant => {\n const peerId = appChatsManager.getParticipantPeerId(participant);\n if(peerId < 0) {\n return;\n }\n\n const user = appUsersManager.getUser(peerId);\n if(user.pFlags.deleted) {\n return;\n }\n\n this.membersList.add(peerId);\n });\n };\n\n if(appChatsManager.isChannel(id)) {\n const LOAD_COUNT = !this.membersList ? 50 : 200;\n promise = appProfileManager.getChannelParticipants(id, undefined, LOAD_COUNT, this.nextRates[mediaTab.inputFilter]).then(participants => {\n if(!middleware()) {\n return;\n }\n\n let list = mediaTab.contentTab.firstElementChild as HTMLUListElement;\n this.nextRates[mediaTab.inputFilter] = (list ? list.childElementCount : 0) + participants.participants.length;\n\n if(participants.participants.length < LOAD_COUNT) {\n this.loaded[mediaTab.inputFilter] = true;\n }\n\n return renderParticipants(participants.participants);\n });\n } else {\n promise = (appProfileManager.getChatFull(id) as Promise<ChatFull.chatFull>).then(chatFull => {\n if(!middleware()) {\n return;\n }\n\n //console.log('anymore', chatFull);\n this.loaded[mediaTab.inputFilter] = true;\n const participants = chatFull.participants;\n if(participants._ === 'chatParticipantsForbidden') {\n return;\n }\n \n return renderParticipants(participants.participants);\n });\n }\n\n return this.loadPromises[mediaTab.inputFilter] = promise.finally(() => { \n if(!middleware()) {\n return;\n }\n\n this.loadPromises[mediaTab.inputFilter] = null;\n });\n }\n\n private loadType(mediaTab: SearchSuperMediaTab, justLoad: boolean, loadCount: number, middleware: () => boolean) {\n const type = mediaTab.inputFilter;\n\n if(this.loadPromises[type]) {\n return this.loadPromises[type];\n }\n\n if(mediaTab.type === 'members') {\n return this.loadMembers(mediaTab);\n }\n\n const history = this.historyStorage[type] ?? (this.historyStorage[type] = []);\n\n if(type === 'inputMessagesFilterEmpty' && !history.length) {\n if(!this.loadedChats) {\n this.loadChats();\n this.loadedChats = true;\n }\n\n if(!this.searchContext.query.trim() && !this.searchContext.peerId && !this.searchContext.minDate) {\n this.loaded[type] = true;\n return Promise.resolve();\n }\n }\n\n const logStr = 'load [' + type + ']: ';\n\n // render from cache\n if(history.length && this.usedFromHistory[type] < history.length && !justLoad) {\n let messages: any[] = [];\n let used = Math.max(0, this.usedFromHistory[type]);\n let slicedLength = 0;\n\n do {\n let ids = history.slice(used, used + loadCount);\n //this.log(logStr + 'will render from cache', used, history, ids, loadCount);\n used += ids.length;\n slicedLength += ids.length;\n\n messages.push(...this.filterMessagesByType(ids.map(m => appMessagesManager.getMessageByPeer(m.peerId, m.mid)), type));\n } while(slicedLength < loadCount && used < history.length);\n \n // если перебор\n /* if(slicedLength > loadCount) {\n let diff = messages.length - loadCount;\n messages = messages.slice(0, messages.length - diff);\n used -= diff;\n } */\n\n this.usedFromHistory[type] = used;\n //if(messages.length) {\n return this.performSearchResult(messages, mediaTab).finally(() => {\n setTimeout(() => {\n this.scrollable.checkForTriggers();\n }, 0);\n });\n //}\n\n return Promise.resolve();\n }\n \n let maxId = history.length ? history[history.length - 1].mid : 0;\n \n //this.log(logStr + 'search house of glass pre', type, maxId);\n \n //let loadCount = history.length ? 50 : 15;\n return this.loadPromises[type] = appMessagesManager.getSearch({\n ...this.searchContext,\n inputFilter: {_: type},\n maxId, \n limit: loadCount,\n nextRate: this.nextRates[type] ?? (this.nextRates[type] = 0)\n }).then(value => {\n history.push(...value.history.map(m => ({mid: m.mid, peerId: m.peerId})));\n \n this.log(logStr + 'search house of glass', type, value);\n\n if(!middleware()) {\n //this.log.warn('peer changed');\n return;\n }\n\n // ! Фикс случая, когда не загружаются документы при открытой панели разработчиков (происходит из-за того, что не совпадают критерии отбора документов в getSearch)\n if(value.history.length < loadCount || (this.searchContext.folderId !== undefined && !value.next_rate) || value.history.length === value.count) {\n //if((value.count || history.length === value.count) && history.length >= value.count) {\n //this.log(logStr + 'loaded all media', value, loadCount);\n this.loaded[type] = true;\n }\n\n this.nextRates[type] = value.next_rate;\n\n if(justLoad) {\n return Promise.resolve();\n }\n\n this.usedFromHistory[type] = history.length;\n\n if(!this.loaded[type]) {\n (this.loadPromises[type] || Promise.resolve()).then(() => {\n setTimeout(() => {\n if(!middleware()) return;\n //this.log('will preload more');\n if(this.mediaTab === mediaTab) {\n const promise = this.load(true, true);\n if(promise) {\n promise.then(() => {\n if(!middleware()) return;\n //this.log('preloaded more');\n setTimeout(() => {\n this.scrollable.checkForTriggers();\n }, 0);\n });\n }\n }\n }, 0);\n });\n }\n\n //if(value.history.length) {\n return this.performSearchResult(this.filterMessagesByType(value.history, type), mediaTab);\n //}\n }).catch(err => {\n this.log.error('load error:', err);\n }).finally(() => {\n this.loadPromises[type] = null;\n });\n }\n \n public async load(single = false, justLoad = false) {\n // if(testScroll/* || 1 === 1 */) {\n // return;\n // }\n\n //return;\n \n const peerId = this.searchContext.peerId;\n this.log('load', single, peerId, this.loadPromises);\n const middleware = this.middleware.get();\n\n if(this.firstLoad) {\n if(this.hideEmptyTabs) {\n const mediaTabs = this.mediaTabs.filter(mediaTab => mediaTab.inputFilter !== 'inputMessagesFilterEmpty')\n const filters = mediaTabs.map(mediaTab => ({_: mediaTab.inputFilter}));\n\n const counters = await appMessagesManager.getSearchCounters(peerId, filters);\n if(!middleware()) {\n return;\n }\n\n if(this.loadMutex) {\n await this.loadMutex;\n\n if(!middleware()) {\n return;\n }\n }\n\n let firstMediaTab: SearchSuperMediaTab;\n let count = 0;\n mediaTabs.forEach(mediaTab => {\n const counter = counters.find(c => c.filter._ === mediaTab.inputFilter);\n\n mediaTab.menuTab.classList.toggle('hide', !counter.count);\n mediaTab.menuTab.classList.remove('active');\n //mediaTab.contentTab.classList.toggle('hide', !counter.count);\n\n if(counter.count && firstMediaTab === undefined) {\n firstMediaTab = mediaTab;\n }\n\n if(counter.count) ++count;\n });\n\n const membersTab = this.mediaTabsMap.get('members');\n const canViewMembers = this.canViewMembers();\n membersTab.menuTab.classList.toggle('hide', !canViewMembers);\n\n if(canViewMembers) {\n firstMediaTab = membersTab;\n }\n\n this.container.classList.toggle('hide', !firstMediaTab);\n this.container.parentElement.classList.toggle('search-empty', !firstMediaTab);\n if(firstMediaTab) {\n this.skipScroll = true;\n this.selectTab(this.mediaTabs.indexOf(firstMediaTab), false);\n firstMediaTab.menuTab.classList.add('active');\n\n this.navScrollableContainer.classList.toggle('hide', count <= 1);\n }\n }\n\n this.firstLoad = false;\n }\n \n let toLoad = single ? [this.mediaTab] : this.mediaTabs.filter(t => t !== this.mediaTab);\n toLoad = toLoad.filter(mediaTab => {\n const inputFilter = mediaTab.inputFilter;\n return !this.loaded[inputFilter] || (this.historyStorage[inputFilter] && this.usedFromHistory[inputFilter] < this.historyStorage[inputFilter].length);\n });\n\n if(peerId > 0) {\n toLoad.findAndSplice(mediaTab => mediaTab.type === 'members');\n }\n\n if(!toLoad.length) {\n return;\n }\n\n const loadCount = justLoad ? 50 : Math.round((windowSize.windowH / 130 | 0) * 3 * 1.25); // that's good for all types\n\n const promises: Promise<any>[] = toLoad.map(mediaTab => {\n return this.loadType(mediaTab, justLoad, loadCount, middleware)\n });\n\n return Promise.all(promises).catch(err => {\n this.log.error('Load error all promises:', err);\n });\n }\n \n public getMonthContainerByTimestamp(timestamp: number, type: SearchSuperType) {\n const date = new Date(timestamp * 1000);\n date.setHours(0, 0, 0);\n date.setDate(1);\n const dateTimestamp = date.getTime();\n const containers = this.monthContainers[type] ?? (this.monthContainers[type] = {});\n if(!(dateTimestamp in containers)) {\n const container = document.createElement('div');\n container.className = 'search-super-month';\n\n const name = document.createElement('div');\n name.classList.add('search-super-month-name');\n\n const options: Intl.DateTimeFormatOptions = {\n month: 'long'\n };\n\n if(date.getFullYear() !== new Date().getFullYear()) {\n options.year = 'numeric';\n }\n\n const dateElement = new I18n.IntlDateElement({\n date,\n options\n }).element;\n name.append(dateElement);\n\n container.append(name);\n\n const items = document.createElement('div');\n items.classList.add('search-super-month-items');\n\n container.append(name, items);\n\n const haveTimestamps = getObjectKeysAndSort(containers, 'desc');\n let i = 0;\n for(; i < haveTimestamps.length; ++i) {\n const t = haveTimestamps[i];\n if(dateTimestamp > t) {\n break;\n }\n }\n \n containers[dateTimestamp] = {container, items};\n positionElementByIndex(container, this.tabs[type], i);\n }\n\n return containers[dateTimestamp];\n }\n\n public canViewMembers() {\n return this.searchContext.peerId < 0 && !appChatsManager.isBroadcast(-this.searchContext.peerId) && appChatsManager.hasRights(-this.searchContext.peerId, 'view_participants');\n }\n\n public cleanup() {\n this.loadPromises = {};\n this.loaded = {};\n this.loadedChats = false;\n this.nextRates = {};\n this.firstLoad = true;\n\n this.lazyLoadQueue.clear();\n\n this.mediaTabs.forEach(mediaTab => {\n this.usedFromHistory[mediaTab.inputFilter] = -1;\n });\n\n if(this.selection.isSelecting) {\n this.selection.cancelSelection();\n }\n\n // * must go to first tab (это костыль)\n /* const membersTab = this.mediaTabsMap.get('members');\n if(membersTab) {\n const tab = this.canViewMembers() ? membersTab : this.mediaTabs[this.mediaTabs.indexOf(membersTab) + 1];\n this.mediaTab = tab;\n } */\n\n this.middleware.clean();\n this.cleanScrollPositions();\n this.membersList = undefined;\n }\n\n public cleanScrollPositions() {\n this.mediaTabs.forEach(mediaTab => {\n mediaTab.scroll = undefined;\n });\n }\n\n public cleanupHTML(goFirst = false) {\n if(this.urlsToRevoke.length) {\n this.urlsToRevoke.forEach(url => {\n URL.revokeObjectURL(url);\n });\n this.urlsToRevoke.length = 0;\n }\n\n this.mediaTabs.forEach((tab) => {\n tab.contentTab.innerHTML = '';\n\n if(this.hideEmptyTabs) {\n //tab.menuTab.classList.add('hide');\n this.container.classList.add('hide');\n this.container.parentElement.classList.add('search-empty');\n }\n\n if(tab.type === 'chats') {\n return;\n }\n \n if(!this.historyStorage[tab.inputFilter]) {\n const parent = tab.contentTab.parentElement;\n //if(!testScroll) {\n if(!parent.querySelector('.preloader')) {\n putPreloader(parent, true);\n }\n //}\n\n const empty = parent.querySelector('.content-empty');\n if(empty) {\n empty.remove();\n }\n }\n });\n\n /* if(goFirst) {\n const membersTab = this.mediaTabsMap.get('members');\n if(membersTab) {\n let idx = this.canViewMembers() ? 0 : 1;\n membersTab.menuTab.classList.toggle('hide', idx !== 0);\n\n this.selectTab(idx, false);\n } else {\n this.selectTab(0, false);\n }\n } */\n\n this.monthContainers = {};\n this.searchGroupMedia.clear();\n this.scrollable.scrollTop = 0;\n\n /* if(testScroll) {\n for(let i = 0; i < 1500; ++i) {\n let div = document.createElement('div');\n div.insertAdjacentHTML('beforeend', `<img class=\"media-image\" src=\"assets/img/camomile.jpg\">`);\n div.classList.add('grid-item');\n div.dataset.id = '' + (i / 3 | 0);\n //div.innerText = '' + (i / 3 | 0);\n this.tabs.inputMessagesFilterPhotoVideo.append(div);\n }\n } */\n }\n\n private copySearchContext(newInputFilter: MyInputMessagesFilter) {\n const context = copy(this.searchContext);\n context.inputFilter = {_: newInputFilter};\n context.nextRate = this.nextRates[newInputFilter];\n return context;\n }\n\n public setQuery({peerId, query, threadId, historyStorage, folderId, minDate, maxDate}: {\n peerId: number, \n query?: string, \n threadId?: number, \n historyStorage?: AppSearchSuper['historyStorage'], \n folderId?: number,\n minDate?: number,\n maxDate?: number\n }) {\n this.searchContext = {\n peerId: peerId || 0,\n query: query || '',\n inputFilter: {_: this.mediaTab.inputFilter},\n threadId,\n folderId,\n minDate,\n maxDate\n };\n \n this.historyStorage = historyStorage ?? {};\n\n this.cleanup();\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport { InputPrivacyKey, InputPrivacyRule, PrivacyRule, Update, PrivacyKey } from \"../../layer\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport appChatsManager from \"./appChatsManager\";\r\nimport appUsersManager from \"./appUsersManager\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport rootScope from \"../rootScope\";\r\nimport { convertInputKeyToKey } from \"../../helpers/string\";\r\n\r\nexport enum PrivacyType {\r\n Everybody = 2,\r\n Contacts = 1,\r\n Nobody = 0\r\n}\r\n\r\nexport class AppPrivacyManager {\r\n private privacy: Partial<{\r\n [key in PrivacyKey['_']]: PrivacyRule[] | Promise<PrivacyRule[]>\r\n }> = {};\r\n\r\n constructor() {\r\n rootScope.addMultipleEventsListeners({\r\n updatePrivacy: (update) => {\r\n const key = update.key._;\r\n this.privacy[key] = update.rules;\r\n rootScope.dispatchEvent('privacy_update', update);\r\n }\r\n });\r\n }\r\n\r\n public setPrivacy(inputKey: InputPrivacyKey['_'], rules: InputPrivacyRule[]) {\r\n return apiManager.invokeApi('account.setPrivacy', {\r\n key: {\r\n _: inputKey\r\n },\r\n rules\r\n }).then(privacyRules => {\r\n appUsersManager.saveApiUsers(privacyRules.users);\r\n appChatsManager.saveApiChats(privacyRules.chats);\r\n\r\n apiUpdatesManager.processLocalUpdate({\r\n _: 'updatePrivacy',\r\n key: {\r\n _: convertInputKeyToKey(inputKey)\r\n },\r\n rules: rules.map(inputRule => {\r\n const rule: PrivacyRule = {} as any;\r\n Object.assign(rule, inputRule);\r\n rule._ = convertInputKeyToKey(rule._) as any;\r\n return rule;\r\n })\r\n });\r\n\r\n //console.log('privacy rules', inputKey, privacyRules, privacyRules.rules);\r\n\r\n return privacyRules.rules;\r\n });\r\n }\r\n\r\n public getPrivacy(inputKey: InputPrivacyKey['_']) {\r\n const privacyKey: PrivacyKey['_'] = convertInputKeyToKey(inputKey) as any;\r\n const rules = this.privacy[privacyKey];\r\n if(rules) {\r\n return Promise.resolve(rules);\r\n }\r\n \r\n return this.privacy[privacyKey] = apiManager.invokeApi('account.getPrivacy', {\r\n key: {\r\n _: inputKey\r\n }\r\n }).then(privacyRules => {\r\n appUsersManager.saveApiUsers(privacyRules.users);\r\n appChatsManager.saveApiChats(privacyRules.chats);\r\n\r\n //console.log('privacy rules', inputKey, privacyRules, privacyRules.rules);\r\n\r\n return this.privacy[privacyKey] = privacyRules.rules;\r\n });\r\n }\r\n\r\n public getPrivacyRulesDetails(rules: PrivacyRule[]) {\r\n const types: PrivacyType[] = [];\r\n\r\n type peers = {users: number[], chats: number[]};\r\n let allowPeers: peers = {users: [], chats: []}, disallowPeers: peers = {users: [], chats: []};\r\n rules.forEach(rule => {\r\n switch(rule._) {\r\n case 'privacyValueAllowAll':\r\n types.push(2);\r\n break;\r\n case 'privacyValueDisallowAll':\r\n types.push(0);\r\n break;\r\n case 'privacyValueAllowContacts': \r\n types.push(1);\r\n break;\r\n /* case 'privacyValueDisallowContacts':\r\n types.push('Except My Contacts');\r\n break; */\r\n case 'privacyValueAllowChatParticipants':\r\n allowPeers.chats.push(...rule.chats);\r\n break;\r\n case 'privacyValueAllowUsers':\r\n allowPeers.users.push(...rule.users);\r\n break;\r\n case 'privacyValueDisallowChatParticipants':\r\n disallowPeers.chats.push(...rule.chats);\r\n break;\r\n case 'privacyValueDisallowUsers':\r\n disallowPeers.users.push(...rule.users);\r\n break;\r\n }\r\n });\r\n\r\n return {type: types[0], disallowPeers, allowPeers};\r\n }\r\n}\r\n\r\nconst appPrivacyManager = new AppPrivacyManager();\r\nMOUNT_CLASS_TO.appPrivacyManager = appPrivacyManager;\r\nexport default appPrivacyManager;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { randomLong } from \"../helpers/random\";\r\nimport { InputPrivacyKey, InputPrivacyRule } from \"../layer\";\r\nimport appPrivacyManager, { PrivacyType } from \"../lib/appManagers/appPrivacyManager\";\r\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\r\nimport { i18n, join, LangPackKey, _i18n } from \"../lib/langPack\";\r\nimport RadioField from \"./radioField\";\r\nimport Row, { RadioFormFromRows } from \"./row\";\r\nimport Scrollable from \"./scrollable\";\r\nimport { SettingSection, generateSection } from \"./sidebarLeft\";\r\nimport AppAddMembersTab from \"./sidebarLeft/tabs/addMembers\";\r\nimport { SliderSuperTabEventable } from \"./sliderTab\";\r\n\r\ntype PrivacySectionStr = LangPackKey | '';\r\nexport default class PrivacySection {\r\n public radioRows: Map<PrivacyType, Row>;\r\n public radioSection: SettingSection;\r\n public exceptions: Map<keyof PrivacySection['peerIds'], {\r\n titleLangKey: LangPackKey,\r\n key: keyof PrivacySection['peerIds'],\r\n row: Row,\r\n icon: string,\r\n subtitleLangKey: LangPackKey,\r\n clickable: true\r\n }>;\r\n public peerIds: {\r\n disallow?: number[],\r\n allow?: number[]\r\n };\r\n public type: PrivacyType;\r\n\r\n constructor(public options: {\r\n tab: SliderSuperTabEventable,\r\n title: LangPackKey, \r\n inputKey: InputPrivacyKey['_'], \r\n captions?: [PrivacySectionStr, PrivacySectionStr, PrivacySectionStr],\r\n appendTo?: Scrollable,\r\n noExceptions?: boolean,\r\n onRadioChange?: (value: number) => any,\r\n skipTypes?: PrivacyType[],\r\n exceptionTexts?: [LangPackKey, LangPackKey]\r\n }) {\r\n if(options.captions) {\r\n options.captions.reverse();\r\n }\r\n\r\n this.radioSection = new SettingSection({name: options.title, caption: true});\r\n\r\n this.radioRows = new Map();\r\n\r\n let r: Array<{type: PrivacyType, langKey: LangPackKey}> = [{\r\n type: PrivacyType.Everybody,\r\n langKey: 'PrivacySettingsController.Everbody'\r\n }, {\r\n type: PrivacyType.Contacts,\r\n langKey: 'PrivacySettingsController.MyContacts'\r\n }, {\r\n type: PrivacyType.Nobody,\r\n langKey: 'PrivacySettingsController.Nobody'\r\n }];\r\n\r\n if(options.skipTypes) {\r\n r = r.filter(r => !options.skipTypes.includes(r.type));\r\n }\r\n \r\n const random = randomLong();\r\n r.forEach(({type, langKey}) => {\r\n const row = new Row({\r\n radioField: new RadioField({\r\n langKey, \r\n name: random, \r\n value: '' + type\r\n })\r\n });\r\n \r\n this.radioRows.set(type, row);\r\n });\r\n\r\n const form = RadioFormFromRows([...this.radioRows.values()], this.onRadioChange);\r\n\r\n this.radioSection.content.append(form);\r\n if(options.appendTo) {\r\n options.appendTo.append(this.radioSection.container);\r\n }\r\n\r\n if(!options.noExceptions) {\r\n const container = generateSection(options.appendTo, 'PrivacyExceptions', 'PrivacySettingsController.PeerInfo');\r\n\r\n this.exceptions = new Map([[\r\n 'disallow', \r\n {\r\n titleLangKey: options.exceptionTexts[0],\r\n key: 'disallow',\r\n row: null,\r\n icon: 'deleteuser',\r\n subtitleLangKey: 'PrivacySettingsController.AddUsers',\r\n clickable: true\r\n }\r\n ], [\r\n 'allow', \r\n {\r\n titleLangKey: options.exceptionTexts[1],\r\n key: 'allow',\r\n row: null,\r\n icon: 'adduser',\r\n subtitleLangKey: 'PrivacySettingsController.AddUsers',\r\n clickable: true\r\n }\r\n ]]);\r\n\r\n this.exceptions.forEach((exception) => {\r\n exception.row = new Row(exception);\r\n\r\n exception.row.container.addEventListener('click', () => {\r\n promise.then(() => {\r\n const _peerIds = this.peerIds[exception.key];\r\n new AppAddMembersTab(options.tab.slider).open({\r\n type: 'privacy',\r\n skippable: true,\r\n title: exception.titleLangKey,\r\n placeholder: 'PrivacyModal.Search.Placeholder',\r\n takeOut: (newPeerIds) => {\r\n _peerIds.length = 0;\r\n _peerIds.push(...newPeerIds);\r\n exception.row.subtitle.innerHTML = '';\r\n exception.row.subtitle.append(...this.generateStr(this.splitPeersByType(newPeerIds)));\r\n },\r\n selectedPeerIds: _peerIds\r\n });\r\n });\r\n });\r\n\r\n container.append(exception.row.container);\r\n });\r\n }\r\n\r\n /* setTimeout(() => {\r\n this.setRadio(PrivacyType.Contacts);\r\n }, 0); */\r\n\r\n const promise = appPrivacyManager.getPrivacy(options.inputKey).then(rules => {\r\n const details = appPrivacyManager.getPrivacyRulesDetails(rules);\r\n this.setRadio(details.type);\r\n\r\n if(this.exceptions) {\r\n this.peerIds = {};\r\n (['allow', 'disallow'] as ('allow' | 'disallow')[]).forEach(k => {\r\n const arr = [];\r\n const from = k === 'allow' ? details.allowPeers : details.disallowPeers;\r\n arr.push(...from.users);\r\n arr.push(...from.chats.map(id => -id));\r\n this.peerIds[k] = arr;\r\n const s = this.exceptions.get(k).row.subtitle;\r\n s.innerHTML = '';\r\n s.append(...this.generateStr(from));\r\n });\r\n }\r\n\r\n options.tab.eventListener.addEventListener('destroy', () => {\r\n const rules: InputPrivacyRule[] = [];\r\n\r\n switch(this.type) {\r\n case PrivacyType.Everybody:\r\n rules.push({_: 'inputPrivacyValueAllowAll'});\r\n break;\r\n case PrivacyType.Contacts:\r\n rules.push({_: 'inputPrivacyValueAllowContacts'});\r\n break;\r\n case PrivacyType.Nobody:\r\n rules.push({_: 'inputPrivacyValueDisallowAll'});\r\n break;\r\n }\r\n\r\n if(this.exceptions) {\r\n ([\r\n ['allow', 'inputPrivacyValueAllowChatParticipants', 'inputPrivacyValueAllowUsers'],\r\n ['disallow', 'inputPrivacyValueDisallowChatParticipants', 'inputPrivacyValueDisallowUsers']\r\n ] as Array<[\r\n 'allow' | 'disallow', \r\n 'inputPrivacyValueAllowChatParticipants' | 'inputPrivacyValueDisallowChatParticipants', \r\n 'inputPrivacyValueAllowUsers' | 'inputPrivacyValueDisallowUsers'\r\n ]>).forEach(([k, chatKey, usersKey], idx) => {\r\n if(this.exceptions.get(k).row.container.classList.contains('hide')) {\r\n return;\r\n }\r\n\r\n const _peerIds: number[] = this.peerIds[k];\r\n \r\n if(_peerIds) {\r\n const splitted = this.splitPeersByType(_peerIds);\r\n if(splitted.chats.length) {\r\n rules.push({_: chatKey, chats: splitted.chats.map(peerId => -peerId)});\r\n }\r\n \r\n if(splitted.users.length) {\r\n rules.push({_: usersKey, users: splitted.users.map(id => appUsersManager.getUserInput(id))});\r\n }\r\n }\r\n });\r\n }\r\n \r\n appPrivacyManager.setPrivacy(options.inputKey, rules);\r\n }, {once: true});\r\n });\r\n }\r\n\r\n private onRadioChange = (value: string | PrivacySection['type']) => {\r\n value = +value as PrivacySection['type'];\r\n this.type = value;\r\n\r\n const caption = this.options.captions[this.type];\r\n const captionElement = this.radioSection.caption;\r\n if(!caption) {\r\n captionElement.innerHTML = '';\r\n } else {\r\n _i18n(captionElement, caption);\r\n }\r\n captionElement.classList.toggle('hide', !caption);\r\n\r\n if(this.exceptions) {\r\n this.exceptions.get('allow').row.container.classList.toggle('hide', this.type === PrivacyType.Everybody);\r\n this.exceptions.get('disallow').row.container.classList.toggle('hide', this.type === PrivacyType.Nobody);\r\n }\r\n\r\n this.options.onRadioChange && this.options.onRadioChange(value);\r\n };\r\n\r\n public setRadio(type: PrivacySection['type']) {\r\n const row = this.radioRows.get(type);\r\n this.onRadioChange(type);\r\n row.radioField.input.checked = true;\r\n }\r\n \r\n private splitPeersByType(peerIds: number[]) {\r\n const peers = {users: [] as number[], chats: [] as number[]};\r\n peerIds.forEach(peerId => {\r\n peers[peerId < 0 ? 'chats' : 'users'].push(peerId < 0 ? -peerId : peerId);\r\n });\r\n\r\n return peers;\r\n }\r\n\r\n private generateStr(peers: {users: number[], chats: number[]}) {\r\n if(!peers.users.length && !peers.chats.length) {\r\n return [i18n('PrivacySettingsController.AddUsers')];\r\n }\r\n\r\n return join([\r\n peers.users.length ? i18n('Users', [peers.users.length]) : null, \r\n peers.chats.length ? i18n('Chats', [peers.chats.length]) : null\r\n ].filter(Boolean), false);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { PrivacyType } from \"../../../../lib/appManagers/appPrivacyManager\";\r\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\r\nimport PrivacySection from \"../../../privacySection\";\r\nimport { LangPackKey } from \"../../../../lib/langPack\";\r\n\r\nexport default class AppPrivacyPhoneNumberTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.container.classList.add('privacy-tab', 'privacy-phone-number');\r\n this.setTitle('PrivacyPhone');\r\n\r\n const phoneCaption: LangPackKey = 'PrivacyPhoneInfo';\r\n const phoneSection = new PrivacySection({\r\n tab: this,\r\n title: 'PrivacyPhoneTitle',\r\n inputKey: 'inputPrivacyKeyPhoneNumber',\r\n captions: [phoneCaption, phoneCaption, ''],\r\n exceptionTexts: ['PrivacySettingsController.NeverShare', 'PrivacySettingsController.AlwaysShare'],\r\n appendTo: this.scrollable,\r\n onRadioChange: (type) => {\r\n s.setRadio(PrivacyType.Everybody);\r\n s.radioSection.container.classList.toggle('hide', type !== PrivacyType.Nobody);\r\n }\r\n });\r\n\r\n const sCaption: LangPackKey = 'PrivacyPhoneInfo3';\r\n const s = new PrivacySection({\r\n tab: this,\r\n title: 'PrivacyPhoneTitle2',\r\n inputKey: 'inputPrivacyKeyAddedByPhone',\r\n captions: [sCaption, sCaption, ''],\r\n noExceptions: true,\r\n skipTypes: [PrivacyType.Nobody]\r\n });\r\n\r\n this.scrollable.container.insertBefore(s.radioSection.container, phoneSection.radioSection.container.nextSibling);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"../..\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\nimport appStickersManager from \"../../../../lib/appManagers/appStickersManager\";\r\nimport Button from \"../../../button\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport { wrapSticker } from \"../../../wrappers\";\r\nimport AppSettingsTab from \"../settings\";\r\n\r\nexport default class AppTwoStepVerificationSetTab extends SliderSuperTab {\r\n protected init() {\r\n this.container.classList.add('two-step-verification', 'two-step-verification-set');\r\n this.setTitle('TwoStepVerificationPasswordSet');\r\n\r\n const section = new SettingSection({\r\n caption: 'TwoStepVerificationPasswordSetInfo',\r\n noDelimiter: true\r\n });\r\n\r\n const emoji = '🥳';\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n const stickerContainer = document.createElement('div');\r\n\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: stickerContainer,\r\n loop: true,\r\n play: true,\r\n width: 160,\r\n height: 160\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n stickerContainer.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n section.content.append(stickerContainer);\r\n\r\n const inputContent = section.generateContentElement();\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const btnReturn = Button('btn-primary btn-color-primary', {text: 'TwoStepVerificationPasswordReturnSettings'});\r\n\r\n attachClickEvent(btnReturn, (e) => {\r\n this.close();\r\n });\r\n\r\n this.slider.sliceTabsUntilTab(AppSettingsTab, this);\r\n\r\n inputWrapper.append(btnReturn);\r\n\r\n inputContent.append(inputWrapper);\r\n\r\n this.scrollable.container.append(section.container);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { IS_MOBILE_SAFARI } from \"../../environment/userAgent\";\r\n\r\nexport function canFocus(isFirstInput: boolean) {\r\n return !IS_MOBILE_SAFARI || !isFirstInput;\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"../..\";\r\nimport { AccountPassword } from \"../../../../layer\";\r\nimport appStickersManager from \"../../../../lib/appManagers/appStickersManager\";\r\nimport Button from \"../../../button\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport { wrapSticker } from \"../../../wrappers\";\r\nimport passwordManager from \"../../../../lib/mtproto/passwordManager\";\r\nimport AppTwoStepVerificationSetTab from \"./passwordSet\";\r\nimport CodeInputField from \"../../../codeInputField\";\r\nimport AppTwoStepVerificationEmailTab from \"./email\";\r\nimport { putPreloader } from \"../../../misc\";\r\nimport { i18n, _i18n } from \"../../../../lib/langPack\";\r\nimport { canFocus } from \"../../../../helpers/dom/canFocus\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\nimport replaceContent from \"../../../../helpers/dom/replaceContent\";\r\nimport toggleDisability from \"../../../../helpers/dom/toggleDisability\";\r\n\r\nexport default class AppTwoStepVerificationEmailConfirmationTab extends SliderSuperTab {\r\n public codeInputField: CodeInputField;\r\n public state: AccountPassword;\r\n public email: string;\r\n public length: number;\r\n public isFirst = false;\r\n\r\n protected init() {\r\n this.container.classList.add('two-step-verification', 'two-step-verification-email-confirmation');\r\n this.setTitle('TwoStepAuth.RecoveryTitle');\r\n\r\n const section = new SettingSection({\r\n caption: true,\r\n noDelimiter: true\r\n });\r\n\r\n _i18n(section.caption, 'TwoStepAuth.ConfirmEmailCodeDesc', [this.email]);\r\n\r\n const emoji = '📬';\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n const stickerContainer = document.createElement('div');\r\n\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: stickerContainer,\r\n loop: false,\r\n play: true,\r\n width: 160,\r\n height: 160,\r\n emoji\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n stickerContainer.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n section.content.append(stickerContainer);\r\n\r\n const inputContent = section.generateContentElement();\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const inputField = this.codeInputField = new CodeInputField({\r\n name: 'recovery-email-code',\r\n label: 'TwoStepAuth.RecoveryCode',\r\n length: this.length,\r\n onFill: (code) => {\r\n freeze(true);\r\n \r\n passwordManager.confirmPasswordEmail('' + code)\r\n .then(value => {\r\n if(!value) {\r\n\r\n }\r\n\r\n goNext();\r\n })\r\n .catch(err => {\r\n switch(err.type) {\r\n case 'CODE_INVALID':\r\n inputField.input.classList.add('error');\r\n replaceContent(inputField.label, i18n('TwoStepAuth.RecoveryCodeInvalid'));\r\n break;\r\n\r\n case 'EMAIL_HASH_EXPIRED':\r\n inputField.input.classList.add('error');\r\n replaceContent(inputField.label, i18n('TwoStepAuth.RecoveryCodeExpired'));\r\n break;\r\n \r\n default:\r\n console.error('confirm error', err);\r\n break;\r\n }\r\n\r\n freeze(false);\r\n });\r\n }\r\n });\r\n\r\n const btnChange = Button('btn-primary btn-primary-transparent primary', {text: 'TwoStepAuth.EmailCodeChangeEmail'});\r\n const btnResend = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'ResendCode'});\r\n\r\n const goNext = () => {\r\n new AppTwoStepVerificationSetTab(this.slider).open();\r\n };\r\n\r\n const freeze = (disable: boolean) => {\r\n toggleDisability([inputField.input, btnChange, btnResend], disable);\r\n };\r\n\r\n attachClickEvent(btnChange, (e) => {\r\n freeze(true);\r\n passwordManager.cancelPasswordEmail().then(value => {\r\n this.slider.sliceTabsUntilTab(AppTwoStepVerificationEmailTab, this);\r\n this.close();\r\n }, () => {\r\n freeze(false);\r\n });\r\n });\r\n\r\n attachClickEvent(btnResend, (e) => {\r\n freeze(true);\r\n const d = putPreloader(btnResend);\r\n passwordManager.resendPasswordEmail().then(value => {\r\n d.remove();\r\n freeze(false);\r\n });\r\n });\r\n\r\n inputWrapper.append(inputField.container, btnChange, btnResend);\r\n\r\n inputContent.append(inputWrapper);\r\n\r\n this.scrollable.container.append(section.container);\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n if(!canFocus(this.isFirst)) return;\r\n this.codeInputField.input.focus();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"../..\";\r\nimport { AccountPassword } from \"../../../../layer\";\r\nimport appStickersManager from \"../../../../lib/appManagers/appStickersManager\";\r\nimport Button from \"../../../button\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport { wrapSticker } from \"../../../wrappers\";\r\nimport InputField from \"../../../inputField\";\r\nimport { putPreloader } from \"../../../misc\";\r\nimport passwordManager from \"../../../../lib/mtproto/passwordManager\";\r\nimport AppTwoStepVerificationSetTab from \"./passwordSet\";\r\nimport AppTwoStepVerificationEmailConfirmationTab from \"./emailConfirmation\";\r\nimport RichTextProcessor from \"../../../../lib/richtextprocessor\";\r\nimport PopupPeer from \"../../../popups/peer\";\r\nimport { cancelEvent } from \"../../../../helpers/dom/cancelEvent\";\r\nimport { canFocus } from \"../../../../helpers/dom/canFocus\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\n\r\nexport default class AppTwoStepVerificationEmailTab extends SliderSuperTab {\r\n public inputField: InputField;\r\n public state: AccountPassword;\r\n public plainPassword: string;\r\n public newPassword: string;\r\n public hint: string;\r\n public isFirst = false;\r\n\r\n protected init() {\r\n this.container.classList.add('two-step-verification', 'two-step-verification-email');\r\n this.setTitle('RecoveryEmailTitle');\r\n\r\n const section = new SettingSection({\r\n caption: true,\r\n noDelimiter: true\r\n });\r\n\r\n const emoji = '💌';\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n const stickerContainer = document.createElement('div');\r\n\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: stickerContainer,\r\n loop: false,\r\n play: true,\r\n width: 160,\r\n height: 160,\r\n emoji\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n stickerContainer.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n section.content.append(stickerContainer);\r\n\r\n const inputContent = section.generateContentElement();\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const inputField = this.inputField = new InputField({\r\n name: 'recovery-email',\r\n label: 'RecoveryEmail',\r\n plainText: true\r\n });\r\n\r\n inputField.input.addEventListener('keypress', (e) => {\r\n if(e.key === 'Enter') {\r\n cancelEvent(e);\r\n return onContinueClick();\r\n }\r\n });\r\n\r\n inputField.input.addEventListener('input', (e) => {\r\n inputField.input.classList.remove('error');\r\n });\r\n\r\n const btnContinue = Button('btn-primary btn-color-primary', {text: 'Continue'});\r\n const btnSkip = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'YourEmailSkip'});\r\n\r\n const goNext = () => {\r\n new AppTwoStepVerificationSetTab(this.slider).open();\r\n };\r\n\r\n const onContinueClick = () => {\r\n const email = inputField.value.trim();\r\n const match = RichTextProcessor.matchEmail(email);\r\n if(!match || match[0].length !== email.length) {\r\n inputField.input.classList.add('error');\r\n return;\r\n }\r\n\r\n toggleButtons(true);\r\n const d = putPreloader(btnContinue);\r\n\r\n passwordManager.updateSettings({\r\n hint: this.hint,\r\n currentPassword: this.plainPassword,\r\n newPassword: this.newPassword,\r\n email\r\n }).then((value) => {\r\n goNext();\r\n }, (err) => {\r\n if(err.type.includes('EMAIL_UNCONFIRMED')) {\r\n const symbols = +err.type.match(/^EMAIL_UNCONFIRMED_(\\d+)/)[1];\r\n\r\n const tab = new AppTwoStepVerificationEmailConfirmationTab(this.slider);\r\n tab.state = this.state;\r\n tab.email = email;\r\n tab.length = symbols;\r\n tab.open();\r\n } else {\r\n console.log('password set error', err);\r\n }\r\n\r\n toggleButtons(false);\r\n d.remove();\r\n });\r\n };\r\n attachClickEvent(btnContinue, onContinueClick);\r\n\r\n const toggleButtons = (freeze: boolean) => {\r\n if(freeze) {\r\n btnContinue.setAttribute('disabled', 'true');\r\n btnSkip.setAttribute('disabled', 'true');\r\n } else {\r\n btnContinue.removeAttribute('disabled');\r\n btnSkip.removeAttribute('disabled');\r\n }\r\n };\r\n\r\n attachClickEvent(btnSkip, (e) => {\r\n const popup = new PopupPeer('popup-skip-email', {\r\n buttons: [{\r\n langKey: 'Cancel',\r\n isCancel: true\r\n }, {\r\n langKey: 'YourEmailSkip',\r\n callback: () => {\r\n //inputContent.classList.add('sidebar-left-section-disabled');\r\n toggleButtons(true);\r\n putPreloader(btnSkip);\r\n passwordManager.updateSettings({\r\n hint: this.hint, \r\n currentPassword: this.plainPassword,\r\n newPassword: this.newPassword,\r\n email: ''\r\n }).then(() => {\r\n goNext();\r\n }, (err) => {\r\n toggleButtons(false);\r\n });\r\n },\r\n isDanger: true,\r\n }], \r\n titleLangKey: 'YourEmailSkipWarning',\r\n descriptionLangKey: 'YourEmailSkipWarningText'\r\n });\r\n\r\n popup.show();\r\n });\r\n\r\n inputWrapper.append(inputField.container, btnContinue, btnSkip);\r\n\r\n inputContent.append(inputWrapper);\r\n\r\n this.scrollable.container.append(section.container);\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n if(!canFocus(this.isFirst)) return;\r\n this.inputField.input.focus();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"../..\";\r\nimport { AccountPassword } from \"../../../../layer\";\r\nimport appStickersManager from \"../../../../lib/appManagers/appStickersManager\";\r\nimport Button from \"../../../button\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport { wrapSticker } from \"../../../wrappers\";\r\nimport InputField from \"../../../inputField\";\r\nimport AppTwoStepVerificationEmailTab from \"./email\";\r\nimport { toast } from \"../../../toast\";\r\nimport I18n from \"../../../../lib/langPack\";\r\nimport { cancelEvent } from \"../../../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\n\r\nexport default class AppTwoStepVerificationHintTab extends SliderSuperTab {\r\n public inputField: InputField;\r\n public state: AccountPassword;\r\n public plainPassword: string;\r\n public newPassword: string;\r\n\r\n protected init() {\r\n this.container.classList.add('two-step-verification', 'two-step-verification-hint');\r\n this.setTitle('TwoStepAuth.SetupHintTitle');\r\n\r\n const section = new SettingSection({\r\n noDelimiter: true\r\n });\r\n\r\n const emoji = '💡';\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n const stickerContainer = document.createElement('div');\r\n\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: stickerContainer,\r\n loop: false,\r\n play: true,\r\n width: 160,\r\n height: 160,\r\n emoji\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n stickerContainer.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n section.content.append(stickerContainer);\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const inputField = this.inputField = new InputField({\r\n name: 'hint',\r\n label: 'TwoStepAuth.SetupHintPlaceholder'\r\n });\r\n\r\n inputField.input.addEventListener('keypress', (e) => {\r\n if(e.key === 'Enter') {\r\n cancelEvent(e);\r\n return inputField.value ? onContinueClick() : onSkipClick();\r\n }\r\n });\r\n\r\n const goNext = (e?: Event, saveHint?: boolean) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n \r\n const hint = saveHint ? inputField.value : undefined;\r\n if(hint && this.newPassword === hint) {\r\n toast(I18n.format('PasswordAsHintError', true));\r\n return;\r\n }\r\n\r\n const tab = new AppTwoStepVerificationEmailTab(this.slider);\r\n tab.state = this.state;\r\n tab.plainPassword = this.plainPassword;\r\n tab.newPassword = this.newPassword;\r\n tab.hint = hint;\r\n\r\n tab.open();\r\n };\r\n\r\n const btnContinue = Button('btn-primary btn-color-primary', {text: 'Continue'});\r\n const btnSkip = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'YourEmailSkip'});\r\n\r\n const onContinueClick = (e?: Event) => goNext(e, true);\r\n const onSkipClick = (e?: Event) => goNext(e, false);\r\n attachClickEvent(btnContinue, onContinueClick);\r\n attachClickEvent(btnSkip, onSkipClick);\r\n\r\n inputWrapper.append(inputField.container, btnContinue, btnSkip);\r\n\r\n section.content.append(inputWrapper);\r\n\r\n this.scrollable.container.append(section.container);\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n this.inputField.input.focus();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"../..\";\r\nimport { AccountPassword } from \"../../../../layer\";\r\nimport Button from \"../../../button\";\r\nimport PasswordInputField from \"../../../passwordInputField\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport TrackingMonkey from \"../../../monkeys/tracking\";\r\nimport AppTwoStepVerificationHintTab from \"./hint\";\r\nimport { InputState } from \"../../../inputField\";\r\nimport { cancelEvent } from \"../../../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\n\r\nexport default class AppTwoStepVerificationReEnterPasswordTab extends SliderSuperTab {\r\n public state: AccountPassword;\r\n public passwordInputField: PasswordInputField;\r\n public plainPassword: string;\r\n public newPassword: string;\r\n\r\n protected init() {\r\n this.container.classList.add('two-step-verification', 'two-step-verification-enter-password', 'two-step-verification-re-enter-password');\r\n this.setTitle('PleaseReEnterPassword');\r\n\r\n const section = new SettingSection({\r\n noDelimiter: true\r\n });\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const passwordInputField = this.passwordInputField = new PasswordInputField({\r\n name: 're-enter-password',\r\n label: 'PleaseReEnterPassword'\r\n });\r\n\r\n const monkey = new TrackingMonkey(passwordInputField, 157);\r\n\r\n const btnContinue = Button('btn-primary btn-color-primary', {text: 'Continue'});\r\n\r\n inputWrapper.append(passwordInputField.container, btnContinue);\r\n section.content.append(monkey.container, inputWrapper);\r\n\r\n this.scrollable.container.append(section.container);\r\n\r\n passwordInputField.input.addEventListener('keypress', (e) => {\r\n if(passwordInputField.input.classList.contains('error')) {\r\n passwordInputField.setState(InputState.Neutral);\r\n }\r\n \r\n if(e.key === 'Enter') {\r\n return onContinueClick();\r\n }\r\n });\r\n\r\n const verifyInput = () => {\r\n if(this.newPassword !== passwordInputField.value) {\r\n passwordInputField.setError();\r\n return false;\r\n }\r\n\r\n return true;\r\n };\r\n\r\n const onContinueClick = (e?: Event) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n\r\n if(!verifyInput()) return;\r\n\r\n const tab = new AppTwoStepVerificationHintTab(this.slider);\r\n tab.state = this.state;\r\n tab.plainPassword = this.plainPassword;\r\n tab.newPassword = this.newPassword;\r\n tab.open();\r\n };\r\n attachClickEvent(btnContinue, onContinueClick);\r\n\r\n return monkey.load();\r\n }\r\n \r\n onOpenAfterTimeout() {\r\n this.passwordInputField.input.focus();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport AppTwoStepVerificationTab from \".\";\r\nimport { SettingSection } from \"../..\";\r\nimport { cancelEvent } from \"../../../../helpers/dom/cancelEvent\";\r\nimport { canFocus } from \"../../../../helpers/dom/canFocus\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\nimport replaceContent from \"../../../../helpers/dom/replaceContent\";\r\nimport { AccountPassword } from \"../../../../layer\";\r\nimport I18n, { i18n } from \"../../../../lib/langPack\";\r\nimport passwordManager from \"../../../../lib/mtproto/passwordManager\";\r\nimport RichTextProcessor from \"../../../../lib/richtextprocessor\";\r\nimport Button from \"../../../button\";\r\nimport { putPreloader } from \"../../../misc\";\r\nimport PasswordMonkey from \"../../../monkeys/password\";\r\nimport PasswordInputField from \"../../../passwordInputField\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport AppTwoStepVerificationReEnterPasswordTab from \"./reEnterPassword\";\r\n\r\nexport default class AppTwoStepVerificationEnterPasswordTab extends SliderSuperTab {\r\n public state: AccountPassword;\r\n public passwordInputField: PasswordInputField;\r\n public plainPassword: string;\r\n public isFirst = true;\r\n \r\n protected init() {\r\n const isNew = !this.state.pFlags.has_password || this.plainPassword;\r\n this.container.classList.add('two-step-verification', 'two-step-verification-enter-password');\r\n this.setTitle(isNew ? 'PleaseEnterFirstPassword' : 'PleaseEnterCurrentPassword');\r\n\r\n const section = new SettingSection({\r\n noDelimiter: true\r\n });\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const passwordInputField = this.passwordInputField = new PasswordInputField({\r\n name: 'enter-password',\r\n label: isNew ? 'PleaseEnterFirstPassword' : (this.state.hint ? undefined : 'LoginPassword'),\r\n labelText: !isNew && this.state.hint ? RichTextProcessor.wrapEmojiText(this.state.hint) : undefined\r\n });\r\n\r\n const monkey = new PasswordMonkey(passwordInputField, 157);\r\n\r\n const btnContinue = Button('btn-primary btn-color-primary');\r\n const textEl = new I18n.IntlElement({key: 'Continue'});\r\n\r\n btnContinue.append(textEl.element);\r\n\r\n inputWrapper.append(passwordInputField.container, btnContinue);\r\n section.content.append(monkey.container, inputWrapper);\r\n\r\n this.scrollable.container.append(section.container);\r\n\r\n passwordInputField.input.addEventListener('keypress', (e) => {\r\n if(passwordInputField.input.classList.contains('error')) {\r\n passwordInputField.input.classList.remove('error');\r\n textEl.key = 'Continue';\r\n textEl.update();\r\n }\r\n \r\n if(e.key === 'Enter') {\r\n return onContinueClick();\r\n }\r\n });\r\n\r\n const verifyInput = () => {\r\n if(!passwordInputField.value.length) {\r\n passwordInputField.input.classList.add('error');\r\n return false;\r\n }\r\n\r\n return true;\r\n };\r\n\r\n let onContinueClick: (e?: Event) => void;\r\n if(!isNew) {\r\n let getStateInterval: number;\r\n\r\n let getState = () => {\r\n // * just to check session relevance\r\n if(!getStateInterval) {\r\n getStateInterval = window.setInterval(getState, 10e3);\r\n }\r\n \r\n return passwordManager.getState().then(_state => {\r\n this.state = _state;\r\n \r\n if(this.state.hint) {\r\n passwordInputField.label.innerHTML = RichTextProcessor.wrapEmojiText(this.state.hint);\r\n } else {\r\n replaceContent(passwordInputField.label, i18n('LoginPassword'));\r\n }\r\n });\r\n };\r\n \r\n const submit = (e?: Event) => {\r\n if(!verifyInput()) {\r\n cancelEvent(e);\r\n return;\r\n }\r\n\r\n btnContinue.setAttribute('disabled', 'true');\r\n textEl.key = 'PleaseWait';\r\n textEl.update();\r\n const preloader = putPreloader(btnContinue);\r\n \r\n const plainPassword = passwordInputField.value;\r\n passwordManager.check(passwordInputField.value, this.state).then(auth => {\r\n console.log(auth);\r\n \r\n if(auth._ === 'auth.authorization') {\r\n clearInterval(getStateInterval);\r\n if(monkey) monkey.remove();\r\n const tab = new AppTwoStepVerificationTab(this.slider);\r\n tab.state = this.state;\r\n tab.plainPassword = plainPassword;\r\n tab.open();\r\n this.slider.removeTabFromHistory(this);\r\n }\r\n }, (err) => {\r\n btnContinue.removeAttribute('disabled');\r\n passwordInputField.input.classList.add('error');\r\n \r\n switch(err.type) {\r\n default:\r\n //btnContinue.innerText = err.type;\r\n textEl.key = 'TwoStepAuth.InvalidPassword';\r\n textEl.update();\r\n preloader.remove();\r\n passwordInputField.select();\r\n break;\r\n }\r\n \r\n getState();\r\n });\r\n };\r\n \r\n onContinueClick = submit;\r\n\r\n getState();\r\n } else {\r\n onContinueClick = (e) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n\r\n if(!verifyInput()) return;\r\n\r\n const tab = new AppTwoStepVerificationReEnterPasswordTab(this.slider);\r\n tab.state = this.state;\r\n tab.newPassword = passwordInputField.value;\r\n tab.plainPassword = this.plainPassword;\r\n tab.open();\r\n };\r\n }\r\n\r\n attachClickEvent(btnContinue, onContinueClick);\r\n\r\n return monkey.load();\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n if(!canFocus(this.isFirst)) return;\r\n this.passwordInputField.input.focus();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"../..\";\r\nimport { attachClickEvent } from \"../../../../helpers/dom/clickEvent\";\r\nimport { AccountPassword } from \"../../../../layer\";\r\nimport appStickersManager from \"../../../../lib/appManagers/appStickersManager\";\r\nimport { _i18n } from \"../../../../lib/langPack\";\r\nimport passwordManager from \"../../../../lib/mtproto/passwordManager\";\r\nimport Button from \"../../../button\";\r\nimport PopupPeer from \"../../../popups/peer\";\r\nimport { SliderSuperTab } from \"../../../slider\";\r\nimport { wrapSticker } from \"../../../wrappers\";\r\nimport AppSettingsTab from \"../settings\";\r\nimport AppTwoStepVerificationEmailTab from \"./email\";\r\nimport AppTwoStepVerificationEnterPasswordTab from \"./enterPassword\";\r\n\r\nexport default class AppTwoStepVerificationTab extends SliderSuperTab {\r\n public state: AccountPassword;\r\n public plainPassword: string;\r\n\r\n protected init() {\r\n this.container.classList.add('two-step-verification', 'two-step-verification-main');\r\n this.setTitle('TwoStepVerificationTitle');\r\n\r\n const section = new SettingSection({\r\n caption: true,\r\n noDelimiter: true\r\n });\r\n\r\n const emoji = '🔐';\r\n const doc = appStickersManager.getAnimatedEmojiSticker(emoji);\r\n const stickerContainer = document.createElement('div');\r\n\r\n if(doc) {\r\n wrapSticker({\r\n doc,\r\n div: stickerContainer,\r\n loop: false,\r\n play: true,\r\n width: 168,\r\n height: 168,\r\n emoji\r\n }).then(() => {\r\n // this.animation = player;\r\n });\r\n } else {\r\n stickerContainer.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n section.content.append(stickerContainer);\r\n\r\n const c = section.generateContentElement();\r\n if(this.state.pFlags.has_password) {\r\n _i18n(section.caption, 'TwoStepAuth.GenericHelp');\r\n\r\n const btnChangePassword = Button('btn-primary btn-transparent', {icon: 'edit', text: 'TwoStepAuth.ChangePassword'});\r\n const btnDisablePassword = Button('btn-primary btn-transparent', {icon: 'passwordoff', text: 'TwoStepAuth.RemovePassword'});\r\n const btnSetRecoveryEmail = Button('btn-primary btn-transparent', {icon: 'email', text: this.state.pFlags.has_recovery ? 'TwoStepAuth.ChangeEmail' : 'TwoStepAuth.SetupEmail'});\r\n\r\n attachClickEvent(btnChangePassword, () => {\r\n const tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);\r\n tab.state = this.state;\r\n tab.plainPassword = this.plainPassword;\r\n tab.open();\r\n });\r\n\r\n attachClickEvent(btnDisablePassword, () => {\r\n const popup = new PopupPeer('popup-disable-password', {\r\n buttons: [{\r\n langKey: 'Disable',\r\n callback: () => {\r\n passwordManager.updateSettings({currentPassword: this.plainPassword}).then(() => {\r\n this.slider.sliceTabsUntilTab(AppSettingsTab, this);\r\n this.close();\r\n });\r\n },\r\n isDanger: true,\r\n }], \r\n titleLangKey: 'TurnPasswordOffQuestionTitle',\r\n descriptionLangKey: 'TurnPasswordOffQuestion'\r\n });\r\n\r\n popup.show();\r\n });\r\n\r\n attachClickEvent(btnSetRecoveryEmail, () => {\r\n const tab = new AppTwoStepVerificationEmailTab(this.slider);\r\n tab.state = this.state;\r\n tab.hint = this.state.hint;\r\n tab.plainPassword = this.plainPassword;\r\n tab.newPassword = this.plainPassword;\r\n tab.isFirst = true;\r\n tab.open();\r\n });\r\n\r\n c.append(btnChangePassword, btnDisablePassword, btnSetRecoveryEmail);\r\n } else {\r\n _i18n(section.caption, 'TwoStepAuth.SetPasswordHelp');\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n const btnSetPassword = Button('btn-primary btn-color-primary', {text: 'TwoStepVerificationSetPassword'});\r\n \r\n inputWrapper.append(btnSetPassword);\r\n c.append(inputWrapper);\r\n\r\n attachClickEvent(btnSetPassword, (e) => {\r\n const tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);\r\n tab.state = this.state;\r\n tab.open();\r\n });\r\n }\r\n\r\n this.scrollable.container.append(section.container);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\r\nimport PrivacySection from \"../../../privacySection\";\r\nimport { LangPackKey } from \"../../../../lib/langPack\";\r\n\r\nexport default class AppPrivacyLastSeenTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.container.classList.add('privacy-tab', 'privacy-last-seen');\r\n this.setTitle('PrivacyLastSeen');\r\n\r\n const caption: LangPackKey = 'PrivacySettingsController.LastSeenDescription';\r\n new PrivacySection({\r\n tab: this,\r\n title: 'LastSeenTitle',\r\n inputKey: 'inputPrivacyKeyStatusTimestamp',\r\n captions: [caption, caption, caption],\r\n exceptionTexts: ['PrivacySettingsController.NeverShare', 'PrivacySettingsController.AlwaysShare'],\r\n appendTo: this.scrollable\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\r\nimport PrivacySection from \"../../../privacySection\";\r\nimport { PrivacyType } from \"../../../../lib/appManagers/appPrivacyManager\";\r\nimport { LangPackKey } from \"../../../../lib/langPack\";\r\n\r\nexport default class AppPrivacyProfilePhotoTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.container.classList.add('privacy-tab', 'privacy-profile-photo');\r\n this.setTitle('PrivacyProfilePhoto');\r\n\r\n const caption: LangPackKey = 'PrivacySettingsController.ProfilePhoto.CustomHelp';\r\n new PrivacySection({\r\n tab: this,\r\n title: 'PrivacyProfilePhotoTitle',\r\n inputKey: 'inputPrivacyKeyProfilePhoto',\r\n captions: [caption, caption, caption],\r\n exceptionTexts: ['PrivacySettingsController.NeverShare', 'PrivacySettingsController.AlwaysShare'],\r\n appendTo: this.scrollable,\r\n skipTypes: [PrivacyType.Nobody]\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\r\nimport PrivacySection from \"../../../privacySection\";\r\nimport { LangPackKey } from \"../../../../lib/langPack\";\r\n\r\nexport default class AppPrivacyForwardMessagesTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.container.classList.add('privacy-tab', 'privacy-forward-messages');\r\n this.setTitle('PrivacySettings.Forwards');\r\n\r\n const caption: LangPackKey = 'PrivacySettingsController.Forwards.CustomHelp';\r\n new PrivacySection({\r\n tab: this,\r\n title: 'PrivacyForwardsTitle',\r\n inputKey: 'inputPrivacyKeyForwards',\r\n captions: [caption, caption, caption],\r\n exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],\r\n appendTo: this.scrollable\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\r\nimport PrivacySection from \"../../../privacySection\";\r\nimport { LangPackKey } from \"../../../../lib/langPack\";\r\nimport { PrivacyType } from \"../../../../lib/appManagers/appPrivacyManager\";\r\n\r\nexport default class AppPrivacyAddToGroupsTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.container.classList.add('privacy-tab', 'privacy-add-to-groups');\r\n this.setTitle('PrivacySettings.Groups');\r\n\r\n const caption: LangPackKey = 'PrivacySettingsController.GroupDescription';\r\n new PrivacySection({\r\n tab: this,\r\n title: 'WhoCanAddMe',\r\n inputKey: 'inputPrivacyKeyChatInvite',\r\n captions: [caption, caption, caption],\r\n exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],\r\n appendTo: this.scrollable,\r\n skipTypes: [PrivacyType.Nobody]\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTabEventable } from \"../../../sliderTab\";\r\nimport PrivacySection from \"../../../privacySection\";\r\nimport { LangPackKey } from \"../../../../lib/langPack\";\r\n\r\nexport default class AppPrivacyCallsTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.container.classList.add('privacy-tab', 'privacy-calls');\r\n this.setTitle('PrivacySettings.VoiceCalls');\r\n\r\n const caption: LangPackKey = 'PrivacySettingsController.PhoneCallDescription';\r\n new PrivacySection({\r\n tab: this,\r\n title: 'WhoCanCallMe',\r\n inputKey: 'inputPrivacyKeyPhoneCall',\r\n captions: [caption, caption, caption],\r\n exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],\r\n appendTo: this.scrollable\r\n });\r\n\r\n {\r\n const caption: LangPackKey = 'PrivacySettingsController.P2p.Desc';\r\n new PrivacySection({\r\n tab: this,\r\n title: 'PrivacyP2PHeader',\r\n inputKey: 'inputPrivacyKeyPhoneP2P',\r\n captions: [caption, caption, caption],\r\n exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],\r\n appendTo: this.scrollable\r\n });\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport { SettingSection } from \"..\";\r\nimport Button from \"../../button\";\r\nimport Row from \"../../row\";\r\nimport { Authorization } from \"../../../layer\";\r\nimport { formatDateAccordingToTodayNew } from \"../../../helpers/date\";\r\nimport { attachContextMenuListener, openBtnMenu, positionMenu } from \"../../misc\";\r\nimport ButtonMenu from \"../../buttonMenu\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport { toast } from \"../../toast\";\r\nimport AppPrivacyAndSecurityTab from \"./privacyAndSecurity\";\r\nimport I18n from \"../../../lib/langPack\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\r\n\r\nexport default class AppActiveSessionsTab extends SliderSuperTab {\r\n public privacyTab: AppPrivacyAndSecurityTab;\r\n public authorizations: Authorization.authorization[];\r\n private menuElement: HTMLElement;\r\n \r\n protected init() {\r\n this.container.classList.add('active-sessions-container');\r\n this.setTitle('SessionsTitle');\r\n\r\n const Session = (auth: Authorization.authorization) => {\r\n const row = new Row({\r\n title: [auth.app_name, auth.app_version].join(' '),\r\n subtitle: [auth.ip, auth.country].join(' - '),\r\n clickable: true,\r\n titleRight: auth.pFlags.current ? undefined : formatDateAccordingToTodayNew(new Date(Math.max(auth.date_active, auth.date_created) * 1000))\r\n });\r\n\r\n row.container.dataset.hash = auth.hash;\r\n\r\n const midtitle = document.createElement('div');\r\n midtitle.classList.add('row-midtitle');\r\n midtitle.innerHTML = [auth.device_model, auth.system_version || auth.platform].filter(Boolean).join(', ');\r\n\r\n row.subtitle.parentElement.insertBefore(midtitle, row.subtitle);\r\n\r\n return row;\r\n };\r\n\r\n const authorizations = this.authorizations.slice();\r\n\r\n {\r\n const section = new SettingSection({\r\n name: 'CurrentSession'\r\n });\r\n\r\n const auth = authorizations.findAndSplice(auth => auth.pFlags.current);\r\n const session = Session(auth);\r\n\r\n section.content.append(session.container);\r\n\r\n if(authorizations.length) {\r\n const btnTerminate = Button('btn-primary btn-transparent danger', {icon: 'stop', text: 'TerminateAllSessions'});\r\n attachClickEvent(btnTerminate, (e) => {\r\n new PopupPeer('revoke-session', {\r\n buttons: [{\r\n langKey: 'Terminate',\r\n isDanger: true,\r\n callback: () => {\r\n const toggle = toggleDisability([btnTerminate], true);\r\n apiManager.invokeApi('auth.resetAuthorizations').then(value => {\r\n //toggleDisability([btnTerminate], false);\r\n btnTerminate.remove();\r\n otherSection.container.remove();\r\n this.privacyTab.updateActiveSessions();\r\n }, onError).finally(() => {\r\n toggle();\r\n });\r\n }\r\n }],\r\n titleLangKey: 'AreYouSureSessionsTitle',\r\n descriptionLangKey: 'AreYouSureSessions'\r\n }).show();\r\n });\r\n \r\n section.content.append(btnTerminate);\r\n }\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n if(!authorizations.length) {\r\n return;\r\n }\r\n\r\n const otherSection = new SettingSection({\r\n name: 'OtherSessions'\r\n });\r\n\r\n authorizations.forEach(auth => {\r\n otherSection.content.append(Session(auth).container);\r\n });\r\n\r\n this.scrollable.append(otherSection.container);\r\n\r\n const onError = (err: any) => {\r\n if(err.type === 'FRESH_RESET_AUTHORISATION_FORBIDDEN') {\r\n toast(I18n.format('RecentSessions.Error.FreshReset', true));\r\n }\r\n };\r\n\r\n let target: HTMLElement;\r\n const onTerminateClick = () => {\r\n const hash = target.dataset.hash;\r\n \r\n new PopupPeer('revoke-session', {\r\n buttons: [{\r\n langKey: 'Terminate',\r\n isDanger: true,\r\n callback: () => {\r\n apiManager.invokeApi('account.resetAuthorization', {hash})\r\n .then(value => {\r\n if(value) {\r\n target.remove();\r\n this.privacyTab.updateActiveSessions();\r\n }\r\n }, onError);\r\n }\r\n }],\r\n titleLangKey: 'AreYouSureSessionTitle',\r\n descriptionLangKey: 'TerminateSessionText'\r\n }).show();\r\n };\r\n\r\n const element = this.menuElement = ButtonMenu([{\r\n icon: 'stop',\r\n text: 'Terminate',\r\n onClick: onTerminateClick\r\n }]);\r\n element.id = 'active-sessions-contextmenu';\r\n element.classList.add('contextmenu');\r\n\r\n document.getElementById('page-chats').append(element);\r\n\r\n attachContextMenuListener(this.scrollable.container, (e) => {\r\n target = findUpClassName(e.target, 'row');\r\n if(!target || target.dataset.hash === '0') {\r\n return;\r\n }\r\n\r\n if(e instanceof MouseEvent) e.preventDefault();\r\n // smth\r\n if(e instanceof MouseEvent) e.cancelBubble = true;\r\n\r\n positionMenu(e, element);\r\n openBtnMenu(element);\r\n });\r\n\r\n attachClickEvent(this.scrollable.container, (e) => {\r\n target = findUpClassName(e.target, 'row');\r\n if(!target || target.dataset.hash === '0') {\r\n return;\r\n }\r\n\r\n onTerminateClick();\r\n });\r\n }\r\n\r\n onCloseAfterTimeout() {\r\n if(this.menuElement) {\r\n this.menuElement.remove();\r\n }\r\n\r\n return super.onCloseAfterTimeout();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport { SettingSection } from \"..\";\r\nimport { attachContextMenuListener, openBtnMenu, positionMenu } from \"../../misc\";\r\nimport ButtonMenu from \"../../buttonMenu\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport PopupPickUser from \"../../popups/pickUser\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport findUpTag from \"../../../helpers/dom/findUpTag\";\r\nimport ButtonCorner from \"../../buttonCorner\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\n\r\nexport default class AppBlockedUsersTab extends SliderSuperTab {\r\n public peerIds: number[];\r\n private menuElement: HTMLElement;\r\n \r\n protected init() {\r\n this.container.classList.add('blocked-users-container');\r\n this.setTitle('BlockedUsers');\r\n\r\n {\r\n const section = new SettingSection({\r\n caption: 'BlockedUsersInfo'\r\n });\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n const btnAdd = ButtonCorner({icon: 'add', className: 'is-visible'});\r\n this.content.append(btnAdd);\r\n\r\n attachClickEvent(btnAdd, (e) => {\r\n new PopupPickUser({\r\n peerTypes: ['contacts'],\r\n placeholder: 'BlockModal.Search.Placeholder',\r\n onSelect: (peerId) => {\r\n //console.log('block', peerId);\r\n appUsersManager.toggleBlock(peerId, true);\r\n },\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n const list = appDialogsManager.createChatList();\r\n this.scrollable.container.classList.add('chatlist-container');\r\n this.scrollable.append(list);\r\n\r\n const add = (peerId: number, append: boolean) => {\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId,\r\n container: list,\r\n drawStatus: false,\r\n rippleEnabled: true,\r\n avatarSize: 48,\r\n append\r\n });\r\n\r\n const user = appUsersManager.getUser(peerId);\r\n if(user.pFlags.bot) {\r\n dom.lastMessageSpan.append('@' + user.username);\r\n } else {\r\n if(user.phone) dom.lastMessageSpan.innerHTML = appUsersManager.formatUserPhone(user.phone);\r\n else dom.lastMessageSpan.append(user.username ? '@' + user.username : appUsersManager.getUserStatusString(peerId));\r\n }\r\n\r\n //dom.titleSpan.innerHTML = 'Raaid El Syed';\r\n //dom.lastMessageSpan.innerHTML = '+1 234 567891';\r\n };\r\n\r\n for(const peerId of this.peerIds) {\r\n add(peerId, true);\r\n }\r\n\r\n let target: HTMLElement;\r\n const onUnblock = () => {\r\n const peerId = +target.dataset.peerId;\r\n appUsersManager.toggleBlock(peerId, false);\r\n };\r\n\r\n const element = this.menuElement = ButtonMenu([{\r\n icon: 'lockoff',\r\n text: 'Unblock',\r\n onClick: onUnblock,\r\n options: {listenerSetter: this.listenerSetter}\r\n }]);\r\n element.id = 'blocked-users-contextmenu';\r\n element.classList.add('contextmenu');\r\n\r\n document.getElementById('page-chats').append(element);\r\n\r\n attachContextMenuListener(this.scrollable.container, (e) => {\r\n target = findUpTag(e.target, 'LI');\r\n if(!target) {\r\n return;\r\n }\r\n\r\n if(e instanceof MouseEvent) e.preventDefault();\r\n // smth\r\n if(e instanceof MouseEvent) e.cancelBubble = true;\r\n\r\n positionMenu(e, element);\r\n openBtnMenu(element);\r\n }, this.listenerSetter);\r\n\r\n this.listenerSetter.add(rootScope)('peer_block', (update) => {\r\n const {peerId, blocked} = update;\r\n const li = list.querySelector(`[data-peer-id=\"${peerId}\"]`);\r\n if(blocked) {\r\n if(!li) {\r\n add(peerId, false);\r\n }\r\n } else {\r\n if(li) {\r\n li.remove();\r\n }\r\n }\r\n });\r\n\r\n const LOAD_COUNT = 50;\r\n let loading = false;\r\n this.scrollable.onScrolledBottom = () => {\r\n if(loading) {\r\n return;\r\n }\r\n\r\n loading = true;\r\n appUsersManager.getBlocked(list.childElementCount, LOAD_COUNT).then(res => {\r\n for(const peerId of res.peerIds) {\r\n add(peerId, true);\r\n }\r\n\r\n if(res.peerIds.length < LOAD_COUNT || list.childElementCount === res.count) {\r\n this.scrollable.onScrolledBottom = null;\r\n }\r\n\r\n this.scrollable.checkForTriggers();\r\n }).finally(() => {\r\n loading = false;\r\n });\r\n };\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n this.scrollable.onScroll();\r\n }\r\n\r\n onCloseAfterTimeout() {\r\n if(this.menuElement) {\r\n this.menuElement.remove();\r\n }\r\n\r\n return super.onCloseAfterTimeout();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport { SettingSection } from \"..\";\r\nimport Row from \"../../row\";\r\nimport { AccountPassword, Authorization, InputPrivacyKey, Updates } from \"../../../layer\";\r\nimport appPrivacyManager, { PrivacyType } from \"../../../lib/appManagers/appPrivacyManager\";\r\nimport AppPrivacyPhoneNumberTab from \"./privacy/phoneNumber\";\r\nimport AppTwoStepVerificationTab from \"./2fa\";\r\nimport passwordManager from \"../../../lib/mtproto/passwordManager\";\r\nimport AppTwoStepVerificationEnterPasswordTab from \"./2fa/enterPassword\";\r\nimport AppTwoStepVerificationEmailConfirmationTab from \"./2fa/emailConfirmation\";\r\nimport AppPrivacyLastSeenTab from \"./privacy/lastSeen\";\r\nimport AppPrivacyProfilePhotoTab from \"./privacy/profilePhoto\";\r\nimport AppPrivacyForwardMessagesTab from \"./privacy/forwardMessages\";\r\nimport AppPrivacyAddToGroupsTab from \"./privacy/addToGroups\";\r\nimport AppPrivacyCallsTab from \"./privacy/calls\";\r\nimport AppActiveSessionsTab from \"./activeSessions\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport AppBlockedUsersTab from \"./blockedUsers\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport { convertKeyToInputKey } from \"../../../helpers/string\";\r\nimport { i18n, LangPackKey, _i18n } from \"../../../lib/langPack\";\r\nimport replaceContent from \"../../../helpers/dom/replaceContent\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport appDraftsManager from \"../../../lib/appManagers/appDraftsManager\";\r\nimport Button from \"../../button\";\r\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\r\n\r\nexport default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {\r\n private activeSessionsRow: Row;\r\n private authorizations: Authorization.authorization[];\r\n\r\n protected init() {\r\n this.container.classList.add('dont-u-dare-block-me');\r\n this.setTitle('PrivacySettings');\r\n\r\n const SUBTITLE: LangPackKey = 'Loading';\r\n\r\n {\r\n const section = new SettingSection({noDelimiter: true});\r\n\r\n let blockedPeerIds: number[];\r\n const blockedUsersRow = new Row({\r\n icon: 'deleteuser',\r\n titleLangKey: 'BlockedUsers',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n const tab = new AppBlockedUsersTab(this.slider);\r\n tab.peerIds = blockedPeerIds;\r\n tab.open();\r\n }\r\n });\r\n blockedUsersRow.freezed = true;\r\n\r\n let passwordState: AccountPassword;\r\n const twoFactorRowOptions = {\r\n icon: 'lock',\r\n titleLangKey: 'TwoStepVerification' as LangPackKey,\r\n subtitleLangKey: SUBTITLE,\r\n clickable: (e: Event) => {\r\n let tab: AppTwoStepVerificationTab | AppTwoStepVerificationEnterPasswordTab | AppTwoStepVerificationEmailConfirmationTab;\r\n if(passwordState.pFlags.has_password) {\r\n tab = new AppTwoStepVerificationEnterPasswordTab(this.slider);\r\n } else if(passwordState.email_unconfirmed_pattern) {\r\n tab = new AppTwoStepVerificationEmailConfirmationTab(this.slider);\r\n tab.email = passwordState.email_unconfirmed_pattern;\r\n tab.length = 6;\r\n tab.isFirst = true;\r\n passwordManager.resendPasswordEmail();\r\n } else {\r\n tab = new AppTwoStepVerificationTab(this.slider);\r\n }\r\n \r\n tab.state = passwordState;\r\n tab.open();\r\n }\r\n };\r\n \r\n const twoFactorRow = new Row(twoFactorRowOptions);\r\n twoFactorRow.freezed = true;\r\n\r\n const activeSessionsRow = this.activeSessionsRow = new Row({\r\n icon: 'activesessions',\r\n titleLangKey: 'SessionsTitle',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n const tab = new AppActiveSessionsTab(this.slider);\r\n tab.privacyTab = this;\r\n tab.authorizations = this.authorizations;\r\n tab.open();\r\n }\r\n });\r\n activeSessionsRow.freezed = true;\r\n\r\n section.content.append(blockedUsersRow.container, twoFactorRow.container, activeSessionsRow.container);\r\n this.scrollable.append(section.container);\r\n\r\n const setBlockedCount = (count: number) => {\r\n if(count) {\r\n replaceContent(blockedUsersRow.subtitle, i18n('PrivacySettingsController.UserCount', [count]));\r\n } else {\r\n replaceContent(blockedUsersRow.subtitle, i18n('BlockedEmpty', [count]));\r\n }\r\n };\r\n\r\n this.listenerSetter.add(rootScope)('peer_block', () => {\r\n /* const {blocked, peerId} = update;\r\n if(!blocked) blockedPeerIds.findAndSplice(p => p === peerId);\r\n else blockedPeerIds.unshift(peerId);\r\n blockedCount += blocked ? 1 : -1;\r\n setBlockedCount(blockedCount); */\r\n updateBlocked();\r\n });\r\n\r\n const updateBlocked = () => {\r\n appUsersManager.getBlocked().then(res => {\r\n blockedUsersRow.freezed = false;\r\n setBlockedCount(res.count);\r\n blockedPeerIds = res.peerIds;\r\n });\r\n };\r\n\r\n updateBlocked();\r\n\r\n passwordManager.getState().then(state => {\r\n passwordState = state;\r\n replaceContent(twoFactorRow.subtitle, i18n(state.pFlags.has_password ? 'PrivacyAndSecurity.Item.On' : 'PrivacyAndSecurity.Item.Off'));\r\n twoFactorRow.freezed = false;\r\n \r\n //console.log('password state', state);\r\n });\r\n\r\n this.updateActiveSessions();\r\n }\r\n\r\n {\r\n const section = new SettingSection({name: 'PrivacyTitle'});\r\n\r\n section.content.classList.add('privacy-navigation-container');\r\n\r\n const rowsByKeys: Partial<{\r\n [key in InputPrivacyKey['_']]: Row\r\n }> = {};\r\n\r\n const numberVisibilityRow = rowsByKeys['inputPrivacyKeyPhoneNumber'] = new Row({\r\n titleLangKey: 'PrivacyPhoneTitle',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n new AppPrivacyPhoneNumberTab(this.slider).open();\r\n }\r\n });\r\n\r\n const lastSeenTimeRow = rowsByKeys['inputPrivacyKeyStatusTimestamp'] = new Row({\r\n titleLangKey: 'LastSeenTitle',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n new AppPrivacyLastSeenTab(this.slider).open();\r\n }\r\n });\r\n\r\n const photoVisibilityRow = rowsByKeys['inputPrivacyKeyProfilePhoto'] = new Row({\r\n titleLangKey: 'PrivacyProfilePhotoTitle',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n new AppPrivacyProfilePhotoTab(this.slider).open();\r\n }\r\n });\r\n\r\n const callRow = rowsByKeys['inputPrivacyKeyPhoneCall'] = new Row({\r\n titleLangKey: 'WhoCanCallMe',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n new AppPrivacyCallsTab(this.slider).open();\r\n }\r\n });\r\n\r\n const linkAccountRow = rowsByKeys['inputPrivacyKeyForwards'] = new Row({\r\n titleLangKey: 'PrivacyForwardsTitle',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n new AppPrivacyForwardMessagesTab(this.slider).open();\r\n }\r\n });\r\n\r\n const groupChatsAddRow = rowsByKeys['inputPrivacyKeyChatInvite'] = new Row({\r\n titleLangKey: 'WhoCanAddMe',\r\n subtitleLangKey: SUBTITLE,\r\n clickable: () => {\r\n new AppPrivacyAddToGroupsTab(this.slider).open();\r\n }\r\n });\r\n\r\n const updatePrivacyRow = (key: InputPrivacyKey['_']) => {\r\n const row = rowsByKeys[key];\r\n if(!row) {\r\n return;\r\n }\r\n\r\n appPrivacyManager.getPrivacy(key).then(rules => {\r\n const details = appPrivacyManager.getPrivacyRulesDetails(rules);\r\n const langKey = details.type === PrivacyType.Everybody ? 'PrivacySettingsController.Everbody' : (details.type === PrivacyType.Contacts ? 'PrivacySettingsController.MyContacts' : 'PrivacySettingsController.Nobody');\r\n const disallowLength = details.disallowPeers.users.length + details.disallowPeers.chats.length;\r\n const allowLength = details.allowPeers.users.length + details.allowPeers.chats.length;\r\n\r\n row.subtitle.innerHTML = '';\r\n const s = i18n(langKey);\r\n row.subtitle.append(s);\r\n if(disallowLength || allowLength) {\r\n row.subtitle.append(` (${[-disallowLength, allowLength ? '+' + allowLength : 0].filter(Boolean).join(', ')})`);\r\n }\r\n });\r\n };\r\n\r\n section.content.append(numberVisibilityRow.container, lastSeenTimeRow.container, photoVisibilityRow.container, callRow.container, linkAccountRow.container, groupChatsAddRow.container);\r\n this.scrollable.append(section.container);\r\n\r\n for(const key in rowsByKeys) {\r\n updatePrivacyRow(key as keyof typeof rowsByKeys);\r\n }\r\n\r\n rootScope.addEventListener('privacy_update', (update) => {\r\n updatePrivacyRow(convertKeyToInputKey(update.key._) as any);\r\n });\r\n }\r\n\r\n const promises: Promise<any>[] = [];\r\n {\r\n const section = new SettingSection({name: 'Privacy.SensitiveContent'});\r\n section.container.classList.add('hide');\r\n\r\n promises.push(apiManager.invokeApi('account.getContentSettings').then(settings => {\r\n if(!settings.pFlags.sensitive_can_change) {\r\n return;\r\n }\r\n \r\n const enabled = settings.pFlags.sensitive_enabled;\r\n\r\n const sensitiveRow = new Row({\r\n checkboxField: new CheckboxField({text: 'PrivacyAndSecurity.SensitiveText', checked: enabled}),\r\n subtitleLangKey: 'PrivacyAndSecurity.SensitiveDesc',\r\n noCheckboxSubtitle: true\r\n });\r\n \r\n section.content.append(sensitiveRow.container);\r\n section.container.classList.remove('hide');\r\n \r\n this.eventListener.addEventListener('destroy', () => {\r\n const _enabled = sensitiveRow.checkboxField.checked;\r\n const isChanged = _enabled !== enabled;\r\n if(!isChanged) {\r\n return;\r\n }\r\n \r\n apiManager.invokeApi('account.setContentSettings', {\r\n sensitive_enabled: _enabled\r\n });\r\n }, {once: true});\r\n }));\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n {\r\n const section = new SettingSection({name: 'FilterChats'});\r\n\r\n const onDeleteClick = () => {\r\n const popup = new PopupPeer('popup-delete-drafts', {\r\n buttons: [{\r\n langKey: 'Delete',\r\n callback: () => {\r\n const toggle = toggleDisability([deleteButton], true);\r\n appDraftsManager.clearAllDrafts().then(() => {\r\n toggle();\r\n });\r\n },\r\n isDanger: true,\r\n }], \r\n titleLangKey: 'AreYouSureClearDraftsTitle',\r\n descriptionLangKey: 'AreYouSureClearDrafts'\r\n });\r\n \r\n popup.show();\r\n };\r\n\r\n const deleteButton = Button('btn-primary btn-transparent', {icon: 'delete', text: 'PrivacyDeleteCloudDrafts'});\r\n this.listenerSetter.add(deleteButton)('click', onDeleteClick);\r\n section.content.append(deleteButton);\r\n\r\n /* promises.push(apiManager.invokeApi('messages.getAllDrafts').then(drafts => {\r\n const draftsRow = new Row({\r\n titleLangKey: 'PrivacyDeleteCloudDrafts',\r\n subtitleLangKey: 'Drafts',\r\n subtitleLangArgs: [(drafts as Updates.updates).updates.length],\r\n icon: 'delete',\r\n clickable: onDeleteClick\r\n });\r\n \r\n section.content.append(draftsRow.container);\r\n })); */\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n\r\n return Promise.all(promises);\r\n }\r\n\r\n public updateActiveSessions() {\r\n apiManager.invokeApi('account.getAuthorizations').then(auths => {\r\n this.activeSessionsRow.freezed = false;\r\n this.authorizations = auths.authorizations;\r\n _i18n(this.activeSessionsRow.subtitle, 'Privacy.Devices', [this.authorizations.length]);\r\n //console.log('auths', auths);\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport type ColorHsla = {\r\n h: number,\r\n s: number,\r\n l: number,\r\n a: number\r\n};\r\n\r\nexport type ColorRgba = [number, number, number, number];\r\n\r\n/**\r\n * @returns h [0, 360], s [0, 100], l [0, 100], a [0, 1]\r\n */\r\nexport function rgbaToHsla(r: number, g: number, b: number, a: number = 1): ColorHsla {\r\n r /= 255, g /= 255, b /= 255;\r\n const max = Math.max(r, g, b),\r\n min = Math.min(r, g, b);\r\n let h, s, l = (max + min) / 2;\r\n\r\n if(max === min) {\r\n h = s = 0; // achromatic\r\n } else {\r\n let d = max - min;\r\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\r\n switch (max) {\r\n case r:\r\n h = (g - b) / d + (g < b ? 6 : 0);\r\n break;\r\n case g:\r\n h = (b - r) / d + 2;\r\n break;\r\n case b:\r\n h = (r - g) / d + 4;\r\n break;\r\n }\r\n h /= 6;\r\n }\r\n\r\n return {\r\n h: h * 360,\r\n s: s * 100,\r\n l: l * 100,\r\n a\r\n };\r\n}\r\n\r\n// * https://stackoverflow.com/a/9493060/6758968\r\n/**\r\n * Converts an HSL color value to RGB. Conversion formula\r\n * adapted from http://en.wikipedia.org/wiki/HSL_color_space.\r\n * Assumes h in [0, 360], s, and l are contained in the set [0, 1], a in [0, 1] and\r\n * returns r, g, and b in the set [0, 255].\r\n *\r\n * @param {number} h The hue\r\n * @param {number} s The saturation\r\n * @param {number} l The lightness\r\n * @return {Array} The RGB representation\r\n */\r\nexport function hslaToRgba(h: number, s: number, l: number, a: number): ColorRgba {\r\n h /= 360, s /= 100, l /= 100;\r\n let r: number, g: number, b: number;\r\n\r\n if(s === 0) {\r\n r = g = b = l; // achromatic\r\n } else {\r\n const hue2rgb = function hue2rgb(p: number, q: number, t: number) {\r\n if(t < 0) t += 1;\r\n if(t > 1) t -= 1;\r\n if(t < 1/6) return p + (q - p) * 6 * t;\r\n if(t < 1/2) return q;\r\n if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;\r\n return p;\r\n }\r\n\r\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\r\n const p = 2 * l - q;\r\n r = hue2rgb(p, q, h + 1/3);\r\n g = hue2rgb(p, q, h);\r\n b = hue2rgb(p, q, h - 1/3);\r\n }\r\n\r\n return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), Math.round(a * 255)];\r\n}\r\n\r\nexport function hslaStringToRgba(hsla: string) {\r\n const splitted = hsla.slice(5, -1).split(', ');\r\n const alpha = +splitted.pop();\r\n const arr = splitted.map((val) => {\r\n if(val.endsWith('%')) {\r\n return +val.slice(0, -1);\r\n }\r\n \r\n return +val;\r\n });\r\n\r\n return hslaToRgba(arr[0], arr[1], arr[2], alpha);\r\n}\r\n\r\nexport function hexaToRgba(hexa: string) {\r\n const arr: ColorRgba = [] as any;\r\n const offset = 1;\r\n if(hexa.length === (3 + offset)) {\r\n for(let i = offset; i < hexa.length; ++i) {\r\n arr.push(parseInt(hexa[i] + hexa[i], 16));\r\n }\r\n } else if(hexa.length === (4 + offset)) {\r\n for(let i = offset; i < (hexa.length - 1); ++i) {\r\n arr.push(parseInt(hexa[i] + hexa[i], 16));\r\n }\r\n\r\n arr.push(parseInt(hexa[hexa.length - 1], 16));\r\n } else {\r\n for(let i = offset; i < hexa.length; i += 2) {\r\n arr.push(parseInt(hexa.slice(i, i + 2), 16));\r\n }\r\n }\r\n\r\n return arr;\r\n}\r\n\r\nexport function hexaToHsla(hexa: string) {\r\n const rgba = hexaToRgba(hexa);\r\n return rgbaToHsla(rgba[0], rgba[1], rgba[2], rgba[3]);\r\n}\r\n\r\nexport function rgbaToHexa(rgba: ColorRgba) {\r\n return '#' + rgba.map(v => ('0' + v.toString(16)).slice(-2)).join('');\r\n}\r\n\r\nexport function hslaStringToHexa(hsla: string) {\r\n return rgbaToHexa(hslaStringToRgba(hsla));\r\n}\r\n\r\nexport function hslaStringToHex(hsla: string) {\r\n return hslaStringToHexa(hsla).slice(0, -2);\r\n}\r\n","import { rgbaToHsla } from \"./color\";\r\n\r\n// * https://github.com/TelegramMessenger/Telegram-iOS/blob/3d062fff78cc6b287c74e6171f855a3500c0156d/submodules/TelegramPresentationData/Sources/PresentationData.swift#L453\r\nexport default function highlightningColor(rgba: [number, number, number, number?]) {\r\n let {h, s, l} = rgbaToHsla(rgba[0], rgba[1], rgba[2]);\r\n if(s > 0) {\r\n s = Math.min(100, s + 5 + 0.1 * (100 - s));\r\n }\r\n l = Math.max(0, l * .65);\r\n \r\n const hsla = `hsla(${h}, ${s}%, ${l}%, .4)`;\r\n return hsla;\r\n}\r\n","import { ColorHsla, ColorRgba, hexaToHsla, hslaToRgba, rgbaToHexa as rgbaToHexa, rgbaToHsla } from \"../helpers/color\";\r\nimport attachGrabListeners from \"../helpers/dom/attachGrabListeners\";\r\nimport { clamp } from \"../helpers/number\";\r\nimport InputField, { InputState } from \"./inputField\";\r\n\r\nexport type ColorPickerColor = { \r\n hsl: string; \r\n rgb: string; \r\n hex: string; \r\n hsla: string; \r\n rgba: string; \r\n hexa: string; \r\n rgbaArray: ColorRgba; \r\n};\r\n\r\nexport default class ColorPicker {\r\n private static BASE_CLASS = 'color-picker';\r\n public container: HTMLElement;\r\n\r\n private boxRect: DOMRect;\r\n //private boxDraggerRect: DOMRect;\r\n private hueRect: DOMRect;\r\n //private hueDraggerRect: DOMRect;\r\n\r\n\tprivate hue = 0;\r\n\tprivate saturation = 100;\r\n\tprivate lightness = 50;\r\n\tprivate alpha = 1;\r\n private elements: {\r\n box: SVGSVGElement,\r\n boxDragger: SVGSVGElement,\r\n sliders: HTMLElement,\r\n hue: SVGSVGElement,\r\n hueDragger: SVGSVGElement,\r\n saturation: SVGLinearGradientElement,\r\n } = {} as any;\r\n private hexInputField: InputField;\r\n private rgbInputField: InputField;\r\n public onChange: (color: ReturnType<ColorPicker['getCurrentColor']>) => void;\r\n\r\n constructor() {\r\n this.container = document.createElement('div');\r\n this.container.classList.add(ColorPicker.BASE_CLASS);\r\n\r\n const html = `\r\n <svg class=\"${ColorPicker.BASE_CLASS + '-box'}\" viewBox=\"0 0 380 198\">\r\n <defs>\r\n <linearGradient id=\"color-picker-saturation\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"0%\">\r\n <stop offset=\"0%\" stop-color=\"#fff\"></stop>\r\n <stop offset=\"100%\" stop-color=\"hsl(0,100%,50%)\"></stop>\r\n </linearGradient>\r\n <linearGradient id=\"color-picker-brightness\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\r\n <stop offset=\"0%\" stop-color=\"rgba(0,0,0,0)\"></stop>\r\n <stop offset=\"100%\" stop-color=\"#000\"></stop>\r\n </linearGradient>\r\n <pattern id=\"color-picker-pattern\" width=\"100%\" height=\"100%\">\r\n <rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" fill=\"url(#color-picker-saturation)\"></rect>\r\n <rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" fill=\"url(#color-picker-brightness)\"></rect>\r\n </pattern>\r\n </defs>\r\n <rect rx=\"10\" ry=\"10\" x=\"0\" y=\"0\" width=\"380\" height=\"198\" fill=\"url(#color-picker-pattern)\"></rect>\r\n <svg class=\"${ColorPicker.BASE_CLASS + '-dragger'} ${ColorPicker.BASE_CLASS + '-box-dragger'}\" x=\"0\" y=\"0\">\r\n <circle r=\"11\" fill=\"inherit\" stroke=\"#fff\" stroke-width=\"2\"></circle>\r\n </svg>\r\n </svg>\r\n <div class=\"${ColorPicker.BASE_CLASS + '-sliders'}\">\r\n <svg class=\"${ColorPicker.BASE_CLASS + '-color-slider'}\" viewBox=\"0 0 380 24\">\r\n <defs>\r\n <linearGradient id=\"hue\" x1=\"100%\" y1=\"0%\" x2=\"0%\" y2=\"0%\">\r\n <stop offset=\"0%\" stop-color=\"#f00\"></stop>\r\n <stop offset=\"16.666%\" stop-color=\"#f0f\"></stop>\r\n <stop offset=\"33.333%\" stop-color=\"#00f\"></stop>\r\n <stop offset=\"50%\" stop-color=\"#0ff\"></stop>\r\n <stop offset=\"66.666%\" stop-color=\"#0f0\"></stop>\r\n <stop offset=\"83.333%\" stop-color=\"#ff0\"></stop>\r\n <stop offset=\"100%\" stop-color=\"#f00\"></stop>\r\n </linearGradient>\r\n </defs>\r\n <rect rx=\"4\" ry=\"4\" x=\"0\" y=\"9\" width=\"380\" height=\"8\" fill=\"url(#hue)\"></rect>\r\n <svg class=\"${ColorPicker.BASE_CLASS + '-dragger'} ${ColorPicker.BASE_CLASS + '-color-slider-dragger'}\" x=\"0\" y=\"13\">\r\n <circle r=\"11\" fill=\"inherit\" stroke=\"#fff\" stroke-width=\"2\"></circle>\r\n </svg>\r\n </svg>\r\n </div>\r\n `;\r\n\r\n this.container.innerHTML = html;\r\n\r\n this.elements.box = this.container.firstElementChild as any;\r\n this.elements.boxDragger = this.elements.box.lastElementChild as any;\r\n this.elements.saturation = this.elements.box.firstElementChild.firstElementChild as any;\r\n\r\n this.elements.sliders = this.elements.box.nextElementSibling as any;\r\n\r\n this.elements.hue = this.elements.sliders.firstElementChild as any;\r\n this.elements.hueDragger = this.elements.hue.lastElementChild as any;\r\n\r\n this.hexInputField = new InputField({plainText: true, label: 'Appearance.Color.Hex'});\r\n this.rgbInputField = new InputField({plainText: true, label: 'Appearance.Color.RGB'});\r\n\r\n const inputs = document.createElement('div');\r\n inputs.className = ColorPicker.BASE_CLASS + '-inputs';\r\n inputs.append(this.hexInputField.container, this.rgbInputField.container);\r\n this.container.append(inputs);\r\n\r\n this.hexInputField.input.addEventListener('input', () => {\r\n let value = this.hexInputField.value.replace(/#/g, '').slice(0, 6);\r\n\r\n const match = value.match(/([a-fA-F\\d]+)/);\r\n const valid = match && match[0].length === value.length && [/* 3, 4, */6].includes(value.length);\r\n this.hexInputField.setState(valid ? InputState.Neutral : InputState.Error);\r\n\r\n value = '#' + value;\r\n this.hexInputField.setValueSilently(value);\r\n \r\n if(valid) {\r\n this.setColor(value, false, true);\r\n }\r\n });\r\n\r\n // patched https://stackoverflow.com/a/34029238/6758968\r\n const rgbRegExp = /^(?:rgb)?\\(?([01]?\\d\\d?|2[0-4]\\d|25[0-5])(?:\\W+)([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\W+(?:([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\)?)$/;\r\n this.rgbInputField.input.addEventListener('input', () => {\r\n const match = this.rgbInputField.value.match(rgbRegExp);\r\n this.rgbInputField.setState(match ? InputState.Neutral : InputState.Error);\r\n\r\n if(match) {\r\n this.setColor(rgbaToHsla(+match[1], +match[2], +match[3]), true, false);\r\n }\r\n });\r\n\r\n this.attachBoxListeners();\r\n this.attachHueListeners();\r\n }\r\n\r\n private onGrabStart = () => {\r\n document.documentElement.style.cursor = this.elements.boxDragger.style.cursor = 'grabbing';\r\n };\r\n\r\n private onGrabEnd = () => {\r\n document.documentElement.style.cursor = this.elements.boxDragger.style.cursor = '';\r\n };\r\n\r\n private attachBoxListeners() {\r\n attachGrabListeners(this.elements.box as any, () => {\r\n this.onGrabStart();\r\n this.boxRect = this.elements.box.getBoundingClientRect();\r\n //this.boxDraggerRect = this.elements.boxDragger.getBoundingClientRect();\r\n }, (pos) => {\r\n this.saturationHandler(pos.x, pos.y);\r\n }, () => {\r\n this.onGrabEnd();\r\n });\r\n }\r\n\r\n private attachHueListeners() {\r\n attachGrabListeners(this.elements.hue as any, () => {\r\n this.onGrabStart();\r\n this.hueRect = this.elements.hue.getBoundingClientRect();\r\n //this.hueDraggerRect = this.elements.hueDragger.getBoundingClientRect();\r\n }, (pos) => {\r\n this.hueHandler(pos.x);\r\n }, () => {\r\n this.onGrabEnd();\r\n });\r\n }\r\n\r\n public setColor(color: ColorHsla | string, updateHexInput = true, updateRgbInput = true) {\r\n if(color === undefined) { // * set to red\r\n color = {\r\n h: 0,\r\n s: 100,\r\n l: 50,\r\n a: 1\r\n };\r\n } else if(typeof(color) === 'string') {\r\n if(color[0] === '#') {\r\n color = hexaToHsla(color);\r\n } else {\r\n const rgb = color.match(/[.?\\d]+/g);\r\n color = rgbaToHsla(+rgb[0], +rgb[1], +rgb[2], rgb[3] === undefined ? 1 : +rgb[3]);\r\n }\r\n }\r\n\r\n // Set box\r\n this.boxRect = this.elements.box.getBoundingClientRect();\r\n\r\n const boxX = this.boxRect.width / 100 * color.s;\r\n const percentY = 100 - (color.l / (100 - color.s / 2)) * 100;\r\n const boxY = this.boxRect.height / 100 * percentY;\r\n\r\n this.saturationHandler(this.boxRect.left + boxX, this.boxRect.top + boxY, false);\r\n\r\n // Set hue\r\n this.hueRect = this.elements.hue.getBoundingClientRect();\r\n\r\n const percentHue = color.h / 360;\r\n const hueX = this.hueRect.left + this.hueRect.width * percentHue;\r\n\r\n this.hueHandler(hueX, false);\r\n\r\n // Set values\r\n this.hue = color.h;\r\n this.saturation = color.s;\r\n this.lightness = color.l;\r\n this.alpha = color.a;\r\n\r\n this.updatePicker(updateHexInput, updateRgbInput);\r\n };\r\n\r\n public getCurrentColor(): ColorPickerColor {\r\n const rgbaArray = hslaToRgba(this.hue, this.saturation, this.lightness, this.alpha);\r\n const hexa = rgbaToHexa(rgbaArray);\r\n const hex = hexa.slice(0, -2);\r\n\r\n return {\r\n hsl: `hsl(${this.hue}, ${this.saturation}%, ${this.lightness}%)`,\r\n rgb: `rgb(${rgbaArray[0]}, ${rgbaArray[1]}, ${rgbaArray[2]})`,\r\n hex: hex,\r\n hsla: `hsla(${this.hue}, ${this.saturation}%, ${this.lightness}%, ${this.alpha})`,\r\n rgba: `rgba(${rgbaArray[0]}, ${rgbaArray[1]}, ${rgbaArray[2]}, ${rgbaArray[3]})`,\r\n hexa: hexa,\r\n rgbaArray: rgbaArray\r\n };\r\n }\r\n\r\n public updatePicker(updateHexInput = true, updateRgbInput = true) {\r\n const color = this.getCurrentColor();\r\n this.elements.boxDragger.setAttributeNS(null, 'fill', color.hex);\r\n\r\n if(updateHexInput) {\r\n this.hexInputField.setValueSilently(color.hex);\r\n this.hexInputField.setState(InputState.Neutral);\r\n }\r\n\r\n if(updateRgbInput) {\r\n this.rgbInputField.setValueSilently(color.rgbaArray.slice(0, -1).join(', '));\r\n this.rgbInputField.setState(InputState.Neutral);\r\n }\r\n\r\n if(this.onChange) {\r\n this.onChange(color);\r\n }\r\n }\r\n\r\n private hueHandler(pageX: number, update = true) {\r\n const eventX = clamp(pageX - this.hueRect.left, 0, this.hueRect.width);\r\n\r\n const percents = eventX / this.hueRect.width;\r\n this.hue = Math.round(360 * percents);\r\n \r\n const hsla = `hsla(${this.hue}, 100%, 50%, ${this.alpha})`;\r\n\r\n this.elements.hueDragger.setAttributeNS(null, 'x', (percents * 100) + '%');\r\n this.elements.hueDragger.setAttributeNS(null, 'fill', hsla);\r\n \r\n this.elements.saturation.lastElementChild.setAttributeNS(null, 'stop-color', hsla);\r\n\r\n if(update) {\r\n this.updatePicker();\r\n }\r\n }\r\n\r\n private saturationHandler(pageX: number, pageY: number, update = true) {\r\n const maxX = this.boxRect.width;\r\n const maxY = this.boxRect.height;\r\n\r\n const eventX = clamp(pageX - this.boxRect.left, 0, maxX);\r\n const eventY = clamp(pageY - this.boxRect.top, 0, maxY);\r\n\r\n const posX = eventX / maxX * 100;\r\n const posY = eventY / maxY * 100;\r\n \r\n const boxDragger = this.elements.boxDragger;\r\n boxDragger.setAttributeNS(null, 'x', posX + '%');\r\n boxDragger.setAttributeNS(null, 'y', posY + '%');\r\n\r\n const saturation = clamp(posX, 0, 100);\r\n\r\n const lightnessX = 100 - saturation / 2;\r\n const lightnessY = 100 - clamp(posY, 0, 100);\r\n\r\n const lightness = clamp(lightnessY / 100 * lightnessX, 0, 100);\r\n\r\n this.saturation = saturation;\r\n this.lightness = lightness;\r\n\r\n if(update) {\r\n this.updatePicker();\r\n }\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"..\";\r\nimport { hexaToRgba } from \"../../../helpers/color\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport highlightningColor from \"../../../helpers/highlightningColor\";\r\nimport throttle from \"../../../helpers/schedulers/throttle\";\r\nimport appImManager from \"../../../lib/appManagers/appImManager\";\r\nimport appStateManager, { Theme } from \"../../../lib/appManagers/appStateManager\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport ColorPicker, { ColorPickerColor } from \"../../colorPicker\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\n\r\nexport default class AppBackgroundColorTab extends SliderSuperTab {\r\n private colorPicker: ColorPicker;\r\n private grid: HTMLElement;\r\n private applyColor: (hex: string, updateColorPicker?: boolean) => void;\r\n private theme: Theme;\r\n\r\n init() {\r\n this.container.classList.add('background-container', 'background-color-container');\r\n this.setTitle('SetColor');\r\n\r\n this.theme = rootScope.getTheme();\r\n\r\n const section = new SettingSection({});\r\n this.colorPicker = new ColorPicker();\r\n\r\n section.content.append(this.colorPicker.container);\r\n\r\n this.scrollable.append(section.container);\r\n\r\n const grid = this.grid = document.createElement('div');\r\n grid.classList.add('grid');\r\n\r\n const colors = [\r\n '#E6EBEE',\r\n '#B2CEE1',\r\n '#008DD0',\r\n '#C6E7CB',\r\n '#C4E1A6',\r\n '#60B16E',\r\n '#CCD0AF',\r\n '#A6A997',\r\n '#7A7072',\r\n '#FDD7AF',\r\n '#FDB76E',\r\n '#DD8851'\r\n ];\r\n\r\n colors.forEach(color => {\r\n const item = document.createElement('div');\r\n item.classList.add('grid-item');\r\n item.dataset.color = color.toLowerCase();\r\n\r\n // * need for transform scale\r\n const media = document.createElement('div');\r\n media.classList.add('grid-item-media');\r\n media.style.backgroundColor = color;\r\n\r\n item.append(media);\r\n grid.append(item);\r\n });\r\n\r\n attachClickEvent(grid, (e) => {\r\n const target = findUpClassName(e.target, 'grid-item');\r\n if(!target || target.classList.contains('active')) {\r\n return;\r\n }\r\n\r\n const color = target.dataset.color;\r\n if(!color) {\r\n return;\r\n }\r\n\r\n this.applyColor(color);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.scrollable.append(grid);\r\n\r\n this.applyColor = throttle(this._applyColor, 16, true);\r\n }\r\n\r\n private setActive() {\r\n const active = this.grid.querySelector('.active');\r\n const background = this.theme.background;\r\n const target = background.type === 'color' ? this.grid.querySelector(`.grid-item[data-color=\"${background.color}\"]`) : null;\r\n if(active === target) {\r\n return;\r\n }\r\n\r\n if(active) {\r\n active.classList.remove('active');\r\n }\r\n\r\n if(target) {\r\n target.classList.add('active');\r\n }\r\n }\r\n\r\n private _applyColor = (hex: string, updateColorPicker = true) => {\r\n if(updateColorPicker) {\r\n this.colorPicker.setColor(hex);\r\n } else {\r\n const rgba = hexaToRgba(hex);\r\n const background = this.theme.background;\r\n const hsla = highlightningColor(rgba);\r\n \r\n background.color = hex.toLowerCase();\r\n background.type = 'color';\r\n background.highlightningColor = hsla;\r\n appStateManager.pushToState('settings', rootScope.settings);\r\n \r\n appImManager.applyCurrentTheme(undefined, undefined, true);\r\n this.setActive();\r\n }\r\n };\r\n\r\n private onColorChange = (color: ColorPickerColor) => {\r\n this.applyColor(color.hex, false);\r\n };\r\n\r\n onOpen() {\r\n setTimeout(() => {\r\n const background = this.theme.background;\r\n\r\n // * set active if type is color\r\n if(background.type === 'color') {\r\n this.colorPicker.onChange = this.onColorChange;\r\n }\r\n\r\n this.colorPicker.setColor(background.color || '#cccccc');\r\n \r\n if(background.type !== 'color') {\r\n this.colorPicker.onChange = this.onColorChange;\r\n }\r\n }, 0);\r\n }\r\n\r\n onCloseAfterTimeout() {\r\n this.colorPicker.onChange = undefined;\r\n this.colorPicker = undefined;\r\n\r\n return super.onCloseAfterTimeout();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { generateSection } from \"..\";\r\nimport { averageColor } from \"../../../helpers/averageColor\";\r\nimport blur from \"../../../helpers/blur\";\r\nimport { deferredPromise } from \"../../../helpers/cancellablePromise\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport { requestFile } from \"../../../helpers/files\";\r\nimport highlightningColor from \"../../../helpers/highlightningColor\";\r\nimport { copy } from \"../../../helpers/object\";\r\nimport sequentialDom from \"../../../helpers/sequentialDom\";\r\nimport { AccountWallPapers, PhotoSize, WallPaper } from \"../../../layer\";\r\nimport appDocsManager, { MyDocument } from \"../../../lib/appManagers/appDocsManager\";\r\nimport appDownloadManager from \"../../../lib/appManagers/appDownloadManager\";\r\nimport appImManager from \"../../../lib/appManagers/appImManager\";\r\nimport appPhotosManager from \"../../../lib/appManagers/appPhotosManager\";\r\nimport appStateManager, { Theme, STATE_INIT } from \"../../../lib/appManagers/appStateManager\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport Button from \"../../button\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport ProgressivePreloader from \"../../preloader\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport { wrapPhoto } from \"../../wrappers\";\r\nimport AppBackgroundColorTab from \"./backgroundColor\";\r\n\r\nlet uploadTempId = 0;\r\n\r\nexport default class AppBackgroundTab extends SliderSuperTab {\r\n private grid: HTMLElement;\r\n private tempId = 0;\r\n private theme: Theme;\r\n private clicked: Set<string> = new Set();\r\n private blurCheckboxField: CheckboxField;\r\n\r\n init() {\r\n this.container.classList.add('background-container', 'background-image-container');\r\n this.setTitle('ChatBackground');\r\n\r\n this.theme = rootScope.getTheme();\r\n\r\n {\r\n const container = generateSection(this.scrollable);\r\n\r\n const uploadButton = Button('btn-primary btn-transparent', {icon: 'cameraadd', text: 'ChatBackground.UploadWallpaper'});\r\n const colorButton = Button('btn-primary btn-transparent', {icon: 'colorize', text: 'SetColor'});\r\n const resetButton = Button('btn-primary btn-transparent', {icon: 'favourites', text: 'Appearance.Reset'});\r\n\r\n attachClickEvent(uploadButton, this.onUploadClick, {listenerSetter: this.listenerSetter});\r\n\r\n attachClickEvent(colorButton, () => {\r\n new AppBackgroundColorTab(this.slider).open();\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n attachClickEvent(resetButton, this.onResetClick, {listenerSetter: this.listenerSetter});\r\n\r\n const blurCheckboxField = this.blurCheckboxField = new CheckboxField({\r\n text: 'ChatBackground.Blur', \r\n name: 'blur', \r\n checked: this.theme.background.blur,\r\n withRipple: true\r\n });\r\n\r\n this.listenerSetter.add(blurCheckboxField.input)('change', () => {\r\n this.theme.background.blur = blurCheckboxField.input.checked;\r\n appStateManager.pushToState('settings', rootScope.settings);\r\n\r\n const active = grid.querySelector('.active') as HTMLElement;\r\n if(!active) return;\r\n\r\n // * wait for animation end\r\n setTimeout(() => {\r\n this.setBackgroundDocument(active.dataset.slug, appDocsManager.getDoc(active.dataset.docId));\r\n }, 100);\r\n });\r\n\r\n container.append(uploadButton, colorButton, resetButton, blurCheckboxField.label);\r\n }\r\n\r\n rootScope.addEventListener('background_change', this.setActive);\r\n\r\n apiManager.invokeApiHashable('account.getWallPapers').then((accountWallpapers) => {\r\n const wallpapers = (accountWallpapers as AccountWallPapers.accountWallPapers).wallpapers as WallPaper.wallPaper[];\r\n wallpapers.forEach((wallpaper) => {\r\n this.addWallPaper(wallpaper);\r\n });\r\n\r\n //console.log(accountWallpapers);\r\n });\r\n\r\n const grid = this.grid = document.createElement('div');\r\n grid.classList.add('grid');\r\n attachClickEvent(grid, this.onGridClick, {listenerSetter: this.listenerSetter});\r\n this.scrollable.append(grid);\r\n }\r\n\r\n private onUploadClick = () => {\r\n requestFile('image/x-png,image/png,image/jpeg').then(file => {\r\n const id = 'wallpaper-upload-' + ++uploadTempId;\r\n\r\n const thumb = {\r\n _: 'photoSize',\r\n h: 0,\r\n w: 0,\r\n location: {} as any,\r\n size: file.size,\r\n type: 'full',\r\n } as PhotoSize.photoSize;\r\n let document: MyDocument = {\r\n _: 'document',\r\n access_hash: '',\r\n attributes: [],\r\n dc_id: 0,\r\n file_reference: [],\r\n id,\r\n mime_type: file.type,\r\n size: file.size,\r\n date: Date.now() / 1000,\r\n pFlags: {},\r\n thumbs: [thumb],\r\n file_name: file.name\r\n };\r\n\r\n document = appDocsManager.saveDoc(document);\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(document);\r\n cacheContext.downloaded = file.size;\r\n cacheContext.url = URL.createObjectURL(file);\r\n\r\n let wallpaper: WallPaper.wallPaper = {\r\n _: 'wallPaper',\r\n access_hash: '',\r\n document: document,\r\n id,\r\n slug: id,\r\n pFlags: {}\r\n };\r\n\r\n const upload = appDownloadManager.upload(file, file.name);\r\n\r\n const deferred = deferredPromise<void>();\r\n deferred.addNotifyListener = upload.addNotifyListener;\r\n deferred.cancel = upload.cancel;\r\n\r\n upload.then(inputFile => {\r\n apiManager.invokeApi('account.uploadWallPaper', {\r\n file: inputFile,\r\n mime_type: file.type,\r\n settings: {\r\n _: 'wallPaperSettings'\r\n }\r\n }).then(_wallpaper => {\r\n const newDoc = (_wallpaper as WallPaper.wallPaper).document as MyDocument;\r\n const newCacheContext = appDownloadManager.getCacheContext(newDoc);\r\n Object.assign(newCacheContext, cacheContext);\r\n\r\n wallpaper = _wallpaper as WallPaper.wallPaper;\r\n wallpaper.document = appDocsManager.saveDoc(wallpaper.document);\r\n\r\n container.dataset.docId = wallpaper.document.id;\r\n container.dataset.slug = wallpaper.slug;\r\n \r\n this.setBackgroundDocument(wallpaper.slug, wallpaper.document).then(deferred.resolve, deferred.reject);\r\n }, deferred.reject);\r\n }, deferred.reject);\r\n\r\n deferred.then(() => {\r\n this.clicked.delete(wallpaper.document.id);\r\n }, (err) => {\r\n container.remove();\r\n //console.error('i saw the body drop', err);\r\n });\r\n\r\n const preloader = new ProgressivePreloader({\r\n isUpload: true,\r\n cancelable: true,\r\n tryAgainOnFail: false\r\n });\r\n\r\n const container = this.addWallPaper(wallpaper, false);\r\n this.clicked.add(wallpaper.document.id);\r\n\r\n preloader.attach(container, false, deferred);\r\n });\r\n };\r\n\r\n private onResetClick = () => {\r\n const defaultTheme = STATE_INIT.settings.themes.find(t => t.name === this.theme.name);\r\n if(defaultTheme) {\r\n ++this.tempId;\r\n this.theme.background = copy(defaultTheme.background);\r\n appStateManager.pushToState('settings', rootScope.settings);\r\n appImManager.applyCurrentTheme(undefined, undefined, true);\r\n this.blurCheckboxField.setValueSilently(this.theme.background.blur);\r\n }\r\n };\r\n\r\n private addWallPaper(wallpaper: WallPaper.wallPaper, append = true) {\r\n if(wallpaper.pFlags.pattern || \r\n !wallpaper.document || \r\n (wallpaper.document as MyDocument).mime_type.indexOf('application/') === 0) {\r\n return;\r\n }\r\n\r\n wallpaper.document = appDocsManager.saveDoc(wallpaper.document);\r\n\r\n const container = document.createElement('div');\r\n container.classList.add('grid-item');\r\n\r\n const media = document.createElement('div');\r\n media.classList.add('grid-item-media');\r\n\r\n const wrapped = wrapPhoto({\r\n photo: wallpaper.document,\r\n message: null,\r\n container: media,\r\n withoutPreloader: true,\r\n size: appPhotosManager.choosePhotoSize(wallpaper.document, 200, 200)\r\n });\r\n\r\n container.dataset.docId = wallpaper.document.id;\r\n container.dataset.slug = wallpaper.slug;\r\n\r\n if(this.theme.background.type === 'image' && this.theme.background.slug === wallpaper.slug) {\r\n container.classList.add('active');\r\n }\r\n\r\n (wrapped.loadPromises.thumb || wrapped.loadPromises.full).then(() => {\r\n sequentialDom.mutate(() => {\r\n container.append(media);\r\n });\r\n });\r\n\r\n this.grid[append ? 'append' : 'prepend'](container);\r\n\r\n return container;\r\n }\r\n\r\n private onGridClick = (e: MouseEvent | TouchEvent) => {\r\n const target = findUpClassName(e.target, 'grid-item') as HTMLElement;\r\n if(!target) return;\r\n\r\n const {docId, slug} = target.dataset;\r\n if(this.clicked.has(docId)) return;\r\n this.clicked.add(docId);\r\n\r\n const preloader = new ProgressivePreloader({\r\n cancelable: true,\r\n tryAgainOnFail: false\r\n });\r\n\r\n const doc = appDocsManager.getDoc(docId);\r\n\r\n const load = () => {\r\n const promise = this.setBackgroundDocument(slug, doc);\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n if(!cacheContext.url || this.theme.background.blur) {\r\n preloader.attach(target, true, promise);\r\n }\r\n };\r\n\r\n preloader.construct();\r\n\r\n attachClickEvent(target, (e) => {\r\n if(preloader.preloader.parentElement) {\r\n preloader.onClick(e);\r\n preloader.detach();\r\n } else {\r\n load();\r\n }\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n load();\r\n\r\n //console.log(doc);\r\n };\r\n\r\n private saveToCache = (slug: string, url: string) => {\r\n fetch(url).then(response => {\r\n appDownloadManager.cacheStorage.save('backgrounds/' + slug, response);\r\n });\r\n };\r\n\r\n private setBackgroundDocument = (slug: string, doc: MyDocument) => {\r\n let _tempId = ++this.tempId;\r\n const middleware = () => _tempId === this.tempId;\r\n\r\n const download = appDocsManager.downloadDoc(doc, appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : 0);\r\n\r\n const deferred = deferredPromise<void>();\r\n deferred.addNotifyListener = download.addNotifyListener;\r\n deferred.cancel = download.cancel;\r\n\r\n download.then(() => {\r\n if(!middleware()) {\r\n deferred.resolve();\r\n return;\r\n }\r\n\r\n const background = this.theme.background;\r\n const onReady = (url: string) => {\r\n //const perf = performance.now();\r\n averageColor(url).then(pixel => {\r\n if(!middleware()) {\r\n deferred.resolve();\r\n return;\r\n }\r\n \r\n const hsla = highlightningColor(Array.from(pixel) as any);\r\n //console.log(doc, hsla, performance.now() - perf);\r\n\r\n background.slug = slug;\r\n background.type = 'image';\r\n background.highlightningColor = hsla;\r\n appStateManager.pushToState('settings', rootScope.settings);\r\n\r\n this.saveToCache(slug, url);\r\n appImManager.applyCurrentTheme(slug, url).then(deferred.resolve);\r\n });\r\n };\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n if(background.blur) {\r\n setTimeout(() => {\r\n blur(cacheContext.url, 12, 4)\r\n .then(url => {\r\n if(!middleware()) {\r\n deferred.resolve();\r\n return;\r\n }\r\n\r\n onReady(url);\r\n });\r\n }, 200);\r\n } else {\r\n onReady(cacheContext.url);\r\n }\r\n });\r\n\r\n return deferred;\r\n };\r\n\r\n private setActive = () => {\r\n const active = this.grid.querySelector('.active');\r\n const background = this.theme.background;\r\n const target = background.type === 'image' ? this.grid.querySelector(`.grid-item[data-slug=\"${background.slug}\"]`) : null;\r\n if(active === target) {\r\n return;\r\n }\r\n\r\n if(active) {\r\n active.classList.remove('active');\r\n }\r\n\r\n if(target) {\r\n target.classList.add('active');\r\n }\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport renderImageFromUrl from \"./dom/renderImageFromUrl\";\r\n\r\nexport const averageColor = (imageUrl: string): Promise<Uint8ClampedArray> => {\r\n const img = document.createElement('img');\r\n return new Promise<Uint8ClampedArray>((resolve) => {\r\n renderImageFromUrl(img, imageUrl, () => {\r\n const canvas = document.createElement('canvas');\r\n const ratio = img.naturalWidth / img.naturalHeight;\r\n const DIMENSIONS = 50;\r\n if(ratio === 1) {\r\n canvas.width = DIMENSIONS;\r\n canvas.height = canvas.width / ratio;\r\n } else if(ratio > 1) {\r\n canvas.height = DIMENSIONS;\r\n canvas.width = canvas.height / ratio;\r\n } else {\r\n canvas.width = canvas.height = DIMENSIONS;\r\n }\r\n \r\n const context = canvas.getContext('2d');\r\n context.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight, 0, 0, canvas.width, canvas.height);\r\n\r\n const pixel = new Array(4).fill(0);\r\n const pixels = context.getImageData(0, 0, canvas.width, canvas.height).data;\r\n for(let i = 0; i < pixels.length; i += 4) {\r\n pixel[0] += pixels[i];\r\n pixel[1] += pixels[i + 1];\r\n pixel[2] += pixels[i + 2];\r\n pixel[3] += pixels[i + 3];\r\n }\r\n\r\n const pixelsLength = pixels.length / 4;\r\n const outPixel = new Uint8ClampedArray(4);\r\n outPixel[0] = pixel[0] / pixelsLength;\r\n outPixel[1] = pixel[1] / pixelsLength;\r\n outPixel[2] = pixel[2] / pixelsLength;\r\n outPixel[3] = pixel[3] / pixelsLength;\r\n resolve(outPixel);\r\n });\r\n });\r\n};\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport PopupElement from \".\";\r\nimport appStickersManager, { AppStickersManager } from \"../../lib/appManagers/appStickersManager\";\r\nimport { RichTextProcessor } from \"../../lib/richtextprocessor\";\r\nimport Scrollable from \"../scrollable\";\r\nimport { wrapSticker } from \"../wrappers\";\r\nimport LazyLoadQueue from \"../lazyLoadQueue\";\r\nimport { putPreloader } from \"../misc\";\r\nimport animationIntersector from \"../animationIntersector\";\r\nimport appImManager from \"../../lib/appManagers/appImManager\";\r\nimport { StickerSet } from \"../../layer\";\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport { i18n } from \"../../lib/langPack\";\r\nimport Button from \"../button\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport toggleDisability from \"../../helpers/dom/toggleDisability\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\n\r\nconst ANIMATION_GROUP = 'STICKERS-POPUP';\r\n\r\nexport default class PopupStickers extends PopupElement {\r\n private stickersFooter: HTMLElement;\r\n private stickersDiv: HTMLElement;\r\n private h6: HTMLElement;\r\n\r\n private set: StickerSet.stickerSet;\r\n\r\n constructor(private stickerSetInput: Parameters<AppStickersManager['getStickerSet']>[0]) {\r\n super('popup-stickers', null, {closable: true, overlayClosable: true, body: true});\r\n\r\n this.h6 = document.createElement('h6');\r\n this.h6.append(i18n('Loading'));\r\n\r\n this.header.append(this.h6);\r\n\r\n this.onClose = () => {\r\n animationIntersector.setOnlyOnePlayableGroup('');\r\n };\r\n\r\n const div = document.createElement('div');\r\n div.classList.add('sticker-set');\r\n\r\n this.stickersDiv = document.createElement('div');\r\n this.stickersDiv.classList.add('sticker-set-stickers', 'is-loading');\r\n\r\n attachClickEvent(this.stickersDiv, this.onStickersClick, {listenerSetter: this.listenerSetter});\r\n\r\n putPreloader(this.stickersDiv, true);\r\n\r\n this.stickersFooter = document.createElement('div');\r\n this.stickersFooter.classList.add('sticker-set-footer');\r\n\r\n div.append(this.stickersDiv);\r\n\r\n const btn = Button('btn-primary btn-primary-transparent disable-hover', {noRipple: true, text: 'Loading'});\r\n this.stickersFooter.append(btn);\r\n\r\n this.body.append(div);\r\n const scrollable = new Scrollable(this.body);\r\n this.body.append(this.stickersFooter);\r\n \r\n // const editButton = document.createElement('button');\r\n // editButton.classList.add('btn-primary');\r\n\r\n // this.stickersFooter.append(editButton);\r\n\r\n this.loadStickerSet();\r\n }\r\n\r\n private onStickersClick = (e: MouseEvent) => {\r\n const target = findUpClassName(e.target, 'sticker-set-sticker');\r\n if(!target) return;\r\n\r\n const fileId = target.dataset.docId;\r\n if(appImManager.chat.input.sendMessageWithDocument(fileId)) {\r\n this.hide();\r\n } else {\r\n console.warn('got no doc by id:', fileId);\r\n }\r\n };\r\n\r\n private loadStickerSet() {\r\n return appStickersManager.getStickerSet(this.stickerSetInput).then(set => {\r\n //console.log('PopupStickers loadStickerSet got set:', set);\r\n\r\n this.set = set.set;\r\n\r\n animationIntersector.setOnlyOnePlayableGroup(ANIMATION_GROUP);\r\n\r\n this.h6.innerHTML = RichTextProcessor.wrapEmojiText(set.set.title);\r\n this.stickersFooter.classList.toggle('add', !set.set.installed_date);\r\n\r\n let button: HTMLElement;\r\n if(set.set.installed_date) {\r\n button = Button('btn-primary btn-primary-transparent danger', {noRipple: true});\r\n button.append(i18n('RemoveStickersCount', [i18n('Stickers', [set.set.count])]));\r\n } else {\r\n button = Button('btn-primary btn-color-primary', {noRipple: true});\r\n button.append(i18n('AddStickersCount', [i18n('Stickers', [set.set.count])]));\r\n }\r\n\r\n this.stickersFooter.textContent = '';\r\n this.stickersFooter.append(button);\r\n\r\n attachClickEvent(button, () => {\r\n const toggle = toggleDisability([button], true);\r\n\r\n appStickersManager.toggleStickerSet(this.set).then(() => {\r\n this.hide();\r\n }).catch(() => {\r\n toggle();\r\n });\r\n });\r\n\r\n const lazyLoadQueue = new LazyLoadQueue();\r\n \r\n this.stickersDiv.classList.remove('is-loading');\r\n this.stickersDiv.innerHTML = '';\r\n for(let doc of set.documents) {\r\n if(doc._ === 'documentEmpty') {\r\n continue;\r\n }\r\n \r\n const div = document.createElement('div');\r\n div.classList.add('sticker-set-sticker');\r\n\r\n const size = mediaSizes.active.esgSticker.width;\r\n \r\n wrapSticker({\r\n doc, \r\n div, \r\n lazyLoadQueue, \r\n group: ANIMATION_GROUP, \r\n play: true,\r\n loop: true,\r\n width: size,\r\n height: size\r\n });\r\n\r\n this.stickersDiv.append(div);\r\n }\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\"\r\nimport { generateSection } from \"..\";\r\nimport RangeSelector from \"../../rangeSelector\";\r\nimport Button from \"../../button\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport RadioField from \"../../radioField\";\r\nimport appStateManager from \"../../../lib/appManagers/appStateManager\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport { IS_APPLE } from \"../../../environment/userAgent\";\r\nimport Row from \"../../row\";\r\nimport AppBackgroundTab from \"./background\";\r\nimport { LangPackKey, _i18n } from \"../../../lib/langPack\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport appStickersManager from \"../../../lib/appManagers/appStickersManager\";\r\nimport assumeType from \"../../../helpers/assumeType\";\r\nimport { MessagesAllStickers, StickerSet } from \"../../../layer\";\r\nimport RichTextProcessor from \"../../../lib/richtextprocessor\";\r\nimport { wrapStickerSetThumb } from \"../../wrappers\";\r\nimport LazyLoadQueue from \"../../lazyLoadQueue\";\r\nimport PopupStickers from \"../../popups/stickers\";\r\n\r\nexport class RangeSettingSelector {\r\n public container: HTMLDivElement;\r\n private range: RangeSelector;\r\n\r\n public onChange: (value: number) => void;\r\n\r\n constructor(name: LangPackKey, step: number, initialValue: number, minValue: number, maxValue: number) {\r\n const BASE_CLASS = 'range-setting-selector';\r\n this.container = document.createElement('div');\r\n this.container.classList.add(BASE_CLASS);\r\n\r\n const details = document.createElement('div');\r\n details.classList.add(BASE_CLASS + '-details');\r\n\r\n const nameDiv = document.createElement('div');\r\n nameDiv.classList.add(BASE_CLASS + '-name');\r\n _i18n(nameDiv, name);\r\n\r\n const valueDiv = document.createElement('div');\r\n valueDiv.classList.add(BASE_CLASS + '-value');\r\n valueDiv.innerHTML = '' + initialValue;\r\n\r\n details.append(nameDiv, valueDiv);\r\n\r\n this.range = new RangeSelector({\r\n step, \r\n min: minValue, \r\n max: maxValue\r\n }, initialValue);\r\n this.range.setListeners();\r\n this.range.setHandlers({\r\n onScrub: value => {\r\n if(this.onChange) {\r\n this.onChange(value);\r\n }\r\n\r\n //console.log('font size scrub:', value);\r\n valueDiv.innerText = '' + value;\r\n }\r\n });\r\n\r\n this.container.append(details, this.range.container);\r\n }\r\n}\r\n\r\nexport default class AppGeneralSettingsTab extends SliderSuperTab {\r\n init() {\r\n this.container.classList.add('general-settings-container');\r\n this.setTitle('General');\r\n\r\n const section = generateSection.bind(null, this.scrollable);\r\n\r\n {\r\n const container = section('Settings');\r\n \r\n const range = new RangeSettingSelector('TextSize', 1, rootScope.settings.messagesTextSize, 12, 20);\r\n range.onChange = (value) => {\r\n appStateManager.setByKey('settings.messagesTextSize', value);\r\n };\r\n\r\n const chatBackgroundButton = Button('btn-primary btn-transparent', {icon: 'image', text: 'ChatBackground'});\r\n\r\n attachClickEvent(chatBackgroundButton, () => {\r\n new AppBackgroundTab(this.slider).open();\r\n });\r\n\r\n const animationsCheckboxField = new CheckboxField({\r\n text: 'EnableAnimations', \r\n name: 'animations', \r\n stateKey: 'settings.animationsEnabled',\r\n withRipple: true\r\n });\r\n \r\n container.append(range.container, chatBackgroundButton, animationsCheckboxField.label);\r\n }\r\n\r\n {\r\n const container = section('General.Keyboard');\r\n\r\n const form = document.createElement('form');\r\n\r\n const enterRow = new Row({\r\n radioField: new RadioField({\r\n langKey: 'General.SendShortcut.Enter', \r\n name: 'send-shortcut', \r\n value: 'enter', \r\n stateKey: 'settings.sendShortcut'\r\n }),\r\n subtitleLangKey: 'General.SendShortcut.NewLine.ShiftEnter'\r\n });\r\n\r\n const ctrlEnterRow = new Row({\r\n radioField: new RadioField({\r\n name: 'send-shortcut',\r\n value: 'ctrlEnter', \r\n stateKey: 'settings.sendShortcut'\r\n }),\r\n subtitleLangKey: 'General.SendShortcut.NewLine.Enter'\r\n });\r\n _i18n(ctrlEnterRow.radioField.main, 'General.SendShortcut.CtrlEnter', [IS_APPLE ? '⌘' : 'Ctrl']);\r\n \r\n form.append(enterRow.container, ctrlEnterRow.container);\r\n container.append(form);\r\n }\r\n\r\n {\r\n const container = section('AutoDownloadMedia');\r\n //container.classList.add('sidebar-left-section-disabled');\r\n\r\n const contactsCheckboxField = new CheckboxField({\r\n text: 'AutodownloadContacts', \r\n name: 'contacts',\r\n stateKey: 'settings.autoDownload.contacts',\r\n withRipple: true\r\n });\r\n const privateCheckboxField = new CheckboxField({\r\n text: 'AutodownloadPrivateChats', \r\n name: 'private',\r\n stateKey: 'settings.autoDownload.private',\r\n withRipple: true\r\n });\r\n const groupsCheckboxField = new CheckboxField({\r\n text: 'AutodownloadGroupChats', \r\n name: 'groups',\r\n stateKey: 'settings.autoDownload.groups',\r\n withRipple: true\r\n });\r\n const channelsCheckboxField = new CheckboxField({\r\n text: 'AutodownloadChannels', \r\n name: 'channels',\r\n stateKey: 'settings.autoDownload.channels',\r\n withRipple: true\r\n });\r\n\r\n container.append(contactsCheckboxField.label, privateCheckboxField.label, groupsCheckboxField.label, channelsCheckboxField.label);\r\n }\r\n\r\n {\r\n const container = section('General.AutoplayMedia');\r\n //container.classList.add('sidebar-left-section-disabled');\r\n\r\n const gifsCheckboxField = new CheckboxField({\r\n text: 'AutoplayGIF', \r\n name: 'gifs', \r\n stateKey: 'settings.autoPlay.gifs',\r\n withRipple: true\r\n });\r\n const videosCheckboxField = new CheckboxField({\r\n text: 'AutoplayVideo', \r\n name: 'videos', \r\n stateKey: 'settings.autoPlay.videos',\r\n withRipple: true\r\n });\r\n\r\n container.append(gifsCheckboxField.label, videosCheckboxField.label);\r\n }\r\n\r\n {\r\n const container = section('Emoji');\r\n\r\n const suggestCheckboxField = new CheckboxField({\r\n text: 'GeneralSettings.EmojiPrediction', \r\n name: 'suggest-emoji', \r\n stateKey: 'settings.emoji.suggest',\r\n withRipple: true\r\n });\r\n const bigCheckboxField = new CheckboxField({\r\n text: 'GeneralSettings.BigEmoji', \r\n name: 'emoji-big', \r\n stateKey: 'settings.emoji.big',\r\n withRipple: true\r\n });\r\n\r\n container.append(suggestCheckboxField.label, bigCheckboxField.label);\r\n }\r\n \r\n {\r\n const container = section('Telegram.InstalledStickerPacksController');\r\n\r\n const suggestCheckboxField = new CheckboxField({\r\n text: 'Stickers.SuggestStickers', \r\n name: 'suggest', \r\n stateKey: 'settings.stickers.suggest',\r\n withRipple: true\r\n });\r\n const loopCheckboxField = new CheckboxField({\r\n text: 'InstalledStickers.LoopAnimated', \r\n name: 'loop', \r\n stateKey: 'settings.stickers.loop',\r\n withRipple: true\r\n });\r\n\r\n const stickerSets: {[id: string]: Row} = {};\r\n\r\n const lazyLoadQueue = new LazyLoadQueue();\r\n const renderStickerSet = (stickerSet: StickerSet.stickerSet, method: 'append' | 'prepend' = 'append') => {\r\n const row = new Row({\r\n title: RichTextProcessor.wrapEmojiText(stickerSet.title),\r\n subtitleLangKey: 'Stickers',\r\n subtitleLangArgs: [stickerSet.count],\r\n havePadding: true,\r\n clickable: () => {\r\n new PopupStickers({id: stickerSet.id, access_hash: stickerSet.access_hash}).show();\r\n }\r\n });\r\n\r\n stickerSets[stickerSet.id] = row;\r\n\r\n const div = document.createElement('div');\r\n div.classList.add('row-media');\r\n\r\n wrapStickerSetThumb({\r\n set: stickerSet,\r\n container: div,\r\n group: 'GENERAL-SETTINGS',\r\n lazyLoadQueue,\r\n width: 48,\r\n height: 48,\r\n autoplay: true\r\n });\r\n\r\n row.container.append(div);\r\n\r\n container[method](row.container);\r\n };\r\n\r\n appStickersManager.getAllStickers().then(allStickers => {\r\n assumeType<MessagesAllStickers.messagesAllStickers>(allStickers);\r\n for(const stickerSet of allStickers.sets) {\r\n renderStickerSet(stickerSet);\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('stickers_installed', (e) => {\r\n const set: StickerSet.stickerSet = e;\r\n \r\n if(!stickerSets[set.id]) {\r\n renderStickerSet(set, 'prepend');\r\n }\r\n });\r\n \r\n this.listenerSetter.add(rootScope)('stickers_deleted', (e) => {\r\n const set: StickerSet.stickerSet = e;\r\n \r\n if(stickerSets[set.id]) {\r\n stickerSets[set.id].container.remove();\r\n delete stickerSets[set.id];\r\n }\r\n });\r\n\r\n container.append(suggestCheckboxField.label, loopCheckboxField.label);\r\n }\r\n }\r\n\r\n onOpen() {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport InputField from \"../../inputField\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport EditPeer from \"../../editPeer\";\r\nimport { UsernameInputField } from \"../../usernameInputField\";\r\nimport { i18n, i18n_ } from \"../../../lib/langPack\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\n\r\n// TODO: аватарка не поменяется в этой вкладке после изменения почему-то (если поставить в другом клиенте, и потом тут проверить, для этого ещё вышел в чатлист)\r\n\r\nexport default class AppEditProfileTab extends SliderSuperTab {\r\n private firstNameInputField: InputField;\r\n private lastNameInputField: InputField;\r\n private bioInputField: InputField;\r\n private usernameInputField: InputField;\r\n \r\n private profileUrlContainer: HTMLDivElement;\r\n private profileUrlAnchor: HTMLAnchorElement;\r\n\r\n private editPeer: EditPeer;\r\n\r\n protected async init() {\r\n this.container.classList.add('edit-profile-container');\r\n this.setTitle('EditAccount.Title');\r\n\r\n const inputFields: InputField[] = [];\r\n\r\n {\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n \r\n this.firstNameInputField = new InputField({\r\n label: 'EditProfile.FirstNameLabel',\r\n name: 'first-name',\r\n maxLength: 70\r\n });\r\n this.lastNameInputField = new InputField({\r\n label: 'Login.Register.LastName.Placeholder',\r\n name: 'last-name',\r\n maxLength: 64\r\n });\r\n this.bioInputField = new InputField({\r\n label: 'EditProfile.BioLabel',\r\n name: 'bio',\r\n maxLength: 70\r\n });\r\n \r\n inputWrapper.append(this.firstNameInputField.container, this.lastNameInputField.container, this.bioInputField.container);\r\n \r\n const caption = document.createElement('div');\r\n caption.classList.add('caption');\r\n i18n_({element: caption, key: 'Bio.Description'});\r\n\r\n inputFields.push(this.firstNameInputField, this.lastNameInputField, this.bioInputField);\r\n this.scrollable.append(inputWrapper, caption);\r\n }\r\n\r\n this.scrollable.append(document.createElement('hr'));\r\n\r\n this.editPeer = new EditPeer({\r\n peerId: appUsersManager.getSelf().id,\r\n inputFields,\r\n listenerSetter: this.listenerSetter\r\n });\r\n this.content.append(this.editPeer.nextBtn);\r\n this.scrollable.prepend(this.editPeer.avatarEdit.container);\r\n\r\n {\r\n const h2 = document.createElement('div');\r\n h2.classList.add('sidebar-left-h2');\r\n i18n_({element: h2, key: 'EditAccount.Username'});\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n this.usernameInputField = new UsernameInputField({\r\n peerId: 0,\r\n label: 'EditProfile.Username.Label',\r\n name: 'username',\r\n plainText: true,\r\n listenerSetter: this.listenerSetter,\r\n onChange: () => {\r\n this.editPeer.handleChange();\r\n this.setProfileUrl();\r\n },\r\n availableText: 'EditProfile.Username.Available',\r\n takenText: 'EditProfile.Username.Taken',\r\n invalidText: 'EditProfile.Username.Invalid'\r\n });\r\n\r\n inputWrapper.append(this.usernameInputField.container);\r\n\r\n const caption = document.createElement('div');\r\n caption.classList.add('caption');\r\n caption.append(i18n('UsernameSettings.ChangeDescription'));\r\n caption.append(document.createElement('br'), document.createElement('br'));\r\n\r\n const profileUrlContainer = this.profileUrlContainer = document.createElement('div');\r\n profileUrlContainer.classList.add('profile-url-container');\r\n \r\n const profileUrlAnchor = this.profileUrlAnchor = document.createElement('a');\r\n profileUrlAnchor.classList.add('profile-url');\r\n profileUrlAnchor.href = '#';\r\n profileUrlAnchor.target = '_blank';\r\n\r\n profileUrlContainer.append(i18n('UsernameHelpLink', [profileUrlAnchor]));\r\n\r\n caption.append(profileUrlContainer);\r\n\r\n inputFields.push(this.usernameInputField);\r\n this.scrollable.append(h2, inputWrapper, caption);\r\n }\r\n\r\n attachClickEvent(this.editPeer.nextBtn, () => {\r\n this.editPeer.nextBtn.disabled = true;\r\n\r\n let promises: Promise<any>[] = [];\r\n \r\n promises.push(appProfileManager.updateProfile(this.firstNameInputField.value, this.lastNameInputField.value, this.bioInputField.value).then(() => {\r\n this.close();\r\n }, (err) => {\r\n console.error('updateProfile error:', err);\r\n }));\r\n\r\n if(this.editPeer.uploadAvatar) {\r\n promises.push(this.editPeer.uploadAvatar().then(inputFile => {\r\n return appProfileManager.uploadProfilePhoto(inputFile);\r\n }));\r\n }\r\n\r\n if(this.usernameInputField.isValid() && !this.usernameInputField.input.classList.contains('error')) {\r\n promises.push(appUsersManager.updateUsername(this.usernameInputField.value));\r\n }\r\n\r\n Promise.race(promises).finally(() => {\r\n this.editPeer.nextBtn.removeAttribute('disabled');\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n const user = appUsersManager.getSelf();\r\n\r\n const userFull = await appProfileManager.getProfile(user.id, true);\r\n\r\n this.firstNameInputField.setOriginalValue(user.first_name, true);\r\n this.lastNameInputField.setOriginalValue(user.last_name, true);\r\n this.bioInputField.setOriginalValue(userFull.about, true);\r\n this.usernameInputField.setOriginalValue(user.username, true);\r\n\r\n this.setProfileUrl();\r\n this.editPeer.handleChange();\r\n }\r\n\r\n private setProfileUrl() {\r\n if(this.usernameInputField.input.classList.contains('error') || !this.usernameInputField.value.length) {\r\n this.profileUrlContainer.style.display = 'none';\r\n } else {\r\n this.profileUrlContainer.style.display = '';\r\n let url = 'https://t.me/' + this.usernameInputField.value;\r\n this.profileUrlAnchor.innerText = url;\r\n this.profileUrlAnchor.href = url;\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport AppSelectPeers from \"../../appSelectPeers\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport { MyDialogFilter as DialogFilter } from \"../../../lib/storages/filters\";\r\nimport { copy } from \"../../../helpers/object\";\r\nimport ButtonIcon from \"../../buttonIcon\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport Button from \"../../button\";\r\nimport AppEditFolderTab from \"./editFolder\";\r\nimport I18n, { i18n, LangPackKey, _i18n, join } from \"../../../lib/langPack\";\r\nimport appMessagesManager from \"../../../lib/appManagers/appMessagesManager\";\r\nimport RichTextProcessor from \"../../../lib/richtextprocessor\";\r\nimport { SettingSection } from \"..\";\r\nimport { toast } from \"../../toast\";\r\n\r\nexport default class AppIncludedChatsTab extends SliderSuperTab {\r\n private editFolderTab: AppEditFolderTab;\r\n private confirmBtn: HTMLElement;\r\n\r\n private selector: AppSelectPeers;\r\n private type: 'included' | 'excluded';\r\n private filter: DialogFilter;\r\n private originalFilter: DialogFilter;\r\n\r\n private dialogsByFilters: Map<DialogFilter, Set<number>>;\r\n\r\n protected init() {\r\n this.content.remove();\r\n this.container.classList.add('included-chatlist-container');\r\n this.confirmBtn = ButtonIcon('check btn-confirm blue', {noRipple: true});\r\n this.confirmBtn.style.display = 'none';\r\n\r\n this.header.append(this.confirmBtn);\r\n\r\n this.confirmBtn.addEventListener('click', () => {\r\n const selected = this.selector.getSelected();\r\n\r\n //this.filter.pFlags = {};\r\n\r\n if(this.type === 'included') {\r\n for(const key in this.filter.pFlags) {\r\n if(key.indexOf('exclude_') === 0) {\r\n continue;\r\n }\r\n\r\n // @ts-ignore\r\n delete this.filter.pFlags[key];\r\n }\r\n } else {\r\n for(const key in this.filter.pFlags) {\r\n if(key.indexOf('exclude_') !== 0) {\r\n continue;\r\n }\r\n\r\n // @ts-ignore\r\n delete this.filter.pFlags[key];\r\n }\r\n }\r\n\r\n const peers: number[] = [];\r\n for(const key of selected) {\r\n if(typeof(key) === 'number') {\r\n peers.push(key);\r\n } else {\r\n // @ts-ignore\r\n this.filter.pFlags[key] = true;\r\n }\r\n }\r\n\r\n if(this.type === 'included') {\r\n this.filter.pinned_peers = this.filter.pinned_peers.filter(peerId => {\r\n return peers.includes(peerId); // * because I have pinned peer in include_peers too\r\n /* const index = peers.indexOf(peerId);\r\n if(index !== -1) {\r\n peers.splice(index, 1);\r\n return true;\r\n } else {\r\n return false;\r\n } */\r\n });\r\n } else {\r\n this.filter.pinned_peers = this.filter.pinned_peers.filter(peerId => {\r\n return !peers.includes(peerId);\r\n });\r\n }\r\n\r\n const other = this.type === 'included' ? 'exclude_peers' : 'include_peers';\r\n this.filter[other] = this.filter[other].filter(peerId => {\r\n return !peers.includes(peerId);\r\n });\r\n \r\n this.filter[this.type === 'included' ? 'include_peers' : 'exclude_peers'] = peers;\r\n //this.filter.pinned_peers = this.filter.pinned_peers.filter(peerId => this.filter.include_peers.includes(peerId));\r\n\r\n this.editFolderTab.setFilter(this.filter, false);\r\n this.close();\r\n });\r\n\r\n this.dialogsByFilters = new Map();\r\n return appMessagesManager.filtersStorage.getDialogFilters().then(filters => {\r\n for(const filter of filters) {\r\n this.dialogsByFilters.set(filter, new Set(appMessagesManager.dialogsStorage.getFolder(filter.id).map(d => d.peerId)));\r\n }\r\n });\r\n }\r\n\r\n checkbox(selected?: boolean) {\r\n const checkboxField = new CheckboxField({\r\n round: true\r\n });\r\n if(selected) {\r\n checkboxField.input.checked = selected;\r\n }\r\n\r\n return checkboxField.label;\r\n }\r\n\r\n renderResults = async(peerIds: number[]) => {\r\n //const other = this.type === 'included' ? this.filter.exclude_peers : this.filter.include_peers;\r\n\r\n await appUsersManager.getContacts();\r\n peerIds.forEach(peerId => {\r\n //if(other.includes(peerId)) return;\r\n\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId,\r\n container: this.selector.scrollable,\r\n drawStatus: false,\r\n rippleEnabled: true,\r\n avatarSize: 46\r\n });\r\n\r\n const selected = this.selector.selected.has(peerId);\r\n dom.containerEl.append(this.checkbox(selected));\r\n //if(selected) dom.listEl.classList.add('active');\r\n\r\n const foundInFilters: HTMLElement[] = [];\r\n this.dialogsByFilters.forEach((dialogs, filter) => {\r\n if(dialogs.has(peerId)) {\r\n const span = document.createElement('span');\r\n span.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);\r\n foundInFilters.push(span);\r\n }\r\n });\r\n\r\n const joined = join(foundInFilters, false);\r\n joined.forEach(el => {\r\n dom.lastMessageSpan.append(el);\r\n });\r\n });\r\n };\r\n\r\n onOpen() {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n this.confirmBtn.style.display = this.type === 'excluded' ? '' : 'none';\r\n this.setTitle(this.type === 'included' ? 'FilterAlwaysShow' : 'FilterNeverShow');\r\n\r\n const filter = this.filter;\r\n\r\n const fragment = document.createDocumentFragment();\r\n\r\n const categoriesSection = new SettingSection({\r\n noDelimiter: true,\r\n name: 'FilterChatTypes'\r\n });\r\n\r\n categoriesSection.container.classList.add('folder-categories');\r\n\r\n let details: {[flag: string]: {ico: string, text: LangPackKey}};\r\n if(this.type === 'excluded') {\r\n details = {\r\n exclude_muted: {ico: 'mute', text: 'ChatList.Filter.MutedChats'},\r\n exclude_archived: {ico: 'archive', text: 'ChatList.Filter.Archive'},\r\n exclude_read: {ico: 'readchats', text: 'ChatList.Filter.ReadChats'}\r\n };\r\n } else {\r\n details = {\r\n contacts: {ico: 'newprivate', text: 'ChatList.Filter.Contacts'},\r\n non_contacts: {ico: 'noncontacts', text: 'ChatList.Filter.NonContacts'},\r\n groups: {ico: 'group', text: 'ChatList.Filter.Groups'},\r\n broadcasts: {ico: 'newchannel', text: 'ChatList.Filter.Channels'},\r\n bots: {ico: 'bots', text: 'ChatList.Filter.Bots'}\r\n };\r\n }\r\n\r\n const f = document.createDocumentFragment();\r\n for(const key in details) {\r\n const button = Button('btn-primary btn-transparent folder-category-button', {icon: details[key].ico, text: details[key].text});\r\n button.dataset.peerId = key;\r\n button.append(this.checkbox());\r\n f.append(button);\r\n }\r\n categoriesSection.content.append(f);\r\n\r\n const chatsSection = new SettingSection({\r\n name: 'FilterChats'\r\n });\r\n\r\n fragment.append(categoriesSection.container, chatsSection.container);\r\n\r\n /////////////////\r\n\r\n const selectedPeers = (this.type === 'included' ? filter.include_peers : filter.exclude_peers).slice();\r\n\r\n this.selector = new AppSelectPeers({\r\n appendTo: this.container, \r\n onChange: this.onSelectChange, \r\n peerType: ['dialogs'], \r\n renderResultsFunc: this.renderResults,\r\n placeholder: 'Search'\r\n });\r\n this.selector.selected = new Set(selectedPeers);\r\n\r\n let addedInitial = false;\r\n const _add = this.selector.add.bind(this.selector);\r\n this.selector.add = (peerId, title, scroll) => {\r\n if(this.selector.selected.size >= 100 && addedInitial && !details[peerId]) {\r\n const el: HTMLInputElement = this.selector.list.querySelector(`[data-peer-id=\"${peerId}\"] [type=\"checkbox\"]`);\r\n if(el) {\r\n setTimeout(() => {\r\n el.checked = false;\r\n }, 0);\r\n }\r\n\r\n const str = I18n.format(this.type === 'excluded' ? 'ChatList.Filter.Exclude.LimitReached': 'ChatList.Filter.Include.LimitReached', true);\r\n toast(str);\r\n return;\r\n }\r\n\r\n const div = _add(peerId, details[peerId] ? i18n(details[peerId].text) : undefined, scroll);\r\n if(details[peerId]) {\r\n div.querySelector('avatar-element').classList.add('tgico-' + details[peerId].ico);\r\n }\r\n return div;\r\n };\r\n\r\n const parent = this.selector.list.parentElement;\r\n chatsSection.content.append(this.selector.list);\r\n parent.append(fragment);\r\n\r\n this.selector.addInitial(selectedPeers);\r\n addedInitial = true;\r\n\r\n for(const flag in filter.pFlags) {\r\n // @ts-ignore\r\n if(details.hasOwnProperty(flag) && !!filter.pFlags[flag]) {\r\n (categoriesSection.content.querySelector(`[data-peer-id=\"${flag}\"]`) as HTMLElement).click();\r\n }\r\n }\r\n }\r\n\r\n onSelectChange = (length: number) => {\r\n //const changed = !deepEqual(this.filter, this.originalFilter);\r\n if(this.type === 'included') {\r\n this.confirmBtn.style.display = length ? '' : 'none';\r\n }\r\n };\r\n\r\n onCloseAfterTimeout() {\r\n if(this.selector) {\r\n this.selector.container.remove();\r\n this.selector = null;\r\n }\r\n\r\n return super.onCloseAfterTimeout();\r\n }\r\n\r\n /**\r\n * Do not ignore arguments!\r\n */\r\n public open(filter?: DialogFilter, type?: 'included' | 'excluded', editFolderTab?: AppIncludedChatsTab['editFolderTab']) {\r\n this.originalFilter = filter;\r\n this.filter = copy(this.originalFilter);\r\n this.type = type;\r\n this.editFolderTab = editFolderTab;\r\n \r\n return super.open();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { deepEqual, copy } from \"../../../helpers/object\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport { MyDialogFilter as DialogFilter } from \"../../../lib/storages/filters\";\r\nimport lottieLoader, { RLottiePlayer } from \"../../../lib/lottieLoader\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport { toast } from \"../../toast\";\r\nimport appMessagesManager from \"../../../lib/appManagers/appMessagesManager\";\r\nimport InputField from \"../../inputField\";\r\nimport RichTextProcessor from \"../../../lib/richtextprocessor\";\r\nimport ButtonIcon from \"../../buttonIcon\";\r\nimport ButtonMenuToggle from \"../../buttonMenuToggle\";\r\nimport { ButtonMenuItemOptions } from \"../../buttonMenu\";\r\nimport Button from \"../../button\";\r\nimport AppIncludedChatsTab from \"./includedChats\";\r\nimport { i18n, i18n_, LangPackKey } from \"../../../lib/langPack\";\r\nimport { SettingSection } from \"..\";\r\n\r\nconst MAX_FOLDER_NAME_LENGTH = 12;\r\n\r\nexport default class AppEditFolderTab extends SliderSuperTab {\r\n private caption: HTMLElement;\r\n private stickerContainer: HTMLElement;\r\n\r\n private confirmBtn: HTMLElement;\r\n private menuBtn: HTMLElement;\r\n private nameInputField: InputField;\r\n\r\n private include_peers: SettingSection;\r\n private exclude_peers: SettingSection;\r\n private flags: {[k in 'contacts' | 'non_contacts' | 'groups' | 'broadcasts' | 'bots' | 'exclude_muted' | 'exclude_archived' | 'exclude_read']: HTMLElement} = {} as any;\r\n\r\n private animation: RLottiePlayer;\r\n private filter: DialogFilter;\r\n private originalFilter: DialogFilter;\r\n\r\n private type: 'edit' | 'create';\r\n private loadAnimationPromise: Promise<void>;\r\n\r\n protected init() {\r\n this.container.classList.add('edit-folder-container');\r\n this.caption = document.createElement('div');\r\n this.caption.classList.add('caption');\r\n this.caption.append(i18n('FilterIncludeExcludeInfo'));\r\n this.stickerContainer = document.createElement('div');\r\n this.stickerContainer.classList.add('sticker-container');\r\n\r\n this.confirmBtn = ButtonIcon('check btn-confirm hide blue');\r\n const deleteFolderButton: ButtonMenuItemOptions = {\r\n icon: 'delete danger',\r\n text: 'FilterMenuDelete',\r\n onClick: () => {\r\n deleteFolderButton.element.setAttribute('disabled', 'true');\r\n appMessagesManager.filtersStorage.updateDialogFilter(this.filter, true).then(bool => {\r\n if(bool) {\r\n this.close();\r\n }\r\n }).finally(() => {\r\n deleteFolderButton.element.removeAttribute('disabled');\r\n });\r\n }\r\n };\r\n this.menuBtn = ButtonMenuToggle({}, 'bottom-left', [deleteFolderButton]);\r\n this.menuBtn.classList.add('hide');\r\n\r\n this.header.append(this.confirmBtn, this.menuBtn);\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n \r\n this.nameInputField = new InputField({\r\n label: 'FilterNameInputLabel',\r\n maxLength: MAX_FOLDER_NAME_LENGTH\r\n });\r\n\r\n inputWrapper.append(this.nameInputField.container);\r\n\r\n const generateList = (className: string, h2Text: LangPackKey, buttons: {icon: string, name?: string, withRipple?: true, text: LangPackKey}[], to: any) => {\r\n const section = new SettingSection({\r\n name: h2Text,\r\n noDelimiter: true\r\n });\r\n\r\n section.container.classList.add('folder-list', className);\r\n\r\n const categories = section.generateContentElement();\r\n categories.classList.add('folder-categories');\r\n\r\n buttons.forEach(o => {\r\n const button = Button('folder-category-button btn btn-primary btn-transparent', {\r\n icon: o.icon,\r\n text: o.text,\r\n noRipple: o.withRipple ? undefined : true\r\n });\r\n\r\n if(o.name) {\r\n to[o.name] = button;\r\n }\r\n\r\n categories.append(button);\r\n });\r\n\r\n return section;\r\n };\r\n\r\n this.include_peers = generateList('folder-list-included', 'FilterInclude', [{\r\n icon: 'add primary',\r\n text: 'ChatList.Filter.Include.AddChat',\r\n withRipple: true\r\n }, {\r\n text: 'ChatList.Filter.Contacts',\r\n icon: 'newprivate',\r\n name: 'contacts'\r\n }, {\r\n text: 'ChatList.Filter.NonContacts',\r\n icon: 'noncontacts',\r\n name: 'non_contacts'\r\n }, {\r\n text: 'ChatList.Filter.Groups',\r\n icon: 'group',\r\n name: 'groups'\r\n }, {\r\n text: 'ChatList.Filter.Channels',\r\n icon: 'channel',\r\n name: 'broadcasts'\r\n }, {\r\n text: 'ChatList.Filter.Bots',\r\n icon: 'bots',\r\n name: 'bots'\r\n }], this.flags);\r\n\r\n this.exclude_peers = generateList('folder-list-excluded', 'FilterExclude', [{\r\n icon: 'minus primary',\r\n text: 'ChatList.Filter.Exclude.AddChat',\r\n withRipple: true\r\n }, {\r\n text: 'ChatList.Filter.MutedChats',\r\n icon: 'mute',\r\n name: 'exclude_muted'\r\n }, {\r\n text: 'ChatList.Filter.Archive',\r\n icon: 'archive',\r\n name: 'exclude_archived'\r\n }, {\r\n text: 'ChatList.Filter.ReadChats',\r\n icon: 'readchats',\r\n name: 'exclude_read'\r\n }], this.flags);\r\n\r\n this.scrollable.append(this.stickerContainer, this.caption, inputWrapper, this.include_peers.container, this.exclude_peers.container);\r\n\r\n const includedFlagsContainer = this.include_peers.container.querySelector('.folder-categories');\r\n const excludedFlagsContainer = this.exclude_peers.container.querySelector('.folder-categories');\r\n\r\n includedFlagsContainer.querySelector('.btn').addEventListener('click', () => {\r\n new AppIncludedChatsTab(this.slider).open(this.filter, 'included', this);\r\n });\r\n\r\n excludedFlagsContainer.querySelector('.btn').addEventListener('click', () => {\r\n new AppIncludedChatsTab(this.slider).open(this.filter, 'excluded', this);\r\n });\r\n\r\n this.confirmBtn.addEventListener('click', () => {\r\n if(this.nameInputField.input.classList.contains('error')) {\r\n return;\r\n }\r\n\r\n if(!this.nameInputField.value.trim()) {\r\n this.nameInputField.input.classList.add('error');\r\n return;\r\n }\r\n\r\n let include = (Array.from(includedFlagsContainer.children) as HTMLElement[]).slice(1).reduce((acc, el) => acc + +!el.style.display, 0);\r\n include += this.filter.include_peers.length;\r\n \r\n if(!include) {\r\n toast('Please choose at least one chat for this folder.');\r\n return;\r\n }\r\n\r\n this.confirmBtn.setAttribute('disabled', 'true');\r\n\r\n let promise: Promise<boolean>;\r\n if(!this.filter.id) {\r\n promise = appMessagesManager.filtersStorage.createDialogFilter(this.filter);\r\n } else {\r\n promise = appMessagesManager.filtersStorage.updateDialogFilter(this.filter);\r\n }\r\n\r\n promise.then(bool => {\r\n if(bool) {\r\n this.close();\r\n }\r\n }).catch(err => {\r\n if(err.type === 'DIALOG_FILTERS_TOO_MUCH') {\r\n toast('Sorry, you can\\'t create more folders.');\r\n } else {\r\n console.error('updateDialogFilter error:', err);\r\n }\r\n }).finally(() => {\r\n this.confirmBtn.removeAttribute('disabled');\r\n });\r\n });\r\n \r\n this.nameInputField.input.addEventListener('input', () => {\r\n this.filter.title = this.nameInputField.value;\r\n this.editCheckForChange();\r\n });\r\n\r\n return this.loadAnimationPromise = lottieLoader.loadAnimationFromURL({\r\n container: this.stickerContainer,\r\n loop: false,\r\n autoplay: false,\r\n width: 86,\r\n height: 86\r\n }, 'assets/img/Folders_2.tgs').then(player => {\r\n this.animation = player;\r\n\r\n return lottieLoader.waitForFirstFrame(player);\r\n });\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n this.loadAnimationPromise.then(() => {\r\n this.animation.autoplay = true;\r\n this.animation.play();\r\n });\r\n }\r\n\r\n private onCreateOpen() {\r\n this.caption.style.display = '';\r\n this.setTitle('FilterNew');\r\n this.menuBtn.classList.add('hide');\r\n this.confirmBtn.classList.remove('hide');\r\n this.nameInputField.value = '';\r\n\r\n for(const flag in this.flags) {\r\n // @ts-ignore\r\n this.flags[flag].style.display = 'none';\r\n }\r\n }\r\n\r\n private onEditOpen() {\r\n this.caption.style.display = 'none';\r\n this.setTitle(this.type === 'create' ? 'FilterNew' : 'FilterHeaderEdit');\r\n\r\n if(this.type === 'edit') {\r\n this.menuBtn.classList.remove('hide');\r\n this.confirmBtn.classList.add('hide');\r\n }\r\n \r\n const filter = this.filter;\r\n this.nameInputField.value = RichTextProcessor.wrapDraftText(filter.title);\r\n\r\n for(const flag in this.flags) {\r\n this.flags[flag as keyof AppEditFolderTab['flags']].style.display = !!filter.pFlags[flag as keyof AppEditFolderTab['flags']] ? '' : 'none';\r\n }\r\n\r\n (['include_peers', 'exclude_peers'] as ['include_peers', 'exclude_peers']).forEach(key => {\r\n const section = this[key];\r\n const ul = appDialogsManager.createChatList();\r\n\r\n const peers = filter[key].slice();\r\n\r\n const renderMore = (_length: number) => {\r\n for(let i = 0, length = Math.min(peers.length, _length); i < length; ++i) {\r\n const peerId = peers.shift();\r\n\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId,\r\n container: ul,\r\n drawStatus: false,\r\n rippleEnabled: false,\r\n meAsSaved: true,\r\n avatarSize: 32\r\n });\r\n dom.lastMessageSpan.parentElement.remove();\r\n }\r\n\r\n if(peers.length) {\r\n showMore.lastElementChild.replaceWith(i18n('FilterShowMoreChats', [peers.length]));\r\n } else if(showMore) {\r\n showMore.remove();\r\n }\r\n };\r\n \r\n section.generateContentElement().append(ul);\r\n\r\n let showMore: HTMLElement;\r\n if(peers.length) {\r\n const content = section.generateContentElement();\r\n showMore = Button('folder-category-button btn btn-primary btn-transparent', {icon: 'down'});\r\n showMore.classList.add('load-more', 'rp-overflow');\r\n showMore.addEventListener('click', () => renderMore(20));\r\n showMore.append(i18n('FilterShowMoreChats', [peers.length]));\r\n\r\n content.append(showMore);\r\n }\r\n\r\n renderMore(4);\r\n });\r\n }\r\n\r\n editCheckForChange() {\r\n if(this.type === 'edit') {\r\n const changed = !deepEqual(this.originalFilter, this.filter);\r\n this.confirmBtn.classList.toggle('hide', !changed);\r\n this.menuBtn.classList.toggle('hide', changed);\r\n }\r\n };\r\n\r\n setFilter(filter: DialogFilter, firstTime: boolean) {\r\n // cleanup\r\n Array.from(this.container.querySelectorAll('ul, .load-more')).forEach(el => el.remove());\r\n\r\n if(firstTime) {\r\n this.originalFilter = filter;\r\n this.filter = copy(filter);\r\n } else {\r\n this.filter = filter;\r\n this.onEditOpen();\r\n this.editCheckForChange();\r\n }\r\n }\r\n\r\n public open(filter?: DialogFilter) {\r\n const ret = super.open();\r\n \r\n if(filter === undefined) {\r\n this.setFilter({\r\n _: 'dialogFilter',\r\n id: 0,\r\n title: '',\r\n pFlags: {},\r\n pinned_peers: [],\r\n include_peers: [],\r\n exclude_peers: []\r\n }, true);\r\n this.type = 'create';\r\n this.onCreateOpen();\r\n } else {\r\n this.setFilter(filter, true);\r\n this.type = 'edit';\r\n this.onEditOpen();\r\n }\r\n\r\n return ret;\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport lottieLoader, { RLottiePlayer } from \"../../../lib/lottieLoader\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport { toast } from \"../../toast\";\r\nimport type { MyDialogFilter } from \"../../../lib/storages/filters\";\r\nimport type { DialogFilterSuggested, DialogFilter } from \"../../../layer\";\r\nimport type _rootScope from \"../../../lib/rootScope\";\r\nimport type { BroadcastEvents } from \"../../../lib/rootScope\";\r\nimport Button from \"../../button\";\r\nimport appMessagesManager from \"../../../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager from \"../../../lib/appManagers/appPeersManager\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport AppEditFolderTab from \"./editFolder\";\r\nimport Row from \"../../row\";\r\nimport { SettingSection } from \"..\";\r\nimport { i18n, i18n_, LangPackKey, join } from \"../../../lib/langPack\";\r\nimport { cancelEvent } from \"../../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport positionElementByIndex from \"../../../helpers/dom/positionElementByIndex\";\r\n\r\nexport default class AppChatFoldersTab extends SliderSuperTab {\r\n private createFolderBtn: HTMLElement;\r\n private foldersSection: SettingSection;\r\n private suggestedSection: SettingSection;\r\n private stickerContainer: HTMLElement;\r\n private animation: RLottiePlayer;\r\n\r\n private filtersRendered: {[filterId: number]: Row} = {};\r\n private loadAnimationPromise: Promise<void>;\r\n\r\n private renderFolder(dialogFilter: DialogFilterSuggested | DialogFilter | MyDialogFilter, container?: HTMLElement, row?: Row) {\r\n let filter: DialogFilter | MyDialogFilter;\r\n let description = '';\r\n let d: HTMLElement[] = [];\r\n if(dialogFilter._ === 'dialogFilterSuggested') {\r\n filter = dialogFilter.filter;\r\n description = dialogFilter.description;\r\n } else {\r\n filter = dialogFilter;\r\n\r\n let enabledFilters = Object.keys(filter.pFlags).length;\r\n /* (['include_peers', 'exclude_peers'] as ['include_peers', 'exclude_peers']).forEach(key => {\r\n enabledFilters += +!!filter[key].length;\r\n }); */\r\n \r\n if(enabledFilters === 1) {\r\n const pFlags = filter.pFlags;\r\n let k: LangPackKey;\r\n if(pFlags.contacts) k = 'FilterAllContacts';\r\n else if(pFlags.non_contacts) k = 'FilterAllNonContacts';\r\n else if(pFlags.groups) k = 'FilterAllGroups';\r\n else if(pFlags.broadcasts) k = 'FilterAllChannels';\r\n else if(pFlags.bots) k = 'FilterAllBots';\r\n\r\n if(k) {\r\n d.push(i18n(k));\r\n }\r\n }\r\n \r\n if(!d.length) {\r\n const folder = appMessagesManager.dialogsStorage.getFolder(filter.id);\r\n let chats = 0, channels = 0, groups = 0;\r\n for(const dialog of folder) {\r\n if(appPeersManager.isAnyGroup(dialog.peerId)) groups++;\r\n else if(appPeersManager.isBroadcast(dialog.peerId)) channels++;\r\n else chats++;\r\n }\r\n\r\n if(chats) d.push(i18n('Chats', [chats]));\r\n if(channels) d.push(i18n('Channels', [channels]));\r\n if(groups) d.push(i18n('Groups', [groups]));\r\n }\r\n }\r\n\r\n let div: HTMLElement;\r\n if(!row) {\r\n row = new Row({\r\n title: RichTextProcessor.wrapEmojiText(filter.title),\r\n subtitle: description,\r\n clickable: true\r\n });\r\n\r\n if(d.length) {\r\n join(d).forEach(el => {\r\n row.subtitle.append(el);\r\n });\r\n }\r\n \r\n if(dialogFilter._ === 'dialogFilter') {\r\n const filterId = filter.id;\r\n if(!this.filtersRendered.hasOwnProperty(filter.id)) {\r\n attachClickEvent(row.container, () => {\r\n new AppEditFolderTab(this.slider).open(appMessagesManager.filtersStorage.getFilter(filterId));\r\n }, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n this.filtersRendered[filter.id] = row;\r\n }\r\n } else {\r\n row.subtitle.textContent = '';\r\n join(d).forEach(el => {\r\n row.subtitle.append(el);\r\n });\r\n }\r\n\r\n div = row.container;\r\n\r\n if((filter as MyDialogFilter).hasOwnProperty('orderIndex')) {\r\n // ! header will be at 0 index\r\n positionElementByIndex(div, div.parentElement || container, (filter as MyDialogFilter).orderIndex);\r\n } else if(container) container.append(div);\r\n \r\n return div;\r\n }\r\n\r\n protected async init() {\r\n this.container.classList.add('chat-folders-container');\r\n this.setTitle('ChatList.Filter.List.Title');\r\n\r\n this.scrollable.container.classList.add('chat-folders');\r\n\r\n this.stickerContainer = document.createElement('div');\r\n this.stickerContainer.classList.add('sticker-container');\r\n \r\n const caption = document.createElement('div');\r\n caption.classList.add('caption');\r\n i18n_({element: caption, key: 'ChatList.Filter.Header'});\r\n \r\n this.createFolderBtn = Button('btn-primary btn-color-primary btn-control tgico', {\r\n text: 'ChatList.Filter.NewTitle',\r\n icon: 'add'\r\n });\r\n\r\n this.foldersSection = new SettingSection({\r\n name: 'Filters'\r\n });\r\n this.foldersSection.container.style.display = 'none';\r\n\r\n this.suggestedSection = new SettingSection({\r\n name: 'FilterRecommended'\r\n });\r\n this.suggestedSection.container.style.display = 'none';\r\n\r\n this.scrollable.append(this.stickerContainer, caption, this.createFolderBtn, this.foldersSection.container, this.suggestedSection.container);\r\n\r\n attachClickEvent(this.createFolderBtn, () => {\r\n if(Object.keys(this.filtersRendered).length >= 10) {\r\n toast('Sorry, you can\\'t create more folders.');\r\n } else {\r\n new AppEditFolderTab(this.slider).open();\r\n }\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n const onFiltersContainerUpdate = () => {\r\n this.foldersSection.container.style.display = Object.keys(this.filtersRendered).length ? '' : 'none';\r\n };\r\n\r\n appMessagesManager.filtersStorage.getDialogFilters().then(filters => {\r\n for(const filter of filters) {\r\n this.renderFolder(filter, this.foldersSection.content);\r\n }\r\n\r\n onFiltersContainerUpdate();\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('filter_update', (e) => {\r\n const filter = e;\r\n if(this.filtersRendered.hasOwnProperty(filter.id)) {\r\n this.renderFolder(filter, null, this.filtersRendered[filter.id]);\r\n } else {\r\n this.renderFolder(filter, this.foldersSection.content);\r\n }\r\n\r\n onFiltersContainerUpdate();\r\n\r\n this.getSuggestedFilters();\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('filter_delete', (e) => {\r\n const filter = e;\r\n if(this.filtersRendered.hasOwnProperty(filter.id)) {\r\n /* for(const suggested of this.suggestedFilters) {\r\n if(deepEqual(suggested.filter, filter)) {\r\n \r\n }\r\n } */\r\n this.getSuggestedFilters();\r\n\r\n this.filtersRendered[filter.id].container.remove();\r\n delete this.filtersRendered[filter.id];\r\n }\r\n\r\n onFiltersContainerUpdate();\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('filter_order', (e: BroadcastEvents['filter_order']) => {\r\n const order = e;\r\n order.forEach((filterId, idx) => {\r\n const container = this.filtersRendered[filterId].container;\r\n positionElementByIndex(container, container.parentElement, idx + 1); // ! + 1 due to header \r\n });\r\n });\r\n\r\n this.loadAnimationPromise = lottieLoader.loadAnimationFromURL({\r\n container: this.stickerContainer,\r\n loop: false,\r\n autoplay: false,\r\n width: 86,\r\n height: 86\r\n }, 'assets/img/Folders_1.tgs').then(player => {\r\n this.animation = player;\r\n\r\n return lottieLoader.waitForFirstFrame(player);\r\n });\r\n\r\n this.getSuggestedFilters()\r\n\r\n /* return Promise.all([\r\n this.loadAnimationPromise\r\n ]); */\r\n return this.loadAnimationPromise;\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n this.loadAnimationPromise.then(() => {\r\n this.animation.autoplay = true;\r\n this.animation.play();\r\n });\r\n }\r\n\r\n private getSuggestedFilters() {\r\n return apiManager.invokeApi('messages.getSuggestedDialogFilters').then(suggestedFilters => {\r\n this.suggestedSection.container.style.display = suggestedFilters.length ? '' : 'none';\r\n Array.from(this.suggestedSection.content.children).slice(1).forEach(el => el.remove());\r\n\r\n suggestedFilters.forEach(filter => {\r\n const div = this.renderFolder(filter);\r\n const button = Button('btn-primary btn-color-primary', {text: 'Add'});\r\n div.append(button);\r\n this.suggestedSection.content.append(div);\r\n\r\n attachClickEvent(button, (e) => {\r\n cancelEvent(e);\r\n\r\n if(Object.keys(this.filtersRendered).length >= 10) {\r\n toast('Sorry, you can\\'t create more folders.');\r\n return;\r\n }\r\n\r\n button.setAttribute('disabled', 'true');\r\n\r\n appMessagesManager.filtersStorage.createDialogFilter(filter.filter as any).then(bool => {\r\n if(bool) {\r\n div.remove();\r\n }\r\n }).finally(() => {\r\n button.removeAttribute('disabled');\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n });\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"..\";\r\nimport Row from \"../../row\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport { InputNotifyPeer, Update } from \"../../../layer\";\r\nimport appNotificationsManager from \"../../../lib/appManagers/appNotificationsManager\";\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport { copy } from \"../../../helpers/object\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport { convertKeyToInputKey } from \"../../../helpers/string\";\r\nimport { LangPackKey } from \"../../../lib/langPack\";\r\nimport appStateManager from \"../../../lib/appManagers/appStateManager\";\r\n\r\ntype InputNotifyKey = Exclude<InputNotifyPeer['_'], 'inputNotifyPeer'>;\r\n\r\nexport default class AppNotificationsTab extends SliderSuperTabEventable {\r\n protected init() {\r\n this.container.classList.add('notifications-container');\r\n this.setTitle('Telegram.NotificationSettingsViewController');\r\n\r\n const NotifySection = (options: {\r\n name: LangPackKey,\r\n typeText: LangPackKey,\r\n inputKey: InputNotifyKey,\r\n }) => {\r\n const section = new SettingSection({\r\n name: options.name\r\n });\r\n\r\n const enabledRow = new Row({\r\n checkboxField: new CheckboxField({text: options.typeText, checked: true}),\r\n subtitleLangKey: 'Loading',\r\n });\r\n \r\n const previewEnabledRow = new Row({\r\n checkboxField: new CheckboxField({text: 'Notifications.MessagePreview', checked: true}),\r\n subtitleLangKey: 'Loading',\r\n });\r\n\r\n section.content.append(enabledRow.container, previewEnabledRow.container);\r\n\r\n this.scrollable.append(section.container);\r\n\r\n const inputNotifyPeer = {_: options.inputKey};\r\n const ret = appNotificationsManager.getNotifySettings(inputNotifyPeer);\r\n (ret instanceof Promise ? ret : Promise.resolve(ret)).then((notifySettings) => {\r\n const applySettings = () => {\r\n const muted = appNotificationsManager.isMuted(notifySettings);\r\n enabledRow.checkboxField.checked = !muted;\r\n previewEnabledRow.checkboxField.checked = notifySettings.show_previews;\r\n \r\n return muted;\r\n };\r\n \r\n applySettings();\r\n\r\n this.eventListener.addEventListener('destroy', () => {\r\n const mute = !enabledRow.checkboxField.checked;\r\n const showPreviews = previewEnabledRow.checkboxField.checked;\r\n\r\n if(mute === appNotificationsManager.isMuted(notifySettings) && showPreviews === notifySettings.show_previews) {\r\n return;\r\n }\r\n\r\n const inputSettings: any = copy(notifySettings);\r\n inputSettings._ = 'inputPeerNotifySettings';\r\n inputSettings.mute_until = mute ? 0x7FFFFFFF : 0;\r\n inputSettings.show_previews = showPreviews;\r\n\r\n appNotificationsManager.updateNotifySettings(inputNotifyPeer, inputSettings);\r\n }, {once: true});\r\n\r\n this.listenerSetter.add(rootScope)('notify_settings', (update: Update.updateNotifySettings) => {\r\n const inputKey = convertKeyToInputKey(update.peer._) as any;\r\n if(options.inputKey === inputKey) {\r\n notifySettings = update.notify_settings;\r\n applySettings();\r\n }\r\n });\r\n });\r\n };\r\n\r\n NotifySection({\r\n name: 'NotificationsPrivateChats',\r\n typeText: 'NotificationsForPrivateChats',\r\n inputKey: 'inputNotifyUsers'\r\n });\r\n\r\n NotifySection({\r\n name: 'NotificationsGroups',\r\n typeText: 'NotificationsForGroups',\r\n inputKey: 'inputNotifyChats'\r\n });\r\n\r\n NotifySection({\r\n name: 'NotificationsChannels',\r\n typeText: 'NotificationsForChannels',\r\n inputKey: 'inputNotifyBroadcasts'\r\n });\r\n\r\n {\r\n const section = new SettingSection({\r\n name: 'NotificationsOther'\r\n });\r\n\r\n const contactsSignUpRow = new Row({\r\n checkboxField: new CheckboxField({text: 'ContactJoined', checked: true}),\r\n subtitleLangKey: 'Loading',\r\n });\r\n \r\n const soundRow = new Row({\r\n checkboxField: new CheckboxField({text: 'Notifications.Sound', checked: true, stateKey: 'settings.notifications.sound'}),\r\n subtitleLangKey: 'Loading',\r\n });\r\n\r\n appStateManager.getState().then(state => {\r\n soundRow.checkboxField.checked = state.settings.notifications.sound;\r\n });\r\n\r\n section.content.append(contactsSignUpRow.container, soundRow.container);\r\n\r\n this.scrollable.append(section.container);\r\n\r\n appNotificationsManager.getContactSignUpNotification().then(enabled => {\r\n contactsSignUpRow.checkboxField.checked = enabled;\r\n\r\n this.eventListener.addEventListener('destroy', () => {\r\n const _enabled = contactsSignUpRow.checkboxField.checked;\r\n if(enabled !== _enabled) {\r\n appNotificationsManager.setContactSignUpNotification(!_enabled);\r\n }\r\n }, {once: true});\r\n });\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SettingSection } from \"..\";\r\nimport { randomLong } from \"../../../helpers/random\";\r\nimport I18n from \"../../../lib/langPack\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport RadioField from \"../../radioField\";\r\nimport Row, { RadioFormFromRows } from \"../../row\";\r\nimport { SliderSuperTab } from \"../../slider\"\r\n\r\nexport default class AppLanguageTab extends SliderSuperTab {\r\n protected async init() {\r\n this.container.classList.add('language-container');\r\n this.setTitle('Telegram.LanguageViewController');\r\n\r\n const section = new SettingSection({});\r\n\r\n const radioRows: Map<string, Row> = new Map();\r\n\r\n const promise = apiManager.invokeApiCacheable('langpack.getLanguages', {\r\n lang_pack: 'macos'\r\n }).then((languages) => {\r\n const random = randomLong();\r\n languages.forEach((language) => {\r\n const row = new Row({\r\n radioField: new RadioField({\r\n text: language.name, \r\n name: random, \r\n value: language.lang_code\r\n }),\r\n subtitle: language.native_name\r\n });\r\n \r\n radioRows.set(language.lang_code, row);\r\n });\r\n\r\n const form = RadioFormFromRows([...radioRows.values()], (value) => {\r\n I18n.getLangPack(value);\r\n });\r\n \r\n I18n.getCacheLangPack().then(langPack => {\r\n const row = radioRows.get(langPack.lang_code);\r\n if(!row) {\r\n console.error('no row', row, langPack);\r\n return;\r\n }\r\n \r\n row.radioField.setValueSilently(true);\r\n });\r\n \r\n section.content.append(form);\r\n });\r\n\r\n this.scrollable.append(section.container);\r\n\r\n return promise;\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport AvatarElement from \"../../avatar\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport ButtonMenuToggle from \"../../buttonMenuToggle\";\r\nimport Button from \"../../button\";\r\nimport AppPrivacyAndSecurityTab from \"./privacyAndSecurity\";\r\nimport AppGeneralSettingsTab from \"./generalSettings\";\r\nimport AppEditProfileTab from \"./editProfile\";\r\nimport AppChatFoldersTab from \"./chatFolders\";\r\nimport AppNotificationsTab from \"./notifications\";\r\nimport PeerTitle from \"../../peerTitle\";\r\nimport AppLanguageTab from \"./language\";\r\nimport lottieLoader from \"../../../lib/lottieLoader\";\r\n//import AppMediaViewer from \"../../appMediaViewerNew\";\r\n\r\nexport default class AppSettingsTab extends SliderSuperTab {\r\n private avatarElem: AvatarElement;\r\n private nameDiv: HTMLElement;\r\n private phoneDiv: HTMLElement;\r\n\r\n private buttons: {\r\n edit: HTMLButtonElement,\r\n folders: HTMLButtonElement,\r\n general: HTMLButtonElement,\r\n notifications: HTMLButtonElement,\r\n privacy: HTMLButtonElement,\r\n language: HTMLButtonElement\r\n } = {} as any;\r\n\r\n protected init() {\r\n this.container.classList.add('settings-container');\r\n this.setTitle('Settings');\r\n \r\n const btnMenu = ButtonMenuToggle({}, 'bottom-left', [{\r\n icon: 'logout',\r\n text: 'EditAccount.Logout',\r\n onClick: () => {\r\n apiManager.logOut();\r\n }\r\n }]);\r\n\r\n this.header.append(btnMenu);\r\n\r\n this.avatarElem = new AvatarElement();\r\n this.avatarElem.setAttribute('clickable', '');\r\n this.avatarElem.classList.add('profile-avatar', 'avatar-120');\r\n\r\n /* const div = document.createElement('div');\r\n //div.style.cssText = 'border-radius: 8px; overflow: hidden; width: 396px; height: 264px; flex: 0 0 auto; position: relative; margin: 10rem 0 10rem auto;';\r\n //div.style.width = '135px';\r\n //div.style.height = '100px';\r\n div.style.cssText = 'border-radius: 8px; overflow: hidden; width: 396px; height: 264px; flex: 0 0 auto; position: relative; margin: 10rem auto 10rem 0;';\r\n div.style.width = '135px';\r\n div.style.height = '100px';\r\n \r\n const img = document.createElement('img');\r\n img.src = 'assets/img/pepe.jpg';\r\n img.classList.add('media-photo');\r\n img.style.cssText = 'max-width: 100%;max-height: 100%;';\r\n\r\n div.append(img);\r\n\r\n div.addEventListener('click', () => {\r\n new AppMediaViewer().setSearchContext({peerId: 61004386, inputFilter: 'inputMessagesFilterPhotos'}).openMedia({\r\n _: 'message',\r\n mid: 1,\r\n peerId: 61004386,\r\n fromId: 61004386,\r\n message: '',\r\n media: {\r\n _: 'messageMediaPhoto',\r\n photo: {\r\n _: 'photo',\r\n url: img.src,\r\n downloaded: 111,\r\n sizes: [{\r\n _: 'photoSize',\r\n type: 'x',\r\n w: 618,\r\n h: 412\r\n }]\r\n }\r\n },\r\n date: Date.now() / 1000 | 0\r\n }, img);\r\n });\r\n\r\n this.scrollable.append(div); */\r\n \r\n this.nameDiv = document.createElement('div');\r\n this.nameDiv.classList.add('profile-name');\r\n\r\n this.phoneDiv = document.createElement('div');\r\n this.phoneDiv.classList.add('profile-subtitle');\r\n\r\n const buttonsDiv = document.createElement('div');\r\n buttonsDiv.classList.add('profile-buttons');\r\n\r\n const className = 'profile-button btn-primary btn-transparent';\r\n buttonsDiv.append(this.buttons.edit = Button(className, {icon: 'edit', text: 'EditAccount.Title'}));\r\n buttonsDiv.append(this.buttons.folders = Button(className, {icon: 'folder', text: 'AccountSettings.Filters'}));\r\n buttonsDiv.append(this.buttons.general = Button(className, {icon: 'settings', text: 'Telegram.GeneralSettingsViewController'}));\r\n buttonsDiv.append(this.buttons.notifications = Button(className, {icon: 'unmute', text: 'AccountSettings.Notifications'}));\r\n buttonsDiv.append(this.buttons.privacy = Button(className, {icon: 'lock', text: 'AccountSettings.PrivacyAndSecurity'}));\r\n buttonsDiv.append(this.buttons.language = Button(className, {icon: 'language', text: 'AccountSettings.Language'}));\r\n \r\n this.scrollable.append(this.avatarElem, this.nameDiv, this.phoneDiv, buttonsDiv);\r\n this.scrollable.container.classList.add('profile-content-wrapper');\r\n\r\n /* rootScope.$on('user_auth', (e) => {\r\n this.fillElements();\r\n }); */\r\n\r\n this.buttons.edit.addEventListener('click', () => {\r\n const tab = new AppEditProfileTab(this.slider);\r\n tab.open();\r\n });\r\n\r\n this.buttons.folders.addEventListener('click', () => {\r\n new AppChatFoldersTab(this.slider).open();\r\n });\r\n\r\n this.buttons.general.addEventListener('click', () => {\r\n new AppGeneralSettingsTab(this.slider).open();\r\n });\r\n\r\n this.buttons.notifications.addEventListener('click', () => {\r\n new AppNotificationsTab(this.slider).open();\r\n });\r\n\r\n this.buttons.privacy.addEventListener('click', () => {\r\n new AppPrivacyAndSecurityTab(this.slider).open();\r\n });\r\n\r\n this.buttons.language.addEventListener('click', () => {\r\n new AppLanguageTab(this.slider).open();\r\n });\r\n\r\n lottieLoader.loadLottieWorkers();\r\n\r\n this.fillElements();\r\n }\r\n\r\n public fillElements() {\r\n let user = appUsersManager.getSelf();\r\n this.avatarElem.setAttribute('peer', '' + user.id);\r\n\r\n this.nameDiv.append(new PeerTitle({peerId: user.id}).element);\r\n this.phoneDiv.innerHTML = user.phone ? appUsersManager.formatUserPhone(user.phone) : '';\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appSidebarLeft from \"..\";\r\nimport { InputFile } from \"../../../layer\";\r\nimport appChatsManager from \"../../../lib/appManagers/appChatsManager\";\r\nimport Button from \"../../button\";\r\nimport InputField from \"../../inputField\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport AvatarEdit from \"../../avatarEdit\";\r\nimport AppAddMembersTab from \"./addMembers\";\r\nimport { _i18n } from \"../../../lib/langPack\";\r\nimport ButtonCorner from \"../../buttonCorner\";\r\n\r\nexport default class AppNewChannelTab extends SliderSuperTab {\r\n private uploadAvatar: () => Promise<InputFile> = null;\r\n\r\n private channelNameInputField: InputField;\r\n private channelDescriptionInputField: InputField;\r\n private nextBtn: HTMLButtonElement;\r\n private avatarEdit: AvatarEdit;\r\n\r\n protected init() {\r\n this.container.classList.add('new-channel-container');\r\n this.setTitle('NewChannel');\r\n\r\n this.avatarEdit = new AvatarEdit((_upload) => {\r\n this.uploadAvatar = _upload;\r\n });\r\n\r\n const inputWrapper = document.createElement('div');\r\n inputWrapper.classList.add('input-wrapper');\r\n\r\n this.channelNameInputField = new InputField({\r\n label: 'EnterChannelName',\r\n maxLength: 128\r\n });\r\n\r\n this.channelDescriptionInputField = new InputField({\r\n label: 'DescriptionOptionalPlaceholder',\r\n maxLength: 255\r\n });\r\n\r\n inputWrapper.append(this.channelNameInputField.container, this.channelDescriptionInputField.container);\r\n\r\n const onLengthChange = () => {\r\n this.nextBtn.classList.toggle('is-visible', !!this.channelNameInputField.value.length && \r\n !this.channelNameInputField.input.classList.contains('error') && \r\n !this.channelDescriptionInputField.input.classList.contains('error'));\r\n };\r\n\r\n this.channelNameInputField.input.addEventListener('input', onLengthChange);\r\n this.channelDescriptionInputField.input.addEventListener('input', onLengthChange);\r\n\r\n const caption = document.createElement('div');\r\n caption.classList.add('caption');\r\n _i18n(caption, 'Channel.DescriptionHolderDescrpiton');\r\n\r\n this.nextBtn = ButtonCorner({icon: 'arrow_next'});\r\n\r\n this.nextBtn.addEventListener('click', () => {\r\n const title = this.channelNameInputField.value;\r\n const about = this.channelDescriptionInputField.value;\r\n\r\n this.nextBtn.disabled = true;\r\n appChatsManager.createChannel(title, about).then((channelId) => {\r\n if(this.uploadAvatar) {\r\n this.uploadAvatar().then((inputFile) => {\r\n appChatsManager.editPhoto(channelId, inputFile);\r\n });\r\n }\r\n \r\n appSidebarLeft.removeTabFromHistory(this);\r\n new AppAddMembersTab(this.slider).open({\r\n peerId: channelId,\r\n type: 'channel',\r\n skippable: true,\r\n title: 'GroupAddMembers',\r\n placeholder: 'SendMessageTo',\r\n takeOut: (peerIds) => {\r\n return appChatsManager.inviteToChannel(Math.abs(channelId), peerIds);\r\n }\r\n });\r\n });\r\n });\r\n\r\n this.content.append(this.nextBtn);\r\n this.scrollable.append(this.avatarEdit.container, inputWrapper, caption);\r\n }\r\n\r\n public onCloseAfterTimeout() {\r\n this.avatarEdit.clear();\r\n this.uploadAvatar = null;\r\n this.channelNameInputField.value = '';\r\n this.channelDescriptionInputField.value = '';\r\n this.nextBtn.disabled = false;\r\n return super.onCloseAfterTimeout();\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport InputField from \"../inputField\";\nimport PopupElement from \".\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport EditPeer from \"../editPeer\";\nimport { _i18n } from \"../../lib/langPack\";\nimport TelInputField from \"../telInputField\";\nimport appUsersManager from \"../../lib/appManagers/appUsersManager\";\nimport { formatPhoneNumber } from \"../../helpers/formatPhoneNumber\";\nimport { toastNew } from \"../toast\";\n\nexport default class PopupCreateContact extends PopupElement {\n constructor() {\n super('popup-create-contact popup-send-photo popup-new-media', null, {closable: true, withConfirm: 'Add'});\n\n _i18n(this.title, 'AddContactTitle');\n\n attachClickEvent(this.btnConfirm, () => {\n const promise = appUsersManager.importContact(nameInputField.value, lastNameInputField.value, telInputField.value);\n\n promise.then(() => {\n this.hide();\n }, (err) => {\n if(err.type === 'NO_USER') {\n toastNew({langPackKey: 'Contacts.PhoneNumber.NotRegistred'});\n editPeer.disabled = false;\n }\n });\n\n editPeer.lockWithPromise(promise);\n }, {listenerSetter: this.listenerSetter});\n\n const inputFields: InputField[] = [];\n const div = document.createElement('div');\n div.classList.add('name-fields');\n const nameInputField = new InputField({\n label: 'FirstName',\n name: 'create-contact-name',\n maxLength: 70,\n required: true\n });\n const lastNameInputField = new InputField({\n label: 'LastName',\n name: 'create-contact-lastname',\n maxLength: 70\n });\n const telInputField = new TelInputField({required: true});\n inputFields.push(nameInputField, lastNameInputField, telInputField);\n\n const onInput = () => {\n const name = nameInputField.value + ' ' + lastNameInputField.value;\n // const abbr = RichTextProcessor.getAbbreviation(name);\n editPeer.avatarElem.setAttribute('peer-title', name);\n editPeer.avatarElem.update();\n };\n\n this.listenerSetter.add(nameInputField.input)('input', onInput);\n this.listenerSetter.add(lastNameInputField.input)('input', onInput);\n\n const user = appUsersManager.getSelf();\n const formatted = formatPhoneNumber(user.phone);\n if(formatted) {\n telInputField.validate = () => {\n return !!telInputField.value.match(/\\d/);\n };\n\n telInputField.value = '+' + formatted.code.country_code;\n }\n\n const editPeer = new EditPeer({\n inputFields,\n listenerSetter: this.listenerSetter,\n doNotEditAvatar: true,\n nextBtn: this.btnConfirm,\n avatarSize: 100\n });\n\n div.append(nameInputField.container, lastNameInputField.container, editPeer.avatarElem);\n this.container.append(div, telInputField.container);\n\n this.show();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { SliderSuperTab } from \"../../slider\";\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\nimport InputSearch from \"../../inputSearch\";\nimport { IS_MOBILE } from \"../../../environment/userAgent\";\nimport { canFocus } from \"../../../helpers/dom/canFocus\";\nimport windowSize from \"../../../helpers/windowSize\";\nimport ButtonCorner from \"../../buttonCorner\";\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\nimport PopupCreateContact from \"../../popups/createContact\";\nimport SortedUserList from \"../../sortedUserList\";\nimport { getMiddleware } from \"../../../helpers/middleware\";\nimport replaceContent from \"../../../helpers/dom/replaceContent\";\nimport rootScope from \"../../../lib/rootScope\";\n\n// TODO: поиск по людям глобальный, если не нашло в контактах никого\n\nexport default class AppContactsTab extends SliderSuperTab {\n private inputSearch: InputSearch;\n private middleware: ReturnType<typeof getMiddleware>;\n private sortedUserList: SortedUserList;\n \n protected init() {\n this.container.id = 'contacts-container';\n\n // this.list = appDialogsManager.createChatList(/* {avatarSize: 48, handheldsSize: 66} */);\n\n const btnAdd = ButtonCorner({icon: 'add', className: 'is-visible'});\n this.content.append(btnAdd);\n\n attachClickEvent(btnAdd, () => {\n new PopupCreateContact();\n }, {listenerSetter: this.listenerSetter});\n\n this.inputSearch = new InputSearch('Search', (value) => {\n this.openContacts(value);\n });\n\n this.listenerSetter.add(rootScope)('contacts_update', (userId) => {\n const isContact = appUsersManager.isContact(userId);\n if(isContact) this.sortedUserList.add(userId);\n else this.sortedUserList.delete(userId);\n });\n\n this.title.replaceWith(this.inputSearch.container);\n\n this.middleware = getMiddleware();\n\n // preload contacts\n // appUsersManager.getContacts();\n }\n\n protected createList() {\n const sortedUserList = new SortedUserList();\n const list = sortedUserList.list;\n list.id = 'contacts';\n list.classList.add('contacts-container');\n appDialogsManager.setListClickListener(list, () => {\n this.close();\n }, undefined, true);\n return sortedUserList;\n }\n\n protected onClose() {\n this.middleware.clean();\n /* // need to clear, and left 1 page for smooth slide\n let pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;\n (Array.from(this.list.children) as HTMLElement[]).slice(pageCount).forEach(el => el.remove()); */\n }\n\n protected onOpenAfterTimeout() {\n if(IS_MOBILE || !canFocus(true)) return;\n this.inputSearch.input.focus();\n }\n\n public openContacts(query?: string) {\n if(this.init) {\n this.init();\n this.init = null;\n }\n\n this.middleware.clean();\n const middleware = this.middleware.get();\n this.scrollable.onScrolledBottom = null;\n this.scrollable.container.textContent = '';\n\n appUsersManager.getContacts(query, undefined, 'online').then(contacts => {\n if(!middleware()) {\n return;\n }\n\n const sortedUserList = this.sortedUserList = this.createList();\n\n let renderPage = () => {\n const pageCount = windowSize.windowH / 72 * 1.25 | 0;\n const arr = contacts.splice(0, pageCount); // надо splice!\n\n arr.forEach((peerId) => {\n sortedUserList.add(peerId);\n });\n\n if(!contacts.length) {\n renderPage = undefined;\n this.scrollable.onScrolledBottom = null;\n }\n };\n\n renderPage();\n this.scrollable.onScrolledBottom = () => {\n if(renderPage) {\n renderPage();\n } else {\n this.scrollable.onScrolledBottom = null;\n }\n };\n\n replaceContent(this.scrollable.container, sortedUserList.list);\n });\n }\n\n public open() {\n this.openContacts();\n return super.open();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\nimport { SliderSuperTab } from \"../../slider\";\n\nexport default class AppArchivedTab extends SliderSuperTab {\n private static filterId = 1;\n private wasFilterId: number;\n\n init() {\n this.container.id = 'chats-archived-container';\n this.setTitle('ArchivedChats');\n\n if(!appDialogsManager.sortedLists[AppArchivedTab.filterId]) {\n const chatList = appDialogsManager.createChatList();\n appDialogsManager.generateScrollable(chatList, AppArchivedTab.filterId).container.append(chatList);\n appDialogsManager.setListClickListener(chatList, null, true);\n //appDialogsManager.setListClickListener(archivedChatList, null, true); // * to test peer changing\n }\n\n const scrollable = appDialogsManager.scrollables[AppArchivedTab.filterId];\n this.scrollable.container.replaceWith(scrollable.container);\n this.scrollable = scrollable;\n }\n\n onOpen() {\n if(this.init) {\n this.init();\n this.init = null;\n }\n\n this.wasFilterId = appDialogsManager.filterId;\n appDialogsManager.setFilterId(AppArchivedTab.filterId);\n appDialogsManager.onTabChange();\n }\n\n // вообще, так делать нельзя, но нет времени чтобы переделать главный чатлист на слайд...\n onOpenAfterTimeout() {\n appDialogsManager.sortedLists[this.wasFilterId].clear();\n }\n\n onClose() {\n appDialogsManager.setFilterId(this.wasFilterId);\n appDialogsManager.onTabChange();\n }\n\n onCloseAfterTimeout() {\n appDialogsManager.sortedLists[AppArchivedTab.filterId].clear();\n return super.onCloseAfterTimeout();\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { formatNumber } from \"../../helpers/number\";\nimport appImManager from \"../../lib/appManagers/appImManager\";\nimport appStateManager from \"../../lib/appManagers/appStateManager\";\nimport appUsersManager from \"../../lib/appManagers/appUsersManager\";\nimport rootScope from \"../../lib/rootScope\";\nimport { SearchGroup } from \"../appSearch\";\nimport \"../avatar\";\nimport Scrollable, { ScrollableX } from \"../scrollable\";\nimport InputSearch from \"../inputSearch\";\nimport SidebarSlider from \"../slider\";\nimport { TransitionSlider } from \"../transition\";\nimport AppNewGroupTab from \"./tabs/newGroup\";\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport AppSearchSuper from \"../appSearchSuper.\";\nimport { DateData, fillTipDates } from \"../../helpers/date\";\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport AppSettingsTab from \"./tabs/settings\";\nimport AppNewChannelTab from \"./tabs/newChannel\";\nimport AppContactsTab from \"./tabs/contacts\";\nimport AppArchivedTab from \"./tabs/archivedTab\";\nimport AppAddMembersTab from \"./tabs/addMembers\";\nimport { i18n_, LangPackKey } from \"../../lib/langPack\";\nimport { ButtonMenuItemOptions } from \"../buttonMenu\";\nimport CheckboxField from \"../checkboxField\";\nimport { IS_MOBILE_SAFARI } from \"../../environment/userAgent\";\nimport appNavigationController from \"../appNavigationController\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport findUpTag from \"../../helpers/dom/findUpTag\";\nimport PeerTitle from \"../peerTitle\";\nimport App from \"../../config/app\";\nimport ButtonMenuToggle from \"../buttonMenuToggle\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport sessionStorage from \"../../lib/sessionStorage\";\nimport { CLICK_EVENT_NAME } from \"../../helpers/dom/clickEvent\";\nimport { closeBtnMenu } from \"../misc\";\n\nexport const LEFT_COLUMN_ACTIVE_CLASSNAME = 'is-left-column-shown';\n\nexport class AppSidebarLeft extends SidebarSlider {\n private toolsBtn: HTMLButtonElement;\n private backBtn: HTMLButtonElement;\n //private searchInput = document.getElementById('global-search') as HTMLInputElement;\n private inputSearch: InputSearch;\n \n public archivedCount: HTMLSpanElement;\n\n private newBtnMenu: HTMLElement;\n\n //private log = logger('SL');\n\n private searchGroups: {[k in 'contacts' | 'globalContacts' | 'messages' | 'people' | 'recent']: SearchGroup} = {} as any;\n private searchSuper: AppSearchSuper;\n\n constructor() {\n super({\n sidebarEl: document.getElementById('column-left') as HTMLDivElement,\n navigationType: 'left'\n });\n\n //this._selectTab(0); // make first tab as default\n\n this.inputSearch = new InputSearch('Search');\n const sidebarHeader = this.sidebarEl.querySelector('.item-main .sidebar-header');\n sidebarHeader.append(this.inputSearch.container);\n\n const onNewGroupClick = () => {\n new AppAddMembersTab(this).open({\n peerId: 0,\n type: 'chat',\n skippable: false,\n takeOut: (peerIds) => {\n new AppNewGroupTab(this).open(peerIds);\n },\n title: 'GroupAddMembers',\n placeholder: 'SendMessageTo'\n });\n };\n\n const onContactsClick = () => {\n new AppContactsTab(this).open();\n };\n\n //this.toolsBtn = this.sidebarEl.querySelector('.sidebar-tools-button') as HTMLButtonElement;\n this.backBtn = this.sidebarEl.querySelector('.sidebar-back-button') as HTMLButtonElement;\n\n const btnArchive: ButtonMenuItemOptions & {verify?: () => boolean} = {\n icon: 'archive',\n text: 'ArchivedChats',\n onClick: () => {\n new AppArchivedTab(this).open();\n },\n verify: () => {\n const folder = appMessagesManager.dialogsStorage.getFolder(1);\n return !!folder.length;\n }\n };\n\n const themeCheckboxField = new CheckboxField({\n toggle: true,\n checked: rootScope.getTheme().name === 'night'\n });\n themeCheckboxField.input.addEventListener('change', () => {\n rootScope.settings.theme = themeCheckboxField.input.checked ? 'night' : 'day';\n appStateManager.pushToState('settings', rootScope.settings);\n appImManager.applyCurrentTheme();\n });\n\n rootScope.addEventListener('theme_change', () => {\n themeCheckboxField.setValueSilently(rootScope.getTheme().name === 'night');\n });\n\n const menuButtons: (ButtonMenuItemOptions & {verify?: () => boolean})[] = [{\n icon: 'saved',\n text: 'SavedMessages',\n onClick: () => {\n setTimeout(() => { // menu doesn't close if no timeout (lol)\n appImManager.setPeer(appImManager.myId);\n }, 0);\n }\n }, btnArchive, {\n icon: 'user',\n text: 'Contacts',\n onClick: onContactsClick\n }, {\n icon: 'settings',\n text: 'Settings',\n onClick: () => {\n new AppSettingsTab(this).open();\n }\n }, {\n icon: 'darkmode',\n text: 'DarkMode',\n onClick: () => {\n \n },\n checkboxField: themeCheckboxField\n }, {\n icon: 'animations',\n text: 'Animations',\n onClick: () => {\n \n },\n checkboxField: new CheckboxField({\n toggle: true, \n checked: true,\n stateKey: 'settings.animationsEnabled',\n })\n }, {\n icon: 'help',\n text: 'TelegramFeatures',\n onClick: () => {\n appImManager.openUsername('TelegramTips');\n }\n }, {\n icon: 'bug',\n text: 'ReportBug',\n onClick: () => {\n const a = document.createElement('a');\n a.target = '_blank';\n a.href = 'https://bugs.telegram.org/?tag_ids=40&sort=time';\n document.body.append(a);\n a.click();\n setTimeout(() => {\n a.remove();\n }, 0);\n }\n }, {\n icon: 'char z',\n text: 'ChatList.Menu.SwitchTo.Z',\n onClick: () => {\n sessionStorage.set({kz_version: 'Z'}).then(() => {\n location.href = 'https://web.telegram.org/z/';\n });\n },\n verify: () => App.isMainDomain\n }, {\n icon: 'char w',\n text: 'ChatList.Menu.SwitchTo.Webogram',\n onClick: () => {\n location.href = 'https://web.telegram.org/?legacy=1';\n },\n verify: () => App.isMainDomain\n }];\n\n this.toolsBtn = ButtonMenuToggle({}, 'bottom-right', menuButtons, (e) => {\n menuButtons.forEach(button => {\n if(button.verify) {\n button.element.classList.toggle('hide', !button.verify());\n }\n });\n });\n this.toolsBtn.classList.remove('tgico-more');\n this.toolsBtn.classList.add('sidebar-tools-button', 'is-visible');\n\n this.backBtn.parentElement.insertBefore(this.toolsBtn, this.backBtn);\n\n const btnMenu = this.toolsBtn.querySelector('.btn-menu') as HTMLElement;\n\n const btnMenuFooter = document.createElement('a');\n btnMenuFooter.href = 'https://github.com/morethanwords/tweb/blob/master/CHANGELOG.md';\n btnMenuFooter.target = '_blank';\n btnMenuFooter.rel = 'noopener noreferrer';\n btnMenuFooter.classList.add('btn-menu-footer');\n btnMenuFooter.addEventListener(CLICK_EVENT_NAME, (e) => {\n e.stopPropagation();\n closeBtnMenu();\n });\n const t = document.createElement('span');\n t.classList.add('btn-menu-footer-text');\n t.innerHTML = 'Telegram Web' + App.suffix + ' alpha ' + App.versionFull;\n btnMenuFooter.append(t); \n btnMenu.classList.add('has-footer');\n btnMenu.append(btnMenuFooter);\n\n this.newBtnMenu = ButtonMenuToggle({}, 'top-left', [{\n icon: 'newchannel',\n text: 'NewChannel',\n onClick: () => {\n new AppNewChannelTab(this).open();\n }\n }, {\n icon: 'newgroup',\n text: 'NewGroup',\n onClick: onNewGroupClick\n }, {\n icon: 'newprivate',\n text: 'NewPrivateChat',\n onClick: onContactsClick\n }]);\n this.newBtnMenu.className = 'btn-circle rp btn-corner z-depth-1 btn-menu-toggle animated-button-icon';\n this.newBtnMenu.insertAdjacentHTML('afterbegin', `\n <span class=\"tgico tgico-newchat_filled\"></span>\n <span class=\"tgico tgico-close\"></span>\n `);\n this.newBtnMenu.id = 'new-menu';\n sidebarHeader.nextElementSibling.append(this.newBtnMenu);\n\n this.inputSearch.input.addEventListener('focus', () => this.initSearch(), {once: true});\n\n //parseMenuButtonsTo(this.newButtons, this.newBtnMenu.firstElementChild.children);\n\n this.archivedCount = document.createElement('span');\n this.archivedCount.className = 'archived-count badge badge-24 badge-gray';\n\n btnArchive.element.append(this.archivedCount);\n\n rootScope.addEventListener('dialogs_archived_unread', (e) => {\n this.archivedCount.innerText = '' + formatNumber(e.count, 1);\n this.archivedCount.classList.toggle('hide', !e.count);\n });\n\n appUsersManager.getTopPeers('correspondents');\n\n appStateManager.getState().then(state => {\n const recentSearch = state.recentSearch || [];\n for(let i = 0, length = recentSearch.length; i < length; ++i) {\n appStateManager.requestPeer(recentSearch[i], 'recentSearch');\n }\n });\n }\n\n private initSearch() {\n const searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement;\n\n const scrollable = new Scrollable(searchContainer);\n\n const close = () => {\n //setTimeout(() => {\n this.backBtn.click();\n //}, 0);\n };\n\n this.searchGroups = {\n contacts: new SearchGroup('Search.Chats', 'contacts', undefined, undefined, undefined, undefined, close),\n globalContacts: new SearchGroup('Search.Global', 'contacts', undefined, undefined, undefined, undefined, close),\n messages: new SearchGroup('Search.Messages', 'messages'),\n people: new SearchGroup(false, 'contacts', true, 'search-group-people', true, false, close),\n recent: new SearchGroup('Recent', 'contacts', true, 'search-group-recent', true, true, close)\n };\n\n const searchSuper = this.searchSuper = new AppSearchSuper({\n mediaTabs: [{\n inputFilter: 'inputMessagesFilterEmpty',\n name: 'FilterChats',\n type: 'chats'\n }, {\n inputFilter: 'inputMessagesFilterPhotoVideo',\n name: 'SharedMediaTab2',\n type: 'media'\n }, {\n inputFilter: 'inputMessagesFilterUrl',\n name: 'SharedLinksTab2',\n type: 'links'\n }, {\n inputFilter: 'inputMessagesFilterDocument',\n name: 'SharedFilesTab2',\n type: 'files'\n }, {\n inputFilter: 'inputMessagesFilterMusic',\n name: 'SharedMusicTab2',\n type: 'music'\n }, {\n inputFilter: 'inputMessagesFilterRoundVoice',\n name: 'SharedVoiceTab2',\n type: 'voice'\n }], \n scrollable, \n searchGroups: this.searchGroups, \n asChatList: true,\n hideEmptyTabs: false,\n showSender: true\n });\n\n searchContainer.prepend(searchSuper.nav.parentElement.parentElement);\n scrollable.container.append(searchSuper.container);\n\n const resetSearch = () => {\n searchSuper.setQuery({\n peerId: 0, \n folderId: 0\n });\n searchSuper.selectTab(0);\n searchSuper.load(true); \n };\n\n resetSearch();\n\n let pickedElements: HTMLElement[] = [];\n let selectedPeerId = 0;\n let selectedMinDate = 0;\n let selectedMaxDate = 0;\n const updatePicked = () => {\n //(this.inputSearch.input as HTMLInputElement).placeholder = pickedElements.length ? 'Search' : 'Telegram Search';\n this.inputSearch.container.classList.toggle('is-picked-twice', pickedElements.length === 2);\n this.inputSearch.container.classList.toggle('is-picked', !!pickedElements.length);\n\n if(pickedElements.length) {\n this.inputSearch.input.style.setProperty('--paddingLeft', (pickedElements[pickedElements.length - 1].getBoundingClientRect().right - this.inputSearch.input.getBoundingClientRect().left) + 'px');\n } else {\n this.inputSearch.input.style.removeProperty('--paddingLeft');\n }\n };\n\n const helper = document.createElement('div');\n helper.classList.add('search-helper');\n helper.addEventListener('click', (e) => {\n const target = findUpClassName(e.target, 'selector-user');\n if(!target) {\n return;\n }\n\n const key = target.dataset.key;\n if(key.indexOf('date_') === 0) {\n const [_, minDate, maxDate] = key.split('_');\n selectedMinDate = +minDate;\n selectedMaxDate = +maxDate;\n } else {\n selectedPeerId = +key;\n }\n\n target.addEventListener('click', () => {\n unselectEntity(target);\n });\n\n this.inputSearch.container.append(target);\n this.inputSearch.onChange(this.inputSearch.value = '');\n pickedElements.push(target);\n updatePicked();\n });\n\n searchSuper.nav.parentElement.append(helper);\n\n const renderEntity = (peerId: any, title?: string | HTMLElement) => {\n const div = document.createElement('div');\n div.classList.add('selector-user'/* , 'scale-in' */);\n\n const avatarEl = document.createElement('avatar-element');\n avatarEl.classList.add('selector-user-avatar', 'tgico');\n avatarEl.setAttribute('dialog', '1');\n avatarEl.classList.add('avatar-30');\n\n div.dataset.key = '' + peerId;\n if(typeof(peerId) === 'number') {\n if(title === undefined) {\n title = new PeerTitle({peerId}).element;\n }\n\n avatarEl.setAttribute('peer', '' + peerId);\n } else {\n avatarEl.classList.add('tgico-calendarfilter');\n }\n\n if(title) {\n if(typeof(title) === 'string') {\n div.innerHTML = title;\n } else {\n replaceContent(div, title);\n div.append(title);\n }\n }\n\n div.insertAdjacentElement('afterbegin', avatarEl);\n\n return div;\n };\n\n const unselectEntity = (target: HTMLElement) => {\n const key = target.dataset.key;\n if(key.indexOf('date_') === 0) {\n selectedMinDate = selectedMaxDate = 0;\n } else {\n selectedPeerId = 0;\n }\n \n target.remove();\n pickedElements.findAndSplice(t => t === target);\n\n setTimeout(() => {\n updatePicked();\n this.inputSearch.onChange(this.inputSearch.value);\n }, 0);\n };\n\n this.inputSearch.onClear = () => {\n pickedElements.forEach(el => {\n unselectEntity(el);\n });\n };\n\n this.inputSearch.onChange = (value) => {\n searchSuper.cleanupHTML();\n searchSuper.setQuery({\n peerId: selectedPeerId, \n folderId: selectedPeerId ? undefined : 0,\n query: value,\n minDate: selectedMinDate,\n maxDate: selectedMaxDate\n });\n searchSuper.load(true);\n\n helper.innerHTML = '';\n searchSuper.nav.classList.remove('hide');\n if(!value) {\n }\n \n if(!selectedPeerId && value.trim()) {\n const middleware = searchSuper.middleware.get();\n Promise.all([\n appMessagesManager.getConversationsAll(value).then(dialogs => dialogs.map(d => d.peerId)),\n appUsersManager.getContacts(value, true)\n ]).then(results => {\n if(!middleware()) return;\n const peerIds = new Set(results[0].concat(results[1]));\n \n peerIds.forEach(peerId => {\n helper.append(renderEntity(peerId));\n });\n \n searchSuper.nav.classList.toggle('hide', !!helper.innerHTML);\n //console.log('got peerIds by value:', value, [...peerIds]);\n });\n }\n \n if(!selectedMinDate && value.trim()) {\n const dates: DateData[] = [];\n fillTipDates(value, dates);\n dates.forEach(dateData => {\n helper.append(renderEntity('date_' + dateData.minDate + '_' + dateData.maxDate, dateData.title));\n });\n\n searchSuper.nav.classList.toggle('hide', !!helper.innerHTML);\n }\n };\n\n searchSuper.tabs.inputMessagesFilterEmpty.addEventListener('mousedown', (e) => {\n const target = findUpTag(e.target, 'LI') as HTMLElement;\n if(!target) {\n return;\n }\n\n const searchGroup = findUpClassName(target, 'search-group');\n if(!searchGroup || searchGroup.classList.contains('search-group-recent') || searchGroup.classList.contains('search-group-people')) {\n return;\n }\n\n const peerId = +target.getAttribute('data-peer-id');\n appStateManager.getState().then(state => {\n const recentSearch = state.recentSearch || [];\n if(recentSearch[0] !== peerId) {\n recentSearch.findAndSplice(p => p === peerId);\n recentSearch.unshift(peerId);\n if(recentSearch.length > 20) {\n recentSearch.length = 20;\n }\n \n appStateManager.pushToState('recentSearch', recentSearch);\n for(const peerId of recentSearch) {\n appStateManager.requestPeer(peerId, 'recentSearch');\n }\n }\n });\n }, {capture: true});\n\n let peopleContainer = document.createElement('div');\n peopleContainer.classList.add('search-group-scrollable');\n peopleContainer.append(this.searchGroups.people.list);\n this.searchGroups.people.container.append(peopleContainer);\n let peopleScrollable = new ScrollableX(peopleContainer);\n\n let first = true;\n let hideNewBtnMenuTimeout: number;\n //const transition = Transition.bind(null, searchContainer.parentElement, 150);\n const transition = TransitionSlider(searchContainer.parentElement, 'zoom-fade', 150, (id) => {\n if(hideNewBtnMenuTimeout) clearTimeout(hideNewBtnMenuTimeout);\n\n if(id === 0 && !first) {\n searchSuper.selectTab(0, false);\n this.inputSearch.onClearClick();\n hideNewBtnMenuTimeout = window.setTimeout(() => {\n hideNewBtnMenuTimeout = 0;\n this.newBtnMenu.classList.remove('is-hidden');\n }, 150);\n }\n\n first = false;\n });\n\n transition(0);\n\n const activeClassName = 'is-visible';\n const onFocus = () => {\n this.toolsBtn.classList.remove(activeClassName);\n this.backBtn.classList.add(activeClassName);\n this.newBtnMenu.classList.add('is-hidden');\n this.toolsBtn.parentElement.firstElementChild.classList.toggle('state-back', true);\n\n if(!IS_MOBILE_SAFARI && !appNavigationController.findItemByType('global-search')) {\n appNavigationController.pushItem({\n onPop: () => {\n close();\n },\n type: 'global-search'\n });\n }\n\n transition(1);\n };\n\n this.inputSearch.input.addEventListener('focus', onFocus);\n onFocus();\n\n this.backBtn.addEventListener('click', (e) => {\n this.toolsBtn.classList.add(activeClassName);\n this.backBtn.classList.remove(activeClassName);\n this.toolsBtn.parentElement.firstElementChild.classList.toggle('state-back', false);\n\n appNavigationController.removeByType('global-search');\n\n transition(0);\n });\n\n const clearRecentSearchBtn = document.createElement('button');\n clearRecentSearchBtn.classList.add('btn-icon', 'tgico-close');\n this.searchGroups.recent.nameEl.append(clearRecentSearchBtn);\n clearRecentSearchBtn.addEventListener('click', () => {\n this.searchGroups.recent.clear();\n appStateManager.pushToState('recentSearch', []);\n });\n }\n}\n\nexport class SettingSection {\n public container: HTMLElement;\n public content: HTMLElement;\n public title: HTMLElement;\n public caption: HTMLElement;\n\n constructor(options: {\n name?: LangPackKey, \n caption?: LangPackKey | true,\n noDelimiter?: boolean,\n fakeGradientDelimiter?: boolean\n }) {\n this.container = document.createElement('div');\n this.container.classList.add('sidebar-left-section');\n\n if(options.fakeGradientDelimiter) {\n this.container.append(generateDelimiter());\n this.container.classList.add('with-fake-delimiter');\n } else if(!options.noDelimiter) {\n const hr = document.createElement('hr');\n this.container.append(hr);\n } else {\n this.container.classList.add('no-delimiter');\n }\n\n this.content = this.generateContentElement();\n\n if(options.name) {\n this.title = document.createElement('div');\n this.title.classList.add('sidebar-left-h2', 'sidebar-left-section-name');\n i18n_({element: this.title, key: options.name});\n this.content.append(this.title);\n }\n\n if(options.caption) {\n this.caption = this.generateContentElement();\n this.caption.classList.add('sidebar-left-section-caption');\n\n if(options.caption !== true) {\n i18n_({element: this.caption, key: options.caption});\n }\n }\n }\n\n public generateContentElement() {\n const content = document.createElement('div');\n content.classList.add('sidebar-left-section-content');\n this.container.append(content);\n return content;\n }\n}\n\nexport const generateSection = (appendTo: Scrollable, name?: LangPackKey, caption?: LangPackKey) => {\n const section = new SettingSection({name, caption});\n appendTo.append(section.container);\n return section.content;\n};\n\nexport const generateDelimiter = () => {\n const delimiter = document.createElement('div');\n delimiter.classList.add('gradient-delimiter');\n return delimiter;\n};\n\nconst appSidebarLeft = new AppSidebarLeft();\nMOUNT_CLASS_TO.appSidebarLeft = appSidebarLeft;\nexport default appSidebarLeft;\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport rootScope from \"../../lib/rootScope\";\r\n//import { generatePathData } from \"../../helpers/dom\";\r\nimport { MyMessage } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type Chat from \"./chat\";\r\n\r\ntype Group = {bubble: HTMLElement, mid: number, timestamp: number}[];\r\ntype BubbleGroup = {timestamp: number, fromId: number, mid: number, group: Group};\r\nexport default class BubbleGroups {\r\n private bubbles: Array<BubbleGroup> = []; // map to group\r\n private detailsMap: Map<HTMLElement, BubbleGroup> = new Map();\r\n private groups: Array<Group> = [];\r\n //updateRAFs: Map<HTMLElement[], number> = new Map();\r\n private newGroupDiff = 121; // * 121 in scheduled messages\r\n\r\n constructor(private chat: Chat) {\r\n\r\n }\r\n\r\n removeBubble(bubble: HTMLElement) {\r\n const details = this.detailsMap.get(bubble);\r\n if(details) {\r\n if(details.group.length) {\r\n details.group.findAndSplice(d => d.bubble === bubble);\r\n if(!details.group.length) {\r\n this.groups.findAndSplice(g => g === details.group);\r\n } else {\r\n this.updateGroup(details.group);\r\n }\r\n }\r\n \r\n this.detailsMap.delete(bubble);\r\n }\r\n }\r\n \r\n addBubble(bubble: HTMLElement, message: MyMessage, reverse: boolean) {\r\n //return;\r\n\r\n const timestamp = message.date;\r\n const mid = message.mid;\r\n let fromId = message.viaBotId || message.fromId;\r\n let group: Group;\r\n\r\n // fix for saved messages forward to self\r\n if(fromId === rootScope.myId && message.peerId === rootScope.myId && (message as any).fwdFromId === fromId) {\r\n fromId = -fromId;\r\n }\r\n \r\n // try to find added\r\n this.removeBubble(bubble);\r\n \r\n const insertObject = {bubble, mid, timestamp};\r\n if(this.bubbles.length) {\r\n let foundBubble: BubbleGroup;\r\n let foundAtIndex = -1;\r\n for(let i = 0; i < this.bubbles.length; ++i) {\r\n const bubble = this.bubbles[i];\r\n const diff = Math.abs(bubble.timestamp - timestamp);\r\n const good = bubble.fromId === fromId && diff <= this.newGroupDiff;\r\n\r\n if(good) {\r\n foundAtIndex = i;\r\n\r\n if(this.chat.type === 'scheduled') {\r\n break;\r\n }\r\n } else {\r\n foundAtIndex = -1;\r\n }\r\n\r\n if(this.chat.type !== 'scheduled') {\r\n if(mid > bubble.mid) {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n if(foundAtIndex !== -1) {\r\n foundBubble = this.bubbles[foundAtIndex];\r\n }\r\n /* const foundBubble = this.bubbles.find(bubble => {\r\n const diff = Math.abs(bubble.timestamp - timestamp);\r\n return bubble.fromId === fromId && diff <= this.newGroupDiff;\r\n }); */\r\n\r\n if(!foundBubble) this.groups.push(group = [insertObject]);\r\n else {\r\n group = foundBubble.group;\r\n \r\n let i = 0, foundMidOnSameTimestamp = 0;\r\n for(; i < group.length; ++i) {\r\n const _timestamp = group[i].timestamp;\r\n const _mid = group[i].mid;\r\n\r\n if(timestamp < _timestamp) {\r\n break;\r\n } else if(timestamp === _timestamp) {\r\n foundMidOnSameTimestamp = _mid;\r\n } \r\n \r\n if(foundMidOnSameTimestamp && mid < foundMidOnSameTimestamp) {\r\n break;\r\n }\r\n }\r\n\r\n group.splice(i, 0, insertObject);\r\n }\r\n } else {\r\n this.groups.push(group = [insertObject]);\r\n }\r\n\r\n //console.log('[BUBBLE]: addBubble', bubble, message.mid, fromId, reverse, group);\r\n\r\n const bubbleGroup = {timestamp, fromId, mid: message.mid, group};\r\n let insertIndex = 0;\r\n for(; insertIndex < this.bubbles.length; ++insertIndex) {\r\n if(this.bubbles[insertIndex].mid < mid) {\r\n break;\r\n }\r\n }\r\n \r\n this.bubbles.splice(insertIndex, 0, {timestamp, fromId, mid: message.mid, group});\r\n this.updateGroup(group);\r\n\r\n this.detailsMap.set(bubble, bubbleGroup);\r\n }\r\n\r\n /* setClipIfNeeded(bubble: HTMLDivElement, remove = false) {\r\n //console.log('setClipIfNeeded', bubble, remove);\r\n const className = bubble.className;\r\n if(className.includes('is-message-empty') && (className.includes('photo') || className.includes('video'))) {\r\n let container = bubble.querySelector('.bubble__media-container') as SVGSVGElement;\r\n //console.log('setClipIfNeeded', bubble, remove, container);\r\n if(!container) return;\r\n\r\n try {\r\n Array.from(container.children).forEach(object => {\r\n if(object instanceof SVGDefsElement) return;\r\n \r\n if(remove) {\r\n object.removeAttributeNS(null, 'clip-path');\r\n } else {\r\n let clipId = container.dataset.clipId;\r\n let path = container.firstElementChild.firstElementChild.lastElementChild as SVGPathElement;\r\n let width = +object.getAttributeNS(null, 'width');\r\n let height = +object.getAttributeNS(null, 'height');\r\n let isOut = className.includes('is-out');\r\n let isReply = className.includes('is-reply');\r\n let d = '';\r\n \r\n //console.log('setClipIfNeeded', object, width, height, isOut);\r\n \r\n let tr: number, tl: number;\r\n if(className.includes('forwarded') || isReply) {\r\n tr = tl = 0;\r\n } else if(isOut) {\r\n tr = className.includes('is-group-first') ? 12 : 6;\r\n tl = 12;\r\n } else {\r\n tr = 12;\r\n tl = className.includes('is-group-first') ? 12 : 6;\r\n }\r\n \r\n if(isOut) {\r\n d = generatePathData(0, 0, width - 9, height, tl, tr, 0, 12);\r\n } else {\r\n d = generatePathData(9, 0, width - 9, height, tl, tr, 12, 0);\r\n }\r\n \r\n path.setAttributeNS(null, 'd', d);\r\n object.setAttributeNS(null, 'clip-path', 'url(#' + clipId + ')');\r\n }\r\n });\r\n } catch(err) {}\r\n }\r\n } */\r\n \r\n updateGroup(group: Group) {\r\n /* if(this.updateRAFs.has(group)) {\r\n window.cancelAnimationFrame(this.updateRAFs.get(group));\r\n this.updateRAFs.delete(group);\r\n } */\r\n \r\n //this.updateRAFs.set(group, window.requestAnimationFrame(() => {\r\n //this.updateRAFs.delete(group);\r\n \r\n if(!group.length) {\r\n return;\r\n }\r\n \r\n const first = group[0].bubble;\r\n\r\n //console.log('[BUBBLE]: updateGroup', group, first);\r\n \r\n if(group.length === 1) {\r\n first.classList.add('is-group-first', 'is-group-last');\r\n //this.setClipIfNeeded(first);\r\n return;\r\n } else {\r\n first.classList.remove('is-group-last');\r\n first.classList.add('is-group-first');\r\n //this.setClipIfNeeded(first, true);\r\n }\r\n \r\n const length = group.length - 1;\r\n for(let i = 1; i < length; ++i) {\r\n const bubble = group[i].bubble;\r\n bubble.classList.remove('is-group-last', 'is-group-first');\r\n //this.setClipIfNeeded(bubble, true);\r\n }\r\n \r\n const last = group[group.length - 1].bubble;\r\n last.classList.remove('is-group-first');\r\n last.classList.add('is-group-last');\r\n //this.setClipIfNeeded(last);\r\n //}));\r\n }\r\n\r\n updateGroupByMessageId(mid: number) {\r\n const details = this.bubbles.find(g => g.mid === mid);\r\n if(details) {\r\n this.updateGroup(details.group);\r\n }\r\n }\r\n \r\n cleanup() {\r\n this.bubbles = [];\r\n this.groups = [];\r\n this.detailsMap.clear();\r\n /* for(let value of this.updateRAFs.values()) {\r\n window.cancelAnimationFrame(value);\r\n }\r\n this.updateRAFs.clear(); */\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport PopupElement, { PopupOptions } from \".\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport I18n, { i18n, LangPackKey } from \"../../lib/langPack\";\r\nimport InputField from \"../inputField\";\r\n\r\nexport default class PopupDatePicker extends PopupElement {\r\n protected controlsDiv: HTMLElement;\r\n protected monthTitle: HTMLElement;\r\n protected prevBtn: HTMLElement;\r\n protected nextBtn: HTMLElement;\r\n\r\n protected monthsContainer: HTMLElement;\r\n protected month: HTMLElement;\r\n\r\n protected minMonth: Date;\r\n protected maxMonth: Date;\r\n protected minDate: Date;\r\n protected maxDate: Date;\r\n protected selectedDate: Date;\r\n protected selectedMonth: Date;\r\n protected selectedEl: HTMLElement;\r\n\r\n protected timeDiv: HTMLDivElement;\r\n protected hoursInputField: InputField;\r\n protected minutesInputField: InputField;\r\n\r\n constructor(initDate: Date, public onPick: (timestamp: number) => void, protected options: Partial<{\r\n noButtons: true, \r\n noTitle: true, \r\n minDate: Date,\r\n maxDate: Date\r\n withTime: true,\r\n showOverflowMonths: true\r\n }> & PopupOptions = {}) {\r\n super('popup-date-picker', options.noButtons ? [] : [{\r\n langKey: 'JumpToDate',\r\n callback: () => {\r\n if(this.onPick) {\r\n this.onPick(this.selectedDate.getTime() / 1000 | 0);\r\n }\r\n }\r\n }, {\r\n langKey: 'Cancel',\r\n isCancel: true\r\n }], {body: true, overlayClosable: true, ...options});\r\n\r\n this.minDate = options.minDate || new Date('2013-08-01T00:00:00');\r\n\r\n if(initDate < this.minDate) {\r\n initDate.setFullYear(this.minDate.getFullYear(), this.minDate.getMonth(), this.minDate.getDate());\r\n }\r\n\r\n // Controls\r\n this.controlsDiv = document.createElement('div');\r\n this.controlsDiv.classList.add('date-picker-controls');\r\n\r\n this.prevBtn = document.createElement('button');\r\n this.prevBtn.classList.add('btn-icon', 'tgico-down', 'date-picker-prev');\r\n attachClickEvent(this.prevBtn, this.onPrevClick, {listenerSetter: this.listenerSetter});\r\n\r\n this.nextBtn = document.createElement('button');\r\n this.nextBtn.classList.add('btn-icon', 'tgico-down', 'date-picker-next');\r\n attachClickEvent(this.nextBtn, this.onNextClick, {listenerSetter: this.listenerSetter});\r\n \r\n this.monthTitle = document.createElement('div');\r\n this.monthTitle.classList.add('date-picker-month-title');\r\n\r\n this.controlsDiv.append(this.prevBtn, this.monthTitle, this.nextBtn);\r\n\r\n // Month\r\n this.monthsContainer = document.createElement('div');\r\n this.monthsContainer.classList.add('date-picker-months');\r\n attachClickEvent(this.monthsContainer, this.onDateClick, {listenerSetter: this.listenerSetter});\r\n\r\n this.body.append(this.controlsDiv, this.monthsContainer);\r\n\r\n // Time inputs\r\n if(options.withTime) {\r\n this.timeDiv = document.createElement('div');\r\n this.timeDiv.classList.add('date-picker-time');\r\n\r\n const delimiter = document.createElement('div');\r\n delimiter.classList.add('date-picker-time-delimiter');\r\n delimiter.append(':');\r\n\r\n const handleTimeInput = (max: number, inputField: InputField, onInput: (length: number) => void, onOverflow?: (number: number) => void) => {\r\n const maxString = '' + max;\r\n this.listenerSetter.add(inputField.input)('input', (e) => {\r\n let value = inputField.value.replace(/\\D/g, '');\r\n if(value.length > 2) {\r\n value = value.slice(0, 2);\r\n } else {\r\n if((value.length === 1 && +value[0] > +maxString[0]) || (value.length === 2 && +value > max)) {\r\n if(value.length === 2 && onOverflow) {\r\n onOverflow(+value[1]);\r\n }\r\n\r\n value = '0' + value[0];\r\n }\r\n }\r\n\r\n inputField.setValueSilently(value);\r\n onInput(value.length);\r\n });\r\n };\r\n\r\n this.hoursInputField = new InputField({plainText: true});\r\n this.minutesInputField = new InputField({plainText: true});\r\n\r\n handleTimeInput(23, this.hoursInputField, (length) => {\r\n if(length === 2) {\r\n this.minutesInputField.input.focus();\r\n }\r\n\r\n this.setTimeTitle();\r\n }, (number) => {\r\n this.minutesInputField.value = (number + this.minutesInputField.value).slice(0, 2);\r\n });\r\n handleTimeInput(59, this.minutesInputField, (length) => {\r\n if(!length) {\r\n this.hoursInputField.input.focus();\r\n }\r\n\r\n this.setTimeTitle();\r\n });\r\n\r\n this.selectedDate = initDate;\r\n\r\n initDate.setMinutes(initDate.getMinutes() + 10);\r\n \r\n this.hoursInputField.setValueSilently(('0' + initDate.getHours()).slice(-2));\r\n this.minutesInputField.setValueSilently(('0' + initDate.getMinutes()).slice(-2));\r\n\r\n initDate.setHours(0, 0, 0, 0);\r\n \r\n this.timeDiv.append(this.hoursInputField.container, delimiter, this.minutesInputField.container);\r\n\r\n attachClickEvent(this.btnConfirm, () => {\r\n if(this.onPick) {\r\n this.selectedDate.setHours(+this.hoursInputField.value || 0, +this.minutesInputField.value || 0, 0, 0);\r\n this.onPick(this.selectedDate.getTime() / 1000 | 0);\r\n }\r\n\r\n this.hide();\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.body.append(this.timeDiv);\r\n\r\n this.prevBtn.classList.add('primary');\r\n this.nextBtn.classList.add('primary');\r\n }\r\n\r\n const popupCenterer = document.createElement('div');\r\n popupCenterer.classList.add('popup-centerer');\r\n popupCenterer.append(this.container);\r\n this.element.append(popupCenterer);\r\n\r\n //const passed = (initDate.getTime() - (initDate.getTimezoneOffset() * 60000)) % 86400000;\r\n //this.selectedDate = this.maxDate = new Date(initDate.getTime() - passed);\r\n initDate.setHours(0, 0, 0, 0);\r\n this.selectedDate = initDate;\r\n\r\n this.maxDate = options.maxDate || new Date();\r\n this.maxDate.setHours(0, 0, 0, 0);\r\n\r\n this.selectedMonth = new Date(this.selectedDate);\r\n this.selectedMonth.setDate(1);\r\n\r\n this.maxMonth = new Date(this.maxDate);\r\n this.maxMonth.setDate(1);\r\n\r\n this.minMonth = new Date(this.minDate);\r\n this.minMonth.setHours(0, 0, 0, 0);\r\n this.minMonth.setDate(1);\r\n\r\n if(this.selectedMonth.getTime() === this.minMonth.getTime()) {\r\n this.prevBtn.setAttribute('disabled', 'true');\r\n }\r\n\r\n if(this.selectedMonth.getTime() === this.maxMonth.getTime()) {\r\n this.nextBtn.setAttribute('disabled', 'true');\r\n }\r\n\r\n if(options.noTitle) {\r\n this.setTitle = () => {};\r\n }\r\n\r\n this.setTimeTitle();\r\n this.setTitle();\r\n this.setMonth();\r\n }\r\n\r\n onPrevClick = (e: MouseEvent) => {\r\n this.selectedMonth.setMonth(this.selectedMonth.getMonth() - 1);\r\n this.setMonth();\r\n\r\n if(this.selectedMonth.getTime() === this.minMonth.getTime()) {\r\n this.prevBtn.setAttribute('disabled', 'true');\r\n }\r\n \r\n this.nextBtn.removeAttribute('disabled');\r\n };\r\n\r\n onNextClick = (e: MouseEvent) => {\r\n this.selectedMonth.setMonth(this.selectedMonth.getMonth() + 1);\r\n this.setMonth();\r\n\r\n if(this.selectedMonth.getTime() === this.maxMonth.getTime()) {\r\n this.nextBtn.setAttribute('disabled', 'true');\r\n }\r\n\r\n this.prevBtn.removeAttribute('disabled');\r\n };\r\n\r\n onDateClick = (e: MouseEvent) => {\r\n //cancelEvent(e);\r\n const target = e.target as HTMLElement;\r\n\r\n if(!target.dataset.timestamp) return;\r\n\r\n if(this.selectedEl) {\r\n if(this.selectedEl === target) return;\r\n this.selectedEl.classList.remove('active');\r\n }\r\n\r\n this.selectedEl = target;\r\n \r\n target.classList.add('active');\r\n const timestamp = +target.dataset.timestamp;\r\n\r\n this.selectedDate = new Date(timestamp);\r\n\r\n this.setTitle();\r\n this.setTimeTitle();\r\n };\r\n\r\n public setTimeTitle() {\r\n if(this.btnConfirm && this.selectedDate) {\r\n let key: LangPackKey, args: any[] = [];\r\n const date = new Date();\r\n date.setHours(0, 0, 0, 0);\r\n\r\n const timeOptions: Intl.DateTimeFormatOptions = {\r\n minute: '2-digit',\r\n hour: '2-digit'\r\n };\r\n \r\n const sendDate = new Date(this.selectedDate.getTime());\r\n sendDate.setHours(+this.hoursInputField.value, +this.minutesInputField.value);\r\n\r\n if(this.selectedDate.getTime() === date.getTime()) {\r\n key = 'Schedule.SendToday';\r\n }/* else if(this.selectedDate.getTime() === (date.getTime() + 86400e3)) {\r\n dayStr = 'Tomorrow';\r\n } */ else {\r\n key = 'Schedule.SendDate';\r\n\r\n const dateOptions: Intl.DateTimeFormatOptions = {\r\n month: 'short',\r\n day: 'numeric'\r\n };\r\n\r\n if(sendDate.getFullYear() !== date.getFullYear()) {\r\n dateOptions.year = 'numeric';\r\n }\r\n\r\n args.push(new I18n.IntlDateElement({\r\n date: sendDate,\r\n options: dateOptions\r\n }).element);\r\n }\r\n\r\n args.push(new I18n.IntlDateElement({\r\n date: sendDate,\r\n options: timeOptions\r\n }).element);\r\n\r\n this.btnConfirm.firstChild.replaceWith(i18n(key, args));\r\n }\r\n }\r\n\r\n public setTitle() {\r\n //const splitted = this.selectedDate.toString().split(' ', 3);\r\n //this.title.innerText = splitted[0] + ', ' + splitted[1] + ' ' + splitted[2];\r\n this.title.textContent = '';\r\n this.title.append(new I18n.IntlDateElement({\r\n date: this.selectedDate,\r\n options: {\r\n day: 'numeric',\r\n month: 'long',\r\n weekday: 'short'\r\n }\r\n }).element);\r\n }\r\n\r\n private renderElement(disabled: boolean, innerText: string | HTMLElement = '') {\r\n const el = document.createElement('button');\r\n el.classList.add('btn-icon', 'date-picker-month-date');\r\n\r\n if(disabled) {\r\n el.setAttribute('disabled', 'true');\r\n }\r\n\r\n if(innerText) {\r\n el.append(innerText);\r\n }\r\n\r\n return el;\r\n }\r\n\r\n public setMonth() {\r\n const firstDate = new Date(this.selectedMonth);\r\n\r\n const options: Intl.DateTimeFormatOptions = {\r\n year: 'numeric',\r\n month: this.timeDiv && mediaSizes.isMobile ? 'short' : 'long'\r\n };\r\n\r\n this.monthTitle.textContent = '';\r\n this.monthTitle.append(new I18n.IntlDateElement({date: firstDate, options}).element);\r\n //this.monthTitle.innerText = (this.timeDiv && mediaSizes.isMobile ? monthName.slice(0, 3) : monthName) + ' ' + this.selectedMonth.getFullYear();\r\n\r\n if(this.month) {\r\n this.month.remove();\r\n }\r\n\r\n this.month = document.createElement('div');\r\n this.month.classList.add('date-picker-month');\r\n\r\n const weekStartDate = new Date();\r\n const day = weekStartDate.getDay();\r\n if(day !== 1) {\r\n weekStartDate.setHours(-24 * (day - 1)); \r\n }\r\n\r\n for(let i = 0; i < 7; ++i) {\r\n const el = this.renderElement(true, new I18n.IntlDateElement({date: weekStartDate, options: {weekday: 'narrow'}}).element);\r\n el.classList.remove('date-picker-month-date');\r\n el.classList.add('date-picker-month-day');\r\n this.month.append(el);\r\n weekStartDate.setDate(weekStartDate.getDate() + 1);\r\n }\r\n\r\n // 0 - sunday\r\n let dayIndex = firstDate.getDay() - 1;\r\n if(dayIndex === -1) dayIndex = 7 - 1;\r\n\r\n const clonedDate = new Date(firstDate.getTime());\r\n clonedDate.setDate(clonedDate.getDate() - dayIndex - 1);\r\n\r\n // Padding first week\r\n for(let i = 0; i < dayIndex; ++i) {\r\n if(this.options.showOverflowMonths) {\r\n clonedDate.setDate(clonedDate.getDate() + 1);\r\n this.month.append(this.renderElement(true, '' + clonedDate.getDate()));\r\n } else {\r\n this.month.append(this.renderElement(true));\r\n }\r\n }\r\n\r\n do {\r\n const date = firstDate.getDate();\r\n const el = this.renderElement(firstDate > this.maxDate || firstDate < this.minDate, '' + date);\r\n el.dataset.timestamp = '' + firstDate.getTime();\r\n\r\n if(firstDate.getTime() === this.selectedDate.getTime()) {\r\n this.selectedEl = el;\r\n el.classList.add('active');\r\n }\r\n\r\n this.month.append(el);\r\n\r\n firstDate.setDate(date + 1);\r\n } while(firstDate.getDate() !== 1);\r\n\r\n const remainder = this.month.childElementCount % 7;\r\n if(this.options.showOverflowMonths && remainder) {\r\n for(let i = remainder; i < 7; ++i) {\r\n this.month.append(this.renderElement(true, '' + firstDate.getDate()));\r\n firstDate.setDate(firstDate.getDate() + 1);\r\n }\r\n }\r\n\r\n const lines = Math.ceil(this.month.childElementCount / 7);\r\n this.container.dataset.lines = '' + lines;\r\n\r\n this.monthsContainer.append(this.month);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default class StickyIntersector {\r\n private headersObserver: IntersectionObserver;\r\n private elementsObserver: IntersectionObserver;\r\n\r\n constructor(private container: HTMLElement, private handler: (stuck: boolean, target: HTMLElement) => void) {\r\n this.observeHeaders();\r\n this.observeElements();\r\n }\r\n\r\n /**\r\n * Sets up an intersection observer to notify when elements with the class\r\n * `.sticky_sentinel--top` become visible/invisible at the top of the container.\r\n * @param {!Element} container\r\n */\r\n private observeHeaders() {\r\n this.headersObserver = new IntersectionObserver((entries) => {\r\n for(const entry of entries) {\r\n const targetInfo = entry.boundingClientRect;\r\n const stickyTarget = entry.target.parentElement;\r\n const rootBoundsInfo = entry.rootBounds;\r\n \r\n // Started sticking.\r\n if(targetInfo.bottom < rootBoundsInfo.top) {\r\n this.handler(true, stickyTarget);\r\n }\r\n \r\n // Stopped sticking.\r\n if(targetInfo.bottom >= rootBoundsInfo.top &&\r\n targetInfo.bottom < rootBoundsInfo.bottom) {\r\n this.handler(false, stickyTarget);\r\n }\r\n }\r\n }, {threshold: 0, root: this.container});\r\n }\r\n \r\n private observeElements() {\r\n this.elementsObserver = new IntersectionObserver((entries) => {\r\n let entry = entries.filter(entry => entry.boundingClientRect.top < 0).sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top)[0];\r\n if(!entry) return;\r\n let container = entry.isIntersecting ? entry.target : entry.target.nextElementSibling;\r\n this.handler(true, container as HTMLElement);\r\n }, {root: this.container});\r\n }\r\n\r\n /**\r\n * @param {!Element} container\r\n * @param {string} className\r\n */\r\n private addSentinel(container: HTMLElement, className: string) {\r\n const sentinel = document.createElement('div');\r\n sentinel.classList.add('sticky_sentinel', className);\r\n return container.appendChild(sentinel);\r\n }\r\n\r\n /**\r\n * Notifies when elements w/ the `sticky` class begin to stick or stop sticking.\r\n * Note: the elements should be children of `container`.\r\n * @param {!Element} container\r\n */\r\n public observeStickyHeaderChanges(element: HTMLElement) {\r\n const headerSentinel = this.addSentinel(element, 'sticky_sentinel--top');\r\n this.headersObserver.observe(headerSentinel);\r\n\r\n this.elementsObserver.observe(element);\r\n }\r\n\r\n public disconnect() {\r\n this.headersObserver.disconnect();\r\n this.elementsObserver.disconnect();\r\n }\r\n\r\n public unobserve(element: HTMLElement, headerSentinel: HTMLElement) {\r\n this.elementsObserver.unobserve(element);\r\n this.headersObserver.unobserve(headerSentinel);\r\n }\r\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { LazyLoadQueueIntersector } from \"../lazyLoadQueue\";\r\nimport { formatNumber } from \"../../helpers/number\";\r\nimport { Message } from \"../../layer\";\r\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager from \"../../lib/appManagers/appPeersManager\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport { ripple } from \"../ripple\";\r\nimport AvatarElement from \"../avatar\";\r\nimport { i18n } from \"../../lib/langPack\";\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\n\r\nconst TAG_NAME = 'replies-element';\r\n\r\nrootScope.addEventListener('replies_updated', (e) => {\r\n const message = e;\r\n (Array.from(document.querySelectorAll(TAG_NAME + `[data-post-key=\"${message.peerId}_${message.mid}\"]`)) as RepliesElement[]).forEach(element => {\r\n element.message = message;\r\n element.render();\r\n });\r\n});\r\n\r\nexport default class RepliesElement extends HTMLElement {\r\n public message: Message.message;\r\n public type: 'footer' | 'beside';\r\n public loadPromises: Promise<any>[];\r\n public lazyLoadQueue: LazyLoadQueueIntersector;\r\n \r\n private updated = false;\r\n\r\n constructor() {\r\n super();\r\n }\r\n\r\n public init() {\r\n this.render();\r\n this.dataset.postKey = this.message.peerId + '_' + this.message.mid;\r\n this.classList.add('replies', 'replies-' + this.type);\r\n }\r\n\r\n public render() {\r\n const replies = this.message.replies;\r\n\r\n /* if(this.firstChild) {\r\n this.innerHTML = '';\r\n } */\r\n\r\n if(this.type === 'footer') {\r\n let leftPart: HTMLElement;\r\n if(this.firstElementChild) {\r\n leftPart = this.firstElementChild as HTMLElement;\r\n }\r\n\r\n if(replies?.recent_repliers) {\r\n if(leftPart && !leftPart.classList.contains('replies-footer-avatars')) {\r\n this.innerHTML = '';\r\n leftPart = null;\r\n }\r\n\r\n if(!leftPart) {\r\n leftPart = document.createElement('div');\r\n leftPart.classList.add('replies-footer-avatars');\r\n }\r\n\r\n replies.recent_repliers.slice().reverse().forEach((peer, idx) => {\r\n let avatarElem = leftPart.children[idx] as AvatarElement;\r\n if(!avatarElem) {\r\n avatarElem = new AvatarElement();\r\n avatarElem.setAttribute('dialog', '0');\r\n avatarElem.classList.add('avatar-30');\r\n avatarElem.lazyLoadQueue = this.lazyLoadQueue;\r\n \r\n if(this.loadPromises) {\r\n avatarElem.loadPromises = this.loadPromises;\r\n }\r\n }\r\n \r\n avatarElem.setAttribute('peer', '' + appPeersManager.getPeerId(peer));\r\n \r\n if(!avatarElem.parentNode) {\r\n leftPart.append(avatarElem);\r\n }\r\n });\r\n\r\n // if were 3 and became 2\r\n (Array.from(leftPart.children) as HTMLElement[]).slice(replies.recent_repliers.length).forEach(el => el.remove());\r\n } else {\r\n if(leftPart && !leftPart.classList.contains('tgico-comments')) {\r\n leftPart.remove();\r\n leftPart = null;\r\n }\r\n\r\n if(!leftPart) {\r\n leftPart = document.createElement('span');\r\n leftPart.classList.add('tgico-comments');\r\n }\r\n }\r\n\r\n if(!leftPart.parentElement) {\r\n this.append(leftPart);\r\n }\r\n \r\n let text: HTMLElement;\r\n if(replies) {\r\n if(replies.replies) {\r\n text = i18n('Comments', [replies.replies]);\r\n } else {\r\n text = i18n('LeaveAComment');\r\n }\r\n } else {\r\n text = i18n('ViewInChat');\r\n }\r\n\r\n if(replies) {\r\n const historyStorage = appMessagesManager.getHistoryStorage(-replies.channel_id);\r\n let isUnread = false;\r\n if(replies.replies) {\r\n if(replies.read_max_id !== undefined && replies.max_id !== undefined) {\r\n isUnread = replies.read_max_id < replies.max_id;\r\n } else {\r\n isUnread = !historyStorage.readMaxId || historyStorage.readMaxId < (replies.max_id || 0);\r\n }\r\n }\r\n this.classList.toggle('is-unread', isUnread);\r\n }\r\n\r\n let textSpan = this.children[1] as HTMLElement;\r\n if(!textSpan) {\r\n textSpan = document.createElement('span');\r\n textSpan.classList.add('replies-footer-text');\r\n\r\n const iconSpan = document.createElement('span');\r\n iconSpan.classList.add('tgico-next');\r\n\r\n const rippleContainer = document.createElement('div');\r\n ripple(rippleContainer);\r\n\r\n this.append(textSpan, iconSpan, rippleContainer);\r\n }\r\n\r\n replaceContent(textSpan, text);\r\n } else {\r\n this.classList.add('bubble-beside-button');\r\n this.innerHTML = `<span class=\"tgico-commentssticker\"></span><span class=\"replies-beside-text\">${replies?.replies ? formatNumber(replies.replies, 0) : ''}</span>`;\r\n }\r\n\r\n if(replies && !this.updated && !this.message.pFlags.is_outgoing) {\r\n appMessagesManager.subscribeRepliesThread(this.message.peerId, this.message.mid);\r\n appMessagesManager.updateMessage(this.message.peerId, this.message.mid, 'replies_updated');\r\n this.updated = true;\r\n }\r\n\r\n if(this.loadPromises) {\r\n this.loadPromises = undefined;\r\n }\r\n }\r\n}\r\n\r\ncustomElements.define(TAG_NAME, RepliesElement);\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { getFullDate } from \"../../helpers/date\";\nimport { formatNumber } from \"../../helpers/number\";\nimport { i18n } from \"../../lib/langPack\";\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\nimport { LazyLoadQueueIntersector } from \"../lazyLoadQueue\";\nimport PeerTitle from \"../peerTitle\";\nimport { wrapReply } from \"../wrappers\";\nimport Chat from \"./chat\";\nimport RepliesElement from \"./replies\";\n\nexport namespace MessageRender {\n /* export const setText = () => {\n\n }; */\n\n export const setTime = (chat: Chat, message: any, bubble: HTMLElement, bubbleContainer: HTMLElement, messageDiv: HTMLElement) => {\n const date = new Date(message.date * 1000);\n let time = ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);\n\n if(message.views) {\n const postAuthor = message.post_author || message.fwd_from?.post_author;\n\n bubble.classList.add('channel-post');\n time = '<span class=\"post-views\">' + formatNumber(message.views, 1) + '</span> <i class=\"tgico-channelviews time-icon\"></i> ' + (postAuthor ? RichTextProcessor.wrapEmojiText(postAuthor) + ', ' : '') + time;\n \n if(!message.fwd_from?.saved_from_msg_id && chat.type !== 'pinned') {\n const forward = document.createElement('div');\n forward.classList.add('bubble-beside-button', 'forward');\n forward.innerHTML = `\n <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" preserveAspectRatio=\"xMidYMid meet\" viewBox=\"0 0 24 24\">\n <defs>\n <path d=\"M13.55 3.24L13.64 3.25L13.73 3.27L13.81 3.29L13.9 3.32L13.98 3.35L14.06 3.39L14.14 3.43L14.22 3.48L14.29 3.53L14.36 3.59L14.43 3.64L22.23 10.85L22.36 10.99L22.48 11.15L22.57 11.31L22.64 11.48L22.69 11.66L22.72 11.85L22.73 12.04L22.71 12.22L22.67 12.41L22.61 12.59L22.53 12.76L22.42 12.93L22.29 13.09L22.23 13.15L14.43 20.36L14.28 20.48L14.12 20.58L13.95 20.66L13.77 20.72L13.58 20.76L13.4 20.77L13.22 20.76L13.03 20.73L12.85 20.68L12.68 20.61L12.52 20.52L12.36 20.4L12.22 20.27L12.16 20.2L12.1 20.13L12.05 20.05L12.01 19.98L11.96 19.9L11.93 19.82L11.89 19.73L11.87 19.65L11.84 19.56L11.83 19.47L11.81 19.39L11.81 19.3L11.8 19.2L11.8 16.42L11 16.49L10.23 16.58L9.51 16.71L8.82 16.88L8.18 17.09L7.57 17.33L7.01 17.6L6.48 17.91L5.99 18.26L5.55 18.64L5.14 19.05L4.77 19.51L4.43 19.99L4.29 20.23L4.21 20.35L4.11 20.47L4 20.57L3.88 20.65L3.75 20.72L3.62 20.78L3.48 20.82L3.33 20.84L3.19 20.84L3.04 20.83L2.9 20.79L2.75 20.74L2.62 20.68L2.53 20.62L2.45 20.56L2.38 20.5L2.31 20.43L2.25 20.36L2.2 20.28L2.15 20.19L2.11 20.11L2.07 20.02L2.04 19.92L2.02 19.83L2.01 19.73L2 19.63L2.04 17.99L2.19 16.46L2.46 15.05L2.85 13.75L3.35 12.58L3.97 11.53L4.7 10.6L5.55 9.8L6.51 9.12L7.59 8.56L8.77 8.13L10.07 7.83L11.48 7.65L11.8 7.63L11.8 4.8L11.91 4.56L12.02 4.35L12.14 4.16L12.25 3.98L12.37 3.82L12.48 3.68L12.61 3.56L12.73 3.46L12.85 3.38L12.98 3.31L13.11 3.27L13.24 3.24L13.37 3.23L13.46 3.23L13.55 3.24Z\" id=\"b13RmHDQtl\"></path>\n </defs>\n <use xlink:href=\"#b13RmHDQtl\" opacity=\"1\" fill=\"#fff\" fill-opacity=\"1\"></use>\n </svg>`;\n bubbleContainer.append(forward);\n bubble.classList.add('with-beside-button');\n }\n }\n\n if(message.edit_date && chat.type !== 'scheduled' && !message.pFlags.edit_hide) {\n bubble.classList.add('is-edited');\n time = '<i class=\"edited\">edited</i> ' + time;\n }\n\n if(chat.type !== 'pinned' && message.pFlags.pinned) {\n bubble.classList.add('is-pinned');\n time = '<i class=\"tgico-pinnedchat time-icon\"></i>' + time;\n }\n\n const title = getFullDate(date) \n + (message.edit_date ? `\\nEdited: ${getFullDate(new Date(message.edit_date * 1000))}` : '')\n + (message.fwd_from ? `\\nOriginal: ${getFullDate(new Date(message.fwd_from.date * 1000))}` : '');\n\n const timeSpan = document.createElement('span');\n timeSpan.classList.add('time', 'tgico');\n timeSpan.title = title;\n timeSpan.innerHTML = `${time}<div class=\"inner tgico\" title=\"${title}\">${time}</div>`;\n\n messageDiv.append(timeSpan);\n\n return timeSpan;\n };\n\n export const renderReplies = ({bubble, bubbleContainer, message, messageDiv, loadPromises, lazyLoadQueue}: {\n bubble: HTMLElement,\n bubbleContainer: HTMLElement,\n message: any,\n messageDiv: HTMLElement,\n loadPromises?: Promise<any>[],\n lazyLoadQueue?: LazyLoadQueueIntersector\n }) => {\n const isFooter = !bubble.classList.contains('sticker') && !bubble.classList.contains('emoji-big') && !bubble.classList.contains('round');\n const repliesFooter = new RepliesElement();\n repliesFooter.message = message;\n repliesFooter.type = isFooter ? 'footer' : 'beside';\n repliesFooter.loadPromises = loadPromises;\n repliesFooter.lazyLoadQueue = lazyLoadQueue;\n repliesFooter.init();\n bubbleContainer.prepend(repliesFooter);\n return isFooter;\n };\n\n export const setReply = ({chat, bubble, bubbleContainer, message}: {\n chat: Chat,\n bubble: HTMLElement,\n bubbleContainer?: HTMLElement,\n message: any\n }) => {\n const isReplacing = !bubbleContainer;\n if(isReplacing) {\n bubbleContainer = bubble.querySelector('.bubble-content');\n }\n\n const currentReplyDiv = isReplacing ? bubbleContainer.querySelector('.reply') : null;\n if(!message.reply_to_mid) {\n if(currentReplyDiv) {\n currentReplyDiv.remove();\n }\n\n bubble.classList.remove('is-reply');\n return;\n }\n\n\n const replyToPeerId = message.reply_to.reply_to_peer_id ? chat.appPeersManager.getPeerId(message.reply_to.reply_to_peer_id) : chat.peerId;\n\n let originalMessage = chat.appMessagesManager.getMessageByPeer(replyToPeerId, message.reply_to_mid);\n let originalPeerTitle: string | HTMLElement;\n \n /////////this.log('message to render reply', originalMessage, originalPeerTitle, bubble, message);\n \n // need to download separately\n if(originalMessage._ === 'messageEmpty') {\n //////////this.log('message to render reply empty, need download', message, message.reply_to_mid);\n chat.appMessagesManager.wrapSingleMessage(replyToPeerId, message.reply_to_mid);\n chat.bubbles.needUpdate.push({replyToPeerId, replyMid: message.reply_to_mid, mid: message.mid});\n \n originalPeerTitle = i18n('Loading');\n } else {\n originalPeerTitle = new PeerTitle({\n peerId: originalMessage.fromId || originalMessage.fwdFromId,\n dialog: false,\n onlyFirstName: false,\n plainText: false\n }).element;\n }\n\n const wrapped = wrapReply(originalPeerTitle, undefined, originalMessage);\n if(currentReplyDiv) {\n currentReplyDiv.replaceWith(wrapped);\n } else {\n bubbleContainer.append(wrapped);\n }\n //bubbleContainer.insertBefore(, nameContainer);\n bubble.classList.add('is-reply');\n };\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\n\r\nexport function getElementByPoint(container: HTMLElement, verticalSide: 'top' | 'bottom', horizontalSide: 'center' | 'left'): HTMLElement {\r\n //return null;\r\n const rect = container.getBoundingClientRect();\r\n const x = horizontalSide === 'center' ? Math.ceil(rect.left + ((rect.right - rect.left) / 2) + 1) : Math.ceil(rect.left + 1);\r\n const y = verticalSide === 'bottom' ? Math.floor(rect.top + rect.height - 1) : Math.ceil(rect.top + 1);\r\n return document.elementFromPoint(x, y) as any;\r\n};\r\n\r\nMOUNT_CLASS_TO.getElementByPoint = getElementByPoint;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function reflowScrollableElement(element: HTMLElement) {\r\n element.style.display = 'none';\r\n void element.offsetLeft; // reflow\r\n element.style.display = '';\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport App from \"../../config/app\";\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport { validateInitObject } from \"../../helpers/object\";\nimport I18n from \"../langPack\";\nimport { isObject } from \"../mtproto/bin_utils\";\nimport apiManager from \"../mtproto/mtprotoworker\";\nimport RichTextProcessor from \"../richtextprocessor\";\nimport rootScope from \"../rootScope\";\nimport SearchIndex from \"../searchIndex\";\nimport stateStorage from \"../stateStorage\";\nimport appStateManager from \"./appStateManager\";\n\ntype EmojiLangPack = {\n keywords: {\n [keyword: string]: string[],\n },\n version: number,\n langCode: string\n};\n\nconst EMOJI_LANG_PACK: EmojiLangPack = {\n keywords: {},\n version: 0,\n langCode: App.langPackCode\n};\n\nconst RECENT_MAX_LENGTH = 36;\n\nexport class AppEmojiManager {\n private static POPULAR_EMOJI = [\"😂\", \"😘\", \"❤️\", \"😍\", \"😊\", \"😁\", \"👍\", \"☺️\", \"😔\", \"😄\", \"😭\", \"💋\", \"😒\", \"😳\", \"😜\", \"🙈\", \"😉\", \"😃\", \"😢\", \"😝\", \"😱\", \"😡\", \"😏\", \"😞\", \"😅\", \"😚\", \"🙊\", \"😌\", \"😀\", \"😋\", \"😆\", \"👌\", \"😐\", \"😕\"];\n private keywordLangPacks: {\n [langCode: string]: EmojiLangPack\n } = {};\n\n private index: SearchIndex<EmojiLangPack['keywords'][keyof EmojiLangPack['keywords']]>;\n private indexedLangPacks: {[langCode: string]: boolean} = {};\n\n private getKeywordsPromises: {[langCode: string]: Promise<EmojiLangPack>} = {};\n\n private recent: string[];\n private getRecentEmojisPromise: Promise<AppEmojiManager['recent']>;\n\n /* public getPopularEmoji() {\n return stateStorage.get('emojis_popular').then(popEmojis => {\n var result = []\n if (popEmojis && popEmojis.length) {\n for (var i = 0, len = popEmojis.length; i < len; i++) {\n result.push({code: popEmojis[i][0], rate: popEmojis[i][1]})\n }\n callback(result)\n return\n }\n\n return stateStorage.get('emojis_recent').then(recentEmojis => {\n recentEmojis = recentEmojis || popular || []\n var shortcut\n var code\n for (var i = 0, len = recentEmojis.length; i < len; i++) {\n shortcut = recentEmojis[i]\n if (Array.isArray(shortcut)) {\n shortcut = shortcut[0]\n }\n if (shortcut && typeof shortcut === 'string') {\n if (shortcut.charAt(0) == ':') {\n shortcut = shortcut.substr(1, shortcut.length - 2)\n }\n if (code = shortcuts[shortcut]) {\n result.push({code: code, rate: 1})\n }\n }\n }\n callback(result)\n });\n });\n }\n\n function pushPopularEmoji (code) {\n getPopularEmoji(function (popularEmoji) {\n var exists = false\n var count = popularEmoji.length\n var result = []\n for (var i = 0; i < count; i++) {\n if (popularEmoji[i].code == code) {\n exists = true\n popularEmoji[i].rate++\n }\n result.push([popularEmoji[i].code, popularEmoji[i].rate])\n }\n if (exists) {\n result.sort(function (a, b) {\n return b[1] - a[1]\n })\n } else {\n if (result.length > 41) {\n result = result.slice(0, 41)\n }\n result.push([code, 1])\n }\n ConfigStorage.set({emojis_popular: result})\n })\n } */\n\n public getEmojiKeywords(langCode: string = App.langPackCode) {\n const promise = this.getKeywordsPromises[langCode];\n if(promise) {\n return promise;\n }\n\n const storageKey: any = 'emojiKeywords_' + langCode;\n return this.getKeywordsPromises[langCode] = stateStorage.get(storageKey).then((pack: EmojiLangPack) => {\n if(!isObject(pack)) {\n pack = {} as any;\n }\n\n validateInitObject(EMOJI_LANG_PACK, pack);\n\n // important\n pack.langCode = langCode;\n this.keywordLangPacks[langCode] = pack;\n\n return apiManager.invokeApi('messages.getEmojiKeywordsDifference', {\n lang_code: pack.langCode,\n from_version: pack.version\n }).then((keywordsDifference) => {\n pack.version = keywordsDifference.version;\n \n const packKeywords = pack.keywords;\n const keywords = keywordsDifference.keywords;\n for(let i = 0, length = keywords.length; i < length; ++i) {\n const {keyword, emoticons} = keywords[i];\n packKeywords[keyword] = emoticons;\n }\n\n stateStorage.set({\n [storageKey]: pack\n });\n\n return pack;\n }, () => {\n return pack;\n });\n });\n }\n\n public getBothEmojiKeywords() {\n const promises: Promise<any>[] = [\n this.getEmojiKeywords()\n ];\n\n if(I18n.lastRequestedLangCode !== App.langPackCode) {\n promises.push(this.getEmojiKeywords(I18n.lastRequestedLangCode));\n }\n\n if(!this.recent) {\n promises.push(this.getRecentEmojis());\n }\n\n return Promise.all(promises);\n }\n\n public indexEmojis() {\n if(!this.index) {\n this.index = new SearchIndex(undefined, 2);\n }\n\n for(const langCode in this.keywordLangPacks) {\n if(this.indexedLangPacks[langCode]) {\n continue;\n }\n\n const pack = this.keywordLangPacks[langCode];\n const keywords = pack.keywords;\n\n for(const keyword in keywords) {\n const emoticons = keywords[keyword];\n this.index.indexObject(emoticons, keyword);\n }\n\n this.indexedLangPacks[langCode] = true;\n }\n }\n\n public searchEmojis(q: string) {\n this.indexEmojis();\n\n q = q.toLowerCase().replace(/_/g, ' ');\n \n //const perf = performance.now();\n let emojis: Array<string>;\n if(q.trim()) {\n const set = this.index.search(q);\n emojis = Array.from(set).reduce((acc, v) => acc.concat(v), []);\n } else {\n emojis = this.recent.concat(AppEmojiManager.POPULAR_EMOJI).slice(0, RECENT_MAX_LENGTH);\n }\n\n emojis = Array.from(new Set(emojis));\n //console.log('searchEmojis', q, 'time', performance.now() - perf);\n\n /* for(let i = 0, length = emojis.length; i < length; ++i) {\n if(emojis[i].includes(zeroWidthJoiner) && !emojis[i].includes('\\ufe0f')) {\n emojis[i] += '\\ufe0f';\n }\n } */\n\n return emojis;\n }\n\n public getRecentEmojis() {\n if(this.getRecentEmojisPromise) return this.getRecentEmojisPromise;\n return this.getRecentEmojisPromise = appStateManager.getState().then(state => {\n return this.recent = Array.isArray(state.recentEmoji) ? state.recentEmoji : [];\n });\n }\n\n public pushRecentEmoji(emoji: string) {\n emoji = RichTextProcessor.fixEmoji(emoji);\n this.getRecentEmojis().then(recent => {\n recent.findAndSplice(e => e === emoji);\n recent.unshift(emoji);\n if(recent.length > RECENT_MAX_LENGTH) {\n recent.length = RECENT_MAX_LENGTH;\n }\n\n appStateManager.pushToState('recentEmoji', recent);\n rootScope.dispatchEvent('emoji_recent', emoji);\n });\n }\n}\n\nconst appEmojiManager = new AppEmojiManager();\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appEmojiManager = appEmojiManager);\nexport default appEmojiManager;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport emoticonsDropdown, { EmoticonsDropdown, EmoticonsTab } from \"..\";\nimport { cancelEvent } from \"../../../helpers/dom/cancelEvent\";\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\nimport { fastRaf } from \"../../../helpers/schedulers\";\nimport { pause } from \"../../../helpers/schedulers/pause\";\nimport { IS_TOUCH_SUPPORTED } from \"../../../environment/touchSupport\";\nimport appEmojiManager from \"../../../lib/appManagers/appEmojiManager\";\nimport appImManager from \"../../../lib/appManagers/appImManager\";\nimport Config from \"../../../lib/config\";\nimport { i18n, LangPackKey } from \"../../../lib/langPack\";\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\nimport rootScope from \"../../../lib/rootScope\";\nimport { emojiFromCodePoints } from \"../../../vendor/emoji\";\nimport { putPreloader } from \"../../misc\";\nimport Scrollable from \"../../scrollable\";\nimport StickyIntersector from \"../../stickyIntersector\";\nimport IS_EMOJI_SUPPORTED from \"../../../environment/emojiSupport\";\n\nconst loadedURLs: Set<string> = new Set();\nexport function appendEmoji(emoji: string, container: HTMLElement, prepend = false, unify = false) {\n //const emoji = details.unified;\n //const emoji = (details.unified as string).split('-')\n //.reduce((prev, curr) => prev + String.fromCodePoint(parseInt(curr, 16)), '');\n\n const spanEmoji = document.createElement('span');\n spanEmoji.classList.add('super-emoji');\n\n let kek: string;\n if(unify && !IS_EMOJI_SUPPORTED) {\n kek = RichTextProcessor.wrapSingleEmoji(emoji);\n } else {\n emoji = RichTextProcessor.fixEmoji(emoji);\n kek = RichTextProcessor.wrapEmojiText(emoji);\n }\n\n /* if(!kek.includes('emoji')) {\n console.log(emoji, kek, spanEmoji, emoji.length, new TextEncoder().encode(emoji), emojiUnicode(emoji));\n return;\n } */\n\n //console.log(kek);\n\n spanEmoji.innerHTML = kek;\n\n if(spanEmoji.children.length > 1) {\n const first = spanEmoji.firstElementChild;\n spanEmoji.innerHTML = '';\n spanEmoji.append(first);\n }\n\n if(spanEmoji.firstElementChild && !IS_EMOJI_SUPPORTED) {\n const image = spanEmoji.firstElementChild as HTMLImageElement;\n \n const url = image.src;\n if(!loadedURLs.has(url)) {\n image.setAttribute('loading', 'lazy');\n const placeholder = document.createElement('span');\n placeholder.classList.add('emoji-placeholder');\n\n if(rootScope.settings.animationsEnabled) {\n image.style.opacity = '0';\n placeholder.style.opacity = '1';\n }\n\n image.addEventListener('load', () => {\n fastRaf(() => {\n if(rootScope.settings.animationsEnabled) {\n image.style.opacity = '';\n placeholder.style.opacity = '';\n }\n\n spanEmoji.classList.remove('empty');\n\n loadedURLs.add(url);\n });\n }, {once: true});\n\n spanEmoji.append(placeholder);\n }\n }\n\n //spanEmoji = spanEmoji.firstElementChild as HTMLSpanElement;\n //spanEmoji.setAttribute('emoji', emoji);\n if(prepend) container.prepend(spanEmoji);\n else container.appendChild(spanEmoji);\n}\n\nexport function getEmojiFromElement(element: HTMLElement) {\n if(!findUpClassName(element, 'super-emoji')) return '';\n\n if(element.nodeType === 3) return element.nodeValue;\n if(element.tagName === 'SPAN' && !element.classList.contains('emoji') && element.firstElementChild) {\n element = element.firstElementChild as HTMLElement;\n }\n \n return element.getAttribute('alt') || element.innerText;\n}\n\nexport default class EmojiTab implements EmoticonsTab {\n private content: HTMLElement;\n\n private recentItemsDiv: HTMLElement;\n\n private scroll: Scrollable;\n private stickyIntersector: StickyIntersector;\n private menu: HTMLElement;\n\n private closeScrollTop = 0;\n private setMenuActive: (id: number) => boolean;\n\n init() {\n this.content = document.getElementById('content-emoji') as HTMLDivElement;\n\n const categories: LangPackKey[] = [\n 'Emoji.SmilesAndPeople', \n 'Emoji.AnimalsAndNature', \n 'Emoji.FoodAndDrink', \n 'Emoji.TravelAndPlaces', \n 'Emoji.ActivityAndSport', \n 'Emoji.Objects', \n /* 'Emoji.Symbols', */\n 'Emoji.Flags', \n 'Skin Tones' as any\n ];\n const divs: {\n [category in LangPackKey]?: HTMLDivElement\n } = {};\n\n const sorted: Map<LangPackKey, string[]> = new Map([\n [\n 'Emoji.Recent',\n []\n ]\n ]);\n\n for(const emoji in Config.Emoji) {\n const details = Config.Emoji[emoji];\n const i = '' + details;\n const category = categories[+i[0] - 1];\n if(!category) continue; // maybe it's skin tones\n\n let s = sorted.get(category);\n if(!s) {\n s = [];\n sorted.set(category, s);\n }\n \n s[+i.slice(1) || 0] = emoji;\n }\n\n //console.log('emoticons sorted:', sorted);\n\n //Object.keys(sorted).forEach(c => sorted[c].sort((a, b) => a - b));\n\n sorted.delete(categories.pop());\n\n //console.time('emojiParse');\n sorted.forEach((emojis, category) => {\n const div = document.createElement('div');\n div.classList.add('emoji-category');\n\n const titleDiv = document.createElement('div');\n titleDiv.classList.add('category-title');\n titleDiv.append(i18n(category));\n\n const itemsDiv = document.createElement('div');\n itemsDiv.classList.add('super-emojis');\n\n div.append(titleDiv, itemsDiv);\n\n emojis.forEach(unified => {\n /* if(emojiUnicode(emoji) === '1f481-200d-2642') {\n console.log('append emoji', emoji, emojiUnicode(emoji));\n } */\n\n let emoji = emojiFromCodePoints(unified);\n //if(emoji.includes('🕵')) {\n //console.log('toCodePoints', toCodePoints(emoji));\n //emoji = emoji.replace(/(\\u200d[\\u2640\\u2642\\u2695])(?!\\ufe0f)/, '\\ufe0f$1');\n // const zwjIndex = emoji.indexOf('\\u200d');\n // if(zwjIndex !== -1 && !emoji.includes('\\ufe0f')) {\n // /* if(zwjIndex !== (emoji.length - 1)) {\n // emoji = emoji.replace(/(\\u200d)/g, '\\ufe0f$1');\n // } */\n\n // emoji += '\\ufe0f';\n // //emoji += '\\ufe0f';\n // }\n\n //debugger;\n //}\n\n appendEmoji(emoji/* .replace(/[\\ufe0f\\u2640\\u2642\\u2695]/g, '') */, itemsDiv, false/* , false */);\n\n /* if(category === 'Smileys & Emotion') {\n console.log('appended emoji', emoji, itemsDiv.children[itemsDiv.childElementCount - 1].innerHTML, emojiUnicode(emoji));\n } */\n });\n\n divs[category] = div;\n });\n\n //console.timeEnd('emojiParse');\n\n const menu = this.menu = this.content.previousElementSibling as HTMLElement;\n const emojiScroll = this.scroll = new Scrollable(this.content, 'EMOJI');\n\n //emojiScroll.setVirtualContainer(emojiScroll.container);\n\n const preloader = putPreloader(this.content, true);\n\n Promise.all([\n pause(200),\n appEmojiManager.getRecentEmojis().then(recent => {\n const hasRecent = !!recent.length;\n const activeId = hasRecent ? 0 : 1;\n this.menu.children[0].classList.toggle('hide', !hasRecent);\n this.menu.children[activeId].classList.add('active');\n const m = EmoticonsDropdown.menuOnClick(menu, emojiScroll, undefined, activeId);\n this.stickyIntersector = m.stickyIntersector;\n this.setMenuActive = m.setActive;\n return recent;\n })\n ]).then(([_, recent]) => {\n preloader.remove();\n\n this.recentItemsDiv = divs['Emoji.Recent'].querySelector('.super-emojis');\n for(const emoji of recent) {\n appendEmoji(emoji, this.recentItemsDiv);\n }\n\n this.recentItemsDiv.parentElement.classList.toggle('hide', !this.recentItemsDiv.childElementCount);\n\n categories.unshift('Emoji.Recent');\n categories.map(category => {\n const div = divs[category];\n \n if(!div) {\n console.error('no div by category:', category);\n }\n \n emojiScroll.container.append(div);\n this.stickyIntersector.observeStickyHeaderChanges(div);\n return div;\n });\n });\n\n this.content.addEventListener('click', this.onContentClick);\n this.init = null;\n\n rootScope.addEventListener('emoji_recent', (emoji) => {\n const children = Array.from(this.recentItemsDiv.children) as HTMLElement[];\n for(let i = 0, length = children.length; i < length; ++i) {\n const el = children[i];\n const _emoji = RichTextProcessor.fixEmoji(getEmojiFromElement(el));\n if(emoji === _emoji) {\n if(i === 0) {\n return;\n }\n\n el.remove();\n }\n }\n\n appendEmoji(emoji, this.recentItemsDiv, true);\n this.recentItemsDiv.parentElement.classList.remove('hide');\n this.menu.children[0].classList.remove('hide');\n\n if(!this.closeScrollTop) {\n this.setMenuActive(0);\n }\n });\n\n emoticonsDropdown.addEventListener('close', () => {\n this.closeScrollTop = this.scroll.scrollTop;\n });\n }\n\n onContentClick = (e: MouseEvent) => {\n cancelEvent(e);\n \n const emoji = getEmojiFromElement(e.target as HTMLElement);\n if(!emoji) {\n return;\n }\n\n const messageInput = appImManager.chat.input.messageInput;\n let inputHTML = messageInput.innerHTML;\n\n const html = RichTextProcessor.wrapEmojiText(emoji, true);\n let inserted = false;\n if(window.getSelection) {\n const savedRange = IS_TOUCH_SUPPORTED ? undefined : emoticonsDropdown.getSavedRange();\n let sel = window.getSelection();\n if(savedRange) {\n sel.removeAllRanges();\n sel.addRange(savedRange);\n }\n\n if(sel.getRangeAt && sel.rangeCount) {\n var el = document.createElement('div');\n el.innerHTML = html;\n var node = el.firstChild;\n var range = sel.getRangeAt(0);\n range.deleteContents();\n //range.insertNode(document.createTextNode(' '));\n range.insertNode(node);\n range.setStart(node, 0);\n inserted = true;\n \n setTimeout(() => {\n range = document.createRange();\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n }, 0);\n }\n }\n\n if(!inserted || messageInput.innerHTML === inputHTML) {\n messageInput.insertAdjacentHTML('beforeend', html);\n }\n \n // Append to input\n const event = new Event('input', {bubbles: true, cancelable: true});\n messageInput.dispatchEvent(event);\n };\n\n onClose() {\n\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appDocsManager, {MyDocument} from \"../lib/appManagers/appDocsManager\";\r\nimport { wrapVideo } from \"./wrappers\";\r\nimport { LazyLoadQueueRepeat2 } from \"./lazyLoadQueue\";\r\nimport animationIntersector from \"./animationIntersector\";\r\nimport Scrollable from \"./scrollable\";\r\nimport { CancellablePromise, deferredPromise } from \"../helpers/cancellablePromise\";\r\nimport renderImageFromUrl from \"../helpers/dom/renderImageFromUrl\";\r\nimport calcImageInBox from \"../helpers/calcImageInBox\";\r\nimport { doubleRaf } from \"../helpers/schedulers\";\r\n\r\nconst width = 400;\r\nconst maxSingleWidth = width - 100;\r\nconst height = 100;\r\n\r\nexport default class GifsMasonry {\r\n public lazyLoadQueue: LazyLoadQueueRepeat2;\r\n private scrollPromise: CancellablePromise<void> = Promise.resolve();\r\n private timeout: number = 0;\r\n\r\n constructor(private element: HTMLElement, private group: string, private scrollable: Scrollable, attach = true) {\r\n this.lazyLoadQueue = new LazyLoadQueueRepeat2(undefined, (target, visible) => {\r\n if(visible) {\r\n this.processVisibleDiv(target);\r\n } else {\r\n this.processInvisibleDiv(target);\r\n }\r\n });\r\n\r\n /* setInterval(() => {\r\n // @ts-ignore\r\n const players = animationIntersector.byGroups[group];\r\n\r\n if(players) {\r\n console.log(`GIFS RENDERED IN ${group}:`, players.length, players.filter(p => !p.animation.paused).length, this.lazyLoadQueue.intersector.getVisible().length);\r\n }\r\n }, .25e3); */\r\n\r\n if(attach) {\r\n this.attach();\r\n }\r\n }\r\n \r\n private onScroll = () => {\r\n if(this.timeout) {\r\n clearTimeout(this.timeout);\r\n } else {\r\n this.scrollPromise = deferredPromise<void>();\r\n //animationIntersector.checkAnimations(true, group);\r\n }\r\n\r\n this.timeout = window.setTimeout(() => {\r\n this.timeout = 0;\r\n this.scrollPromise.resolve();\r\n //animationIntersector.checkAnimations(false, group);\r\n }, 150);\r\n };\r\n\r\n public attach() {\r\n this.scrollable.container.addEventListener('scroll', this.onScroll);\r\n }\r\n\r\n public detach() {\r\n this.clear();\r\n this.scrollable.container.removeEventListener('scroll', this.onScroll);\r\n }\r\n\r\n public clear() {\r\n this.lazyLoadQueue.clear();\r\n }\r\n\r\n private processVisibleDiv(div: HTMLElement) {\r\n const video = div.querySelector('video');\r\n if(video) {\r\n return;\r\n }\r\n\r\n //console.log('processVisibleDiv');\r\n\r\n const load = () => {\r\n const docId = div.dataset.docId;\r\n const doc = appDocsManager.getDoc(docId);\r\n\r\n const promise = this.scrollPromise.then(() => {\r\n const res = wrapVideo({\r\n doc,\r\n container: div as HTMLDivElement,\r\n lazyLoadQueue: null,\r\n //lazyLoadQueue: EmoticonsDropdown.lazyLoadQueue,\r\n group: this.group,\r\n noInfo: true,\r\n });\r\n \r\n const promise = res.loadPromise;\r\n promise.finally(() => {\r\n const video = div.querySelector('video');\r\n\r\n div.style.opacity = '';\r\n const img = div.querySelector('img');\r\n img && img.classList.add('hide');\r\n\r\n if(video && !video.parentElement) {\r\n setTimeout(() => {\r\n video.src = '';\r\n video.load();\r\n const animations = animationIntersector.getAnimations(video);\r\n animations.forEach(item => {\r\n animationIntersector.checkAnimation(item, true, true);\r\n });\r\n }, 0);\r\n }\r\n\r\n //clearTimeout(timeout);\r\n if(!this.lazyLoadQueue.intersector.isVisible(div)) {\r\n this.processInvisibleDiv(div);\r\n }\r\n });\r\n\r\n return promise;\r\n });\r\n\r\n /* let timeout = window.setTimeout(() => {\r\n console.error('processVisibleDiv timeout', div, doc);\r\n }, 1e3); */\r\n\r\n return promise;\r\n };\r\n\r\n //return load();\r\n \r\n this.lazyLoadQueue.push({div, load});\r\n }\r\n\r\n public processInvisibleDiv = (div: HTMLElement) => {\r\n return this.scrollPromise.then(async() => {\r\n //return;\r\n\r\n if(this.lazyLoadQueue.intersector.isVisible(div)) {\r\n return;\r\n }\r\n\r\n const video = div.querySelector('video');\r\n const img = div.querySelector('img');\r\n \r\n if(img) {\r\n img && img.classList.remove('hide');\r\n \r\n await doubleRaf();\r\n }\r\n\r\n if(this.lazyLoadQueue.intersector.isVisible(div)) {\r\n return;\r\n }\r\n \r\n if(video) {\r\n video.remove();\r\n video.src = '';\r\n video.load();\r\n const animations = animationIntersector.getAnimations(video);\r\n animations.forEach(item => {\r\n animationIntersector.checkAnimation(item, true, true);\r\n });\r\n }\r\n });\r\n };\r\n\r\n public add(doc: MyDocument, appendTo = this.element) {\r\n let gifWidth = doc.w;\r\n let gifHeight = doc.h;\r\n if(gifHeight < height) {\r\n gifWidth = height / gifHeight * gifWidth;\r\n gifHeight = height;\r\n }\r\n\r\n const willUseWidth = Math.min(maxSingleWidth, width, gifWidth);\r\n const size = calcImageInBox(gifWidth, gifHeight, willUseWidth, height);\r\n\r\n /* wastedWidth += w;\r\n\r\n if(wastedWidth === width || h < height) {\r\n wastedWidth = 0;\r\n console.log('completed line', i, line);\r\n line = [];\r\n continue;\r\n }\r\n\r\n line.push(gif); */\r\n\r\n //console.log('gif:', gif, w, h);\r\n\r\n const div = document.createElement('div');\r\n div.classList.add('gif', 'fade-in-transition');\r\n div.style.width = size.width + 'px';\r\n div.style.opacity = '0';\r\n //div.style.height = h + 'px';\r\n div.dataset.docId = doc.id;\r\n\r\n appendTo.append(div);\r\n\r\n //this.lazyLoadQueue.observe({div, load: this.processVisibleDiv});\r\n this.lazyLoadQueue.observe(div);\r\n\r\n //let preloader = new ProgressivePreloader(div);\r\n\r\n const gotThumb = appDocsManager.getThumb(doc, false);\r\n\r\n const willBeAPoster = !!gotThumb;\r\n let img: HTMLImageElement;\r\n if(willBeAPoster) {\r\n img = new Image();\r\n img.classList.add('media-poster');\r\n\r\n if(!gotThumb.cacheContext.url) {\r\n gotThumb.promise.then(() => {\r\n img.src = gotThumb.cacheContext.url;\r\n });\r\n }\r\n }\r\n\r\n const afterRender = () => {\r\n if(img) {\r\n div.append(img);\r\n div.style.opacity = '';\r\n }\r\n };\r\n\r\n (gotThumb?.cacheContext?.url ? renderImageFromUrl(img, gotThumb.cacheContext.url, afterRender) : afterRender());\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport emoticonsDropdown, { EmoticonsDropdown, EmoticonsTab, EMOTICONSSTICKERGROUP } from \"..\";\r\nimport GifsMasonry from \"../../gifsMasonry\";\r\nimport Scrollable from \"../../scrollable\";\r\nimport { putPreloader } from \"../../misc\";\r\nimport apiManager from \"../../../lib/mtproto/mtprotoworker\";\r\nimport appDocsManager, {MyDocument} from \"../../../lib/appManagers/appDocsManager\";\r\n\r\nexport default class GifsTab implements EmoticonsTab {\r\n private content: HTMLElement;\r\n\r\n init() {\r\n this.content = document.getElementById('content-gifs');\r\n const gifsContainer = this.content.firstElementChild as HTMLDivElement;\r\n gifsContainer.addEventListener('click', EmoticonsDropdown.onMediaClick);\r\n\r\n const scroll = new Scrollable(this.content, 'GIFS');\r\n const masonry = new GifsMasonry(gifsContainer, EMOTICONSSTICKERGROUP, scroll);\r\n const preloader = putPreloader(this.content, true);\r\n\r\n apiManager.invokeApi('messages.getSavedGifs', {hash: 0}).then((res) => {\r\n //console.log('getSavedGifs res:', res);\r\n\r\n if(res._ === 'messages.savedGifs') {\r\n res.gifs.forEach((doc, idx) => {\r\n res.gifs[idx] = doc = appDocsManager.saveDoc(doc);\r\n //if(doc._ === 'documentEmpty') return;\r\n masonry.add(doc as MyDocument);\r\n });\r\n }\r\n\r\n preloader.remove();\r\n });\r\n\r\n emoticonsDropdown.addLazyLoadQueueRepeat(masonry.lazyLoadQueue, masonry.processInvisibleDiv);\r\n\r\n this.init = null;\r\n }\r\n\r\n onClose() {\r\n\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport emoticonsDropdown, { EmoticonsDropdown, EMOTICONSSTICKERGROUP, EmoticonsTab } from \"..\";\r\nimport findUpAttribute from \"../../../helpers/dom/findUpAttribute\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport mediaSizes from \"../../../helpers/mediaSizes\";\r\nimport { MessagesAllStickers, StickerSet } from \"../../../layer\";\r\nimport appDocsManager, { MyDocument } from \"../../../lib/appManagers/appDocsManager\";\r\nimport appStickersManager from \"../../../lib/appManagers/appStickersManager\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport animationIntersector from \"../../animationIntersector\";\r\nimport LazyLoadQueue, { LazyLoadQueueRepeat } from \"../../lazyLoadQueue\";\r\nimport { putPreloader } from \"../../misc\";\r\nimport PopupStickers from \"../../popups/stickers\";\r\nimport Scrollable, { ScrollableX } from \"../../scrollable\";\r\nimport StickyIntersector from \"../../stickyIntersector\";\r\nimport { wrapSticker, wrapStickerSetThumb } from \"../../wrappers\";\r\n\r\nexport class SuperStickerRenderer {\r\n public lazyLoadQueue: LazyLoadQueueRepeat;\r\n private animatedDivs: Set<HTMLDivElement> = new Set();\r\n\r\n constructor(private regularLazyLoadQueue: LazyLoadQueue, private group: string) {\r\n this.lazyLoadQueue = new LazyLoadQueueRepeat(undefined, (target, visible) => {\r\n if(!visible) {\r\n this.processInvisibleDiv(target as HTMLDivElement);\r\n }\r\n });\r\n }\r\n\r\n public clear() {\r\n this.lazyLoadQueue.clear();\r\n }\r\n\r\n public renderSticker(doc: MyDocument, div?: HTMLDivElement, loadPromises?: Promise<any>[]) {\r\n if(!div) {\r\n div = document.createElement('div');\r\n div.classList.add('grid-item', 'super-sticker');\r\n\r\n if(doc.sticker === 2) {\r\n this.observeAnimatedDiv(div);\r\n }\r\n }\r\n\r\n // * This will wrap only a thumb\r\n wrapSticker({\r\n doc, \r\n div,\r\n lazyLoadQueue: this.regularLazyLoadQueue, \r\n group: this.group, \r\n onlyThumb: doc.sticker === 2,\r\n loadPromises\r\n });\r\n\r\n return div;\r\n }\r\n\r\n public observeAnimatedDiv(div: HTMLDivElement) {\r\n this.animatedDivs.add(div);\r\n\r\n this.lazyLoadQueue.observe({\r\n div, \r\n load: this.processVisibleDiv\r\n });\r\n }\r\n\r\n private checkAnimationContainer = (div: HTMLElement, visible: boolean) => {\r\n //console.error('checkAnimationContainer', div, visible);\r\n const players = animationIntersector.getAnimations(div);\r\n players.forEach(player => {\r\n if(!visible) {\r\n animationIntersector.checkAnimation(player, true, true);\r\n } else {\r\n animationIntersector.checkAnimation(player, false);\r\n }\r\n });\r\n };\r\n\r\n private processVisibleDiv = (div: HTMLElement) => {\r\n const docId = div.dataset.docId;\r\n const doc = appDocsManager.getDoc(docId);\r\n \r\n const size = mediaSizes.active.esgSticker.width;\r\n\r\n //console.log('processVisibleDiv:', div);\r\n\r\n const promise = wrapSticker({\r\n doc, \r\n div: div as HTMLDivElement,\r\n width: size,\r\n height: size,\r\n lazyLoadQueue: null, \r\n group: this.group, \r\n onlyThumb: false,\r\n play: true,\r\n loop: true\r\n });\r\n\r\n promise.then(() => {\r\n //clearTimeout(timeout);\r\n this.checkAnimationContainer(div, this.lazyLoadQueue.intersector.isVisible(div));\r\n });\r\n\r\n /* let timeout = window.setTimeout(() => {\r\n console.error('processVisibleDiv timeout', div, doc);\r\n }, 1e3); */\r\n\r\n return promise;\r\n };\r\n\r\n public processInvisibleDiv = (div: HTMLElement) => {\r\n const docId = div.dataset.docId;\r\n const doc = appDocsManager.getDoc(docId);\r\n\r\n //console.log('STICKER INvisible:', /* div, */docId);\r\n\r\n this.checkAnimationContainer(div, false);\r\n\r\n div.innerHTML = '';\r\n this.renderSticker(doc, div as HTMLDivElement);\r\n };\r\n}\r\n\r\nexport default class StickersTab implements EmoticonsTab {\r\n private content: HTMLElement;\r\n private stickersDiv: HTMLElement;\r\n\r\n private stickerSets: {[id: string]: {\r\n stickers: HTMLElement,\r\n tab: HTMLElement\r\n }} = {};\r\n\r\n private recentDiv: HTMLElement;\r\n private recentStickers: MyDocument[] = [];\r\n\r\n private scroll: Scrollable;\r\n\r\n private menu: HTMLElement;\r\n \r\n private mounted = false;\r\n\r\n private queueCategoryPush: {element: HTMLElement, prepend: boolean}[] = [];\r\n\r\n private stickyIntersector: StickyIntersector;\r\n\r\n private superStickerRenderer: SuperStickerRenderer;\r\n\r\n categoryPush(categoryDiv: HTMLElement, categoryTitle: string = '', promise: Promise<MyDocument[]>, prepend?: boolean) {\r\n //if((docs.length % 5) !== 0) categoryDiv.classList.add('not-full');\r\n\r\n const itemsDiv = document.createElement('div');\r\n itemsDiv.classList.add('category-items', 'super-stickers');\r\n\r\n const titleDiv = document.createElement('div');\r\n titleDiv.classList.add('category-title');\r\n\r\n if(categoryTitle) {\r\n titleDiv.innerHTML = categoryTitle;\r\n }\r\n\r\n categoryDiv.append(titleDiv, itemsDiv);\r\n\r\n this.stickyIntersector.observeStickyHeaderChanges(categoryDiv);\r\n\r\n this.queueCategoryPush.push({element: categoryDiv, prepend});\r\n\r\n promise.then(documents => {\r\n documents.forEach(doc => {\r\n //if(doc._ === 'documentEmpty') return;\r\n itemsDiv.append(this.superStickerRenderer.renderSticker(doc));\r\n });\r\n\r\n if(this.queueCategoryPush.length) {\r\n this.queueCategoryPush.forEach(({element, prepend}) => {\r\n if(prepend) {\r\n if(this.recentDiv.parentElement) {\r\n this.stickersDiv.prepend(element);\r\n this.stickersDiv.prepend(this.recentDiv);\r\n } else {\r\n this.stickersDiv.prepend(element);\r\n }\r\n } else this.stickersDiv.append(element);\r\n });\r\n\r\n this.queueCategoryPush.length = 0;\r\n }\r\n });\r\n\r\n return {titleDiv};\r\n }\r\n\r\n async renderStickerSet(set: StickerSet.stickerSet, prepend = false) {\r\n const categoryDiv = document.createElement('div');\r\n categoryDiv.classList.add('sticker-category');\r\n categoryDiv.dataset.id = set.id;\r\n categoryDiv.dataset.access_hash = set.access_hash;\r\n\r\n const button = document.createElement('button');\r\n button.classList.add('btn-icon', 'menu-horizontal-div-item');\r\n\r\n this.stickerSets[set.id] = {\r\n stickers: categoryDiv,\r\n tab: button\r\n };\r\n\r\n if(prepend) {\r\n this.menu.insertBefore(button, this.menu.firstElementChild.nextSibling);\r\n } else {\r\n this.menu.append(button);\r\n }\r\n\r\n //stickersScroll.append(categoryDiv);\r\n\r\n const promise = appStickersManager.getStickerSet(set);\r\n this.categoryPush(categoryDiv, RichTextProcessor.wrapEmojiText(set.title), promise.then(stickerSet => stickerSet.documents as MyDocument[]), prepend);\r\n const stickerSet = await promise;\r\n\r\n //console.log('got stickerSet', stickerSet, li);\r\n \r\n wrapStickerSetThumb({\r\n set,\r\n container: button,\r\n group: EMOTICONSSTICKERGROUP,\r\n lazyLoadQueue: EmoticonsDropdown.lazyLoadQueue,\r\n width: 32,\r\n height: 32,\r\n autoplay: false\r\n });\r\n }\r\n\r\n init() {\r\n this.content = document.getElementById('content-stickers');\r\n //let stickersDiv = contentStickersDiv.querySelector('.os-content') as HTMLDivElement;\r\n\r\n this.recentDiv = document.createElement('div');\r\n this.recentDiv.classList.add('sticker-category', 'stickers-recent');\r\n\r\n let menuWrapper = this.content.previousElementSibling as HTMLDivElement;\r\n this.menu = menuWrapper.firstElementChild as HTMLUListElement;\r\n\r\n let menuScroll = new ScrollableX(menuWrapper);\r\n\r\n this.stickersDiv = document.createElement('div');\r\n this.stickersDiv.classList.add('stickers-categories');\r\n this.content.append(this.stickersDiv);\r\n\r\n /* stickersDiv.addEventListener('mouseover', (e) => {\r\n let target = e.target as HTMLElement;\r\n\r\n if(target.tagName === 'CANVAS') { // turn on sticker\r\n let animation = lottieLoader.getAnimation(target.parentElement, EMOTICONSSTICKERGROUP);\r\n\r\n if(animation) {\r\n // @ts-ignore\r\n if(animation.currentFrame === animation.totalFrames - 1) {\r\n animation.goToAndPlay(0, true);\r\n } else {\r\n animation.play();\r\n }\r\n }\r\n }\r\n }); */\r\n\r\n rootScope.addEventListener('stickers_installed', (e) => {\r\n const set: StickerSet.stickerSet = e;\r\n \r\n if(!this.stickerSets[set.id] && this.mounted) {\r\n this.renderStickerSet(set, true);\r\n }\r\n });\r\n\r\n rootScope.addEventListener('stickers_deleted', (e) => {\r\n const set: StickerSet.stickerSet = e;\r\n \r\n if(this.stickerSets[set.id] && this.mounted) {\r\n const elements = this.stickerSets[set.id];\r\n elements.stickers.remove();\r\n elements.tab.remove();\r\n delete this.stickerSets[set.id];\r\n }\r\n });\r\n\r\n this.stickersDiv.addEventListener('click', (e) => {\r\n const target = e.target as HTMLElement;\r\n if(findUpClassName(target, 'category-title')) {\r\n const el = findUpAttribute(target, 'data-id');\r\n new PopupStickers({id: el.dataset.id, access_hash: el.dataset.access_hash}).show();\r\n return;\r\n }\r\n\r\n EmoticonsDropdown.onMediaClick(e);\r\n });\r\n\r\n this.scroll = new Scrollable(this.content, 'STICKERS');\r\n this.scroll.setVirtualContainer(this.stickersDiv);\r\n\r\n this.stickyIntersector = EmoticonsDropdown.menuOnClick(this.menu, this.scroll, menuScroll).stickyIntersector;\r\n\r\n const preloader = putPreloader(this.content, true);\r\n\r\n Promise.all([\r\n appStickersManager.getRecentStickers().then(stickers => {\r\n this.recentStickers = stickers.stickers.slice(0, 20) as MyDocument[];\r\n \r\n //stickersScroll.prepend(categoryDiv);\r\n\r\n this.stickerSets['recent'] = {\r\n stickers: this.recentDiv,\r\n tab: this.menu.firstElementChild as HTMLElement\r\n };\r\n\r\n preloader.remove();\r\n const {titleDiv} = this.categoryPush(this.recentDiv, '', Promise.resolve(this.recentStickers), true);\r\n titleDiv.append(i18n('Stickers.Recent'));\r\n }),\r\n\r\n appStickersManager.getAllStickers().then((res) => {\r\n preloader.remove();\r\n\r\n for(let set of (res as MessagesAllStickers.messagesAllStickers).sets) {\r\n this.renderStickerSet(set);\r\n }\r\n })\r\n ]).finally(() => {\r\n this.mounted = true;\r\n });\r\n\r\n this.superStickerRenderer = new SuperStickerRenderer(EmoticonsDropdown.lazyLoadQueue, EMOTICONSSTICKERGROUP);\r\n\r\n emoticonsDropdown.addLazyLoadQueueRepeat(this.superStickerRenderer.lazyLoadQueue, this.superStickerRenderer.processInvisibleDiv);\r\n\r\n /* setInterval(() => {\r\n // @ts-ignore\r\n const players = Object.values(lottieLoader.players).filter(p => p.width === 80);\r\n \r\n console.log('STICKERS RENDERED IN PANEL:', players.length, players.filter(p => !p.paused).length, this.superStickerRenderer.lazyLoadQueue.intersector.getVisible().length);\r\n }, .25e3); */\r\n \r\n\r\n this.init = null;\r\n }\r\n\r\n pushRecentSticker(doc: MyDocument) {\r\n if(!this.recentDiv?.parentElement) {\r\n return;\r\n }\r\n\r\n let div = this.recentDiv.querySelector(`[data-doc-id=\"${doc.id}\"]`);\r\n if(!div) {\r\n div = this.superStickerRenderer.renderSticker(doc);\r\n }\r\n\r\n const items = this.recentDiv.querySelector('.category-items');\r\n items.prepend(div);\r\n\r\n if(items.childElementCount > 20) {\r\n (Array.from(items.children) as HTMLElement[]).slice(20).forEach(el => el.remove());\r\n }\r\n }\r\n\r\n onClose() {\r\n\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport { toast } from \"../../components/toast\";\r\nimport { BotInlineResult, GeoPoint, InputGeoPoint, InputMedia, MessageEntity, ReplyMarkup } from \"../../layer\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport apiManagerProxy from \"../mtproto/mtprotoworker\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport appDocsManager, { MyDocument } from \"./appDocsManager\";\r\nimport appPhotosManager, { MyPhoto } from \"./appPhotosManager\";\r\nimport appUsersManager, { MyTopPeer } from \"./appUsersManager\";\r\nimport appMessagesManager from \"./appMessagesManager\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport rootScope from \"../rootScope\";\r\nimport appDraftsManager from \"./appDraftsManager\";\r\nimport appMessagesIdsManager from \"./appMessagesIdsManager\";\r\nimport { insertInDescendSortedArray } from \"../../helpers/array\";\r\nimport appStateManager from \"./appStateManager\";\r\n\r\nexport class AppInlineBotsManager {\r\n private inlineResults: {[queryAndResultIds: string]: BotInlineResult} = {};\r\n private setHash: {\r\n [botId: string]: {\r\n peerId: number, \r\n time: number\r\n }\r\n } = {};\r\n\r\n public getGeoInput(geo: GeoPoint): InputGeoPoint {\r\n return geo._ === 'geoPoint' ? {\r\n _: 'inputGeoPoint',\r\n lat: geo.lat,\r\n long: geo.long,\r\n accuracy_radius: geo.accuracy_radius\r\n } : {\r\n _: 'inputGeoPointEmpty'\r\n };\r\n }\r\n\r\n public getInlineResults(peerId: number, botId: number, query = '', offset = '', geo?: GeoPoint) {\r\n return apiManagerProxy.invokeApi('messages.getInlineBotResults', {\r\n bot: appUsersManager.getUserInput(botId),\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n query,\r\n geo_point: geo ? this.getGeoInput(geo) : undefined,\r\n offset\r\n }, {/* timeout: 1, */stopTime: -1, noErrorBox: true}).then(botResults => {\r\n const queryId = botResults.query_id;\r\n\r\n /* if(botResults.switch_pm) {\r\n botResults.switch_pm.rText = RichTextProcessor.wrapRichText(botResults.switch_pm.text, {noLinebreaks: true, noLinks: true});\r\n } */\r\n \r\n botResults.results.forEach(result => {\r\n if(result._ === 'botInlineMediaResult') {\r\n if(result.document) {\r\n result.document = appDocsManager.saveDoc(result.document);\r\n }\r\n \r\n if(result.photo) {\r\n result.photo = appPhotosManager.savePhoto(result.photo);\r\n }\r\n }\r\n \r\n this.inlineResults[this.generateQId(queryId, result.id)] = result;\r\n });\r\n\r\n return botResults;\r\n });\r\n }\r\n\r\n public generateQId(queryId: string, resultId: string) {\r\n return queryId + '_' + resultId;\r\n }\r\n\r\n private pushPopularBot(botId: number) {\r\n appUsersManager.getTopPeers('bots_inline').then((topPeers) => {\r\n const index = topPeers.findIndex(topPeer => topPeer.id);\r\n let topPeer: MyTopPeer;\r\n if(index !== -1) {\r\n topPeer = topPeers[index];\r\n } else {\r\n topPeer = {\r\n id: botId,\r\n rating: 0\r\n };\r\n }\r\n\r\n ++topPeer.rating;\r\n insertInDescendSortedArray(topPeers, topPeer, 'rating');\r\n\r\n appStateManager.setKeyValueToStorage('topPeersCache');\r\n \r\n // rootScope.$broadcast('inline_bots_popular')\r\n });\r\n }\r\n\r\n public switchToPM(fromPeerId: number, botId: number, startParam: string) {\r\n this.setHash[botId] = {peerId: fromPeerId, time: Date.now()};\r\n rootScope.dispatchEvent('history_focus', {peerId: botId});\r\n return appMessagesManager.startBot(botId, 0, startParam);\r\n }\r\n \r\n /*\r\n function resolveInlineMention (username) {\r\n return AppPeersManager.resolveUsername(username).then(function (peerId) {\r\n if (peerId > 0) {\r\n var bot = AppUsersManager.getUser(peerId)\r\n if (bot.pFlags.bot && bot.bot_inline_placeholder !== undefined) {\r\n var resolvedBot = {\r\n username: username,\r\n id: peerId,\r\n placeholder: bot.bot_inline_placeholder\r\n }\r\n if (bot.pFlags.bot_inline_geo &&\r\n GeoLocationManager.isAvailable()) {\r\n return checkGeoLocationAccess(peerId).then(function () {\r\n return GeoLocationManager.getPosition().then(function (coords) {\r\n resolvedBot.geo = coords\r\n return qSync.when(resolvedBot)\r\n })\r\n })['catch'](function () {\r\n return qSync.when(resolvedBot)\r\n })\r\n }\r\n return qSync.when(resolvedBot)\r\n }\r\n }\r\n return $q.reject()\r\n }, function (error) {\r\n error.handled = true\r\n return $q.reject(error)\r\n })\r\n }\r\n \r\n function regroupWrappedResults (results, rowW, rowH) {\r\n if (!results ||\r\n !results[0] ||\r\n ['photo', 'gif', 'sticker'].indexOf(results[0].type) === -1) {\r\n return\r\n }\r\n var ratios = []\r\n angular.forEach(results, function (result) {\r\n var w\r\n var h, doc\r\n var photo\r\n if (result._ === 'botInlineMediaResult') {\r\n if (doc = result.document) {\r\n w = result.document.w\r\n h = result.document.h\r\n }\r\n else if (photo = result.photo) {\r\n var photoSize = (photo.sizes || [])[0]\r\n w = photoSize && photoSize.w\r\n h = photoSize && photoSize.h\r\n }\r\n }else {\r\n w = result.w\r\n h = result.h\r\n }\r\n if (!w || !h) {\r\n w = h = 1\r\n }\r\n ratios.push(w / h)\r\n })\r\n \r\n var rows = []\r\n var curCnt = 0\r\n var curW = 0\r\n angular.forEach(ratios, function (ratio) {\r\n var w = ratio * rowH\r\n curW += w\r\n if (!curCnt || curCnt < 4 && curW < (rowW * 1.1)) {\r\n curCnt++\r\n } else {\r\n rows.push(curCnt)\r\n curCnt = 1\r\n curW = w\r\n }\r\n })\r\n if (curCnt) {\r\n rows.push(curCnt)\r\n }\r\n \r\n var i = 0\r\n var thumbs = []\r\n var lastRowI = rows.length - 1\r\n angular.forEach(rows, function (rowCnt, rowI) {\r\n var lastRow = rowI === lastRowI\r\n var curRatios = ratios.slice(i, i + rowCnt)\r\n var sumRatios = 0\r\n angular.forEach(curRatios, function (ratio) {\r\n sumRatios += ratio\r\n })\r\n angular.forEach(curRatios, function (ratio, j) {\r\n var thumbH = rowH\r\n var thumbW = rowW * ratio / sumRatios\r\n var realW = thumbH * ratio\r\n if (lastRow && thumbW > realW) {\r\n thumbW = realW\r\n }\r\n var result = results[i + j]\r\n result.thumbW = Math.floor(thumbW) - 2\r\n result.thumbH = Math.floor(thumbH) - 2\r\n })\r\n \r\n i += rowCnt\r\n })\r\n } */\r\n\r\n public async checkSwitchReturn(botId: number) {\r\n const bot = appUsersManager.getUser(botId);\r\n if(!bot || !bot.pFlags.bot || !bot.bot_inline_placeholder) {\r\n return;\r\n }\r\n\r\n const peerData = this.setHash[botId];\r\n if(peerData) {\r\n delete this.setHash[botId];\r\n if((Date.now() - peerData.time) < 3600e3) {\r\n return peerData.peerId;\r\n }\r\n }\r\n }\r\n\r\n public switchInlineQuery(peerId: number, threadId: number, botId: number, query: string) {\r\n rootScope.dispatchEvent('history_focus', {peerId, threadId});\r\n appDraftsManager.setDraft(peerId, threadId, '@' + appUsersManager.getUser(botId).username + ' ' + query);\r\n }\r\n\r\n public callbackButtonClick(peerId: number, mid: number, button: any) {\r\n return apiManagerProxy.invokeApi('messages.getBotCallbackAnswer', {\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n msg_id: appMessagesIdsManager.getServerMessageId(mid),\r\n data: button.data\r\n }, {/* timeout: 1, */stopTime: -1, noErrorBox: true}).then((callbackAnswer) => {\r\n if(typeof callbackAnswer.message === 'string' && callbackAnswer.message.length) {\r\n toast(RichTextProcessor.wrapRichText(callbackAnswer.message, {noLinks: true, noLinebreaks: true}));\r\n }\r\n \r\n //console.log('callbackButtonClick callbackAnswer:', callbackAnswer);\r\n });\r\n }\r\n \r\n /* function gameButtonClick (id) {\r\n var message = AppMessagesManager.getMessage(id)\r\n var peerId = AppMessagesManager.getMessagePeer(message)\r\n \r\n return MtpApiManager.invokeApi('messages.getBotCallbackAnswer', {\r\n peer: AppPeersManager.getInputPeerByID(peerId),\r\n msg_id: AppMessagesIDsManager.getMessageLocalID(id)\r\n }, {timeout: 1, stopTime: -1, noErrorBox: true}).then(function (callbackAnswer) {\r\n if (typeof callbackAnswer.message === 'string' &&\r\n callbackAnswer.message.length) {\r\n showCallbackMessage(callbackAnswer.message, callbackAnswer.pFlags.alert)\r\n }\r\n else if (typeof callbackAnswer.url === 'string') {\r\n AppGamesManager.openGame(message.media.game.id, id, callbackAnswer.url)\r\n }\r\n })\r\n } */\r\n\r\n public sendInlineResult(peerId: number, botId: number, queryAndResultIds: string, options: Partial<{\r\n viaBotId: number,\r\n queryId: string,\r\n resultId: string,\r\n replyMarkup: ReplyMarkup,\r\n entities: MessageEntity[],\r\n replyToMsgId: number,\r\n clearDraft: true,\r\n scheduleDate: number,\r\n silent: true,\r\n geoPoint: GeoPoint\r\n }> = {}) {\r\n const inlineResult = this.inlineResults[queryAndResultIds];\r\n if(!inlineResult) {\r\n return;\r\n }\r\n\r\n this.pushPopularBot(botId);\r\n const splitted = queryAndResultIds.split('_');\r\n const queryID = splitted.shift();\r\n const resultID = splitted.join('_');\r\n options.viaBotId = botId;\r\n options.queryId = queryID;\r\n options.resultId = resultID;\r\n if(inlineResult.send_message.reply_markup) {\r\n options.replyMarkup = inlineResult.send_message.reply_markup;\r\n }\r\n \r\n if(inlineResult.send_message._ === 'botInlineMessageText') {\r\n options.entities = inlineResult.send_message.entities;\r\n appMessagesManager.sendText(peerId, inlineResult.send_message.message, options);\r\n } else {\r\n let caption = '';\r\n let inputMedia: InputMedia;\r\n const sendMessage = inlineResult.send_message;\r\n switch(sendMessage._) {\r\n case 'botInlineMessageMediaAuto': {\r\n caption = sendMessage.message;\r\n\r\n if(inlineResult._ === 'botInlineMediaResult') {\r\n const {document, photo} = inlineResult;\r\n if(document) {\r\n inputMedia = appDocsManager.getMediaInput(document as MyDocument);\r\n } else {\r\n inputMedia = appPhotosManager.getMediaInput(photo as MyPhoto);\r\n }\r\n }\r\n\r\n break;\r\n }\r\n\r\n case 'botInlineMessageMediaGeo': {\r\n inputMedia = {\r\n _: 'inputMediaGeoPoint',\r\n geo_point: this.getGeoInput(sendMessage.geo)\r\n };\r\n\r\n options.geoPoint = sendMessage.geo;\r\n\r\n break;\r\n }\r\n \r\n case 'botInlineMessageMediaVenue': {\r\n inputMedia = {\r\n _: 'inputMediaVenue',\r\n geo_point: this.getGeoInput(sendMessage.geo),\r\n title: sendMessage.title,\r\n address: sendMessage.address,\r\n provider: sendMessage.provider,\r\n venue_id: sendMessage.venue_id,\r\n venue_type: sendMessage.venue_type\r\n };\r\n\r\n options.geoPoint = sendMessage.geo;\r\n\r\n break;\r\n }\r\n\r\n case 'botInlineMessageMediaContact': {\r\n inputMedia = {\r\n _: 'inputMediaContact',\r\n phone_number: sendMessage.phone_number,\r\n first_name: sendMessage.first_name,\r\n last_name: sendMessage.last_name,\r\n vcard: sendMessage.vcard\r\n };\r\n\r\n break;\r\n }\r\n }\r\n\r\n if(!inputMedia) {\r\n inputMedia = {\r\n _: 'messageMediaPending',\r\n type: inlineResult.type,\r\n file_name: inlineResult.title || \r\n (inlineResult as BotInlineResult.botInlineResult).content?.url || \r\n (inlineResult as BotInlineResult.botInlineResult).url,\r\n size: 0,\r\n progress: {percent: 30, total: 0}\r\n } as any;\r\n }\r\n\r\n appMessagesManager.sendOther(peerId, inputMedia, options);\r\n }\r\n }\r\n \r\n /* function checkGeoLocationAccess (botID) {\r\n var key = 'bot_access_geo' + botID\r\n return Storage.get(key).then(function (geoAccess) {\r\n if (geoAccess && geoAccess.granted) {\r\n return true\r\n }\r\n return ErrorService.confirm({\r\n type: 'BOT_ACCESS_GEO_INLINE'\r\n }).then(function () {\r\n var setHash = {}\r\n setHash[key] = {granted: true, time: tsNow()}\r\n Storage.set(setHash)\r\n return true\r\n }, function () {\r\n var setHash = {}\r\n setHash[key] = {denied: true, time: tsNow()}\r\n Storage.set(setHash)\r\n return $q.reject()\r\n })\r\n })\r\n } */\r\n}\r\n\r\nconst appInlineBotsManager = new AppInlineBotsManager();\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appInlineBotsManager = appInlineBotsManager);\r\nexport default appInlineBotsManager;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport InputSearch from \"../../inputSearch\";\r\nimport animationIntersector from \"../../animationIntersector\";\r\nimport appSidebarRight from \"..\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport appInlineBotsManager, { AppInlineBotsManager } from \"../../../lib/appManagers/appInlineBotsManager\";\r\nimport GifsMasonry from \"../../gifsMasonry\";\r\nimport appImManager from \"../../../lib/appManagers/appImManager\";\r\nimport type { MyDocument } from \"../../../lib/appManagers/appDocsManager\";\r\nimport mediaSizes from \"../../../helpers/mediaSizes\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\n\r\nconst ANIMATIONGROUP = 'GIFS-SEARCH';\r\n\r\nexport default class AppGifsTab extends SliderSuperTab {\r\n private inputSearch: InputSearch;\r\n private gifsDiv: HTMLDivElement;\r\n\r\n private nextOffset = '';\r\n private loadedAll = false;\r\n\r\n private gifBotPeerId: number;\r\n private masonry: GifsMasonry;\r\n\r\n private searchPromise: ReturnType<AppInlineBotsManager['getInlineResults']>;\r\n\r\n protected init() {\r\n this.container.id = 'search-gifs-container';\r\n \r\n this.inputSearch = new InputSearch('SearchGifsTitle', (value) => {\r\n this.reset();\r\n this.search(value);\r\n });\r\n \r\n this.title.replaceWith(this.inputSearch.container);\r\n \r\n this.gifsDiv = document.createElement('div');\r\n this.gifsDiv.classList.add('gifs-masonry');\r\n attachClickEvent(this.gifsDiv, this.onGifsClick, {listenerSetter: this.listenerSetter});\r\n \r\n this.scrollable.append(this.gifsDiv);\r\n \r\n this.masonry = new GifsMasonry(this.gifsDiv, ANIMATIONGROUP, this.scrollable);\r\n //this.backBtn.parentElement.append(this.inputSearch.container);\r\n }\r\n\r\n private onGifsClick = (e: MouseEvent | TouchEvent) => {\r\n const target = findUpClassName(e.target, 'gif');\r\n if(!target) return;\r\n\r\n const fileId = target.dataset.docId;\r\n if(appImManager.chat.input.sendMessageWithDocument(fileId)) {\r\n if(mediaSizes.isMobile) {\r\n appSidebarRight.onCloseBtnClick();\r\n }\r\n } else {\r\n console.warn('got no doc by id:', fileId);\r\n }\r\n };\r\n\r\n public onClose() {\r\n this.scrollable.onScrolledBottom = () => {};\r\n }\r\n\r\n public onCloseAfterTimeout() {\r\n this.reset();\r\n this.gifsDiv.innerHTML = '';\r\n animationIntersector.checkAnimations(undefined, ANIMATIONGROUP);\r\n this.inputSearch.remove();\r\n return super.onCloseAfterTimeout();\r\n }\r\n\r\n private reset() {\r\n this.searchPromise = null;\r\n this.nextOffset = '';\r\n this.loadedAll = false;\r\n this.masonry.clear();\r\n }\r\n\r\n public open() {\r\n const ret = super.open();\r\n appSidebarRight.toggleSidebar(true).then(() => {\r\n this.search('', true);\r\n\r\n this.scrollable.onScrolledBottom = () => {\r\n this.search(this.inputSearch.value, false);\r\n };\r\n });\r\n return ret;\r\n }\r\n\r\n public async search(query: string, newSearch = true) {\r\n if(this.searchPromise || this.loadedAll) return;\r\n\r\n if(!this.gifBotPeerId) {\r\n this.gifBotPeerId = (await appUsersManager.resolveUsername('gif')).id;\r\n }\r\n\r\n try {\r\n this.searchPromise = appInlineBotsManager.getInlineResults(0, this.gifBotPeerId, query, this.nextOffset);\r\n const { results, next_offset } = await this.searchPromise;\r\n\r\n if(this.inputSearch.value !== query) {\r\n return;\r\n }\r\n\r\n this.searchPromise = null;\r\n this.nextOffset = next_offset;\r\n if(newSearch) {\r\n this.gifsDiv.innerHTML = '';\r\n }\r\n\r\n if(results.length) {\r\n results.forEach((result) => {\r\n if(result._ === 'botInlineMediaResult' && result.document) {\r\n this.masonry.add(result.document as MyDocument);\r\n }\r\n });\r\n } else {\r\n this.loadedAll = true;\r\n }\r\n\r\n this.scrollable.onScroll();\r\n } catch(err) {\r\n this.searchPromise = null;\r\n console.error('gifs loading error:', err);\r\n throw err;\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { SliderSuperTab } from \"../../slider\";\r\nimport InputSearch from \"../../inputSearch\";\r\nimport LazyLoadQueue from \"../../lazyLoadQueue\";\r\nimport appImManager from \"../../../lib/appManagers/appImManager\";\r\nimport appStickersManager from \"../../../lib/appManagers/appStickersManager\";\r\nimport PopupStickers from \"../../popups/stickers\";\r\nimport animationIntersector from \"../../animationIntersector\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport { wrapSticker } from \"../../wrappers\";\r\nimport appSidebarRight from \"..\";\r\nimport { StickerSet, StickerSetCovered } from \"../../../layer\";\r\nimport { forEachReverse } from \"../../../helpers/array\";\r\nimport { i18n } from \"../../../lib/langPack\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\n\r\nexport default class AppStickersTab extends SliderSuperTab {\r\n private inputSearch: InputSearch;\r\n private setsDiv: HTMLDivElement;\r\n private lazyLoadQueue: LazyLoadQueue;\r\n\r\n protected init() {\r\n this.container.id = 'stickers-container';\r\n this.container.classList.add('chatlist-container');\r\n\r\n this.lazyLoadQueue = new LazyLoadQueue();\r\n\r\n this.inputSearch = new InputSearch('StickersTab.SearchPlaceholder', (value) => {\r\n this.search(value);\r\n });\r\n\r\n this.title.replaceWith(this.inputSearch.container);\r\n\r\n this.setsDiv = document.createElement('div');\r\n this.setsDiv.classList.add('sticker-sets');\r\n this.scrollable.append(this.setsDiv);\r\n\r\n attachClickEvent(this.setsDiv, (e) => {\r\n const sticker = findUpClassName(e.target, 'sticker-set-sticker');\r\n if(sticker) {\r\n const docId = sticker.dataset.docId;\r\n appImManager.chat.input.sendMessageWithDocument(docId);\r\n return;\r\n }\r\n\r\n const target = findUpClassName(e.target, 'sticker-set');\r\n if(!target) return;\r\n\r\n const id = target.dataset.stickerSet as string;\r\n const access_hash = target.dataset.access_hash as string;\r\n\r\n const button = findUpClassName(e.target, 'sticker-set-button') as HTMLElement;\r\n if(button) {\r\n e.preventDefault();\r\n e.cancelBubble = true;\r\n\r\n button.setAttribute('disabled', 'true');\r\n \r\n appStickersManager.getStickerSet({id, access_hash}).then(full => {\r\n appStickersManager.toggleStickerSet(full.set).then(changed => {\r\n if(changed) {\r\n button.textContent = '';\r\n button.append(i18n(full.set.installed_date ? 'Stickers.SearchAdded' : 'Stickers.SearchAdd'));\r\n button.classList.toggle('gray', !!full.set.installed_date);\r\n }\r\n }).finally(() => {\r\n //button.style.width = set.installed_date ? '68px' : '52px';\r\n button.removeAttribute('disabled');\r\n });\r\n });\r\n } else {\r\n appStickersManager.getStickerSet({id, access_hash}).then(full => {\r\n new PopupStickers(full.set).show();\r\n });\r\n }\r\n }, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n public onCloseAfterTimeout() {\r\n this.setsDiv.innerHTML = '';\r\n animationIntersector.checkAnimations(undefined, 'STICKERS-SEARCH');\r\n return super.onCloseAfterTimeout();\r\n }\r\n\r\n public renderSet(set: StickerSet.stickerSet) {\r\n //console.log('renderSet:', set);\r\n const div = document.createElement('div');\r\n div.classList.add('sticker-set');\r\n\r\n const header = document.createElement('div');\r\n header.classList.add('sticker-set-header');\r\n\r\n const details = document.createElement('div');\r\n details.classList.add('sticker-set-details');\r\n details.innerHTML = `\r\n <div class=\"sticker-set-name\">${RichTextProcessor.wrapEmojiText(set.title)}</div>\r\n `;\r\n\r\n const countDiv = document.createElement('div');\r\n countDiv.classList.add('sticker-set-count');\r\n countDiv.append(i18n('Stickers', [set.count]));\r\n details.append(countDiv);\r\n \r\n const button = document.createElement('button');\r\n button.classList.add('btn-primary', 'btn-color-primary', 'sticker-set-button');\r\n button.append(i18n(set.installed_date ? 'Stickers.SearchAdded' : 'Stickers.SearchAdd'));\r\n // button.style.width = set.installed_date ? '68px' : '52px';\r\n\r\n if(set.installed_date) {\r\n button.classList.add('gray');\r\n }\r\n\r\n //ripple(button);\r\n\r\n header.append(details, button);\r\n\r\n const stickersDiv = document.createElement('div');\r\n stickersDiv.classList.add('sticker-set-stickers');\r\n\r\n const count = Math.min(5, set.count);\r\n for(let i = 0; i < count; ++i) {\r\n const stickerDiv = document.createElement('div');\r\n stickerDiv.classList.add('sticker-set-sticker');\r\n\r\n stickersDiv.append(stickerDiv);\r\n }\r\n\r\n appStickersManager.getStickerSet(set).then(set => {\r\n //console.log('renderSet got set:', set);\r\n \r\n for(let i = 0; i < count; ++i) {\r\n const div = stickersDiv.children[i] as HTMLDivElement;\r\n const doc = set.documents[i];\r\n if(doc._ === 'documentEmpty') {\r\n continue;\r\n }\r\n\r\n wrapSticker({\r\n doc, \r\n div, \r\n lazyLoadQueue: this.lazyLoadQueue, \r\n group: 'STICKERS-SEARCH', \r\n /* play: false,\r\n loop: false, */\r\n play: true,\r\n loop: true,\r\n width: 68,\r\n height: 68\r\n });\r\n }\r\n });\r\n\r\n /* const onMouseOver = () => {\r\n const animations: AnimationItem['animation'][] = [];\r\n for(let i = 0; i < count; ++i) {\r\n const stickerDiv = stickersDiv.children[i] as HTMLElement;\r\n const animationItem = animationIntersector.getAnimation(stickerDiv);\r\n if(!animationItem) continue;\r\n\r\n const animation = animationItem.animation;\r\n\r\n animations.push(animation);\r\n animation.loop = true;\r\n animation.play();\r\n }\r\n\r\n div.addEventListener('mouseout', () => {\r\n animations.forEach(animation => {\r\n animation.loop = false;\r\n });\r\n\r\n div.addEventListener('mouseover', onMouseOver, {once: true});\r\n }, {once: true});\r\n };\r\n\r\n div.addEventListener('mouseover', onMouseOver, {once: true}); */\r\n\r\n div.dataset.stickerSet = set.id;\r\n div.dataset.access_hash = set.access_hash;\r\n div.dataset.title = set.title;\r\n\r\n div.append(header, stickersDiv);\r\n\r\n this.setsDiv.append(div);\r\n }\r\n\r\n public open() {\r\n const ret = super.open();\r\n appSidebarRight.toggleSidebar(true).then(() => {\r\n this.renderFeatured();\r\n });\r\n\r\n return ret;\r\n }\r\n\r\n public renderFeatured() {\r\n return appStickersManager.getFeaturedStickers().then(coveredSets => {\r\n if(this.inputSearch.value) {\r\n return;\r\n }\r\n\r\n coveredSets = this.filterRendered('', coveredSets);\r\n coveredSets.forEach(set => {\r\n this.renderSet(set.set);\r\n });\r\n });\r\n }\r\n\r\n private filterRendered(query: string, coveredSets: StickerSetCovered[]) {\r\n coveredSets = coveredSets.slice();\r\n\r\n const children = Array.from(this.setsDiv.children) as HTMLElement[];\r\n forEachReverse(children, el => {\r\n const id = el.dataset.stickerSet;\r\n const index = coveredSets.findIndex(covered => covered.set.id === id);\r\n \r\n if(index !== -1) {\r\n coveredSets.splice(index, 1);\r\n } else if(!query || !el.dataset.title.toLowerCase().includes(query.toLowerCase())) {\r\n el.remove();\r\n }\r\n });\r\n\r\n animationIntersector.checkAnimations(undefined, 'STICKERS-SEARCH');\r\n\r\n return coveredSets;\r\n }\r\n\r\n public search(query: string) {\r\n if(!query) {\r\n return this.renderFeatured();\r\n }\r\n\r\n return appStickersManager.searchStickerSets(query, false).then(coveredSets => {\r\n if(this.inputSearch.value !== query) {\r\n return;\r\n }\r\n\r\n //console.log('search result:', coveredSets);\r\n\r\n coveredSets = this.filterRendered(query, coveredSets);\r\n coveredSets.forEach(set => {\r\n this.renderSet(set.set);\r\n });\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { attachClickEvent } from \"./dom/clickEvent\";\r\nimport findUpAsChild from \"./dom/findUpAsChild\";\r\nimport EventListenerBase from \"./eventListenerBase\";\r\nimport ListenerSetter from \"./listenerSetter\";\r\nimport { safeAssign } from \"./object\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\r\n\r\nconst KEEP_OPEN = false;\r\nconst TOGGLE_TIMEOUT = 200;\r\nconst ANIMATION_DURATION = 200;\r\n\r\nexport default class DropdownHover extends EventListenerBase<{\r\n open: () => Promise<any> | void,\r\n opened: () => any,\r\n close: () => any,\r\n closed: () => any\r\n}> {\r\n protected element: HTMLElement;\r\n protected displayTimeout: number;\r\n protected forceClose = false;\r\n protected inited = false;\r\n\r\n constructor(options: {\r\n element: DropdownHover['element']\r\n }) {\r\n super(false);\r\n safeAssign(this, options);\r\n }\r\n\r\n public attachButtonListener(button: HTMLElement, listenerSetter: ListenerSetter) {\r\n let firstTime = true;\r\n if(IS_TOUCH_SUPPORTED) {\r\n attachClickEvent(button, () => {\r\n if(firstTime) {\r\n firstTime = false;\r\n this.toggle(true);\r\n } else {\r\n this.toggle();\r\n }\r\n }, {listenerSetter});\r\n } else {\r\n listenerSetter.add(button)('mouseover', (e) => {\r\n //console.log('onmouseover button');\r\n if(firstTime) {\r\n listenerSetter.add(button)('mouseout', this.onMouseOut);\r\n firstTime = false;\r\n }\r\n\r\n clearTimeout(this.displayTimeout);\r\n this.displayTimeout = window.setTimeout(() => {\r\n this.toggle(true);\r\n }, TOGGLE_TIMEOUT);\r\n });\r\n }\r\n }\r\n\r\n private onMouseOut = (e: MouseEvent) => {\r\n if(KEEP_OPEN) return;\r\n clearTimeout(this.displayTimeout);\r\n if(!this.isActive()) return;\r\n\r\n const toElement = (e as any).toElement as Element;\r\n if(toElement && findUpAsChild(toElement, this.element)) {\r\n return;\r\n }\r\n\r\n this.displayTimeout = window.setTimeout(() => {\r\n this.toggle(false);\r\n }, TOGGLE_TIMEOUT);\r\n };\r\n\r\n protected init() {\r\n if(!IS_TOUCH_SUPPORTED) {\r\n this.element.onmouseout = this.onMouseOut;\r\n this.element.onmouseover = (e) => {\r\n if(this.forceClose) {\r\n return;\r\n }\r\n\r\n //console.log('onmouseover element');\r\n clearTimeout(this.displayTimeout);\r\n };\r\n }\r\n }\r\n\r\n public toggle = async(enable?: boolean) => {\r\n //if(!this.element) return;\r\n const willBeActive = (!!this.element.style.display && enable === undefined) || enable;\r\n if(this.init) {\r\n if(willBeActive) {\r\n this.init();\r\n this.init = null;\r\n } else {\r\n return;\r\n }\r\n }\r\n\r\n if(willBeActive === this.isActive()) {\r\n return;\r\n }\r\n \r\n if((this.element.style.display && enable === undefined) || enable) {\r\n const res = this.dispatchEvent('open');\r\n await Promise.all(res);\r\n\r\n this.element.style.display = '';\r\n void this.element.offsetLeft; // reflow\r\n this.element.classList.add('active');\r\n\r\n clearTimeout(this.displayTimeout);\r\n this.displayTimeout = window.setTimeout(() => {\r\n this.forceClose = false;\r\n this.dispatchEvent('opened');\r\n }, IS_TOUCH_SUPPORTED ? 0 : ANIMATION_DURATION);\r\n\r\n // ! can't use together with resizeObserver\r\n /* if(isTouchSupported) {\r\n const height = this.element.scrollHeight + appImManager.chat.input.inputContainer.scrollHeight - 10;\r\n console.log('[ESG]: toggle: enable height', height);\r\n appImManager.chat.bubbles.scrollable.scrollTop += height;\r\n } */\r\n\r\n /* if(touchSupport) {\r\n this.restoreScroll();\r\n } */\r\n } else {\r\n this.dispatchEvent('close');\r\n\r\n this.element.classList.remove('active');\r\n\r\n clearTimeout(this.displayTimeout);\r\n this.displayTimeout = window.setTimeout(() => {\r\n this.element.style.display = 'none';\r\n this.forceClose = false;\r\n this.dispatchEvent('closed');\r\n }, IS_TOUCH_SUPPORTED ? 0 : ANIMATION_DURATION);\r\n\r\n /* if(isTouchSupported) {\r\n const scrollHeight = this.container.scrollHeight;\r\n if(scrollHeight) {\r\n const height = this.container.scrollHeight + appImManager.chat.input.inputContainer.scrollHeight - 10;\r\n appImManager.chat.bubbles.scrollable.scrollTop -= height;\r\n }\r\n } */\r\n\r\n /* if(touchSupport) {\r\n this.restoreScroll();\r\n } */\r\n }\r\n\r\n //animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);\r\n };\r\n\r\n public isActive() {\r\n return this.element.classList.contains('active');\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\nimport appImManager from \"../../lib/appManagers/appImManager\";\nimport rootScope from \"../../lib/rootScope\";\nimport animationIntersector from \"../animationIntersector\";\nimport { horizontalMenu } from \"../horizontalMenu\";\nimport LazyLoadQueue, { LazyLoadQueueIntersector } from \"../lazyLoadQueue\";\nimport Scrollable, { ScrollableX } from \"../scrollable\";\nimport appSidebarRight from \"../sidebarRight\";\nimport StickyIntersector from \"../stickyIntersector\";\nimport EmojiTab from \"./tabs/emoji\";\nimport GifsTab from \"./tabs/gifs\";\nimport StickersTab from \"./tabs/stickers\";\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport AppGifsTab from \"../sidebarRight/tabs/gifs\";\nimport AppStickersTab from \"../sidebarRight/tabs/stickers\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport findUpTag from \"../../helpers/dom/findUpTag\";\nimport blurActiveElement from \"../../helpers/dom/blurActiveElement\";\nimport whichChild from \"../../helpers/dom/whichChild\";\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\nimport DropdownHover from \"../../helpers/dropdownHover\";\nimport { pause } from \"../../helpers/schedulers/pause\";\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\n\nexport const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';\n\nexport interface EmoticonsTab {\n init: () => void,\n onCloseAfterTimeout?: () => void\n}\n\nexport class EmoticonsDropdown extends DropdownHover {\n public static lazyLoadQueue = new LazyLoadQueue();\n\n private emojiTab: EmojiTab;\n public stickersTab: StickersTab;\n private gifsTab: GifsTab;\n\n private container: HTMLElement;\n private tabsEl: HTMLElement;\n private tabId = -1;\n\n private tabs: {[id: number]: EmoticonsTab};\n\n private searchButton: HTMLElement;\n private deleteBtn: HTMLElement;\n\n private selectTab: ReturnType<typeof horizontalMenu>;\n\n private savedRange: Range;\n\n constructor() {\n super({\n element: document.getElementById('emoji-dropdown') as HTMLDivElement\n });\n\n this.addEventListener('open', async() => {\n if(IS_TOUCH_SUPPORTED) {\n //appImManager.chat.input.saveScroll();\n if(blurActiveElement()) {\n await pause(100);\n }\n }\n\n if(this.element.parentElement !== appImManager.chat.input.chatInput) {\n appImManager.chat.input.chatInput.append(this.element);\n }\n\n this.savedRange = this.getGoodRange();\n\n EmoticonsDropdown.lazyLoadQueue.lock();\n //EmoticonsDropdown.lazyLoadQueue.unlock();\n animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);\n });\n\n this.addEventListener('opened', () => {\n animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);\n EmoticonsDropdown.lazyLoadQueue.unlock();\n EmoticonsDropdown.lazyLoadQueue.refresh();\n\n this.container.classList.remove('disable-hover');\n });\n\n this.addEventListener('close', () => {\n EmoticonsDropdown.lazyLoadQueue.lock();\n //EmoticonsDropdown.lazyLoadQueue.lock();\n\n // нужно залочить группу и выключить стикеры\n animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);\n animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);\n });\n\n this.addEventListener('closed', () => {\n // теперь можно убрать visible, чтобы они не включились после фокуса\n animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);\n EmoticonsDropdown.lazyLoadQueue.unlock();\n EmoticonsDropdown.lazyLoadQueue.refresh();\n\n this.container.classList.remove('disable-hover');\n\n this.savedRange = undefined;\n });\n }\n\n protected init() {\n this.emojiTab = new EmojiTab();\n this.stickersTab = new StickersTab();\n this.gifsTab = new GifsTab();\n\n this.tabs = {\n 0: this.emojiTab,\n 1: this.stickersTab,\n 2: this.gifsTab\n };\n\n this.container = this.element.querySelector('.emoji-container .tabs-container') as HTMLDivElement;\n this.tabsEl = this.element.querySelector('.emoji-tabs') as HTMLUListElement;\n this.selectTab = horizontalMenu(this.tabsEl, this.container, this.onSelectTabClick, () => {\n const tab = this.tabs[this.tabId];\n if(tab.init) {\n tab.init();\n }\n\n tab.onCloseAfterTimeout && tab.onCloseAfterTimeout();\n animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);\n });\n\n this.searchButton = this.element.querySelector('.emoji-tabs-search');\n this.searchButton.addEventListener('click', () => {\n if(this.tabId === 1) {\n if(!appSidebarRight.isTabExists(AppStickersTab)) {\n new AppStickersTab(appSidebarRight).open();\n }\n } else {\n if(!appSidebarRight.isTabExists(AppGifsTab)) {\n new AppGifsTab(appSidebarRight).open();\n }\n }\n });\n\n this.deleteBtn = this.element.querySelector('.emoji-tabs-delete');\n this.deleteBtn.addEventListener('click', (e) => {\n const input = appImManager.chat.input.messageInput;\n if((input.lastChild as any)?.tagName) {\n input.lastElementChild.remove();\n } else if(input.lastChild) {\n if(!input.lastChild.textContent.length) {\n input.lastChild.remove();\n } else {\n input.lastChild.textContent = input.lastChild.textContent.slice(0, -1);\n }\n }\n\n const event = new Event('input', {bubbles: true, cancelable: true});\n appImManager.chat.input.messageInput.dispatchEvent(event);\n //appSidebarRight.stickersTab.init();\n\n cancelEvent(e);\n });\n\n (this.tabsEl.children[1] as HTMLLIElement).click(); // set emoji tab\n if(this.tabs[0].init) {\n this.tabs[0].init(); // onTransitionEnd не вызовется, т.к. это первая открытая вкладка\n }\n\n rootScope.addEventListener('peer_changed', this.checkRights);\n this.checkRights();\n\n return super.init();\n }\n\n private onSelectTabClick = (id: number) => {\n if(this.tabId === id) {\n return;\n }\n \n animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);\n\n this.tabId = id;\n this.searchButton.classList.toggle('hide', this.tabId === 0);\n this.deleteBtn.classList.toggle('hide', this.tabId !== 0);\n };\n\n private checkRights = () => {\n const {peerId, threadId} = appImManager.chat;\n const children = this.tabsEl.children;\n const tabsElements = Array.from(children) as HTMLElement[];\n\n const canSendStickers = appMessagesManager.canSendToPeer(peerId, threadId, 'send_stickers');\n tabsElements[2].toggleAttribute('disabled', !canSendStickers);\n\n const canSendGifs = appMessagesManager.canSendToPeer(peerId, threadId, 'send_gifs');\n tabsElements[3].toggleAttribute('disabled', !canSendGifs);\n\n const active = this.tabsEl.querySelector('.active');\n if(active && whichChild(active) !== 1 && (!canSendStickers || !canSendGifs)) {\n this.selectTab(0, false);\n }\n };\n\n public static menuOnClick = (menu: HTMLElement, scroll: Scrollable, menuScroll?: ScrollableX, prevId = 0) => {\n let jumpedTo = -1;\n\n const setActive = (id: number) => {\n if(id === prevId) {\n return false;\n }\n\n menu.children[prevId].classList.remove('active');\n menu.children[id].classList.add('active');\n prevId = id;\n\n return true;\n };\n\n const stickyIntersector = new StickyIntersector(scroll.container, (stuck, target) => {\n //console.log('sticky scrollTOp', stuck, target, scroll.container.scrollTop);\n\n if(Math.abs(jumpedTo - scroll.container.scrollTop) <= 1) {\n return;\n } else {\n jumpedTo = -1;\n }\n\n const which = whichChild(target);\n if(!stuck && which) { // * due to stickyIntersector\n return;\n }\n\n setActive(which);\n\n if(menuScroll) {\n if(which < menu.childElementCount - 4) {\n menuScroll.container.scrollLeft = (which - 3) * 47;\n } else {\n menuScroll.container.scrollLeft = which * 47;\n }\n }\n });\n\n menu.addEventListener('click', (e) => {\n let target = e.target as HTMLElement;\n target = findUpClassName(target, 'menu-horizontal-div-item');\n\n if(!target) {\n return;\n }\n\n const which = whichChild(target);\n\n /* if(menuScroll) {\n menuScroll.scrollIntoView(target, false, 0);\n } */\n\n if(!setActive(which)) {\n return;\n }\n\n const element = (scroll.splitUp || scroll.container).children[which] as HTMLElement;\n const offsetTop = element.offsetTop + 1; // * due to stickyIntersector\n\n scroll.container.scrollTop = jumpedTo = offsetTop;\n\n //console.log('set scrollTop:', offsetTop);\n });\n\n return {stickyIntersector, setActive};\n };\n\n public static onMediaClick = (e: {target: EventTarget | Element}, clearDraft = false) => {\n let target = e.target as HTMLElement;\n target = findUpTag(target, 'DIV');\n\n if(!target) return false;\n \n const fileId = target.dataset.docId;\n if(!fileId) return false;\n\n if(appImManager.chat.input.sendMessageWithDocument(fileId, undefined, clearDraft)) {\n /* dropdown.classList.remove('active');\n toggleEl.classList.remove('active'); */\n if(emoticonsDropdown.container) {\n emoticonsDropdown.forceClose = true;\n emoticonsDropdown.container.classList.add('disable-hover');\n emoticonsDropdown.toggle(false);\n }\n\n return true;\n } else {\n console.warn('got no doc by id:', fileId);\n return false;\n }\n };\n\n public addLazyLoadQueueRepeat(lazyLoadQueue: LazyLoadQueueIntersector, processInvisibleDiv: (div: HTMLElement) => void) {\n this.addEventListener('close', () => {\n lazyLoadQueue.lock();\n });\n\n this.addEventListener('closed', () => {\n const divs = lazyLoadQueue.intersector.getVisible();\n\n for(const div of divs) {\n processInvisibleDiv(div);\n }\n\n lazyLoadQueue.intersector.clearVisible();\n });\n\n this.addEventListener('opened', () => {\n lazyLoadQueue.unlockAndRefresh();\n });\n }\n\n public getSavedRange() {\n return this.getGoodRange() || this.savedRange;\n }\n\n private getGoodRange() {\n const sel = document.getSelection();\n if(sel.rangeCount && document.activeElement === appImManager.chat.input.messageInput) {\n return sel.getRangeAt(0);\n }\n }\n}\n\nconst emoticonsDropdown = new EmoticonsDropdown();\nMOUNT_CLASS_TO.emoticonsDropdown = emoticonsDropdown;\nexport default emoticonsDropdown;\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppImManager } from \"../../lib/appManagers/appImManager\";\r\nimport type { AppMessagesManager, HistoryResult, HistoryStorage, MyMessage } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppStickersManager } from \"../../lib/appManagers/appStickersManager\";\r\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\r\nimport type { AppInlineBotsManager } from \"../../lib/appManagers/appInlineBotsManager\";\r\nimport type { AppPhotosManager } from \"../../lib/appManagers/appPhotosManager\";\r\nimport type { MyDocument } from \"../../lib/appManagers/appDocsManager\";\r\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\r\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\r\nimport type { AppDraftsManager } from \"../../lib/appManagers/appDraftsManager\";\r\nimport type { AppMessagesIdsManager } from \"../../lib/appManagers/appMessagesIdsManager\";\r\nimport type Chat from \"./chat\";\r\nimport { CHAT_ANIMATION_GROUP } from \"../../lib/appManagers/appImManager\";\r\nimport { getObjectKeysAndSort } from \"../../helpers/object\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport { logger } from \"../../lib/logger\";\r\nimport rootScope, { BroadcastEvents } from \"../../lib/rootScope\";\r\nimport BubbleGroups from \"./bubbleGroups\";\r\nimport PopupDatePicker from \"../popups/datePicker\";\r\nimport PopupForward from \"../popups/forward\";\r\nimport PopupStickers from \"../popups/stickers\";\r\nimport ProgressivePreloader from \"../preloader\";\r\nimport Scrollable, { SliceSides } from \"../scrollable\";\r\nimport StickyIntersector from \"../stickyIntersector\";\r\nimport animationIntersector from \"../animationIntersector\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport { IS_ANDROID, IS_APPLE, IS_MOBILE, IS_SAFARI } from \"../../environment/userAgent\";\r\nimport I18n, { i18n, langPack } from \"../../lib/langPack\";\r\nimport AvatarElement from \"../avatar\";\r\nimport { ripple } from \"../ripple\";\r\nimport { wrapAlbum, wrapPhoto, wrapVideo, wrapDocument, wrapSticker, wrapPoll, wrapGroupedDocuments } from \"../wrappers\";\r\nimport { MessageRender } from \"./messageRender\";\r\nimport LazyLoadQueue from \"../lazyLoadQueue\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport PollElement from \"../poll\";\r\nimport AudioElement from \"../audio\";\r\nimport { Message, MessageEntity, MessageReplyHeader, Photo, PhotoSize, ReplyMarkup, Update, WebPage } from \"../../layer\";\r\nimport { REPLIES_PEER_ID } from \"../../lib/mtproto/mtproto_config\";\r\nimport { FocusDirection } from \"../../helpers/fastSmoothScroll\";\r\nimport useHeavyAnimationCheck, { getHeavyAnimationPromise, dispatchHeavyAnimationEvent, interruptHeavyAnimation } from \"../../hooks/useHeavyAnimationCheck\";\r\nimport { fastRaf, fastRafPromise } from \"../../helpers/schedulers\";\r\nimport { deferredPromise } from \"../../helpers/cancellablePromise\";\r\nimport RepliesElement from \"./replies\";\r\nimport DEBUG from \"../../config/debug\";\r\nimport { SliceEnd } from \"../../helpers/slicedArray\";\r\nimport serverTimeManager from \"../../lib/mtproto/serverTimeManager\";\r\nimport PeerTitle from \"../peerTitle\";\r\nimport { forEachReverse } from \"../../helpers/array\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport { toast } from \"../toast\";\r\nimport { getElementByPoint } from \"../../helpers/dom/getElementByPoint\";\r\nimport { getMiddleware } from \"../../helpers/middleware\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport htmlToDocumentFragment from \"../../helpers/dom/htmlToDocumentFragment\";\r\nimport positionElementByIndex from \"../../helpers/dom/positionElementByIndex\";\r\nimport reflowScrollableElement from \"../../helpers/dom/reflowScrollableElement\";\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\nimport setInnerHTML from \"../../helpers/dom/setInnerHTML\";\r\nimport whichChild from \"../../helpers/dom/whichChild\";\r\nimport { cancelAnimationByKey } from \"../../helpers/animation\";\r\nimport assumeType from \"../../helpers/assumeType\";\r\nimport { EmoticonsDropdown } from \"../emoticonsDropdown\";\r\nimport debounce from \"../../helpers/schedulers/debounce\";\r\nimport { formatNumber } from \"../../helpers/number\";\r\nimport { SEND_WHEN_ONLINE_TIMESTAMP } from \"../../lib/mtproto/constants\";\r\nimport windowSize from \"../../helpers/windowSize\";\r\nimport { formatPhoneNumber } from \"../../helpers/formatPhoneNumber\";\r\nimport AppMediaViewer from \"../appMediaViewer\";\r\n\r\nconst USE_MEDIA_TAILS = false;\r\nconst IGNORE_ACTIONS: Set<Message.messageService['action']['_']> = new Set([\r\n 'messageActionHistoryClear',\r\n 'messageActionChatCreate'/* ,\r\n 'messageActionChannelMigrateFrom' */\r\n]);\r\n\r\nconst TEST_SCROLL_TIMES: number = undefined;\r\nlet TEST_SCROLL = TEST_SCROLL_TIMES;\r\n\r\nlet queueId = 0;\r\n\r\ntype GenerateLocalMessageType<IsService> = IsService extends true ? Message.messageService : Message.message;\r\n\r\nexport default class ChatBubbles {\r\n public bubblesContainer: HTMLDivElement;\r\n private chatInner: HTMLDivElement;\r\n public scrollable: Scrollable;\r\n\r\n private getHistoryTopPromise: Promise<boolean>;\r\n private getHistoryBottomPromise: Promise<boolean>;\r\n\r\n public peerId = 0;\r\n //public messagesCount: number = -1;\r\n\r\n private unreadOut = new Set<number>();\r\n public needUpdate: {replyToPeerId: number, replyMid: number, mid: number}[] = []; // if need wrapSingleMessage\r\n\r\n public bubbles: {[mid: string]: HTMLDivElement} = {};\r\n public skippedMids: Set<number> = new Set();\r\n private dateMessages: {[timestamp: number]: { \r\n div: HTMLDivElement, \r\n firstTimestamp: number, \r\n container: HTMLDivElement,\r\n timeout?: number \r\n }} = {};\r\n\r\n private scrolledDown = true;\r\n private isScrollingTimeout = 0;\r\n\r\n private stickyIntersector: StickyIntersector;\r\n\r\n private unreadedObserver: IntersectionObserver;\r\n private unreaded: Map<HTMLElement, number> = new Map();\r\n private unreadedSeen: Set<number> = new Set();\r\n private readPromise: Promise<void>;\r\n\r\n private bubbleGroups: BubbleGroups;\r\n\r\n private preloader: ProgressivePreloader = null;\r\n \r\n private loadedTopTimes = 0;\r\n private loadedBottomTimes = 0;\r\n\r\n private messagesQueuePromise: Promise<void> = null;\r\n private messagesQueue: {message: any, bubble: HTMLElement, reverse: boolean, promises: Promise<void>[]}[] = [];\r\n private messagesQueueOnRender: () => void = null;\r\n private messagesQueueOnRenderAdditional: () => void = null;\r\n\r\n private firstUnreadBubble: HTMLDivElement = null;\r\n private attachedUnreadBubble: boolean;\r\n\r\n public lazyLoadQueue: LazyLoadQueue;\r\n\r\n private middleware = getMiddleware();\r\n\r\n private log: ReturnType<typeof logger>;\r\n\r\n public listenerSetter: ListenerSetter;\r\n\r\n private replyFollowHistory: number[] = [];\r\n\r\n private isHeavyAnimationInProgress = false;\r\n private scrollingToBubble: HTMLElement;\r\n\r\n private isFirstLoad = true;\r\n private needReflowScroll: boolean;\r\n\r\n private fetchNewPromise: Promise<void>;\r\n private historyStorage: HistoryStorage;\r\n\r\n private passEntities: Partial<{\r\n [_ in MessageEntity['_']]: boolean\r\n }> = {};\r\n\r\n private onAnimateLadder: () => Promise<any> | void;\r\n // private ladderDeferred: CancellablePromise<void>;\r\n private resolveLadderAnimation: () => Promise<any>;\r\n private emptyPlaceholderMid: number;\r\n\r\n private viewsObserver: IntersectionObserver;\r\n private viewsMids: Set<number> = new Set();\r\n private sendViewCountersDebounced: () => Promise<void>;\r\n\r\n constructor(private chat: Chat, \r\n private appMessagesManager: AppMessagesManager, \r\n private appStickersManager: AppStickersManager, \r\n private appUsersManager: AppUsersManager, \r\n private appInlineBotsManager: AppInlineBotsManager, \r\n private appPhotosManager: AppPhotosManager, \r\n private appPeersManager: AppPeersManager,\r\n private appProfileManager: AppProfileManager,\r\n private appDraftsManager: AppDraftsManager,\r\n private appMessagesIdsManager: AppMessagesIdsManager\r\n ) {\r\n //this.chat.log.error('Bubbles construction');\r\n \r\n this.listenerSetter = new ListenerSetter();\r\n\r\n this.bubblesContainer = document.createElement('div');\r\n this.bubblesContainer.classList.add('bubbles', 'scrolled-down');\r\n\r\n this.chatInner = document.createElement('div');\r\n this.chatInner.classList.add('bubbles-inner');\r\n\r\n this.setScroll();\r\n\r\n this.bubblesContainer.append(this.scrollable.container);\r\n\r\n // * constructor end\r\n\r\n this.log = this.chat.log;\r\n this.bubbleGroups = new BubbleGroups(this.chat);\r\n this.preloader = new ProgressivePreloader({\r\n cancelable: false\r\n });\r\n this.lazyLoadQueue = new LazyLoadQueue();\r\n this.lazyLoadQueue.queueId = ++queueId;\r\n\r\n // * events\r\n\r\n // will call when sent for update pos\r\n this.listenerSetter.add(rootScope)('history_update', ({storage, peerId, mid}) => {\r\n if(this.chat.getMessagesStorage() === storage) {\r\n const bubble = this.bubbles[mid];\r\n if(!bubble) return;\r\n\r\n const message = this.chat.getMessage(mid);\r\n \r\n if(+bubble.dataset.timestamp >= (message.date + serverTimeManager.serverTimeOffset - 1)) {\r\n //this.bubbleGroups.addBubble(bubble, message, false); // ! TEMP COMMENTED\r\n return;\r\n }\r\n\r\n this.setBubblePosition(bubble, message, false);\r\n //this.log('history_update', this.bubbles[mid], mid, message);\r\n\r\n if(this.scrollingToBubble) {\r\n this.scrollToBubbleEnd();\r\n }\r\n\r\n //this.renderMessage(message, false, false, bubble);\r\n }\r\n });\r\n\r\n //this.listenerSetter.add(rootScope)('')\r\n\r\n this.listenerSetter.add(rootScope)('dialog_flush', ({peerId}) => {\r\n if(this.peerId === peerId) {\r\n this.deleteMessagesByIds(Object.keys(this.bubbles).map(m => +m));\r\n }\r\n });\r\n\r\n // Calls when message successfully sent and we have an id\r\n this.listenerSetter.add(rootScope)('message_sent', (e) => {\r\n const {storage, tempId, tempMessage, mid} = e;\r\n\r\n // ! can't use peerId to validate here, because id can be the same in 'scheduled' and 'chat' types\r\n if(this.chat.getMessagesStorage() !== storage) {\r\n return;\r\n }\r\n \r\n //this.log('message_sent', e);\r\n\r\n const mounted = this.getMountedBubble(tempId, tempMessage) || this.getMountedBubble(mid);\r\n if(mounted) {\r\n const message = this.chat.getMessage(mid);\r\n const bubble = mounted.bubble;\r\n //this.bubbles[mid] = bubble;\r\n \r\n /////this.log('message_sent', bubble);\r\n\r\n if(message.replies) {\r\n const repliesElement = bubble.querySelector('replies-element') as RepliesElement;\r\n if(repliesElement) {\r\n repliesElement.message = message;\r\n repliesElement.init();\r\n }\r\n }\r\n\r\n if(message.media?.document && !message.media.document.type) {\r\n const div = bubble.querySelector(`.document-container[data-mid=\"${tempId}\"] .document`);\r\n if(div) {\r\n div.replaceWith(wrapDocument({message}));\r\n }\r\n }\r\n\r\n // set new mids to album items for mediaViewer\r\n if(message.grouped_id) {\r\n const item = (bubble.querySelector(`.grouped-item[data-mid=\"${tempId}\"]`) as HTMLElement) || bubble; // * it can be .document-container\r\n if(item) {\r\n item.dataset.mid = '' + mid;\r\n }\r\n }\r\n\r\n if(message.media?.poll) {\r\n const pollElement = bubble.querySelector('poll-element') as PollElement;\r\n if(pollElement) {\r\n const newPoll = message.media.poll;\r\n pollElement.message = message;\r\n pollElement.setAttribute('poll-id', newPoll.id);\r\n pollElement.setAttribute('message-id', '' + mid);\r\n }\r\n }\r\n\r\n if(message.media?.document) {\r\n const element = bubble.querySelector(`audio-element[data-mid=\"${tempId}\"], .document[data-doc-id=\"${tempId}\"], .media-round[data-mid=\"${tempId}\"]`) as HTMLElement;\r\n if(element) {\r\n if(element instanceof AudioElement || element.classList.contains('media-round')) {\r\n element.dataset.mid = '' + message.mid;\r\n delete element.dataset.isOutgoing;\r\n (element as any).message = message;\r\n (element as any).onLoad(true);\r\n } else {\r\n element.dataset.docId = message.media.document.id;\r\n }\r\n }\r\n }\r\n\r\n /* bubble.classList.remove('is-sending');\r\n bubble.classList.add('is-sent');\r\n bubble.dataset.mid = '' + mid;\r\n\r\n this.bubbleGroups.removeBubble(bubble, tempId); */\r\n\r\n if(message.media?.webpage && !bubble.querySelector('.web')) {\r\n getHeavyAnimationPromise().then(() => {\r\n this.safeRenderMessage(message, true, false, bubble, false);\r\n this.scrollToBubbleIfLast(bubble);\r\n });\r\n /* const mounted = this.getMountedBubble(mid);\r\n if(!mounted) return;\r\n this.renderMessage(mounted.message, true, false, mounted.bubble, false); */\r\n }\r\n \r\n //delete this.bubbles[tempId];\r\n } else {\r\n this.log.warn('message_sent there is no bubble', e);\r\n }\r\n\r\n const bubbles = this.bubbles;\r\n if(bubbles[tempId]) {\r\n const bubble = bubbles[tempId];\r\n bubbles[mid] = bubble;\r\n delete bubbles[tempId];\r\n\r\n //getHeavyAnimationPromise().then(() => {\r\n fastRaf(() => {\r\n if(bubble.classList.contains('is-sending')) {\r\n bubble.classList.remove('is-sending');\r\n bubble.classList.add(this.peerId === rootScope.myId && this.chat.type !== 'scheduled' ? 'is-read' : 'is-sent');\r\n }\r\n });\r\n //});\r\n\r\n bubble.dataset.mid = '' + mid;\r\n }\r\n\r\n if(this.unreadOut.has(tempId)) {\r\n this.unreadOut.delete(tempId);\r\n this.unreadOut.add(mid);\r\n }\r\n\r\n // * check timing of scheduled message\r\n if(this.chat.type === 'scheduled') {\r\n const timestamp = Date.now() / 1000 | 0;\r\n const maxTimestamp = tempMessage.date - 10;\r\n //this.log('scheduled timing:', timestamp, maxTimestamp);\r\n if(timestamp >= maxTimestamp) {\r\n this.deleteMessagesByIds([mid]);\r\n }\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('message_edit', ({storage, peerId, mid}) => {\r\n // fastRaf(() => {\r\n if(storage !== this.chat.getMessagesStorage()) return;\r\n const message = this.chat.getMessage(mid);\r\n const mounted = message.grouped_id ? this.getGroupedBubble(message.grouped_id) : this.getMountedBubble(mid);\r\n if(!mounted) return;\r\n\r\n const updatePosition = this.chat.type === 'scheduled';\r\n const scrolledDown = this.scrolledDown;\r\n this.safeRenderMessage(mounted.message, true, false, mounted.bubble, updatePosition);\r\n if(scrolledDown) {\r\n this.scrollToBubbleIfLast(mounted.bubble);\r\n }\r\n\r\n if(updatePosition) {\r\n (this.messagesQueuePromise || Promise.resolve()).then(() => {\r\n this.deleteEmptyDateGroups();\r\n });\r\n }\r\n // });\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('album_edit', ({peerId, groupId, deletedMids}) => {\r\n //fastRaf(() => { // ! can't use delayed smth here, need original bubble to be edited\r\n if(peerId !== this.peerId) return;\r\n const mids = this.appMessagesManager.getMidsByAlbum(groupId);\r\n const renderedId = mids.concat(deletedMids).find(mid => this.bubbles[mid]);\r\n if(!renderedId) return;\r\n\r\n const renderMaxId = getObjectKeysAndSort(this.appMessagesManager.groupedMessagesStorage[groupId], 'asc').pop();\r\n\r\n this.safeRenderMessage(this.chat.getMessage(renderMaxId), true, false, this.bubbles[renderedId], false);\r\n //});\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('messages_downloaded', ({peerId, mids}) => {\r\n const middleware = this.getMiddleware();\r\n getHeavyAnimationPromise().then(() => {\r\n if(!middleware()) return;\r\n\r\n (mids as number[]).forEach(mid => {\r\n /* const promise = (this.scrollable.scrollLocked && this.scrollable.scrollLockedPromise) || Promise.resolve();\r\n promise.then(() => {\r\n \r\n }); */\r\n forEachReverse(this.needUpdate, (obj, idx) => {\r\n if(obj.replyMid === mid && obj.replyToPeerId === peerId) {\r\n const {mid, replyMid} = this.needUpdate.splice(idx, 1)[0];\r\n \r\n //this.log('messages_downloaded', mid, replyMid, i, this.needUpdate, this.needUpdate.length, mids, this.bubbles[mid]);\r\n const bubble = this.bubbles[mid];\r\n if(!bubble) return;\r\n \r\n const message = this.chat.getMessage(mid);\r\n \r\n const repliedMessage = this.appMessagesManager.getMessageByPeer(obj.replyToPeerId, replyMid);\r\n if(repliedMessage.deleted) { // ! чтобы не пыталось бесконечно загрузить удалённое сообщение\r\n delete message.reply_to_mid; // ! WARNING!\r\n }\r\n \r\n MessageRender.setReply({\r\n chat: this.chat,\r\n bubble,\r\n message\r\n });\r\n }\r\n });\r\n });\r\n });\r\n });\r\n\r\n // attachClickEvent(this.bubblesContainer, this.onBubblesClick, {listenerSetter: this.listenerSetter});\r\n this.listenerSetter.add(this.bubblesContainer)('click', this.onBubblesClick/* , {capture: true, passive: false} */);\r\n\r\n if(DEBUG) {\r\n this.listenerSetter.add(this.bubblesContainer)('dblclick', (e) => {\r\n const bubble = findUpClassName(e.target, 'grouped-item') || findUpClassName(e.target, 'bubble');\r\n if(bubble) {\r\n const mid = +bubble.dataset.mid\r\n this.log('debug message:', this.chat.getMessage(mid));\r\n this.highlightBubble(bubble);\r\n }\r\n });\r\n }\r\n\r\n if(!IS_MOBILE) {\r\n this.listenerSetter.add(this.bubblesContainer)('dblclick', (e) => {\r\n if(this.chat.selection.isSelecting || \r\n !this.appMessagesManager.canSendToPeer(this.peerId, this.chat.threadId)) {\r\n return;\r\n }\r\n \r\n const target = e.target as HTMLElement;\r\n const bubble = target.classList.contains('bubble') ? \r\n target : \r\n (target.classList.contains('document-selection') ? target.parentElement : null);\r\n if(bubble && !bubble.classList.contains('bubble-first')) {\r\n const mid = +bubble.dataset.mid;\r\n const message = this.chat.getMessage(mid);\r\n if(message.pFlags.is_outgoing) {\r\n return;\r\n }\r\n \r\n this.chat.input.initMessageReply(mid);\r\n }\r\n });\r\n }\r\n\r\n /* if(false) */this.stickyIntersector = new StickyIntersector(this.scrollable.container, (stuck, target) => {\r\n for(const timestamp in this.dateMessages) {\r\n const dateMessage = this.dateMessages[timestamp];\r\n if(dateMessage.container === target) {\r\n dateMessage.div.classList.toggle('is-sticky', stuck);\r\n break;\r\n }\r\n }\r\n });\r\n\r\n\r\n let middleware: ReturnType<ChatBubbles['getMiddleware']>;\r\n useHeavyAnimationCheck(() => {\r\n this.isHeavyAnimationInProgress = true;\r\n this.lazyLoadQueue.lock();\r\n middleware = this.getMiddleware();\r\n }, () => {\r\n this.isHeavyAnimationInProgress = false;\r\n\r\n if(middleware && middleware()) {\r\n this.lazyLoadQueue.unlock();\r\n this.lazyLoadQueue.refresh();\r\n }\r\n\r\n middleware = null;\r\n }, this.listenerSetter);\r\n }\r\n\r\n public constructPeerHelpers() {\r\n // will call when message is sent (only 1)\r\n this.listenerSetter.add(rootScope)('history_append', ({storage, mid}) => {\r\n if(storage !== this.chat.getMessagesStorage()) return;\r\n\r\n if(!this.scrollable.loadedAll.bottom) {\r\n this.chat.setMessageId();\r\n } else {\r\n this.renderNewMessagesByIds([mid], true);\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('history_multiappend', (msgIdsByPeer) => {\r\n if(!(this.peerId in msgIdsByPeer)) return;\r\n const msgIds = Array.from(msgIdsByPeer[this.peerId]).slice().sort((a, b) => b - a);\r\n this.renderNewMessagesByIds(msgIds);\r\n });\r\n \r\n this.listenerSetter.add(rootScope)('history_delete', ({peerId, msgs}) => {\r\n if(peerId === this.peerId) {\r\n this.deleteMessagesByIds(Array.from(msgs));\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('dialog_unread', ({peerId}) => {\r\n if(peerId === this.peerId) {\r\n this.chat.input.setUnreadCount();\r\n this.updateUnreadByDialog();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('dialogs_multiupdate', (dialogs) => {\r\n if(dialogs[this.peerId]) {\r\n this.chat.input.setUnreadCount();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('dialog_notify_settings', (dialog) => {\r\n if(this.peerId === dialog.peerId) {\r\n this.chat.input.setUnreadCount();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('chat_update', (chatId) => {\r\n if(this.peerId === -chatId) {\r\n const hadRights = this.chatInner.classList.contains('has-rights');\r\n const hasRights = this.appMessagesManager.canSendToPeer(this.peerId, this.chat.threadId);\r\n\r\n if(hadRights !== hasRights) {\r\n this.finishPeerChange();\r\n this.chat.input.updateMessageInput();\r\n }\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('settings_updated', (e: BroadcastEvents['settings_updated']) => {\r\n if(e.key === 'settings.emoji.big') {\r\n const isScrolledDown = this.scrollable.isScrolledDown;\r\n if(!isScrolledDown) {\r\n this.setMessagesQueuePromise();\r\n }\r\n \r\n const mids = getObjectKeysAndSort(this.bubbles, 'desc');\r\n mids.forEach(mid => {\r\n const bubble = this.bubbles[mid];\r\n if(bubble.classList.contains('can-have-big-emoji')) {\r\n const message = this.chat.getMessage(mid);\r\n this.safeRenderMessage(message, undefined, false, bubble);\r\n // this.bubbleGroups.addBubble(bubble, message, false);\r\n }\r\n });\r\n\r\n if(isScrolledDown) {\r\n this.scrollable.scrollTop = 99999;\r\n } else {\r\n this.performHistoryResult([], true, false, undefined);\r\n }\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('message_views', ({peerId, views, mid}) => {\r\n if(this.peerId !== peerId) return;\r\n\r\n fastRaf(() => {\r\n const bubble = this.bubbles[mid];\r\n if(!bubble) return;\r\n\r\n const postViewsElements = Array.from(bubble.querySelectorAll('.post-views')) as HTMLElement[];\r\n if(postViewsElements.length) {\r\n const str = formatNumber(views, 1);\r\n let different = false;\r\n postViewsElements.forEach(postViews => {\r\n if(different || postViews.innerHTML !== str) {\r\n different = true;\r\n postViews.innerHTML = str;\r\n }\r\n });\r\n }\r\n });\r\n });\r\n\r\n this.unreadedObserver = new IntersectionObserver((entries) => {\r\n entries.forEach(entry => {\r\n if(entry.isIntersecting) {\r\n const target = entry.target as HTMLElement;\r\n const mid = this.unreaded.get(target as HTMLElement);\r\n this.onUnreadedInViewport(target, mid);\r\n }\r\n });\r\n });\r\n\r\n this.viewsObserver = new IntersectionObserver((entries) => {\r\n entries.forEach(entry => {\r\n if(entry.isIntersecting) {\r\n this.viewsMids.add(+(entry.target as HTMLElement).dataset.mid);\r\n this.viewsObserver.unobserve(entry.target);\r\n this.sendViewCountersDebounced();\r\n }\r\n });\r\n });\r\n\r\n this.sendViewCountersDebounced = debounce(() => {\r\n const mids = [...this.viewsMids];\r\n this.viewsMids.clear();\r\n\r\n this.appMessagesManager.incrementMessageViews(this.peerId, mids);\r\n }, 1000, false, true);\r\n\r\n if('ResizeObserver' in window) {\r\n let wasHeight = this.scrollable.container.offsetHeight;\r\n let resizing = false;\r\n let skip = false;\r\n let scrolled = 0;\r\n let part = 0;\r\n let rAF = 0;\r\n\r\n const onResizeEnd = () => {\r\n const height = this.scrollable.container.offsetHeight;\r\n const isScrolledDown = this.scrollable.isScrolledDown;\r\n if(height !== wasHeight && (!skip || !isScrolledDown)) { // * fix opening keyboard while ESG is active, offsetHeight will change right between 'start' and this first frame\r\n part += wasHeight - height;\r\n }\r\n\r\n /* if(DEBUG) {\r\n this.log('resize end', scrolled, part, this.scrollable.scrollTop, height, wasHeight, this.scrollable.isScrolledDown);\r\n } */\r\n\r\n if(part) {\r\n this.scrollable.scrollTop += Math.round(part);\r\n }\r\n\r\n wasHeight = height;\r\n scrolled = 0;\r\n rAF = 0;\r\n part = 0;\r\n resizing = false;\r\n skip = false;\r\n };\r\n\r\n const setEndRAF = (single: boolean) => {\r\n if(rAF) window.cancelAnimationFrame(rAF);\r\n rAF = window.requestAnimationFrame(single ? onResizeEnd : () => {\r\n rAF = window.requestAnimationFrame(onResizeEnd);\r\n //this.log('resize after RAF', part);\r\n });\r\n };\r\n\r\n const processEntries = (entries: any) => {\r\n if(skip) {\r\n setEndRAF(false);\r\n return;\r\n }\r\n\r\n const entry = entries[0];\r\n const height = entry.contentRect.height;/* Math.ceil(entry.contentRect.height); */\r\n \r\n if(!wasHeight) {\r\n wasHeight = height;\r\n return;\r\n }\r\n\r\n const realDiff = wasHeight - height;\r\n let diff = realDiff + part;\r\n const _part = diff % 1;\r\n diff -= _part;\r\n \r\n if(!resizing) {\r\n resizing = true;\r\n\r\n /* if(DEBUG) {\r\n this.log('resize start', realDiff, this.scrollable.scrollTop, this.scrollable.container.offsetHeight, this.scrollable.isScrolledDown);\r\n } */\r\n\r\n if(realDiff < 0 && this.scrollable.isScrolledDown) {\r\n //if(isSafari) { // * fix opening keyboard while ESG is active \r\n part = -realDiff;\r\n //}\r\n\r\n skip = true;\r\n setEndRAF(false);\r\n return;\r\n }\r\n }\r\n\r\n scrolled += diff;\r\n\r\n /* if(DEBUG) {\r\n this.log('resize', wasHeight - height, diff, this.scrollable.container.offsetHeight, this.scrollable.isScrolledDown, height, wasHeight);\r\n } */\r\n\r\n if(diff) {\r\n const needScrollTop = this.scrollable.scrollTop + diff;\r\n this.scrollable.scrollTop = needScrollTop;\r\n }\r\n \r\n setEndRAF(false);\r\n\r\n part = _part;\r\n wasHeight = height;\r\n };\r\n\r\n // @ts-ignore\r\n const resizeObserver = new ResizeObserver(processEntries);\r\n resizeObserver.observe(this.bubblesContainer);\r\n }\r\n }\r\n\r\n public getRenderedLength() {\r\n return Object.keys(this.bubbles).length - this.skippedMids.size;\r\n }\r\n\r\n private onUnreadedInViewport(target: HTMLElement, mid: number) {\r\n this.unreadedSeen.add(mid);\r\n this.unreadedObserver.unobserve(target);\r\n this.unreaded.delete(target);\r\n this.readUnreaded();\r\n }\r\n\r\n private readUnreaded() {\r\n if(this.readPromise) return;\r\n\r\n const middleware = this.getMiddleware();\r\n this.readPromise = rootScope.idle.focusPromise.then(() => {\r\n if(!middleware()) return;\r\n let maxId = Math.max(...Array.from(this.unreadedSeen));\r\n\r\n // ? if message with maxId is not rendered ?\r\n if(this.scrollable.loadedAll.bottom) {\r\n const bubblesMaxId = Math.max(...Object.keys(this.bubbles).map(i => +i));\r\n if(maxId >= bubblesMaxId) {\r\n maxId = Math.max(this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId).maxId || 0, maxId);\r\n }\r\n }\r\n\r\n this.unreaded.forEach((mid, target) => {\r\n if(mid <= maxId) {\r\n this.onUnreadedInViewport(target, mid);\r\n }\r\n });\r\n\r\n const readContents: number[] = [];\r\n for(const mid of this.unreadedSeen) {\r\n const message: MyMessage = this.chat.getMessage(mid);\r\n if(this.appMessagesManager.isMentionUnread(message)) {\r\n readContents.push(mid);\r\n }\r\n }\r\n\r\n this.appMessagesManager.readMessages(this.peerId, readContents);\r\n\r\n this.unreadedSeen.clear();\r\n\r\n if(DEBUG) {\r\n this.log('will readHistory by maxId:', maxId);\r\n }\r\n\r\n // return;\r\n \r\n return this.appMessagesManager.readHistory(this.peerId, maxId, this.chat.threadId).catch((err: any) => {\r\n this.log.error('readHistory err:', err);\r\n this.appMessagesManager.readHistory(this.peerId, maxId, this.chat.threadId);\r\n }).finally(() => {\r\n if(!middleware()) return;\r\n this.readPromise = undefined;\r\n\r\n if(this.unreadedSeen.size) {\r\n this.readUnreaded();\r\n }\r\n });\r\n });\r\n }\r\n\r\n public constructPinnedHelpers() {\r\n this.listenerSetter.add(rootScope)('peer_pinned_messages', (e) => {\r\n const {peerId, mids, pinned} = e;\r\n if(peerId !== this.peerId) return;\r\n\r\n if(mids) {\r\n if(!pinned) {\r\n this.deleteMessagesByIds(mids);\r\n }\r\n }\r\n });\r\n }\r\n\r\n public constructScheduledHelpers() {\r\n const onUpdate = () => {\r\n this.chat.topbar.setTitle(this.appMessagesManager.getScheduledMessagesStorage(this.peerId).size);\r\n };\r\n\r\n this.listenerSetter.add(rootScope)('scheduled_new', ({peerId, mid}) => {\r\n if(peerId !== this.peerId) return;\r\n\r\n this.renderNewMessagesByIds([mid]);\r\n onUpdate();\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('scheduled_delete', ({peerId, mids}) => {\r\n if(peerId !== this.peerId) return;\r\n\r\n this.deleteMessagesByIds(mids);\r\n onUpdate();\r\n });\r\n }\r\n\r\n public onBubblesClick = (e: Event) => {\r\n let target = e.target as HTMLElement;\r\n let bubble: HTMLElement = null;\r\n try {\r\n bubble = findUpClassName(target, 'bubble');\r\n } catch(err) {}\r\n \r\n if(!bubble) return;\r\n\r\n if(bubble.classList.contains('is-date') && findUpClassName(target, 'bubble-content')) {\r\n if(bubble.classList.contains('is-sticky') && !this.chatInner.classList.contains('is-scrolling')) {\r\n return;\r\n }\r\n\r\n for(const timestamp in this.dateMessages) {\r\n const d = this.dateMessages[timestamp];\r\n if(d.div === bubble) {\r\n new PopupDatePicker(new Date(+timestamp), this.onDatePick).show();\r\n break;\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n if(!IS_TOUCH_SUPPORTED && findUpClassName(target, 'time')) {\r\n this.chat.selection.toggleByElement(bubble);\r\n return;\r\n }\r\n\r\n // ! Trusted - due to audio autoclick\r\n if(this.chat.selection.isSelecting && e.isTrusted) {\r\n if(bubble.classList.contains('service') && bubble.dataset.mid === undefined) {\r\n return;\r\n }\r\n\r\n cancelEvent(e);\r\n //console.log('bubble click', e);\r\n\r\n if(IS_TOUCH_SUPPORTED && this.chat.selection.selectedText) {\r\n this.chat.selection.selectedText = undefined;\r\n return;\r\n }\r\n\r\n //this.chatSelection.toggleByBubble(bubble);\r\n this.chat.selection.toggleByElement(findUpClassName(target, 'grouped-item') || bubble);\r\n return;\r\n }\r\n\r\n const contactDiv: HTMLElement = findUpClassName(target, 'contact');\r\n if(contactDiv) {\r\n this.chat.appImManager.setInnerPeer(+contactDiv.dataset.peerId);\r\n return;\r\n }\r\n\r\n const commentsDiv: HTMLElement = findUpClassName(target, 'replies');\r\n if(commentsDiv) {\r\n const bubbleMid = +bubble.dataset.mid;\r\n if(this.peerId === REPLIES_PEER_ID) {\r\n const message = this.chat.getMessage(bubbleMid) as Message.message;\r\n const peerId = this.appPeersManager.getPeerId(message.reply_to.reply_to_peer_id);\r\n const threadId = message.reply_to.reply_to_top_id;\r\n const lastMsgId = message.fwd_from.saved_from_msg_id;\r\n this.chat.appImManager.openThread(peerId, lastMsgId, threadId);\r\n } else {\r\n const message = this.appMessagesManager.filterMessages(this.chat.getMessage(bubbleMid), message => !!(message as Message.message).replies)[0] as Message.message;\r\n const replies = message.replies;\r\n if(replies) {\r\n this.appMessagesManager.getDiscussionMessage(this.peerId, message.mid).then(message => {\r\n this.chat.appImManager.setInnerPeer(-replies.channel_id, undefined, 'discussion', (message as MyMessage).mid);\r\n });\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n const nameDiv = findUpClassName(target, 'peer-title') || findUpClassName(target, 'name') || findUpTag(target, 'AVATAR-ELEMENT');\r\n if(nameDiv) {\r\n target = nameDiv || target;\r\n const peerId = +(target.dataset.peerId || target.getAttribute('peer'));\r\n const savedFrom = target.dataset.savedFrom;\r\n if(nameDiv.classList.contains('is-via')) {\r\n const message = '@' + this.appUsersManager.getUser(peerId).username + ' ';\r\n this.appDraftsManager.setDraft(this.peerId, this.chat.threadId, message);\r\n cancelEvent(e);\r\n } else if(savedFrom) {\r\n const splitted = savedFrom.split('_');\r\n const peerId = +splitted[0];\r\n const msgId = +splitted[1];\r\n\r\n this.chat.appImManager.setInnerPeer(peerId, msgId);\r\n } else {\r\n if(peerId) {\r\n this.chat.appImManager.setInnerPeer(peerId);\r\n } else {\r\n toast(I18n.format('HidAccount', true));\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n //this.log('chatInner click:', target);\r\n const isVideoComponentElement = target.tagName === 'SPAN' && !target.classList.contains('emoji');\r\n /* if(isVideoComponentElement) {\r\n const video = target.parentElement.querySelector('video') as HTMLElement;\r\n if(video) {\r\n video.click(); // hot-fix for time and play button\r\n return;\r\n }\r\n } */\r\n\r\n if(bubble.classList.contains('sticker') && target.parentElement.classList.contains('attachment')) {\r\n const messageId = +bubble.dataset.mid;\r\n const message = this.chat.getMessage(messageId);\r\n\r\n const doc = message.media?.document;\r\n\r\n if(doc?.stickerSetInput) {\r\n new PopupStickers(doc.stickerSetInput).show();\r\n }\r\n\r\n return;\r\n }\r\n\r\n const documentDiv = findUpClassName(target, 'document-with-thumb');\r\n if((target.tagName === 'IMG' && !target.classList.contains('emoji') && !target.classList.contains('document-thumb')) \r\n || target.classList.contains('album-item')\r\n || isVideoComponentElement\r\n || (target.tagName === 'VIDEO' && !bubble.classList.contains('round'))\r\n || (documentDiv && !documentDiv.querySelector('.preloader-container'))) {\r\n const groupedItem = findUpClassName(target, 'album-item') || findUpClassName(target, 'document-container');\r\n const messageId = +(groupedItem || bubble).dataset.mid;\r\n const message = this.chat.getMessage(messageId);\r\n if(!message) {\r\n this.log.warn('no message by messageId:', messageId);\r\n return;\r\n }\r\n\r\n const f = documentDiv ? (media: any) => {\r\n return AppMediaViewer.isMediaCompatibleForDocumentViewer(media);\r\n } : (media: any) => {\r\n return media._ === 'photo' || ['video', 'gif'].includes(media.type);\r\n };\r\n\r\n const targets: {element: HTMLElement, mid: number, peerId: number}[] = [];\r\n const ids = Object.keys(this.bubbles).map(k => +k).filter(id => {\r\n //if(!this.scrollable.visibleElements.find(e => e.element === this.bubbles[id])) return false;\r\n\r\n const message = this.chat.getMessage(id);\r\n const media = this.appMessagesManager.getMediaFromMessage(message);\r\n \r\n return media && f(media);\r\n }).sort((a, b) => a - b);\r\n\r\n ids.forEach(id => {\r\n let selector: string;\r\n if(documentDiv) {\r\n selector = '.document-container';\r\n } else {\r\n const withTail = this.bubbles[id].classList.contains('with-media-tail');\r\n selector = '.album-item video, .album-item img, .preview video, .preview img, ';\r\n if(withTail) {\r\n selector += '.bubble__media-container';\r\n } else {\r\n selector += '.attachment video, .attachment img';\r\n }\r\n }\r\n\r\n const elements = Array.from(this.bubbles[id].querySelectorAll(selector)) as HTMLElement[];\r\n const parents: Set<HTMLElement> = new Set();\r\n if(documentDiv) {\r\n elements.forEach((element) => {\r\n targets.push({\r\n element: element.querySelector('.document-ico'),\r\n mid: +element.dataset.mid,\r\n peerId: this.peerId\r\n });\r\n });\r\n } else {\r\n const hasAspecter = !!this.bubbles[id].querySelector('.media-container-aspecter');\r\n elements.forEach((element) => {\r\n if(hasAspecter && !findUpClassName(element, 'media-container-aspecter')) return;\r\n let albumItem = findUpClassName(element, 'album-item');\r\n const parent = albumItem || element.parentElement;\r\n if(parents.has(parent)) return;\r\n parents.add(parent);\r\n targets.push({\r\n element,\r\n mid: albumItem ? +albumItem.dataset.mid : id,\r\n peerId: this.peerId\r\n });\r\n });\r\n }\r\n });\r\n\r\n targets.sort((a, b) => a.mid - b.mid);\r\n\r\n let idx = targets.findIndex(t => t.mid === messageId);\r\n\r\n if(DEBUG) {\r\n this.log('open mediaViewer single with ids:', ids, idx, targets);\r\n }\r\n\r\n if(!targets[idx]) {\r\n this.log('no target for media viewer!', target);\r\n return;\r\n }\r\n\r\n new AppMediaViewer()\r\n .setSearchContext({\r\n threadId: this.chat.threadId,\r\n peerId: this.peerId,\r\n inputFilter: {_: documentDiv ? 'inputMessagesFilterDocument' : 'inputMessagesFilterPhotoVideo'},\r\n useSearch: this.chat.type !== 'scheduled',\r\n isScheduled: this.chat.type === 'scheduled'\r\n })\r\n .openMedia(message, targets[idx].element, 0, true, targets.slice(0, idx), targets.slice(idx + 1));\r\n \r\n cancelEvent(e);\r\n //appMediaViewer.openMedia(message, target as HTMLImageElement);\r\n return;\r\n }\r\n \r\n if(['IMG', 'DIV', 'SPAN'/* , 'A' */].indexOf(target.tagName) === -1) target = findUpTag(target, 'DIV');\r\n \r\n if(['DIV', 'SPAN'].indexOf(target.tagName) !== -1/* || target.tagName === 'A' */) {\r\n if(target.classList.contains('goto-original')) {\r\n const savedFrom = bubble.dataset.savedFrom;\r\n const splitted = savedFrom.split('_');\r\n const peerId = +splitted[0];\r\n const msgId = +splitted[1];\r\n ////this.log('savedFrom', peerId, msgID);\r\n this.chat.appImManager.setInnerPeer(peerId, msgId);\r\n return;\r\n } else if(target.classList.contains('forward')) {\r\n const mid = +bubble.dataset.mid;\r\n const message = this.appMessagesManager.getMessageByPeer(this.peerId, mid);\r\n new PopupForward({\r\n [this.peerId]: this.appMessagesManager.getMidsByMessage(message)\r\n });\r\n //appSidebarRight.forwardTab.open([mid]);\r\n return;\r\n }\r\n \r\n let isReplyClick = false;\r\n \r\n try {\r\n isReplyClick = !!findUpClassName(e.target, 'reply');\r\n } catch(err) {}\r\n \r\n if(isReplyClick && bubble.classList.contains('is-reply')/* || bubble.classList.contains('forwarded') */) {\r\n const bubbleMid = +bubble.dataset.mid;\r\n this.replyFollowHistory.push(bubbleMid);\r\n\r\n const message = this.chat.getMessage(bubbleMid) as Message.message;\r\n\r\n const replyToPeerId = message.reply_to.reply_to_peer_id ? this.appPeersManager.getPeerId(message.reply_to.reply_to_peer_id) : this.peerId;\r\n const replyToMid = message.reply_to.reply_to_msg_id;\r\n\r\n this.chat.appImManager.setInnerPeer(replyToPeerId, replyToMid, this.chat.type, this.chat.threadId);\r\n\r\n /* if(this.chat.type === 'discussion') {\r\n this.chat.appImManager.setMessageId(, originalMessageId);\r\n } else {\r\n this.chat.appImManager.setInnerPeer(this.peerId, originalMessageId);\r\n } */\r\n //this.chat.setMessageId(, originalMessageId);\r\n }\r\n }\r\n \r\n //console.log('chatInner click', e);\r\n };\r\n\r\n public onGoDownClick() {\r\n if(this.replyFollowHistory.length) {\r\n forEachReverse(this.replyFollowHistory, (mid, idx) => {\r\n const bubble = this.bubbles[mid];\r\n let bad = true;\r\n if(bubble) {\r\n const rect = bubble.getBoundingClientRect();\r\n bad = (windowSize.windowH / 2) > rect.top;\r\n } else {\r\n const message = this.chat.getMessage(mid);\r\n if(!message.deleted) {\r\n bad = false;\r\n }\r\n }\r\n \r\n if(bad) {\r\n this.replyFollowHistory.splice(idx, 1);\r\n }\r\n });\r\n\r\n this.replyFollowHistory.sort((a, b) => b - a);\r\n\r\n const mid = this.replyFollowHistory.pop();\r\n this.chat.setMessageId(mid);\r\n } else {\r\n this.chat.setMessageId(/* , dialog.top_message */);\r\n // const dialog = this.appMessagesManager.getDialogByPeerId(this.peerId)[0];\r\n \r\n // if(dialog) {\r\n // this.chat.setPeer(this.peerId/* , dialog.top_message */);\r\n // } else {\r\n // this.log('will scroll down 3');\r\n // this.scroll.scrollTop = this.scroll.scrollHeight;\r\n // }\r\n }\r\n }\r\n\r\n public getBubbleByPoint(verticalSide: 'top' | 'bottom') {\r\n let element = getElementByPoint(this.scrollable.container, verticalSide, 'center');\r\n /* if(element) {\r\n if(element.classList.contains('bubbles-date-group')) {\r\n const children = Array.from(element.children) as HTMLElement[];\r\n if(verticalSide === 'top') {\r\n element = children[this.stickyIntersector ? 2 : 1];\r\n } else {\r\n element = children[children.length - 1];\r\n }\r\n } else {\r\n element = findUpClassName(element, 'bubble');\r\n if(element && element.classList.contains('is-date')) {\r\n element = element.nextElementSibling as HTMLElement;\r\n }\r\n }\r\n } */\r\n if(element) element = findUpClassName(element, 'bubble');\r\n\r\n return element;\r\n }\r\n\r\n public getGroupedBubble(groupId: string) {\r\n const group = this.appMessagesManager.groupedMessagesStorage[groupId];\r\n for(const [mid] of group) {\r\n if(this.bubbles[mid]) {\r\n const maxId = Math.max(...group.keys()); // * because in scheduled album can be rendered by lowest mid during sending\r\n return {\r\n bubble: this.bubbles[mid], \r\n mid: +mid,\r\n message: this.chat.getMessage(maxId)\r\n };\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n public getBubbleGroupedItems(bubble: HTMLElement) {\r\n return Array.from(bubble.querySelectorAll('.grouped-item')) as HTMLElement[];\r\n }\r\n\r\n public getMountedBubble(mid: number, message = this.chat.getMessage(mid)) {\r\n if(message.grouped_id && this.appMessagesManager.getMidsByAlbum(message.grouped_id).length > 1) {\r\n const a = this.getGroupedBubble(message.grouped_id);\r\n if(a) {\r\n a.bubble = a.bubble.querySelector(`.document-container[data-mid=\"${mid}\"]`) || a.bubble;\r\n return a;\r\n }\r\n }\r\n\r\n const bubble = this.bubbles[mid];\r\n if(!bubble) return;\r\n\r\n return {bubble, mid, message};\r\n }\r\n\r\n private findNextMountedBubbleByMsgId(mid: number) {\r\n return this.bubbles[getObjectKeysAndSort(this.bubbles).find(id => {\r\n if(id < mid) return false;\r\n return !!this.bubbles[id]?.parentElement;\r\n })];\r\n }\r\n\r\n public loadMoreHistory(top: boolean, justLoad = false) {\r\n //this.log('loadMoreHistory', top);\r\n if(!this.peerId || \r\n /* TEST_SCROLL || */ \r\n this.chat.setPeerPromise || \r\n this.isHeavyAnimationInProgress || \r\n (top && (this.getHistoryTopPromise || this.scrollable.loadedAll.top)) || \r\n (!top && (this.getHistoryBottomPromise || this.scrollable.loadedAll.bottom))\r\n ) {\r\n return;\r\n }\r\n\r\n // warning, если иды только отрицательные то вниз не попадёт (хотя мб и так не попадёт)\r\n const history = Object.keys(this.bubbles).map(id => +id).sort((a, b) => a - b);\r\n if(!history.length) return;\r\n \r\n if(top) {\r\n if(DEBUG) {\r\n this.log('Will load more (up) history by id:', history[0], 'maxId:', history[history.length - 1], justLoad/* , history */);\r\n }\r\n\r\n /* if(history.length === 75) {\r\n this.log('load more', this.scrollable.scrollHeight, this.scrollable.scrollTop, this.scrollable);\r\n return;\r\n } */\r\n /* false && */this.getHistory(history[0], true, undefined, undefined, justLoad);\r\n } else {\r\n //let dialog = this.appMessagesManager.getDialogByPeerId(this.peerId)[0];\r\n const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);\r\n \r\n // if scroll down after search\r\n if(history.indexOf(historyStorage.maxId) !== -1) {\r\n this.setLoaded('bottom', true);\r\n return;\r\n }\r\n\r\n if(DEBUG) {\r\n this.log('Will load more (down) history by id:', history[history.length - 1], justLoad/* , history */);\r\n }\r\n\r\n /* false && */this.getHistory(history[history.length - 1], false, true, undefined, justLoad);\r\n }\r\n }\r\n\r\n public onScroll = () => {\r\n //return;\r\n \r\n // * В таком случае, кнопка не будет моргать если чат в самом низу, и правильно отработает случай написания нового сообщения и проскролла вниз\r\n if(this.isHeavyAnimationInProgress && this.scrolledDown) return;\r\n //lottieLoader.checkAnimations(false, 'chat');\r\n\r\n if(!IS_TOUCH_SUPPORTED) {\r\n if(this.isScrollingTimeout) {\r\n clearTimeout(this.isScrollingTimeout);\r\n } else if(!this.chatInner.classList.contains('is-scrolling')) {\r\n this.chatInner.classList.add('is-scrolling');\r\n }\r\n \r\n this.isScrollingTimeout = window.setTimeout(() => {\r\n this.chatInner.classList.remove('is-scrolling');\r\n this.isScrollingTimeout = 0;\r\n }, 1350);\r\n }\r\n \r\n if(this.scrollable.getDistanceToEnd() < 300 && this.scrollable.loadedAll.bottom) {\r\n this.bubblesContainer.classList.add('scrolled-down');\r\n this.scrolledDown = true;\r\n } else if(this.bubblesContainer.classList.contains('scrolled-down')) {\r\n this.bubblesContainer.classList.remove('scrolled-down');\r\n this.scrolledDown = false;\r\n }\r\n\r\n if(this.chat.topbar.pinnedMessage) {\r\n this.chat.topbar.pinnedMessage.setCorrectIndex(this.scrollable.lastScrollDirection);\r\n }\r\n };\r\n\r\n public setScroll() {\r\n this.scrollable = new Scrollable(null, 'IM', /* 10300 */300);\r\n this.setLoaded('top', false);\r\n this.setLoaded('bottom', false);\r\n\r\n this.scrollable.container.append(this.chatInner);\r\n\r\n /* const getScrollOffset = () => {\r\n //return Math.round(Math.max(300, appPhotosManager.windowH / 1.5));\r\n return 300; \r\n };\r\n\r\n window.addEventListener('resize', () => {\r\n this.scrollable.onScrollOffset = getScrollOffset();\r\n });\r\n\r\n this.scrollable = new Scrollable(this.bubblesContainer, 'y', 'IM', this.chatInner, getScrollOffset()); */\r\n\r\n this.scrollable.onAdditionalScroll = this.onScroll;\r\n this.scrollable.onScrolledTop = () => this.loadMoreHistory(true);\r\n this.scrollable.onScrolledBottom = () => this.loadMoreHistory(false);\r\n //this.scrollable.attachSentinels(undefined, 300);\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n this.scrollable.container.addEventListener('touchmove', () => {\r\n if(this.isScrollingTimeout) {\r\n clearTimeout(this.isScrollingTimeout);\r\n } else if(!this.chatInner.classList.contains('is-scrolling')) {\r\n this.chatInner.classList.add('is-scrolling');\r\n }\r\n }, {passive: true});\r\n\r\n this.scrollable.container.addEventListener('touchend', () => {\r\n if(!this.chatInner.classList.contains('is-scrolling')) {\r\n return;\r\n }\r\n\r\n if(this.isScrollingTimeout) {\r\n clearTimeout(this.isScrollingTimeout);\r\n }\r\n\r\n this.isScrollingTimeout = window.setTimeout(() => {\r\n this.chatInner.classList.remove('is-scrolling');\r\n this.isScrollingTimeout = 0;\r\n }, 1350);\r\n }, {passive: true});\r\n }\r\n }\r\n\r\n public updateUnreadByDialog() {\r\n const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);\r\n const maxId = this.peerId === rootScope.myId ? historyStorage.readMaxId : historyStorage.readOutboxMaxId;\r\n \r\n ///////this.log('updateUnreadByDialog', maxId, dialog, this.unreadOut);\r\n \r\n for(const msgId of this.unreadOut) {\r\n if(msgId > 0 && msgId <= maxId) {\r\n const bubble = this.bubbles[msgId];\r\n if(bubble) {\r\n bubble.classList.remove('is-sent', 'is-sending'); // is-sending can be when there are bulk of updates (e.g. sending command to Stickers bot)\r\n bubble.classList.add('is-read');\r\n }\r\n \r\n this.unreadOut.delete(msgId);\r\n }\r\n }\r\n }\r\n \r\n public deleteMessagesByIds(mids: number[], permanent = true) {\r\n mids.forEach(mid => {\r\n if(!(mid in this.bubbles)) return;\r\n \r\n /* const mounted = this.getMountedBubble(mid);\r\n if(!mounted) return; */\r\n\r\n const bubble = this.bubbles[mid];\r\n delete this.bubbles[mid];\r\n this.skippedMids.delete(mid);\r\n\r\n if(this.firstUnreadBubble === bubble) {\r\n this.firstUnreadBubble = null;\r\n }\r\n\r\n this.bubbleGroups.removeBubble(bubble);\r\n if(this.unreadedObserver) {\r\n this.unreadedObserver.unobserve(bubble);\r\n this.unreaded.delete(bubble);\r\n }\r\n if(this.viewsObserver) {\r\n this.viewsObserver.unobserve(bubble);\r\n this.viewsMids.delete(mid);\r\n }\r\n //this.unreaded.findAndSplice(mid => mid === id);\r\n bubble.remove();\r\n //bubble.remove();\r\n\r\n if(this.emptyPlaceholderMid === mid) {\r\n this.emptyPlaceholderMid = undefined;\r\n }\r\n });\r\n\r\n if(permanent && this.chat.selection.isSelecting) {\r\n this.chat.selection.deleteSelectedMids(this.peerId, mids);\r\n }\r\n \r\n animationIntersector.checkAnimations(false, CHAT_ANIMATION_GROUP);\r\n this.deleteEmptyDateGroups();\r\n }\r\n \r\n public renderNewMessagesByIds(mids: number[], scrolledDown = this.scrolledDown) {\r\n if(!this.scrollable.loadedAll.bottom) { // seems search active or sliced\r\n //this.log('renderNewMessagesByIds: seems search is active, skipping render:', mids);\r\n return;\r\n }\r\n\r\n if(this.chat.threadId) {\r\n mids = mids.filter(mid => {\r\n const message = this.chat.getMessage(mid);\r\n const replyTo = message.reply_to as MessageReplyHeader;\r\n return replyTo && (replyTo.reply_to_top_id || replyTo.reply_to_msg_id) === this.chat.threadId;\r\n });\r\n }\r\n\r\n mids = mids.filter(mid => !this.bubbles[mid]);\r\n // ! should scroll even without new messages\r\n /* if(!mids.length) {\r\n return;\r\n } */\r\n\r\n if(!scrolledDown) {\r\n if(this.scrollingToBubble && this.scrollingToBubble === this.getLastBubble()) {\r\n scrolledDown = true;\r\n }\r\n }\r\n\r\n const promise = this.performHistoryResult(mids, false, true);\r\n if(scrolledDown) {\r\n promise.then(() => {\r\n //this.log('renderNewMessagesByIDs: messagesQueuePromise after', this.scrollable.isScrolledDown);\r\n //this.scrollable.scrollTo(this.scrollable.scrollHeight, 'top', true, true, 5000);\r\n //const bubble = this.bubbles[Math.max(...mids)];\r\n\r\n let bubble: HTMLElement;\r\n if(this.chat.type === 'scheduled') {\r\n bubble = this.bubbles[Math.max(...mids)];\r\n }\r\n\r\n this.scrollToBubbleEnd(bubble);\r\n\r\n //this.scrollable.scrollIntoViewNew(this.chatInner, 'end');\r\n\r\n /* setTimeout(() => {\r\n this.log('messagesQueuePromise afterafter:', this.chatInner.childElementCount, this.scrollable.scrollHeight);\r\n }, 10); */\r\n });\r\n }\r\n }\r\n\r\n public getLastBubble() {\r\n const lastDateGroup = this.getLastDateGroup();\r\n if(lastDateGroup) {\r\n return lastDateGroup.lastElementChild as HTMLElement;\r\n }\r\n }\r\n\r\n public scrollToBubble(\r\n element: HTMLElement, \r\n position: ScrollLogicalPosition,\r\n forceDirection?: FocusDirection,\r\n forceDuration?: number\r\n ) {\r\n // * 4 = .25rem\r\n const bubble = findUpClassName(element, 'bubble');\r\n\r\n // * if it's a start, then scroll to start of the group\r\n if(position === 'center' && whichChild(bubble) === (this.stickyIntersector ? 2 : 1)) {\r\n const dateGroup = bubble.parentElement;\r\n if(whichChild(dateGroup) === 0) {\r\n element = dateGroup;\r\n position = 'start';\r\n }\r\n }\r\n\r\n return this.scrollable.scrollIntoViewNew(element, position, 4, undefined, forceDirection, forceDuration);\r\n }\r\n\r\n public scrollToBubbleEnd(bubble = this.getLastBubble()) {\r\n /* if(DEBUG) {\r\n this.log('scrollToNewLastBubble: will scroll into view:', bubble);\r\n } */\r\n\r\n if(bubble) {\r\n this.scrollingToBubble = bubble;\r\n const middleware = this.getMiddleware();\r\n this.scrollToBubble(bubble, 'end').then(() => {\r\n if(!middleware()) return;\r\n this.scrollingToBubble = undefined;\r\n });\r\n }\r\n }\r\n\r\n // ! can't get it by chatInner.lastElementChild because placeholder can be the last...\r\n private getLastDateGroup() {\r\n let lastTime = 0, lastElem: HTMLElement;\r\n for(const i in this.dateMessages) {\r\n const dateMessage = this.dateMessages[i];\r\n if(dateMessage.firstTimestamp > lastTime) {\r\n lastElem = dateMessage.container;\r\n lastTime = dateMessage.firstTimestamp;\r\n }\r\n }\r\n\r\n return lastElem;\r\n }\r\n\r\n public scrollToBubbleIfLast(bubble: HTMLElement) {\r\n if(bubble.parentElement.lastElementChild === bubble && \r\n this.getLastDateGroup().parentElement.lastElementChild === bubble.parentElement) {\r\n this.scrollToBubbleEnd(bubble);\r\n }\r\n }\r\n\r\n public highlightBubble(element: HTMLElement) {\r\n const datasetKey = 'highlightTimeout';\r\n if(element.dataset[datasetKey]) {\r\n clearTimeout(+element.dataset[datasetKey]);\r\n element.classList.remove('is-highlighted');\r\n void element.offsetWidth; // reflow\r\n }\r\n\r\n element.classList.add('is-highlighted');\r\n element.dataset[datasetKey] = '' + setTimeout(() => {\r\n element.classList.remove('is-highlighted');\r\n delete element.dataset[datasetKey];\r\n }, 2000);\r\n }\r\n\r\n public getDateContainerByMessage(message: any, reverse: boolean) {\r\n const date = new Date(message.date * 1000);\r\n date.setHours(0, 0, 0);\r\n const dateTimestamp = date.getTime();\r\n if(!this.dateMessages[dateTimestamp]) {\r\n let dateElement: HTMLElement;\r\n \r\n const today = new Date();\r\n today.setHours(0, 0, 0, 0);\r\n\r\n const isScheduled = this.chat.type === 'scheduled';\r\n \r\n if(today.getTime() === date.getTime()) {\r\n dateElement = i18n(isScheduled ? 'Chat.Date.ScheduledForToday' : 'Date.Today');\r\n } else if(isScheduled && message.date === SEND_WHEN_ONLINE_TIMESTAMP) {\r\n dateElement = i18n('MessageScheduledUntilOnline');\r\n } else {\r\n const options: Intl.DateTimeFormatOptions = {\r\n day: 'numeric',\r\n month: 'long'\r\n };\r\n\r\n if(date.getFullYear() !== today.getFullYear()) {\r\n options.year = 'numeric';\r\n }\r\n\r\n dateElement = new I18n.IntlDateElement({\r\n date,\r\n options\r\n }).element;\r\n\r\n if(isScheduled) {\r\n dateElement = i18n('Chat.Date.ScheduledFor', [dateElement]);\r\n }\r\n }\r\n \r\n const bubble = document.createElement('div');\r\n bubble.className = 'bubble service is-date';\r\n const bubbleContent = document.createElement('div');\r\n bubbleContent.classList.add('bubble-content');\r\n const serviceMsg = document.createElement('div');\r\n serviceMsg.classList.add('service-msg');\r\n\r\n serviceMsg.append(dateElement);\r\n\r\n bubbleContent.append(serviceMsg);\r\n bubble.append(bubbleContent);\r\n ////////this.log('need to render date message', dateTimestamp, str);\r\n\r\n const container = document.createElement('div');\r\n container.className = 'bubbles-date-group';\r\n container.append(bubble);\r\n\r\n this.dateMessages[dateTimestamp] = {\r\n div: bubble,\r\n container,\r\n firstTimestamp: date.getTime()\r\n };\r\n\r\n const haveTimestamps = getObjectKeysAndSort(this.dateMessages, 'asc');\r\n let i = 0, length = haveTimestamps.length, insertBefore: HTMLElement; // there can be 'first bubble' (e.g. bot description) so can't insert by index\r\n for(; i < haveTimestamps.length; ++i) {\r\n const t = haveTimestamps[i];\r\n insertBefore = this.dateMessages[t].container;\r\n if(dateTimestamp < t) {\r\n break;\r\n }\r\n }\r\n\r\n if(i === length && insertBefore) {\r\n insertBefore = insertBefore.nextElementSibling as HTMLElement;\r\n }\r\n\r\n if(!insertBefore) {\r\n this.chatInner.append(container);\r\n } else {\r\n this.chatInner.insertBefore(container, insertBefore);\r\n }\r\n\r\n if(this.stickyIntersector) {\r\n this.stickyIntersector.observeStickyHeaderChanges(container);\r\n }\r\n }\r\n\r\n return this.dateMessages[dateTimestamp];\r\n }\r\n\r\n public destroy() {\r\n //this.chat.log.error('Bubbles destroying');\r\n\r\n this.scrollable.onScrolledTop = this.scrollable.onScrolledBottom = this.scrollable.onAdditionalScroll = null;\r\n\r\n this.listenerSetter.removeAll();\r\n\r\n this.lazyLoadQueue.clear();\r\n this.unreadedObserver && this.unreadedObserver.disconnect();\r\n this.viewsObserver && this.viewsObserver.disconnect();\r\n this.stickyIntersector && this.stickyIntersector.disconnect();\r\n\r\n delete this.lazyLoadQueue;\r\n this.unreadedObserver && delete this.unreadedObserver;\r\n this.viewsObserver && delete this.viewsObserver;\r\n this.stickyIntersector && delete this.stickyIntersector;\r\n }\r\n\r\n public cleanup(bubblesToo = false) {\r\n ////console.time('appImManager cleanup');\r\n this.setLoaded('top', false);\r\n this.setLoaded('bottom', false);\r\n\r\n // cancel scroll\r\n cancelAnimationByKey(this.scrollable.container);\r\n\r\n // do not wait ending of previous scale animation\r\n interruptHeavyAnimation();\r\n\r\n if(TEST_SCROLL !== undefined) {\r\n TEST_SCROLL = TEST_SCROLL_TIMES;\r\n }\r\n\r\n this.bubbles = {};\r\n this.skippedMids.clear();\r\n this.dateMessages = {};\r\n this.bubbleGroups.cleanup();\r\n this.unreadOut.clear();\r\n this.needUpdate.length = 0;\r\n this.lazyLoadQueue.clear();\r\n \r\n // clear messages\r\n if(bubblesToo) {\r\n this.scrollable.container.textContent = '';\r\n }\r\n \r\n this.firstUnreadBubble = null;\r\n this.attachedUnreadBubble = false;\r\n \r\n this.messagesQueue.length = 0;\r\n this.messagesQueuePromise = null;\r\n \r\n this.getHistoryTopPromise = this.getHistoryBottomPromise = undefined;\r\n this.fetchNewPromise = undefined;\r\n \r\n if(this.stickyIntersector) {\r\n this.stickyIntersector.disconnect();\r\n }\r\n \r\n if(this.unreadedObserver) {\r\n this.unreadedObserver.disconnect();\r\n this.unreaded.clear();\r\n this.unreadedSeen.clear();\r\n this.readPromise = undefined;\r\n }\r\n\r\n if(this.viewsObserver) {\r\n this.viewsObserver.disconnect();\r\n this.viewsMids.clear();\r\n }\r\n \r\n this.loadedTopTimes = this.loadedBottomTimes = 0;\r\n \r\n this.middleware.clean();\r\n \r\n this.onAnimateLadder = undefined;\r\n this.resolveLadderAnimation = undefined;\r\n this.emptyPlaceholderMid = undefined;\r\n\r\n this.scrollingToBubble = undefined;\r\n ////console.timeEnd('appImManager cleanup');\r\n }\r\n\r\n public setPeer(peerId: number, lastMsgId?: number): {cached?: boolean, promise: Chat['setPeerPromise']} {\r\n //console.time('appImManager setPeer');\r\n //console.time('appImManager setPeer pre promise');\r\n ////console.time('appImManager: pre render start');\r\n if(!peerId) {\r\n this.cleanup(true);\r\n this.peerId = 0;\r\n return null;\r\n }\r\n\r\n const samePeer = this.peerId === peerId;\r\n\r\n /* if(samePeer && this.chat.setPeerPromise) {\r\n return {cached: true, promise: this.chat.setPeerPromise};\r\n } */\r\n\r\n this.historyStorage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);\r\n let topMessage = this.chat.type === 'pinned' ? this.appMessagesManager.pinnedMessages[peerId].maxId : this.historyStorage.maxId ?? 0;\r\n const isTarget = lastMsgId !== undefined;\r\n\r\n // * this one will fix topMessage for null message in history (e.g. channel comments with only 1 comment and it is a topMessage)\r\n /* if(this.chat.type !== 'pinned' && topMessage && !historyStorage.history.slice.includes(topMessage)) {\r\n topMessage = 0;\r\n } */\r\n\r\n let readMaxId = 0, savedPosition: ReturnType<AppImManager['getChatSavedPosition']>;\r\n if(!isTarget) {\r\n if(!samePeer) {\r\n savedPosition = this.chat.appImManager.getChatSavedPosition(this.chat);\r\n }\r\n\r\n if(savedPosition) {\r\n \r\n } else if(topMessage) {\r\n readMaxId = this.appMessagesManager.getReadMaxIdIfUnread(peerId, this.chat.threadId);\r\n if(/* dialog.unread_count */readMaxId && !samePeer) {\r\n lastMsgId = readMaxId;\r\n } else {\r\n lastMsgId = topMessage;\r\n //lastMsgID = topMessage;\r\n }\r\n }\r\n }\r\n\r\n const isJump = lastMsgId !== topMessage;\r\n \r\n if(samePeer) {\r\n const mounted = this.getMountedBubble(lastMsgId);\r\n if(mounted) {\r\n if(isTarget) {\r\n this.scrollToBubble(mounted.bubble, 'center');\r\n this.highlightBubble(mounted.bubble);\r\n this.chat.dispatchEvent('setPeer', lastMsgId, false);\r\n } else if(topMessage && !isJump) {\r\n //this.log('will scroll down', this.scroll.scrollTop, this.scroll.scrollHeight);\r\n this.scrollable.scrollTop = this.scrollable.scrollHeight;\r\n this.chat.dispatchEvent('setPeer', lastMsgId, true);\r\n }\r\n \r\n return null;\r\n }\r\n } else {\r\n if(this.peerId) { // * set new queue id if new peer (setting not from 0)\r\n this.lazyLoadQueue.queueId = ++queueId;\r\n this.chat.apiManager.setQueueId(this.chat.bubbles.lazyLoadQueue.queueId);\r\n }\r\n\r\n this.peerId = peerId;\r\n this.replyFollowHistory.length = 0;\r\n\r\n this.passEntities = {\r\n messageEntityBotCommand: this.appPeersManager.isAnyGroup(this.peerId) || this.appUsersManager.isBot(this.peerId)\r\n };\r\n }\r\n\r\n if(DEBUG) {\r\n this.log('setPeer peerId:', this.peerId, this.historyStorage, lastMsgId, topMessage);\r\n }\r\n\r\n // add last message, bc in getHistory will load < max_id\r\n const additionMsgId = isJump || this.chat.type === 'scheduled' ? 0 : topMessage;\r\n\r\n /* this.setPeerPromise = null;\r\n this.preloader.detach();\r\n return true; */\r\n\r\n //////appSidebarRight.toggleSidebar(true);\r\n\r\n let maxBubbleId = 0;\r\n if(samePeer) {\r\n let el = this.getBubbleByPoint('bottom'); // ! this may not work if being called when chat is hidden\r\n //this.chat.log('[PM]: setCorrectIndex: get last element perf:', performance.now() - perf, el);\r\n if(el) {\r\n maxBubbleId = +el.dataset.mid;\r\n }\r\n\r\n if(maxBubbleId <= 0) {\r\n maxBubbleId = Math.max(...Object.keys(this.bubbles).map(mid => +mid));\r\n }\r\n } else {\r\n this.isFirstLoad = true;\r\n }\r\n\r\n const oldChatInner = this.chatInner;\r\n this.cleanup();\r\n this.chatInner = document.createElement('div');\r\n if(samePeer) {\r\n this.chatInner.className = oldChatInner.className;\r\n this.chatInner.classList.remove('disable-hover', 'is-scrolling');\r\n } else {\r\n this.chatInner.classList.add('bubbles-inner');\r\n }\r\n\r\n this.lazyLoadQueue.lock();\r\n\r\n let result: ReturnType<ChatBubbles['getHistory']>;\r\n if(!savedPosition) {\r\n result = this.getHistory(lastMsgId, true, isJump, additionMsgId);\r\n } else {\r\n result = {\r\n promise: getHeavyAnimationPromise().then(() => {\r\n return this.performHistoryResult(savedPosition.mids, true, false, undefined);\r\n }) as any,\r\n cached: true\r\n };\r\n }\r\n\r\n const {promise, cached} = result;\r\n\r\n // clear \r\n if(!cached) {\r\n if(!samePeer) {\r\n this.scrollable.container.textContent = '';\r\n //oldChatInner.remove();\r\n this.chat.finishPeerChange(isTarget, isJump, lastMsgId);\r\n this.preloader.attach(this.bubblesContainer);\r\n }\r\n }\r\n\r\n //console.timeEnd('appImManager setPeer pre promise');\r\n /* this.ladderDeferred && this.ladderDeferred.resolve();\r\n this.ladderDeferred = deferredPromise<void>(); */\r\n \r\n animationIntersector.lockGroup(CHAT_ANIMATION_GROUP);\r\n const setPeerPromise = promise.then(() => {\r\n ////this.log('setPeer removing preloader');\r\n\r\n if(cached) {\r\n if(!samePeer) {\r\n this.chat.finishPeerChange(isTarget, isJump, lastMsgId); // * костыль\r\n }\r\n } else {\r\n this.preloader.detach();\r\n }\r\n\r\n if(this.resolveLadderAnimation) {\r\n this.resolveLadderAnimation();\r\n this.resolveLadderAnimation = undefined;\r\n }\r\n\r\n // this.ladderDeferred.resolve();\r\n\r\n this.scrollable.lastScrollDirection = 0;\r\n this.scrollable.lastScrollTop = 0;\r\n replaceContent(this.scrollable.container, this.chatInner);\r\n\r\n animationIntersector.unlockGroup(CHAT_ANIMATION_GROUP);\r\n animationIntersector.checkAnimations(false, CHAT_ANIMATION_GROUP/* , true */);\r\n\r\n //fastRaf(() => {\r\n this.lazyLoadQueue.unlock();\r\n //});\r\n\r\n //if(dialog && lastMsgID && lastMsgID !== topMessage && (this.bubbles[lastMsgID] || this.firstUnreadBubble)) {\r\n if(savedPosition) {\r\n this.scrollable.scrollTop = savedPosition.top;\r\n /* const mountedByLastMsgId = this.getMountedBubble(lastMsgId);\r\n let bubble: HTMLElement = mountedByLastMsgId?.bubble;\r\n if(!bubble?.parentElement) {\r\n bubble = this.findNextMountedBubbleByMsgId(lastMsgId);\r\n }\r\n\r\n if(bubble) {\r\n const top = bubble.getBoundingClientRect().top;\r\n const distance = savedPosition.top - top;\r\n this.scrollable.scrollTop += distance;\r\n } */\r\n } else if((topMessage && isJump) || isTarget) {\r\n const fromUp = maxBubbleId > 0 && (maxBubbleId < lastMsgId || lastMsgId < 0);\r\n const followingUnread = readMaxId === lastMsgId && !isTarget;\r\n if(!fromUp && samePeer) {\r\n this.scrollable.scrollTop = 99999;\r\n } else if(fromUp/* && (samePeer || forwardingUnread) */) {\r\n this.scrollable.scrollTop = 0;\r\n }\r\n\r\n const mountedByLastMsgId = this.getMountedBubble(lastMsgId);\r\n let bubble: HTMLElement = (followingUnread && this.firstUnreadBubble) || mountedByLastMsgId?.bubble;\r\n if(!bubble?.parentElement) {\r\n bubble = this.findNextMountedBubbleByMsgId(lastMsgId);\r\n }\r\n \r\n // ! sometimes there can be no bubble\r\n if(bubble) {\r\n this.scrollToBubble(bubble, followingUnread ? 'start' : 'center', !samePeer ? FocusDirection.Static : undefined);\r\n if(!followingUnread) {\r\n this.highlightBubble(bubble);\r\n }\r\n }\r\n } else {\r\n this.scrollable.scrollTop = 99999;\r\n }\r\n\r\n this.onScroll();\r\n\r\n const middleware = this.getMiddleware();\r\n const afterSetPromise = Promise.all([setPeerPromise, getHeavyAnimationPromise()]);\r\n afterSetPromise.then(() => { // check whether list isn't full\r\n this.scrollable.checkForTriggers();\r\n });\r\n\r\n this.chat.dispatchEvent('setPeer', lastMsgId, !isJump);\r\n\r\n const needFetchInterval = this.appMessagesManager.isFetchIntervalNeeded(peerId);\r\n const needFetchNew = savedPosition || needFetchInterval;\r\n if(!needFetchNew) {\r\n // warning\r\n if(!lastMsgId || this.bubbles[topMessage] || lastMsgId === topMessage) {\r\n this.setLoaded('bottom', true);\r\n }\r\n } else {\r\n afterSetPromise.then(() => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n this.scrollable.checkForTriggers();\r\n\r\n if(needFetchInterval) {\r\n const f = () => {\r\n this.fetchNewPromise = new Promise<void>((resolve) => {\r\n if(!middleware() || !this.appMessagesManager.isFetchIntervalNeeded(peerId)) {\r\n resolve();\r\n return;\r\n }\r\n \r\n this.appMessagesManager.getNewHistory(peerId, this.chat.threadId).then((historyStorage) => {\r\n if(!middleware() || !historyStorage) {\r\n resolve();\r\n return;\r\n }\r\n \r\n const slice = historyStorage.history.slice;\r\n const isBottomEnd = slice.isEnd(SliceEnd.Bottom);\r\n if(this.scrollable.loadedAll.bottom && this.scrollable.loadedAll.bottom !== isBottomEnd) {\r\n this.setLoaded('bottom', isBottomEnd);\r\n this.onScroll();\r\n }\r\n\r\n setTimeout(f, 30e3);\r\n resolve();\r\n });\r\n }).finally(() => {\r\n this.fetchNewPromise = undefined;\r\n });\r\n };\r\n \r\n if(samePeer) {\r\n setTimeout(f, 30e3);\r\n } else {\r\n f();\r\n }\r\n }\r\n });\r\n }\r\n \r\n this.log('scrolledAllDown:', this.scrollable.loadedAll.bottom);\r\n\r\n //if(!this.unreaded.length && dialog) { // lol\r\n if(this.scrollable.loadedAll.bottom && topMessage && !this.unreaded.size) { // lol\r\n this.onScrolledAllDown();\r\n }\r\n\r\n if(this.chat.type === 'chat') {\r\n const dialog = this.appMessagesManager.getDialogOnly(peerId);\r\n if(dialog?.pFlags.unread_mark) {\r\n this.appMessagesManager.markDialogUnread(peerId, true);\r\n }\r\n }\r\n\r\n //this.chatInner.classList.remove('disable-hover', 'is-scrolling'); // warning, performance!\r\n\r\n /* if(!document.body.classList.contains(RIGHT_COLUMN_ACTIVE_CLASSNAME)) {\r\n return new Promise<void>((resolve) => fastRaf(resolve));\r\n } */\r\n //console.timeEnd('appImManager setPeer');\r\n }).catch(err => {\r\n this.log.error('getHistory promise error:', err);\r\n this.preloader.detach();\r\n throw err;\r\n });\r\n\r\n return {cached, promise: setPeerPromise};\r\n }\r\n\r\n public onScrolledAllDown() {\r\n if(this.chat.type === 'chat' || this.chat.type === 'discussion') {\r\n const storage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);\r\n this.appMessagesManager.readHistory(this.peerId, storage.maxId, this.chat.threadId, true);\r\n }\r\n }\r\n\r\n public finishPeerChange() {\r\n const peerId = this.peerId;\r\n const isChannel = this.appPeersManager.isChannel(peerId);\r\n const canWrite = this.appMessagesManager.canSendToPeer(peerId, this.chat.threadId);\r\n \r\n this.chatInner.classList.toggle('has-rights', canWrite);\r\n this.bubblesContainer.classList.toggle('is-chat-input-hidden', !canWrite);\r\n\r\n this.chatInner.classList.toggle('is-chat', this.chat.isAnyGroup());\r\n this.chatInner.classList.toggle('is-channel', isChannel);\r\n }\r\n\r\n public renderMessagesQueue(message: any, bubble: HTMLElement, reverse: boolean, promises: Promise<any>[]) {\r\n /* let dateMessage = this.getDateContainerByMessage(message, reverse);\r\n if(reverse) dateMessage.container.insertBefore(bubble, dateMessage.div.nextSibling);\r\n else dateMessage.container.append(bubble);\r\n return; */\r\n\r\n /* if(DEBUG && message.mid === 4314759167) {\r\n this.log('renderMessagesQueue', message, bubble, reverse, promises);\r\n } */\r\n\r\n this.messagesQueue.push({message, bubble, reverse, promises});\r\n\r\n this.setMessagesQueuePromise(); \r\n }\r\n\r\n public setMessagesQueuePromise() {\r\n if(this.messagesQueuePromise || !this.messagesQueue.length) return;\r\n\r\n this.messagesQueuePromise = new Promise((resolve, reject) => {\r\n setTimeout(() => {\r\n const queue = this.messagesQueue.slice();\r\n this.messagesQueue.length = 0;\r\n\r\n const promises = queue.reduce((acc, {promises}) => acc.concat(promises), []);\r\n\r\n // * это нужно для того, чтобы если захочет подгрузить reply или какое-либо сообщение, то скролл не прервался\r\n // * если добавить этот промис - в таком случае нужно сделать, чтобы скроллило к последнему сообщению после рендера\r\n // promises.push(getHeavyAnimationPromise());\r\n\r\n this.log('promises to call', promises, queue, this.isHeavyAnimationInProgress);\r\n const middleware = this.getMiddleware();\r\n Promise.all(promises).then(() => {\r\n if(!middleware()) {\r\n throw 'setMessagesQueuePromise: peer changed!';\r\n }\r\n\r\n if(this.messagesQueueOnRender) {\r\n this.messagesQueueOnRender();\r\n }\r\n\r\n if(this.messagesQueueOnRenderAdditional) {\r\n this.messagesQueueOnRenderAdditional();\r\n }\r\n\r\n queue.forEach(({message, bubble, reverse}) => {\r\n this.setBubblePosition(bubble, message, reverse);\r\n });\r\n\r\n //setTimeout(() => {\r\n resolve();\r\n //}, 500);\r\n this.messagesQueuePromise = null;\r\n\r\n if(this.messagesQueue.length) {\r\n this.setMessagesQueuePromise();\r\n }\r\n\r\n this.setUnreadDelimiter(); // не нашёл места лучше\r\n }).catch(reject);\r\n }, 0);\r\n });\r\n\r\n //this.messagesQueuePromise.catch(() => {});\r\n }\r\n\r\n public setBubblePosition(bubble: HTMLElement, message: any, reverse: boolean) {\r\n if(message.id < 0) {\r\n this.chatInner.prepend(bubble);\r\n return;\r\n }\r\n\r\n const dateMessage = this.getDateContainerByMessage(message, reverse);\r\n if(this.chat.type === 'scheduled' || this.chat.type === 'pinned'/* || true */) { // ! TEMP COMMENTED\r\n const offset = this.stickyIntersector ? 2 : 1;\r\n let children = Array.from(dateMessage.container.children).slice(offset) as HTMLElement[];\r\n let i = 0, foundMidOnSameTimestamp = 0;\r\n for(; i < children.length; ++i) {\r\n const t = children[i];\r\n const timestamp = +t.dataset.timestamp;\r\n if(message.date < timestamp) {\r\n break;\r\n } else if(message.date === timestamp) {\r\n foundMidOnSameTimestamp = +t.dataset.mid;\r\n }\r\n \r\n if(foundMidOnSameTimestamp && message.mid < foundMidOnSameTimestamp) {\r\n break;\r\n }\r\n }\r\n \r\n // * 1 for date, 1 for date sentinel\r\n let index = offset + i;\r\n /* if(bubble.parentElement) { // * if already mounted\r\n const currentIndex = whichChild(bubble);\r\n if(index > currentIndex) {\r\n index -= 1; // * minus for already mounted\r\n }\r\n } */\r\n \r\n positionElementByIndex(bubble, dateMessage.container, index);\r\n } else {\r\n if(reverse) {\r\n dateMessage.container.insertBefore(bubble, dateMessage.container.children[this.stickyIntersector ? 1 : 0].nextSibling);\r\n } else {\r\n dateMessage.container.append(bubble);\r\n }\r\n }\r\n\r\n if(message._ === 'message') {\r\n this.bubbleGroups.addBubble(bubble, message, reverse);\r\n } else {\r\n bubble.classList.add('is-group-first', 'is-group-last');\r\n }\r\n }\r\n\r\n public getMiddleware() {\r\n return this.middleware.get();\r\n }\r\n \r\n // reverse means top\r\n private renderMessage(message: any, reverse = false, multipleRender = false, bubble: HTMLDivElement = null, updatePosition = true) {\r\n /* if(DEBUG) {\r\n this.log.debug('message to render:', message);\r\n } */\r\n if(!bubble && this.bubbles[message.mid]) {\r\n return;\r\n }\r\n\r\n //return;\r\n const albumMustBeRenderedFull = this.chat.type !== 'pinned';\r\n if(message.deleted) return;\r\n else if(message.grouped_id && albumMustBeRenderedFull) { // will render only last album's message\r\n const storage = this.appMessagesManager.groupedMessagesStorage[message.grouped_id];\r\n const maxId = Math.max(...storage.keys());\r\n if(message.mid < maxId) {\r\n return;\r\n }\r\n }\r\n \r\n const peerId = this.peerId;\r\n // * can't use 'message.pFlags.out' here because this check will be used to define side of message (left-right)\r\n const our = message.fromId === rootScope.myId || (message.pFlags.out && this.appPeersManager.isMegagroup(this.peerId));\r\n \r\n const messageDiv = document.createElement('div');\r\n messageDiv.classList.add('message');\r\n \r\n //messageDiv.innerText = message.message;\r\n\r\n let bubbleContainer: HTMLDivElement;\r\n let contentWrapper: HTMLElement;\r\n \r\n // bubble\r\n if(!bubble) {\r\n contentWrapper = document.createElement('div');\r\n contentWrapper.classList.add('bubble-content-wrapper');\r\n \r\n bubbleContainer = document.createElement('div');\r\n bubbleContainer.classList.add('bubble-content');\r\n \r\n bubble = document.createElement('div');\r\n bubble.classList.add('bubble');\r\n contentWrapper.appendChild(bubbleContainer);\r\n bubble.appendChild(contentWrapper);\r\n\r\n if(!our && !message.pFlags.out && this.unreadedObserver) {\r\n //this.log('not our message', message, message.pFlags.unread);\r\n const isUnread = message.pFlags.unread || \r\n this.appMessagesManager.isMentionUnread(message) || \r\n (this.historyStorage.readMaxId !== undefined && this.historyStorage.readMaxId < message.mid);\r\n if(isUnread) {\r\n this.unreadedObserver.observe(bubble); \r\n this.unreaded.set(bubble, message.mid);\r\n }\r\n }\r\n } else {\r\n const save = ['is-highlighted', 'is-group-first', 'is-group-last'];\r\n const wasClassNames = bubble.className.split(' ');\r\n const classNames = ['bubble'].concat(save.filter(c => wasClassNames.includes(c)));\r\n bubble.className = classNames.join(' ');\r\n\r\n contentWrapper = bubble.lastElementChild as HTMLElement;\r\n bubbleContainer = contentWrapper.firstElementChild as HTMLDivElement;\r\n bubbleContainer.innerHTML = '';\r\n bubbleContainer.style.cssText = '';\r\n contentWrapper.innerHTML = '';\r\n contentWrapper.appendChild(bubbleContainer);\r\n //bubbleContainer.style.marginBottom = '';\r\n const transitionDelay = contentWrapper.style.transitionDelay;\r\n contentWrapper.style.cssText = '';\r\n contentWrapper.style.transitionDelay = transitionDelay;\r\n\r\n if(bubble === this.firstUnreadBubble) {\r\n bubble.classList.add('is-first-unread');\r\n }\r\n\r\n // * Нужно очистить прошлую информацию, полезно если удалить последний элемент из альбома в ПОСЛЕДНЕМ БАББЛЕ ГРУППЫ (видно по аватару)\r\n const originalMid = +bubble.dataset.mid;\r\n const sameMid = +message.mid === originalMid;\r\n /* if(updatePosition) {\r\n bubble.remove(); // * for positionElementByIndex\r\n } */\r\n\r\n if(!sameMid) {\r\n delete this.bubbles[originalMid];\r\n this.skippedMids.delete(originalMid);\r\n }\r\n\r\n //bubble.innerHTML = '';\r\n }\r\n\r\n // ! reset due to album edit or delete item\r\n this.bubbles[+message.mid] = bubble;\r\n bubble.dataset.mid = message.mid;\r\n bubble.dataset.peerId = '' + message.peerId;\r\n bubble.dataset.timestamp = message.date;\r\n\r\n const loadPromises: Promise<any>[] = [];\r\n\r\n if(message._ === 'messageService') {\r\n assumeType<Message.messageService>(message);\r\n\r\n const action = message.action;\r\n if(action) {\r\n const _ = action._;\r\n if(IGNORE_ACTIONS.has(_) || (langPack.hasOwnProperty(_) && !langPack[_])) {\r\n this.skippedMids.add(+message.mid);\r\n return bubble;\r\n }\r\n }\r\n\r\n bubble.className = 'bubble service';\r\n\r\n bubbleContainer.innerHTML = '';\r\n const s = document.createElement('div');\r\n s.classList.add('service-msg');\r\n if(action) {\r\n if(action._ === 'messageActionChannelMigrateFrom') {\r\n s.append(i18n('ChatMigration.From', [new PeerTitle({peerId: -action.chat_id}).element]));\r\n } else if(action._ === 'messageActionChatMigrateTo') {\r\n s.append(i18n('ChatMigration.To', [new PeerTitle({peerId: -action.channel_id}).element]));\r\n } else {\r\n s.append(this.appMessagesManager.wrapMessageActionTextNew(message));\r\n }\r\n }\r\n bubbleContainer.append(s);\r\n\r\n if(updatePosition) {\r\n this.renderMessagesQueue(message, bubble, reverse, loadPromises);\r\n\r\n if(message.pFlags.is_single) { // * Ignore 'Discussion started'\r\n bubble.classList.add('is-group-last');\r\n }\r\n }\r\n\r\n return bubble;\r\n }\r\n\r\n let messageMedia = message.media;\r\n\r\n let messageMessage: string, totalEntities: MessageEntity[];\r\n if(messageMedia?.document && !['video', 'gif'].includes(messageMedia.document.type)) {\r\n // * just filter these cases for documents caption\r\n } else if(message.grouped_id && albumMustBeRenderedFull) {\r\n const t = this.appMessagesManager.getAlbumText(message.grouped_id);\r\n messageMessage = t.message;\r\n //totalEntities = t.entities;\r\n totalEntities = t.totalEntities;\r\n } else if(messageMedia?.document?.type !== 'sticker') {\r\n messageMessage = message.message;\r\n //totalEntities = message.entities;\r\n totalEntities = message.totalEntities;\r\n }\r\n \r\n /* let richText = RichTextProcessor.wrapRichText(messageMessage, {\r\n entities: totalEntities\r\n }); */\r\n let richText = RichTextProcessor.wrapRichText(messageMessage, {\r\n entities: totalEntities,\r\n passEntities: this.passEntities\r\n });\r\n\r\n let canHaveTail = true;\r\n let isStandaloneMedia = false;\r\n let needToSetHTML = true;\r\n if(totalEntities && !messageMedia) {\r\n let emojiEntities = totalEntities.filter((e) => e._ === 'messageEntityEmoji');\r\n let strLength = messageMessage.length;\r\n let emojiStrLength = emojiEntities.reduce((acc: number, curr: any) => acc + curr.length, 0);\r\n \r\n if(emojiStrLength === strLength && emojiEntities.length <= 3) {\r\n if(rootScope.settings.emoji.big) {\r\n let sticker = this.appStickersManager.getAnimatedEmojiSticker(messageMessage);\r\n if(emojiEntities.length === 1 && !messageMedia && sticker) {\r\n messageMedia = {\r\n _: 'messageMediaDocument',\r\n document: sticker\r\n };\r\n } else {\r\n let attachmentDiv = document.createElement('div');\r\n attachmentDiv.classList.add('attachment');\r\n \r\n attachmentDiv.innerHTML = richText;\r\n \r\n bubble.classList.add('emoji-' + emojiEntities.length + 'x');\r\n \r\n bubbleContainer.append(attachmentDiv);\r\n }\r\n\r\n bubble.classList.add('is-message-empty', 'emoji-big');\r\n isStandaloneMedia = true;\r\n canHaveTail = false;\r\n needToSetHTML = false;\r\n }\r\n \r\n bubble.classList.add('can-have-big-emoji');\r\n }\r\n \r\n /* if(strLength === emojiStrLength) {\r\n messageDiv.classList.add('emoji-only');\r\n messageDiv.classList.add('message-empty');\r\n } */\r\n }\r\n\r\n if(needToSetHTML) {\r\n setInnerHTML(messageDiv, richText);\r\n }\r\n \r\n const timeSpan = MessageRender.setTime(this.chat, message, bubble, bubbleContainer, messageDiv);\r\n bubbleContainer.prepend(messageDiv);\r\n //bubble.prepend(timeSpan, messageDiv); // that's bad\r\n\r\n if(message.views && !message.pFlags.is_outgoing && this.viewsObserver) {\r\n this.viewsObserver.observe(bubble);\r\n }\r\n\r\n if(message.reply_markup && message.reply_markup._ === 'replyInlineMarkup' && message.reply_markup.rows && message.reply_markup.rows.length) {\r\n const rows = (message.reply_markup as ReplyMarkup.replyKeyboardMarkup).rows;\r\n\r\n const containerDiv = document.createElement('div');\r\n containerDiv.classList.add('reply-markup');\r\n rows.forEach((row) => {\r\n const buttons = row.buttons;\r\n if(!buttons || !buttons.length) return;\r\n\r\n const rowDiv = document.createElement('div');\r\n rowDiv.classList.add('reply-markup-row');\r\n\r\n buttons.forEach((button) => {\r\n const text = RichTextProcessor.wrapRichText(button.text, {noLinks: true, noLinebreaks: true});\r\n\r\n let buttonEl: HTMLButtonElement | HTMLAnchorElement;\r\n \r\n switch(button._) {\r\n case 'keyboardButtonUrl': {\r\n const r = RichTextProcessor.wrapRichText(' ', {\r\n entities: [{\r\n _: 'messageEntityTextUrl',\r\n length: 1,\r\n offset: 0,\r\n url: button.url\r\n }]\r\n });\r\n\r\n buttonEl = htmlToDocumentFragment(r).firstElementChild as HTMLAnchorElement;\r\n buttonEl.classList.add('is-link', 'tgico');\r\n\r\n break;\r\n }\r\n\r\n case 'keyboardButtonSwitchInline': {\r\n buttonEl = document.createElement('button');\r\n buttonEl.classList.add('is-switch-inline'/* , 'tgico' */);\r\n const i = document.createElement('i');\r\n i.classList.add('forward-icon');\r\n i.innerHTML = `<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" preserveAspectRatio=\"xMidYMid meet\" viewBox=\"0 0 24 24\">\r\n <defs>\r\n <path d=\"M13.55 3.24L13.64 3.25L13.73 3.27L13.81 3.29L13.9 3.32L13.98 3.35L14.06 3.39L14.14 3.43L14.22 3.48L14.29 3.53L14.36 3.59L14.43 3.64L22.23 10.85L22.36 10.99L22.48 11.15L22.57 11.31L22.64 11.48L22.69 11.66L22.72 11.85L22.73 12.04L22.71 12.22L22.67 12.41L22.61 12.59L22.53 12.76L22.42 12.93L22.29 13.09L22.23 13.15L14.43 20.36L14.28 20.48L14.12 20.58L13.95 20.66L13.77 20.72L13.58 20.76L13.4 20.77L13.22 20.76L13.03 20.73L12.85 20.68L12.68 20.61L12.52 20.52L12.36 20.4L12.22 20.27L12.16 20.2L12.1 20.13L12.05 20.05L12.01 19.98L11.96 19.9L11.93 19.82L11.89 19.73L11.87 19.65L11.84 19.56L11.83 19.47L11.81 19.39L11.81 19.3L11.8 19.2L11.8 16.42L11 16.49L10.23 16.58L9.51 16.71L8.82 16.88L8.18 17.09L7.57 17.33L7.01 17.6L6.48 17.91L5.99 18.26L5.55 18.64L5.14 19.05L4.77 19.51L4.43 19.99L4.29 20.23L4.21 20.35L4.11 20.47L4 20.57L3.88 20.65L3.75 20.72L3.62 20.78L3.48 20.82L3.33 20.84L3.19 20.84L3.04 20.83L2.9 20.79L2.75 20.74L2.62 20.68L2.53 20.62L2.45 20.56L2.38 20.5L2.31 20.43L2.25 20.36L2.2 20.28L2.15 20.19L2.11 20.11L2.07 20.02L2.04 19.92L2.02 19.83L2.01 19.73L2 19.63L2.04 17.99L2.19 16.46L2.46 15.05L2.85 13.75L3.35 12.58L3.97 11.53L4.7 10.6L5.55 9.8L6.51 9.12L7.59 8.56L8.77 8.13L10.07 7.83L11.48 7.65L11.8 7.63L11.8 4.8L11.91 4.56L12.02 4.35L12.14 4.16L12.25 3.98L12.37 3.82L12.48 3.68L12.61 3.56L12.73 3.46L12.85 3.38L12.98 3.31L13.11 3.27L13.24 3.24L13.37 3.23L13.46 3.23L13.55 3.24Z\" id=\"b13RmHDQtl\"></path>\r\n </defs>\r\n <use xlink:href=\"#b13RmHDQtl\" opacity=\"1\" fill=\"#fff\" fill-opacity=\"1\"></use>\r\n </svg>`;\r\n buttonEl.append(i);\r\n attachClickEvent(buttonEl, (e) => {\r\n cancelEvent(e);\r\n\r\n const botId = message.viaBotId || message.fromId;\r\n let promise: Promise<number>;\r\n if(button.pFlags.same_peer) promise = Promise.resolve(this.peerId);\r\n else promise = this.appInlineBotsManager.checkSwitchReturn(botId).then(peerId => {\r\n if(peerId) {\r\n return peerId;\r\n }\r\n \r\n return new Promise<number>((resolve, reject) => {\r\n new PopupForward({\r\n [this.peerId]: []\r\n }, (peerId) => {\r\n resolve(peerId);\r\n }, () => {\r\n reject();\r\n }, true);\r\n });\r\n });\r\n \r\n promise.then(peerId => {\r\n const threadId = this.peerId === peerId ? this.chat.threadId : undefined;\r\n this.appInlineBotsManager.switchInlineQuery(peerId, threadId, botId, button.query);\r\n });\r\n });\r\n break;\r\n }\r\n\r\n default: {\r\n buttonEl = document.createElement('button');\r\n break;\r\n }\r\n }\r\n \r\n buttonEl.classList.add('reply-markup-button', 'rp');\r\n buttonEl.insertAdjacentHTML('beforeend', text);\r\n\r\n ripple(buttonEl);\r\n\r\n rowDiv.append(buttonEl);\r\n });\r\n\r\n containerDiv.append(rowDiv);\r\n });\r\n\r\n attachClickEvent(containerDiv, (e) => {\r\n let target = e.target as HTMLElement;\r\n \r\n if(!target.classList.contains('reply-markup-button')) target = findUpClassName(target, 'reply-markup-button');\r\n if(!target || target.classList.contains('is-link') || target.classList.contains('is-switch-inline')) return;\r\n\r\n cancelEvent(e);\r\n\r\n const column = whichChild(target);\r\n const row = rows[whichChild(target.parentElement)];\r\n\r\n if(!row.buttons || !row.buttons[column]) {\r\n this.log.warn('no such button', row, column, message);\r\n return;\r\n }\r\n\r\n const button = row.buttons[column];\r\n this.appInlineBotsManager.callbackButtonClick(this.peerId, message.mid, button);\r\n });\r\n\r\n canHaveTail = false;\r\n bubble.classList.add('with-reply-markup');\r\n contentWrapper.append(containerDiv);\r\n }\r\n \r\n const isOutgoing = message.pFlags.is_outgoing/* && this.peerId !== rootScope.myId */;\r\n if(our) {\r\n if(message.pFlags.unread || isOutgoing) this.unreadOut.add(message.mid);\r\n let status = '';\r\n if(isOutgoing) status = 'is-sending';\r\n else status = message.pFlags.unread ? 'is-sent' : 'is-read';\r\n bubble.classList.add(status);\r\n }\r\n\r\n const messageWithReplies = this.appMessagesManager.getMessageWithReplies(message);\r\n const withReplies = !!messageWithReplies && message.mid > 0;\r\n\r\n if(withReplies) {\r\n bubble.classList.add('with-replies');\r\n }\r\n\r\n const isOut = our && (!message.fwd_from || this.peerId !== rootScope.myId);\r\n let nameContainer: HTMLElement = bubbleContainer;\r\n\r\n // media\r\n if(messageMedia/* && messageMedia._ === 'messageMediaPhoto' */) {\r\n let attachmentDiv = document.createElement('div');\r\n attachmentDiv.classList.add('attachment');\r\n \r\n if(!messageMessage) {\r\n bubble.classList.add('is-message-empty');\r\n }\r\n \r\n let processingWebPage = false;\r\n \r\n switch(messageMedia._) {\r\n case 'messageMediaPhoto': {\r\n const photo = messageMedia.photo;\r\n ////////this.log('messageMediaPhoto', photo);\r\n\r\n if(!messageMessage) {\r\n canHaveTail = false;\r\n }\r\n \r\n if(!message.viaBotId) {\r\n bubble.classList.add('hide-name'); \r\n }\r\n\r\n bubble.classList.add('photo');\r\n \r\n const storage = this.appMessagesManager.groupedMessagesStorage[message.grouped_id];\r\n if(message.grouped_id && storage.size !== 1 && albumMustBeRenderedFull) {\r\n bubble.classList.add('is-album', 'is-grouped');\r\n wrapAlbum({\r\n groupId: message.grouped_id, \r\n attachmentDiv,\r\n middleware: this.getMiddleware(),\r\n isOut: our,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n chat: this.chat,\r\n loadPromises,\r\n noAutoDownload: this.chat.noAutoDownloadMedia,\r\n });\r\n \r\n break;\r\n }\r\n \r\n const withTail = !IS_ANDROID && canHaveTail && !withReplies && USE_MEDIA_TAILS;\r\n if(withTail) bubble.classList.add('with-media-tail');\r\n wrapPhoto({\r\n photo, \r\n message,\r\n container: attachmentDiv,\r\n withTail, \r\n isOut, \r\n lazyLoadQueue: this.lazyLoadQueue,\r\n middleware: this.getMiddleware(),\r\n loadPromises,\r\n noAutoDownload: this.chat.noAutoDownloadMedia,\r\n });\r\n\r\n break;\r\n }\r\n \r\n case 'messageMediaWebPage': {\r\n processingWebPage = true;\r\n \r\n let webpage: WebPage = messageMedia.webpage;\r\n ////////this.log('messageMediaWebPage', webpage);\r\n if(webpage._ !== 'webPage') {\r\n break;\r\n } \r\n \r\n bubble.classList.add('webpage');\r\n \r\n let box = document.createElement('div');\r\n box.classList.add('web');\r\n \r\n let quote = document.createElement('div');\r\n quote.classList.add('quote');\r\n\r\n let previewResizer: HTMLDivElement, preview: HTMLDivElement;\r\n const photo: Photo.photo = webpage.photo as any;\r\n if(photo || webpage.document) {\r\n previewResizer = document.createElement('div');\r\n previewResizer.classList.add('preview-resizer');\r\n preview = document.createElement('div');\r\n preview.classList.add('preview');\r\n previewResizer.append(preview);\r\n }\r\n \r\n const doc = webpage.document as MyDocument;\r\n if(doc) {\r\n if(doc.type === 'gif' || doc.type === 'video') {\r\n //if(doc.size <= 20e6) {\r\n bubble.classList.add('video');\r\n wrapVideo({\r\n doc, \r\n container: preview, \r\n message, \r\n boxWidth: mediaSizes.active.webpage.width,\r\n boxHeight: mediaSizes.active.webpage.height,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n middleware: this.getMiddleware(),\r\n isOut,\r\n group: CHAT_ANIMATION_GROUP,\r\n loadPromises,\r\n noAutoDownload: this.chat.noAutoDownloadMedia,\r\n });\r\n //}\r\n } else {\r\n const docDiv = wrapDocument({\r\n message,\r\n noAutoDownload: this.chat.noAutoDownloadMedia,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n loadPromises\r\n });\r\n preview.append(docDiv);\r\n preview.classList.add('preview-with-document');\r\n //messageDiv.classList.add((webpage.type || 'document') + '-message');\r\n //doc = null;\r\n }\r\n }\r\n \r\n let quoteTextDiv = document.createElement('div');\r\n quoteTextDiv.classList.add('quote-text');\r\n\r\n if(previewResizer) {\r\n quoteTextDiv.append(previewResizer);\r\n }\r\n\r\n let t: HTMLElement;\r\n if(webpage.site_name) {\r\n const html = RichTextProcessor.wrapRichText(webpage.url);\r\n const a: HTMLAnchorElement = htmlToDocumentFragment(html).firstElementChild as any;\r\n a.classList.add('webpage-name');\r\n setInnerHTML(a, RichTextProcessor.wrapEmojiText(webpage.site_name));\r\n quoteTextDiv.append(a);\r\n t = a;\r\n }\r\n\r\n if(webpage.rTitle) {\r\n let titleDiv = document.createElement('div');\r\n titleDiv.classList.add('title');\r\n setInnerHTML(titleDiv, webpage.rTitle);\r\n quoteTextDiv.append(titleDiv);\r\n t = titleDiv;\r\n }\r\n\r\n if(webpage.rDescription) {\r\n let textDiv = document.createElement('div');\r\n textDiv.classList.add('text');\r\n setInnerHTML(textDiv, webpage.rDescription);\r\n quoteTextDiv.append(textDiv);\r\n t = textDiv;\r\n }\r\n\r\n /* if(t) {\r\n t.append(timeSpan);\r\n } else {\r\n box.classList.add('no-text');\r\n } */\r\n\r\n quote.append(quoteTextDiv);\r\n\r\n if(photo && !doc) {\r\n bubble.classList.add('photo');\r\n\r\n const size: PhotoSize.photoSize = photo.sizes[photo.sizes.length - 1] as any;\r\n let isSquare = false;\r\n if(size.w === size.h && t) {\r\n bubble.classList.add('is-square-photo');\r\n isSquare = true;\r\n this.appPhotosManager.setAttachmentSize(photo, preview, 48, 48, false);\r\n\r\n /* if(t) {\r\n t.append(timeSpan);\r\n } */\r\n } else if(size.h > size.w) {\r\n bubble.classList.add('is-vertical-photo');\r\n }\r\n\r\n wrapPhoto({\r\n photo, \r\n message, \r\n container: preview, \r\n boxWidth: isSquare ? 0 : mediaSizes.active.webpage.width, \r\n boxHeight: isSquare ? 0 : mediaSizes.active.webpage.height, \r\n isOut, \r\n lazyLoadQueue: this.lazyLoadQueue, \r\n middleware: this.getMiddleware(),\r\n loadPromises,\r\n withoutPreloader: isSquare,\r\n noAutoDownload: this.chat.noAutoDownloadMedia,\r\n });\r\n }\r\n \r\n box.append(quote);\r\n \r\n //bubble.prepend(box);\r\n // if(timeSpan.parentElement === messageDiv) {\r\n messageDiv.insertBefore(box, timeSpan);\r\n // } else {\r\n // messageDiv.append(box);\r\n // }\r\n \r\n //this.log('night running', bubble.scrollHeight);\r\n \r\n break;\r\n }\r\n \r\n case 'messageMediaDocument': {\r\n const doc = messageMedia.document;\r\n\r\n //this.log('messageMediaDocument', doc, bubble);\r\n \r\n if(doc.sticker/* && doc.size <= 1e6 */) {\r\n bubble.classList.add('sticker');\r\n canHaveTail = false;\r\n isStandaloneMedia = true;\r\n \r\n if(doc.animated) {\r\n bubble.classList.add('sticker-animated');\r\n }\r\n \r\n const sizes = mediaSizes.active;\r\n const size = bubble.classList.contains('emoji-big') ? sizes.emojiSticker : (doc.animated ? sizes.animatedSticker : sizes.staticSticker);\r\n this.appPhotosManager.setAttachmentSize(doc, attachmentDiv, size.width, size.height);\r\n //let preloader = new ProgressivePreloader(attachmentDiv, false);\r\n bubbleContainer.style.height = attachmentDiv.style.height;\r\n bubbleContainer.style.width = attachmentDiv.style.width;\r\n //appPhotosManager.setAttachmentSize(doc, bubble);\r\n wrapSticker({\r\n doc, \r\n div: attachmentDiv,\r\n middleware: this.getMiddleware(),\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n group: CHAT_ANIMATION_GROUP,\r\n //play: !!message.pending || !multipleRender,\r\n play: true,\r\n loop: true,\r\n emoji: bubble.classList.contains('emoji-big') ? messageMessage : undefined,\r\n withThumb: true,\r\n loadPromises\r\n });\r\n } else if(doc.type === 'video' || doc.type === 'gif' || doc.type === 'round'/* && doc.size <= 20e6 */) {\r\n //this.log('never get free 2', doc);\r\n\r\n const isRound = doc.type === 'round';\r\n if(isRound) {\r\n isStandaloneMedia = true;\r\n }\r\n\r\n if(isRound || !messageMessage) {\r\n canHaveTail = false;\r\n }\r\n\r\n if(!message.viaBotId) {\r\n bubble.classList.add('hide-name');\r\n }\r\n \r\n bubble.classList.add(isRound ? 'round' : 'video');\r\n const storage = this.appMessagesManager.groupedMessagesStorage[message.grouped_id];\r\n if(message.grouped_id && storage.size !== 1 && albumMustBeRenderedFull) {\r\n bubble.classList.add('is-album', 'is-grouped');\r\n \r\n wrapAlbum({\r\n groupId: message.grouped_id, \r\n attachmentDiv,\r\n middleware: this.getMiddleware(),\r\n isOut: our,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n chat: this.chat,\r\n loadPromises,\r\n noAutoDownload: this.chat.noAutoDownloadMedia,\r\n });\r\n } else {\r\n const withTail = !IS_ANDROID && !IS_APPLE && !isRound && canHaveTail && !withReplies && USE_MEDIA_TAILS;\r\n if(withTail) bubble.classList.add('with-media-tail');\r\n wrapVideo({\r\n doc, \r\n container: attachmentDiv, \r\n message, \r\n boxWidth: mediaSizes.active.regular.width,\r\n boxHeight: mediaSizes.active.regular.height, \r\n withTail, \r\n isOut,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n middleware: this.getMiddleware(),\r\n group: CHAT_ANIMATION_GROUP,\r\n loadPromises,\r\n noAutoDownload: this.chat.noAutoDownloadMedia,\r\n searchContext: isRound ? {\r\n peerId: this.peerId,\r\n inputFilter: {_: 'inputMessagesFilterRoundVoice'},\r\n threadId: this.chat.threadId,\r\n useSearch: !message.pFlags.is_scheduled,\r\n isScheduled: message.pFlags.is_scheduled\r\n } : undefined,\r\n });\r\n }\r\n } else {\r\n const newNameContainer = wrapGroupedDocuments({\r\n albumMustBeRenderedFull,\r\n message,\r\n bubble,\r\n messageDiv,\r\n chat: this.chat,\r\n loadPromises,\r\n noAutoDownload: this.chat.noAutoDownloadMedia,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n searchContext: doc.type === 'voice' || doc.type === 'audio' ? {\r\n peerId: this.peerId,\r\n inputFilter: {_: doc.type === 'voice' ? 'inputMessagesFilterRoundVoice' : 'inputMessagesFilterMusic'},\r\n threadId: this.chat.threadId,\r\n useSearch: !message.pFlags.is_scheduled,\r\n isScheduled: message.pFlags.is_scheduled\r\n } : undefined,\r\n });\r\n\r\n if(newNameContainer) {\r\n nameContainer = newNameContainer;\r\n }\r\n\r\n const lastContainer = messageDiv.lastElementChild.querySelector('.document-message, .document-size, .audio');\r\n lastContainer && lastContainer.append(timeSpan.cloneNode(true));\r\n\r\n bubble.classList.remove('is-message-empty');\r\n messageDiv.classList.add((!(['photo', 'pdf'] as MyDocument['type'][]).includes(doc.type) ? doc.type || 'document' : 'document') + '-message');\r\n processingWebPage = true;\r\n }\r\n\r\n break;\r\n }\r\n\r\n case 'messageMediaContact': {\r\n //this.log('wrapping contact', message);\r\n\r\n const contactDiv = document.createElement('div');\r\n contactDiv.classList.add('contact');\r\n contactDiv.dataset.peerId = '' + messageMedia.user_id;\r\n\r\n messageDiv.classList.add('contact-message');\r\n processingWebPage = true;\r\n\r\n const texts = [];\r\n if(message.media.first_name) texts.push(RichTextProcessor.wrapEmojiText(message.media.first_name));\r\n if(message.media.last_name) texts.push(RichTextProcessor.wrapEmojiText(message.media.last_name));\r\n\r\n contactDiv.innerHTML = `\r\n <div class=\"contact-details\">\r\n <div class=\"contact-name\">${texts.join(' ')}</div>\r\n <div class=\"contact-number\">${message.media.phone_number ? '+' + formatPhoneNumber(message.media.phone_number).formatted : 'Unknown phone number'}</div>\r\n </div>`;\r\n\r\n const avatarElem = new AvatarElement();\r\n avatarElem.lazyLoadQueue = this.lazyLoadQueue;\r\n avatarElem.setAttribute('peer', '' + message.media.user_id);\r\n avatarElem.classList.add('contact-avatar', 'avatar-54');\r\n\r\n contactDiv.prepend(avatarElem);\r\n\r\n bubble.classList.remove('is-message-empty');\r\n messageDiv.classList.add('contact-message');\r\n messageDiv.append(contactDiv);\r\n\r\n break;\r\n }\r\n\r\n case 'messageMediaPoll': {\r\n bubble.classList.remove('is-message-empty');\r\n \r\n const pollElement = wrapPoll(message);\r\n messageDiv.prepend(pollElement);\r\n messageDiv.classList.add('poll-message');\r\n\r\n break;\r\n }\r\n \r\n default:\r\n bubble.classList.remove('is-message-empty');\r\n messageDiv.innerHTML = '<i class=\"media-not-supported\">This message is currently not supported on Telegram Web. Try <a href=\"https://desktop.telegram.org/\" target=\"_blank\">desktop.telegram.org</a></i>';\r\n messageDiv.append(timeSpan);\r\n this.log.warn('unrecognized media type:', message.media._, message);\r\n break;\r\n }\r\n \r\n if(!processingWebPage) {\r\n bubbleContainer.append(attachmentDiv);\r\n }\r\n\r\n /* if(bubble.classList.contains('is-message-empty') && (bubble.classList.contains('photo') || bubble.classList.contains('video'))) {\r\n bubble.classList.add('no-tail');\r\n\r\n if(!bubble.classList.contains('with-media-tail')) {\r\n bubble.classList.add('use-border-radius');\r\n }\r\n } */\r\n }\r\n\r\n if(isStandaloneMedia) {\r\n bubble.classList.add('just-media');\r\n }\r\n\r\n if(this.chat.selection.isSelecting) {\r\n this.chat.selection.toggleElementCheckbox(bubble, true);\r\n }\r\n\r\n let savedFrom = '';\r\n \r\n // const needName = ((peerId < 0 && (peerId !== message.fromId || our)) && message.fromId !== rootScope.myId) || message.viaBotId;\r\n const needName = (message.fromId !== rootScope.myId && peerId < 0 && !this.appPeersManager.isBroadcast(peerId)) || message.viaBotId;\r\n if(needName || message.fwd_from || message.reply_to_mid) { // chat\r\n let title: HTMLElement | DocumentFragment;\r\n\r\n const isForwardFromChannel = message.from_id && message.from_id._ === 'peerChannel' && message.fromId === message.fwdFromId;\r\n \r\n let isHidden = message.fwd_from && !message.fwd_from.from_id && !message.fwd_from.channel_id;\r\n if(message.viaBotId) {\r\n title = document.createElement('span');\r\n title.innerText = '@' + this.appUsersManager.getUser(message.viaBotId).username;\r\n title.classList.add('peer-title');\r\n } else if(isHidden) {\r\n ///////this.log('message to render hidden', message);\r\n title = document.createElement('span');\r\n title.innerHTML = RichTextProcessor.wrapEmojiText(message.fwd_from.from_name);\r\n title.classList.add('peer-title');\r\n //title = message.fwd_from.from_name;\r\n bubble.classList.add('hidden-profile');\r\n } else {\r\n title = new PeerTitle({peerId: message.viaBotId || message.fwdFromId || message.fromId}).element;\r\n }\r\n \r\n //this.log(title);\r\n \r\n if(message.viaBotId) {\r\n //if(!bubble.classList.contains('sticker') || true) {\r\n let nameDiv = document.createElement('div');\r\n nameDiv.classList.add('name', 'is-via');\r\n nameDiv.dataset.peerId = message.viaBotId;\r\n nameDiv.append(i18n('ViaBot'), ' ', title);\r\n nameContainer.append(nameDiv);\r\n // } else {\r\n // bubble.classList.add('hide-name');\r\n // }\r\n } else if((message.fwdFromId || message.fwd_from)) {\r\n if(this.peerId !== rootScope.myId && !isForwardFromChannel) {\r\n bubble.classList.add('forwarded');\r\n }\r\n \r\n if(message.savedFrom) {\r\n savedFrom = message.savedFrom;\r\n }\r\n \r\n //if(!bubble.classList.contains('sticker') || true) {\r\n let nameDiv = document.createElement('div');\r\n nameDiv.classList.add('name');\r\n nameDiv.dataset.peerId = message.fwdFromId;\r\n\r\n if((this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID || isForwardFromChannel) && !isStandaloneMedia) {\r\n nameDiv.style.color = this.appPeersManager.getPeerColorById(message.fwdFromId, false);\r\n nameDiv.append(title);\r\n } else {\r\n /* const fromTitle = message.fromId === this.myID || appPeersManager.isBroadcast(message.fwdFromId || message.fromId) ? '' : `<div class=\"name\" data-peer-id=\"${message.fromId}\" style=\"color: ${appPeersManager.getPeerColorByID(message.fromId, false)};\">${appPeersManager.getPeerTitle(message.fromId)}</div>`;\r\n nameDiv.innerHTML = fromTitle + 'Forwarded from ' + title; */\r\n if(isStandaloneMedia) {\r\n const fragment = document.createDocumentFragment();\r\n fragment.append(document.createElement('br'));\r\n fragment.append(title);\r\n title = fragment;\r\n }\r\n nameDiv.append(i18n('ForwardedFrom', [title]));\r\n\r\n if(savedFrom) {\r\n nameDiv.dataset.savedFrom = savedFrom;\r\n }\r\n }\r\n \r\n nameContainer.append(nameDiv);\r\n //}\r\n } else {\r\n if(!isStandaloneMedia && needName) {\r\n let nameDiv = document.createElement('div');\r\n nameDiv.classList.add('name');\r\n nameDiv.append(title);\r\n\r\n if(!our) {\r\n nameDiv.style.color = this.appPeersManager.getPeerColorById(message.fromId, false);\r\n }\r\n\r\n nameDiv.dataset.peerId = message.fromId;\r\n nameContainer.append(nameDiv);\r\n } else /* if(!message.reply_to_mid) */ {\r\n bubble.classList.add('hide-name');\r\n }\r\n }\r\n\r\n if(message.reply_to_mid && message.reply_to_mid !== this.chat.threadId) {\r\n MessageRender.setReply({\r\n chat: this.chat,\r\n bubble,\r\n bubbleContainer,\r\n message\r\n });\r\n }\r\n \r\n const needAvatar = this.chat.isAnyGroup() && !isOut;\r\n if(needAvatar) {\r\n let avatarElem = new AvatarElement();\r\n avatarElem.lazyLoadQueue = this.lazyLoadQueue;\r\n avatarElem.classList.add('user-avatar', 'avatar-40');\r\n avatarElem.loadPromises = loadPromises;\r\n\r\n if(!message.fwdFromId && message.fwd_from && message.fwd_from.from_name) {\r\n avatarElem.setAttribute('peer-title', /* '🔥 FF 🔥' */message.fwd_from.from_name);\r\n }\r\n\r\n avatarElem.setAttribute('peer', '' + (((message.fwd_from && (this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID)) || isForwardFromChannel ? message.fwdFromId : message.fromId) || 0));\r\n //avatarElem.update();\r\n \r\n //this.log('exec loadDialogPhoto', message);\r\n\r\n contentWrapper.append(avatarElem);\r\n }\r\n } else {\r\n bubble.classList.add('hide-name');\r\n }\r\n\r\n if(this.chat.type === 'pinned') {\r\n savedFrom = `${this.chat.peerId}_${message.mid}`;\r\n }\r\n\r\n const isThreadStarter = messageWithReplies && messageWithReplies.mid === this.chat.threadId;\r\n if(isThreadStarter) {\r\n bubble.classList.add('is-thread-starter', 'is-group-last');\r\n }\r\n\r\n if(savedFrom && (this.chat.type === 'pinned' || message.fwd_from.saved_from_msg_id) && this.peerId !== REPLIES_PEER_ID) {\r\n const goto = document.createElement('div');\r\n goto.classList.add('bubble-beside-button', 'goto-original', 'tgico-arrow_next');\r\n bubbleContainer.append(goto);\r\n bubble.dataset.savedFrom = savedFrom;\r\n bubble.classList.add('with-beside-button');\r\n }\r\n \r\n bubble.classList.add(isOut ? 'is-out' : 'is-in');\r\n if(updatePosition) {\r\n this.renderMessagesQueue(message, bubble, reverse, loadPromises);\r\n }\r\n\r\n if(withReplies) {\r\n const isFooter = MessageRender.renderReplies({\r\n bubble,\r\n bubbleContainer,\r\n message: messageWithReplies,\r\n messageDiv,\r\n loadPromises,\r\n lazyLoadQueue: this.lazyLoadQueue\r\n });\r\n\r\n if(isFooter) {\r\n canHaveTail = true;\r\n }\r\n }\r\n\r\n if(canHaveTail) {\r\n bubble.classList.add('can-have-tail');\r\n\r\n bubbleContainer.append(generateTail());\r\n }\r\n\r\n return bubble;\r\n }\r\n\r\n private safeRenderMessage(message: any, reverse?: boolean, multipleRender?: boolean, bubble?: HTMLDivElement, updatePosition?: boolean) {\r\n try {\r\n return this.renderMessage(message, reverse, multipleRender, bubble, updatePosition);\r\n } catch(err) {\r\n this.log.error('renderMessage error:', err);\r\n }\r\n }\r\n\r\n public async performHistoryResult(history: number[], reverse: boolean, isBackLimit: boolean, additionMsgId?: number) {\r\n // commented bot getProfile in getHistory!\r\n // if(!history/* .filter((id: number) => id > 0) */.length) {\r\n // if(!isBackLimit) {\r\n // this.scrollable.loadedAll.top = true;\r\n\r\n // /* if(this.chat.type === 'discussion') {\r\n // const serviceStartMessageId = this.appMessagesManager.threadsServiceMessagesIdsStorage[this.peerId + '_' + this.chat.threadId];\r\n // if(serviceStartMessageId) history.push(serviceStartMessageId);\r\n // history.push(this.chat.threadId);\r\n // } */\r\n // } else {\r\n // this.scrollable.loadedAll.bottom = true;\r\n // }\r\n // }\r\n\r\n history = history.slice(); // need\r\n\r\n if(additionMsgId) {\r\n history.unshift(additionMsgId);\r\n }\r\n\r\n /* if(testScroll && additionMsgID) {\r\n for(let i = 0; i < 3; ++i) {\r\n let _history = history.slice();\r\n setTimeout(() => {\r\n this.performHistoryResult(_history, reverse, isBackLimit, 0, resetPromises);\r\n }, 0);\r\n }\r\n } */\r\n\r\n //console.time('appImManager render history');\r\n\r\n //await new Promise((resolve) => setTimeout(resolve, 1e3));\r\n\r\n /* if(DEBUG) {\r\n this.log('performHistoryResult: will render some messages:', history.length, this.isHeavyAnimationInProgress, this.messagesQueuePromise);\r\n } */\r\n\r\n //const padding = 10000;\r\n //const realLength = this.scrollable.container.childElementCount;\r\n let previousScrollHeightMinusTop: number/* , previousScrollHeight: number */;\r\n //if(realLength > 0/* && (reverse || isSafari) */) { // for safari need set when scrolling bottom too\r\n //if(!this.scrollable.isHeavyScrolling) {\r\n this.messagesQueueOnRender = () => {\r\n const {scrollTop, scrollHeight} = this.scrollable;\r\n\r\n //previousScrollHeight = scrollHeight;\r\n //previousScrollHeight = scrollHeight + padding;\r\n previousScrollHeightMinusTop = reverse ? scrollHeight - scrollTop : scrollTop;\r\n\r\n //this.chatInner.style.paddingTop = padding + 'px';\r\n /* if(reverse) {\r\n previousScrollHeightMinusTop = this.scrollable.scrollHeight - scrollTop;\r\n } else {\r\n previousScrollHeightMinusTop = scrollTop;\r\n } */\r\n\r\n /* if(DEBUG) {\r\n this.log('performHistoryResult: messagesQueueOnRender, scrollTop:', scrollTop, scrollHeight, previousScrollHeightMinusTop);\r\n } */\r\n this.messagesQueueOnRender = undefined;\r\n };\r\n //}\r\n //}\r\n\r\n if(this.needReflowScroll) {\r\n reflowScrollableElement(this.scrollable.container);\r\n this.needReflowScroll = false;\r\n }\r\n\r\n const cb = (mid: number) => {\r\n const message = this.chat.getMessage(mid);\r\n if(message.id > 0) {\r\n this.safeRenderMessage(message, reverse, true);\r\n } else {\r\n this.processLocalMessageRender(message);\r\n }\r\n };\r\n\r\n const length = history.length;\r\n if(reverse) for(let i = 0; i < length; ++i) cb(history[i]);\r\n else for(let i = length - 1; i >= 0; --i) cb(history[i]);\r\n\r\n if(this.chat.type !== 'scheduled') {\r\n const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);\r\n const firstSlice = historyStorage.history.first;\r\n const lastSlice = historyStorage.history.last;\r\n if(firstSlice.isEnd(SliceEnd.Bottom) && (!firstSlice.length || history.includes(firstSlice[0]))) {\r\n this.setLoaded('bottom', true, false);\r\n }\r\n \r\n if(lastSlice.isEnd(SliceEnd.Top) && (!lastSlice.length || history.includes(lastSlice[lastSlice.length - 1]))) {\r\n this.setLoaded('top', true, false);\r\n }\r\n } else {\r\n this.setLoaded('top', true);\r\n this.setLoaded('bottom', true);\r\n }\r\n\r\n await this.messagesQueuePromise;//.then(() => new Promise(resolve => setTimeout(resolve, 100)))\r\n\r\n if(this.scrollable.loadedAll.top && this.messagesQueueOnRenderAdditional) {\r\n this.messagesQueueOnRenderAdditional();\r\n\r\n if(this.messagesQueueOnRenderAdditional) {\r\n this.messagesQueueOnRenderAdditional();\r\n }\r\n }\r\n\r\n if(previousScrollHeightMinusTop !== undefined) {\r\n /* const scrollHeight = this.scrollable.scrollHeight;\r\n const addedHeight = scrollHeight - previousScrollHeight;\r\n \r\n this.chatInner.style.paddingTop = (10000 - addedHeight) + 'px'; */\r\n /* const scrollHeight = this.scrollable.scrollHeight;\r\n const addedHeight = scrollHeight - previousScrollHeight;\r\n \r\n this.chatInner.style.paddingTop = (padding - addedHeight) + 'px';\r\n \r\n //const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;\r\n const newScrollTop = reverse ? scrollHeight - addedHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;\r\n this.log('performHistoryResult: will set scrollTop', \r\n previousScrollHeightMinusTop, this.scrollable.scrollHeight, \r\n newScrollTop, this.scrollable.container.clientHeight); */\r\n //const newScrollTop = reverse ? scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;\r\n const newScrollTop = reverse ? this.scrollable.scrollHeight - previousScrollHeightMinusTop : previousScrollHeightMinusTop;\r\n \r\n /* if(DEBUG) {\r\n this.log('performHistoryResult: will set up scrollTop:', newScrollTop, this.isHeavyAnimationInProgress);\r\n } */\r\n\r\n // touchSupport for safari iOS\r\n //isTouchSupported && isApple && (this.scrollable.container.style.overflow = 'hidden');\r\n this.scrollable.scrollTop = newScrollTop;\r\n //this.scrollable.scrollTop = this.scrollable.scrollHeight;\r\n //isTouchSupported && isApple && (this.scrollable.container.style.overflow = '');\r\n\r\n if(IS_SAFARI/* && !isAppleMobile */) { // * fix blinking and jumping\r\n reflowScrollableElement(this.scrollable.container);\r\n }\r\n\r\n /* if(DEBUG) {\r\n this.log('performHistoryResult: have set up scrollTop:', newScrollTop, this.scrollable.scrollTop, this.scrollable.scrollHeight, this.isHeavyAnimationInProgress);\r\n } */\r\n }\r\n\r\n return true;\r\n }\r\n\r\n onDatePick = (timestamp: number) => {\r\n const peerId = this.peerId;\r\n this.appMessagesManager.requestHistory(peerId, 0, 2, -1, timestamp, this.chat.threadId).then(history => {\r\n if(!history?.messages?.length) {\r\n this.log.error('no history!');\r\n return;\r\n } else if(this.peerId !== peerId) {\r\n return;\r\n }\r\n\r\n this.chat.setMessageId((history.messages[0] as MyMessage).mid);\r\n //console.log('got history date:', history);\r\n });\r\n };\r\n\r\n public requestHistory(maxId: number, loadCount: number, backLimit: number) {\r\n //const middleware = this.getMiddleware();\r\n if(this.chat.type === 'chat' || this.chat.type === 'discussion') {\r\n return this.appMessagesManager.getHistory(this.peerId, maxId, loadCount, backLimit, this.chat.threadId);\r\n } else if(this.chat.type === 'pinned') {\r\n const promise = this.appMessagesManager.getSearch({\r\n peerId: this.peerId, \r\n inputFilter: {_: 'inputMessagesFilterPinned'}, \r\n maxId, \r\n limit: loadCount, \r\n backLimit\r\n })\r\n .then(value => ({history: value.history.map(m => m.mid)}));\r\n\r\n return promise;\r\n } else if(this.chat.type === 'scheduled') {\r\n return this.appMessagesManager.getScheduledMessages(this.peerId).then(mids => {\r\n // this.setLoaded('top', true);\r\n // this.setLoaded('bottom', true);\r\n return {history: mids.slice().reverse()};\r\n });\r\n }\r\n }\r\n\r\n private async animateAsLadder(additionMsgId: number, additionMsgIds: number[], isAdditionRender: boolean, backLimit: number, maxId: number) {\r\n /* const middleware = this.getMiddleware();\r\n await this.ladderDeferred; */\r\n\r\n if(this.chat.setPeerPromise && !this.resolveLadderAnimation) {\r\n // @ts-ignore\r\n this.resolveLadderAnimation = this.animateAsLadder.bind(this, additionMsgId, additionMsgIds, isAdditionRender, backLimit, maxId);\r\n return;\r\n }\r\n\r\n /* if(!middleware()) {\r\n return;\r\n } */\r\n\r\n if(!Object.keys(this.bubbles).length) {\r\n return;\r\n }\r\n\r\n let sortedMids = getObjectKeysAndSort(this.bubbles, 'desc');\r\n\r\n if(isAdditionRender && additionMsgIds.length) {\r\n sortedMids = sortedMids.filter(mid => !additionMsgIds.includes(mid));\r\n }\r\n\r\n let targetMid: number;\r\n if(backLimit) {\r\n targetMid = maxId || Math.max(...sortedMids); // * on discussion enter\r\n } else {\r\n if(additionMsgId) {\r\n targetMid = additionMsgId;\r\n } else { // * if maxId === 0\r\n targetMid = Math.max(...sortedMids);\r\n }\r\n }\r\n\r\n const topIds = sortedMids.slice(sortedMids.findIndex(mid => targetMid > mid));\r\n const middleIds = isAdditionRender ? [] : [targetMid];\r\n const bottomIds = isAdditionRender ? [] : sortedMids.slice(0, sortedMids.findIndex(mid => targetMid >= mid)).reverse();\r\n \r\n if(DEBUG) {\r\n this.log('getHistory: targeting mid:', targetMid, maxId, additionMsgId, \r\n topIds.map(m => this.appMessagesIdsManager.getServerMessageId(m)), \r\n bottomIds.map(m => this.appMessagesIdsManager.getServerMessageId(m)));\r\n }\r\n\r\n const setBubbles: HTMLElement[] = [];\r\n\r\n this.chatInner.classList.add('zoom-fading');\r\n const delay = isAdditionRender ? 10 : 40;\r\n const offsetIndex = isAdditionRender ? 0 : 1;\r\n const animateAsLadder = (mids: number[], offsetIndex = 0) => {\r\n const animationPromise = deferredPromise<void>();\r\n let lastMsDelay = 0;\r\n mids.forEach((mid, idx) => {\r\n if(!this.bubbles[mid] || this.skippedMids.has(mid)) {\r\n this.log.warn('animateAsLadder: no bubble by mid:', mid);\r\n return;\r\n }\r\n\r\n const contentWrapper = this.bubbles[mid].lastElementChild as HTMLElement;\r\n\r\n lastMsDelay = ((idx + offsetIndex) || 0.1) * delay;\r\n //lastMsDelay = (idx + offsetIndex) * delay;\r\n //lastMsDelay = (idx || 0.1) * 1000;\r\n \r\n contentWrapper.classList.add('zoom-fade');\r\n contentWrapper.style.transitionDelay = lastMsDelay + 'ms';\r\n\r\n if(idx === (mids.length - 1)) {\r\n const onTransitionEnd = (e: TransitionEvent) => {\r\n if(e.target !== contentWrapper) {\r\n return;\r\n }\r\n\r\n animationPromise.resolve();\r\n contentWrapper.removeEventListener('transitionend', onTransitionEnd);\r\n };\r\n\r\n contentWrapper.addEventListener('transitionend', onTransitionEnd);\r\n }\r\n \r\n //this.log('supa', bubble);\r\n\r\n setBubbles.push(contentWrapper);\r\n });\r\n\r\n if(!mids.length) {\r\n animationPromise.resolve();\r\n }\r\n\r\n return {lastMsDelay, animationPromise};\r\n };\r\n\r\n const topRes = animateAsLadder(topIds, offsetIndex);\r\n const middleRes = animateAsLadder(middleIds);\r\n const bottomRes = animateAsLadder(bottomIds, offsetIndex);\r\n const promises = [topRes.animationPromise, middleRes.animationPromise, bottomRes.animationPromise];\r\n const delays: number[] = [topRes.lastMsDelay, middleRes.lastMsDelay, bottomRes.lastMsDelay];\r\n\r\n if(this.onAnimateLadder) {\r\n await this.onAnimateLadder();\r\n }\r\n\r\n // fastRaf(() => {\r\n fastRaf(() => {\r\n setBubbles.forEach(contentWrapper => {\r\n contentWrapper.classList.remove('zoom-fade');\r\n });\r\n });\r\n // });\r\n\r\n let promise: Promise<any>;\r\n if(topIds.length || middleIds.length || bottomIds.length) {\r\n promise = Promise.all(promises);\r\n\r\n dispatchHeavyAnimationEvent(promise, Math.max(...delays) + 200) // * 200 - transition time\r\n .then(() => { \r\n fastRaf(() => {\r\n setBubbles.forEach(contentWrapper => {\r\n contentWrapper.style.transitionDelay = '';\r\n });\r\n\r\n this.chatInner.classList.remove('zoom-fading');\r\n });\r\n\r\n // ! в хроме, каким-то образом из-за zoom-fade класса начинает прыгать скролл при подгрузке сообщений вверх, \r\n // ! т.е. скролл не ставится, так же, как в сафари при translateZ на блок выше scrollable\r\n if(!IS_SAFARI) {\r\n this.needReflowScroll = true;\r\n }\r\n });\r\n }\r\n\r\n return promise;\r\n }\r\n\r\n private renderEmptyPlaceholder(type: 'group' | 'saved' | 'noMessages' | 'noScheduledMessages' | 'greeting', bubble: HTMLElement, message: any, elements: (Node | string)[]) {\r\n const BASE_CLASS = 'empty-bubble-placeholder';\r\n bubble.classList.add(BASE_CLASS, BASE_CLASS + '-' + type);\r\n\r\n let title: HTMLElement; \r\n if(type === 'group') title = i18n('GroupEmptyTitle1');\r\n else if(type === 'saved') title = i18n('ChatYourSelfTitle');\r\n else if(type === 'noMessages' || type === 'greeting') title = i18n('NoMessages');\r\n else if(type === 'noScheduledMessages') title = i18n('NoScheduledMessages');\r\n title.classList.add('center', BASE_CLASS + '-title');\r\n\r\n elements.push(title);\r\n\r\n let listElements: HTMLElement[];\r\n if(type === 'group') {\r\n elements.push(i18n('GroupEmptyTitle2'));\r\n listElements = [\r\n i18n('GroupDescription1'),\r\n i18n('GroupDescription2'),\r\n i18n('GroupDescription3'),\r\n i18n('GroupDescription4')\r\n ];\r\n } else if(type === 'saved') {\r\n listElements = [\r\n i18n('ChatYourSelfDescription1'),\r\n i18n('ChatYourSelfDescription2'),\r\n i18n('ChatYourSelfDescription3'),\r\n i18n('ChatYourSelfDescription4')\r\n ];\r\n } else if(type === 'greeting') {\r\n const subtitle = i18n('NoMessagesGreetingsDescription');\r\n subtitle.classList.add('center', BASE_CLASS + '-subtitle');\r\n\r\n this.messagesQueue.findAndSplice(q => q.bubble === bubble);\r\n\r\n const stickerDiv = document.createElement('div');\r\n stickerDiv.classList.add(BASE_CLASS + '-sticker');\r\n\r\n const middleware = this.getMiddleware();\r\n \r\n const loadPromise = this.appStickersManager.getGreetingSticker().then(doc => {\r\n if(!middleware()) return;\r\n\r\n const loadPromises: Promise<any>[] = [];\r\n wrapSticker({\r\n doc, \r\n // doc: appDocsManager.getDoc(\"5431607541660389336\"), // cubigator mockup\r\n div: stickerDiv,\r\n middleware,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n group: CHAT_ANIMATION_GROUP,\r\n //play: !!message.pending || !multipleRender,\r\n play: true,\r\n loop: true,\r\n withThumb: true,\r\n loadPromises\r\n });\r\n\r\n attachClickEvent(stickerDiv, (e) => {\r\n cancelEvent(e);\r\n EmoticonsDropdown.onMediaClick({target: e.target});\r\n });\r\n\r\n return Promise.all(loadPromises);\r\n });\r\n\r\n this.renderMessagesQueue(message, bubble, false, [loadPromise]);\r\n\r\n elements.push(subtitle, stickerDiv);\r\n }\r\n\r\n if(listElements) {\r\n elements.push(\r\n ...listElements.map(elem => {\r\n const span = document.createElement('span');\r\n span.classList.add(BASE_CLASS + '-list-item');\r\n span.append(elem);\r\n return span;\r\n })\r\n );\r\n \r\n if(type === 'group') {\r\n listElements.forEach(elem => {\r\n const i = document.createElement('span');\r\n i.classList.add('tgico-check');\r\n elem.prepend(i);\r\n });\r\n } else if(type === 'saved') {\r\n listElements.forEach(elem => {\r\n const i = document.createElement('span');\r\n i.classList.add(BASE_CLASS + '-list-bullet');\r\n i.innerText = '•';\r\n elem.prepend(i);\r\n });\r\n }\r\n }\r\n\r\n if(elements.length > 1) {\r\n bubble.classList.add('has-description');\r\n }\r\n\r\n elements.forEach((element: any) => element.classList.add(BASE_CLASS + '-line'));\r\n }\r\n\r\n private processLocalMessageRender(message: Message.message | Message.messageService) {\r\n const bubble = this.safeRenderMessage(message, undefined, undefined, undefined, false);\r\n bubble.classList.add('bubble-first', 'is-group-last', 'is-group-first');\r\n bubble.classList.remove('can-have-tail', 'is-in');\r\n\r\n const messageDiv = bubble.querySelector('.message, .service-msg');\r\n const elements: (Node | string)[] = [];\r\n const isBot = this.appPeersManager.isBot(this.peerId);\r\n if(isBot && message._ === 'message') {\r\n const b = document.createElement('b');\r\n b.append(i18n('BotInfoTitle'));\r\n elements.push(b, '\\n\\n');\r\n } else if(this.appPeersManager.isAnyGroup(this.peerId) && this.appPeersManager.getPeer(this.peerId).pFlags.creator) {\r\n this.renderEmptyPlaceholder('group', bubble, message, elements);\r\n } else if(rootScope.myId === this.peerId) {\r\n this.renderEmptyPlaceholder('saved', bubble, message, elements);\r\n } else if(this.peerId > 0 && !isBot && this.appMessagesManager.canSendToPeer(this.peerId) && this.chat.type === 'chat') {\r\n this.renderEmptyPlaceholder('greeting', bubble, message, elements);\r\n } else if(this.chat.type === 'scheduled') {\r\n this.renderEmptyPlaceholder('noScheduledMessages', bubble, message, elements);\r\n } else {\r\n this.renderEmptyPlaceholder('noMessages', bubble, message, elements);\r\n }\r\n\r\n /* for(let i = 1; i < elements.length; i += 2) {\r\n elements.splice(i, 0, '\\n');\r\n } */\r\n\r\n messageDiv.prepend(...elements);\r\n \r\n if(this.messagesQueueOnRenderAdditional) {\r\n this.onAnimateLadder = () => {\r\n this.chatInner.prepend(bubble);\r\n this.onAnimateLadder = undefined;\r\n\r\n // need raf here because animation won't fire if this message is single\r\n if(!this.messagesQueuePromise) {\r\n return fastRafPromise();\r\n }\r\n };\r\n } else {\r\n this.chatInner.prepend(bubble);\r\n }\r\n\r\n this.emptyPlaceholderMid = message.mid;\r\n }\r\n\r\n private generateLocalFirstMessage<T extends boolean>(service?: T, fill?: (message: GenerateLocalMessageType<T>) => void): GenerateLocalMessageType<T> {\r\n const offset = this.appMessagesIdsManager.generateMessageId(this.chat.type === 'scheduled' ? -1 : 0);\r\n\r\n const message: Omit<Message.message | Message.messageService, 'message'> & {message?: string} = {\r\n _: service ? 'messageService' : 'message',\r\n date: 0,\r\n id: -(this.peerId + offset),\r\n peer_id: this.appPeersManager.getOutputPeer(this.peerId),\r\n pFlags: {}\r\n };\r\n\r\n if(!service) {\r\n message.message = '';\r\n }\r\n\r\n assumeType<GenerateLocalMessageType<T>>(message);\r\n\r\n fill && fill(message);\r\n\r\n this.appMessagesManager.saveMessages([message]);\r\n return message;\r\n }\r\n\r\n private setLoaded(side: SliceSides, value: boolean, checkPlaceholders = true) {\r\n const willChange = this.scrollable.loadedAll[side] !== value;\r\n if(!willChange) {\r\n return;\r\n }\r\n\r\n this.scrollable.loadedAll[side] = value;\r\n\r\n /* if(!checkPlaceholders) {\r\n return;\r\n } */\r\n\r\n if(side === 'top' && value && this.appUsersManager.isBot(this.peerId)) {\r\n this.log('inject bot description');\r\n\r\n const middleware = this.getMiddleware();\r\n return this.appProfileManager.getProfile(this.peerId).then(userFull => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n if(!userFull.bot_info?.description) {\r\n this.checkIfEmptyPlaceholderNeeded();\r\n return;\r\n }\r\n\r\n const message = this.generateLocalFirstMessage(false, message => {\r\n message.message = userFull.bot_info.description;\r\n });\r\n\r\n this.processLocalMessageRender(message);\r\n });\r\n }\r\n\r\n this.checkIfEmptyPlaceholderNeeded();\r\n }\r\n\r\n public checkIfEmptyPlaceholderNeeded() {\r\n if(this.scrollable.loadedAll.top && \r\n this.scrollable.loadedAll.bottom && \r\n this.emptyPlaceholderMid === undefined && \r\n (\r\n !this.appMessagesManager.getHistoryStorage(this.peerId).count || \r\n (\r\n Object.keys(this.bubbles).length && \r\n !this.getRenderedLength()\r\n ) ||\r\n (this.chat.type === 'scheduled' && !Object.keys(this.bubbles).length)\r\n )\r\n ) {\r\n this.log('inject empty peer placeholder');\r\n\r\n const message = this.generateLocalFirstMessage(true);\r\n this.processLocalMessageRender(message);\r\n\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Load and render history\r\n * @param maxId max message id\r\n * @param reverse 'true' means up\r\n * @param isBackLimit is search\r\n * @param additionMsgId for the last message\r\n * @param justLoad do not render\r\n */\r\n public getHistory(maxId = 0, reverse = false, isBackLimit = false, additionMsgId = 0, justLoad = false): {cached: boolean, promise: Promise<boolean>} {\r\n const peerId = this.peerId;\r\n\r\n //console.time('appImManager call getHistory');\r\n const pageCount = Math.min(30, windowSize.windowH / 38/* * 1.25 */ | 0);\r\n //const loadCount = Object.keys(this.bubbles).length > 0 ? 50 : pageCount;\r\n const realLoadCount = Object.keys(this.bubbles).length > 0/* || additionMsgId */ ? Math.max(40, pageCount) : pageCount;//const realLoadCount = 50;\r\n //const realLoadCount = pageCount;//const realLoadCount = 50;\r\n let loadCount = realLoadCount;\r\n \r\n /* if(TEST_SCROLL) {\r\n //loadCount = 1;\r\n if(Object.keys(this.bubbles).length > 0)\r\n return {cached: false, promise: Promise.resolve(true)};\r\n } */\r\n if(TEST_SCROLL !== undefined) {\r\n if(TEST_SCROLL) {\r\n if(Object.keys(this.bubbles).length > 0) {\r\n --TEST_SCROLL;\r\n }\r\n } else {\r\n return {cached: false, promise: Promise.resolve(true)};\r\n }\r\n }\r\n \r\n ////console.time('render history total');\r\n \r\n let backLimit = 0;\r\n if(isBackLimit) {\r\n backLimit = loadCount;\r\n\r\n if(!reverse) { // if not jump\r\n loadCount = 0;\r\n //maxId = this.appMessagesManager.incrementMessageId(maxId, 1);\r\n }\r\n }\r\n\r\n let additionMsgIds: number[];\r\n if(additionMsgId && !isBackLimit) {\r\n if(this.chat.type === 'pinned') {\r\n additionMsgIds = [additionMsgId];\r\n } else {\r\n const historyStorage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);\r\n const slice = historyStorage.history.slice;\r\n if(slice.length < loadCount && !slice.isEnd(SliceEnd.Both)) {\r\n additionMsgIds = slice.slice();\r\n\r\n // * filter last album, because we don't know is it the last item\r\n for(let i = additionMsgIds.length - 1; i >= 0; --i) {\r\n const message = this.chat.getMessage(additionMsgIds[i]);\r\n if(message.grouped_id) additionMsgIds.splice(i, 1);\r\n else break;\r\n }\r\n\r\n maxId = additionMsgIds[additionMsgIds.length - 1] || maxId;\r\n }\r\n }\r\n }\r\n\r\n /* const result = additionMsgID ? \r\n {history: [additionMsgID]} : \r\n appMessagesManager.getHistory(this.peerId, maxId, loadCount, backLimit); */\r\n let result: ReturnType<AppMessagesManager['getHistory']> | {history: number[]} = this.requestHistory(maxId, loadCount, backLimit) as any;\r\n let resultPromise: Promise<any>;\r\n\r\n //const isFirstMessageRender = !!additionMsgID && result instanceof Promise && !appMessagesManager.getMessage(additionMsgID).grouped_id;\r\n const isAdditionRender = additionMsgIds?.length && result instanceof Promise;\r\n const isFirstMessageRender = (this.isFirstLoad && backLimit && result instanceof Promise) || isAdditionRender;\r\n if(isAdditionRender) {\r\n resultPromise = result as Promise<any>;\r\n result = {history: additionMsgIds};\r\n //additionMsgID = 0;\r\n }\r\n\r\n this.isFirstLoad = false;\r\n\r\n const processResult = async(historyResult: typeof result) => {\r\n if('offsetIdOffset' in historyResult && historyResult.history.isEnd(SliceEnd.Top)) {\r\n if(this.chat.type === 'discussion') { // * inject discussion start\r\n //this.log('discussion got history', loadCount, backLimit, historyResult, isTopEnd);\r\n const serviceStartMessageId = this.appMessagesManager.threadsServiceMessagesIdsStorage[this.peerId + '_' + this.chat.threadId];\r\n if(serviceStartMessageId) historyResult.history.push(serviceStartMessageId);\r\n historyResult.history.push(...this.chat.getMidsByMid(this.chat.threadId).reverse());\r\n }\r\n\r\n await this.setLoaded('top', true);\r\n }\r\n };\r\n\r\n const sup = (result: HistoryResult) => {\r\n /* if(maxId && result.history?.length) {\r\n if(this.bubbles[maxId]) {\r\n result.history.findAndSplice(mid => mid === maxId); \r\n }\r\n } */\r\n\r\n ////console.timeEnd('render history total');\r\n \r\n return getHeavyAnimationPromise().then(() => {\r\n return processResult(result);\r\n }).then(() => {\r\n return this.performHistoryResult(result.history || [], reverse, isBackLimit, !isAdditionRender && additionMsgId);\r\n });\r\n };\r\n\r\n const processPromise = (result: Promise<HistoryResult>) => {\r\n const promise = result.then((result) => {\r\n //this.log('getHistory not cached result by maxId:', maxId, reverse, isBackLimit, result, peerId, justLoad);\r\n\r\n if(reverse ? this.getHistoryTopPromise !== promise : this.getHistoryBottomPromise !== promise) {\r\n this.log.warn('getHistory: peer changed');\r\n ////console.timeEnd('render history total');\r\n return Promise.reject();\r\n }\r\n\r\n if(justLoad) {\r\n this.scrollable.onScroll(); // нужно делать из-за ранней прогрузки\r\n return true;\r\n }\r\n //console.timeEnd('appImManager call getHistory');\r\n\r\n return sup(result);\r\n }, (err) => {\r\n this.log.error('getHistory error:', err);\r\n throw err;\r\n });\r\n \r\n return promise;\r\n };\r\n\r\n let promise: Promise<boolean>, cached: boolean;\r\n if(result instanceof Promise) {\r\n cached = false;\r\n promise = processPromise(result);\r\n } else if(justLoad) {\r\n return null;\r\n } else {\r\n cached = true;\r\n //this.log('getHistory cached result by maxId:', maxId, reverse, isBackLimit, result, peerId, justLoad);\r\n promise = sup(result as HistoryResult);\r\n //return (reverse ? this.getHistoryTopPromise = promise : this.getHistoryBottomPromise = promise);\r\n //return this.performHistoryResult(result.history || [], reverse, isBackLimit, additionMsgID, true);\r\n }\r\n\r\n const waitPromise = isAdditionRender ? processPromise(resultPromise) : promise;\r\n\r\n if(isFirstMessageRender && rootScope.settings.animationsEnabled/* && false */) {\r\n let times = isAdditionRender ? 2 : 1;\r\n this.messagesQueueOnRenderAdditional = () => {\r\n this.log('ship went past rocks of magnets');\r\n\r\n if(--times) return;\r\n\r\n this.messagesQueueOnRenderAdditional = undefined;\r\n \r\n const promise = this.animateAsLadder(additionMsgId, additionMsgIds, isAdditionRender, backLimit, maxId);\r\n (promise || Promise.resolve()).then(() => {\r\n setTimeout(() => { // preload messages\r\n this.loadMoreHistory(reverse, true);\r\n }, 0);\r\n });\r\n };\r\n } else {\r\n this.messagesQueueOnRenderAdditional = undefined;\r\n }\r\n\r\n (reverse ? this.getHistoryTopPromise = waitPromise : this.getHistoryBottomPromise = waitPromise);\r\n waitPromise.then(() => {\r\n (reverse ? this.getHistoryTopPromise = undefined : this.getHistoryBottomPromise = undefined);\r\n });\r\n\r\n if(justLoad) {\r\n return null;\r\n }\r\n\r\n /* false && */!isFirstMessageRender && promise.then(() => {\r\n if(reverse) {\r\n this.loadedTopTimes++;\r\n this.loadedBottomTimes = Math.max(0, --this.loadedBottomTimes);\r\n } else {\r\n this.loadedBottomTimes++;\r\n this.loadedTopTimes = Math.max(0, --this.loadedTopTimes);\r\n }\r\n\r\n let ids: number[];\r\n if((reverse && this.loadedTopTimes > 2) || (!reverse && this.loadedBottomTimes > 2)) {\r\n ids = getObjectKeysAndSort(this.bubbles);\r\n }\r\n\r\n //let removeCount = loadCount / 2;\r\n const safeCount = realLoadCount * 2; // cause i've been runningrunningrunning all day\r\n //this.log('getHistory: slice loadedTimes:', reverse, pageCount, this.loadedTopTimes, this.loadedBottomTimes, ids?.length, safeCount);\r\n if(ids && ids.length > safeCount) {\r\n if(reverse) {\r\n //ids = ids.slice(-removeCount);\r\n //ids = ids.slice(removeCount * 2);\r\n ids = ids.slice(safeCount);\r\n this.setLoaded('bottom', false);\r\n\r\n //this.log('getHistory: slice bottom messages:', ids.length, loadCount);\r\n //this.getHistoryBottomPromise = undefined; // !WARNING, это нужно для обратной загрузки истории, если запрос словил флуд\r\n } else {\r\n //ids = ids.slice(0, removeCount);\r\n //ids = ids.slice(0, ids.length - (removeCount * 2));\r\n ids = ids.slice(0, ids.length - safeCount);\r\n this.setLoaded('top', false);\r\n\r\n //this.log('getHistory: slice up messages:', ids.length, loadCount);\r\n //this.getHistoryTopPromise = undefined; // !WARNING, это нужно для обратной загрузки истории, если запрос словил флуд\r\n }\r\n\r\n //this.log('getHistory: will slice ids:', ids, reverse);\r\n\r\n this.deleteMessagesByIds(ids, false);\r\n }\r\n });\r\n\r\n promise.then(() => {\r\n // preload more\r\n //if(!isFirstMessageRender) {\r\n if(this.chat.type === 'chat'/* || this.chat.type === 'discussion' */) {\r\n /* const storage = this.appMessagesManager.getHistoryStorage(peerId, this.chat.threadId);\r\n const isMaxIdInHistory = storage.history.indexOf(maxId) !== -1;\r\n if(isMaxIdInHistory || true) { // * otherwise it is a search or jump */\r\n setTimeout(() => {\r\n if(reverse) {\r\n this.loadMoreHistory(true, true);\r\n } else {\r\n this.loadMoreHistory(false, true);\r\n }\r\n }, 0);\r\n //}\r\n }\r\n //}\r\n });\r\n\r\n return {cached, promise};\r\n }\r\n\r\n public setUnreadDelimiter() {\r\n if(!(this.chat.type === 'chat' || this.chat.type === 'discussion')) {\r\n return;\r\n }\r\n\r\n if(this.attachedUnreadBubble) {\r\n return;\r\n }\r\n\r\n const historyStorage = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId);\r\n let readMaxId = this.appMessagesManager.getReadMaxIdIfUnread(this.peerId, this.chat.threadId);\r\n if(!readMaxId) return;\r\n\r\n readMaxId = Object.keys(this.bubbles)\r\n .filter(mid => !this.bubbles[mid].classList.contains('is-out'))\r\n .map(i => +i)\r\n .sort((a, b) => a - b)\r\n .find(i => i > readMaxId);\r\n\r\n if(readMaxId && this.bubbles[readMaxId]) {\r\n let bubble = this.bubbles[readMaxId];\r\n if(this.firstUnreadBubble && this.firstUnreadBubble !== bubble) {\r\n this.firstUnreadBubble.classList.remove('is-first-unread');\r\n this.firstUnreadBubble = null;\r\n }\r\n\r\n if(readMaxId !== historyStorage.maxId) {\r\n bubble.classList.add('is-first-unread');\r\n }\r\n\r\n this.firstUnreadBubble = bubble;\r\n this.attachedUnreadBubble = true;\r\n }\r\n }\r\n\r\n public deleteEmptyDateGroups() {\r\n const mustBeCount = 1 + +!!this.stickyIntersector;\r\n for(const i in this.dateMessages) {\r\n const dateMessage = this.dateMessages[i];\r\n\r\n if(dateMessage.container.childElementCount === mustBeCount) { // only date div + sentinel div\r\n dateMessage.container.remove();\r\n if(this.stickyIntersector) {\r\n this.stickyIntersector.unobserve(dateMessage.container, dateMessage.div);\r\n }\r\n delete this.dateMessages[i];\r\n }\r\n }\r\n\r\n this.checkIfEmptyPlaceholderNeeded();\r\n }\r\n}\r\n\r\nexport function generateTail() {\r\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\r\n svg.setAttributeNS(null, 'viewBox', '0 0 11 20');\r\n svg.setAttributeNS(null, 'width', '11');\r\n svg.setAttributeNS(null, 'height', '20');\r\n svg.classList.add('bubble-tail');\r\n\r\n const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');\r\n use.setAttributeNS(null, 'href', '#message-tail-filled');\r\n\r\n svg.append(use);\r\n\r\n return svg;\r\n}\r\n","export const SEND_WHEN_ONLINE_TIMESTAMP = 0x7FFFFFFE;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport { addCancelButton } from \".\";\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerOptions } from \"./peer\";\nimport appPeersManager from \"../../lib/appManagers/appPeersManager\";\nimport rootScope from \"../../lib/rootScope\";\nimport { FormatterArguments, LangPackKey } from \"../../lib/langPack\";\nimport appChatsManager from \"../../lib/appManagers/appChatsManager\";\nimport PeerTitle from \"../peerTitle\";\n\nexport default class PopupPinMessage {\n constructor(peerId: number, mid: number, unpin?: true, onConfirm?: () => void) {\n let title: LangPackKey, description: LangPackKey, descriptionArgs: FormatterArguments, \n buttons: PopupPeerOptions['buttons'] = [], checkboxes: PopupPeerOptions['checkboxes'] = [];\n\n const canUnpin = appPeersManager.canPinMessage(peerId);\n\n const callback = (checked: PopupPeerButtonCallbackCheckboxes, oneSide?: boolean, silent?: boolean) => {\n setTimeout(() => { // * костыль, потому что document.elementFromPoint вернёт popup-peer пока он будет закрываться\n let promise: Promise<any>;\n if(unpin && !mid) {\n if(canUnpin) {\n promise = appMessagesManager.unpinAllMessages(peerId);\n } else {\n promise = appMessagesManager.hidePinnedMessages(peerId);\n }\n } else {\n promise = appMessagesManager.updatePinnedMessage(peerId, mid, unpin, silent, oneSide);\n }\n\n if(onConfirm) {\n promise.then(onConfirm);\n }\n }, 300);\n };\n\n if(unpin) {\n let buttonText: LangPackKey = 'UnpinMessage';\n if(!mid) {\n if(canUnpin) {\n title = 'Popup.Unpin.AllTitle';\n description = 'Chat.UnpinAllMessagesConfirmation';\n descriptionArgs = ['' + (appMessagesManager.pinnedMessages[peerId]?.count || 1)];\n } else {\n title = 'Popup.Unpin.HideTitle';\n description = 'Popup.Unpin.HideDescription';\n buttonText = 'Popup.Unpin.Hide';\n }\n } else {\n title = 'UnpinMessageAlertTitle';\n description = 'Chat.Confirm.Unpin';\n }\n \n buttons.push({\n langKey: buttonText,\n isDanger: true,\n callback\n });\n } else {\n title = 'PinMessageAlertTitle';\n const pinButtonText: LangPackKey = 'PinMessage';\n \n if(peerId < 0) {\n buttons.push({\n langKey: pinButtonText,\n callback: (checked) => callback(checked, false, !checked.size)\n });\n\n if(appChatsManager.isBroadcast(-peerId)) {\n description = 'PinMessageAlertChannel';\n } else {\n description = 'PinMessageAlert';\n \n checkboxes.push({\n text: 'PinNotify',\n checked: true\n });\n }\n } else {\n description = 'PinMessageAlertChat';\n\n if(peerId === rootScope.myId) {\n buttons.push({\n langKey: pinButtonText,\n callback\n });\n } else {\n buttons.push({\n langKey: pinButtonText,\n callback: (checked) => callback(checked, !checked.size)\n });\n\n checkboxes.push({\n text: 'PinAlsoFor',\n textArgs: [new PeerTitle({peerId}).element],\n checked: true\n });\n }\n }\n }\n\n addCancelButton(buttons);\n\n const popup = new PopupPeer('popup-delete-chat', {\n peerId,\n titleLangKey: title,\n descriptionLangKey: description,\n descriptionLangArgs: descriptionArgs,\n buttons,\n checkboxes\n });\n\n popup.show();\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function isSelectionEmpty(selection = window.getSelection()) {\r\n if(!selection || !selection.rangeCount) {\r\n return true;\r\n }\r\n\r\n const selectionRange = selection.getRangeAt(0);\r\n if(!selectionRange.toString() || !selectionRange.START_TO_END) {\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { ReportReason } from \"../../layer\";\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\nimport appStickersManager from \"../../lib/appManagers/appStickersManager\";\nimport InputField from \"../inputField\";\nimport { toastNew } from \"../toast\";\nimport { wrapSticker } from \"../wrappers\";\nimport PopupPeer from \"./peer\";\n\nexport default class PopupReportMessagesConfirm extends PopupPeer {\n public static STICKER_EMOJI = '👮‍♀️';\n constructor(peerId: number, mids: number[], reason: ReportReason['_'], onConfirm?: () => void) {\n super('popup-report-messages-confirm', {\n noTitle: true, \n descriptionLangKey: 'ReportInfo', \n buttons: [{\n langKey: 'ReportChat',\n callback: () => {\n if(!inputField.isValid()) {\n return;\n }\n\n onConfirm && onConfirm();\n appMessagesManager.reportMessages(peerId, mids, reason, inputField.value).then(bool => {\n if(!bool) return;\n\n toastNew({\n langPackKey: 'ReportSentInfo'\n });\n });\n }\n }], \n body: true\n });\n\n const div = document.createElement('div');\n const doc = appStickersManager.getAnimatedEmojiSticker(PopupReportMessagesConfirm.STICKER_EMOJI);\n const size = 100;\n wrapSticker({\n doc,\n div,\n emoji: PopupReportMessagesConfirm.STICKER_EMOJI,\n width: size,\n height: size,\n loop: false,\n play: true\n }).finally(() => {\n this.show();\n });\n\n this.header.append(div);\n\n const inputField = new InputField({\n label: 'ReportHint',\n maxLength: 512,\n placeholder: 'ReportChatDescription'\n });\n\n this.body.append(inputField.container);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport whichChild from \"../../helpers/dom/whichChild\";\nimport { ReportReason } from \"../../layer\";\nimport appStickersManager from \"../../lib/appManagers/appStickersManager\";\nimport { LangPackKey } from \"../../lib/langPack\";\nimport Button from \"../button\";\nimport PopupPeer from \"./peer\";\nimport PopupReportMessagesConfirm from \"./reportMessagesConfirm\";\n\nexport default class PopupReportMessages extends PopupPeer {\n constructor(peerId: number, mids: number[], onConfirm?: () => void) {\n super('popup-report-messages', {titleLangKey: 'ChatTitle.ReportMessages', buttons: [], body: true});\n\n mids = mids.slice();\n\n const buttons: [LangPackKey, ReportReason['_']][] = [\n ['ReportChatSpam', 'inputReportReasonSpam'],\n ['ReportChatViolence', 'inputReportReasonViolence'],\n ['ReportChatChild', 'inputReportReasonChildAbuse'],\n ['ReportChatPornography', 'inputReportReasonPornography'],\n ['ReportChatOther', 'inputReportReasonOther']\n ];\n\n const className = 'btn-primary btn-transparent';\n buttons.forEach(b => {\n const button = Button(className, {/* icon: 'edit', */text: b[0]});\n this.body.append(button);\n });\n\n const preloadStickerPromise = appStickersManager.preloadAnimatedEmojiSticker(PopupReportMessagesConfirm.STICKER_EMOJI);\n\n attachClickEvent(this.body, (e) => {\n const target = findUpClassName(e.target, 'btn-primary');\n const reason = buttons[whichChild(target)][1];\n\n preloadStickerPromise.then(() => {\n this.hide();\n\n new PopupReportMessagesConfirm(peerId, mids, reason, onConfirm);\n });\n }, {listenerSetter: this.listenerSetter});\n \n this.body.style.margin = '0 -1rem';\n this.buttons.style.marginTop = '.5rem';\n\n this.show();\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\r\nimport type { AppPollsManager, Poll } from \"../../lib/appManagers/appPollsManager\";\r\nimport type { AppDocsManager, MyDocument } from \"../../lib/appManagers/appDocsManager\";\r\nimport type { AppMessagesIdsManager } from \"../../lib/appManagers/appMessagesIdsManager\";\r\nimport type Chat from \"./chat\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport ButtonMenu, { ButtonMenuItemOptions } from \"../buttonMenu\";\r\nimport { attachContextMenuListener, openBtnMenu, positionMenu } from \"../misc\";\r\nimport PopupDeleteMessages from \"../popups/deleteMessages\";\r\nimport PopupForward from \"../popups/forward\";\r\nimport PopupPinMessage from \"../popups/unpinMessage\";\r\nimport { copyTextToClipboard } from \"../../helpers/clipboard\";\r\nimport PopupSendNow from \"../popups/sendNow\";\r\nimport { toast } from \"../toast\";\r\nimport I18n, { LangPackKey } from \"../../lib/langPack\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent, simulateClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport isSelectionEmpty from \"../../helpers/dom/isSelectionEmpty\";\r\nimport { Message } from \"../../layer\";\r\nimport PopupReportMessages from \"../popups/reportMessages\";\r\n\r\nexport default class ChatContextMenu {\r\n private buttons: (ButtonMenuItemOptions & {verify: () => boolean, notDirect?: () => boolean, withSelection?: true})[];\r\n private element: HTMLElement;\r\n\r\n private isSelectable: boolean;\r\n private isSelected: boolean;\r\n private target: HTMLElement;\r\n private isTargetAGroupedItem: boolean;\r\n private isTextSelected: boolean;\r\n private isAnchorTarget: boolean;\r\n private isUsernameTarget: boolean;\r\n private peerId: number;\r\n private mid: number;\r\n private message: any;\r\n\r\n constructor(private attachTo: HTMLElement, \r\n private chat: Chat, \r\n private appMessagesManager: AppMessagesManager, \r\n private appPeersManager: AppPeersManager, \r\n private appPollsManager: AppPollsManager,\r\n private appDocsManager: AppDocsManager,\r\n private appMessagesIdsManager: AppMessagesIdsManager\r\n ) {\r\n const onContextMenu = (e: MouseEvent | Touch | TouchEvent) => {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n let bubble: HTMLElement, contentWrapper: HTMLElement;\r\n\r\n try {\r\n contentWrapper = findUpClassName(e.target, 'bubble-content-wrapper');\r\n bubble = contentWrapper ? contentWrapper.parentElement : findUpClassName(e.target, 'bubble');\r\n } catch(e) {}\r\n\r\n // ! context menu click by date bubble (there is no pointer-events)\r\n if(!bubble || bubble.classList.contains('bubble-first')) return;\r\n\r\n if(e instanceof MouseEvent || e.hasOwnProperty('preventDefault')) (e as any).preventDefault();\r\n if(this.element.classList.contains('active')) {\r\n return false;\r\n }\r\n if(e instanceof MouseEvent || e.hasOwnProperty('cancelBubble')) (e as any).cancelBubble = true;\r\n\r\n let mid = +bubble.dataset.mid;\r\n if(!mid) return;\r\n\r\n this.isSelectable = this.chat.selection.canSelectBubble(bubble);\r\n this.peerId = this.chat.peerId;\r\n //this.msgID = msgID;\r\n this.target = e.target as HTMLElement;\r\n this.isTextSelected = !isSelectionEmpty();\r\n this.isAnchorTarget = this.target.tagName === 'A' && (\r\n (this.target as HTMLAnchorElement).target === '_blank' || \r\n this.target.classList.contains('anchor-url')\r\n );\r\n this.isUsernameTarget = this.target.tagName === 'A' && this.target.classList.contains('mention');\r\n\r\n // * если открыть контекстное меню для альбома не по бабблу, и последний элемент не выбран, чтобы показать остальные пункты\r\n if(chat.selection.isSelecting && !contentWrapper) {\r\n const mids = this.chat.getMidsByMid(mid);\r\n if(mids.length > 1) {\r\n const selectedMid = this.chat.selection.isMidSelected(this.peerId, mid) ? \r\n mid : \r\n mids.find(mid => this.chat.selection.isMidSelected(this.peerId, mid));\r\n if(selectedMid) {\r\n mid = selectedMid;\r\n }\r\n }\r\n }\r\n\r\n const groupedItem = findUpClassName(this.target, 'grouped-item');\r\n this.isTargetAGroupedItem = !!groupedItem;\r\n if(groupedItem) {\r\n this.mid = +groupedItem.dataset.mid;\r\n } else {\r\n this.mid = mid;\r\n }\r\n\r\n this.isSelected = this.chat.selection.isMidSelected(this.peerId, this.mid);\r\n this.message = this.chat.getMessage(this.mid);\r\n\r\n this.buttons.forEach(button => {\r\n let good: boolean;\r\n\r\n //if((appImManager.chatSelection.isSelecting && !button.withSelection) || (button.withSelection && !appImManager.chatSelection.isSelecting)) {\r\n if(chat.selection.isSelecting && !button.withSelection) {\r\n good = false;\r\n } else {\r\n good = contentWrapper || IS_TOUCH_SUPPORTED || true ? \r\n button.verify() : \r\n button.notDirect && button.verify() && button.notDirect();\r\n }\r\n\r\n button.element.classList.toggle('hide', !good);\r\n });\r\n\r\n const side: 'left' | 'right' = bubble.classList.contains('is-in') ? 'left' : 'right';\r\n //bubble.parentElement.append(this.element);\r\n //appImManager.log('contextmenu', e, bubble, side);\r\n positionMenu((e as TouchEvent).touches ? (e as TouchEvent).touches[0] : e as MouseEvent, this.element, side);\r\n openBtnMenu(this.element, () => {\r\n this.peerId = this.mid = 0;\r\n this.target = null;\r\n });\r\n };\r\n\r\n if(IS_TOUCH_SUPPORTED/* && false */) {\r\n attachClickEvent(attachTo, (e) => {\r\n if(chat.selection.isSelecting) {\r\n return;\r\n }\r\n\r\n const className = (e.target as HTMLElement).className;\r\n if(!className || !className.includes) return;\r\n\r\n chat.log('touchend', e);\r\n\r\n const good = ['bubble', 'bubble-content-wrapper', 'bubble-content', 'message', 'time', 'inner'].find(c => className.match(new RegExp(c + '($|\\\\s)')));\r\n if(good) {\r\n cancelEvent(e);\r\n //onContextMenu((e as TouchEvent).changedTouches[0]);\r\n // onContextMenu((e as TouchEvent).changedTouches ? (e as TouchEvent).changedTouches[0] : e as MouseEvent);\r\n onContextMenu(e);\r\n }\r\n }, {listenerSetter: this.chat.bubbles.listenerSetter});\r\n } else attachContextMenuListener(attachTo, onContextMenu, this.chat.bubbles.listenerSetter);\r\n }\r\n\r\n private init() {\r\n this.buttons = [{\r\n icon: 'send2',\r\n text: 'MessageScheduleSend',\r\n onClick: this.onSendScheduledClick,\r\n verify: () => this.chat.type === 'scheduled' && !this.message.pFlags.is_outgoing\r\n }, {\r\n icon: 'send2',\r\n text: 'Message.Context.Selection.SendNow',\r\n onClick: this.onSendScheduledClick,\r\n verify: () => this.chat.type === 'scheduled' && this.isSelected && !this.chat.selection.selectionSendNowBtn.hasAttribute('disabled'),\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'schedule',\r\n text: 'MessageScheduleEditTime',\r\n onClick: () => {\r\n this.chat.input.scheduleSending(() => {\r\n this.appMessagesManager.editMessage(this.message, this.message.message, {\r\n scheduleDate: this.chat.input.scheduleDate,\r\n entities: this.message.entities\r\n });\r\n\r\n this.chat.input.onMessageSent(false, false);\r\n }, new Date(this.message.date * 1000));\r\n },\r\n verify: () => this.chat.type === 'scheduled'\r\n }, {\r\n icon: 'reply',\r\n text: 'Reply',\r\n onClick: this.onReplyClick,\r\n verify: () => this.appMessagesManager.canSendToPeer(this.peerId, this.chat.threadId) && \r\n !this.message.pFlags.is_outgoing && \r\n !!this.chat.input.messageInput && \r\n this.chat.type !== 'scheduled'/* ,\r\n cancelEvent: true */\r\n }, {\r\n icon: 'edit',\r\n text: 'Edit',\r\n onClick: this.onEditClick,\r\n verify: () => this.appMessagesManager.canEditMessage(this.message, 'text') && !!this.chat.input.messageInput\r\n }, {\r\n icon: 'copy',\r\n text: 'Copy',\r\n onClick: this.onCopyClick,\r\n verify: () => !!this.message.message && !this.isTextSelected && (!this.isAnchorTarget || this.message.message !== this.target.innerText)\r\n }, {\r\n icon: 'copy',\r\n text: 'Chat.CopySelectedText',\r\n onClick: this.onCopyClick,\r\n verify: () => !!this.message.message && this.isTextSelected\r\n }, {\r\n icon: 'copy',\r\n text: 'Message.Context.Selection.Copy',\r\n onClick: this.onCopyClick,\r\n verify: () => {\r\n if(!this.isSelected) {\r\n return false;\r\n }\r\n\r\n for(const [peerId, mids] of this.chat.selection.selectedMids) {\r\n for(const mid of mids) {\r\n if(!!this.appMessagesManager.getMessageByPeer(peerId, mid).message) {\r\n return true;\r\n }\r\n }\r\n }\r\n\r\n return false;\r\n },\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'copy',\r\n text: 'CopyLink',\r\n onClick: this.onCopyAnchorLinkClick,\r\n verify: () => this.isAnchorTarget,\r\n withSelection: true\r\n }, {\r\n icon: 'copy',\r\n text: 'Text.Context.Copy.Username',\r\n onClick: () => {\r\n copyTextToClipboard(this.target.innerHTML);\r\n },\r\n verify: () => this.isUsernameTarget,\r\n withSelection: true\r\n }, {\r\n icon: 'copy',\r\n text: 'Text.Context.Copy.Hashtag',\r\n onClick: () => {\r\n copyTextToClipboard(this.target.innerHTML);\r\n },\r\n verify: () => this.target.classList.contains('anchor-hashtag'),\r\n withSelection: true\r\n }, {\r\n icon: 'link',\r\n text: 'MessageContext.CopyMessageLink1',\r\n onClick: this.onCopyLinkClick,\r\n verify: () => this.appPeersManager.isChannel(this.peerId) && !this.message.pFlags.is_outgoing\r\n }, {\r\n icon: 'pin',\r\n text: 'Message.Context.Pin',\r\n onClick: this.onPinClick,\r\n verify: () => !this.message.pFlags.is_outgoing && \r\n this.message._ !== 'messageService' && \r\n !this.message.pFlags.pinned && \r\n this.appPeersManager.canPinMessage(this.peerId) && \r\n this.chat.type !== 'scheduled',\r\n }, {\r\n icon: 'unpin',\r\n text: 'Message.Context.Unpin',\r\n onClick: this.onUnpinClick,\r\n verify: () => this.message.pFlags.pinned && this.appPeersManager.canPinMessage(this.peerId),\r\n }, {\r\n icon: 'download',\r\n text: 'MediaViewer.Context.Download',\r\n onClick: () => {\r\n this.appDocsManager.saveDocFile(this.message.media.document);\r\n },\r\n verify: () => {\r\n if(this.message.pFlags.is_outgoing) {\r\n return false;\r\n }\r\n \r\n const doc: MyDocument = this.message.media?.document;\r\n if(!doc) return false;\r\n \r\n let hasTarget = !!IS_TOUCH_SUPPORTED;\r\n const isGoodType = !doc.type || !(['gif', 'video', 'sticker'] as MyDocument['type'][]).includes(doc.type);\r\n if(isGoodType) hasTarget = hasTarget || !!findUpClassName(this.target, 'document') || !!findUpClassName(this.target, 'audio');\r\n return isGoodType && hasTarget;\r\n }\r\n }, {\r\n icon: 'checkretract',\r\n text: 'Chat.Poll.Unvote',\r\n onClick: this.onRetractVote,\r\n verify: () => {\r\n const poll = this.message.media?.poll as Poll;\r\n return poll && poll.chosenIndexes.length && !poll.pFlags.closed && !poll.pFlags.quiz;\r\n }/* ,\r\n cancelEvent: true */\r\n }, {\r\n icon: 'stop',\r\n text: 'Chat.Poll.Stop',\r\n onClick: this.onStopPoll,\r\n verify: () => {\r\n const poll = this.message.media?.poll;\r\n return this.appMessagesManager.canEditMessage(this.message, 'poll') && poll && !poll.pFlags.closed && !this.message.pFlags.is_outgoing;\r\n }/* ,\r\n cancelEvent: true */\r\n }, {\r\n icon: 'forward',\r\n text: 'Forward',\r\n onClick: this.onForwardClick,\r\n verify: () => this.chat.type !== 'scheduled' && !this.message.pFlags.is_outgoing && this.message._ !== 'messageService'\r\n }, {\r\n icon: 'forward',\r\n text: 'Message.Context.Selection.Forward',\r\n onClick: this.onForwardClick,\r\n verify: () => this.chat.selection.selectionForwardBtn && \r\n this.isSelected && \r\n !this.chat.selection.selectionForwardBtn.hasAttribute('disabled'),\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'flag',\r\n text: 'ReportChat',\r\n onClick: () => {\r\n new PopupReportMessages(this.peerId, [this.mid]);\r\n },\r\n verify: () => !this.message.pFlags.out && this.message._ === 'message' && !this.message.pFlags.is_outgoing && this.appPeersManager.isChannel(this.peerId),\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'select',\r\n text: 'Message.Context.Select',\r\n onClick: this.onSelectClick,\r\n verify: () => !this.message.action && !this.isSelected && this.isSelectable,\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'select',\r\n text: 'Message.Context.Selection.Clear',\r\n onClick: this.onClearSelectionClick,\r\n verify: () => this.isSelected,\r\n notDirect: () => true,\r\n withSelection: true\r\n }, {\r\n icon: 'delete danger',\r\n text: 'Delete',\r\n onClick: this.onDeleteClick,\r\n verify: () => this.appMessagesManager.canDeleteMessage(this.message)\r\n }, {\r\n icon: 'delete danger',\r\n text: 'Message.Context.Selection.Delete',\r\n onClick: this.onDeleteClick,\r\n verify: () => this.isSelected && !this.chat.selection.selectionDeleteBtn.hasAttribute('disabled'),\r\n notDirect: () => true,\r\n withSelection: true\r\n }];\r\n\r\n this.element = ButtonMenu(this.buttons, this.chat.bubbles.listenerSetter);\r\n this.element.id = 'bubble-contextmenu';\r\n this.element.classList.add('contextmenu');\r\n this.chat.container.append(this.element);\r\n }\r\n\r\n private onSendScheduledClick = () => {\r\n if(this.chat.selection.isSelecting) {\r\n simulateClickEvent(this.chat.selection.selectionSendNowBtn);\r\n } else {\r\n new PopupSendNow(this.peerId, this.chat.getMidsByMid(this.mid));\r\n }\r\n };\r\n\r\n private onReplyClick = () => {\r\n this.chat.input.initMessageReply(this.mid);\r\n };\r\n\r\n private onEditClick = () => {\r\n this.chat.input.initMessageEditing(this.mid);\r\n };\r\n\r\n private onCopyClick = () => {\r\n if(isSelectionEmpty()) {\r\n const mids = this.chat.selection.isSelecting ? \r\n [...this.chat.selection.selectedMids.get(this.peerId)].sort((a, b) => a - b) : \r\n [this.mid];\r\n\r\n const str = mids.reduce((acc, mid) => {\r\n const message = this.chat.getMessage(mid);\r\n return acc + (message?.message ? message.message + '\\n' : '');\r\n }, '').trim();\r\n\r\n copyTextToClipboard(str);\r\n } else {\r\n document.execCommand('copy');\r\n //cancelSelection();\r\n }\r\n };\r\n\r\n private onCopyAnchorLinkClick = () => {\r\n copyTextToClipboard((this.target as HTMLAnchorElement).href);\r\n };\r\n\r\n private onCopyLinkClick = () => {\r\n let threadMessage: Message.message;\r\n if(this.chat.type === 'discussion') {\r\n threadMessage = this.appMessagesManager.getMessageByPeer(this.peerId, this.chat.threadId);\r\n }\r\n\r\n const username = this.appPeersManager.getPeerUsername(threadMessage ? threadMessage.fromId : this.peerId);\r\n const msgId = this.appMessagesIdsManager.getServerMessageId(this.mid);\r\n let url = 'https://t.me/';\r\n let key: LangPackKey;\r\n if(username) {\r\n url += username + '/' + (threadMessage ? this.appMessagesIdsManager.getServerMessageId(threadMessage.fwd_from.channel_post) : msgId);\r\n if(threadMessage) url += '?comment=' + msgId;\r\n key = 'LinkCopied';\r\n } else {\r\n url += 'c/' + Math.abs(this.peerId) + '/' + msgId;\r\n if(threadMessage) url += '?thread=' + this.appMessagesIdsManager.getServerMessageId(threadMessage.mid);\r\n key = 'LinkCopiedPrivateInfo';\r\n }\r\n\r\n toast(I18n.format(key, true));\r\n\r\n copyTextToClipboard(url);\r\n };\r\n\r\n private onPinClick = () => {\r\n new PopupPinMessage(this.peerId, this.mid);\r\n };\r\n\r\n private onUnpinClick = () => {\r\n new PopupPinMessage(this.peerId, this.mid, true);\r\n };\r\n\r\n private onRetractVote = () => {\r\n this.appPollsManager.sendVote(this.message, []);\r\n };\r\n\r\n private onStopPoll = () => {\r\n this.appPollsManager.stopPoll(this.message);\r\n };\r\n\r\n private onForwardClick = () => {\r\n if(this.chat.selection.isSelecting) {\r\n simulateClickEvent(this.chat.selection.selectionForwardBtn);\r\n } else {\r\n const mids = this.isTargetAGroupedItem ? [this.mid] : this.chat.getMidsByMid(this.mid);\r\n new PopupForward({\r\n [this.peerId]: mids\r\n });\r\n }\r\n };\r\n\r\n private onSelectClick = () => {\r\n this.chat.selection.toggleByElement(findUpClassName(this.target, 'grouped-item') || findUpClassName(this.target, 'bubble'));\r\n };\r\n\r\n private onClearSelectionClick = () => {\r\n this.chat.selection.cancelSelection();\r\n };\r\n\r\n private onDeleteClick = () => {\r\n if(this.chat.selection.isSelecting) {\r\n simulateClickEvent(this.chat.selection.selectionDeleteBtn);\r\n } else {\r\n new PopupDeleteMessages(this.peerId, this.isTargetAGroupedItem ? [this.mid] : this.chat.getMidsByMid(this.mid), this.chat.type);\r\n }\r\n };\r\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport ButtonMenu, { ButtonMenuItemOptions } from \"../buttonMenu\";\r\nimport { attachContextMenuListener, openBtnMenu } from \"../misc\";\r\n\r\nexport default class SendMenu {\r\n public sendMenu: HTMLDivElement;\r\n private sendMenuButtons: (ButtonMenuItemOptions & {verify: () => boolean})[];\r\n private type: 'schedule' | 'reminder';\r\n \r\n constructor(options: {\r\n onSilentClick: () => void,\r\n onScheduleClick: () => void,\r\n listenerSetter?: ListenerSetter,\r\n openSide: string,\r\n onContextElement: HTMLElement,\r\n onOpen?: () => boolean\r\n }) {\r\n this.sendMenuButtons = [{\r\n icon: 'mute',\r\n text: 'Chat.Send.WithoutSound',\r\n onClick: options.onSilentClick,\r\n verify: () => this.type === 'schedule'\r\n }, {\r\n icon: 'schedule',\r\n text: 'Chat.Send.ScheduledMessage',\r\n onClick: options.onScheduleClick,\r\n verify: () => this.type === 'schedule'\r\n }, {\r\n icon: 'schedule',\r\n text: 'Chat.Send.SetReminder',\r\n onClick: options.onScheduleClick,\r\n verify: () => this.type === 'reminder'\r\n }];\r\n \r\n this.sendMenu = ButtonMenu(this.sendMenuButtons, options.listenerSetter);\r\n this.sendMenu.classList.add('menu-send', options.openSide);\r\n\r\n attachContextMenuListener(options.onContextElement, (e: any) => {\r\n if(options.onOpen && !options.onOpen()) {\r\n return;\r\n }\r\n\r\n this.sendMenuButtons.forEach(button => {\r\n button.element.classList.toggle('hide', !button.verify());\r\n });\r\n \r\n cancelEvent(e);\r\n openBtnMenu(this.sendMenu);\r\n }, options.listenerSetter);\r\n }\r\n\r\n public setPeerId(peerId: number) {\r\n this.type = peerId === rootScope.myId ? 'reminder' : 'schedule';\r\n }\r\n};\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { Poll } from \"../../lib/appManagers/appPollsManager\";\r\nimport type Chat from \"../chat/chat\";\r\nimport PopupElement from \".\";\r\nimport CheckboxField from \"../checkboxField\";\r\nimport InputField from \"../inputField\";\r\nimport RadioField from \"../radioField\";\r\nimport Scrollable from \"../scrollable\";\r\nimport SendContextMenu from \"../chat/sendContextMenu\";\r\nimport I18n, { _i18n } from \"../../lib/langPack\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport getRichValue from \"../../helpers/dom/getRichValue\";\r\nimport isInputEmpty from \"../../helpers/dom/isInputEmpty\";\r\nimport whichChild from \"../../helpers/dom/whichChild\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\n\r\nconst MAX_LENGTH_QUESTION = 255;\r\nconst MAX_LENGTH_OPTION = 100;\r\nconst MAX_LENGTH_SOLUTION = 200;\r\n\r\nexport default class PopupCreatePoll extends PopupElement {\r\n private questionInputField: InputField;\r\n private questions: HTMLElement;\r\n private scrollable: Scrollable;\r\n private tempId = 0;\r\n\r\n private anonymousCheckboxField: CheckboxField;\r\n private multipleCheckboxField: PopupCreatePoll['anonymousCheckboxField'];\r\n private quizCheckboxField: PopupCreatePoll['anonymousCheckboxField'];\r\n\r\n private correctAnswers: Uint8Array[];\r\n private quizSolutionField: InputField;\r\n private optionInputFields: InputField[];\r\n\r\n constructor(private chat: Chat) {\r\n super('popup-create-poll popup-new-media', null, {closable: true, withConfirm: 'Create', body: true});\r\n\r\n _i18n(this.title, 'NewPoll');\r\n\r\n this.questionInputField = new InputField({\r\n placeholder: 'AskAQuestion',\r\n label: 'AskAQuestion', \r\n name: 'question', \r\n maxLength: MAX_LENGTH_QUESTION\r\n });\r\n\r\n this.listenerSetter.add(this.questionInputField.input)('input', () => {\r\n this.handleChange();\r\n });\r\n\r\n this.optionInputFields = [];\r\n\r\n if(this.chat.type !== 'scheduled') {\r\n const sendMenu = new SendContextMenu({\r\n onSilentClick: () => {\r\n this.chat.input.sendSilent = true;\r\n this.send();\r\n },\r\n onScheduleClick: () => {\r\n this.chat.input.scheduleSending(() => {\r\n this.send();\r\n });\r\n },\r\n openSide: 'bottom-left',\r\n onContextElement: this.btnConfirm,\r\n });\r\n \r\n sendMenu.setPeerId(this.chat.peerId);\r\n\r\n this.header.append(sendMenu.sendMenu);\r\n }\r\n\r\n this.header.append(this.questionInputField.container);\r\n\r\n const hr = document.createElement('hr');\r\n const d = document.createElement('div');\r\n d.classList.add('caption');\r\n _i18n(d, 'PollOptions');\r\n\r\n this.questions = document.createElement('form');\r\n this.questions.classList.add('poll-create-questions');\r\n\r\n const dd = document.createElement('div');\r\n dd.classList.add('poll-create-settings');\r\n \r\n const settingsCaption = document.createElement('div');\r\n settingsCaption.classList.add('caption');\r\n _i18n(settingsCaption, 'Settings');\r\n\r\n if(!this.chat.appPeersManager.isBroadcast(this.chat.peerId)) {\r\n this.anonymousCheckboxField = new CheckboxField({\r\n text: 'NewPoll.Anonymous', \r\n name: 'anonymous'\r\n });\r\n this.anonymousCheckboxField.input.checked = true;\r\n dd.append(this.anonymousCheckboxField.label);\r\n }\r\n \r\n this.multipleCheckboxField = new CheckboxField({\r\n text: 'NewPoll.MultipleChoice', \r\n name: 'multiple'\r\n });\r\n this.quizCheckboxField = new CheckboxField({\r\n text: 'NewPoll.Quiz', \r\n name: 'quiz'\r\n });\r\n\r\n this.listenerSetter.add(this.multipleCheckboxField.input)('change', () => {\r\n const checked = this.multipleCheckboxField.input.checked;\r\n this.quizCheckboxField.input.toggleAttribute('disabled', checked);\r\n });\r\n\r\n this.listenerSetter.add(this.quizCheckboxField.input)('change', () => {\r\n const checked = this.quizCheckboxField.input.checked;\r\n\r\n (Array.from(this.questions.children) as HTMLElement[]).map(el => {\r\n el.classList.toggle('radio-field', checked);\r\n });\r\n\r\n if(!checked) {\r\n this.correctAnswers = undefined;\r\n this.quizSolutionField.setValueSilently('');\r\n }\r\n\r\n quizElements.forEach(el => el.classList.toggle('hide', !checked));\r\n\r\n this.multipleCheckboxField.input.toggleAttribute('disabled', checked);\r\n this.handleChange();\r\n });\r\n\r\n dd.append(this.multipleCheckboxField.label, this.quizCheckboxField.label);\r\n\r\n const quizElements: HTMLElement[] = [];\r\n\r\n const quizSolutionCaption = document.createElement('div');\r\n quizSolutionCaption.classList.add('caption');\r\n _i18n(quizSolutionCaption, 'AccDescrQuizExplanation');\r\n\r\n const quizHr = document.createElement('hr');\r\n\r\n const quizSolutionContainer = document.createElement('div');\r\n quizSolutionContainer.classList.add('poll-create-questions');\r\n\r\n this.quizSolutionField = new InputField({\r\n placeholder: 'NewPoll.Explanation.Placeholder', \r\n label: 'NewPoll.Explanation.Placeholder',\r\n name: 'solution',\r\n maxLength: MAX_LENGTH_SOLUTION\r\n });\r\n\r\n this.listenerSetter.add(this.questionInputField.input)('input', () => {\r\n this.handleChange();\r\n });\r\n\r\n const quizSolutionSubtitle = document.createElement('div');\r\n quizSolutionSubtitle.classList.add('subtitle');\r\n _i18n(quizSolutionSubtitle, 'AddAnExplanationInfo');\r\n\r\n quizSolutionContainer.append(this.quizSolutionField.container, quizSolutionSubtitle);\r\n\r\n quizElements.push(quizHr, quizSolutionCaption, quizSolutionContainer);\r\n quizElements.forEach(el => el.classList.add('hide'));\r\n\r\n this.body.parentElement.insertBefore(hr, this.body);\r\n this.body.append(d, this.questions, document.createElement('hr'), settingsCaption, dd, ...quizElements);\r\n\r\n attachClickEvent(this.btnConfirm, this.onSubmitClick, {listenerSetter: this.listenerSetter});\r\n\r\n this.scrollable = new Scrollable(this.body);\r\n this.appendMoreField();\r\n\r\n this.onEscape = () => {\r\n return !this.getFilledAnswers().length;\r\n };\r\n\r\n this.handleChange();\r\n }\r\n\r\n private getFilledAnswers() {\r\n const answers = Array.from(this.questions.children).map((el, idx) => {\r\n const input = el.querySelector('.input-field-input') as HTMLElement;\r\n return input instanceof HTMLInputElement ? input.value : getRichValue(input, false).value;\r\n }).filter(v => !!v.trim());\r\n\r\n return answers;\r\n }\r\n\r\n private onSubmitClick = () => {\r\n this.send();\r\n };\r\n\r\n private validate() {\r\n const question = this.questionInputField.value;\r\n if(!question) {\r\n return false;\r\n }\r\n\r\n if(question.length > MAX_LENGTH_QUESTION) {\r\n return false;\r\n }\r\n\r\n if(this.quizCheckboxField.input.checked && !this.correctAnswers?.length) {\r\n return false;\r\n }\r\n\r\n const answers = this.getFilledAnswers();\r\n if(answers.length < 2) {\r\n return false;\r\n }\r\n \r\n const tooLongOption = answers.find(a => a.length > MAX_LENGTH_OPTION);\r\n if(tooLongOption) {\r\n return false;\r\n }\r\n\r\n const {value: quizSolution} = getRichValue(this.quizSolutionField.input, false);\r\n if(quizSolution.length > MAX_LENGTH_SOLUTION) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n private handleChange() {\r\n const valid = this.validate();\r\n this.btnConfirm.toggleAttribute('disabled', !valid);\r\n }\r\n\r\n public send(force = false) {\r\n const question = this.questionInputField.value;\r\n\r\n const answers = this.getFilledAnswers();\r\n\r\n const {value: quizSolution, entities: quizSolutionEntities} = getRichValue(this.quizSolutionField.input);\r\n\r\n if(this.chat.type === 'scheduled' && !force) {\r\n this.chat.input.scheduleSending(() => {\r\n this.send(true);\r\n });\r\n \r\n return;\r\n }\r\n\r\n this.hide();\r\n\r\n //const randomID = [nextRandomInt(0xFFFFFFFF), nextRandomInt(0xFFFFFFFF)];\r\n //const randomIDS = bigint(randomID[0]).shiftLeft(32).add(bigint(randomID[1])).toString();\r\n\r\n const pFlags: Poll['pFlags'] = {};\r\n\r\n if(this.anonymousCheckboxField && !this.anonymousCheckboxField.input.checked) {\r\n pFlags.public_voters = true;\r\n }\r\n\r\n if(this.multipleCheckboxField.input.checked) {\r\n pFlags.multiple_choice = true;\r\n }\r\n\r\n if(this.quizCheckboxField.input.checked) {\r\n pFlags.quiz = true;\r\n }\r\n\r\n const poll: Poll = {\r\n _: 'poll',\r\n pFlags,\r\n question,\r\n answers: answers.map((value, idx) => {\r\n return {\r\n _: 'pollAnswer',\r\n text: value,\r\n option: new Uint8Array([idx])\r\n };\r\n }),\r\n id: undefined\r\n };\r\n //poll.id = randomIDS;\r\n\r\n const inputMediaPoll = this.chat.appPollsManager.getInputMediaPoll(poll, this.correctAnswers, quizSolution, quizSolutionEntities);\r\n\r\n //console.log('Will try to create poll:', inputMediaPoll);\r\n\r\n this.chat.appMessagesManager.sendOther(this.chat.peerId, inputMediaPoll, {\r\n threadId: this.chat.threadId,\r\n replyToMsgId: this.chat.input.replyToMsgId,\r\n scheduleDate: this.chat.input.scheduleDate,\r\n silent: this.chat.input.sendSilent\r\n });\r\n\r\n if(this.chat.input.helperType === 'reply') {\r\n this.chat.input.clearHelper();\r\n }\r\n\r\n this.chat.input.onMessageSent(false, false);\r\n }\r\n\r\n onInput = (e: Event) => {\r\n const target = e.target as HTMLInputElement;\r\n\r\n const radioLabel = findUpTag(target, 'LABEL');\r\n const isEmpty = isInputEmpty(target);\r\n if(!isEmpty) {\r\n target.parentElement.classList.add('is-filled');\r\n radioLabel.classList.remove('hidden-widget');\r\n radioLabel.firstElementChild.removeAttribute('disabled');\r\n }\r\n\r\n const isLast = !radioLabel.nextElementSibling;\r\n if(isLast && !isEmpty && this.questions.childElementCount < 10) {\r\n this.appendMoreField();\r\n }\r\n\r\n this.handleChange();\r\n };\r\n\r\n onDeleteClick = (e: MouseEvent) => {\r\n const target = e.target as HTMLSpanElement;\r\n const label = findUpTag(target, 'LABEL');\r\n const idx = whichChild(label);\r\n\r\n if(this.correctAnswers && this.correctAnswers[0][0] === idx) {\r\n this.correctAnswers = undefined;\r\n }\r\n\r\n label.remove();\r\n this.optionInputFields.splice(idx, 1);\r\n\r\n this.optionInputFields.forEach((inputField, idx) => {\r\n inputField.options.labelOptions.length = 0;\r\n inputField.options.labelOptions.push(idx + 1);\r\n const i18nElement = I18n.weakMap.get(inputField.label.firstElementChild as HTMLElement);\r\n i18nElement.update();\r\n });\r\n\r\n this.handleChange();\r\n };\r\n\r\n private appendMoreField() {\r\n const tempId = this.tempId++;\r\n const idx = this.questions.childElementCount + 1;\r\n const questionField = new InputField({\r\n placeholder: 'NewPoll.OptionsAddOption', \r\n label: 'NewPoll.OptionLabel',\r\n labelOptions: [idx],\r\n name: 'question-' + tempId, \r\n maxLength: MAX_LENGTH_OPTION\r\n });\r\n this.listenerSetter.add(questionField.input)('input', this.onInput);\r\n\r\n const radioField = new RadioField({\r\n text: '', \r\n name: 'question'\r\n });\r\n radioField.main.append(questionField.container);\r\n attachClickEvent(questionField.input, cancelEvent, {listenerSetter: this.listenerSetter});\r\n radioField.label.classList.add('hidden-widget');\r\n radioField.input.disabled = true;\r\n if(!this.quizCheckboxField.input.checked) {\r\n radioField.label.classList.remove('radio-field');\r\n }\r\n this.listenerSetter.add(radioField.input)('change', () => {\r\n const checked = radioField.input.checked;\r\n if(checked) {\r\n const idx = whichChild(radioField.label);\r\n this.correctAnswers = [new Uint8Array([idx])];\r\n this.handleChange();\r\n }\r\n });\r\n\r\n const deleteBtn = document.createElement('span');\r\n deleteBtn.classList.add('btn-icon', 'tgico-close');\r\n questionField.container.append(deleteBtn);\r\n \r\n attachClickEvent(deleteBtn, this.onDeleteClick, {listenerSetter: this.listenerSetter, once: true});\r\n\r\n this.questions.append(radioField.label);\r\n\r\n this.scrollable.scrollIntoViewNew(this.questions.lastElementChild as HTMLElement, 'center');\r\n //this.scrollable.scrollTo(this.scrollable.scrollHeight, 'top', true, true);\r\n\r\n this.optionInputFields.push(questionField);\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type Chat from \"../chat/chat\";\nimport InputField from \"../inputField\";\nimport PopupElement from \".\";\nimport Scrollable from \"../scrollable\";\nimport { toast } from \"../toast\";\nimport { prepareAlbum, wrapDocument } from \"../wrappers\";\nimport CheckboxField from \"../checkboxField\";\nimport SendContextMenu from \"../chat/sendContextMenu\";\nimport { createPosterFromVideo, onMediaLoad } from \"../../helpers/files\";\nimport { MyDocument } from \"../../lib/appManagers/appDocsManager\";\nimport I18n, { i18n, LangPackKey } from \"../../lib/langPack\";\nimport appDownloadManager from \"../../lib/appManagers/appDownloadManager\";\nimport calcImageInBox from \"../../helpers/calcImageInBox\";\nimport placeCaretAtEnd from \"../../helpers/dom/placeCaretAtEnd\";\nimport rootScope from \"../../lib/rootScope\";\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\nimport { MediaSize } from \"../../helpers/mediaSizes\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';\n\ntype SendFileParams = Partial<{\n file: File,\n objectURL: string,\n thumb: {\n blob: Blob,\n url: string,\n size: MediaSize\n },\n width: number,\n height: number,\n duration: number,\n noSound: boolean\n}>;\n\n// TODO: .gif upload as video\n\nexport default class PopupNewMedia extends PopupElement {\n private input: HTMLElement;\n private mediaContainer: HTMLElement;\n private groupCheckboxField: CheckboxField;\n private wasInputValue = '';\n\n private willAttach: Partial<{\n type: 'media' | 'document',\n isMedia: true,\n group: boolean,\n sendFileDetails: SendFileParams[]\n }> = {\n sendFileDetails: [],\n group: false\n };\n private inputField: InputField;\n\n constructor(private chat: Chat, files: File[], willAttachType: PopupNewMedia['willAttach']['type']) {\n super('popup-send-photo popup-new-media', null, {closable: true, withConfirm: 'Modal.Send', confirmShortcutIsSendShortcut: true});\n\n this.willAttach.type = willAttachType;\n\n attachClickEvent(this.btnConfirm, () => this.send(), {listenerSetter: this.listenerSetter});\n\n if(this.chat.type !== 'scheduled') {\n const sendMenu = new SendContextMenu({\n onSilentClick: () => {\n this.chat.input.sendSilent = true;\n this.send();\n },\n onScheduleClick: () => {\n this.chat.input.scheduleSending(() => {\n this.send();\n });\n },\n openSide: 'bottom-left',\n onContextElement: this.btnConfirm,\n listenerSetter: this.listenerSetter\n });\n\n sendMenu.setPeerId(this.chat.peerId);\n\n this.header.append(sendMenu.sendMenu);\n }\n\n this.mediaContainer = document.createElement('div');\n this.mediaContainer.classList.add('popup-photo');\n const scrollable = new Scrollable(null);\n scrollable.container.append(this.mediaContainer);\n \n this.inputField = new InputField({\n placeholder: 'PreviewSender.CaptionPlaceholder',\n label: 'Caption',\n name: 'photo-caption',\n maxLength: rootScope.config.caption_length_max,\n showLengthOn: 80\n });\n this.input = this.inputField.input;\n\n this.inputField.value = this.wasInputValue = this.chat.input.messageInputField.input.innerHTML;\n this.chat.input.messageInputField.value = '';\n\n this.container.append(scrollable.container);\n\n if(files.length > 1) {\n this.groupCheckboxField = new CheckboxField({\n text: 'PreviewSender.GroupItems', \n name: 'group-items'\n });\n this.container.append(this.groupCheckboxField.label, this.inputField.container);\n \n this.groupCheckboxField.input.checked = true;\n this.willAttach.group = true;\n\n this.listenerSetter.add(this.groupCheckboxField.input)('change', () => {\n const checked = this.groupCheckboxField.input.checked;\n \n this.willAttach.group = checked;\n this.willAttach.sendFileDetails.length = 0;\n\n //this.mediaContainer.innerHTML = '';\n //this.container.classList.remove('is-media', 'is-document', 'is-album');\n this.attachFiles(files);\n });\n }\n \n this.container.append(this.inputField.container);\n\n this.attachFiles(files);\n }\n\n private onKeyDown = (e: KeyboardEvent) => {\n const target = e.target as HTMLElement;\n if(target !== this.input) {\n if(target.tagName === 'INPUT' || target.hasAttribute('contenteditable')) {\n return;\n }\n\n this.input.focus();\n placeCaretAtEnd(this.input);\n }\n };\n\n public send(force = false) {\n if(this.chat.type === 'scheduled' && !force) {\n this.chat.input.scheduleSending(() => {\n this.send(true);\n });\n \n return;\n }\n\n let caption = this.inputField.value;\n if(caption.length > rootScope.config.caption_length_max) {\n toast(I18n.format('Error.PreviewSender.CaptionTooLong', true));\n return;\n }\n\n this.hide();\n const willAttach = this.willAttach;\n willAttach.isMedia = willAttach.type === 'media' ? true : undefined;\n\n //console.log('will send files with options:', willAttach);\n\n const peerId = this.chat.peerId;\n const input = this.chat.input;\n const silent = input.sendSilent;\n const scheduleDate = input.scheduleDate;\n\n if(willAttach.sendFileDetails.length > 1 && willAttach.group) {\n for(let i = 0; i < willAttach.sendFileDetails.length;) {\n let firstType = willAttach.sendFileDetails[i].file.type.split('/')[0];\n for(var k = 0; k < 10 && i < willAttach.sendFileDetails.length; ++i, ++k) {\n const type = willAttach.sendFileDetails[i].file.type.split('/')[0];\n if(firstType !== type) {\n break;\n }\n }\n\n const w = {...willAttach};\n w.sendFileDetails = willAttach.sendFileDetails.slice(i - k, i);\n\n this.chat.appMessagesManager.sendAlbum(peerId, w.sendFileDetails.map(d => d.file), Object.assign({\n caption,\n replyToMsgId: input.replyToMsgId,\n threadId: this.chat.threadId,\n isMedia: willAttach.isMedia,\n silent,\n scheduleDate,\n clearDraft: true as true\n }, w));\n\n caption = undefined;\n input.replyToMsgId = this.chat.threadId;\n }\n } else {\n if(caption) {\n if(willAttach.sendFileDetails.length > 1) {\n this.chat.appMessagesManager.sendText(peerId, caption, {\n replyToMsgId: input.replyToMsgId, \n threadId: this.chat.threadId,\n silent, \n scheduleDate,\n clearDraft: true\n });\n caption = '';\n //input.replyToMsgId = undefined;\n }\n }\n \n const promises = willAttach.sendFileDetails.map(params => {\n const promise = this.chat.appMessagesManager.sendFile(peerId, params.file, Object.assign({\n //isMedia: willAttach.isMedia, \n isMedia: willAttach.isMedia, \n caption,\n replyToMsgId: input.replyToMsgId,\n threadId: this.chat.threadId,\n silent,\n scheduleDate,\n clearDraft: true as true\n }, params));\n\n caption = '';\n return promise;\n });\n\n input.replyToMsgId = this.chat.threadId;\n }\n\n //Promise.all(promises);\n\n //appMessagesManager.sendFile(appImManager.peerId, willAttach.file, willAttach);\n \n input.onMessageSent();\n }\n\n public attachFile = (file: File) => {\n const willAttach = this.willAttach;\n return new Promise<HTMLDivElement>((resolve) => {\n const params: SendFileParams = {};\n params.file = file;\n //console.log('selected file:', file, typeof(file), willAttach);\n const itemDiv = document.createElement('div');\n switch(willAttach.type) {\n case 'media': {\n const isVideo = file.type.indexOf('video/') === 0;\n\n itemDiv.classList.add('popup-item-media');\n\n if(isVideo) {\n const video = document.createElement('video');\n const source = document.createElement('source');\n source.src = params.objectURL = URL.createObjectURL(file);\n video.autoplay = true;\n video.controls = false;\n video.muted = true;\n video.setAttribute('playsinline', 'true');\n\n video.addEventListener('timeupdate', () => {\n video.pause();\n }, {once: true});\n\n onMediaLoad(video).then(() => {\n params.width = video.videoWidth;\n params.height = video.videoHeight;\n params.duration = Math.floor(video.duration);\n \n const audioDecodedByteCount = (video as any).webkitAudioDecodedByteCount;\n if(audioDecodedByteCount !== undefined) {\n params.noSound = !audioDecodedByteCount;\n }\n\n itemDiv.append(video);\n createPosterFromVideo(video).then(thumb => {\n params.thumb = {\n url: URL.createObjectURL(thumb.blob),\n ...thumb\n };\n resolve(itemDiv);\n });\n });\n\n video.append(source);\n } else {\n const img = new Image();\n img.src = params.objectURL = URL.createObjectURL(file);\n img.onload = () => {\n params.width = img.naturalWidth;\n params.height = img.naturalHeight;\n\n itemDiv.append(img);\n resolve(itemDiv);\n };\n }\n \n break;\n }\n\n case 'document': {\n const isPhoto = file.type.indexOf('image/') !== -1;\n const isAudio = file.type.indexOf('audio/') !== -1;\n if(isPhoto || isAudio) {\n params.objectURL = URL.createObjectURL(file);\n }\n\n const doc = {\n _: 'document',\n file: file,\n file_name: file.name || '',\n fileName: file.name ? RichTextProcessor.wrapEmojiText(file.name) : '',\n size: file.size,\n type: isPhoto ? 'photo' : 'doc'\n } as MyDocument;\n\n const cacheContext = appDownloadManager.getCacheContext(doc);\n cacheContext.url = params.objectURL;\n cacheContext.downloaded = file.size;\n\n const docDiv = wrapDocument({\n message: {\n _: 'message',\n pFlags: {\n is_outgoing: true\n },\n mid: 0,\n peerId: 0,\n media: {\n _: 'messageMediaDocument',\n document: doc\n }\n } as any\n });\n\n const finish = () => {\n itemDiv.append(docDiv);\n resolve(itemDiv);\n };\n\n if(isPhoto) {\n const img = new Image();\n img.src = params.objectURL;\n img.onload = () => {\n params.width = img.naturalWidth;\n params.height = img.naturalHeight;\n\n finish();\n };\n\n img.onerror = finish;\n } else {\n finish();\n }\n\n break;\n }\n }\n\n willAttach.sendFileDetails.push(params);\n });\n };\n\n public attachFiles(files: File[]) {\n const container = this.container;\n const willAttach = this.willAttach;\n\n /* if(files.length > 10 && willAttach.type === 'media') {\n willAttach.type = 'document';\n } */\n\n if(willAttach.type === 'media') {\n files = files.filter(file => MEDIA_MIME_TYPES_SUPPORTED.has(file.type));\n } else {\n files = files.slice();\n }\n\n Promise.all(files.map(this.attachFile)).then(results => {\n this.container.classList.remove('is-media', 'is-document', 'is-album');\n this.mediaContainer.innerHTML = '';\n\n if(files.length) {\n let key: LangPackKey;\n const args: any[] = [];\n if(willAttach.type === 'document') {\n key = 'PreviewSender.SendFile';\n args.push(files.length);\n container.classList.add('is-document');\n } else {\n container.classList.add('is-media');\n \n let foundPhotos = 0;\n let foundVideos = 0;\n files.forEach(file => {\n if(file.type.indexOf('image/') === 0) ++foundPhotos;\n else if(file.type.indexOf('video/') === 0) ++foundVideos;\n });\n \n const sum = foundPhotos + foundVideos;\n if(sum > 1 && willAttach.group) {\n key = 'PreviewSender.SendAlbum';\n const albumsLength = Math.ceil(sum / 10);\n args.push(albumsLength);\n } else if(foundPhotos) {\n key = 'PreviewSender.SendPhoto';\n args.push(foundPhotos);\n } else if(foundVideos) {\n key = 'PreviewSender.SendVideo';\n args.push(foundVideos);\n }\n }\n\n this.title.textContent = '';\n this.title.append(i18n(key, args));\n }\n\n if(willAttach.type === 'media') {\n if(willAttach.sendFileDetails.length > 1 && willAttach.group) {\n container.classList.add('is-album');\n\n for(let i = 0; i < results.length; i += 10) {\n const albumContainer = document.createElement('div');\n albumContainer.classList.add('popup-album');\n\n albumContainer.append(...results.slice(i, i + 10));\n prepareAlbum({\n container: albumContainer,\n items: willAttach.sendFileDetails.slice(i, i + 10).map(o => ({w: o.width, h: o.height})),\n maxWidth: 380,\n minWidth: 100,\n spacing: 4\n });\n\n this.mediaContainer.append(albumContainer);\n }\n\n //console.log('chatInput album layout:', layout);\n } else {\n for(let i = 0; i < results.length; ++i) {\n const params = willAttach.sendFileDetails[i];\n const div = results[i];\n const size = calcImageInBox(params.width, params.height, 380, 320);\n div.style.width = size.width + 'px';\n div.style.height = size.height + 'px';\n this.mediaContainer.append(div);\n }\n }\n } else {\n this.mediaContainer.append(...results);\n }\n\n // show now\n if(!this.element.classList.contains('active')) {\n this.listenerSetter.add(document.body)('keydown', this.onKeyDown);\n this.onClose = () => {\n if(this.wasInputValue) {\n this.chat.input.messageInputField.value = this.wasInputValue;\n }\n };\n this.show();\n }\n });\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport fastSmoothScroll from \"../fastSmoothScroll\";\r\nimport { cancelEvent } from \"./cancelEvent\";\r\nimport { attachClickEvent, detachClickEvent } from \"./clickEvent\";\r\nimport findUpAsChild from \"./findUpAsChild\";\r\nimport findUpClassName from \"./findUpClassName\";\r\n\r\ntype ArrowKey = 'ArrowUp' | 'ArrowDown' | 'ArrowLeft' | 'ArrowRight';\r\nconst HANDLE_EVENT = 'keydown';\r\nconst ACTIVE_CLASS_NAME = 'active';\r\n\r\nconst AXIS_Y_KEYS: ArrowKey[] = ['ArrowUp', 'ArrowDown'];\r\nconst AXIS_X_KEYS: ArrowKey[] = ['ArrowLeft', 'ArrowRight'];\r\n\r\nexport default function attachListNavigation({list, type, onSelect, once, waitForKey}: {\r\n list: HTMLElement, \r\n type: 'xy' | 'x' | 'y',\r\n onSelect: (target: Element) => void | boolean,\r\n once: boolean,\r\n waitForKey?: string\r\n}) {\r\n const keyNames = new Set(type === 'xy' ? AXIS_Y_KEYS.concat(AXIS_X_KEYS) : (type === 'x' ? AXIS_X_KEYS : AXIS_Y_KEYS)); \r\n\r\n let target: Element;\r\n const getCurrentTarget = () => {\r\n return target || list.querySelector('.' + ACTIVE_CLASS_NAME) || list.firstElementChild;\r\n };\r\n\r\n const setCurrentTarget = (_target: Element, scrollTo: boolean) => {\r\n if(target === _target) {\r\n return;\r\n }\r\n\r\n let hadTarget = false;\r\n if(target) {\r\n hadTarget = true;\r\n target.classList.remove(ACTIVE_CLASS_NAME);\r\n }\r\n\r\n target = _target;\r\n if(!target) return;\r\n target.classList.add(ACTIVE_CLASS_NAME);\r\n\r\n if(hadTarget && scrollable && scrollTo) {\r\n fastSmoothScroll(scrollable, target as HTMLElement, 'center', undefined, undefined, undefined, 100, type === 'x' ? 'x' : 'y');\r\n }\r\n };\r\n\r\n const getNextTargetX = (currentTarget: Element, isNext: boolean) => {\r\n let nextTarget: Element;\r\n if(isNext) nextTarget = currentTarget.nextElementSibling || list.firstElementChild;\r\n else nextTarget = currentTarget.previousElementSibling || list.lastElementChild;\r\n\r\n return nextTarget;\r\n };\r\n\r\n const getNextTargetY = (currentTarget: Element, isNext: boolean) => {\r\n const property = isNext ? 'nextElementSibling' : 'previousElementSibling';\r\n const endProperty = isNext ? 'firstElementChild' : 'lastElementChild';\r\n const currentRect = currentTarget.getBoundingClientRect();\r\n\r\n let nextTarget = currentTarget[property] || list[endProperty];\r\n while(nextTarget !== currentTarget) {\r\n const targetRect = nextTarget.getBoundingClientRect();\r\n if(targetRect.x === currentRect.x && targetRect.y !== currentRect.y) {\r\n break;\r\n }\r\n\r\n nextTarget = nextTarget[property] || list[endProperty];\r\n }\r\n\r\n return nextTarget;\r\n };\r\n\r\n let handleArrowKey: (currentTarget: Element, key: ArrowKey) => Element;\r\n if(type === 'xy') { // flex-direction: row; flex-wrap: wrap;\r\n handleArrowKey = (currentTarget, key) => {\r\n if(key === 'ArrowUp' || key === 'ArrowDown') return getNextTargetY(currentTarget, key === 'ArrowDown');\r\n else return getNextTargetX(currentTarget, key === 'ArrowRight');\r\n };\r\n } else { // flex-direction: row | column;\r\n handleArrowKey = (currentTarget, key) => getNextTargetX(currentTarget, key === 'ArrowRight' || key === 'ArrowDown');\r\n }\r\n\r\n let onKeyDown = (e: KeyboardEvent) => {\r\n if(!keyNames.has(e.key as any)) {\r\n if(e.key === 'Enter') {\r\n cancelEvent(e);\r\n fireSelect(getCurrentTarget());\r\n }\r\n\r\n return;\r\n }\r\n\r\n cancelEvent(e);\r\n\r\n if(list.childElementCount > 1) {\r\n let currentTarget = getCurrentTarget();\r\n currentTarget = handleArrowKey(currentTarget, e.key as any);\r\n setCurrentTarget(currentTarget, true);\r\n }\r\n };\r\n\r\n const scrollable = findUpClassName(list, 'scrollable');\r\n list.classList.add('navigable-list');\r\n\r\n const onMouseMove = (e: MouseEvent) => {\r\n const target = findUpAsChild(e.target, list) as HTMLElement;\r\n if(!target) {\r\n return;\r\n }\r\n\r\n setCurrentTarget(target, false);\r\n };\r\n\r\n const onClick = (e: Event) => {\r\n cancelEvent(e); // cancel keyboard closening\r\n\r\n const target = findUpAsChild(e.target, list) as HTMLElement;\r\n if(!target) {\r\n return;\r\n }\r\n\r\n setCurrentTarget(target, false);\r\n fireSelect(getCurrentTarget());\r\n };\r\n\r\n const fireSelect = (target: Element) => {\r\n const canContinue = onSelect(target);\r\n if(canContinue !== undefined ? !canContinue : once) {\r\n detach();\r\n }\r\n };\r\n\r\n const detach = () => {\r\n // input.removeEventListener(HANDLE_EVENT, onKeyDown, {capture: true});\r\n document.removeEventListener(HANDLE_EVENT, onKeyDown, {capture: true});\r\n list.removeEventListener('mousemove', onMouseMove);\r\n detachClickEvent(list, onClick);\r\n };\r\n\r\n const resetTarget = () => {\r\n if(waitForKey) return;\r\n setCurrentTarget(list.firstElementChild, false);\r\n };\r\n\r\n if(waitForKey) {\r\n const _onKeyDown = onKeyDown;\r\n onKeyDown = (e) => {\r\n if(e.key === waitForKey) {\r\n cancelEvent(e);\r\n\r\n document.removeEventListener(HANDLE_EVENT, onKeyDown, {capture: true});\r\n onKeyDown = _onKeyDown;\r\n document.addEventListener(HANDLE_EVENT, onKeyDown, {capture: true, passive: false});\r\n\r\n waitForKey = undefined;\r\n resetTarget();\r\n }\r\n };\r\n } else {\r\n resetTarget();\r\n }\r\n\r\n // const input = document.activeElement as HTMLElement;\r\n // input.addEventListener(HANDLE_EVENT, onKeyDown, {capture: true, passive: false});\r\n document.addEventListener(HANDLE_EVENT, onKeyDown, {capture: true, passive: false});\r\n list.addEventListener('mousemove', onMouseMove, {passive: true});\r\n attachClickEvent(list, onClick);\r\n\r\n return {\r\n detach,\r\n resetTarget\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport attachListNavigation from \"../../helpers/dom/attachListNavigation\";\r\nimport EventListenerBase from \"../../helpers/eventListenerBase\";\r\nimport { safeAssign } from \"../../helpers/object\";\r\nimport { IS_MOBILE } from \"../../environment/userAgent\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport appNavigationController, { NavigationItem } from \"../appNavigationController\";\r\nimport SetTransition from \"../singleTransition\";\r\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\r\n\r\nexport default class AutocompleteHelper extends EventListenerBase<{\r\n hidden: () => void,\r\n visible: () => void,\r\n}> {\r\n protected hidden = true;\r\n protected container: HTMLElement;\r\n protected list: HTMLElement;\r\n protected resetTarget: () => void;\r\n protected detach: () => void;\r\n protected init?(): void;\r\n\r\n protected controller: AutocompleteHelperController;\r\n protected listType: 'xy' | 'x' | 'y';\r\n protected onSelect: (target: Element) => boolean | void;\r\n protected waitForKey?: string;\r\n\r\n protected navigationItem: NavigationItem;\r\n\r\n constructor(options: {\r\n appendTo: HTMLElement,\r\n controller: AutocompleteHelper['controller'],\r\n listType: AutocompleteHelper['listType'],\r\n onSelect: AutocompleteHelper['onSelect'],\r\n waitForKey?: AutocompleteHelper['waitForKey']\r\n }) {\r\n super(false);\r\n\r\n safeAssign(this, options);\r\n \r\n this.container = document.createElement('div');\r\n this.container.classList.add('autocomplete-helper', 'z-depth-1');\r\n \r\n options.appendTo.append(this.container);\r\n \r\n this.attachNavigation();\r\n\r\n this.controller.addHelper(this);\r\n }\r\n\r\n protected onVisible = () => {\r\n if(this.detach) { // it can be so because 'visible' calls before animation's end\r\n this.detach();\r\n }\r\n\r\n const list = this.list;\r\n const {detach, resetTarget} = attachListNavigation({\r\n list, \r\n type: this.listType,\r\n onSelect: this.onSelect,\r\n once: true,\r\n waitForKey: this.waitForKey\r\n });\r\n\r\n this.detach = detach;\r\n this.resetTarget = resetTarget;\r\n if(!IS_MOBILE && !this.navigationItem) {\r\n this.navigationItem = {\r\n type: 'autocomplete-helper',\r\n onPop: () => {\r\n this.navigationItem = undefined;\r\n this.toggle(true);\r\n },\r\n noBlurOnPop: true\r\n };\r\n\r\n appNavigationController.pushItem(this.navigationItem);\r\n }\r\n\r\n this.addEventListener('hidden', () => {\r\n this.resetTarget = undefined;\r\n this.detach = undefined;\r\n\r\n list.innerHTML = '';\r\n detach();\r\n\r\n if(this.navigationItem) {\r\n appNavigationController.removeItem(this.navigationItem);\r\n this.navigationItem = undefined;\r\n }\r\n }, {once: true});\r\n };\r\n\r\n protected attachNavigation() {\r\n this.addEventListener('visible', this.onVisible);\r\n }\r\n\r\n public toggle(hide?: boolean, fromController = false) {\r\n if(this.init) {\r\n return;\r\n }\r\n \r\n if(hide === undefined) {\r\n hide = this.container.classList.contains('is-visible') && !this.container.classList.contains('backwards');\r\n }\r\n\r\n if(this.hidden === hide) {\r\n if(!hide) {\r\n this.dispatchEvent('visible'); // reset target and listener\r\n }\r\n\r\n return;\r\n }\r\n\r\n this.hidden = hide;\r\n\r\n if(!hide) {\r\n this.controller.hideOtherHelpers(this);\r\n this.dispatchEvent('visible'); // fire it before so target will be set\r\n } else {\r\n if(this.navigationItem) {\r\n appNavigationController.removeItem(this.navigationItem);\r\n this.navigationItem = undefined;\r\n }\r\n\r\n if(!fromController) {\r\n this.controller.hideOtherHelpers();\r\n }\r\n\r\n if(this.detach) { // force detach here\r\n this.detach();\r\n }\r\n }\r\n\r\n SetTransition(this.container, 'is-visible', !hide, rootScope.settings.animationsEnabled ? 200 : 0, () => {\r\n this.hidden && this.dispatchEvent('hidden');\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport { MyDocument } from \"../../lib/appManagers/appDocsManager\";\r\nimport { CHAT_ANIMATION_GROUP } from \"../../lib/appManagers/appImManager\";\r\nimport appStickersManager from \"../../lib/appManagers/appStickersManager\";\r\nimport { EmoticonsDropdown } from \"../emoticonsDropdown\";\r\nimport { SuperStickerRenderer } from \"../emoticonsDropdown/tabs/stickers\";\r\nimport LazyLoadQueue from \"../lazyLoadQueue\";\r\nimport Scrollable from \"../scrollable\";\r\nimport AutocompleteHelper from \"./autocompleteHelper\";\r\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\r\n\r\nexport default class StickersHelper extends AutocompleteHelper {\r\n private scrollable: Scrollable;\r\n private superStickerRenderer: SuperStickerRenderer;\r\n private lazyLoadQueue: LazyLoadQueue;\r\n private onChangeScreen: () => void;\r\n\r\n constructor(appendTo: HTMLElement, controller: AutocompleteHelperController) {\r\n super({\r\n appendTo, \r\n controller,\r\n listType: 'xy', \r\n onSelect: (target) => {\r\n return !EmoticonsDropdown.onMediaClick({target}, true);\r\n }, \r\n waitForKey: 'ArrowUp'\r\n });\r\n\r\n this.container.classList.add('stickers-helper');\r\n\r\n this.addEventListener('visible', () => {\r\n setTimeout(() => { // it is not rendered yet\r\n this.scrollable.container.scrollTop = 0;\r\n }, 0);\r\n });\r\n\r\n this.addEventListener('hidden', () => {\r\n if(this.onChangeScreen) {\r\n mediaSizes.removeEventListener('changeScreen', this.onChangeScreen);\r\n this.onChangeScreen = undefined;\r\n }\r\n });\r\n }\r\n\r\n public checkEmoticon(emoticon: string) {\r\n const middleware = this.controller.getMiddleware();\r\n\r\n if(this.lazyLoadQueue) {\r\n this.lazyLoadQueue.clear();\r\n }\r\n\r\n appStickersManager.getStickersByEmoticon(emoticon)\r\n .then((stickers) => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n const container = this.list.cloneNode() as HTMLElement;\r\n\r\n let ready: Promise<void>;\r\n\r\n this.lazyLoadQueue.clear();\r\n if(stickers.length) {\r\n ready = new Promise<void>((resolve) => {\r\n const promises: Promise<any>[] = [];\r\n stickers.forEach(sticker => {\r\n container.append(this.superStickerRenderer.renderSticker(sticker as MyDocument, undefined, promises));\r\n });\r\n\r\n (Promise.all(promises) as Promise<any>).finally(resolve);\r\n });\r\n } else {\r\n ready = Promise.resolve();\r\n }\r\n\r\n ready.then(() => {\r\n this.list.replaceWith(container);\r\n this.list = container;\r\n\r\n if(!this.onChangeScreen) {\r\n this.onChangeScreen = () => {\r\n const width = (this.list.childElementCount * mediaSizes.active.esgSticker.width) + (this.list.childElementCount - 1 * 1);\r\n this.list.style.width = width + 'px';\r\n };\r\n mediaSizes.addEventListener('changeScreen', this.onChangeScreen);\r\n }\r\n\r\n this.onChangeScreen();\r\n\r\n this.toggle(!stickers.length);\r\n this.scrollable.scrollTop = 0;\r\n });\r\n });\r\n }\r\n\r\n protected init() {\r\n this.list = document.createElement('div');\r\n this.list.classList.add('stickers-helper-stickers', 'super-stickers');\r\n\r\n this.container.append(this.list);\r\n\r\n this.scrollable = new Scrollable(this.container);\r\n this.lazyLoadQueue = new LazyLoadQueue();\r\n this.superStickerRenderer = new SuperStickerRenderer(this.lazyLoadQueue, CHAT_ANIMATION_GROUP);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport { SEND_WHEN_ONLINE_TIMESTAMP } from \"../../lib/mtproto/constants\";\r\nimport Button from \"../button\";\r\nimport PopupDatePicker from \"./datePicker\";\r\n\r\nconst getMinDate = () => {\r\n const date = new Date();\r\n //date.setDate(date.getDate() - 1);\r\n date.setHours(0, 0, 0, 0);\r\n return date;\r\n};\r\n\r\nconst getMaxDate = () => {\r\n const date = new Date();\r\n date.setFullYear(date.getFullYear() + 1);\r\n date.setDate(date.getDate() - 1);\r\n return date;\r\n};\r\n\r\nconst checkDate = (date: Date) => {\r\n return date.getTime() > getMaxDate().getTime() ? new Date() : date;\r\n};\r\n\r\nexport default class PopupSchedule extends PopupDatePicker {\r\n constructor(initDate: Date, onPick: (timestamp: number) => void, canSendWhenOnline: boolean) {\r\n super(checkDate(initDate), onPick, {\r\n noButtons: true,\r\n noTitle: true,\r\n closable: true,\r\n withConfirm: true,\r\n minDate: getMinDate(),\r\n maxDate: getMaxDate(),\r\n withTime: true,\r\n showOverflowMonths: true,\r\n confirmShortcutIsSendShortcut: true\r\n });\r\n\r\n this.element.classList.add('popup-schedule');\r\n this.header.append(this.controlsDiv);\r\n this.title.replaceWith(this.monthTitle);\r\n this.body.append(this.btnConfirm);\r\n\r\n if(canSendWhenOnline) {\r\n const btnSendWhenOnline = Button('btn-primary btn-secondary btn-primary-transparent primary', {text: 'Schedule.SendWhenOnline'});\r\n this.body.append(btnSendWhenOnline);\r\n\r\n attachClickEvent(btnSendWhenOnline, () => {\r\n onPick(SEND_WHEN_ONLINE_TIMESTAMP);\r\n this.hide();\r\n });\r\n }\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport { MessageEntity } from \"../../layer\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport getRichElementValue from \"./getRichElementValue\";\r\n\r\nexport default function getRichValueWithCaret(field: HTMLElement, withEntities = true) {\r\n const lines: string[] = [];\r\n const line: string[] = [];\r\n\r\n const sel = window.getSelection();\r\n let selNode: Node;\r\n let selOffset: number;\r\n if(sel && sel.rangeCount) {\r\n const range = sel.getRangeAt(0);\r\n if(range.startContainer &&\r\n range.startContainer == range.endContainer &&\r\n range.startOffset == range.endOffset) {\r\n selNode = range.startContainer;\r\n selOffset = range.startOffset;\r\n }\r\n }\r\n\r\n const entities: MessageEntity[] = withEntities ? [] : undefined;\r\n getRichElementValue(field, lines, line, selNode, selOffset, entities);\r\n\r\n if(line.length) {\r\n lines.push(line.join(''));\r\n }\r\n\r\n let value = lines.join('\\n');\r\n const caretPos = value.indexOf('\\x01');\r\n if(caretPos != -1) {\r\n value = value.substr(0, caretPos) + value.substr(caretPos + 1);\r\n }\r\n value = value.replace(/\\u00A0/g, ' ');\r\n\r\n if(entities) {\r\n RichTextProcessor.combineSameEntities(entities);\r\n }\r\n\r\n return {value, entities, caretPos};\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type ChatInput from \"./input\";\r\nimport type { AppEmojiManager } from \"../../lib/appManagers/appEmojiManager\";\r\nimport { appendEmoji, getEmojiFromElement } from \"../emoticonsDropdown/tabs/emoji\";\r\nimport { ScrollableX } from \"../scrollable\";\r\nimport AutocompleteHelper from \"./autocompleteHelper\";\r\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\r\n\r\nexport default class EmojiHelper extends AutocompleteHelper {\r\n private scrollable: ScrollableX;\r\n\r\n constructor(appendTo: HTMLElement, \r\n controller: AutocompleteHelperController, \r\n chatInput: ChatInput, \r\n private appEmojiManager: AppEmojiManager) {\r\n super({\r\n appendTo,\r\n controller, \r\n listType: 'x', \r\n onSelect: (target) => {\r\n chatInput.onEmojiSelected(getEmojiFromElement(target as any), true);\r\n }\r\n });\r\n\r\n this.container.classList.add('emoji-helper');\r\n }\r\n\r\n protected init() {\r\n this.list = document.createElement('div');\r\n this.list.classList.add('emoji-helper-emojis', 'super-emojis');\r\n\r\n this.container.append(this.list);\r\n\r\n this.scrollable = new ScrollableX(this.container);\r\n\r\n this.addEventListener('visible', () => {\r\n setTimeout(() => { // it is not rendered yet\r\n this.scrollable.container.scrollLeft = 0;\r\n }, 0);\r\n });\r\n }\r\n\r\n public render(emojis: string[], waitForKey: boolean) {\r\n if(this.init) {\r\n if(!emojis.length) {\r\n return;\r\n }\r\n\r\n this.init();\r\n this.init = null;\r\n }\r\n \r\n emojis = emojis.slice(0, 80);\r\n\r\n if(emojis.length) {\r\n this.list.innerHTML = '';\r\n emojis.forEach(emoji => {\r\n appendEmoji(emoji, this.list, false, true);\r\n });\r\n }\r\n\r\n this.waitForKey = waitForKey ? 'ArrowUp' : undefined;\r\n this.toggle(!emojis.length);\r\n\r\n /* window.requestAnimationFrame(() => {\r\n this.container.style.width = (3 * 2) + (emojis.length * 44) + 'px';\r\n }); */\r\n }\r\n\r\n public checkQuery(query: string, firstChar: string) {\r\n const middleware = this.controller.getMiddleware();\r\n this.appEmojiManager.getBothEmojiKeywords().then(() => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n const q = query.replace(/^:/, '');\r\n const emojis = this.appEmojiManager.searchEmojis(q);\r\n this.render(emojis, firstChar !== ':');\r\n //console.log(emojis);\r\n });\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport AvatarElement from \"../avatar\";\r\nimport PeerTitle from \"../peerTitle\";\r\nimport Scrollable from \"../scrollable\";\r\nimport AutocompleteHelper from \"./autocompleteHelper\";\r\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\r\n\r\nexport default class AutocompletePeerHelper extends AutocompleteHelper {\r\n protected static BASE_CLASS = 'autocomplete-peer-helper';\r\n protected static BASE_CLASS_LIST_ELEMENT = AutocompletePeerHelper.BASE_CLASS + '-list-element';\r\n private scrollable: Scrollable;\r\n\r\n constructor(appendTo: HTMLElement, controller: AutocompleteHelperController, protected className: string, onSelect: (target: Element) => boolean | void) {\r\n super({\r\n appendTo, \r\n controller,\r\n listType: 'y', \r\n onSelect\r\n });\r\n\r\n this.container.classList.add(AutocompletePeerHelper.BASE_CLASS, className);\r\n }\r\n\r\n protected init() {\r\n this.list = document.createElement('div');\r\n this.list.classList.add(AutocompletePeerHelper.BASE_CLASS + '-list');\r\n\r\n this.container.append(this.list);\r\n\r\n this.scrollable = new Scrollable(this.container);\r\n\r\n this.addEventListener('visible', () => {\r\n setTimeout(() => { // it is not rendered yet\r\n this.scrollable.container.scrollTop = 0;\r\n }, 0);\r\n });\r\n }\r\n\r\n public render(data: {peerId: number, name?: string, description?: string}[]) {\r\n if(this.init) {\r\n if(!data.length) {\r\n return;\r\n }\r\n\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n if(data.length) {\r\n this.list.innerHTML = '';\r\n data.forEach(d => {\r\n const div = AutocompletePeerHelper.listElement({\r\n className: this.className,\r\n peerId: d.peerId,\r\n name: d.name,\r\n description: d.description\r\n });\r\n\r\n this.list.append(div);\r\n });\r\n }\r\n\r\n this.toggle(!data.length);\r\n }\r\n\r\n public static listElement(options: {\r\n className: string,\r\n peerId: number,\r\n name?: string,\r\n description?: string\r\n }) {\r\n const BASE = AutocompletePeerHelper.BASE_CLASS_LIST_ELEMENT;\r\n options.className += '-list-element';\r\n\r\n const div = document.createElement('div');\r\n div.classList.add(BASE, options.className);\r\n div.dataset.peerId = '' + options.peerId;\r\n \r\n const avatar = new AvatarElement();\r\n avatar.classList.add('avatar-30', BASE + '-avatar', options.className + '-avatar');\r\n avatar.setAttribute('dialog', '0');\r\n avatar.setAttribute('peer', '' + options.peerId);\r\n \r\n const name = document.createElement('div');\r\n name.classList.add(BASE + '-name', options.className + '-name');\r\n if(!options.name) {\r\n name.append(new PeerTitle({\r\n peerId: options.peerId,\r\n dialog: false,\r\n onlyFirstName: false,\r\n plainText: false\r\n }).element);\r\n } else {\r\n name.innerHTML = RichTextProcessor.wrapEmojiText(options.name);\r\n }\r\n \r\n div.append(avatar, name);\r\n\r\n if(options.description) {\r\n const description = document.createElement('div');\r\n description.classList.add(BASE + '-description', options.className + '-description');\r\n description.innerHTML = RichTextProcessor.wrapEmojiText(options.description);\r\n div.append(description);\r\n }\r\n \r\n return div;\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type ChatInput from \"./input\";\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\nimport type { BotInfo } from \"../../layer\";\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\nimport AutocompletePeerHelper from \"./autocompletePeerHelper\";\nimport SearchIndex from \"../../lib/searchIndex\";\n\nexport default class CommandsHelper extends AutocompletePeerHelper {\n constructor(appendTo: HTMLElement, \n controller: AutocompleteHelperController, \n chatInput: ChatInput, \n private appProfileManager: AppProfileManager,\n private appUsersManager: AppUsersManager) {\n super(appendTo, \n controller,\n 'commands-helper',\n (target) => {\n const innerHTML = target.querySelector(`.${AutocompletePeerHelper.BASE_CLASS_LIST_ELEMENT}-name`).innerHTML;\n return chatInput.getReadyToSend(() => {\n chatInput.messageInput.innerHTML = innerHTML;\n chatInput.sendMessage(true);\n });\n }\n );\n }\n\n public checkQuery(query: string, peerId: number) {\n if(!this.appUsersManager.isBot(peerId)) {\n return false;\n }\n\n const middleware = this.controller.getMiddleware();\n this.appProfileManager.getProfileByPeerId(peerId).then(full => {\n if(!middleware()) {\n return;\n }\n\n const botInfos: BotInfo.botInfo[] = [].concat(full.bot_info);\n const index = new SearchIndex<string>({\n ignoreCase: true\n });\n \n const commands: Map<string, {peerId: number, name: string, description: string}> = new Map();\n botInfos.forEach(botInfo => {\n botInfo.commands.forEach(botCommand => {\n const c = '/' + botCommand.command;\n commands.set(botCommand.command, {\n peerId: botInfo.user_id, \n name: c, \n description: botCommand.description\n });\n\n index.indexObject(botCommand.command, c);\n });\n });\n\n const found = index.search(query);\n const filtered = Array.from(found).map(command => commands.get(command));\n this.render(filtered);\n // console.log('found commands', found, filtered);\n });\n\n return true;\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { getMiddleware } from \"../../helpers/middleware\";\r\nimport AutocompleteHelper from \"./autocompleteHelper\";\r\n\r\nexport default class AutocompleteHelperController {\r\n private helpers: Set<AutocompleteHelper> = new Set();\r\n private middleware = getMiddleware();\r\n /* private tempId = 0;\r\n\r\n public incrementToggleCount() {\r\n return ++this.tempId;\r\n }\r\n\r\n public getToggleCount() {\r\n return this.tempId;\r\n } */\r\n\r\n public getMiddleware() {\r\n this.middleware.clean();\r\n return this.middleware.get();\r\n }\r\n\r\n public addHelper(helper: AutocompleteHelper) {\r\n this.helpers.add(helper);\r\n }\r\n\r\n public hideOtherHelpers(preserveHelper?: AutocompleteHelper) {\r\n this.helpers.forEach(helper => {\r\n if(helper !== preserveHelper) {\r\n helper.toggle(true, true);\r\n }\r\n });\r\n\r\n if(!preserveHelper) {\r\n this.middleware.clean();\r\n }\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type ChatInput from \"./input\";\nimport type { MessageEntity } from \"../../layer\";\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\nimport AutocompletePeerHelper from \"./autocompletePeerHelper\";\n\nexport default class MentionsHelper extends AutocompletePeerHelper {\n constructor(appendTo: HTMLElement, \n controller: AutocompleteHelperController, \n chatInput: ChatInput, \n private appProfileManager: AppProfileManager,\n private appUsersManager: AppUsersManager) {\n super(appendTo, \n controller,\n 'mentions-helper',\n (target) => {\n const user = appUsersManager.getUser(+(target as HTMLElement).dataset.peerId);\n let str = '', entity: MessageEntity;\n if(user.username) {\n str = '@' + user.username;\n } else {\n str = user.first_name || user.last_name;\n entity = {\n _: 'messageEntityMentionName',\n length: str.length,\n offset: 0,\n user_id: user.id\n };\n }\n\n str += ' ';\n chatInput.insertAtCaret(str, entity);\n }\n );\n }\n\n public checkQuery(query: string, peerId: number, topMsgId: number) {\n const trimmed = query.trim(); // check that there is no whitespace\n if(query.length !== trimmed.length) return false;\n\n const middleware = this.controller.getMiddleware();\n this.appProfileManager.getMentions(peerId ? -peerId : 0, trimmed, topMsgId).then(peerIds => {\n if(!middleware()) return;\n \n const username = trimmed.slice(1).toLowerCase();\n this.render(peerIds.map(peerId => {\n const user = this.appUsersManager.getUser(peerId);\n if(user.username && user.username.toLowerCase() === username) { // hide full matched suggestion\n return;\n }\n\n return {\n peerId,\n description: user.username ? '@' + user.username : undefined\n };\n }).filter(Boolean));\n });\n\n return true;\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type ChatInput from \"./input\";\r\nimport DropdownHover from \"../../helpers/dropdownHover\";\r\nimport { ReplyMarkup } from \"../../layer\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport { safeAssign } from \"../../helpers/object\";\r\nimport ListenerSetter, { Listener } from \"../../helpers/listenerSetter\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport findUpAsChild from \"../../helpers/dom/findUpAsChild\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport { getHeavyAnimationPromise } from \"../../hooks/useHeavyAnimationCheck\";\r\n\r\nexport default class ReplyKeyboard extends DropdownHover {\r\n private static BASE_CLASS = 'reply-keyboard';\r\n private appendTo: HTMLElement;\r\n private listenerSetter: ListenerSetter;\r\n private appMessagesManager: AppMessagesManager;\r\n private btnHover: HTMLElement;\r\n private peerId: number;\r\n private touchListener: Listener;\r\n private chatInput: ChatInput;\r\n\r\n constructor(options: {\r\n listenerSetter: ListenerSetter,\r\n appMessagesManager: AppMessagesManager,\r\n appendTo: HTMLElement,\r\n btnHover: HTMLElement,\r\n chatInput: ChatInput\r\n }) {\r\n super({\r\n element: document.createElement('div')\r\n });\r\n\r\n safeAssign(this, options);\r\n\r\n this.element.classList.add(ReplyKeyboard.BASE_CLASS);\r\n this.element.style.display = 'none';\r\n\r\n this.attachButtonListener(this.btnHover, this.listenerSetter);\r\n this.listenerSetter.add(rootScope)('history_reply_markup', ({peerId}) => {\r\n if(this.peerId === peerId) {\r\n if(this.checkAvailability() && this.isActive()) {\r\n this.render();\r\n }\r\n\r\n getHeavyAnimationPromise().then(() => {\r\n this.checkForceReply();\r\n });\r\n }\r\n });\r\n }\r\n\r\n protected init() {\r\n this.appendTo.append(this.element);\r\n\r\n this.listenerSetter.add(this)('open', () => {\r\n this.render();\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n this.touchListener = this.listenerSetter.add(document.body)('touchstart', this.onBodyTouchStart, {passive: false, capture: true}) as any as Listener;\r\n this.listenerSetter.add(this)('close', () => {\r\n this.listenerSetter.remove(this.touchListener);\r\n }, {once: true});\r\n }\r\n });\r\n \r\n this.listenerSetter.add(this.element)('click', (e) => {\r\n const target = findUpClassName(e.target, 'btn');\r\n if(!target) {\r\n return;\r\n }\r\n\r\n this.appMessagesManager.sendText(this.peerId, target.dataset.text);\r\n this.toggle(false);\r\n });\r\n\r\n return super.init();\r\n }\r\n\r\n private onBodyTouchStart = (e: TouchEvent) => {\r\n const target = e.touches[0].target as HTMLElement;\r\n if(!findUpAsChild(target, this.element) && target !== this.btnHover) {\r\n cancelEvent(e);\r\n this.toggle(false);\r\n }\r\n };\r\n\r\n public checkForceReply() {\r\n const replyMarkup = this.getReplyMarkup();\r\n if(replyMarkup._ === 'replyKeyboardForceReply' &&\r\n !replyMarkup.pFlags.hidden && \r\n !replyMarkup.pFlags.used) {\r\n replyMarkup.pFlags.used = true;\r\n this.chatInput.initMessageReply(replyMarkup.mid);\r\n }\r\n }\r\n\r\n private getReplyMarkup(): ReplyMarkup {\r\n return this.appMessagesManager.getHistoryStorage(this.peerId).replyMarkup ?? {\r\n _: 'replyKeyboardHide'\r\n };\r\n }\r\n\r\n public render(replyMarkup: ReplyMarkup.replyKeyboardMarkup = this.getReplyMarkup() as any) {\r\n this.element.innerHTML = '';\r\n\r\n for(const row of replyMarkup.rows) {\r\n const div = document.createElement('div');\r\n div.classList.add(ReplyKeyboard.BASE_CLASS + '-row');\r\n\r\n for(const button of row.buttons) {\r\n const btn = document.createElement('button');\r\n btn.classList.add(ReplyKeyboard.BASE_CLASS + '-button', 'btn');\r\n btn.innerHTML = RichTextProcessor.wrapEmojiText(button.text);\r\n btn.dataset.text = button.text;\r\n div.append(btn);\r\n }\r\n\r\n this.element.append(div);\r\n }\r\n }\r\n\r\n public checkAvailability(replyMarkup: ReplyMarkup = this.getReplyMarkup()) {\r\n const hide = replyMarkup._ === 'replyKeyboardHide' || !(replyMarkup as ReplyMarkup.replyInlineMarkup).rows?.length;\r\n this.btnHover.classList.toggle('hide', hide);\r\n\r\n if(hide) {\r\n this.toggle(false);\r\n }\r\n\r\n return !hide;\r\n }\r\n\r\n public setPeer(peerId: number) {\r\n this.peerId = peerId;\r\n\r\n this.checkAvailability();\r\n this.checkForceReply();\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppInlineBotsManager } from \"../../lib/appManagers/appInlineBotsManager\";\r\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\r\nimport type Chat from \"./chat\";\r\nimport debounce from \"../../helpers/schedulers/debounce\";\r\nimport { WebDocument } from \"../../layer\";\r\nimport { MyDocument } from \"../../lib/appManagers/appDocsManager\";\r\nimport appDownloadManager from \"../../lib/appManagers/appDownloadManager\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport LazyLoadQueue from \"../lazyLoadQueue\";\r\nimport Scrollable from \"../scrollable\";\r\nimport { renderImageWithFadeIn, wrapPhoto } from \"../wrappers\";\r\nimport AutocompleteHelper from \"./autocompleteHelper\";\r\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\r\nimport Button from \"../button\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport { MyPhoto } from \"../../lib/appManagers/appPhotosManager\";\r\nimport { readBlobAsDataURL } from \"../../helpers/blob\";\r\nimport assumeType from \"../../helpers/assumeType\";\r\nimport GifsMasonry from \"../gifsMasonry\";\r\nimport { SuperStickerRenderer } from \"../emoticonsDropdown/tabs/stickers\";\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\n\r\nconst ANIMATION_GROUP = 'INLINE-HELPER';\r\n// const GRID_ITEMS = 5;\r\n\r\nexport default class InlineHelper extends AutocompleteHelper {\r\n private scrollable: Scrollable;\r\n private lazyLoadQueue: LazyLoadQueue;\r\n private gifsMasonry: GifsMasonry;\r\n private superStickerRenderer: SuperStickerRenderer;\r\n private onChangeScreen: () => void;\r\n public checkQuery: (peerId: number, username: string, query: string) => ReturnType<InlineHelper['_checkQuery']>;\r\n\r\n constructor(appendTo: HTMLElement, \r\n controller: AutocompleteHelperController,\r\n private chat: Chat,\r\n private appUsersManager: AppUsersManager,\r\n private appInlineBotsManager: AppInlineBotsManager) {\r\n super({\r\n appendTo, \r\n controller,\r\n listType: 'xy', \r\n onSelect: (target) => {\r\n const {peerId, botId, queryId} = this.list.dataset;\r\n return this.chat.input.getReadyToSend(() => {\r\n const queryAndResultIds = this.appInlineBotsManager.generateQId(queryId, (target as HTMLElement).dataset.resultId);\r\n this.appInlineBotsManager.sendInlineResult(+peerId, +botId, queryAndResultIds, {\r\n clearDraft: true,\r\n scheduleDate: this.chat.input.scheduleDate,\r\n silent: this.chat.input.sendSilent,\r\n replyToMsgId: this.chat.input.replyToMsgId\r\n });\r\n\r\n this.chat.input.onMessageSent(true, true);\r\n });\r\n }\r\n });\r\n\r\n this.container.classList.add('inline-helper');\r\n\r\n this.addEventListener('visible', () => {\r\n setTimeout(() => { // it is not rendered yet\r\n this.scrollable.container.scrollTop = 0;\r\n }, 0); \r\n });\r\n\r\n this.checkQuery = debounce(this._checkQuery, 200, true, true);\r\n\r\n this.addEventListener('hidden', () => {\r\n if(this.onChangeScreen) {\r\n mediaSizes.removeEventListener('changeScreen', this.onChangeScreen);\r\n this.onChangeScreen = undefined;\r\n }\r\n });\r\n }\r\n\r\n public _checkQuery = async(peerId: number, username: string, query: string) => {\r\n const middleware = this.controller.getMiddleware();\r\n\r\n const peer = await this.appUsersManager.resolveUsername(username);\r\n if(!middleware()) {\r\n throw 'PEER_CHANGED';\r\n }\r\n\r\n if(peer._ !== 'user') {\r\n throw 'NOT_A_BOT';\r\n }\r\n\r\n const renderPromise = this.appInlineBotsManager.getInlineResults(peerId, peer.id, query).then(botResults => {\r\n if(!middleware()) {\r\n throw 'PEER_CHANGED';\r\n }\r\n\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n const list = this.list.cloneNode() as HTMLElement;\r\n list.dataset.peerId = '' + peerId;\r\n list.dataset.botId = '' + peer.id;\r\n list.dataset.queryId = botResults.query_id;\r\n\r\n const gifsMasonry = new GifsMasonry(null, ANIMATION_GROUP, this.scrollable, false);\r\n\r\n this.lazyLoadQueue.clear();\r\n this.superStickerRenderer.clear();\r\n \r\n const loadPromises: Promise<any>[] = [];\r\n const isGallery = !!botResults.pFlags.gallery;\r\n // botResults.results.length = 3;\r\n for(const item of botResults.results) {\r\n const container = document.createElement('div');\r\n container.classList.add('inline-helper-result');\r\n container.dataset.resultId = item.id;\r\n \r\n const preview = isGallery ? undefined : document.createElement('div');\r\n if(preview) {\r\n preview.classList.add('inline-helper-result-preview');\r\n\r\n container.append(preview);\r\n }\r\n\r\n list.append(container);\r\n\r\n if(!isGallery) {\r\n preview.classList.add('empty');\r\n preview.innerHTML = RichTextProcessor.wrapEmojiText([...item.title.trim()][0]);\r\n\r\n const title = document.createElement('div');\r\n title.classList.add('inline-helper-result-title');\r\n title.innerHTML = RichTextProcessor.wrapEmojiText(item.title);\r\n \r\n const description = document.createElement('div');\r\n description.classList.add('inline-helper-result-description');\r\n description.innerHTML = RichTextProcessor.wrapRichText(item.description, {\r\n noCommands: true,\r\n noLinks: true\r\n });\r\n \r\n container.append(title, description);\r\n \r\n const separator = document.createElement('div');\r\n separator.classList.add('inline-helper-separator');\r\n \r\n list.append(separator);\r\n } else {\r\n container.classList.add('grid-item');\r\n }\r\n \r\n if(item._ === 'botInlineResult') {\r\n if(item.thumb && item.thumb.mime_type.indexOf('image/') === 0) {\r\n let mediaContainer: HTMLElement;\r\n if(preview) {\r\n mediaContainer = document.createElement('div');\r\n preview.append(mediaContainer);\r\n } else {\r\n mediaContainer = container;\r\n }\r\n\r\n mediaContainer.classList.add('media-container'); \r\n isGallery && mediaContainer.classList.add('no-border-radius');\r\n\r\n this.lazyLoadQueue.push({\r\n div: container,\r\n load: () => {\r\n return appDownloadManager.download({\r\n dcId: 4,\r\n location: {\r\n _: 'inputWebFileLocation',\r\n access_hash: (item.thumb as WebDocument.webDocument).access_hash,\r\n url: item.thumb.url\r\n },\r\n size: item.thumb.size,\r\n mimeType: item.thumb.mime_type\r\n }).then(blob => {\r\n const image = new Image();\r\n image.classList.add('media-photo');\r\n readBlobAsDataURL(blob).then(dataURL => {\r\n renderImageWithFadeIn(mediaContainer, image, dataURL, true);\r\n });\r\n });\r\n }\r\n });\r\n }\r\n } else {\r\n const media = item.document as MyDocument || item.photo as MyPhoto;\r\n if((['sticker', 'gif'] as MyDocument['type'][]).includes((media as MyDocument)?.type) && isGallery) {\r\n assumeType<MyDocument>(media);\r\n\r\n if(media.type === 'gif') {\r\n gifsMasonry.add(media, container);\r\n } else if(media.type === 'sticker') {\r\n container.classList.add('super-sticker');\r\n this.superStickerRenderer.renderSticker(media, container, loadPromises);\r\n if(media.sticker === 2) {\r\n this.superStickerRenderer.observeAnimatedDiv(container);\r\n }\r\n }\r\n } else if(media) {\r\n const size = isGallery ? 48 : undefined;\r\n isGallery && container.classList.add('no-border-radius');\r\n wrapPhoto({\r\n photo: media,\r\n container: isGallery ? container : preview,\r\n boxWidth: size,\r\n boxHeight: size,\r\n middleware,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n loadPromises\r\n });\r\n }\r\n }\r\n }\r\n\r\n return Promise.all(loadPromises).then(() => {\r\n if(!middleware()) {\r\n gifsMasonry.clear();\r\n return;\r\n }\r\n\r\n list.classList.toggle('is-gallery', isGallery);\r\n list.classList.toggle('super-stickers', isGallery);\r\n this.container.classList.toggle('is-gallery', isGallery);\r\n\r\n /* if(isGallery) {\r\n list.style.gridTemplateColumns = `repeat(${Math.min(botResults.results.length, 4)}, 1fr)`;\r\n }\r\n\r\n this.container.style.setProperty('width', isGallery ? `${Math.min(botResults.results.length, 4) * 25}%` : '', 'important'); */\r\n\r\n const parent = this.list.parentElement;\r\n parent.textContent = '';\r\n if(botResults.switch_pm) {\r\n const btnSwitchToPM = Button('btn-primary btn-secondary btn-primary-transparent primary');\r\n btnSwitchToPM.insertAdjacentHTML('beforeend', RichTextProcessor.wrapEmojiText(botResults.switch_pm.text));\r\n attachClickEvent(btnSwitchToPM, (e) => {\r\n this.appInlineBotsManager.switchToPM(peerId, peer.id, botResults.switch_pm.start_param);\r\n });\r\n parent.append(btnSwitchToPM);\r\n }\r\n parent.append(this.list = list);\r\n\r\n if(this.gifsMasonry) {\r\n this.gifsMasonry.detach();\r\n }\r\n this.gifsMasonry = gifsMasonry;\r\n gifsMasonry.attach();\r\n\r\n if(!this.onChangeScreen) {\r\n this.onChangeScreen = () => {\r\n if(this.list.classList.contains('is-gallery')) {\r\n const width = (this.list.childElementCount * mediaSizes.active.esgSticker.width) + (this.list.childElementCount - 1 * 1);\r\n this.list.style.width = width + 'px';\r\n } else {\r\n this.list.style.width = '';\r\n }\r\n };\r\n mediaSizes.addEventListener('changeScreen', this.onChangeScreen);\r\n }\r\n\r\n this.onChangeScreen();\r\n \r\n this.toggle(!botResults.results.length && !botResults.switch_pm);\r\n this.scrollable.scrollTop = 0;\r\n });\r\n });\r\n\r\n return {user: peer, renderPromise};\r\n };\r\n\r\n protected init() {\r\n this.list = document.createElement('div');\r\n this.list.classList.add('inline-helper-results');\r\n\r\n this.container.append(this.list);\r\n\r\n this.scrollable = new Scrollable(this.container);\r\n this.lazyLoadQueue = new LazyLoadQueue();\r\n this.superStickerRenderer = new SuperStickerRenderer(this.lazyLoadQueue, ANIMATION_GROUP);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppNotificationsManager } from '../../lib/appManagers/appNotificationsManager';\r\nimport type { AppChatsManager } from '../../lib/appManagers/appChatsManager';\r\nimport type { AppDocsManager, MyDocument } from \"../../lib/appManagers/appDocsManager\";\r\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppPeersManager } from '../../lib/appManagers/appPeersManager';\r\nimport type { AppWebPagesManager } from \"../../lib/appManagers/appWebPagesManager\";\r\nimport type { AppImManager } from '../../lib/appManagers/appImManager';\r\nimport type { AppDraftsManager, MyDraftMessage } from '../../lib/appManagers/appDraftsManager';\r\nimport type { AppEmojiManager } from '../../lib/appManagers/appEmojiManager';\r\nimport type { ServerTimeManager } from '../../lib/mtproto/serverTimeManager';\r\nimport type { AppUsersManager } from '../../lib/appManagers/appUsersManager';\r\nimport type { AppInlineBotsManager } from '../../lib/appManagers/appInlineBotsManager';\r\nimport type { AppMessagesIdsManager } from '../../lib/appManagers/appMessagesIdsManager';\r\nimport type Chat from './chat';\r\nimport Recorder from '../../../public/recorder.min';\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport apiManager from \"../../lib/mtproto/mtprotoworker\";\r\n//import Recorder from '../opus-recorder/dist/recorder.min';\r\nimport opusDecodeController from \"../../lib/opusDecodeController\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport { ButtonMenuItemOptions } from '../buttonMenu';\r\nimport emoticonsDropdown from \"../emoticonsDropdown\";\r\nimport PopupCreatePoll from \"../popups/createPoll\";\r\nimport PopupForward from '../popups/forward';\r\nimport PopupNewMedia from '../popups/newMedia';\r\nimport { toast } from \"../toast\";\r\nimport { wrapReply } from \"../wrappers\";\r\nimport InputField from '../inputField';\r\nimport { MessageEntity, DraftMessage, WebPage, Message } from '../../layer';\r\nimport StickersHelper from './stickersHelper';\r\nimport ButtonIcon from '../buttonIcon';\r\nimport ButtonMenuToggle from '../buttonMenuToggle';\r\nimport ListenerSetter, { Listener } from '../../helpers/listenerSetter';\r\nimport Button from '../button';\r\nimport PopupSchedule from '../popups/schedule';\r\nimport SendMenu from './sendContextMenu';\r\nimport rootScope from '../../lib/rootScope';\r\nimport PopupPinMessage from '../popups/unpinMessage';\r\nimport { tsNow } from '../../helpers/date';\r\nimport appNavigationController, { NavigationItem } from '../appNavigationController';\r\nimport { IS_MOBILE, IS_MOBILE_SAFARI } from '../../environment/userAgent';\r\nimport I18n, { i18n, join, LangPackKey } from '../../lib/langPack';\r\nimport { generateTail } from './bubbles';\r\nimport findUpClassName from '../../helpers/dom/findUpClassName';\r\nimport ButtonCorner from '../buttonCorner';\r\nimport blurActiveElement from '../../helpers/dom/blurActiveElement';\r\nimport { cancelEvent } from '../../helpers/dom/cancelEvent';\r\nimport cancelSelection from '../../helpers/dom/cancelSelection';\r\nimport { attachClickEvent, simulateClickEvent } from '../../helpers/dom/clickEvent';\r\nimport getRichValue from '../../helpers/dom/getRichValue';\r\nimport isInputEmpty from '../../helpers/dom/isInputEmpty';\r\nimport isSendShortcutPressed from '../../helpers/dom/isSendShortcutPressed';\r\nimport placeCaretAtEnd from '../../helpers/dom/placeCaretAtEnd';\r\nimport { MarkdownType, markdownTags } from '../../helpers/dom/getRichElementValue';\r\nimport getRichValueWithCaret from '../../helpers/dom/getRichValueWithCaret';\r\nimport EmojiHelper from './emojiHelper';\r\nimport setRichFocus from '../../helpers/dom/setRichFocus';\r\nimport CommandsHelper from './commandsHelper';\r\nimport AutocompleteHelperController from './autocompleteHelperController';\r\nimport AutocompleteHelper from './autocompleteHelper';\r\nimport MentionsHelper from './mentionsHelper';\r\nimport fixSafariStickyInput from '../../helpers/dom/fixSafariStickyInput';\r\nimport { emojiFromCodePoints } from '../../vendor/emoji';\r\nimport ReplyKeyboard from './replyKeyboard';\r\nimport InlineHelper from './inlineHelper';\r\nimport debounce from '../../helpers/schedulers/debounce';\r\nimport noop from '../../helpers/noop';\r\nimport { putPreloader } from '../misc';\r\nimport SetTransition from '../singleTransition';\r\nimport PeerTitle from '../peerTitle';\r\nimport { fastRaf } from '../../helpers/schedulers';\r\nimport PopupDeleteMessages from '../popups/deleteMessages';\r\nimport fixSafariStickyInputFocusing, { IS_STICKY_INPUT_BUGGED } from '../../helpers/dom/fixSafariStickyInputFocusing';\r\nimport { copy } from '../../helpers/object';\r\nimport PopupPeer from '../popups/peer';\r\nimport MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';\r\nimport appMediaPlaybackController from '../appMediaPlaybackController';\r\n\r\nconst RECORD_MIN_TIME = 500;\r\nconst POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\\'t allowed in this group.';\r\n\r\ntype ChatInputHelperType = 'edit' | 'webpage' | 'forward' | 'reply';\r\n\r\nexport default class ChatInput {\r\n // private static AUTO_COMPLETE_REG_EXP = /(\\s|^)((?::|.)(?!.*[:@]).*|(?:[@\\/]\\S*))$/;\r\n private static AUTO_COMPLETE_REG_EXP = /(\\s|^)((?:(?:@|^\\/)\\S*)|(?::|^[^:@\\/])(?!.*[:@\\/]).*)$/;\r\n public messageInput: HTMLElement;\r\n public messageInputField: InputField;\r\n private fileInput: HTMLInputElement;\r\n private inputMessageContainer: HTMLDivElement;\r\n private btnSend: HTMLButtonElement;\r\n private btnCancelRecord: HTMLButtonElement;\r\n private lastUrl = '';\r\n private lastTimeType = 0;\r\n\r\n public chatInput: HTMLElement;\r\n private inputContainer: HTMLElement;\r\n public rowsWrapper: HTMLDivElement;\r\n private newMessageWrapper: HTMLDivElement;\r\n private btnToggleEmoticons: HTMLButtonElement;\r\n private btnToggleReplyMarkup: HTMLButtonElement;\r\n private btnSendContainer: HTMLDivElement;\r\n\r\n private replyKeyboard: ReplyKeyboard;\r\n\r\n private attachMenu: HTMLButtonElement;\r\n private attachMenuButtons: (ButtonMenuItemOptions & {verify: (peerId: number, threadId: number) => boolean})[];\r\n\r\n private sendMenu: SendMenu;\r\n\r\n private replyElements: {\r\n container: HTMLElement,\r\n cancelBtn: HTMLButtonElement\r\n } = {} as any;\r\n\r\n private getWebPagePromise: Promise<void>;\r\n private willSendWebPage: WebPage = null;\r\n private forwarding: {[fromPeerId: number]: number[]};\r\n public replyToMsgId: number;\r\n public editMsgId: number;\r\n private noWebPage: true;\r\n public scheduleDate: number;\r\n public sendSilent: true;\r\n\r\n private recorder: any;\r\n public recording = false;\r\n private recordCanceled = false;\r\n private recordTimeEl: HTMLElement;\r\n private recordRippleEl: HTMLElement;\r\n private recordStartTime = 0;\r\n private recordingOverlayListener: Listener;\r\n private recordingNavigationItem: NavigationItem;\r\n\r\n // private scrollTop = 0;\r\n // private scrollOffsetTop = 0;\r\n // private scrollDiff = 0;\r\n\r\n public helperType: Exclude<ChatInputHelperType, 'webpage'>;\r\n private helperFunc: () => void;\r\n private helperWaitingForward: boolean;\r\n\r\n public willAttachType: 'document' | 'media';\r\n\r\n private lockRedo = false;\r\n private canRedoFromHTML = '';\r\n private readonly undoHistory: string[] = [];\r\n private readonly executedHistory: string[] = [];\r\n private canUndoFromHTML = '';\r\n\r\n private autocompleteHelperController: AutocompleteHelperController;\r\n private stickersHelper: StickersHelper;\r\n private emojiHelper: EmojiHelper;\r\n private commandsHelper: CommandsHelper;\r\n private mentionsHelper: MentionsHelper;\r\n private inlineHelper: InlineHelper;\r\n private listenerSetter: ListenerSetter;\r\n\r\n private pinnedControlBtn: HTMLButtonElement;\r\n\r\n private goDownBtn: HTMLButtonElement;\r\n private goDownUnreadBadge: HTMLElement;\r\n private goMentionBtn: HTMLButtonElement;\r\n private goMentionUnreadBadge: HTMLSpanElement;\r\n private btnScheduled: HTMLButtonElement;\r\n\r\n private btnPreloader: HTMLButtonElement;\r\n\r\n private saveDraftDebounced: () => void;\r\n\r\n private fakeRowsWrapper: HTMLDivElement;\r\n private fakePinnedControlBtn: HTMLElement;\r\n\r\n private previousQuery: string;\r\n \r\n private releaseMediaPlayback: () => void;\r\n\r\n constructor(private chat: Chat, \r\n private appMessagesManager: AppMessagesManager, \r\n private appMessagesIdsManager: AppMessagesIdsManager, \r\n private appDocsManager: AppDocsManager, \r\n private appChatsManager: AppChatsManager, \r\n private appPeersManager: AppPeersManager, \r\n private appWebPagesManager: AppWebPagesManager, \r\n private appImManager: AppImManager, \r\n private appDraftsManager: AppDraftsManager, \r\n private serverTimeManager: ServerTimeManager, \r\n private appNotificationsManager: AppNotificationsManager,\r\n private appEmojiManager: AppEmojiManager,\r\n private appUsersManager: AppUsersManager,\r\n private appInlineBotsManager: AppInlineBotsManager\r\n ) {\r\n this.listenerSetter = new ListenerSetter();\r\n }\r\n\r\n public construct() {\r\n this.chatInput = document.createElement('div');\r\n this.chatInput.classList.add('chat-input');\r\n this.chatInput.style.display = 'none';\r\n\r\n this.inputContainer = document.createElement('div');\r\n this.inputContainer.classList.add('chat-input-container');\r\n\r\n this.rowsWrapper = document.createElement('div');\r\n this.rowsWrapper.classList.add('rows-wrapper', 'chat-input-wrapper');\r\n\r\n const tail = generateTail();\r\n this.rowsWrapper.append(tail);\r\n\r\n const fakeRowsWrapper = this.fakeRowsWrapper = document.createElement('div');\r\n fakeRowsWrapper.classList.add('fake-wrapper', 'fake-rows-wrapper');\r\n\r\n const fakeSelectionWrapper = document.createElement('div');\r\n fakeSelectionWrapper.classList.add('fake-wrapper', 'fake-selection-wrapper');\r\n\r\n this.inputContainer.append(this.rowsWrapper, fakeRowsWrapper, fakeSelectionWrapper);\r\n this.chatInput.append(this.inputContainer);\r\n\r\n this.goDownBtn = ButtonCorner({icon: 'arrow_down', className: 'bubbles-corner-button bubbles-go-down hide'});\r\n this.inputContainer.append(this.goDownBtn);\r\n\r\n attachClickEvent(this.goDownBtn, (e) => {\r\n cancelEvent(e);\r\n this.chat.bubbles.onGoDownClick();\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n // * constructor end\r\n\r\n /* let setScrollTopTimeout: number;\r\n // @ts-ignore\r\n let height = window.visualViewport.height; */\r\n // @ts-ignore\r\n // this.listenerSetter.add(window.visualViewport)('resize', () => {\r\n // const scrollable = this.chat.bubbles.scrollable;\r\n // const wasScrolledDown = scrollable.isScrolledDown;\r\n \r\n // /* if(wasScrolledDown) {\r\n // this.saveScroll();\r\n // } */\r\n \r\n // // @ts-ignore\r\n // let newHeight = window.visualViewport.height;\r\n // const diff = height - newHeight;\r\n // const scrollTop = scrollable.scrollTop;\r\n // const needScrollTop = wasScrolledDown ? scrollable.scrollHeight : scrollTop + diff; // * wasScrolledDown это проверка для десктоп хрома, когда пропадает панель загрузок снизу\r\n\r\n // console.log('resize before', scrollable.scrollTop, scrollable.container.clientHeight, scrollable.scrollHeight, wasScrolledDown, scrollable.lastScrollTop, diff, needScrollTop);\r\n\r\n // scrollable.scrollTop = needScrollTop;\r\n\r\n // if(setScrollTopTimeout) clearTimeout(setScrollTopTimeout);\r\n // setScrollTopTimeout = window.setTimeout(() => {\r\n // const diff = height - newHeight;\r\n // const isScrolledDown = scrollable.scrollHeight - Math.round(scrollable.scrollTop + scrollable.container.offsetHeight + diff) <= 1;\r\n // height = newHeight;\r\n\r\n // scrollable.scrollTop = needScrollTop;\r\n \r\n // console.log('resize after', scrollable.scrollTop, scrollable.container.clientHeight, scrollable.scrollHeight, scrollable.isScrolledDown, scrollable.lastScrollTop, isScrolledDown);\r\n\r\n // /* if(isScrolledDown) {\r\n // scrollable.scrollTop = scrollable.scrollHeight;\r\n // } */\r\n\r\n // //scrollable.scrollTop += diff;\r\n // setScrollTopTimeout = 0;\r\n // }, 0);\r\n // });\r\n\r\n // ! Can't use it with resizeObserver\r\n /* this.listenerSetter.add(window.visualViewport)('resize', () => {\r\n const scrollable = this.chat.bubbles.scrollable;\r\n const wasScrolledDown = scrollable.isScrolledDown;\r\n\r\n // @ts-ignore\r\n let newHeight = window.visualViewport.height;\r\n const diff = height - newHeight;\r\n const needScrollTop = wasScrolledDown ? scrollable.scrollHeight : scrollable.scrollTop + diff; // * wasScrolledDown это проверка для десктоп хрома, когда пропадает панель загрузок снизу\r\n\r\n //console.log('resize before', scrollable.scrollTop, scrollable.container.clientHeight, scrollable.scrollHeight, wasScrolledDown, scrollable.lastScrollTop, diff, needScrollTop);\r\n\r\n scrollable.scrollTop = needScrollTop;\r\n height = newHeight;\r\n\r\n if(setScrollTopTimeout) clearTimeout(setScrollTopTimeout);\r\n setScrollTopTimeout = window.setTimeout(() => { // * try again for scrolled down Android Chrome\r\n scrollable.scrollTop = needScrollTop;\r\n \r\n //console.log('resize after', scrollable.scrollTop, scrollable.container.clientHeight, scrollable.scrollHeight, scrollable.isScrolledDown, scrollable.lastScrollTop, isScrolledDown);\r\n setScrollTopTimeout = 0;\r\n }, 0);\r\n }); */\r\n }\r\n\r\n public constructPeerHelpers() {\r\n this.replyElements.container = document.createElement('div');\r\n this.replyElements.container.classList.add('reply-wrapper');\r\n\r\n this.replyElements.cancelBtn = ButtonIcon('close reply-cancel');\r\n\r\n this.replyElements.container.append(this.replyElements.cancelBtn);\r\n\r\n this.newMessageWrapper = document.createElement('div');\r\n this.newMessageWrapper.classList.add('new-message-wrapper');\r\n\r\n this.btnToggleEmoticons = ButtonIcon('none toggle-emoticons', {noRipple: true});\r\n\r\n this.inputMessageContainer = document.createElement('div');\r\n this.inputMessageContainer.classList.add('input-message-container');\r\n\r\n if(this.chat.type === 'chat') {\r\n this.goDownUnreadBadge = document.createElement('span');\r\n this.goDownUnreadBadge.classList.add('badge', 'badge-24', 'badge-primary');\r\n this.goDownBtn.append(this.goDownUnreadBadge);\r\n\r\n this.goMentionBtn = ButtonCorner({icon: 'mention', className: 'bubbles-corner-button bubbles-go-mention'});\r\n this.goMentionUnreadBadge = document.createElement('span');\r\n this.goMentionUnreadBadge.classList.add('badge', 'badge-24', 'badge-primary');\r\n this.goMentionBtn.append(this.goMentionUnreadBadge);\r\n this.inputContainer.append(this.goMentionBtn);\r\n\r\n attachClickEvent(this.goMentionBtn, (e) => {\r\n cancelEvent(e);\r\n this.appMessagesManager.goToNextMention(this.chat.peerId);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.btnScheduled = ButtonIcon('scheduled btn-scheduled float hide', {noRipple: true});\r\n\r\n attachClickEvent(this.btnScheduled, (e) => {\r\n this.appImManager.openScheduled(this.chat.peerId);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.listenerSetter.add(rootScope)('scheduled_new', ({peerId}) => {\r\n if(this.chat.peerId !== peerId) {\r\n return;\r\n }\r\n\r\n this.btnScheduled.classList.remove('hide');\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('scheduled_delete', ({peerId}) => {\r\n if(this.chat.peerId !== peerId) {\r\n return;\r\n }\r\n\r\n this.appMessagesManager.getScheduledMessages(this.chat.peerId).then(value => {\r\n this.btnScheduled.classList.toggle('hide', !value.length);\r\n });\r\n });\r\n\r\n this.btnToggleReplyMarkup = ButtonIcon('botcom toggle-reply-markup float hide', {noRipple: true});\r\n this.replyKeyboard = new ReplyKeyboard({\r\n appendTo: this.rowsWrapper,\r\n listenerSetter: this.listenerSetter,\r\n appMessagesManager: this.appMessagesManager,\r\n btnHover: this.btnToggleReplyMarkup,\r\n chatInput: this\r\n });\r\n this.listenerSetter.add(this.replyKeyboard)('open', () => this.btnToggleReplyMarkup.classList.add('active'));\r\n this.listenerSetter.add(this.replyKeyboard)('close', () => this.btnToggleReplyMarkup.classList.remove('active'));\r\n }\r\n\r\n this.attachMenuButtons = [{\r\n icon: 'image',\r\n text: 'Chat.Input.Attach.PhotoOrVideo',\r\n onClick: () => {\r\n this.fileInput.value = '';\r\n const accept = [...MEDIA_MIME_TYPES_SUPPORTED].join(', ');\r\n this.fileInput.setAttribute('accept', accept);\r\n this.willAttachType = 'media';\r\n this.fileInput.click();\r\n },\r\n verify: (peerId, threadId) => this.appMessagesManager.canSendToPeer(peerId, threadId, 'send_media')\r\n }, {\r\n icon: 'document',\r\n text: 'Chat.Input.Attach.Document',\r\n onClick: () => {\r\n this.fileInput.value = '';\r\n this.fileInput.removeAttribute('accept');\r\n this.willAttachType = 'document';\r\n this.fileInput.click();\r\n },\r\n verify: (peerId, threadId) => this.appMessagesManager.canSendToPeer(peerId, threadId, 'send_media')\r\n }, {\r\n icon: 'poll',\r\n text: 'Poll',\r\n onClick: () => {\r\n new PopupCreatePoll(this.chat).show();\r\n },\r\n verify: (peerId, threadId) => peerId < 0 && this.appMessagesManager.canSendToPeer(peerId, threadId, 'send_polls')\r\n }];\r\n\r\n this.attachMenu = ButtonMenuToggle({noRipple: true, listenerSetter: this.listenerSetter}, 'top-left', this.attachMenuButtons);\r\n this.attachMenu.classList.add('attach-file', 'tgico-attach');\r\n this.attachMenu.classList.remove('tgico-more');\r\n\r\n //this.inputContainer.append(this.sendMenu);\r\n\r\n this.recordTimeEl = document.createElement('div');\r\n this.recordTimeEl.classList.add('record-time');\r\n\r\n this.fileInput = document.createElement('input');\r\n this.fileInput.type = 'file';\r\n this.fileInput.multiple = true;\r\n this.fileInput.style.display = 'none';\r\n\r\n this.newMessageWrapper.append(...[this.btnToggleEmoticons, this.inputMessageContainer, this.btnScheduled, this.btnToggleReplyMarkup, this.attachMenu, this.recordTimeEl, this.fileInput].filter(Boolean));\r\n\r\n this.rowsWrapper.append(this.replyElements.container);\r\n this.autocompleteHelperController = new AutocompleteHelperController();\r\n this.stickersHelper = new StickersHelper(this.rowsWrapper, this.autocompleteHelperController);\r\n this.emojiHelper = new EmojiHelper(this.rowsWrapper, this.autocompleteHelperController, this, this.appEmojiManager);\r\n this.commandsHelper = new CommandsHelper(this.rowsWrapper, this.autocompleteHelperController, this, this.chat.appProfileManager, this.chat.appUsersManager);\r\n this.mentionsHelper = new MentionsHelper(this.rowsWrapper, this.autocompleteHelperController, this, this.chat.appProfileManager, this.chat.appUsersManager);\r\n this.inlineHelper = new InlineHelper(this.rowsWrapper, this.autocompleteHelperController, this.chat, this.appUsersManager, this.appInlineBotsManager);\r\n this.rowsWrapper.append(this.newMessageWrapper);\r\n\r\n this.btnCancelRecord = ButtonIcon('delete danger btn-circle z-depth-1 btn-record-cancel');\r\n\r\n this.btnSendContainer = document.createElement('div');\r\n this.btnSendContainer.classList.add('btn-send-container');\r\n\r\n this.recordRippleEl = document.createElement('div');\r\n this.recordRippleEl.classList.add('record-ripple');\r\n\r\n this.btnSend = ButtonIcon('none btn-circle z-depth-1 btn-send animated-button-icon');\r\n this.btnSend.insertAdjacentHTML('afterbegin', `\r\n <span class=\"tgico tgico-send\"></span>\r\n <span class=\"tgico tgico-schedule\"></span>\r\n <span class=\"tgico tgico-check\"></span>\r\n <span class=\"tgico tgico-microphone\"></span>\r\n `);\r\n\r\n this.btnSendContainer.append(this.recordRippleEl, this.btnSend);\r\n\r\n if(this.chat.type !== 'scheduled') {\r\n this.sendMenu = new SendMenu({\r\n onSilentClick: () => {\r\n this.sendSilent = true;\r\n this.sendMessage();\r\n },\r\n onScheduleClick: () => {\r\n this.scheduleSending(undefined);\r\n },\r\n listenerSetter: this.listenerSetter,\r\n openSide: 'top-left',\r\n onContextElement: this.btnSend,\r\n onOpen: () => {\r\n return !this.isInputEmpty();\r\n }\r\n });\r\n \r\n this.btnSendContainer.append(this.sendMenu.sendMenu);\r\n }\r\n\r\n this.inputContainer.append(this.btnCancelRecord, this.btnSendContainer);\r\n\r\n emoticonsDropdown.attachButtonListener(this.btnToggleEmoticons, this.listenerSetter);\r\n this.listenerSetter.add(emoticonsDropdown)('open', this.onEmoticonsOpen);\r\n this.listenerSetter.add(emoticonsDropdown)('close', this.onEmoticonsClose);\r\n\r\n this.attachMessageInputField();\r\n\r\n /* this.attachMenu.addEventListener('mousedown', (e) => {\r\n const hidden = this.attachMenu.querySelectorAll('.hide');\r\n if(hidden.length === this.attachMenuButtons.length) {\r\n toast(POSTING_MEDIA_NOT_ALLOWED);\r\n cancelEvent(e);\r\n return false;\r\n }\r\n }, {passive: false, capture: true}); */\r\n\r\n this.listenerSetter.add(rootScope)('settings_updated', () => {\r\n if(this.stickersHelper || this.emojiHelper) {\r\n // this.previousQuery = undefined;\r\n this.previousQuery = '';\r\n this.checkAutocomplete();\r\n /* if(!rootScope.settings.stickers.suggest) {\r\n this.stickersHelper.checkEmoticon('');\r\n } else {\r\n this.onMessageInput();\r\n } */\r\n }\r\n\r\n if(this.messageInputField) {\r\n this.messageInputField.onFakeInput();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('draft_updated', ({peerId, threadId, draft, force}) => {\r\n if(this.chat.threadId !== threadId || this.chat.peerId !== peerId) return;\r\n this.setDraft(draft, true, force);\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('peer_changing', (chat) => {\r\n if(this.chat === chat) {\r\n this.saveDraft();\r\n }\r\n });\r\n\r\n if(this.chat.type === 'scheduled') {\r\n this.listenerSetter.add(rootScope)('scheduled_delete', ({peerId, mids}) => {\r\n if(this.chat.peerId === peerId && mids.includes(this.editMsgId)) {\r\n this.onMessageSent();\r\n }\r\n });\r\n } else {\r\n this.listenerSetter.add(rootScope)('history_delete', ({peerId, msgs}) => {\r\n if(this.chat.peerId === peerId) {\r\n if(msgs.has(this.editMsgId)) {\r\n this.onMessageSent();\r\n }\r\n\r\n if(this.replyToMsgId && msgs.has(this.replyToMsgId)) {\r\n this.clearHelper('reply');\r\n }\r\n }\r\n });\r\n }\r\n\r\n try {\r\n this.recorder = new Recorder({\r\n //encoderBitRate: 32,\r\n //encoderPath: \"../dist/encoderWorker.min.js\",\r\n encoderSampleRate: 48000,\r\n monitorGain: 0,\r\n numberOfChannels: 1,\r\n recordingGain: 1,\r\n reuseWorker: true\r\n });\r\n } catch(err) {\r\n console.error('Recorder constructor error:', err);\r\n }\r\n\r\n this.updateSendBtn();\r\n\r\n this.listenerSetter.add(this.fileInput)('change', (e) => {\r\n let files = (e.target as HTMLInputElement & EventTarget).files;\r\n if(!files.length) {\r\n return;\r\n }\r\n \r\n new PopupNewMedia(this.chat, Array.from(files).slice(), this.willAttachType);\r\n this.fileInput.value = '';\r\n }, false);\r\n\r\n /* let time = Date.now();\r\n this.btnSend.addEventListener('touchstart', (e) => {\r\n time = Date.now();\r\n });\r\n\r\n let eventName1 = 'touchend';\r\n this.btnSend.addEventListener(eventName1, (e: Event) => {\r\n //cancelEvent(e);\r\n console.log(eventName1 + ', time: ' + (Date.now() - time));\r\n });\r\n\r\n let eventName = 'mousedown';\r\n this.btnSend.addEventListener(eventName, (e: Event) => {\r\n cancelEvent(e);\r\n console.log(eventName + ', time: ' + (Date.now() - time));\r\n }); */\r\n attachClickEvent(this.btnSend, this.onBtnSendClick, {listenerSetter: this.listenerSetter, touchMouseDown: true});\r\n\r\n if(this.recorder) {\r\n attachClickEvent(this.btnCancelRecord, this.onCancelRecordClick, {listenerSetter: this.listenerSetter});\r\n\r\n this.recorder.onstop = () => {\r\n this.recording = false;\r\n this.chatInput.classList.remove('is-recording', 'is-locked');\r\n this.updateSendBtn();\r\n this.recordRippleEl.style.transform = '';\r\n };\r\n \r\n this.recorder.ondataavailable = (typedArray: Uint8Array) => {\r\n if(this.releaseMediaPlayback) {\r\n this.releaseMediaPlayback();\r\n this.releaseMediaPlayback = undefined;\r\n }\r\n\r\n if(this.recordingOverlayListener) {\r\n this.listenerSetter.remove(this.recordingOverlayListener);\r\n this.recordingOverlayListener = undefined;\r\n }\r\n\r\n if(this.recordingNavigationItem) {\r\n appNavigationController.removeItem(this.recordingNavigationItem);\r\n this.recordingNavigationItem = undefined;\r\n }\r\n\r\n if(this.recordCanceled) {\r\n return;\r\n }\r\n\r\n const {peerId, threadId} = this.chat;\r\n const replyToMsgId = this.replyToMsgId;\r\n \r\n const duration = (Date.now() - this.recordStartTime) / 1000 | 0;\r\n const dataBlob = new Blob([typedArray], {type: 'audio/ogg'});\r\n /* const fileName = new Date().toISOString() + \".opus\";\r\n console.log('Recorder data received', typedArray, dataBlob); */\r\n\r\n //let perf = performance.now();\r\n opusDecodeController.decode(typedArray, true).then(result => {\r\n //console.log('WAVEFORM!:', /* waveform, */performance.now() - perf);\r\n \r\n opusDecodeController.setKeepAlive(false);\r\n \r\n // тут objectURL ставится уже с audio/wav\r\n this.appMessagesManager.sendFile(peerId, dataBlob, {\r\n isVoiceMessage: true,\r\n isMedia: true,\r\n duration,\r\n waveform: result.waveform,\r\n objectURL: result.url,\r\n replyToMsgId,\r\n threadId,\r\n clearDraft: true\r\n });\r\n\r\n this.onMessageSent(false, true);\r\n });\r\n };\r\n }\r\n\r\n attachClickEvent(this.replyElements.cancelBtn, this.onHelperCancel, {listenerSetter: this.listenerSetter});\r\n attachClickEvent(this.replyElements.container, this.onHelperClick, {listenerSetter: this.listenerSetter});\r\n\r\n this.saveDraftDebounced = debounce(() => this.saveDraft(), 2500, false, true);\r\n }\r\n\r\n public constructPinnedHelpers() {\r\n const container = document.createElement('div');\r\n container.classList.add('pinned-container');\r\n\r\n this.pinnedControlBtn = Button('btn-primary btn-transparent text-bold pinned-container-button', {icon: 'unpin'});\r\n container.append(this.pinnedControlBtn);\r\n\r\n const fakeContainer = container.cloneNode(true);\r\n this.fakePinnedControlBtn = fakeContainer.firstChild as HTMLElement;\r\n this.fakeRowsWrapper.append(fakeContainer);\r\n\r\n this.listenerSetter.add(this.pinnedControlBtn)('click', () => {\r\n const peerId = this.chat.peerId;\r\n\r\n new PopupPinMessage(peerId, 0, true, () => {\r\n this.chat.appImManager.setPeer(0); // * close tab\r\n\r\n // ! костыль, это скроет закреплённые сообщения сразу, вместо того, чтобы ждать пока анимация перехода закончится\r\n const originalChat = this.chat.appImManager.chat;\r\n if(originalChat.topbar.pinnedMessage) {\r\n originalChat.topbar.pinnedMessage.pinnedMessageContainer.toggle(true);\r\n }\r\n });\r\n });\r\n\r\n this.rowsWrapper.append(container);\r\n\r\n this.chatInput.classList.add('type-pinned');\r\n this.rowsWrapper.classList.add('is-centered');\r\n }\r\n\r\n private onCancelRecordClick = (e?: Event) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n \r\n this.recordCanceled = true;\r\n this.recorder.stop();\r\n opusDecodeController.setKeepAlive(false);\r\n };\r\n\r\n private onEmoticonsOpen = () => {\r\n const toggleClass = IS_TOUCH_SUPPORTED ? 'flip-icon' : 'active';\r\n this.btnToggleEmoticons.classList.toggle(toggleClass, true);\r\n };\r\n\r\n private onEmoticonsClose = () => {\r\n const toggleClass = IS_TOUCH_SUPPORTED ? 'flip-icon' : 'active';\r\n this.btnToggleEmoticons.classList.toggle(toggleClass, false);\r\n };\r\n\r\n public getReadyToSend(callback: () => void) {\r\n return this.chat.type === 'scheduled' ? (this.scheduleSending(callback), true) : (callback(), false);\r\n }\r\n\r\n public scheduleSending = (callback: () => void = this.sendMessage.bind(this, true), initDate = new Date()) => {\r\n const canSendWhenOnline = this.chat.peerId > 0 && this.appUsersManager.isUserOnlineVisible(this.chat.peerId);\r\n\r\n new PopupSchedule(initDate, (timestamp) => {\r\n const minTimestamp = (Date.now() / 1000 | 0) + 10;\r\n if(timestamp <= minTimestamp) {\r\n timestamp = undefined;\r\n }\r\n\r\n this.scheduleDate = timestamp;\r\n callback();\r\n\r\n if(this.chat.type !== 'scheduled' && timestamp) {\r\n this.appImManager.openScheduled(this.chat.peerId);\r\n }\r\n }, canSendWhenOnline).show();\r\n };\r\n\r\n public setUnreadCount() {\r\n const dialog = this.appMessagesManager.getDialogOnly(this.chat.peerId);\r\n const count = dialog?.unread_count;\r\n this.goDownUnreadBadge.innerText = '' + (count || '');\r\n this.goDownUnreadBadge.classList.toggle('badge-gray', this.appNotificationsManager.isPeerLocalMuted(this.chat.peerId, true));\r\n\r\n if(this.goMentionUnreadBadge && this.chat.type === 'chat') {\r\n const hasMentions = !!dialog?.unread_mentions_count;\r\n this.goMentionUnreadBadge.innerText = hasMentions ? '' + (dialog.unread_mentions_count) : '';\r\n this.goMentionBtn.classList.toggle('is-visible', hasMentions);\r\n }\r\n }\r\n\r\n public saveDraft() {\r\n if(!this.chat.peerId || this.editMsgId || this.chat.type === 'scheduled') return;\r\n \r\n const {value, entities} = getRichValue(this.messageInputField.input);\r\n\r\n let draft: DraftMessage.draftMessage;\r\n if(value.length || this.replyToMsgId) {\r\n draft = {\r\n _: 'draftMessage',\r\n date: tsNow(true) + this.serverTimeManager.serverTimeOffset,\r\n message: value,\r\n entities: entities.length ? entities : undefined,\r\n pFlags: {\r\n no_webpage: this.noWebPage\r\n },\r\n reply_to_msg_id: this.replyToMsgId\r\n };\r\n }\r\n\r\n this.appDraftsManager.syncDraft(this.chat.peerId, this.chat.threadId, draft);\r\n }\r\n\r\n public destroy() {\r\n //this.chat.log.error('Input destroying');\r\n\r\n this.listenerSetter.removeAll();\r\n }\r\n\r\n public cleanup(helperToo = true) {\r\n if(!this.chat.peerId) {\r\n this.chatInput.style.display = 'none';\r\n this.goDownBtn.classList.add('hide');\r\n }\r\n\r\n cancelSelection();\r\n\r\n this.lastTimeType = 0;\r\n\r\n if(this.messageInput) {\r\n this.clearInput();\r\n helperToo && this.clearHelper();\r\n }\r\n }\r\n\r\n public setDraft(draft?: MyDraftMessage, fromUpdate = true, force = false) {\r\n if((!force && !isInputEmpty(this.messageInput)) || this.chat.type === 'scheduled') return false;\r\n \r\n if(!draft) {\r\n draft = this.appDraftsManager.getDraft(this.chat.peerId, this.chat.threadId);\r\n\r\n if(!draft) {\r\n return false;\r\n }\r\n }\r\n\r\n if(this.messageInputField.value === draft.rMessage && this.replyToMsgId === draft.reply_to_msg_id) return false;\r\n\r\n this.clearHelper();\r\n this.noWebPage = draft.pFlags.no_webpage;\r\n if(draft.reply_to_msg_id) {\r\n this.initMessageReply(draft.reply_to_msg_id);\r\n }\r\n\r\n this.setInputValue(draft.rMessage, fromUpdate, fromUpdate);\r\n return true;\r\n }\r\n\r\n public finishPeerChange() {\r\n const peerId = this.chat.peerId;\r\n\r\n this.chatInput.style.display = '';\r\n \r\n const isBroadcast = this.appPeersManager.isBroadcast(peerId);\r\n this.goDownBtn.classList.toggle('is-broadcast', isBroadcast);\r\n this.goDownBtn.classList.remove('hide');\r\n\r\n if(this.goDownUnreadBadge) {\r\n this.setUnreadCount();\r\n }\r\n\r\n if(this.chat.type === 'pinned') {\r\n this.chatInput.classList.toggle('can-pin', this.appPeersManager.canPinMessage(peerId));\r\n }/* else if(this.chat.type === 'chat') {\r\n } */\r\n\r\n if(this.btnScheduled) {\r\n this.btnScheduled.classList.add('hide');\r\n const middleware = this.chat.bubbles.getMiddleware();\r\n this.appMessagesManager.getScheduledMessages(peerId).then(mids => {\r\n if(!middleware()) return;\r\n this.btnScheduled.classList.toggle('hide', !mids.length);\r\n });\r\n }\r\n\r\n if(this.replyKeyboard) {\r\n this.replyKeyboard.setPeer(peerId);\r\n }\r\n\r\n if(this.sendMenu) {\r\n this.sendMenu.setPeerId(peerId);\r\n }\r\n\r\n if(this.messageInput) {\r\n this.updateMessageInput();\r\n } else if(this.pinnedControlBtn) {\r\n if(this.appPeersManager.canPinMessage(this.chat.peerId)) {\r\n this.pinnedControlBtn.append(i18n('Chat.Input.UnpinAll'));\r\n this.fakePinnedControlBtn.append(i18n('Chat.Input.UnpinAll'));\r\n } else {\r\n this.pinnedControlBtn.append(i18n('Chat.Pinned.DontShow'));\r\n this.fakePinnedControlBtn.append(i18n('Chat.Pinned.DontShow'));\r\n }\r\n }\r\n }\r\n\r\n public updateMessageInput() {\r\n const {peerId, threadId} = this.chat;\r\n const canWrite = this.appMessagesManager.canSendToPeer(peerId, threadId);\r\n this.chatInput.classList.add('no-transition');\r\n this.chatInput.classList.toggle('is-hidden', !canWrite);\r\n void this.chatInput.offsetLeft; // reflow\r\n this.chatInput.classList.remove('no-transition');\r\n\r\n const i = I18n.weakMap.get(this.messageInput) as I18n.IntlElement;\r\n if(i) {\r\n let key: LangPackKey;\r\n if(threadId) {\r\n key = 'Comment';\r\n } else if(this.appPeersManager.isBroadcast(peerId)) {\r\n key = 'ChannelBroadcast';\r\n } else if(this.appMessagesManager.isAnonymousSending(peerId)) {\r\n key = 'SendAnonymously';\r\n } else {\r\n key = 'Message';\r\n }\r\n\r\n if(i.key !== key) {\r\n i.key = key;\r\n i.update();\r\n }\r\n }\r\n\r\n const visible = this.attachMenuButtons.filter(button => {\r\n const good = button.verify(peerId, threadId);\r\n button.element.classList.toggle('hide', !good);\r\n return good;\r\n });\r\n\r\n if(!canWrite) {\r\n this.messageInput.removeAttribute('contenteditable');\r\n } else {\r\n this.messageInput.setAttribute('contenteditable', 'true');\r\n this.setDraft(undefined, false);\r\n\r\n if(!this.messageInput.innerHTML) {\r\n this.messageInputField.onFakeInput();\r\n }\r\n }\r\n \r\n this.attachMenu.toggleAttribute('disabled', !visible.length);\r\n this.attachMenu.classList.toggle('btn-disabled', !visible.length);\r\n this.updateSendBtn();\r\n }\r\n\r\n private attachMessageInputField() {\r\n const oldInputField = this.messageInputField;\r\n this.messageInputField = new InputField({\r\n placeholder: 'Message',\r\n name: 'message',\r\n animate: true\r\n });\r\n\r\n this.messageInputField.input.classList.replace('input-field-input', 'input-message-input');\r\n this.messageInputField.inputFake.classList.replace('input-field-input', 'input-message-input');\r\n this.messageInput = this.messageInputField.input;\r\n this.messageInput.classList.add('no-scrollbar');\r\n this.attachMessageInputListeners();\r\n \r\n if(IS_STICKY_INPUT_BUGGED) {\r\n fixSafariStickyInputFocusing(this.messageInput);\r\n }\r\n\r\n if(oldInputField) {\r\n oldInputField.input.replaceWith(this.messageInputField.input);\r\n oldInputField.inputFake.replaceWith(this.messageInputField.inputFake);\r\n } else {\r\n this.inputMessageContainer.append(this.messageInputField.input, this.messageInputField.inputFake);\r\n }\r\n }\r\n\r\n private attachMessageInputListeners() {\r\n this.listenerSetter.add(this.messageInput)('keydown', (e: KeyboardEvent) => {\r\n if(isSendShortcutPressed(e)) {\r\n this.sendMessage();\r\n } else if(e.ctrlKey || e.metaKey) {\r\n this.handleMarkdownShortcut(e);\r\n } else if((e.key === 'PageUp' || e.key === 'PageDown') && !e.shiftKey) { // * fix pushing page to left (Chrome Windows)\r\n e.preventDefault();\r\n\r\n if(e.key === 'PageUp') {\r\n const range = document.createRange();\r\n const sel = window.getSelection();\r\n \r\n range.setStart(this.messageInput.childNodes[0] || this.messageInput, 0);\r\n range.collapse(true);\r\n \r\n sel.removeAllRanges();\r\n sel.addRange(range);\r\n } else {\r\n placeCaretAtEnd(this.messageInput);\r\n }\r\n }\r\n });\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n attachClickEvent(this.messageInput, (e) => {\r\n this.appImManager.selectTab(1); // * set chat tab for album orientation\r\n //this.saveScroll();\r\n emoticonsDropdown.toggle(false);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n /* this.listenerSetter.add(window)('resize', () => {\r\n this.restoreScroll();\r\n }); */\r\n\r\n /* if(isSafari) { \r\n this.listenerSetter.add(this.messageInput)('mousedown', () => {\r\n window.requestAnimationFrame(() => {\r\n window.requestAnimationFrame(() => {\r\n emoticonsDropdown.toggle(false);\r\n });\r\n });\r\n });\r\n } */\r\n }\r\n\r\n /* this.listenerSetter.add(this.messageInput)('beforeinput', (e: Event) => {\r\n // * validate due to manual formatting through browser's context menu\r\n const inputType = (e as InputEvent).inputType;\r\n //console.log('message beforeinput event', e);\r\n\r\n if(inputType.indexOf('format') === 0) {\r\n //console.log('message beforeinput format', e, inputType, this.messageInput.innerHTML);\r\n const markdownType = inputType.split('format')[1].toLowerCase() as MarkdownType;\r\n if(this.applyMarkdown(markdownType)) {\r\n cancelEvent(e); // * cancel legacy markdown event\r\n }\r\n }\r\n }); */\r\n this.listenerSetter.add(this.messageInput)('input', this.onMessageInput);\r\n this.listenerSetter.add(this.messageInput)('keyup', () => {\r\n this.checkAutocomplete();\r\n });\r\n\r\n if(this.chat.type === 'chat' || this.chat.type === 'discussion') {\r\n this.listenerSetter.add(this.messageInput)('focusin', () => {\r\n if(this.chat.bubbles.scrollable.loadedAll.bottom) {\r\n this.appMessagesManager.readAllHistory(this.chat.peerId, this.chat.threadId);\r\n }\r\n }); \r\n }\r\n }\r\n\r\n private prepareDocumentExecute = () => {\r\n this.executedHistory.push(this.messageInput.innerHTML);\r\n return () => this.canUndoFromHTML = this.messageInput.innerHTML;\r\n };\r\n\r\n private undoRedo = (e: Event, type: 'undo' | 'redo', needHTML: string) => {\r\n cancelEvent(e); // cancel legacy event\r\n\r\n let html = this.messageInput.innerHTML;\r\n if(html && html !== needHTML) {\r\n this.lockRedo = true;\r\n\r\n let sameHTMLTimes = 0;\r\n do {\r\n document.execCommand(type, false, null);\r\n const currentHTML = this.messageInput.innerHTML;\r\n if(html === currentHTML) {\r\n if(++sameHTMLTimes > 2) { // * unlink, removeFormat (а может и нет, случай: заболдить подчёркнутый текст (выделить ровно его), попробовать отменить)\r\n break;\r\n }\r\n } else {\r\n sameHTMLTimes = 0;\r\n }\r\n\r\n html = currentHTML;\r\n } while(html !== needHTML);\r\n\r\n this.lockRedo = false;\r\n }\r\n };\r\n\r\n public applyMarkdown(type: MarkdownType, href?: string) {\r\n const commandsMap: Partial<{[key in typeof type]: string | (() => void)}> = {\r\n bold: 'Bold',\r\n italic: 'Italic',\r\n underline: 'Underline',\r\n strikethrough: 'Strikethrough',\r\n monospace: () => document.execCommand('fontName', false, 'monospace'),\r\n link: href ? () => document.execCommand('createLink', false, href) : () => document.execCommand('unlink', false, null)\r\n };\r\n\r\n if(!commandsMap[type]) {\r\n return false;\r\n }\r\n\r\n const command = commandsMap[type];\r\n\r\n //type = 'monospace';\r\n\r\n const saveExecuted = this.prepareDocumentExecute();\r\n const executed: any[] = [];\r\n /**\r\n * * clear previous formatting, due to Telegram's inability to handle several entities\r\n */\r\n /* const checkForSingle = () => {\r\n const nodes = getSelectedNodes();\r\n //console.log('Using formatting:', commandsMap[type], nodes, this.executedHistory);\r\n\r\n const parents = [...new Set(nodes.map(node => node.parentNode))];\r\n //const differentParents = !!nodes.find(node => node.parentNode !== firstParent);\r\n const differentParents = parents.length > 1;\r\n\r\n let notSingle = false;\r\n if(differentParents) {\r\n notSingle = true;\r\n } else {\r\n const node = nodes[0];\r\n if(node && (node.parentNode as HTMLElement) !== this.messageInput && (node.parentNode.parentNode as HTMLElement) !== this.messageInput) {\r\n notSingle = true;\r\n }\r\n }\r\n\r\n if(notSingle) {\r\n //if(type === 'monospace') {\r\n executed.push(document.execCommand('styleWithCSS', false, 'true'));\r\n //}\r\n\r\n executed.push(document.execCommand('unlink', false, null));\r\n executed.push(document.execCommand('removeFormat', false, null));\r\n executed.push(typeof(command) === 'function' ? command() : document.execCommand(command, false, null));\r\n\r\n //if(type === 'monospace') {\r\n executed.push(document.execCommand('styleWithCSS', false, 'false'));\r\n //}\r\n }\r\n }; */\r\n\r\n executed.push(document.execCommand('styleWithCSS', false, 'true'));\r\n \r\n if(type === 'monospace') {\r\n let haveThisType = false;\r\n //executed.push(document.execCommand('styleWithCSS', false, 'true'));\r\n\r\n const selection = window.getSelection();\r\n if(!selection.isCollapsed) {\r\n const range = selection.getRangeAt(0);\r\n const tag = markdownTags[type];\r\n\r\n const node = range.commonAncestorContainer;\r\n if((node.parentNode as HTMLElement).matches(tag.match) || (node instanceof HTMLElement && node.matches(tag.match))) {\r\n haveThisType = true;\r\n }\r\n }\r\n\r\n //executed.push(document.execCommand('removeFormat', false, null));\r\n\r\n if(haveThisType) {\r\n executed.push(document.execCommand('fontName', false, 'Roboto'));\r\n } else {\r\n executed.push(typeof(command) === 'function' ? command() : document.execCommand(command, false, null));\r\n }\r\n } else {\r\n executed.push(typeof(command) === 'function' ? command() : document.execCommand(command, false, null));\r\n }\r\n\r\n executed.push(document.execCommand('styleWithCSS', false, 'false'));\r\n\r\n //checkForSingle();\r\n saveExecuted();\r\n if(this.appImManager.markupTooltip) {\r\n this.appImManager.markupTooltip.setActiveMarkupButton();\r\n }\r\n\r\n return true;\r\n }\r\n\r\n private handleMarkdownShortcut = (e: KeyboardEvent) => {\r\n // console.log('handleMarkdownShortcut', e);\r\n const formatKeys: {[key: string]: MarkdownType} = {\r\n 'B': 'bold',\r\n 'I': 'italic',\r\n 'U': 'underline',\r\n 'S': 'strikethrough',\r\n 'M': 'monospace',\r\n 'K': 'link'\r\n };\r\n\r\n const selection = document.getSelection();\r\n if(selection.toString().trim().length) {\r\n for(const key in formatKeys) {\r\n const good = e.code === ('Key' + key);\r\n \r\n if(good) {\r\n // * костыльчик\r\n if(key === 'K' && this.appImManager.markupTooltip) {\r\n this.appImManager.markupTooltip.showLinkEditor();\r\n cancelEvent(e);\r\n break;\r\n }\r\n \r\n this.applyMarkdown(formatKeys[key]);\r\n cancelEvent(e); // cancel legacy event\r\n break;\r\n }\r\n }\r\n }\r\n\r\n //return;\r\n if(e.code === 'KeyZ') {\r\n let html = this.messageInput.innerHTML;\r\n\r\n if(e.shiftKey) {\r\n if(this.undoHistory.length) {\r\n this.executedHistory.push(html);\r\n html = this.undoHistory.pop();\r\n this.undoRedo(e, 'redo', html);\r\n html = this.messageInput.innerHTML;\r\n this.canRedoFromHTML = this.undoHistory.length ? html : '';\r\n this.canUndoFromHTML = html;\r\n }\r\n } else {\r\n // * подождём, когда пользователь сам восстановит поле до нужного состояния, которое стало сразу после saveExecuted\r\n if(this.executedHistory.length && (!this.canUndoFromHTML || html === this.canUndoFromHTML)) {\r\n this.undoHistory.push(html);\r\n html = this.executedHistory.pop();\r\n this.undoRedo(e, 'undo', html);\r\n\r\n // * поставим новое состояние чтобы снова подождать, если пользователь изменит что-то, и потом попробует откатить до предыдущего состояния\r\n this.canUndoFromHTML = this.canRedoFromHTML = this.messageInput.innerHTML;\r\n }\r\n }\r\n }\r\n };\r\n\r\n private onMessageInput = (e?: Event) => {\r\n // * validate due to manual formatting through browser's context menu\r\n /* const inputType = (e as InputEvent).inputType;\r\n console.log('message input event', e);\r\n if(inputType === 'formatBold') {\r\n console.log('message input format', this.messageInput.innerHTML);\r\n cancelEvent(e);\r\n }\r\n\r\n if(!isSelectionSingle()) {\r\n alert('not single');\r\n } */\r\n\r\n //console.log('messageInput input', this.messageInput.innerText);\r\n //const value = this.messageInput.innerText;\r\n const {value: richValue, entities: markdownEntities, caretPos} = getRichValueWithCaret(this.messageInputField.input);\r\n \r\n //const entities = RichTextProcessor.parseEntities(value);\r\n const value = RichTextProcessor.parseMarkdown(richValue, markdownEntities, true);\r\n const entities = RichTextProcessor.mergeEntities(markdownEntities, RichTextProcessor.parseEntities(value));\r\n\r\n //this.chat.log('messageInput entities', richValue, value, markdownEntities, caretPos);\r\n\r\n if(this.canRedoFromHTML && !this.lockRedo && this.messageInput.innerHTML !== this.canRedoFromHTML) {\r\n this.canRedoFromHTML = '';\r\n this.undoHistory.length = 0;\r\n }\r\n\r\n const urlEntities: Array<MessageEntity.messageEntityUrl | MessageEntity.messageEntityTextUrl> = entities.filter(e => e._ === 'messageEntityUrl' || e._ === 'messageEntityTextUrl') as any;\r\n if(urlEntities.length) {\r\n for(const entity of urlEntities) {\r\n let url: string;\r\n if(entity._ === 'messageEntityTextUrl') {\r\n url = entity.url;\r\n } else {\r\n url = richValue.slice(entity.offset, entity.offset + entity.length);\r\n\r\n if(!(url.includes('http://') || url.includes('https://'))) {\r\n continue;\r\n }\r\n }\r\n\r\n //console.log('messageInput url:', url);\r\n\r\n if(this.lastUrl !== url) {\r\n this.lastUrl = url;\r\n // this.willSendWebPage = null;\r\n const promise = this.getWebPagePromise = apiManager.invokeApiHashable('messages.getWebPage', {\r\n url,\r\n }).then((webpage) => {\r\n webpage = this.appWebPagesManager.saveWebPage(webpage);\r\n if(this.getWebPagePromise === promise) this.getWebPagePromise = undefined;\r\n if(this.lastUrl !== url) return;\r\n if(webpage._ === 'webPage') {\r\n //console.log('got webpage: ', webpage);\r\n\r\n this.setTopInfo('webpage', () => {}, webpage.site_name || webpage.title || 'Webpage', webpage.description || webpage.url || '');\r\n delete this.noWebPage;\r\n this.willSendWebPage = webpage;\r\n } else if(this.willSendWebPage) {\r\n this.onHelperCancel();\r\n }\r\n });\r\n }\r\n\r\n break;\r\n }\r\n } else if(this.lastUrl) {\r\n this.lastUrl = '';\r\n delete this.noWebPage;\r\n this.willSendWebPage = null;\r\n \r\n if(this.helperType) {\r\n this.helperFunc();\r\n } else {\r\n this.clearHelper();\r\n }\r\n }\r\n\r\n if(!richValue.trim()) {\r\n if(this.lastTimeType) {\r\n this.appMessagesManager.setTyping(this.chat.peerId, {_: 'sendMessageCancelAction'});\r\n }\r\n\r\n if(this.appImManager.markupTooltip) {\r\n this.appImManager.markupTooltip.hide();\r\n }\r\n } else {\r\n const time = Date.now();\r\n if(time - this.lastTimeType >= 6000) {\r\n this.lastTimeType = time;\r\n this.appMessagesManager.setTyping(this.chat.peerId, {_: 'sendMessageTypingAction'});\r\n }\r\n }\r\n\r\n if(!this.editMsgId) {\r\n this.saveDraftDebounced();\r\n }\r\n\r\n this.checkAutocomplete(richValue, caretPos, entities);\r\n\r\n this.updateSendBtn();\r\n };\r\n\r\n public insertAtCaret(insertText: string, insertEntity?: MessageEntity, isHelper = true) {\r\n const {value: fullValue, caretPos, entities} = getRichValueWithCaret(this.messageInput);\r\n const pos = caretPos >= 0 ? caretPos : fullValue.length;\r\n const prefix = fullValue.substr(0, pos);\r\n const suffix = fullValue.substr(pos);\r\n\r\n const matches = isHelper ? prefix.match(ChatInput.AUTO_COMPLETE_REG_EXP) : null;\r\n\r\n const matchIndex = matches ? matches.index + (matches[0].length - matches[2].length) : prefix.length;\r\n const newPrefix = prefix.slice(0, matchIndex);\r\n const newValue = newPrefix + insertText + suffix;\r\n\r\n // merge emojis\r\n const hadEntities = RichTextProcessor.parseEntities(fullValue);\r\n RichTextProcessor.mergeEntities(entities, hadEntities);\r\n\r\n // max for additional whitespace\r\n const insertLength = insertEntity ? Math.max(insertEntity.length, insertText.length) : insertText.length;\r\n const addEntities: MessageEntity[] = [];\r\n if(insertEntity) {\r\n addEntities.push(insertEntity);\r\n insertEntity.offset = matchIndex;\r\n }\r\n\r\n addEntities.push({\r\n _: 'messageEntityCaret',\r\n length: 0,\r\n offset: matchIndex + insertLength\r\n });\r\n \r\n // add offset to entities next to emoji\r\n const diff = insertLength - (matches ? matches[2].length : prefix.length);\r\n entities.forEach(entity => {\r\n if(entity.offset >= matchIndex) {\r\n entity.offset += diff;\r\n }\r\n });\r\n\r\n RichTextProcessor.mergeEntities(entities, addEntities);\r\n\r\n //const saveExecuted = this.prepareDocumentExecute();\r\n // can't exec .value here because it will instantly check for autocomplete\r\n this.messageInputField.setValueSilently(RichTextProcessor.wrapDraftText(newValue, {entities}), true);\r\n\r\n const caret = this.messageInput.querySelector('.composer-sel');\r\n setRichFocus(this.messageInput, caret);\r\n caret.remove();\r\n\r\n // but it's needed to be checked only here\r\n this.onMessageInput();\r\n\r\n //saveExecuted();\r\n\r\n //document.execCommand('insertHTML', true, RichTextProcessor.wrapEmojiText(emoji));\r\n }\r\n\r\n public onEmojiSelected = (emoji: string, autocomplete: boolean) => {\r\n if(autocomplete) {\r\n this.insertAtCaret(emoji, RichTextProcessor.getEmojiEntityFromEmoji(emoji));\r\n }\r\n };\r\n\r\n private checkAutocomplete(value?: string, caretPos?: number, entities?: MessageEntity[]) {\r\n //return;\r\n\r\n if(value === undefined) {\r\n const r = getRichValueWithCaret(this.messageInputField.input, true);\r\n value = r.value;\r\n caretPos = r.caretPos;\r\n entities = r.entities;\r\n }\r\n\r\n if(caretPos === -1) {\r\n caretPos = value.length;\r\n }\r\n\r\n if(entities === undefined) {\r\n const _value = RichTextProcessor.parseMarkdown(value, entities, true);\r\n entities = RichTextProcessor.mergeEntities(entities, RichTextProcessor.parseEntities(_value));\r\n }\r\n\r\n value = value.substr(0, caretPos);\r\n\r\n if(this.previousQuery === value) {\r\n return;\r\n }\r\n\r\n this.previousQuery = value;\r\n \r\n const matches = value.match(ChatInput.AUTO_COMPLETE_REG_EXP);\r\n let foundHelper: AutocompleteHelper;\r\n if(matches) {\r\n const entity = entities[0];\r\n\r\n let query = matches[2];\r\n const firstChar = query[0];\r\n\r\n if(this.stickersHelper && \r\n rootScope.settings.stickers.suggest && \r\n this.appMessagesManager.canSendToPeer(this.chat.peerId, this.chat.threadId, 'send_stickers') &&\r\n entity?._ === 'messageEntityEmoji' && entity.length === value.length && !entity.offset) {\r\n foundHelper = this.stickersHelper;\r\n this.stickersHelper.checkEmoticon(value);\r\n } else if(firstChar === '@') { // mentions\r\n const topMsgId = this.chat.threadId ? this.appMessagesIdsManager.getServerMessageId(this.chat.threadId) : undefined;\r\n if(this.mentionsHelper.checkQuery(query, this.chat.peerId > 0 ? 0 : this.chat.peerId, topMsgId)) {\r\n foundHelper = this.mentionsHelper;\r\n }\r\n } else if(!matches[1] && firstChar === '/') { // commands\r\n if(this.commandsHelper.checkQuery(query, this.chat.peerId)) {\r\n foundHelper = this.commandsHelper;\r\n }\r\n } else if(rootScope.settings.emoji.suggest) { // emoji\r\n query = query.replace(/^\\s*/, '');\r\n if(!value.match(/^\\s*:(.+):\\s*$/) && !value.match(/:[;!@#$%^&*()-=|]/) && query) {\r\n foundHelper = this.emojiHelper;\r\n this.emojiHelper.checkQuery(query, firstChar);\r\n }\r\n }\r\n }\r\n \r\n foundHelper = this.checkInlineAutocomplete(value, foundHelper);\r\n\r\n this.autocompleteHelperController.hideOtherHelpers(foundHelper);\r\n }\r\n\r\n private checkInlineAutocomplete(value: string, foundHelper?: AutocompleteHelper): AutocompleteHelper {\r\n let needPlaceholder = false;\r\n\r\n if(!foundHelper) {\r\n const inlineMatch = value.match(/^@([a-zA-Z\\\\d_]{3,32})\\s/);\r\n if(inlineMatch) {\r\n const username = inlineMatch[1];\r\n const query = value.slice(inlineMatch[0].length);\r\n needPlaceholder = inlineMatch[0].length === value.length;\r\n \r\n foundHelper = this.inlineHelper;\r\n\r\n if(!this.btnPreloader) {\r\n this.btnPreloader = ButtonIcon('none btn-preloader float show disable-hover', {noRipple: true});\r\n putPreloader(this.btnPreloader, true);\r\n this.inputMessageContainer.parentElement.insertBefore(this.btnPreloader, this.inputMessageContainer.nextSibling);\r\n } else {\r\n SetTransition(this.btnPreloader, 'show', true, 400);\r\n }\r\n \r\n this.inlineHelper.checkQuery(this.chat.peerId, username, query).then(({user, renderPromise}) => {\r\n if(needPlaceholder && user.bot_inline_placeholder) {\r\n this.messageInput.dataset.inlinePlaceholder = user.bot_inline_placeholder;\r\n }\r\n\r\n renderPromise.then(() => {\r\n SetTransition(this.btnPreloader, 'show', false, 400);\r\n });\r\n }).catch(noop);\r\n }\r\n }\r\n \r\n if(!needPlaceholder) {\r\n delete this.messageInput.dataset.inlinePlaceholder;\r\n }\r\n\r\n if(foundHelper !== this.inlineHelper) {\r\n if(this.btnPreloader) {\r\n SetTransition(this.btnPreloader, 'show', false, 400);\r\n }\r\n }\r\n\r\n return foundHelper;\r\n }\r\n\r\n private onBtnSendClick = (e: Event) => {\r\n cancelEvent(e);\r\n\r\n if(!this.recorder || this.recording || !this.isInputEmpty() || this.forwarding || this.editMsgId) {\r\n if(this.recording) {\r\n if((Date.now() - this.recordStartTime) < RECORD_MIN_TIME) {\r\n this.onCancelRecordClick();\r\n } else {\r\n this.recorder.stop();\r\n }\r\n } else {\r\n this.sendMessage();\r\n }\r\n } else {\r\n if(this.chat.peerId < 0 && !this.appMessagesManager.canSendToPeer(this.chat.peerId, this.chat.threadId, 'send_media')) {\r\n toast(POSTING_MEDIA_NOT_ALLOWED);\r\n return;\r\n }\r\n\r\n this.chatInput.classList.add('is-locked');\r\n blurActiveElement();\r\n\r\n this.recorder.start().then(() => {\r\n this.releaseMediaPlayback = appMediaPlaybackController.setSingleMedia();\r\n this.recordCanceled = false;\r\n \r\n this.chatInput.classList.add('is-recording');\r\n this.recording = true;\r\n this.updateSendBtn();\r\n opusDecodeController.setKeepAlive(true);\r\n \r\n const showDiscardPopup = () => {\r\n new PopupPeer('popup-cancel-record', {\r\n titleLangKey: 'DiscardVoiceMessageTitle',\r\n descriptionLangKey: 'DiscardVoiceMessageDescription',\r\n buttons: [{\r\n langKey: 'DiscardVoiceMessageAction',\r\n callback: () => {\r\n simulateClickEvent(this.btnCancelRecord);\r\n }\r\n }, {\r\n langKey: 'Continue',\r\n isCancel: true\r\n }]\r\n }).show();\r\n };\r\n\r\n this.recordingOverlayListener = this.listenerSetter.add(document.body)('mousedown', (e) => {\r\n if(!findUpClassName(e.target, 'chat-input') && !findUpClassName(e.target, 'popup-cancel-record')) {\r\n cancelEvent(e);\r\n showDiscardPopup();\r\n }\r\n }, {capture: true, passive: false}) as any;\r\n\r\n appNavigationController.pushItem(this.recordingNavigationItem = {\r\n type: 'voice',\r\n onPop: () => {\r\n setTimeout(() => {\r\n showDiscardPopup();\r\n }, 0);\r\n\r\n return false;\r\n }\r\n });\r\n\r\n this.recordStartTime = Date.now();\r\n\r\n const sourceNode: MediaStreamAudioSourceNode = this.recorder.sourceNode;\r\n const context = sourceNode.context;\r\n\r\n const analyser = context.createAnalyser();\r\n sourceNode.connect(analyser);\r\n //analyser.connect(context.destination);\r\n analyser.fftSize = 32;\r\n\r\n const frequencyData = new Uint8Array(analyser.frequencyBinCount);\r\n const max = frequencyData.length * 255;\r\n const min = 54 / 150;\r\n let r = () => {\r\n if(!this.recording) return;\r\n\r\n analyser.getByteFrequencyData(frequencyData);\r\n\r\n let sum = 0;\r\n frequencyData.forEach(value => {\r\n sum += value;\r\n });\r\n \r\n let percents = Math.min(1, (sum / max) + min);\r\n //console.log('frequencyData', frequencyData, percents);\r\n\r\n this.recordRippleEl.style.transform = `scale(${percents})`;\r\n\r\n let diff = Date.now() - this.recordStartTime;\r\n let ms = diff % 1000;\r\n\r\n let formatted = ('' + (diff / 1000)).toHHMMSS() + ',' + ('00' + Math.round(ms / 10)).slice(-2);\r\n\r\n this.recordTimeEl.innerText = formatted;\r\n\r\n fastRaf(r);\r\n };\r\n\r\n r();\r\n }).catch((e: Error) => {\r\n switch(e.name as string) {\r\n case 'NotAllowedError': {\r\n toast('Please allow access to your microphone');\r\n break;\r\n }\r\n\r\n case 'NotReadableError': {\r\n toast(e.message);\r\n break;\r\n }\r\n\r\n default:\r\n console.error('Recorder start error:', e, e.name, e.message);\r\n toast(e.message);\r\n break;\r\n }\r\n\r\n this.chatInput.classList.remove('is-recording', 'is-locked');\r\n });\r\n }\r\n };\r\n\r\n private onHelperCancel = (e?: Event) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n\r\n if(this.willSendWebPage) {\r\n const lastUrl = this.lastUrl;\r\n let needReturn = false;\r\n if(this.helperType) {\r\n //if(this.helperFunc) {\r\n this.helperFunc();\r\n //}\r\n\r\n needReturn = true;\r\n }\r\n\r\n // * restore values\r\n this.lastUrl = lastUrl;\r\n this.noWebPage = true;\r\n this.willSendWebPage = null;\r\n\r\n if(needReturn) return;\r\n }\r\n\r\n this.clearHelper();\r\n this.updateSendBtn();\r\n };\r\n\r\n private onHelperClick = (e: Event) => {\r\n cancelEvent(e);\r\n \r\n if(!findUpClassName(e.target, 'reply-wrapper')) return;\r\n if(this.helperType === 'forward') {\r\n if(this.helperWaitingForward) return;\r\n this.helperWaitingForward = true;\r\n\r\n const helperFunc = this.helperFunc;\r\n this.clearHelper();\r\n this.updateSendBtn();\r\n let selected = false;\r\n new PopupForward(copy(this.forwarding), () => {\r\n selected = true;\r\n }, () => {\r\n this.helperWaitingForward = false;\r\n\r\n if(!selected) {\r\n helperFunc();\r\n }\r\n });\r\n } else if(this.helperType === 'reply') {\r\n this.chat.setMessageId(this.replyToMsgId);\r\n } else if(this.helperType === 'edit') {\r\n this.chat.setMessageId(this.editMsgId);\r\n }\r\n };\r\n\r\n public clearInput(canSetDraft = true, fireEvent = true, clearValue = '') {\r\n if(document.activeElement === this.messageInput && IS_MOBILE_SAFARI) { // fix first char uppercase\r\n const i = document.createElement('input');\r\n document.body.append(i);\r\n fixSafariStickyInput(i);\r\n this.messageInputField.setValueSilently(clearValue);\r\n fixSafariStickyInput(this.messageInput);\r\n i.remove();\r\n } else {\r\n this.messageInputField.setValueSilently(clearValue);\r\n }\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n //this.messageInput.innerText = '';\r\n } else {\r\n //this.attachMessageInputField();\r\n //this.messageInput.innerText = '';\r\n\r\n // clear executions\r\n this.canRedoFromHTML = '';\r\n this.undoHistory.length = 0;\r\n this.executedHistory.length = 0;\r\n this.canUndoFromHTML = '';\r\n }\r\n\r\n let set = false;\r\n if(canSetDraft) {\r\n set = this.setDraft(undefined, false);\r\n }\r\n\r\n if(!set && fireEvent) {\r\n this.onMessageInput();\r\n }\r\n }\r\n\r\n public isInputEmpty() {\r\n return isInputEmpty(this.messageInput);\r\n }\r\n\r\n public updateSendBtn() {\r\n let icon: 'send' | 'record' | 'edit' | 'schedule';\r\n\r\n const isInputEmpty = this.isInputEmpty();\r\n\r\n if(this.editMsgId) icon = 'edit';\r\n else if(!this.recorder || this.recording || !isInputEmpty || this.forwarding) icon = this.chat.type === 'scheduled' ? 'schedule' : 'send';\r\n else icon = 'record';\r\n\r\n ['send', 'record', 'edit', 'schedule'].forEach(i => {\r\n this.btnSend.classList.toggle(i, icon === i);\r\n });\r\n\r\n if(this.btnScheduled) {\r\n this.btnScheduled.classList.toggle('show', isInputEmpty);\r\n }\r\n\r\n if(this.btnToggleReplyMarkup) {\r\n this.btnToggleReplyMarkup.classList.toggle('show', isInputEmpty);\r\n }\r\n }\r\n\r\n public onMessageSent(clearInput = true, clearReply?: boolean) {\r\n if(this.chat.type !== 'scheduled') {\r\n this.appMessagesManager.readAllHistory(this.chat.peerId, this.chat.threadId, true);\r\n }\r\n\r\n this.scheduleDate = undefined;\r\n this.sendSilent = undefined;\r\n\r\n const value = this.messageInputField.value;\r\n const entities = RichTextProcessor.parseEntities(value);\r\n const emojiEntities: MessageEntity.messageEntityEmoji[] = entities.filter(entity => entity._ === 'messageEntityEmoji') as any;\r\n emojiEntities.forEach(entity => {\r\n const emoji = emojiFromCodePoints(entity.unicode);\r\n this.appEmojiManager.pushRecentEmoji(emoji);\r\n });\r\n\r\n if(clearInput) {\r\n this.lastUrl = '';\r\n delete this.noWebPage;\r\n this.willSendWebPage = null;\r\n this.clearInput();\r\n }\r\n\r\n if(clearReply || clearInput) {\r\n this.clearHelper();\r\n }\r\n\r\n this.updateSendBtn();\r\n }\r\n\r\n public sendMessage(force = false) {\r\n if(this.chat.type === 'scheduled' && !force && !this.editMsgId) {\r\n this.scheduleSending();\r\n return;\r\n }\r\n\r\n const {value, entities} = getRichValue(this.messageInputField.input);\r\n\r\n //return;\r\n if(this.editMsgId) {\r\n const message = this.chat.getMessage(this.editMsgId);\r\n if(!!value.trim() || message.media) {\r\n this.appMessagesManager.editMessage(message, value, {\r\n entities,\r\n noWebPage: this.noWebPage\r\n });\r\n } else {\r\n new PopupDeleteMessages(this.chat.peerId, [this.editMsgId], this.chat.type);\r\n\r\n return;\r\n }\r\n } else {\r\n this.appMessagesManager.sendText(this.chat.peerId, value, {\r\n entities,\r\n replyToMsgId: this.replyToMsgId,\r\n threadId: this.chat.threadId,\r\n noWebPage: this.noWebPage,\r\n webPage: this.getWebPagePromise ? undefined : this.willSendWebPage,\r\n scheduleDate: this.scheduleDate,\r\n silent: this.sendSilent,\r\n clearDraft: true\r\n });\r\n }\r\n\r\n // * wait for sendText set messageId for invokeAfterMsg\r\n if(this.forwarding) {\r\n const forwarding = copy(this.forwarding);\r\n const peerId = this.chat.peerId;\r\n const silent = this.sendSilent;\r\n const scheduleDate = this.scheduleDate;\r\n setTimeout(() => {\r\n for(const fromPeerId in forwarding) {\r\n this.appMessagesManager.forwardMessages(peerId, +fromPeerId, forwarding[fromPeerId], {\r\n silent,\r\n scheduleDate: scheduleDate\r\n });\r\n }\r\n }, 0);\r\n }\r\n\r\n this.onMessageSent();\r\n }\r\n\r\n public sendMessageWithDocument(document: MyDocument | string, force = false, clearDraft = false) {\r\n document = this.appDocsManager.getDoc(document);\r\n\r\n const flag = document.type === 'sticker' ? 'send_stickers' : (document.type === 'gif' ? 'send_gifs' : 'send_media');\r\n if(this.chat.peerId < 0 && !this.appMessagesManager.canSendToPeer(this.chat.peerId, this.chat.threadId, flag)) {\r\n toast(POSTING_MEDIA_NOT_ALLOWED);\r\n return false;\r\n }\r\n\r\n if(this.chat.type === 'scheduled' && !force) {\r\n this.scheduleSending(() => this.sendMessageWithDocument(document, true, clearDraft));\r\n return false;\r\n }\r\n\r\n if(document) {\r\n this.appMessagesManager.sendFile(this.chat.peerId, document, {\r\n isMedia: true, \r\n replyToMsgId: this.replyToMsgId, \r\n threadId: this.chat.threadId,\r\n silent: this.sendSilent, \r\n scheduleDate: this.scheduleDate,\r\n clearDraft: clearDraft || undefined\r\n });\r\n this.onMessageSent(clearDraft, true);\r\n\r\n if(document.type === 'sticker') {\r\n emoticonsDropdown.stickersTab?.pushRecentSticker(document);\r\n }\r\n\r\n return true;\r\n }\r\n \r\n return false;\r\n }\r\n\r\n /* public sendSomething(callback: () => void, force = false) {\r\n if(this.chat.type === 'scheduled' && !force) {\r\n this.scheduleSending(() => this.sendSomething(callback, true));\r\n return false;\r\n }\r\n\r\n callback();\r\n this.onMessageSent(false, true);\r\n\r\n return true;\r\n } */\r\n\r\n public initMessageEditing(mid: number) {\r\n const message = this.chat.getMessage(mid);\r\n\r\n let input = RichTextProcessor.wrapDraftText(message.message, {entities: message.totalEntities});\r\n const f = () => {\r\n const replyFragment = this.appMessagesManager.wrapMessageForReply(message, undefined, [message.mid]);\r\n this.setTopInfo('edit', f, i18n('AccDescrEditing'), replyFragment, input, message);\r\n\r\n this.editMsgId = mid;\r\n input = undefined;\r\n };\r\n f();\r\n }\r\n\r\n public initMessagesForward(fromPeerIdsMids: {[fromPeerId: number]: number[]}) {\r\n const f = () => {\r\n //const peerTitles: string[]\r\n const fromPeerIds = Object.keys(fromPeerIdsMids).map(str => +str);\r\n const smth: Set<string | number> = new Set();\r\n let length = 0;\r\n\r\n fromPeerIds.forEach(fromPeerId => {\r\n const mids = fromPeerIdsMids[fromPeerId];\r\n mids.forEach(mid => {\r\n const message = this.appMessagesManager.getMessageByPeer(fromPeerId, mid);\r\n if(message.fwd_from?.from_name && !message.fromId && !message.fwdFromId) {\r\n smth.add(message.fwd_from.from_name);\r\n } else {\r\n smth.add(message.fromId);\r\n }\r\n });\r\n\r\n length += mids.length;\r\n });\r\n\r\n const onlyFirstName = smth.size > 2;\r\n const peerTitles = [...smth].map(smth => {\r\n return typeof(smth) === 'number' ? \r\n new PeerTitle({peerId: smth, dialog: false, onlyFirstName}).element : \r\n (onlyFirstName ? smth.split(' ')[0] : smth);\r\n });\r\n\r\n const title = document.createDocumentFragment();\r\n if(peerTitles.length < 3) {\r\n title.append(...join(peerTitles, false));\r\n } else {\r\n title.append(peerTitles[0], i18n('AndOther', [peerTitles.length - 1]));\r\n }\r\n \r\n let firstMessage: any, usingFullAlbum: boolean;\r\n if(fromPeerIds.length === 1) {\r\n const fromPeerId = fromPeerIds[0];\r\n const mids = fromPeerIdsMids[fromPeerId];\r\n firstMessage = this.appMessagesManager.getMessageByPeer(fromPeerId, mids[0]);\r\n \r\n usingFullAlbum = !!firstMessage.grouped_id;\r\n if(usingFullAlbum) {\r\n const albumMids = this.appMessagesManager.getMidsByMessage(firstMessage);\r\n if(albumMids.length !== length || albumMids.find(mid => !mids.includes(mid))) {\r\n usingFullAlbum = false;\r\n }\r\n }\r\n }\r\n \r\n if(usingFullAlbum || length === 1) {\r\n const mids = fromPeerIdsMids[fromPeerIds[0]];\r\n const replyFragment = this.appMessagesManager.wrapMessageForReply(firstMessage, undefined, mids);\r\n this.setTopInfo('forward', f, title, replyFragment);\r\n } else {\r\n this.setTopInfo('forward', f, title, i18n('ForwardedMessageCount', [length]));\r\n }\r\n\r\n this.forwarding = fromPeerIdsMids;\r\n };\r\n \r\n f();\r\n }\r\n\r\n public initMessageReply(mid: number) {\r\n let message: Message = this.chat.getMessage(mid);\r\n const f = () => {\r\n let peerTitleEl: HTMLElement;\r\n if(message._ === 'messageEmpty') { // load missing replying message\r\n peerTitleEl = i18n('Loading');\r\n\r\n this.chat.appMessagesManager.wrapSingleMessage(this.chat.peerId, mid).then(() => {\r\n if(this.replyToMsgId !== mid) {\r\n return;\r\n }\r\n\r\n message = this.chat.getMessage(mid);\r\n if(message._ === 'messageEmpty') {\r\n this.clearHelper('reply');\r\n } else {\r\n f();\r\n }\r\n });\r\n } else {\r\n peerTitleEl = new PeerTitle({\r\n peerId: message.fromId,\r\n dialog: false\r\n }).element;\r\n }\r\n\r\n this.setTopInfo('reply', f, peerTitleEl, message && (message as Message.message).message, undefined, message);\r\n this.replyToMsgId = mid;\r\n };\r\n f();\r\n }\r\n\r\n public clearHelper(type?: ChatInputHelperType) {\r\n if(this.helperType === 'edit' && type !== 'edit') {\r\n this.clearInput();\r\n }\r\n\r\n if(type) {\r\n this.lastUrl = '';\r\n delete this.noWebPage;\r\n this.willSendWebPage = null;\r\n }\r\n \r\n this.replyToMsgId = undefined;\r\n this.forwarding = undefined;\r\n this.editMsgId = undefined;\r\n this.helperType = this.helperFunc = undefined;\r\n\r\n if(this.chat.container.classList.contains('is-helper-active')) {\r\n appNavigationController.removeByType('input-helper');\r\n this.chat.container.classList.remove('is-helper-active');\r\n }\r\n }\r\n\r\n public setInputValue(value: string, clear = true, focus = true) {\r\n if(!value) value = '';\r\n\r\n if(clear) this.clearInput(false, false, value);\r\n else this.messageInputField.setValueSilently(value);\r\n\r\n fastRaf(() => {\r\n focus && placeCaretAtEnd(this.messageInput);\r\n this.onMessageInput();\r\n this.messageInput.scrollTop = this.messageInput.scrollHeight;\r\n });\r\n }\r\n\r\n public setTopInfo(type: ChatInputHelperType, \r\n callerFunc: () => void, \r\n title: Parameters<typeof wrapReply>[0] = '', \r\n subtitle: Parameters<typeof wrapReply>[1] = '', \r\n input?: string, \r\n message?: any) {\r\n if(type !== 'webpage') {\r\n this.clearHelper(type);\r\n this.helperType = type;\r\n this.helperFunc = callerFunc;\r\n }\r\n\r\n const replyParent = this.replyElements.container;\r\n if(replyParent.lastElementChild.tagName === 'DIV') {\r\n replyParent.lastElementChild.remove();\r\n }\r\n\r\n replyParent.append(wrapReply(title, subtitle, message));\r\n\r\n this.chat.container.classList.add('is-helper-active');\r\n /* const scroll = appImManager.scrollable;\r\n if(scroll.isScrolledDown && !scroll.scrollLocked && !appImManager.messagesQueuePromise && !appImManager.setPeerPromise) {\r\n scroll.scrollTo(scroll.scrollHeight, 'top', true, true, 200);\r\n } */\r\n\r\n if(!IS_MOBILE) {\r\n appNavigationController.pushItem({\r\n type: 'input-helper',\r\n onPop: () => {\r\n this.onHelperCancel();\r\n }\r\n });\r\n }\r\n\r\n if(input !== undefined) {\r\n this.setInputValue(input);\r\n }\r\n\r\n setTimeout(() => {\r\n this.updateSendBtn();\r\n }, 0);\r\n }\r\n\r\n // public saveScroll() {\r\n // this.scrollTop = this.chat.bubbles.scrollable.container.scrollTop;\r\n // this.scrollOffsetTop = this.chatInput.offsetTop;\r\n // }\r\n\r\n // public restoreScroll() {\r\n // if(this.chatInput.style.display) return;\r\n // //console.log('input resize', offsetTop, this.chatInput.offsetTop);\r\n // let newOffsetTop = this.chatInput.offsetTop;\r\n // let container = this.chat.bubbles.scrollable.container;\r\n // let scrollTop = container.scrollTop;\r\n // let clientHeight = container.clientHeight;\r\n // let maxScrollTop = container.scrollHeight;\r\n\r\n // if(newOffsetTop < this.scrollOffsetTop) {\r\n // this.scrollDiff = this.scrollOffsetTop - newOffsetTop;\r\n // container.scrollTop += this.scrollDiff;\r\n // } else if(scrollTop !== this.scrollTop) {\r\n // let endDiff = maxScrollTop - (scrollTop + clientHeight);\r\n // if(endDiff < this.scrollDiff/* && false */) {\r\n // //container.scrollTop -= endDiff;\r\n // } else {\r\n // container.scrollTop -= this.scrollDiff;\r\n // }\r\n // }\r\n // }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nexport default function setRichFocus(field: HTMLElement, selectNode: Node, noCollapse?: boolean) {\r\n field.focus();\r\n if(selectNode &&\r\n selectNode.parentNode == field &&\r\n !selectNode.nextSibling &&\r\n !noCollapse) {\r\n field.removeChild(selectNode);\r\n selectNode = null;\r\n }\r\n\r\n if(window.getSelection && document.createRange) {\r\n const range = document.createRange();\r\n if(selectNode) {\r\n range.selectNode(selectNode);\r\n } else {\r\n range.selectNodeContents(field);\r\n }\r\n\r\n if(!noCollapse) {\r\n range.collapse(false);\r\n }\r\n\r\n const sel = window.getSelection();\r\n sel.removeAllRanges();\r\n sel.addRange(range);\r\n }\r\n /* else if (document.body.createTextRange !== undefined) {\r\n var textRange = document.body.createTextRange()\r\n textRange.moveToElementText(selectNode || field)\r\n if (!noCollapse) {\r\n textRange.collapse(false)\r\n }\r\n textRange.select()\r\n } */\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type Chat from \"./chat\";\r\nimport type ChatTopbar from \"./topbar\";\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport DivAndCaption from \"../divAndCaption\";\r\nimport { ripple } from \"../ripple\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport { safeAssign } from \"../../helpers/object\";\r\nimport { Message } from \"../../layer\";\r\n\r\nconst classNames: string[] = ['is-pinned-message-shown', 'is-pinned-audio-shown'];\r\nconst CLASSNAME_BASE = 'pinned-container';\r\nconst HEIGHT = 52;\r\n\r\nexport default class PinnedContainer {\r\n public wrapperUtils: HTMLElement;\r\n public btnClose: HTMLElement;\r\n protected wrapper: HTMLElement;\r\n\r\n protected topbar: ChatTopbar;\r\n protected chat: Chat;\r\n protected listenerSetter: ListenerSetter;\r\n public className: string;\r\n public divAndCaption: DivAndCaption<(title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment, message?: any) => void>;\r\n \r\n protected floating = false;\r\n\r\n public onClose?: () => void | Promise<boolean>;\r\n\r\n constructor(options: {\r\n topbar: PinnedContainer['topbar'],\r\n chat: PinnedContainer['chat'],\r\n listenerSetter: PinnedContainer['listenerSetter'],\r\n className: PinnedContainer['className'],\r\n divAndCaption: PinnedContainer['divAndCaption'],\r\n onClose?: PinnedContainer['onClose'],\r\n floating?: PinnedContainer['floating']\r\n }) {\r\n safeAssign(this, options);\r\n\r\n const {divAndCaption, className} = this;\r\n divAndCaption.container.classList.add(CLASSNAME_BASE, 'hide');\r\n divAndCaption.title.classList.add(CLASSNAME_BASE + '-title');\r\n divAndCaption.subtitle.classList.add(CLASSNAME_BASE + '-subtitle');\r\n divAndCaption.content.classList.add(CLASSNAME_BASE + '-content');\r\n \r\n this.btnClose = document.createElement('button');\r\n this.btnClose.classList.add(CLASSNAME_BASE + '-close', `pinned-${className}-close`, 'btn-icon', 'tgico-close');\r\n \r\n this.wrapper = document.createElement('div');\r\n this.wrapper.classList.add(CLASSNAME_BASE + '-wrapper');\r\n ripple(this.wrapper);\r\n\r\n this.wrapperUtils = document.createElement('div');\r\n this.wrapperUtils.classList.add(CLASSNAME_BASE + '-wrapper-utils');\r\n this.wrapperUtils.append(this.btnClose);\r\n\r\n this.wrapper.append(...Array.from(divAndCaption.container.children), this.wrapperUtils);\r\n\r\n divAndCaption.container.append(this.wrapper/* , this.close */);\r\n\r\n this.attachOnCloseEvent(this.btnClose);\r\n }\r\n\r\n public attachOnCloseEvent(elem: HTMLElement) {\r\n attachClickEvent(elem, (e) => {\r\n cancelEvent(e);\r\n\r\n ((this.onClose ? this.onClose() : null) || Promise.resolve(true)).then(needClose => {\r\n if(needClose) {\r\n this.toggle(true);\r\n }\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n public toggle(hide?: boolean) {\r\n const isHidden = this.divAndCaption.container.classList.contains('hide');\r\n if(hide === undefined) {\r\n hide = !isHidden;\r\n } else if(hide === isHidden) {\r\n return;\r\n }\r\n\r\n const scrollable = this.chat.bubbles.scrollable;\r\n \r\n const isFloating = (this.floating || mediaSizes.isMobile) && !hide;\r\n const scrollTop = isFloating || this.divAndCaption.container.classList.contains('is-floating') ? scrollable.scrollTop : undefined;\r\n\r\n this.divAndCaption.container.classList.toggle('is-floating', isFloating);\r\n this.divAndCaption.container.classList.toggle('hide', hide);\r\n \r\n this.topbar.container.classList.toggle('is-pinned-floating', isFloating);\r\n this.topbar.container.classList.toggle(`is-pinned-${this.className}-shown`, !hide);\r\n \r\n const active = classNames.filter(className => this.topbar.container.classList.contains(className));\r\n const maxActive = hide ? 0 : 1;\r\n \r\n if(scrollTop !== undefined && active.length <= maxActive/* && !scrollable.isScrolledDown */) {\r\n scrollable.scrollTop = scrollTop + ((hide ? -1 : 1) * HEIGHT);\r\n }\r\n \r\n this.topbar.setFloating();\r\n this.topbar.setUtilsWidth();\r\n }\r\n\r\n public fill(title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment, message: Message.message) {\r\n this.divAndCaption.container.dataset.peerId = '' + message.peerId;\r\n this.divAndCaption.container.dataset.mid = '' + message.mid;\r\n this.divAndCaption.fill(title, subtitle, message);\r\n this.topbar.setUtilsWidth();\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\nimport type ChatTopbar from \"./topbar\";\nimport rootScope from \"../../lib/rootScope\";\nimport appMediaPlaybackController from \"../appMediaPlaybackController\";\nimport DivAndCaption from \"../divAndCaption\";\nimport PinnedContainer from \"./pinnedContainer\";\nimport Chat from \"./chat\";\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport PeerTitle from \"../peerTitle\";\nimport { i18n } from \"../../lib/langPack\";\nimport { formatFullSentTime } from \"../../helpers/date\";\nimport { MediaProgressLine, VolumeSelector } from \"../../lib/mediaPlayer\";\nimport ButtonIcon from \"../buttonIcon\";\n\nexport default class ChatAudio extends PinnedContainer {\n private toggleEl: HTMLElement;\n private progressLine: MediaProgressLine;\n private volumeSelector: VolumeSelector;\n\n constructor(protected topbar: ChatTopbar, protected chat: Chat, protected appMessagesManager: AppMessagesManager) {\n super({\n topbar, \n chat, \n listenerSetter: topbar.listenerSetter, \n className: 'audio', \n divAndCaption: new DivAndCaption(\n 'pinned-audio', \n (title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment) => {\n replaceContent(this.divAndCaption.title, title);\n replaceContent(this.divAndCaption.subtitle, subtitle);\n }\n ), \n onClose: () => {\n appMediaPlaybackController.stop();\n },\n floating: true\n });\n\n this.divAndCaption.border.remove();\n\n const prevEl = ButtonIcon('pprevious active', {noRipple: true});\n const nextEl = ButtonIcon('nnext active', {noRipple: true});\n\n prevEl.innerHTML = `<svg class=\"missing-icon\" viewBox=\"0 0 24 24\" preserveAspectRatio=\"xMidYMid meet\"><g><path class=\"missing-icon-path\" d=\"M6 6h2v12H6zm3.5 6l8.5 6V6z\"></path></g></svg>`;\n nextEl.innerHTML = `<svg class=\"missing-icon\" viewBox=\"0 0 24 24\" preserveAspectRatio=\"xMidYMid meet\"><g><path class=\"missing-icon-path\" d=\"M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z\"></path></g></svg>`;\n\n const attachClick = (elem: HTMLElement, callback: () => void) => {\n attachClickEvent(elem, (e) => {\n cancelEvent(e);\n callback();\n }, {listenerSetter: this.topbar.listenerSetter});\n };\n\n attachClick(prevEl, () => {\n appMediaPlaybackController.previous();\n });\n\n attachClick(nextEl, () => {\n appMediaPlaybackController.next();\n });\n\n this.toggleEl = ButtonIcon('', {noRipple: true});\n this.toggleEl.classList.add('active', 'pinned-audio-ico', 'tgico');\n attachClick(this.toggleEl, () => {\n appMediaPlaybackController.toggle();\n });\n this.wrapper.prepend(this.wrapper.firstElementChild, prevEl, this.toggleEl, nextEl);\n\n this.volumeSelector = new VolumeSelector(this.listenerSetter, true);\n const volumeProgressLineContainer = document.createElement('div');\n volumeProgressLineContainer.classList.add('progress-line-container');\n volumeProgressLineContainer.append(this.volumeSelector.container);\n const tunnel = document.createElement('div');\n tunnel.classList.add('pinned-audio-volume-tunnel');\n this.volumeSelector.btn.classList.add('pinned-audio-volume', 'active');\n this.volumeSelector.btn.prepend(tunnel);\n this.volumeSelector.btn.append(volumeProgressLineContainer);\n this.wrapperUtils.prepend(this.volumeSelector.btn);\n\n const progressWrapper = document.createElement('div');\n progressWrapper.classList.add('pinned-audio-progress-wrapper');\n\n this.progressLine = new MediaProgressLine(undefined, undefined, true, true);\n this.progressLine.container.classList.add('pinned-audio-progress');\n progressWrapper.append(this.progressLine.container);\n this.wrapper.insertBefore(progressWrapper, this.wrapperUtils);\n\n this.topbar.listenerSetter.add(rootScope)('media_play', ({doc, message, media}) => {\n let title: string | HTMLElement, subtitle: string | HTMLElement | DocumentFragment;\n if(doc.type === 'voice' || doc.type === 'round') {\n title = new PeerTitle({peerId: message.fromId}).element;\n\n //subtitle = 'Voice message';\n subtitle = formatFullSentTime(message.date);\n } else {\n title = doc.audioTitle || doc.fileName;\n subtitle = doc.audioPerformer || i18n('AudioUnknownArtist');\n }\n\n this.progressLine.setMedia(media);\n\n this.fill(title, subtitle, message);\n this.toggleEl.classList.add('flip-icon');\n this.toggle(false);\n });\n\n this.topbar.listenerSetter.add(rootScope)('media_pause', () => {\n this.toggleEl.classList.remove('flip-icon');\n });\n\n this.topbar.listenerSetter.add(rootScope)('media_stop', () => {\n this.toggle(true);\n });\n }\n}\n","// https://github.com/evgeny-nadymov/telegram-react/blob/master/src/Components/ColumnMiddle/PinnedMessageBorder.js\n\nenum BAR_HEIGHTS {\n ONE = 32,\n TWO = 15,\n THREE = 10,\n FOUR = 8,\n MORE = 8\n};\n\nconst GAP = 1;\nconst WIDTH = 2;\nconst BASE_CLASS = 'pinned-message-border';\n\nexport default class PinnedMessageBorder {\n private border: HTMLElement;\n private wrapper: HTMLElement;\n private svg: SVGSVGElement;\n private defs: SVGDefsElement;\n private clipPath: SVGClipPathElement;\n private path: SVGPathElement;\n private mark: HTMLElement;\n\n private count: number;\n private index: number;\n\n private drawRect = (x: number, y: number, width: number, height: number, radius: number) => {\n return `M${x},${y + radius}a${radius},${radius},0,0,1,${width},0v${height - 2 * radius}a${radius},${radius},0,0,1,${-width},0Z`;\n };\n\n private getClipPath = (id: string, barHeight: number, count: number) => {\n const radius = 1;\n\n let d = '';\n /* if(count === 3) {\n d = this.drawRect(0, 0, WIDTH, barHeight, radius)\n + this.drawRect(0, barHeight + GAP, WIDTH, barHeight + 1, radius)\n + this.drawRect(0, barHeight * 2 + GAP * 2 + 1, WIDTH, barHeight, radius);\n } */if(count === 2) {\n d = this.drawRect(0, 0, WIDTH, barHeight, radius) + this.drawRect(0, barHeight + GAP * 2, WIDTH, barHeight, radius);\n } else {\n for(let i = 0; i < count; ++i) {\n d += this.drawRect(0, (barHeight + GAP) * i, WIDTH, barHeight, radius);\n }\n }\n\n if(!this.clipPath) {\n this.clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');\n this.path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n\n this.clipPath.append(this.path);\n }\n\n this.clipPath.id = id;\n this.path.setAttributeNS(null, 'd', d);\n\n return this.clipPath;\n };\n\n private getBarHeight = (count: number, index: number) => {\n let barHeight: number;\n if(count <= 1) {\n barHeight = BAR_HEIGHTS.ONE;\n } else if(count === 2) {\n barHeight = BAR_HEIGHTS.TWO;\n } else if(count === 3) {\n barHeight = BAR_HEIGHTS.THREE;\n } else if(count === 4) {\n barHeight = BAR_HEIGHTS.FOUR;\n } else if(count > 3) {\n barHeight = BAR_HEIGHTS.MORE;\n }\n\n return barHeight;\n };\n\n private getMarkHeight = (count: number, index: number) => {\n let markHeight: number;\n if(count <= 1) {\n markHeight = BAR_HEIGHTS.ONE;\n } else if(count === 2) {\n markHeight = BAR_HEIGHTS.TWO;\n } else if(count === 3) {\n markHeight = BAR_HEIGHTS.THREE;\n } else if(count === 4) {\n markHeight = BAR_HEIGHTS.FOUR;\n } else if(count > 3) {\n markHeight = BAR_HEIGHTS.MORE;\n }\n\n return markHeight;\n };\n\n private getMarkTranslateY = (index: number, barHeight: number, count: number) => {\n if(count === 1) {\n return 0;\n } else if(count === 2) {\n return !index ? 0 : barHeight + GAP;\n }\n\n if(count === 3) {\n if(!index) {\n return 0;\n } else if(index === 1) {\n return barHeight + GAP;\n }\n\n return barHeight * 2 + GAP * 2 + 1;\n } else {\n return (barHeight + GAP) * index;\n }\n };\n\n private getTrackTranslateY = (index: number, count: number, barHeight: number, trackHeight: number) => {\n if(count <= 4) {\n return 0;\n }\n\n if(index <= 1) {\n return 0;\n } else if(index >= (count - 2)) {\n return trackHeight - BAR_HEIGHTS.ONE - barHeight;\n }\n\n // return (index + 1) * barHeight + index * GAP;\n return (index - 2) * barHeight + index * GAP;\n //return (barHeight + GAP * 2) / 2 + (index - 2) * (barHeight + GAP);\n };\n\n private getTrackHeight = (count: number, barHeight: number) => {\n return count <= 3 ? BAR_HEIGHTS.ONE : barHeight * count + GAP * (count - 1);\n };\n\n public render(count: number, index: number) {\n if(!this.border) {\n this.border = document.createElement('div');\n this.border.classList.add(BASE_CLASS);\n\n this.wrapper = document.createElement('div');\n this.border.append(this.wrapper);\n }\n \n if(count === 1) {\n if(this.count !== count) {\n this.wrapper.className = BASE_CLASS + '-wrapper-1';\n this.border.classList.remove(BASE_CLASS + '-mask');\n this.wrapper.innerHTML = this.wrapper.style.cssText = '';\n }\n\n return this.border;\n }\n\n const barHeight = this.getBarHeight(count, index);\n const markHeight = this.getMarkHeight(count, index);\n const trackHeight = this.getTrackHeight(count, barHeight);\n\n const clipPathId = `clipPath_${count}`;\n const clipPath = this.getClipPath(clipPathId, barHeight, count);\n\n const markTranslateY = this.getMarkTranslateY(index, barHeight, count);\n const trackTranslateY = this.getTrackTranslateY(index, count, barHeight, trackHeight);\n\n this.border.classList.toggle(BASE_CLASS + '-mask', count > 4);\n\n if(index <= 1) {\n this.border.classList.add('mask-bottom');\n this.border.classList.remove('mask-top');\n } else if(index >= (count - 2)) {\n this.border.classList.add('mask-top');\n this.border.classList.remove('mask-bottom');\n } else {\n this.border.classList.add('mask-top', 'mask-bottom');\n }\n\n this.wrapper.className = BASE_CLASS + '-wrapper';\n this.wrapper.style.cssText = `clip-path: url(#${clipPathId}); width: 2px; height: ${trackHeight}px; transform: translateY(-${trackTranslateY}px);`;\n \n if(!this.svg) {\n this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n this.svg.setAttributeNS(null, 'height', '0');\n this.svg.setAttributeNS(null, 'width', '0');\n \n this.defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');\n this.defs.append(clipPath);\n\n this.svg.append(this.defs);\n\n this.mark = document.createElement('div');\n this.mark.classList.add(BASE_CLASS + '-mark');\n }\n\n if(!this.svg.parentElement) {\n this.wrapper.append(this.svg, this.mark);\n }\n\n this.mark.style.cssText = `height: ${markHeight}px; transform: translateY(${markTranslateY}px);`;\n \n this.count = count;\n this.index = index;\n\n return this.border;\n }\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\r\nimport type ChatTopbar from \"./topbar\";\r\nimport PopupPinMessage from \"../popups/unpinMessage\";\r\nimport PinnedContainer from \"./pinnedContainer\";\r\nimport PinnedMessageBorder from \"./pinnedMessageBorder\";\r\nimport ReplyContainer, { wrapReplyDivAndCaption } from \"./replyContainer\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport Chat from \"./chat\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport ButtonIcon from \"../buttonIcon\";\r\nimport { getHeavyAnimationPromise } from \"../../hooks/useHeavyAnimationCheck\";\r\nimport { i18n } from \"../../lib/langPack\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport handleScrollSideEvent from \"../../helpers/dom/handleScrollSideEvent\";\r\nimport debounce from \"../../helpers/schedulers/debounce\";\r\n\r\nclass AnimatedSuper {\r\n static DURATION = 200;\r\n static BASE_CLASS = 'animated-super';\r\n container: HTMLDivElement;\r\n rows: {[index: string]: {element: HTMLElement, timeout?: number, new?: true}} = {};\r\n clearTimeout: number;\r\n\r\n constructor() {\r\n this.container = document.createElement('div');\r\n this.container.className = AnimatedSuper.BASE_CLASS;\r\n }\r\n\r\n public getRow(index: number, animateFirst = false) {\r\n if(this.rows[index]) return this.rows[index].element;\r\n const row = document.createElement('div');\r\n const isFirst = !Object.keys(this.rows).length && !animateFirst;\r\n row.className = AnimatedSuper.BASE_CLASS + '-row' + (isFirst ? '' : ' is-hiding hide');\r\n this.rows[index] = {element: row, new: true};\r\n this.container.append(row);\r\n return row;\r\n }\r\n\r\n public clearRow(index: number) {\r\n if(!this.rows[index]) return;\r\n this.rows[index].element.remove();\r\n delete this.rows[index];\r\n }\r\n\r\n public clearRows(currentIndex?: number) {\r\n if(this.clearTimeout) clearTimeout(this.clearTimeout);\r\n this.clearTimeout = window.setTimeout(() => {\r\n for(const i in this.rows) {\r\n if(+i === currentIndex) continue;\r\n this.clearRow(+i);\r\n }\r\n }, AnimatedSuper.DURATION);\r\n }\r\n\r\n public setNewRow(index: number, reflow = false) {\r\n const row = this.rows[index];\r\n if(row.new) {\r\n if(reflow) {\r\n row.element.classList.remove('hide');\r\n void row.element.offsetLeft; // reflow\r\n } else {\r\n row.element.classList.remove('is-hiding', 'hide');\r\n }\r\n\r\n delete row.new;\r\n }\r\n\r\n this.clearRows(index);\r\n }\r\n\r\n public animate(index: number, previousIndex: number, fromTop = index > previousIndex, ignorePrevious = false) {\r\n if(index === previousIndex) { // * handle if set index 0 and previousIndex 0\r\n return this.setNewRow(index);\r\n }\r\n\r\n const row = this.rows[index];\r\n const previousRow = this.rows[previousIndex];\r\n if(!previousRow && !ignorePrevious) {\r\n return this.setNewRow(index);\r\n }\r\n\r\n const sides = ['from-top', 'from-bottom'];\r\n if(!fromTop) sides.reverse();\r\n\r\n row.element.classList.add(sides[0]);\r\n row.element.classList.remove(sides[1]);\r\n if(previousRow) {\r\n previousRow.element.classList.add(sides[1]);\r\n previousRow.element.classList.remove(sides[0]);\r\n }\r\n\r\n if(row.new) {\r\n this.setNewRow(index, true);\r\n }\r\n\r\n row.element.classList.toggle('is-hiding', false);\r\n previousRow && previousRow.element.classList.toggle('is-hiding', true);\r\n\r\n /* const height = row.element.getBoundingClientRect().height;\r\n row.element.style.transform = `translateY(${fromTop ? height * -1 : height}px)`;\r\n if(previousRow) {\r\n previousRow.element.style.transform = `translateY(${fromTop ? height : height * -1}px)`;\r\n } */\r\n\r\n /* row.element.style.setProperty('--height', row.element.getBoundingClientRect().height + 'px');\r\n if(previousRow) {\r\n previousRow.element.style.setProperty('--height', previousRow.element.getBoundingClientRect().height + 'px');\r\n } */\r\n \r\n this.clearRows(index);\r\n }\r\n}\r\n\r\nclass AnimatedCounter {\r\n static EMPTY_INDEX = -1;\r\n static BASE_CLASS = 'animated-counter';\r\n container: HTMLElement;\r\n decimals: {\r\n container: HTMLElement,\r\n placeholder: HTMLElement,\r\n animatedSuper: AnimatedSuper\r\n }[] = [];\r\n previousNumber = 0;\r\n clearTimeout: number;\r\n\r\n constructor(private reverse = false) {\r\n this.container = document.createElement('div');\r\n this.container.className = AnimatedCounter.BASE_CLASS;\r\n }\r\n\r\n getDecimal(index: number) {\r\n if(this.decimals[index]) return this.decimals[index];\r\n const item = document.createElement('div');\r\n item.className = AnimatedCounter.BASE_CLASS + '-decimal';\r\n\r\n const placeholder = document.createElement('div');\r\n placeholder.className = AnimatedCounter.BASE_CLASS + '-decimal-placeholder';\r\n\r\n const animatedSuper = new AnimatedSuper();\r\n animatedSuper.container.className = AnimatedCounter.BASE_CLASS + '-decimal-wrapper';\r\n\r\n item.append(placeholder, animatedSuper.container);\r\n\r\n this.container.append(item);\r\n\r\n return this.decimals[index] = {container: item, placeholder, animatedSuper};\r\n }\r\n\r\n clear(number: number) {\r\n if(this.clearTimeout) clearTimeout(this.clearTimeout);\r\n\r\n const decimals = ('' + number).length;\r\n if(decimals >= this.decimals.length) {\r\n return;\r\n }\r\n\r\n this.clearTimeout = window.setTimeout(() => {\r\n const byDecimal = this.decimals.splice(decimals, this.decimals.length - decimals);\r\n byDecimal.forEach((decimal) => {\r\n decimal.container.remove();\r\n });\r\n }, AnimatedSuper.DURATION);\r\n }\r\n\r\n /* prepareNumber(number: number) {\r\n const decimals = ('' + number).length;\r\n if(this.decimals.length < decimals) {\r\n for(let i = this.decimals.length; i < decimals; ++i) {\r\n this.getDecimal(i);\r\n }\r\n }\r\n } */\r\n\r\n hideLeft(number: number) {\r\n const decimals = ('' + number).length;\r\n const byDecimal = this.decimals.slice(decimals);//this.decimals.splice(deleteCount, this.decimals.length - deleteCount);\r\n byDecimal.forEach((decimal) => {\r\n const previousDecimalNumber = +decimal.placeholder.innerText || 0;\r\n const row = decimal.animatedSuper.getRow(AnimatedCounter.EMPTY_INDEX, true);\r\n decimal.animatedSuper.animate(AnimatedCounter.EMPTY_INDEX, previousDecimalNumber, this.reverse ? number < this.previousNumber : number > this.previousNumber, true);\r\n });\r\n\r\n this.clear(number);\r\n }\r\n\r\n setCount(number: number) {\r\n //this.prepareNumber(number);\r\n\r\n const previousByDecimal = Array.from('' + this.previousNumber).map(n => +n);\r\n const byDecimal = Array.from('' + number).map(n => +n);\r\n byDecimal.forEach((decimalNumber, idx) => {\r\n const decimal = this.getDecimal(idx);\r\n //const row = decimal.animatedSuper.getRow(number, true);\r\n const row = decimal.animatedSuper.getRow(decimalNumber, true);\r\n const previousDecimalNumber = previousByDecimal[idx] ?? AnimatedCounter.EMPTY_INDEX;\r\n row.innerText = decimal.placeholder.innerText = '' + decimalNumber;\r\n //decimal.animatedSuper.animate(number, this.previousNumber, this.reverse ? number < this.previousNumber : number > this.previousNumber, true);\r\n decimal.animatedSuper.animate(decimalNumber, previousDecimalNumber, this.reverse ? number < this.previousNumber : number > this.previousNumber, true);\r\n });\r\n\r\n this.hideLeft(number);\r\n //this.clear(number);\r\n this.previousNumber = number;\r\n }\r\n}\r\n\r\nexport default class ChatPinnedMessage {\r\n public static LOAD_COUNT = 50;\r\n public static LOAD_OFFSET = 5;\r\n\r\n public pinnedMessageContainer: PinnedContainer;\r\n public pinnedMessageBorder: PinnedMessageBorder;\r\n\r\n public pinnedMaxMid = 0;\r\n public pinnedMid = 0;\r\n public pinnedIndex = -1;\r\n public wasPinnedIndex = 0;\r\n public wasPinnedMediaIndex = 0;\r\n \r\n public locked = false;\r\n public waitForScrollBottom = false;\r\n\r\n public count = 0;\r\n public mids: number[] = [];\r\n public offsetIndex = 0;\r\n\r\n public loading = false;\r\n public loadedBottom = false;\r\n public loadedTop = false;\r\n\r\n public animatedSubtitle: AnimatedSuper;\r\n public animatedMedia: AnimatedSuper;\r\n public animatedCounter: AnimatedCounter;\r\n\r\n public listenerSetter: ListenerSetter;\r\n public scrollDownListenerSetter: ListenerSetter = null;\r\n\r\n public hidden = false;\r\n\r\n public getCurrentIndexPromise: Promise<any> = null;\r\n public btnOpen: HTMLButtonElement;\r\n \r\n public setPinnedMessage: () => void;\r\n\r\n private isStatic = false;\r\n\r\n private debug = false;\r\n \r\n constructor(private topbar: ChatTopbar, private chat: Chat, private appMessagesManager: AppMessagesManager, private appPeersManager: AppPeersManager) {\r\n this.listenerSetter = new ListenerSetter();\r\n\r\n const dAC = new ReplyContainer('pinned-message');\r\n this.pinnedMessageContainer = new PinnedContainer({\r\n topbar, \r\n chat, \r\n listenerSetter: this.listenerSetter, \r\n className: 'message', \r\n divAndCaption: dAC, \r\n onClose: async() => {\r\n if(appPeersManager.canPinMessage(this.topbar.peerId)) {\r\n new PopupPinMessage(this.topbar.peerId, this.pinnedMid, true);\r\n } else {\r\n new PopupPinMessage(this.topbar.peerId, 0, true);\r\n }\r\n\r\n return false;\r\n }\r\n });\r\n\r\n this.pinnedMessageBorder = new PinnedMessageBorder();\r\n dAC.border.replaceWith(this.pinnedMessageBorder.render(1, 0));\r\n\r\n this.animatedSubtitle = new AnimatedSuper();\r\n dAC.subtitle.append(this.animatedSubtitle.container);\r\n\r\n this.animatedMedia = new AnimatedSuper();\r\n this.animatedMedia.container.classList.add('pinned-message-media-container');\r\n dAC.content.prepend(this.animatedMedia.container);\r\n\r\n this.animatedCounter = new AnimatedCounter(true);\r\n dAC.title.append(i18n('PinnedMessage'), ' ', this.animatedCounter.container);\r\n\r\n const btnClose = this.pinnedMessageContainer.btnClose.cloneNode(true) as HTMLElement;\r\n this.pinnedMessageContainer.attachOnCloseEvent(btnClose);\r\n dAC.container.prepend(btnClose);\r\n\r\n this.btnOpen = ButtonIcon('pinlist pinned-container-close pinned-message-pinlist', {noRipple: true});\r\n\r\n this.pinnedMessageContainer.wrapperUtils.prepend(this.btnOpen);\r\n\r\n attachClickEvent(this.btnOpen, (e) => {\r\n cancelEvent(e);\r\n this.topbar.openPinned(true);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.listenerSetter.add(rootScope)('peer_pinned_messages', ({peerId}) => {\r\n if(peerId === this.topbar.peerId) {\r\n //this.wasPinnedIndex = 0;\r\n //setTimeout(() => {\r\n if(this.hidden) {\r\n this.pinnedMessageContainer.toggle(this.hidden = false);\r\n }\r\n\r\n this.loadedTop = this.loadedBottom = false;\r\n this.pinnedIndex = -1;\r\n this.pinnedMid = 0;\r\n this.count = 0;\r\n this.mids = [];\r\n this.offsetIndex = 0;\r\n this.pinnedMaxMid = 0;\r\n this.setCorrectIndex(0);\r\n //}, 300);\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('peer_pinned_hidden', ({peerId}) => {\r\n if(peerId === this.topbar.peerId) {\r\n this.pinnedMessageContainer.toggle(this.hidden = true);\r\n }\r\n });\r\n\r\n // * 200 - no lags\r\n // * 100 - need test\r\n this.setPinnedMessage = debounce(() => this._setPinnedMessage(), 100, true, true);\r\n\r\n this.isStatic = this.chat.type === 'discussion';\r\n }\r\n\r\n public destroy() {\r\n this.pinnedMessageContainer.divAndCaption.container.remove();\r\n this.pinnedMessageContainer.toggle(true);\r\n this.listenerSetter.removeAll();\r\n this.unsetScrollDownListener(false);\r\n }\r\n\r\n public setCorrectIndex(lastScrollDirection?: number) {\r\n if(this.isStatic) return;\r\n //return;\r\n\r\n if(this.locked || this.hidden/* || this.chat.setPeerPromise || this.chat.bubbles.messagesQueuePromise */) {\r\n return;\r\n }\r\n\r\n if((this.loadedBottom || this.loadedTop) && !this.count) {\r\n return;\r\n }\r\n\r\n //const perf = performance.now();\r\n let el = this.chat.bubbles.getBubbleByPoint('bottom');\r\n //this.chat.log('[PM]: setCorrectIndex: get last element perf:', performance.now() - perf, el);\r\n if(!el) return;\r\n\r\n //return;\r\n\r\n const mid = el.dataset.mid;\r\n if(el && mid !== undefined) {\r\n //this.chat.log('[PM]: setCorrectIndex will test mid:', mid);\r\n this.testMid(+mid, lastScrollDirection);\r\n }\r\n }\r\n\r\n public testMid(mid: number, lastScrollDirection?: number) {\r\n if(this.isStatic) return;\r\n \r\n //if(lastScrollDirection !== undefined) return;\r\n if(this.hidden) return;\r\n\r\n //this.chat.log('[PM]: testMid', mid);\r\n\r\n let currentIndex: number = this.mids.findIndex(_mid => _mid <= mid);\r\n if(currentIndex !== -1 && !this.isNeededMore(currentIndex)) {\r\n currentIndex += this.offsetIndex;\r\n } else if(this.loadedTop && mid < this.mids[this.mids.length - 1]) {\r\n //currentIndex = 0;\r\n currentIndex = this.mids.length - 1 + this.offsetIndex;\r\n } else {\r\n if(!this.getCurrentIndexPromise) {\r\n this.getCurrentIndexPromise = this.getCurrentIndex(mid, lastScrollDirection !== undefined);\r\n }\r\n\r\n return;\r\n }\r\n\r\n //const idx = Math.max(0, this.mids.indexOf(mid));\r\n\r\n /* if(currentIndex === this.count) {\r\n currentIndex = 0;\r\n } */\r\n\r\n //this.chat.log('[PM]: testMid: pinned currentIndex', currentIndex, mid);\r\n\r\n const changed = this.pinnedIndex !== currentIndex;\r\n if(changed) {\r\n if(this.waitForScrollBottom && lastScrollDirection !== undefined) {\r\n if(this.pinnedIndex === 0 || this.pinnedIndex > currentIndex) { // если не скроллил вниз и пытается поставить нижний пиннед - выйти\r\n return;\r\n }\r\n }\r\n\r\n this.pinnedIndex = currentIndex;\r\n this.pinnedMid = this.mids.find(_mid => _mid <= mid) || this.mids[this.mids.length - 1];\r\n this.setPinnedMessage();\r\n }\r\n }\r\n\r\n private isNeededMore(currentIndex: number) {\r\n return (this.count > ChatPinnedMessage.LOAD_COUNT && \r\n (\r\n (!this.loadedBottom && currentIndex <= ChatPinnedMessage.LOAD_OFFSET) || \r\n (!this.loadedTop && (this.count - 1 - currentIndex) <= ChatPinnedMessage.LOAD_OFFSET)\r\n )\r\n );\r\n }\r\n\r\n private async getCurrentIndex(mid: number, correctAfter = true) {\r\n if(this.loading) return;\r\n this.loading = true;\r\n\r\n try {\r\n let gotRest = false;\r\n const promises = [\r\n this.appMessagesManager.getSearch({\r\n peerId: this.topbar.peerId, \r\n inputFilter: {_: 'inputMessagesFilterPinned'}, \r\n maxId: mid, \r\n limit: ChatPinnedMessage.LOAD_COUNT, \r\n backLimit: ChatPinnedMessage.LOAD_COUNT\r\n })\r\n .then(r => {\r\n gotRest = true;\r\n return r;\r\n })\r\n ];\r\n \r\n if(!this.pinnedMaxMid) {\r\n const promise = this.appMessagesManager.getPinnedMessage(this.topbar.peerId).then(p => {\r\n if(!p.maxId) return;\r\n this.pinnedMaxMid = p.maxId;\r\n\r\n if(!gotRest && correctAfter) {\r\n this.mids = [this.pinnedMaxMid];\r\n this.count = p.count;\r\n this.pinnedIndex = 0;\r\n this.pinnedMid = this.mids[0];\r\n this.setPinnedMessage();\r\n //this.pinnedMessageContainer.toggle(false);\r\n }\r\n });\r\n \r\n promises.push(promise as any);\r\n }\r\n \r\n const result = (await Promise.all(promises))[0];\r\n \r\n let backLimited = result.history.findIndex(message => message.mid <= mid);\r\n if(backLimited === -1) {\r\n backLimited = result.history.length;\r\n }/* else {\r\n backLimited -= 1;\r\n } */\r\n \r\n this.offsetIndex = result.offset_id_offset ? result.offset_id_offset - backLimited : 0;\r\n this.mids = result.history.map(message => message.mid).slice();\r\n this.count = result.count;\r\n\r\n if(!this.count) {\r\n this.pinnedMessageContainer.toggle(true);\r\n }\r\n \r\n this.loadedTop = (this.offsetIndex + this.mids.length) === this.count;\r\n this.loadedBottom = !this.offsetIndex;\r\n \r\n this.debug && this.chat.log('[PM]: getCurrentIndex result:', mid, result, backLimited, this.offsetIndex, this.loadedTop, this.loadedBottom);\r\n } catch(err) {\r\n this.chat.log.error('[PM]: getCurrentIndex error', err);\r\n }\r\n \r\n this.loading = false;\r\n\r\n if(this.locked) {\r\n this.testMid(mid);\r\n } else if(correctAfter) {\r\n this.setCorrectIndex(0);\r\n }\r\n\r\n this.getCurrentIndexPromise = null;\r\n //return result.offset_id_offset || 0;\r\n }\r\n\r\n public setScrollDownListener() {\r\n this.waitForScrollBottom = true;\r\n\r\n if(!this.scrollDownListenerSetter) {\r\n this.scrollDownListenerSetter = new ListenerSetter();\r\n handleScrollSideEvent(this.chat.bubbles.scrollable.container, 'bottom', () => {\r\n this.unsetScrollDownListener();\r\n }, this.scrollDownListenerSetter);\r\n }\r\n }\r\n\r\n public unsetScrollDownListener(refreshPosition = true) {\r\n this.waitForScrollBottom = false;\r\n\r\n if(this.scrollDownListenerSetter) {\r\n this.scrollDownListenerSetter.removeAll();\r\n this.scrollDownListenerSetter = null;\r\n }\r\n\r\n if(refreshPosition) {\r\n this.setCorrectIndex(0);\r\n }\r\n }\r\n\r\n public async handleFollowingPinnedMessage() {\r\n this.locked = true;\r\n\r\n this.debug && this.chat.log('[PM]: handleFollowingPinnedMessage');\r\n try {\r\n this.setScrollDownListener();\r\n\r\n const setPeerPromise = this.chat.setPeerPromise;\r\n if(setPeerPromise instanceof Promise) {\r\n await setPeerPromise;\r\n }\r\n \r\n //await this.chat.bubbles.scrollable.scrollLockedPromise;\r\n await getHeavyAnimationPromise();\r\n\r\n if(this.getCurrentIndexPromise) {\r\n await this.getCurrentIndexPromise;\r\n }\r\n\r\n this.debug && this.chat.log('[PM]: handleFollowingPinnedMessage: unlock');\r\n this.locked = false;\r\n\r\n /* // подождём, пока скролл остановится\r\n setTimeout(() => {\r\n this.chat.log('[PM]: handleFollowingPinnedMessage: unlock');\r\n this.locked = false;\r\n }, 50); */\r\n } catch(err) {\r\n this.chat.log.error('[PM]: handleFollowingPinnedMessage error:', err);\r\n\r\n this.locked = false;\r\n this.waitForScrollBottom = false;\r\n this.setCorrectIndex(0);\r\n }\r\n }\r\n\r\n public async followPinnedMessage(mid: number) {\r\n const message = this.chat.getMessage(mid);\r\n if(message && !message.deleted) {\r\n this.chat.setMessageId(mid);\r\n (this.chat.setPeerPromise || Promise.resolve()).then(() => { // * debounce fast clicker\r\n this.handleFollowingPinnedMessage();\r\n this.testMid(this.pinnedIndex >= (this.count - 1) ? this.pinnedMaxMid : mid - 1);\r\n });\r\n }\r\n }\r\n\r\n public async _setPinnedMessage() {\r\n /////this.log('setting pinned message', message);\r\n //return;\r\n /* const promise: Promise<any> = this.chat.setPeerPromise || this.chat.bubbles.messagesQueuePromise || Promise.resolve();\r\n Promise.all([\r\n promise\r\n ]).then(() => { */\r\n //const mids = results[0];\r\n const count = this.count;\r\n if(count) {\r\n const pinnedIndex = this.pinnedIndex;\r\n const message = this.chat.getMessage(this.pinnedMid);\r\n\r\n //this.animatedCounter.prepareNumber(count);\r\n\r\n //setTimeout(() => {\r\n const isLast = pinnedIndex === 0;\r\n this.animatedCounter.container.classList.toggle('is-last', isLast);\r\n //SetTransition(this.animatedCounter.container, 'is-last', isLast, AnimatedSuper.DURATION);\r\n if(!isLast) {\r\n this.animatedCounter.setCount(count - pinnedIndex);\r\n }\r\n //}, 100);\r\n\r\n //this.pinnedMessageContainer.fill(undefined, message.message, message);\r\n this.pinnedMessageContainer.toggle(false);\r\n\r\n const fromTop = pinnedIndex > this.wasPinnedIndex;\r\n\r\n this.debug && this.chat.log('[PM]: setPinnedMessage: fromTop', fromTop, pinnedIndex, this.wasPinnedIndex);\r\n\r\n const writeTo = this.animatedSubtitle.getRow(pinnedIndex);\r\n const writeMediaTo = this.animatedMedia.getRow(pinnedIndex);\r\n writeMediaTo.classList.add('pinned-message-media');\r\n //writeMediaTo.innerHTML = writeMediaTo.style.cssText = writeMediaTo.dataset.docId = '';\r\n const loadPromises: Promise<any>[] = [];\r\n const isMediaSet = wrapReplyDivAndCaption({\r\n title: undefined,\r\n titleEl: null,\r\n subtitle: message.message,\r\n subtitleEl: writeTo,\r\n message,\r\n mediaEl: writeMediaTo,\r\n loadPromises\r\n });\r\n\r\n await Promise.all(loadPromises);\r\n\r\n this.pinnedMessageContainer.divAndCaption.container.classList.toggle('is-media', isMediaSet);\r\n\r\n //if(this.wasPinnedIndex !== this.pinnedIndex) {\r\n this.animatedSubtitle.animate(pinnedIndex, this.wasPinnedIndex);\r\n if(isMediaSet) {\r\n this.animatedMedia.animate(pinnedIndex, this.wasPinnedMediaIndex); // * wasPinnedMediaIndex из-за того, что блок меняется с другим алгоритмом\r\n this.wasPinnedMediaIndex = pinnedIndex;\r\n } else {\r\n this.animatedMedia.clearRows();\r\n }\r\n //}\r\n\r\n this.pinnedMessageBorder.render(count, count - pinnedIndex - 1);\r\n this.wasPinnedIndex = pinnedIndex;\r\n this.pinnedMessageContainer.divAndCaption.container.dataset.mid = '' + message.mid;\r\n } else {\r\n this.pinnedMessageContainer.toggle(true);\r\n this.wasPinnedIndex = 0;\r\n }\r\n\r\n this.pinnedMessageContainer.divAndCaption.container.classList.toggle('is-many', this.count > 1);\r\n //});\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type ListenerSetter from \"../listenerSetter\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\n\r\nexport default function handleScrollSideEvent(elem: HTMLElement, side: 'top' | 'bottom', callback: () => void, listenerSetter: ListenerSetter) {\r\n if(IS_TOUCH_SUPPORTED) {\r\n let lastY: number;\r\n const options = {passive: true};\r\n listenerSetter.add(elem)('touchstart', (e) => {\r\n if(e.touches.length > 1) {\r\n onTouchEnd();\r\n return;\r\n }\r\n\r\n lastY = e.touches[0].clientY;\r\n\r\n listenerSetter.add(elem)('touchmove', onTouchMove, options);\r\n listenerSetter.add(elem)('touchend', onTouchEnd, options);\r\n }, options);\r\n\r\n const onTouchMove = (e: TouchEvent) => {\r\n const clientY = e.touches[0].clientY;\r\n\r\n const isDown = clientY < lastY;\r\n if(side === 'bottom' && isDown) callback();\r\n else if(side === 'top' && !isDown) callback();\r\n lastY = clientY;\r\n //alert('isDown: ' + !!isDown);\r\n };\r\n \r\n const onTouchEnd = () => {\r\n listenerSetter.removeManual(elem, 'touchmove', onTouchMove, options);\r\n listenerSetter.removeManual(elem, 'touchend', onTouchEnd, options);\r\n };\r\n } else {\r\n listenerSetter.add(elem)('wheel', (e) => {\r\n const isDown = e.deltaY > 0;\r\n //this.log('wheel', e, isDown);\r\n if(side === 'bottom' && isDown) callback();\r\n else if(side === 'top' && !isDown) callback();\r\n }, {passive: true});\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { AppNotificationsManager } from \"../../lib/appManagers/appNotificationsManager\";\nimport type { AppChatsManager, Channel } from \"../../lib/appManagers/appChatsManager\";\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\nimport type { AppSidebarRight } from \"../sidebarRight\";\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\nimport type Chat from \"./chat\";\nimport { RIGHT_COLUMN_ACTIVE_CLASSNAME } from \"../sidebarRight\";\nimport mediaSizes, { ScreenSize } from \"../../helpers/mediaSizes\";\nimport { IS_SAFARI } from \"../../environment/userAgent\";\nimport rootScope from \"../../lib/rootScope\";\nimport AvatarElement from \"../avatar\";\nimport Button from \"../button\";\nimport ButtonIcon from \"../buttonIcon\";\nimport ButtonMenuToggle from \"../buttonMenuToggle\";\nimport ChatAudio from \"./audio\";\nimport ChatPinnedMessage from \"./pinnedMessage\";\nimport { ButtonMenuItemOptions } from \"../buttonMenu\";\nimport ListenerSetter from \"../../helpers/listenerSetter\";\nimport appStateManager from \"../../lib/appManagers/appStateManager\";\nimport PopupDeleteDialog from \"../popups/deleteDialog\";\nimport appNavigationController from \"../appNavigationController\";\nimport { LEFT_COLUMN_ACTIVE_CLASSNAME } from \"../sidebarLeft\";\nimport PeerTitle from \"../peerTitle\";\nimport { i18n } from \"../../lib/langPack\";\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\nimport blurActiveElement from \"../../helpers/dom/blurActiveElement\";\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport findUpTag from \"../../helpers/dom/findUpTag\";\nimport { toast, toastNew } from \"../toast\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport { ChatFull } from \"../../layer\";\nimport PopupPickUser from \"../popups/pickUser\";\nimport PopupPeer from \"../popups/peer\";\nimport generateVerifiedIcon from \"../generateVerifiedIcon\";\nimport { fastRaf } from \"../../helpers/schedulers\";\nimport AppEditContactTab from \"../sidebarRight/tabs/editContact\";\nimport appMediaPlaybackController from \"../appMediaPlaybackController\";\n\nexport default class ChatTopbar {\n public container: HTMLDivElement;\n private btnBack: HTMLButtonElement;\n private chatInfo: HTMLDivElement;\n private avatarElement: AvatarElement;\n private title: HTMLDivElement;\n private subtitle: HTMLDivElement;\n private chatUtils: HTMLDivElement;\n private btnJoin: HTMLButtonElement;\n private btnPinned: HTMLButtonElement;\n private btnMute: HTMLButtonElement;\n private btnSearch: HTMLButtonElement;\n private btnMore: HTMLButtonElement;\n \n private chatAudio: ChatAudio;\n public pinnedMessage: ChatPinnedMessage;\n\n private setUtilsRAF: number;\n public peerId: number;\n private wasPeerId: number;\n private setPeerStatusInterval: number;\n\n public listenerSetter: ListenerSetter;\n\n private menuButtons: (ButtonMenuItemOptions & {verify: () => boolean})[] = [];\n\n constructor(private chat: Chat, \n private appSidebarRight: AppSidebarRight, \n private appMessagesManager: AppMessagesManager, \n private appPeersManager: AppPeersManager, \n private appChatsManager: AppChatsManager, \n private appNotificationsManager: AppNotificationsManager,\n private appProfileManager: AppProfileManager,\n private appUsersManager: AppUsersManager\n ) {\n this.listenerSetter = new ListenerSetter();\n }\n\n public construct() {\n //this.chat.log.error('Topbar construction');\n\n this.container = document.createElement('div');\n this.container.classList.add('sidebar-header', 'topbar');\n this.container.dataset.floating = '0';\n\n this.btnBack = ButtonIcon('left sidebar-close-button', {noRipple: true});\n\n // * chat info section\n this.chatInfo = document.createElement('div');\n this.chatInfo.classList.add('chat-info');\n\n const person = document.createElement('div');\n person.classList.add('person');\n\n const content = document.createElement('div');\n content.classList.add('content');\n\n const top = document.createElement('div');\n top.classList.add('top');\n\n this.title = document.createElement('div');\n this.title.classList.add('user-title');\n\n top.append(this.title);\n\n const bottom = document.createElement('div');\n bottom.classList.add('bottom');\n\n if(this.subtitle) {\n bottom.append(this.subtitle);\n }\n\n content.append(top, bottom);\n if(this.avatarElement) {\n person.append(this.avatarElement);\n }\n\n person.append(content);\n this.chatInfo.append(person);\n\n // * chat utils section\n this.chatUtils = document.createElement('div');\n this.chatUtils.classList.add('chat-utils');\n\n this.chatAudio = new ChatAudio(this, this.chat, this.appMessagesManager);\n\n if(this.menuButtons.length) {\n this.btnMore = ButtonMenuToggle({listenerSetter: this.listenerSetter}, 'bottom-left', this.menuButtons, (e) => {\n cancelEvent(e);\n this.menuButtons.forEach(button => {\n button.element.classList.toggle('hide', !button.verify());\n });\n\n // delete button\n this.menuButtons[this.menuButtons.length - 1].element.lastChild.replaceWith(i18n(this.appPeersManager.getDeleteButtonText(this.peerId)));\n });\n }\n\n this.chatUtils.append(...[\n // this.chatAudio ? this.chatAudio.divAndCaption.container : null, \n this.pinnedMessage ? this.pinnedMessage.pinnedMessageContainer.divAndCaption.container : null, \n this.btnJoin, \n this.btnPinned, \n this.btnMute, \n this.btnSearch, \n this.btnMore\n ].filter(Boolean));\n\n this.container.append(this.btnBack, this.chatInfo, this.chatUtils);\n\n if(this.chatAudio) {\n this.container.append(this.chatAudio.divAndCaption.container, this.chatUtils);\n }\n\n // * construction end\n\n // * fix topbar overflow section\n\n this.listenerSetter.add(window)('resize', this.onResize);\n this.listenerSetter.add(mediaSizes)('changeScreen', this.onChangeScreen);\n\n attachClickEvent(this.container, (e) => {\n const container: HTMLElement = findUpClassName(e.target, 'pinned-container');\n blurActiveElement();\n if(container) {\n cancelEvent(e);\n\n if(findUpClassName(e.target, 'progress-line')) {\n return;\n }\n \n const mid = +container.dataset.mid;\n const peerId = +container.dataset.peerId;\n if(container.classList.contains('pinned-message')) {\n //if(!this.pinnedMessage.locked) {\n this.pinnedMessage.followPinnedMessage(mid);\n //}\n } else {\n const searchContext = appMediaPlaybackController.getSearchContext();\n this.chat.appImManager.setInnerPeer(\n peerId, \n mid, \n searchContext.isScheduled ? 'scheduled' : (searchContext.threadId ? 'discussion' : undefined), \n searchContext.threadId\n );\n }\n } else {\n if(mediaSizes.activeScreen === ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {\n onBtnBackClick();\n } else if(findUpTag(e.target, 'AVATAR-ELEMENT')) {\n this.appSidebarRight.toggleSidebar(!document.body.classList.contains(RIGHT_COLUMN_ACTIVE_CLASSNAME));\n } else {\n this.appSidebarRight.toggleSidebar(true);\n }\n }\n }, {listenerSetter: this.listenerSetter});\n\n const onBtnBackClick = (e?: Event) => {\n if(e) {\n cancelEvent(e);\n }\n\n //const item = appNavigationController.findItemByType('chat');\n // * return manually to chat by arrow, since can't get back to\n if(mediaSizes.activeScreen === ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {\n this.chat.appImManager.setPeer(this.peerId);\n } else {\n const isFirstChat = this.chat.appImManager.chats.indexOf(this.chat) === 0;\n appNavigationController.back(isFirstChat ? 'im' : 'chat');\n return;\n\n if(mediaSizes.activeScreen === ScreenSize.medium && !appNavigationController.findItemByType('chat')) {\n this.chat.appImManager.setPeer(0);\n blurActiveElement();\n } else {\n appNavigationController.back('chat');\n }\n }\n };\n\n attachClickEvent(this.btnBack, onBtnBackClick, {listenerSetter: this.listenerSetter});\n }\n\n public constructUtils() {\n this.menuButtons = [{\n icon: 'search',\n text: 'Search',\n onClick: () => {\n this.chat.initSearch()\n },\n verify: () => mediaSizes.isMobile\n }, /* {\n icon: 'pinlist',\n text: 'Pinned Messages',\n onClick: () => this.openPinned(false),\n verify: () => mediaSizes.isMobile\n }, */{\n icon: 'mute',\n text: 'ChatList.Context.Mute',\n onClick: () => {\n this.appMessagesManager.mutePeer(this.peerId);\n },\n verify: () => this.chat.type === 'chat' && rootScope.myId !== this.peerId && !this.appNotificationsManager.isPeerLocalMuted(this.peerId, false)\n }, {\n icon: 'unmute',\n text: 'ChatList.Context.Unmute',\n onClick: () => {\n this.appMessagesManager.mutePeer(this.peerId);\n },\n verify: () => this.chat.type === 'chat' && rootScope.myId !== this.peerId && this.appNotificationsManager.isPeerLocalMuted(this.peerId, false)\n }, {\n icon: 'comments',\n text: 'ViewDiscussion',\n onClick: () => {\n this.appProfileManager.getChannelFull(-this.peerId).then(channelFull => {\n if(channelFull.linked_chat_id) {\n this.chat.appImManager.setInnerPeer(-channelFull.linked_chat_id);\n }\n });\n },\n verify: () => {\n const chatFull = this.appProfileManager.chatsFull[-this.peerId];\n return this.chat.type === 'chat' && this.appPeersManager.isBroadcast(this.peerId) && !!(chatFull as ChatFull.channelFull)?.linked_chat_id;\n }\n }, {\n icon: 'select',\n text: 'Chat.Menu.SelectMessages',\n onClick: () => {\n const selection = this.chat.selection;\n selection.toggleSelection(true, true);\n appStateManager.getState().then(state => {\n if(state.chatContextMenuHintWasShown) {\n return;\n }\n\n const original = selection.toggleByElement.bind(selection);\n selection.toggleByElement = (bubble) => {\n appStateManager.pushToState('chatContextMenuHintWasShown', true);\n toast(i18n('Chat.Menu.Hint'));\n\n selection.toggleByElement = original;\n selection.toggleByElement(bubble);\n };\n });\n },\n verify: () => !this.chat.selection.isSelecting && !!Object.keys(this.chat.bubbles.bubbles).length\n }, {\n icon: 'select',\n text: 'Chat.Menu.ClearSelection',\n onClick: () => {\n this.chat.selection.cancelSelection();\n },\n verify: () => this.chat.selection.isSelecting\n }, {\n icon: 'adduser',\n text: 'AddContact',\n onClick: () => {\n if(!this.appSidebarRight.isTabExists(AppEditContactTab)) {\n const tab = new AppEditContactTab(this.appSidebarRight);\n tab.peerId = this.peerId;\n tab.open();\n\n this.appSidebarRight.toggleSidebar(true);\n }\n },\n verify: () => this.peerId > 0 && !this.appUsersManager.isContact(this.peerId)\n }, {\n icon: 'forward',\n text: 'ShareContact',\n onClick: () => {\n const contactPeerId = this.peerId;\n new PopupPickUser({\n peerTypes: ['dialogs', 'contacts'],\n onSelect: (peerId) => {\n return new Promise((resolve, reject) => {\n new PopupPeer('', {\n titleLangKey: 'SendMessageTitle',\n descriptionLangKey: 'SendContactToGroupText',\n descriptionLangArgs: [new PeerTitle({peerId, dialog: true}).element],\n buttons: [{\n langKey: 'Send',\n callback: () => {\n resolve();\n\n this.appMessagesManager.sendOther(peerId, this.appUsersManager.getContactMediaInput(contactPeerId));\n this.chat.appImManager.setInnerPeer(peerId);\n }\n }, {\n langKey: 'Cancel',\n callback: () => {\n reject();\n },\n isCancel: true,\n }],\n peerId,\n overlayClosable: true\n }).show();\n });\n },\n placeholder: 'ShareModal.Search.Placeholder',\n chatRightsAction: 'send_messages',\n selfPresence: 'ChatYourSelf'\n });\n },\n verify: () => rootScope.myId !== this.peerId && this.peerId > 0 && this.appUsersManager.isContact(this.peerId)\n }, {\n icon: 'lock',\n text: 'BlockUser',\n onClick: () => {\n new PopupPeer('', {\n peerId: this.peerId,\n titleLangKey: 'BlockUser',\n descriptionLangKey: 'AreYouSureBlockContact2',\n descriptionLangArgs: [new PeerTitle({peerId: this.peerId}).element],\n buttons: [{\n langKey: 'BlockUser',\n isDanger: true,\n callback: () => {\n this.appUsersManager.toggleBlock(this.peerId, true).then(value => {\n if(value) {\n toastNew({langPackKey: 'UserBlocked'});\n }\n });\n }\n }]\n }).show();\n },\n verify: () => {\n const userFull = this.appProfileManager.usersFull[this.peerId];\n return this.peerId > 0 && this.peerId !== rootScope.myId && userFull && !userFull.pFlags?.blocked;\n }\n }, {\n icon: 'lockoff',\n text: 'Unblock',\n onClick: () => {\n this.appUsersManager.toggleBlock(this.peerId, false).then(value => {\n if(value) {\n toastNew({langPackKey: 'UserUnblocked'});\n }\n });\n },\n verify: () => {\n const userFull = this.appProfileManager.usersFull[this.peerId];\n return this.peerId > 0 && !!userFull?.pFlags?.blocked;\n }\n }, {\n icon: 'delete danger',\n text: 'Delete',\n onClick: () => {\n new PopupDeleteDialog(this.peerId/* , 'leave' */);\n },\n verify: () => this.chat.type === 'chat' && !!this.appMessagesManager.getDialogOnly(this.peerId)\n }];\n\n this.btnSearch = ButtonIcon('search');\n attachClickEvent(this.btnSearch, (e) => {\n cancelEvent(e);\n this.chat.initSearch();\n }, {listenerSetter: this.listenerSetter});\n }\n\n public constructPeerHelpers() {\n this.avatarElement = new AvatarElement();\n this.avatarElement.setAttribute('dialog', '1');\n //this.avatarElement.setAttribute('clickable', '');\n this.avatarElement.classList.add('avatar-42', 'person-avatar');\n\n this.subtitle = document.createElement('div');\n this.subtitle.classList.add('info');\n\n this.pinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);\n\n this.btnJoin = Button('btn-primary btn-color-primary chat-join hide');\n this.btnPinned = ButtonIcon('pinlist');\n this.btnMute = ButtonIcon('mute');\n\n attachClickEvent(this.btnPinned, (e) => {\n cancelEvent(e);\n blurActiveElement();\n this.openPinned(true);\n }, {listenerSetter: this.listenerSetter});\n\n attachClickEvent(this.btnMute, (e) => {\n cancelEvent(e);\n blurActiveElement();\n this.appMessagesManager.mutePeer(this.peerId);\n }, {listenerSetter: this.listenerSetter});\n\n attachClickEvent(this.btnJoin, (e) => {\n cancelEvent(e);\n\n blurActiveElement();\n const middleware = this.chat.bubbles.getMiddleware();\n this.btnJoin.setAttribute('disabled', 'true');\n\n const chatId = -this.peerId;\n let promise: Promise<any>;\n if(this.appChatsManager.isChannel(chatId)) {\n promise = this.appChatsManager.joinChannel(chatId);\n } else {\n promise = this.appChatsManager.addChatUser(chatId, rootScope.myId);\n }\n\n promise.finally(() => {\n if(!middleware()) {\n return;\n }\n\n this.btnJoin.removeAttribute('disabled');\n });\n }, {listenerSetter: this.listenerSetter});\n\n this.listenerSetter.add(rootScope)('chat_update', (chatId) => {\n if(this.peerId === -chatId) {\n const chat = this.appChatsManager.getChat(chatId) as Channel/* | Chat */;\n \n this.btnJoin.classList.toggle('hide', !(chat as Channel)?.pFlags?.left);\n this.setUtilsWidth();\n }\n });\n\n this.listenerSetter.add(rootScope)('dialog_notify_settings', (dialog) => {\n if(dialog.peerId === this.peerId) {\n this.setMutedState();\n }\n });\n\n this.listenerSetter.add(rootScope)('peer_typings', ({peerId}) => {\n if(this.peerId === peerId) {\n this.setPeerStatus();\n }\n });\n\n this.listenerSetter.add(rootScope)('user_update', (userId) => {\n if(this.peerId === userId) {\n this.setPeerStatus();\n }\n });\n\n if(this.pinnedMessage) {\n this.chat.addEventListener('setPeer', (mid, isTopMessage) => {\n const middleware = this.chat.bubbles.getMiddleware();\n appStateManager.getState().then((state) => {\n if(!middleware()) return;\n \n this.pinnedMessage.hidden = !!state.hiddenPinnedMessages[this.chat.peerId];\n \n if(isTopMessage) {\n this.pinnedMessage.unsetScrollDownListener();\n this.pinnedMessage.testMid(mid, 0); // * because slider will not let get bubble by document.elementFromPoint\n } else if(!this.pinnedMessage.locked) {\n this.pinnedMessage.handleFollowingPinnedMessage();\n this.pinnedMessage.testMid(mid);\n }\n });\n });\n }\n\n this.setPeerStatusInterval = window.setInterval(this.setPeerStatus, 60e3);\n\n return this;\n }\n\n public constructPinnedHelpers() {\n this.listenerSetter.add(rootScope)('peer_pinned_messages', (e) => {\n const {peerId, mids, pinned} = e;\n\n if(peerId !== this.peerId) return;\n\n if(mids) {\n this.setTitle();\n }\n });\n }\n \n public constructDiscussionHelpers() {\n this.pinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);\n }\n\n public openPinned(byCurrent: boolean) {\n this.chat.appImManager.setInnerPeer(this.peerId, byCurrent ? +this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.dataset.mid : 0, 'pinned');\n }\n\n private onResize = () => {\n this.setUtilsWidth(true);\n this.setFloating();\n };\n\n private onChangeScreen = (from: ScreenSize, to: ScreenSize) => {\n this.container.classList.toggle('is-pinned-floating', mediaSizes.isMobile);\n // this.chatAudio && this.chatAudio.divAndCaption.container.classList.toggle('is-floating', to === ScreenSize.mobile);\n this.pinnedMessage && this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.classList.toggle('is-floating', to === ScreenSize.mobile);\n this.onResize();\n };\n\n public destroy() {\n //this.chat.log.error('Topbar destroying');\n\n this.listenerSetter.removeAll();\n window.clearInterval(this.setPeerStatusInterval);\n \n if(this.pinnedMessage) {\n this.pinnedMessage.destroy(); // * возможно это можно не делать\n }\n\n delete this.chatAudio;\n delete this.pinnedMessage;\n }\n\n public setPeer(peerId: number) {\n this.wasPeerId = this.peerId;\n this.peerId = peerId;\n\n this.container.style.display = peerId ? '' : 'none';\n }\n\n public finishPeerChange(isTarget: boolean, isJump: boolean, lastMsgId: number) {\n const peerId = this.peerId;\n\n if(this.avatarElement) {\n this.avatarElement.setAttribute('peer', '' + peerId);\n this.avatarElement.update();\n }\n\n const isBroadcast = this.appPeersManager.isBroadcast(peerId);\n\n this.btnMute && this.btnMute.classList.toggle('hide', !isBroadcast);\n if(this.btnJoin) {\n replaceContent(this.btnJoin, i18n(this.appChatsManager.isChannel(-peerId) ? 'Chat.Subscribe' : 'ChannelJoin'));\n this.btnJoin.classList.toggle('hide', !this.appChatsManager.getChat(-peerId)?.pFlags?.left);\n }\n this.setUtilsWidth();\n\n const middleware = this.chat.bubbles.getMiddleware();\n if(this.pinnedMessage) { // * replace with new one\n if(this.chat.type === 'chat') {\n if(this.wasPeerId !== undefined) { // * change\n const newPinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);\n this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.replaceWith(newPinnedMessage.pinnedMessageContainer.divAndCaption.container);\n this.pinnedMessage.destroy();\n //this.pinnedMessage.pinnedMessageContainer.toggle(true);\n this.pinnedMessage = newPinnedMessage;\n }\n \n appStateManager.getState().then((state) => {\n if(!middleware()) return;\n \n this.pinnedMessage.hidden = !!state.hiddenPinnedMessages[peerId];\n \n if(!isTarget) {\n this.pinnedMessage.setCorrectIndex(0);\n }\n });\n } else if(this.chat.type === 'discussion') {\n this.pinnedMessage.pinnedMid = this.chat.threadId;\n this.pinnedMessage.count = 1;\n this.pinnedMessage.pinnedIndex = 0;\n this.pinnedMessage._setPinnedMessage();\n }\n }\n\n fastRaf(() => {\n this.setTitle();\n this.setPeerStatus(true);\n this.setMutedState();\n });\n }\n\n public setTitle(count?: number) {\n let titleEl: HTMLElement;\n if(this.chat.type === 'pinned') {\n if(count === undefined) titleEl = i18n('Loading');\n else titleEl = i18n('PinnedMessagesCount', [count]);\n\n if(count === undefined) {\n this.appMessagesManager.getSearchCounters(this.peerId, [{_: 'inputMessagesFilterPinned'}], false).then(result => {\n const count = result[0].count;\n this.setTitle(count);\n\n // ! костыль х2, это нужно делать в другом месте\n if(!count) {\n this.chat.appImManager.setPeer(0); // * close tab\n\n // ! костыль, это скроет закреплённые сообщения сразу, вместо того, чтобы ждать пока анимация перехода закончится\n const originalChat = this.chat.appImManager.chat;\n if(originalChat.topbar.pinnedMessage) {\n originalChat.topbar.pinnedMessage.pinnedMessageContainer.toggle(true);\n }\n }\n });\n }\n } else if(this.chat.type === 'scheduled') {\n if(this.peerId === rootScope.myId) {\n //title = [count > 1 ? count : false, 'Reminders'].filter(Boolean).join(' ');\n titleEl = i18n('Reminders');\n } else {\n titleEl = i18n('ScheduledMessages');\n //title = [count > 1 ? count : false, 'Scheduled Messages'].filter(Boolean).join(' ');\n }\n \n if(count === undefined) {\n this.appMessagesManager.getScheduledMessages(this.peerId).then(mids => {\n this.setTitle(mids.length);\n });\n }\n } else if(this.chat.type === 'discussion') {\n if(count === undefined) titleEl = i18n('Loading');\n else titleEl = i18n('Chat.Title.Comments', [count]);\n\n if(count === undefined) {\n Promise.all([\n this.appMessagesManager.getHistory(this.peerId, 0, 1, 0, this.chat.threadId),\n Promise.resolve()\n ]).then(() => {\n const count = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId).count;\n if(count === null) {\n setTimeout(() => {\n this.setTitle();\n }, 30);\n } else {\n this.setTitle(count);\n }\n });\n }\n } else if(this.chat.type === 'chat') {\n titleEl = new PeerTitle({\n peerId: this.peerId,\n dialog: true,\n }).element;\n }\n \n replaceContent(this.title, titleEl);\n\n if(this.chat.type === 'chat') {\n const peer = this.appPeersManager.getPeer(this.peerId);\n if(peer?.pFlags?.verified) {\n this.title.append(generateVerifiedIcon());\n }\n }\n }\n\n public setMutedState() {\n if(!this.btnMute) return;\n\n const peerId = this.peerId;\n let muted = this.appNotificationsManager.isPeerLocalMuted(peerId, false);\n if(this.appPeersManager.isBroadcast(peerId)) { // not human\n this.btnMute.classList.remove('tgico-mute', 'tgico-unmute');\n this.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');\n this.btnMute.style.display = '';\n } else {\n this.btnMute.style.display = 'none';\n }\n }\n\n // ! У МЕНЯ ПРОСТО СГОРЕЛО, САФАРИ КОНЧЕННЫЙ БРАУЗЕР - ЕСЛИ НЕ СКРЫВАТЬ БЛОК, ТО ПРИ ПЕРЕВОРОТЕ ЭКРАНА НА АЙФОНЕ БЛОК БУДЕТ НЕПРАВИЛЬНО ШИРИНЫ, ДАЖЕ БЕЗ ЭТОЙ ФУНКЦИИ!\n public setUtilsWidth = (resize = false) => {\n //return;\n if(this.setUtilsRAF) window.cancelAnimationFrame(this.setUtilsRAF);\n\n if(IS_SAFARI && resize) {\n this.chatUtils.classList.add('hide');\n }\n\n //mutationObserver.disconnect();\n this.setUtilsRAF = window.requestAnimationFrame(() => {\n \n //mutationRAF = window.requestAnimationFrame(() => {\n \n //setTimeout(() => {\n if(IS_SAFARI && resize) {\n this.chatUtils.classList.remove('hide');\n }\n /* this.chatInfo.style.removeProperty('--utils-width');\n void this.chatInfo.offsetLeft; // reflow */\n const width = /* chatUtils.scrollWidth */this.chatUtils.getBoundingClientRect().width;\n this.chat.log('utils width:', width);\n this.chatInfo.style.setProperty('--utils-width', width + 'px');\n //this.chatInfo.classList.toggle('have-utils-width', !!width);\n //}, 0);\n \n this.setUtilsRAF = 0;\n\n //mutationObserver.observe(chatUtils, observeOptions);\n //});\n });\n };\n\n public setFloating = () => {\n const containers = [this.chatAudio, this.pinnedMessage && this.pinnedMessage.pinnedMessageContainer].filter(Boolean);\n const count = containers.reduce((acc, container) => {\n const isFloating = container.divAndCaption.container.classList.contains('is-floating');\n this.container.classList.toggle(`is-pinned-${container.className}-floating`, isFloating);\n return acc + +isFloating;\n }, 0);\n this.container.dataset.floating = '' + count;\n };\n\n public setPeerStatus = (needClear = false) => {\n if(!this.subtitle) return;\n\n const peerId = this.peerId;\n this.chat.appImManager.setPeerStatus(this.peerId, this.subtitle, needClear, false, () => peerId === this.peerId);\n };\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appSidebarRight from \"..\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport AppSearch, { SearchGroup } from \"../../appSearch\";\r\nimport ButtonIcon from \"../../buttonIcon\";\r\nimport InputSearch from \"../../inputSearch\";\r\nimport PopupDatePicker from \"../../popups/datePicker\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\n\r\nexport default class AppPrivateSearchTab extends SliderSuperTab {\r\n private inputSearch: InputSearch;\r\n private appSearch: AppSearch;\r\n private btnPickDate: HTMLElement;\r\n\r\n private peerId = 0;\r\n private threadId = 0;\r\n private query = '';\r\n private onDatePick: (timestamp: number) => void;\r\n\r\n onOpenAfterTimeout() {\r\n this.appSearch.beginSearch(this.peerId, this.threadId, this.query);\r\n }\r\n\r\n protected init() {\r\n this.container.id = 'search-private-container';\r\n this.container.classList.add('chatlist-container');\r\n this.inputSearch = new InputSearch('Search');\r\n this.title.replaceWith(this.inputSearch.container);\r\n\r\n this.btnPickDate = ButtonIcon('calendar sidebar-header-right');\r\n this.header.append(this.btnPickDate);\r\n\r\n const c = document.createElement('div');\r\n c.classList.add('chatlist-container');\r\n this.scrollable.container.replaceWith(c);\r\n this.appSearch = new AppSearch(c, this.inputSearch, {\r\n messages: new SearchGroup('Chat.Search.PrivateSearch', 'messages')\r\n });\r\n }\r\n\r\n open(peerId: number, threadId?: number, onDatePick?: AppPrivateSearchTab['onDatePick'], query?: string) {\r\n const ret = super.open();\r\n\r\n if(!this.peerId) {\r\n this.query = query;\r\n this.peerId = peerId;\r\n this.threadId = threadId;\r\n this.onDatePick = onDatePick;\r\n \r\n this.btnPickDate.classList.toggle('hide', !this.onDatePick);\r\n if(this.onDatePick) {\r\n attachClickEvent(this.btnPickDate, () => {\r\n new PopupDatePicker(new Date(), this.onDatePick).show();\r\n });\r\n }\r\n\r\n query && this.appSearch.searchInput.inputField.setValueSilently(query);\r\n \r\n appSidebarRight.toggleSidebar(true);\r\n } else {\r\n this.appSearch.beginSearch(this.peerId, this.threadId, query);\r\n }\r\n\r\n return ret;\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type ChatTopbar from \"./topbar\";\r\nimport AppSearch, { SearchGroup } from \"../appSearch\";\r\nimport PopupDatePicker from \"../popups/datePicker\";\r\nimport { ripple } from \"../ripple\";\r\nimport InputSearch from \"../inputSearch\";\r\nimport type Chat from \"./chat\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport whichChild from \"../../helpers/dom/whichChild\";\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\nimport { i18n } from \"../../lib/langPack\";\r\n\r\nexport default class ChatSearch {\r\n private element: HTMLElement;\r\n private backBtn: HTMLElement;\r\n private inputSearch: InputSearch;\r\n\r\n private results: HTMLElement;\r\n\r\n private footer: HTMLElement;\r\n private dateBtn: HTMLElement;\r\n private foundCountEl: HTMLElement;\r\n private controls: HTMLElement;\r\n private downBtn: HTMLElement;\r\n private upBtn: HTMLElement;\r\n\r\n private appSearch: AppSearch;\r\n private searchGroup: SearchGroup;\r\n\r\n private foundCount = 0;\r\n private selectedIndex = 0;\r\n private setPeerPromise: Promise<any>;\r\n\r\n constructor(private topbar: ChatTopbar, private chat: Chat, private query?: string) {\r\n this.element = document.createElement('div');\r\n this.element.classList.add('sidebar-header', 'chat-search', 'chatlist-container');\r\n\r\n this.backBtn = document.createElement('button');\r\n this.backBtn.classList.add('btn-icon', 'tgico-left', 'sidebar-close-button');\r\n ripple(this.backBtn);\r\n \r\n this.backBtn.addEventListener('click', () => {\r\n this.topbar.container.classList.remove('hide-pinned');\r\n this.element.remove();\r\n this.inputSearch.remove();\r\n this.results.remove();\r\n this.footer.remove();\r\n this.footer.removeEventListener('click', this.onFooterClick);\r\n this.dateBtn.removeEventListener('click', this.onDateClick);\r\n this.upBtn.removeEventListener('click', this.onUpClick);\r\n this.downBtn.removeEventListener('click', this.onDownClick);\r\n this.searchGroup.list.removeEventListener('click', this.onResultsClick);\r\n this.chat.bubbles.bubblesContainer.classList.remove('search-results-active');\r\n }, {once: true});\r\n\r\n this.inputSearch = new InputSearch('Search');\r\n \r\n // Results\r\n this.results = document.createElement('div');\r\n this.results.classList.add('chat-search-results', 'chatlist-container');\r\n\r\n this.searchGroup = new SearchGroup(false, 'messages', undefined, '', false);\r\n this.searchGroup.list.addEventListener('click', this.onResultsClick);\r\n\r\n this.appSearch = new AppSearch(this.results, this.inputSearch, {\r\n messages: this.searchGroup\r\n }, (count) => {\r\n this.foundCount = count;\r\n\r\n if(!this.foundCount) {\r\n this.foundCountEl.replaceWith(this.inputSearch.value ? i18n('NoResult') : '');\r\n this.results.classList.remove('active');\r\n this.chat.bubbles.bubblesContainer.classList.remove('search-results-active');\r\n this.upBtn.setAttribute('disabled', 'true');\r\n this.downBtn.setAttribute('disabled', 'true');\r\n } else {\r\n this.selectResult(this.searchGroup.list.children[0] as HTMLElement);\r\n }\r\n });\r\n this.appSearch.beginSearch(this.chat.peerId, this.chat.threadId);\r\n\r\n //appImManager.topbar.parentElement.insertBefore(this.results, appImManager.bubblesContainer);\r\n this.chat.bubbles.bubblesContainer.append(this.results);\r\n\r\n // Footer\r\n this.footer = document.createElement('div');\r\n this.footer.classList.add('chat-search-footer');\r\n\r\n this.footer.addEventListener('click', this.onFooterClick);\r\n ripple(this.footer);\r\n\r\n this.foundCountEl = document.createElement('span');\r\n this.foundCountEl.classList.add('chat-search-count');\r\n\r\n this.dateBtn = document.createElement('button');\r\n this.dateBtn.classList.add('btn-icon', 'tgico-calendar');\r\n\r\n this.controls = document.createElement('div');\r\n this.controls.classList.add('chat-search-controls');\r\n\r\n this.upBtn = document.createElement('button');\r\n this.upBtn.classList.add('btn-icon', 'tgico-up');\r\n this.downBtn = document.createElement('button');\r\n this.downBtn.classList.add('btn-icon', 'tgico-down');\r\n\r\n this.upBtn.setAttribute('disabled', 'true');\r\n this.downBtn.setAttribute('disabled', 'true');\r\n\r\n this.dateBtn.addEventListener('click', this.onDateClick);\r\n this.upBtn.addEventListener('click', this.onUpClick);\r\n this.downBtn.addEventListener('click', this.onDownClick);\r\n this.controls.append(this.upBtn, this.downBtn);\r\n\r\n this.footer.append(this.foundCountEl, this.dateBtn, this.controls);\r\n \r\n this.topbar.container.parentElement.insertBefore(this.footer, chat.input.chatInput);\r\n\r\n // Append container\r\n this.element.append(this.backBtn, this.inputSearch.container);\r\n\r\n this.topbar.container.classList.add('hide-pinned');\r\n this.topbar.container.parentElement.append(this.element);\r\n\r\n this.inputSearch.input.focus();\r\n\r\n query && (this.inputSearch.inputField.value = query);\r\n }\r\n\r\n onDateClick = (e: MouseEvent) => {\r\n cancelEvent(e);\r\n new PopupDatePicker(new Date(), this.chat.bubbles.onDatePick).show();\r\n };\r\n\r\n selectResult = (elem: HTMLElement) => {\r\n if(this.setPeerPromise) return this.setPeerPromise;\r\n\r\n const peerId = +elem.dataset.peerId;\r\n const lastMsgId = +elem.dataset.mid || undefined;\r\n\r\n const index = whichChild(elem);\r\n\r\n if(index === (this.foundCount - 1)) {\r\n this.upBtn.setAttribute('disabled', 'true');\r\n } else {\r\n this.upBtn.removeAttribute('disabled');\r\n }\r\n\r\n if(!index) {\r\n this.downBtn.setAttribute('disabled', 'true');\r\n } else {\r\n this.downBtn.removeAttribute('disabled');\r\n }\r\n\r\n this.results.classList.remove('active');\r\n this.chat.bubbles.bubblesContainer.classList.remove('search-results-active');\r\n\r\n const res = this.chat.setPeer(peerId, lastMsgId);\r\n this.setPeerPromise = ((res instanceof Promise ? res : Promise.resolve(res)) as Promise<any>).then(() => {\r\n this.selectedIndex = index;\r\n replaceContent(this.foundCountEl, i18n('Of', [index + 1, this.foundCount]));\r\n\r\n const renderedCount = this.searchGroup.list.childElementCount;\r\n if(this.selectedIndex >= (renderedCount - 6)) {\r\n this.appSearch.searchMore();\r\n }\r\n }).finally(() => {\r\n this.setPeerPromise = null;\r\n });\r\n };\r\n\r\n onResultsClick = (e: MouseEvent) => {\r\n const target = findUpTag(e.target, 'LI');\r\n if(target) {\r\n this.selectResult(target);\r\n }\r\n };\r\n\r\n onFooterClick = (e: MouseEvent) => {\r\n if(this.foundCount) {\r\n this.chat.bubbles.bubblesContainer.classList.toggle('search-results-active');\r\n this.results.classList.toggle('active');\r\n }\r\n };\r\n\r\n onUpClick = (e: MouseEvent) => {\r\n cancelEvent(e);\r\n this.selectResult(this.searchGroup.list.children[this.selectedIndex + 1] as HTMLElement);\r\n };\r\n\r\n onDownClick = (e: MouseEvent) => {\r\n cancelEvent(e);\r\n this.selectResult(this.searchGroup.list.children[this.selectedIndex - 1] as HTMLElement);\r\n };\r\n}","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type { AppNotificationsManager } from \"../../lib/appManagers/appNotificationsManager\";\nimport type { AppChatsManager } from \"../../lib/appManagers/appChatsManager\";\nimport type { AppDocsManager } from \"../../lib/appManagers/appDocsManager\";\nimport type { AppImManager } from \"../../lib/appManagers/appImManager\";\nimport type { AppInlineBotsManager } from \"../../lib/appManagers/appInlineBotsManager\";\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\nimport type { AppPhotosManager } from \"../../lib/appManagers/appPhotosManager\";\nimport type { AppPollsManager } from \"../../lib/appManagers/appPollsManager\";\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\nimport type { AppStickersManager } from \"../../lib/appManagers/appStickersManager\";\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\nimport type { AppWebPagesManager } from \"../../lib/appManagers/appWebPagesManager\";\nimport type { ApiManagerProxy } from \"../../lib/mtproto/mtprotoworker\";\nimport type { AppDraftsManager } from \"../../lib/appManagers/appDraftsManager\";\nimport type { AppEmojiManager } from \"../../lib/appManagers/appEmojiManager\";\nimport type { ServerTimeManager } from \"../../lib/mtproto/serverTimeManager\";\nimport type { AppMessagesIdsManager } from \"../../lib/appManagers/appMessagesIdsManager\";\nimport type { State } from \"../../lib/appManagers/appStateManager\";\nimport type stateStorage from '../../lib/stateStorage';\nimport EventListenerBase from \"../../helpers/eventListenerBase\";\nimport { logger, LogTypes } from \"../../lib/logger\";\nimport rootScope from \"../../lib/rootScope\";\nimport appSidebarRight from \"../sidebarRight\";\nimport ChatBubbles from \"./bubbles\";\nimport ChatContextMenu from \"./contextMenu\";\nimport ChatInput from \"./input\";\nimport ChatSelection from \"./selection\";\nimport ChatTopbar from \"./topbar\";\nimport { REPLIES_PEER_ID } from \"../../lib/mtproto/mtproto_config\";\nimport SetTransition from \"../singleTransition\";\nimport { fastRaf } from \"../../helpers/schedulers\";\nimport AppPrivateSearchTab from \"../sidebarRight/tabs/search\";\nimport renderImageFromUrl from \"../../helpers/dom/renderImageFromUrl\";\nimport mediaSizes from \"../../helpers/mediaSizes\";\nimport ChatSearch from \"./search\";\n\nexport type ChatType = 'chat' | 'pinned' | 'replies' | 'discussion' | 'scheduled';\n\nexport default class Chat extends EventListenerBase<{\n setPeer: (mid: number, isTopMessage: boolean) => void\n}> {\n public container: HTMLElement;\n public backgroundEl: HTMLElement;\n\n public topbar: ChatTopbar;\n public bubbles: ChatBubbles;\n public input: ChatInput;\n public selection: ChatSelection;\n public contextMenu: ChatContextMenu;\n\n public wasAlreadyUsed = false;\n // public initPeerId = 0;\n public peerId = 0;\n public threadId: number;\n public setPeerPromise: Promise<void>;\n public peerChanged: boolean;\n\n public log: ReturnType<typeof logger>;\n\n public type: ChatType = 'chat';\n\n public noAutoDownloadMedia: boolean;\n\n public inited = false;\n \n constructor(public appImManager: AppImManager, \n public appChatsManager: AppChatsManager, \n public appDocsManager: AppDocsManager, \n public appInlineBotsManager: AppInlineBotsManager, \n public appMessagesManager: AppMessagesManager, \n public appPeersManager: AppPeersManager, \n public appPhotosManager: AppPhotosManager, \n public appProfileManager: AppProfileManager, \n public appStickersManager: AppStickersManager, \n public appUsersManager: AppUsersManager, \n public appWebPagesManager: AppWebPagesManager, \n public appPollsManager: AppPollsManager, \n public apiManager: ApiManagerProxy, \n public appDraftsManager: AppDraftsManager, \n public serverTimeManager: ServerTimeManager, \n public storage: typeof stateStorage, \n public appNotificationsManager: AppNotificationsManager,\n public appEmojiManager: AppEmojiManager,\n public appMessagesIdsManager: AppMessagesIdsManager\n ) {\n super();\n\n this.container = document.createElement('div');\n this.container.classList.add('chat', 'tabs-tab');\n\n this.backgroundEl = document.createElement('div');\n this.backgroundEl.classList.add('chat-background');\n\n // * constructor end\n\n this.log = logger('CHAT', LogTypes.Log | LogTypes.Warn | LogTypes.Debug | LogTypes.Error);\n //this.log.error('Chat construction');\n\n this.container.append(this.backgroundEl);\n this.appImManager.chatsContainer.append(this.container);\n }\n\n public setBackground(url: string): Promise<void> {\n const theme = rootScope.getTheme();\n\n let item: HTMLElement;\n if(theme.background.type === 'color' && document.documentElement.style.cursor === 'grabbing') {\n const _item = this.backgroundEl.lastElementChild as HTMLElement;\n if(_item && _item.dataset.type === theme.background.type) {\n item = _item;\n }\n }\n \n if(!item) {\n item = document.createElement('div');\n item.classList.add('chat-background-item');\n item.dataset.type = theme.background.type;\n }\n\n if(theme.background.type === 'color') {\n item.style.backgroundColor = theme.background.color;\n item.style.backgroundImage = 'none';\n }\n\n return new Promise<void>((resolve) => {\n const cb = () => {\n const prev = this.backgroundEl.lastElementChild as HTMLElement;\n\n if(prev === item) {\n resolve();\n return;\n }\n\n this.backgroundEl.append(item);\n\n // * одного недостаточно, при обновлении страницы все равно фон появляется неплавно\n // ! с requestAnimationFrame лучше, но все равно иногда моргает, так что использую два фаста.\n fastRaf(() => {\n fastRaf(() => {\n SetTransition(item, 'is-visible', true, 200, prev ? () => {\n prev.remove();\n } : null);\n });\n });\n\n resolve();\n };\n\n if(url) {\n renderImageFromUrl(item, url, cb);\n } else {\n cb();\n }\n });\n }\n\n public setType(type: ChatType) {\n this.type = type;\n\n if(this.type === 'scheduled') {\n this.getMessagesStorage = () => this.appMessagesManager.getScheduledMessagesStorage(this.peerId);\n //this.getMessage = (mid) => this.appMessagesManager.getMessageFromStorage(this.appMessagesManager.getScheduledMessagesStorage(this.peerId), mid);\n }\n }\n\n public init(/* peerId: number */) {\n // this.initPeerId = peerId;\n\n this.topbar = new ChatTopbar(this, appSidebarRight, this.appMessagesManager, this.appPeersManager, this.appChatsManager, this.appNotificationsManager, this.appProfileManager, this.appUsersManager);\n this.bubbles = new ChatBubbles(this, this.appMessagesManager, this.appStickersManager, this.appUsersManager, this.appInlineBotsManager, this.appPhotosManager, this.appPeersManager, this.appProfileManager, this.appDraftsManager, this.appMessagesIdsManager);\n this.input = new ChatInput(this, this.appMessagesManager, this.appMessagesIdsManager, this.appDocsManager, this.appChatsManager, this.appPeersManager, this.appWebPagesManager, this.appImManager, this.appDraftsManager, this.serverTimeManager, this.appNotificationsManager, this.appEmojiManager, this.appUsersManager, this.appInlineBotsManager);\n this.selection = new ChatSelection(this, this.bubbles, this.input, this.appMessagesManager);\n this.contextMenu = new ChatContextMenu(this.bubbles.bubblesContainer, this, this.appMessagesManager, this.appPeersManager, this.appPollsManager, this.appDocsManager, this.appMessagesIdsManager);\n\n if(this.type === 'chat') {\n this.topbar.constructUtils();\n this.topbar.constructPeerHelpers();\n } else if(this.type === 'pinned') {\n this.topbar.constructPinnedHelpers();\n } else if(this.type === 'discussion') {\n this.topbar.constructUtils();\n this.topbar.constructDiscussionHelpers();\n }\n\n this.topbar.construct();\n this.input.construct();\n\n if(this.type === 'chat') { // * гений в деле, разный порядок из-за разной последовательности действий\n this.bubbles.constructPeerHelpers();\n this.input.constructPeerHelpers();\n } else if(this.type === 'pinned') {\n this.bubbles.constructPinnedHelpers();\n this.input.constructPinnedHelpers();\n } else if(this.type === 'scheduled') {\n this.bubbles.constructScheduledHelpers();\n this.input.constructPeerHelpers();\n } else if(this.type === 'discussion') {\n this.bubbles.constructPeerHelpers();\n this.input.constructPeerHelpers();\n }\n\n this.container.classList.add('type-' + this.type);\n this.container.append(this.topbar.container, this.bubbles.bubblesContainer, this.input.chatInput);\n\n this.bubbles.listenerSetter.add(rootScope)('dialog_migrate', ({migrateFrom, migrateTo}) => {\n if(this.peerId === migrateFrom) {\n this.setPeer(migrateTo);\n }\n });\n\n this.bubbles.listenerSetter.add(rootScope)('dialog_drop', (e) => {\n if(e.peerId === this.peerId) {\n this.appImManager.setPeer(0);\n }\n });\n }\n\n public beforeDestroy() {\n this.bubbles.cleanup();\n }\n\n public destroy() {\n //const perf = performance.now();\n\n this.topbar.destroy();\n this.bubbles.destroy();\n this.input.destroy();\n\n delete this.topbar;\n delete this.bubbles;\n delete this.input;\n delete this.selection;\n delete this.contextMenu;\n\n this.container.remove();\n\n //this.log.error('Chat destroy time:', performance.now() - perf);\n }\n\n public cleanup(helperToo = true) {\n this.input.cleanup(helperToo);\n this.selection.cleanup();\n }\n\n public setPeer(peerId: number, lastMsgId?: number) {\n if(!peerId) {\n this.inited = false;\n } else if(!this.inited) {\n if(this.init) {\n this.init(/* peerId */);\n this.init = null;\n }\n\n this.inited = true;\n }\n\n const samePeer = this.peerId === peerId;\n if(!samePeer) {\n rootScope.dispatchEvent('peer_changing', this);\n this.peerId = peerId;\n } else if(this.setPeerPromise) {\n return;\n }\n\n //console.time('appImManager setPeer');\n //console.time('appImManager setPeer pre promise');\n ////console.time('appImManager: pre render start');\n if(!peerId) {\n appSidebarRight.toggleSidebar(false);\n this.cleanup(true);\n this.topbar.setPeer(peerId);\n this.bubbles.setPeer(peerId);\n rootScope.dispatchEvent('peer_changed', peerId);\n\n return;\n }\n\n // set new\n if(!samePeer) {\n const searchTab = appSidebarRight.getTab(AppPrivateSearchTab);\n if(searchTab) {\n searchTab.close();\n }\n\n appSidebarRight.sharedMediaTab.setPeer(peerId, this.threadId);\n this.input.clearHelper(); // костыль\n this.selection.cleanup(); // TODO: REFACTOR !!!!!!\n this.setAutoDownloadMedia();\n }\n\n this.peerChanged = samePeer;\n\n const result = this.bubbles.setPeer(peerId, lastMsgId);\n if(!result) {\n return;\n }\n\n const {promise} = result;\n\n //console.timeEnd('appImManager setPeer pre promise');\n \n const setPeerPromise = this.setPeerPromise = promise.finally(() => {\n if(this.setPeerPromise === setPeerPromise) {\n this.setPeerPromise = null;\n }\n });\n\n if(!samePeer) {\n appSidebarRight.sharedMediaTab.setLoadMutex(this.setPeerPromise);\n appSidebarRight.sharedMediaTab.loadSidebarMedia(true);\n }\n /* this.setPeerPromise.then(() => {\n appSidebarRight.sharedMediaTab.loadSidebarMedia(false);\n }); */\n\n return result;\n }\n\n public setAutoDownloadMedia() {\n let type: keyof State['settings']['autoDownload'];\n if(this.peerId < 0) {\n if(this.appPeersManager.isBroadcast(this.peerId)) {\n type = 'channels';\n } else {\n type = 'groups';\n }\n } else {\n if(this.appUsersManager.isContact(this.peerId)) {\n type = 'contacts';\n } else {\n type = 'private';\n }\n }\n\n this.noAutoDownloadMedia = !rootScope.settings.autoDownload[type];\n }\n\n public setMessageId(messageId?: number) {\n return this.setPeer(this.peerId, messageId);\n }\n\n public finishPeerChange(isTarget: boolean, isJump: boolean, lastMsgId: number) {\n if(this.peerChanged) return;\n\n let peerId = this.peerId;\n this.peerChanged = true;\n\n this.cleanup(false);\n\n this.topbar.setPeer(peerId);\n this.topbar.finishPeerChange(isTarget, isJump, lastMsgId);\n this.bubbles.finishPeerChange();\n this.input.finishPeerChange();\n\n appSidebarRight.sharedMediaTab.fillProfileElements();\n\n this.log.setPrefix('CHAT-' + peerId + '-' + this.type);\n\n rootScope.dispatchEvent('peer_changed', peerId);\n this.wasAlreadyUsed = true;\n }\n\n public getMessagesStorage() {\n return this.appMessagesManager.getMessagesStorage(this.peerId);\n }\n\n public getMessage(mid: number) {\n return this.appMessagesManager.getMessageFromStorage(this.getMessagesStorage(), mid);\n //return this.appMessagesManager.getMessageByPeer(this.peerId, mid);\n }\n\n public getMidsByMid(mid: number) {\n return this.appMessagesManager.getMidsByMessage(this.getMessage(mid));\n }\n\n public isAnyGroup() {\n return this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID || this.appPeersManager.isAnyGroup(this.peerId);\n }\n\n public initSearch(query?: string) {\n if(!this.peerId) return;\n\n if(mediaSizes.isMobile) {\n new ChatSearch(this.topbar, this, query);\n } else {\n let tab = appSidebarRight.getTab(AppPrivateSearchTab);\n if(!tab) {\n tab = new AppPrivateSearchTab(appSidebarRight);\n }\n\n tab.open(this.peerId, this.threadId, this.bubbles.onDatePick, query);\n }\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type { AppImManager } from \"../../lib/appManagers/appImManager\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport ButtonIcon from \"../buttonIcon\";\r\nimport { clamp } from \"../../helpers/number\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport { IS_APPLE, IS_MOBILE } from \"../../environment/userAgent\";\r\nimport appNavigationController from \"../appNavigationController\";\r\nimport { _i18n } from \"../../lib/langPack\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport getSelectedNodes from \"../../helpers/dom/getSelectedNodes\";\r\nimport isSelectionEmpty from \"../../helpers/dom/isSelectionEmpty\";\r\nimport { MarkdownType, markdownTags } from \"../../helpers/dom/getRichElementValue\";\r\n//import { logger } from \"../../lib/logger\";\r\n\r\nexport default class MarkupTooltip {\r\n public container: HTMLElement;\r\n private wrapper: HTMLElement;\r\n private buttons: {[type in MarkdownType]: HTMLElement} = {} as any;\r\n private linkBackButton: HTMLElement;\r\n private linkApplyButton: HTMLButtonElement;\r\n private hideTimeout: number;\r\n private addedListener = false;\r\n private waitingForMouseUp = false;\r\n private linkInput: HTMLInputElement;\r\n private savedRange: Range;\r\n private mouseUpCounter: number = 0;\r\n //private log: ReturnType<typeof logger>;\r\n\r\n constructor(private appImManager: AppImManager) {\r\n //this.log = logger('MARKUP');\r\n }\r\n\r\n private init() {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('markup-tooltip', 'z-depth-1', 'hide');\r\n\r\n this.wrapper = document.createElement('div');\r\n this.wrapper.classList.add('markup-tooltip-wrapper');\r\n \r\n const tools1 = document.createElement('div');\r\n const tools2 = document.createElement('div');\r\n tools1.classList.add('markup-tooltip-tools');\r\n tools2.classList.add('markup-tooltip-tools');\r\n\r\n const arr = ['bold', 'italic', 'underline', 'strikethrough', 'monospace', 'link'] as (keyof MarkupTooltip['buttons'])[];\r\n arr.forEach(c => {\r\n const button = ButtonIcon(c, {noRipple: true});\r\n tools1.append(this.buttons[c] = button);\r\n\r\n if(c !== 'link') {\r\n button.addEventListener('mousedown', (e) => {\r\n cancelEvent(e); \r\n this.appImManager.chat.input.applyMarkdown(c);\r\n this.cancelClosening();\r\n \r\n /* this.mouseUpCounter = 0;\r\n this.setMouseUpEvent(); */\r\n //this.hide();\r\n });\r\n } else {\r\n attachClickEvent(button, (e) => {\r\n cancelEvent(e);\r\n this.showLinkEditor();\r\n this.cancelClosening();\r\n });\r\n }\r\n });\r\n\r\n this.linkBackButton = ButtonIcon('left', {noRipple: true});\r\n this.linkInput = document.createElement('input');\r\n _i18n(this.linkInput, 'MarkupTooltip.LinkPlaceholder', undefined, 'placeholder');\r\n this.linkInput.classList.add('input-clear');\r\n this.linkInput.addEventListener('keydown', (e) => {\r\n const valid = !this.linkInput.value.length || !!RichTextProcessor.matchUrl(this.linkInput.value);///^(http)|(https):\\/\\//i.test(this.linkInput.value);\r\n\r\n if(e.code === 'Enter') {\r\n if(!valid) {\r\n if(this.linkInput.classList.contains('error')) {\r\n this.linkInput.classList.remove('error');\r\n void this.linkInput.offsetLeft; // reflow\r\n }\r\n\r\n this.linkInput.classList.add('error');\r\n } else {\r\n this.applyLink(e);\r\n }\r\n }\r\n });\r\n\r\n this.linkInput.addEventListener('input', (e) => {\r\n const valid = this.isLinkValid();\r\n\r\n this.linkInput.classList.toggle('is-valid', valid);\r\n this.linkInput.classList.remove('error');\r\n });\r\n\r\n this.linkBackButton.addEventListener('mousedown', (e) => {\r\n //this.log('linkBackButton click');\r\n cancelEvent(e);\r\n this.container.classList.remove('is-link');\r\n //input.value = '';\r\n this.resetSelection();\r\n this.setTooltipPosition();\r\n this.cancelClosening();\r\n });\r\n\r\n this.linkApplyButton = ButtonIcon('check markup-tooltip-link-apply', {noRipple: true});\r\n this.linkApplyButton.addEventListener('mousedown', (e) => {\r\n //this.log('linkApplyButton click');\r\n this.applyLink(e);\r\n });\r\n\r\n const applyDiv = document.createElement('div');\r\n applyDiv.classList.add('markup-tooltip-link-apply-container');\r\n \r\n const delimiter1 = document.createElement('span');\r\n const delimiter2 = document.createElement('span');\r\n const delimiter3 = document.createElement('span');\r\n delimiter1.classList.add('markup-tooltip-delimiter');\r\n delimiter2.classList.add('markup-tooltip-delimiter');\r\n delimiter3.classList.add('markup-tooltip-delimiter');\r\n tools1.insertBefore(delimiter1, this.buttons.link);\r\n applyDiv.append(delimiter3, this.linkApplyButton);\r\n tools2.append(this.linkBackButton, delimiter2, this.linkInput, applyDiv);\r\n //tools1.insertBefore(delimiter2, this.buttons.link.nextSibling);\r\n\r\n this.wrapper.append(tools1, tools2);\r\n this.container.append(this.wrapper);\r\n document.body.append(this.container);\r\n \r\n window.addEventListener('resize', () => {\r\n this.hide();\r\n });\r\n }\r\n\r\n public showLinkEditor() {\r\n if(!this.container || !this.container.classList.contains('is-visible')) { // * if not inited yet (Ctrl+A + Ctrl+K)\r\n this.show();\r\n }\r\n\r\n const button = this.buttons.link;\r\n this.container.classList.add('is-link');\r\n\r\n const selection = document.getSelection();\r\n this.savedRange = selection.getRangeAt(0);\r\n \r\n if(button.classList.contains('active')) {\r\n const startContainer = this.savedRange.startContainer;\r\n const anchor = startContainer.parentElement as HTMLAnchorElement;\r\n this.linkInput.value = anchor.href;\r\n } else {\r\n this.linkInput.value = '';\r\n }\r\n\r\n this.setTooltipPosition(true);\r\n\r\n setTimeout(() => {\r\n this.linkInput.focus(); // !!! instant focus will break animation\r\n }, 200);\r\n this.linkInput.classList.toggle('is-valid', this.isLinkValid());\r\n }\r\n\r\n private applyLink(e: Event) {\r\n cancelEvent(e);\r\n this.resetSelection();\r\n let url = this.linkInput.value;\r\n if(url && !RichTextProcessor.matchUrlProtocol(url)) {\r\n url = 'https://' + url;\r\n }\r\n this.appImManager.chat.input.applyMarkdown('link', url);\r\n setTimeout(() => {\r\n this.hide();\r\n }, 0);\r\n }\r\n\r\n private isLinkValid() {\r\n return !this.linkInput.value.length || !!RichTextProcessor.matchUrl(this.linkInput.value);\r\n }\r\n\r\n private resetSelection(range: Range = this.savedRange) {\r\n const selection = window.getSelection();\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n this.appImManager.chat.input.messageInput.focus();\r\n }\r\n\r\n public hide() {\r\n //return;\r\n\r\n if(this.init) return;\r\n\r\n this.container.classList.remove('is-visible');\r\n //document.removeEventListener('mouseup', this.onMouseUp);\r\n document.removeEventListener('mouseup', this.onMouseUpSingle);\r\n this.waitingForMouseUp = false;\r\n\r\n appNavigationController.removeByType('markup');\r\n\r\n if(this.hideTimeout) clearTimeout(this.hideTimeout);\r\n this.hideTimeout = window.setTimeout(() => {\r\n this.hideTimeout = undefined;\r\n this.container.classList.add('hide');\r\n this.container.classList.remove('is-link');\r\n }, 200);\r\n }\r\n\r\n public getActiveMarkupButton() {\r\n const nodes = getSelectedNodes();\r\n const parents = [...new Set(nodes.map(node => node.parentNode))];\r\n //if(parents.length > 1 && parents) return [];\r\n\r\n const currentMarkups: Set<HTMLElement> = new Set();\r\n (parents as HTMLElement[]).forEach(node => {\r\n for(const type in markdownTags) {\r\n const tag = markdownTags[type as MarkdownType];\r\n const closest = node.closest(tag.match + ', [contenteditable]');\r\n if(closest !== this.appImManager.chat.input.messageInput) {\r\n currentMarkups.add(this.buttons[type as MarkdownType]);\r\n }\r\n }\r\n });\r\n \r\n\r\n return [...currentMarkups];\r\n }\r\n\r\n public setActiveMarkupButton() {\r\n const activeButtons = this.getActiveMarkupButton();\r\n\r\n for(const i in this.buttons) {\r\n // @ts-ignore\r\n const button = this.buttons[i];\r\n button.classList.toggle('active', activeButtons.includes(button));\r\n }\r\n }\r\n\r\n private setTooltipPosition(isLinkToggle = false) {\r\n const selection = document.getSelection();\r\n const range = selection.getRangeAt(0);\r\n\r\n const bodyRect = document.body.getBoundingClientRect();\r\n const selectionRect = range.getBoundingClientRect();\r\n const inputRect = this.appImManager.chat.input.rowsWrapper.getBoundingClientRect();\r\n\r\n this.container.style.maxWidth = inputRect.width + 'px';\r\n\r\n const selectionTop = selectionRect.top + (bodyRect.top * -1);\r\n \r\n const currentTools = this.container.classList.contains('is-link') ? this.wrapper.lastElementChild : this.wrapper.firstElementChild;\r\n\r\n const sizesRect = currentTools.getBoundingClientRect();\r\n const top = selectionTop - sizesRect.height - 8;\r\n \r\n const minX = inputRect.left;\r\n const maxX = (inputRect.left + inputRect.width) - Math.min(inputRect.width, sizesRect.width);\r\n let left: number;\r\n if(isLinkToggle) {\r\n const containerRect = this.container.getBoundingClientRect();\r\n left = clamp(containerRect.left, minX, maxX);\r\n } else {\r\n const x = selectionRect.left + (selectionRect.width - sizesRect.width) / 2;\r\n left = clamp(x, minX, maxX);\r\n }\r\n\r\n /* const isClamped = x !== minX && x !== maxX && (left === minX || left === maxX || this.container.getBoundingClientRect().left >= maxX);\r\n\r\n if(isLinkToggle && this.container.classList.contains('is-link') && !isClamped) return; */\r\n \r\n this.container.style.transform = `translate3d(${left}px, ${top}px, 0)`;\r\n }\r\n\r\n public show() {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n if(isSelectionEmpty()) {\r\n this.hide();\r\n return;\r\n }\r\n\r\n if(this.hideTimeout !== undefined) {\r\n clearTimeout(this.hideTimeout);\r\n }\r\n\r\n if(this.container.classList.contains('is-visible')) {\r\n return;\r\n }\r\n\r\n this.setActiveMarkupButton();\r\n \r\n this.container.classList.remove('is-link');\r\n const isFirstShow = this.container.classList.contains('hide');\r\n if(isFirstShow) {\r\n this.container.classList.remove('hide');\r\n this.container.classList.add('no-transition');\r\n }\r\n \r\n this.setTooltipPosition();\r\n \r\n if(isFirstShow) {\r\n void this.container.offsetLeft; // reflow\r\n this.container.classList.remove('no-transition');\r\n }\r\n \r\n this.container.classList.add('is-visible');\r\n\r\n if(!IS_MOBILE) {\r\n appNavigationController.pushItem({\r\n type: 'markup',\r\n onPop: () => {\r\n this.hide();\r\n }\r\n });\r\n }\r\n\r\n //this.log('selection', selectionRect, activeButton);\r\n }\r\n\r\n /* private onMouseUp = (e: Event) => {\r\n this.log('onMouseUp');\r\n if(findUpClassName(e.target, 'markup-tooltip')) return;\r\n\r\n this.hide();\r\n //document.removeEventListener('mouseup', this.onMouseUp);\r\n }; */\r\n\r\n private onMouseUpSingle = (e: Event) => {\r\n //this.log('onMouseUpSingle');\r\n this.waitingForMouseUp = false;\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n cancelEvent(e);\r\n if(this.mouseUpCounter++ === 0) {\r\n this.resetSelection(this.savedRange);\r\n } else {\r\n this.hide();\r\n return;\r\n }\r\n }\r\n\r\n this.show();\r\n\r\n /* !isTouchSupported && document.addEventListener('mouseup', this.onMouseUp); */\r\n };\r\n\r\n public setMouseUpEvent() {\r\n if(this.waitingForMouseUp) return;\r\n this.waitingForMouseUp = true;\r\n\r\n //this.log('setMouseUpEvent');\r\n\r\n document.addEventListener('mouseup', this.onMouseUpSingle, {once: true});\r\n }\r\n\r\n public cancelClosening() {\r\n if(IS_TOUCH_SUPPORTED && !IS_APPLE) {\r\n document.removeEventListener('mouseup', this.onMouseUpSingle);\r\n document.addEventListener('mouseup', (e) => {\r\n cancelEvent(e);\r\n this.mouseUpCounter = 1;\r\n this.waitingForMouseUp = false;\r\n this.setMouseUpEvent();\r\n }, {once: true});\r\n }\r\n }\r\n\r\n public handleSelection() {\r\n if(this.addedListener) return;\r\n this.addedListener = true;\r\n document.addEventListener('selectionchange', (e) => {\r\n //this.log('selectionchange');\r\n\r\n if(document.activeElement === this.linkInput) {\r\n return;\r\n }\r\n\r\n if(document.activeElement !== this.appImManager.chat.input.messageInput) {\r\n this.hide();\r\n return;\r\n }\r\n\r\n const selection = document.getSelection();\r\n if(isSelectionEmpty(selection)) {\r\n this.hide();\r\n return;\r\n }\r\n\r\n if(IS_TOUCH_SUPPORTED) {\r\n if(IS_APPLE) {\r\n this.show();\r\n this.setTooltipPosition(); // * because can skip this in .show();\r\n } else {\r\n if(this.mouseUpCounter === 2) {\r\n this.mouseUpCounter = 0;\r\n return;\r\n }\r\n\r\n this.savedRange = selection.getRangeAt(0);\r\n this.setMouseUpEvent();\r\n /* document.addEventListener('touchend', (e) => {\r\n cancelEvent(e);\r\n this.resetSelection(range);\r\n this.show();\r\n }, {once: true, passive: false}); */\r\n }\r\n } else {\r\n this.setMouseUpEvent();\r\n }\r\n });\r\n }\r\n}","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function getSelectedNodes() {\r\n const nodes: Node[] = [];\r\n const selection = window.getSelection();\r\n for(let i = 0; i < selection.rangeCount; ++i) {\r\n const range = selection.getRangeAt(i);\r\n let {startContainer, endContainer} = range;\r\n if(endContainer.nodeType !== 3) endContainer = endContainer.firstChild;\r\n \r\n while(startContainer && startContainer !== endContainer) {\r\n nodes.push(startContainer.nodeType === 3 ? startContainer : startContainer.firstChild);\r\n startContainer = startContainer.nextSibling;\r\n }\r\n \r\n if(nodes[nodes.length - 1] !== endContainer) {\r\n nodes.push(endContainer);\r\n }\r\n }\r\n\r\n // * filter null's due to <br>\r\n return nodes.filter(node => !!node);\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\n// generate a path's arc data parameter\r\n\r\nimport { MOUNT_CLASS_TO } from \"../config/debug\";\r\n\r\n// http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands\r\nfunction arcParameter(rx: number, ry: number, xAxisRotation: number, largeArcFlag: number, sweepFlag: number, x: number, y: number) {\r\n return [rx, ',', ry, ' ',\r\n xAxisRotation, ' ',\r\n largeArcFlag, ',',\r\n sweepFlag, ' ',\r\n x, ',', y ].join('');\r\n}\r\n\r\nexport default function generatePathData(x: number, y: number, width: number, height: number, tl: number, tr: number, br: number, bl: number) {\r\n const data: string[] = [];\r\n\r\n // start point in top-middle of the rectangle\r\n data.push('M' + (x + width / 2) + ',' + y);\r\n\r\n // next we go to the right\r\n data.push('H' + (x + width - tr));\r\n\r\n if(tr > 0) {\r\n // now we draw the arc in the top-right corner\r\n data.push('A' + arcParameter(tr, tr, 0, 0, 1, (x + width), (y + tr)));\r\n }\r\n\r\n // next we go down\r\n data.push('V' + (y + height - br));\r\n\r\n if(br > 0) {\r\n // now we draw the arc in the lower-right corner\r\n data.push('A' + arcParameter(br, br, 0, 0, 1, (x + width - br), (y + height)));\r\n }\r\n\r\n // now we go to the left\r\n data.push('H' + (x + bl));\r\n\r\n if(bl > 0) {\r\n // now we draw the arc in the lower-left corner\r\n data.push('A' + arcParameter(bl, bl, 0, 0, 1, (x + 0), (y + height - bl)));\r\n }\r\n\r\n // next we go up\r\n data.push('V' + (y + tl));\r\n\r\n if(tl > 0) {\r\n // now we draw the arc in the top-left corner\r\n data.push('A' + arcParameter(tl, tl, 0, 0, 1, (x + tl), (y + 0)));\r\n }\r\n\r\n // and we close the path\r\n data.push('Z');\r\n\r\n return data.join(' ');\r\n}\r\n\r\nMOUNT_CLASS_TO.generatePathData = generatePathData;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport generatePathData from \"../../helpers/generatePathData\";\r\nimport { i18n, LangPackKey } from \"../../lib/langPack\";\r\n\r\nexport default class ChatDragAndDrop {\r\n container: HTMLDivElement;\r\n svg: SVGSVGElement;\r\n outlineWrapper: HTMLDivElement;\r\n path: SVGPathElement;\r\n\r\n constructor(appendTo: HTMLElement, private options: {\r\n icon: string,\r\n header: LangPackKey,\r\n subtitle: LangPackKey,\r\n onDrop: (e: DragEvent) => void\r\n }) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('drop', 'z-depth-1');\r\n\r\n this.outlineWrapper = document.createElement('div');\r\n this.outlineWrapper.classList.add('drop-outline-wrapper');\r\n\r\n this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\r\n this.svg.classList.add('drop-outline');\r\n\r\n this.path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r\n this.path.classList.add('drop-outline-path');\r\n\r\n const dropIcon = document.createElement('div');\r\n dropIcon.classList.add('drop-icon', 'tgico-' + options.icon);\r\n\r\n const dropHeader = document.createElement('div');\r\n dropHeader.classList.add('drop-header');\r\n dropHeader.append(i18n(options.header));\r\n\r\n const dropSubtitle = document.createElement('div');\r\n dropSubtitle.classList.add('drop-subtitle');\r\n dropSubtitle.append(i18n(options.subtitle));\r\n\r\n this.svg.append(this.path);\r\n this.outlineWrapper.append(this.svg);\r\n\r\n this.container.append(this.outlineWrapper, dropIcon, dropHeader, dropSubtitle);\r\n appendTo.append(this.container);\r\n\r\n this.container.addEventListener('dragover', this.onDragOver);\r\n this.container.addEventListener('dragleave', this.onDragLeave);\r\n this.container.addEventListener('drop', this.onDrop);\r\n }\r\n\r\n onDragOver = (e: DragEvent) => {\r\n this.container.classList.add('is-dragover');\r\n //SetTransition(this.container, 'is-dragover', true, 500);\r\n };\r\n\r\n onDragLeave = (e: DragEvent) => {\r\n this.container.classList.remove('is-dragover');\r\n //SetTransition(this.container, 'is-dragover', false, 500);\r\n };\r\n\r\n onDrop = (e: DragEvent) => {\r\n this.options.onDrop(e);\r\n };\r\n\r\n destroy() {\r\n delete this.options;\r\n this.container.remove();\r\n this.container.removeEventListener('dragover', this.onDragOver);\r\n this.container.removeEventListener('dragleave', this.onDragLeave);\r\n this.container.removeEventListener('drop', this.onDrop);\r\n }\r\n\r\n setPath() {\r\n const rect = this.outlineWrapper.getBoundingClientRect();\r\n this.svg.setAttributeNS(null, 'preserveAspectRatio', 'none');\r\n this.svg.setAttributeNS(null, 'viewBox', `0 0 ${rect.width} ${rect.height}`);\r\n this.svg.setAttributeNS(null, 'width', `${rect.width}`);\r\n this.svg.setAttributeNS(null, 'height', `${rect.height}`);\r\n\r\n const radius = 10;\r\n //const strokeWidth = 2;\r\n const sizeX = rect.width - radius;\r\n const sizeY = rect.height - radius;\r\n const pos = radius / 2;\r\n const d = generatePathData(pos, pos, sizeX, sizeY, radius, radius, radius, radius);\r\n this.path.setAttributeNS(null, 'd', d);\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { doubleRaf } from \"../schedulers\";\r\n\r\nexport default function disableTransition(elements: HTMLElement[]) {\r\n elements.forEach(el => el.classList.add('no-transition'));\r\n\r\n doubleRaf().then(() => {\r\n elements.forEach(el => el.classList.remove('no-transition'));\r\n });\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nexport enum INTERNAL_LINK_TYPE {\n MESSAGE,\n PRIVATE_POST,\n STICKER_SET,\n JOIN_CHAT\n};\n\nexport type InternalLink = InternalLink.InternalLinkMessage | InternalLink.InternalLinkPrivatePost | InternalLink.InternalLinkStickerSet | InternalLink.InternalLinkJoinChat;\n\nexport namespace InternalLink {\n export interface InternalLinkMessage {\n _: INTERNAL_LINK_TYPE.MESSAGE,\n domain: string,\n post?: string,\n comment?: string\n }\n\n export interface InternalLinkPrivatePost {\n _: INTERNAL_LINK_TYPE.PRIVATE_POST,\n channel: string,\n post: string,\n thread?: string,\n comment?: string\n }\n\n export interface InternalLinkStickerSet {\n _: INTERNAL_LINK_TYPE.STICKER_SET,\n set: string\n }\n\n export interface InternalLinkJoinChat {\n _: INTERNAL_LINK_TYPE.JOIN_CHAT,\n invite: string\n }\n}\n\nexport type InternalLinkTypeMap = {\n [INTERNAL_LINK_TYPE.MESSAGE]: InternalLink.InternalLinkMessage,\n [INTERNAL_LINK_TYPE.PRIVATE_POST]: InternalLink.InternalLinkPrivatePost,\n [INTERNAL_LINK_TYPE.STICKER_SET]: InternalLink.InternalLinkStickerSet,\n [INTERNAL_LINK_TYPE.JOIN_CHAT]: InternalLink.InternalLinkJoinChat\n};\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport PopupElement, { addCancelButton } from \".\";\r\nimport { ChatInvite, Updates } from \"../../layer\";\r\nimport apiUpdatesManager from \"../../lib/appManagers/apiUpdatesManager\";\r\nimport appAvatarsManager from \"../../lib/appManagers/appAvatarsManager\";\r\nimport appPhotosManager from \"../../lib/appManagers/appPhotosManager\";\r\nimport { i18n } from \"../../lib/langPack\";\r\nimport apiManager from \"../../lib/mtproto/mtprotoworker\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport AvatarElement from \"../avatar\";\r\nimport { wrapPhoto } from \"../wrappers\";\r\n\r\n// const FAKE_CHAT_ID = Number.MAX_SAFE_INTEGER - 0x1000;\r\n\r\nexport default class PopupJoinChatInvite extends PopupElement {\r\n constructor(hash: string, chatInvite: ChatInvite.chatInvite) {\r\n super('popup-join-chat-invite', addCancelButton([{\r\n langKey: chatInvite.pFlags.broadcast ? 'JoinByPeekChannelTitle' : 'JoinByPeekGroupTitle',\r\n callback: () => {\r\n apiManager.invokeApi('messages.importChatInvite', {hash})\r\n .then((updates) => {\r\n apiUpdatesManager.processUpdateMessage(updates);\r\n const chat = (updates as Updates.updates).chats[0];\r\n const peerId = -chat.id;\r\n rootScope.dispatchEvent('history_focus', {peerId});\r\n });\r\n }\r\n }]), {closable: true, overlayClosable: true, body: true});\r\n\r\n this.header.remove();\r\n\r\n /* const fakeChat: Chat.channel | Chat.chat = {\r\n _: chatInvite.pFlags.channel ? 'channel' : 'chat',\r\n id: FAKE_CHAT_ID,\r\n title: chatInvite.title,\r\n photo: chatInvite.photo as any,\r\n date: Date.now() / 1000 | 0,\r\n version: 0,\r\n participants_count: chatInvite.participants_count,\r\n pFlags: chatInvite.pFlags as any\r\n };\r\n\r\n appChatsManager.saveApiChat(fakeChat); */\r\n \r\n const avatarElem = new AvatarElement();\r\n avatarElem.setAttribute('dialog', '0');\r\n avatarElem.classList.add('avatar-100');\r\n if(chatInvite.photo._ === 'photo') {\r\n chatInvite.photo = appPhotosManager.savePhoto(chatInvite.photo);\r\n wrapPhoto({\r\n container: avatarElem,\r\n message: null,\r\n photo: chatInvite.photo,\r\n boxHeight: 100,\r\n boxWidth: 100,\r\n withoutPreloader: true\r\n });\r\n avatarElem.style.width = avatarElem.style.height = '';\r\n } else {\r\n appAvatarsManager.putPhoto(avatarElem, -0, false, chatInvite.title);\r\n }\r\n\r\n const title = document.createElement('div');\r\n title.classList.add('chat-title');\r\n title.innerHTML = RichTextProcessor.wrapEmojiText(chatInvite.title);\r\n //avatarElem.setAttribute('peer', '' + -fakeChat.id);\r\n \r\n const isBroadcast = chatInvite.pFlags.broadcast;\r\n const peopleCount = i18n(isBroadcast ? 'Subscribers' : 'Members', [chatInvite.participants_count]);\r\n peopleCount.classList.add('chat-participants-count');\r\n\r\n this.body.append(avatarElem, title, peopleCount);\r\n }\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\n//import apiManager from '../mtproto/apiManager';\nimport animationIntersector from '../../components/animationIntersector';\nimport appSidebarLeft, { LEFT_COLUMN_ACTIVE_CLASSNAME } from \"../../components/sidebarLeft\";\nimport appSidebarRight, { RIGHT_COLUMN_ACTIVE_CLASSNAME } from '../../components/sidebarRight';\nimport mediaSizes, { ScreenSize } from '../../helpers/mediaSizes';\nimport { logger, LogTypes } from \"../logger\";\nimport apiManager from '../mtproto/mtprotoworker';\nimport rootScope from '../rootScope';\nimport apiUpdatesManager from './apiUpdatesManager';\nimport appUsersManager from \"./appUsersManager\";\nimport Chat, { ChatType } from '../../components/chat/chat';\nimport appChatsManager from './appChatsManager';\nimport appDocsManager from './appDocsManager';\nimport appInlineBotsManager from './appInlineBotsManager';\nimport appMessagesManager from './appMessagesManager';\nimport appPeersManager from './appPeersManager';\nimport appPhotosManager from './appPhotosManager';\nimport appProfileManager from './appProfileManager';\nimport appStickersManager from './appStickersManager';\nimport appWebPagesManager from './appWebPagesManager';\nimport PopupNewMedia from '../../components/popups/newMedia';\nimport MarkupTooltip from '../../components/chat/markupTooltip';\nimport { IS_TOUCH_SUPPORTED } from '../../environment/touchSupport';\nimport appPollsManager from './appPollsManager';\nimport SetTransition from '../../components/singleTransition';\nimport ChatDragAndDrop from '../../components/chat/dragAndDrop';\nimport { doubleRaf } from '../../helpers/schedulers';\nimport lottieLoader from '../lottieLoader';\nimport useHeavyAnimationCheck, { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';\nimport appDraftsManager from './appDraftsManager';\nimport serverTimeManager from '../mtproto/serverTimeManager';\nimport stateStorage from '../stateStorage';\nimport appDownloadManager from './appDownloadManager';\nimport { AppStateManager } from './appStateManager';\nimport { MOUNT_CLASS_TO } from '../../config/debug';\nimport appNavigationController from '../../components/appNavigationController';\nimport appNotificationsManager from './appNotificationsManager';\nimport AppPrivateSearchTab from '../../components/sidebarRight/tabs/search';\nimport { i18n, LangPackKey } from '../langPack';\nimport { ChatInvite, Dialog, SendMessageAction } from '../../layer';\nimport { hslaStringToHex } from '../../helpers/color';\nimport { copy, getObjectKeysAndSort } from '../../helpers/object';\nimport { getFilesFromEvent } from '../../helpers/files';\nimport PeerTitle from '../../components/peerTitle';\nimport PopupPeer from '../../components/popups/peer';\nimport { SliceEnd } from '../../helpers/slicedArray';\nimport blurActiveElement from '../../helpers/dom/blurActiveElement';\nimport { cancelEvent } from '../../helpers/dom/cancelEvent';\nimport disableTransition from '../../helpers/dom/disableTransition';\nimport placeCaretAtEnd from '../../helpers/dom/placeCaretAtEnd';\nimport replaceContent from '../../helpers/dom/replaceContent';\nimport whichChild from '../../helpers/dom/whichChild';\nimport appEmojiManager from './appEmojiManager';\nimport PopupElement from '../../components/popups';\nimport singleInstance from '../mtproto/singleInstance';\nimport PopupStickers from '../../components/popups/stickers';\nimport PopupJoinChatInvite from '../../components/popups/joinChatInvite';\nimport { toast, toastNew } from '../../components/toast';\nimport debounce from '../../helpers/schedulers/debounce';\nimport { pause } from '../../helpers/schedulers/pause';\nimport appMessagesIdsManager from './appMessagesIdsManager';\nimport { InternalLink, InternalLinkTypeMap, INTERNAL_LINK_TYPE } from './internalLink';\nimport RichTextProcessor from '../richtextprocessor';\nimport MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';\n\n//console.log('appImManager included33!');\n\nappSidebarLeft; // just to include\n\nexport const CHAT_ANIMATION_GROUP = 'chat';\nconst FOCUS_EVENT_NAME = IS_TOUCH_SUPPORTED ? 'touchstart' : 'mousemove';\n\nexport type ChatSavedPosition = {\n mids: number[], \n top: number\n};\n\nexport class AppImManager {\n public columnEl = document.getElementById('column-center') as HTMLDivElement;\n public chatsContainer: HTMLElement;\n\n public offline = false;\n public updateStatusInterval = 0;\n\n public log: ReturnType<typeof logger>;\n\n public setPeerPromise: Promise<void> = null;\n\n public tabId = -1;\n \n public chats: Chat[] = [];\n private prevTab: HTMLElement;\n private chatsSelectTabDebounced: () => void;\n \n public markupTooltip: MarkupTooltip;\n private backgroundPromises: {[slug: string]: Promise<string>} = {};\n\n get myId() {\n return rootScope.myId;\n }\n\n get chat(): Chat {\n return this.chats[this.chats.length - 1];\n }\n\n constructor() {\n apiUpdatesManager.attach();\n appNotificationsManager.start();\n\n this.log = logger('IM', LogTypes.Log | LogTypes.Warn | LogTypes.Debug | LogTypes.Error);\n\n this.selectTab(0);\n \n window.addEventListener('blur', () => {\n animationIntersector.checkAnimations(true);\n \n this.offline = rootScope.idle.isIDLE = true;\n this.updateStatus();\n clearInterval(this.updateStatusInterval);\n rootScope.dispatchEvent('idle', rootScope.idle.isIDLE);\n \n window.addEventListener('focus', () => {\n this.offline = rootScope.idle.isIDLE = false;\n this.updateStatus();\n this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);\n \n // в обратном порядке\n animationIntersector.checkAnimations(false);\n\n rootScope.dispatchEvent('idle', rootScope.idle.isIDLE);\n }, {once: true});\n });\n\n // * Prevent setting online after reloading page\n window.addEventListener(FOCUS_EVENT_NAME, () => {\n this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);\n this.updateStatus();\n\n this.offline = rootScope.idle.isIDLE = false;\n rootScope.dispatchEvent('idle', rootScope.idle.isIDLE);\n }, {once: true, passive: true});\n\n this.chatsContainer = document.createElement('div');\n this.chatsContainer.classList.add('chats-container', 'tabs-container');\n this.chatsContainer.dataset.animation = 'navigation';\n\n this.columnEl.append(this.chatsContainer);\n \n this.createNewChat();\n this.chatsSelectTab(this.chat.container);\n\n appNavigationController.onHashChange = this.onHashChange;\n //window.addEventListener('hashchange', this.onHashChange);\n\n this.setSettings();\n rootScope.addEventListener('settings_updated', this.setSettings);\n\n useHeavyAnimationCheck(() => {\n animationIntersector.setOnlyOnePlayableGroup('lock');\n animationIntersector.checkAnimations(true);\n }, () => {\n animationIntersector.setOnlyOnePlayableGroup('');\n animationIntersector.checkAnimations(false);\n });\n\n this.applyCurrentTheme();\n\n // * fix simultaneous opened both sidebars, can happen when floating sidebar is opened with left sidebar\n mediaSizes.addEventListener('changeScreen', (from, to) => {\n if(document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME) \n && document.body.classList.contains(RIGHT_COLUMN_ACTIVE_CLASSNAME)) {\n appSidebarRight.toggleSidebar(false);\n }\n });\n\n rootScope.addEventListener('history_focus', (e) => {\n let {peerId, threadId, mid} = e;\n if(threadId) threadId = appMessagesIdsManager.generateMessageId(threadId);\n if(mid) mid = appMessagesIdsManager.generateMessageId(mid); // because mid can come from notification, i.e. server message id\n \n this.setInnerPeer(peerId, mid, threadId ? 'discussion' : undefined, threadId);\n });\n\n rootScope.addEventListener('peer_changing', (chat) => {\n this.saveChatPosition(chat);\n });\n\n rootScope.addEventListener('theme_change', () => {\n this.applyCurrentTheme();\n });\n\n rootScope.addEventListener('instance_deactivated', () => {\n const popup = new PopupElement('popup-instance-deactivated', undefined, {overlayClosable: true});\n const c = document.createElement('div');\n c.classList.add('instance-deactivated-container');\n (popup as any).container.replaceWith(c);\n\n const header = document.createElement('div');\n header.classList.add('header');\n header.append(i18n('Deactivated.Title'));\n\n const subtitle = document.createElement('div');\n subtitle.classList.add('subtitle');\n subtitle.append(i18n('Deactivated.Subtitle'));\n\n c.append(header, subtitle);\n\n document.body.classList.add('deactivated');\n\n (popup as any).onClose = () => {\n document.body.classList.add('deactivated-backwards');\n\n singleInstance.activateInstance();\n\n setTimeout(() => {\n document.body.classList.remove('deactivated', 'deactivated-backwards');\n }, 333);\n };\n\n popup.show();\n });\n\n stateStorage.get('chatPositions').then((c) => {\n stateStorage.setToCache('chatPositions', c || {});\n });\n\n // ! do not remove this line \n // ! instance can be deactivated before the UI starts, because it waits in background for RAF that is delayed\n singleInstance.activateInstance();\n\n this.addAnchorListener<{}>({\n name: 'showMaskedAlert', \n callback: (params, element) => {\n const href = element.href;\n\n const a = element.cloneNode(true) as HTMLAnchorElement;\n a.className = 'anchor-url';\n a.innerText = href;\n a.removeAttribute('onclick');\n\n new PopupPeer('popup-masked-url', {\n titleLangKey: 'OpenUrlTitle',\n descriptionLangKey: 'OpenUrlAlert2',\n descriptionLangArgs: [a],\n buttons: [{\n langKey: 'Open',\n callback: () => {\n a.click();\n },\n }]\n }).show();\n }\n });\n\n this.addAnchorListener<{uriParams: {command: string, bot: string}}>({\n name: 'execBotCommand', \n callback: ({uriParams}) => {\n const {command, bot} = uriParams;\n\n /* const promise = bot ? this.openUsername(bot).then(() => this.chat.peerId) : Promise.resolve(this.chat.peerId);\n promise.then(peerId => {\n appMessagesManager.sendText(peerId, '/' + command);\n }); */\n\n appMessagesManager.sendText(this.chat.peerId, '/' + command + (bot ? '@' + bot : ''));\n\n //console.log(command, bot);\n }\n });\n\n this.addAnchorListener<{uriParams: {hashtag: string}}>({\n name: 'searchByHashtag', \n callback: ({uriParams}) => {\n const {hashtag} = uriParams;\n if(!hashtag) {\n return;\n }\n\n this.chat.initSearch('#' + hashtag + ' ');\n }\n });\n\n this.addAnchorListener<{pathnameParams: ['addstickers', string]}>({\n name: 'addstickers', \n callback: ({pathnameParams}) => {\n const link: InternalLink = {\n _: INTERNAL_LINK_TYPE.STICKER_SET,\n set: pathnameParams[1]\n };\n\n this.processInternalLink(link);\n }\n });\n\n this.addAnchorListener<{pathnameParams: ['joinchat', string]}>({\n name: 'joinchat', \n callback: ({pathnameParams}) => {\n const link: InternalLink = {\n _: INTERNAL_LINK_TYPE.JOIN_CHAT,\n invite: pathnameParams[1]\n };\n\n this.processInternalLink(link);\n }\n });\n\n this.addAnchorListener<{\n // pathnameParams: ['c', string, string],\n // uriParams: {thread?: number}\n // } | {\n // pathnameParams: [string, string?],\n // uriParams: {comment?: number}\n pathnameParams: ['c', string, string] | [string, string?],\n uriParams: {thread?: string, comment?: string} | {comment?: string}\n }>({\n name: 'im',\n callback: async({pathnameParams, uriParams}) => {\n let link: InternalLink;\n if(pathnameParams[0] === 'c') {\n link = {\n _: INTERNAL_LINK_TYPE.PRIVATE_POST,\n channel: pathnameParams[1],\n post: pathnameParams[2],\n thread: 'thread' in uriParams ? uriParams.thread : undefined,\n comment: uriParams.comment\n };\n } else {\n link = {\n _: INTERNAL_LINK_TYPE.MESSAGE,\n domain: pathnameParams[0],\n post: pathnameParams[1],\n comment: uriParams.comment\n };\n }\n\n this.processInternalLink(link);\n }\n });\n\n this.addAnchorListener<{\n uriParams: {\n domain: string,\n\n // telegrampassport\n scope?: string,\n nonce?: string,\n payload?: string,\n bot_id?: string,\n public_key?: string,\n callback_url?: string,\n\n // regular\n start?: string,\n startgroup?: string,\n game?: string,\n voicechat?: string,\n post?: string,\n thread?: string,\n comment?: string\n }\n }>({\n name: 'resolve',\n protocol: 'tg',\n callback: ({uriParams}) => {\n let link: InternalLink;\n if(uriParams.domain === 'telegrampassport') {\n\n } else {\n link = this.makeLink(INTERNAL_LINK_TYPE.MESSAGE, uriParams);\n }\n\n this.processInternalLink(link);\n }\n });\n\n this.addAnchorListener<{\n uriParams: {\n channel: string,\n post: string,\n thread?: string,\n comment?: string\n }\n }>({\n name: 'privatepost',\n protocol: 'tg',\n callback: ({uriParams}) => {\n const link = this.makeLink(INTERNAL_LINK_TYPE.PRIVATE_POST, uriParams);\n this.processInternalLink(link);\n }\n });\n\n this.addAnchorListener<{\n uriParams: {\n set: string\n }\n }>({\n name: 'addstickers',\n protocol: 'tg',\n callback: ({uriParams}) => {\n const link = this.makeLink(INTERNAL_LINK_TYPE.STICKER_SET, uriParams);\n this.processInternalLink(link);\n }\n });\n\n this.addAnchorListener<{\n uriParams: {\n invite: string\n }\n }>({\n name: 'joinchat',\n protocol: 'tg',\n callback: ({uriParams}) => {\n const link = this.makeLink(INTERNAL_LINK_TYPE.JOIN_CHAT, uriParams);\n this.processInternalLink(link);\n }\n });\n\n this.onHashChange();\n this.attachKeydownListener();\n }\n\n private attachKeydownListener() {\n const IGNORE_KEYS = new Set(['PageUp', 'PageDown', 'Meta', 'Control']);\n const onKeyDown = (e: KeyboardEvent) => {\n if(rootScope.isOverlayActive || IGNORE_KEYS.has(e.key)) return;\n \n const target = e.target as HTMLElement;\n \n //if(target.tagName === 'INPUT') return;\n \n //this.log('onkeydown', e, document.activeElement);\n\n const chat = this.chat;\n\n if(e.code === 'KeyC' && (e.ctrlKey || e.metaKey) && target.tagName !== 'INPUT') {\n return;\n } else if(e.altKey && (e.code === 'ArrowUp' || e.code === 'ArrowDown')) {\n const folder = appMessagesManager.dialogsStorage.getFolder(rootScope.filterId, true);\n let nextDialog: Dialog.dialog;\n if(!rootScope.peerId) {\n if(e.code === 'ArrowDown') {\n nextDialog = folder[0];\n }\n } else {\n const idx = folder.findIndex(dialog => dialog.peerId === rootScope.peerId);\n if(idx !== -1) {\n const nextIndex = e.code === 'ArrowUp' ? idx - 1 : idx + 1;\n nextDialog = folder[nextIndex];\n }\n }\n \n if(nextDialog) {\n this.setPeer(nextDialog.peerId);\n }\n } else if(e.code === 'ArrowUp') {\n if(!chat.input.editMsgId && chat.input.isInputEmpty()) {\n const historyStorage = appMessagesManager.getHistoryStorage(chat.peerId, chat.threadId);\n const slice = historyStorage.history.slice;\n if(slice.isEnd(SliceEnd.Bottom) && slice.length) {\n let goodMid: number;\n for(const mid of slice) {\n const message = chat.getMessage(mid);\n const good = this.myId === chat.peerId ? message.fromId === this.myId : message.pFlags.out;\n\n if(good) {\n if(appMessagesManager.canEditMessage(chat.getMessage(mid), 'text')) {\n goodMid = mid;\n break;\n }\n\n // * this check will allow editing only last message\n //break;\n }\n }\n \n if(goodMid) {\n chat.input.initMessageEditing(goodMid);\n cancelEvent(e); // * prevent from scrolling\n }\n }\n } else {\n return;\n }\n } else if(e.code === 'ArrowDown') {\n return;\n }\n \n if(chat.input.messageInput && \n e.target !== chat.input.messageInput && \n target.tagName !== 'INPUT' && \n !target.hasAttribute('contenteditable') && \n !IS_TOUCH_SUPPORTED && \n (!mediaSizes.isMobile || this.tabId === 1) && \n !this.chat.selection.isSelecting && \n !this.chat.input.recording) {\n chat.input.messageInput.focus();\n placeCaretAtEnd(chat.input.messageInput);\n }\n };\n \n document.body.addEventListener('keydown', onKeyDown);\n }\n\n private makeLink<T extends INTERNAL_LINK_TYPE>(type: T, uriParams: Omit<InternalLinkTypeMap[T], '_'>) {\n return {\n _: type,\n ...uriParams\n } as any as InternalLinkTypeMap[T];\n }\n\n public async processInternalLink(link: InternalLink) {\n switch(link?._) {\n case INTERNAL_LINK_TYPE.MESSAGE: {\n const postId = link.post ? appMessagesIdsManager.generateMessageId(+link.post) : undefined;\n const commentId = link.comment ? appMessagesIdsManager.generateMessageId(+link.comment) : undefined;\n\n this.openUsername(link.domain, postId, undefined, commentId);\n break;\n }\n\n case INTERNAL_LINK_TYPE.PRIVATE_POST: {\n const peerId = -+link.channel;\n\n const chat = appChatsManager.getChat(-peerId);\n if(chat.deleted) {\n try {\n await appChatsManager.resolveChannel(-peerId);\n } catch(err) {\n toastNew({langPackKey: 'LinkNotFound'});\n throw err;\n }\n }\n\n const postId = appMessagesIdsManager.generateMessageId(+link.post);\n const threadId = link.thread ? appMessagesIdsManager.generateMessageId(+link.thread) : undefined;\n\n if(threadId) this.openThread(peerId, postId, threadId);\n else this.setInnerPeer(peerId, postId);\n break;\n }\n\n case INTERNAL_LINK_TYPE.STICKER_SET: {\n new PopupStickers({id: link.set}).show();\n break;\n }\n\n case INTERNAL_LINK_TYPE.JOIN_CHAT: {\n apiManager.invokeApi('messages.checkChatInvite', {\n hash: link.invite\n }).then(chatInvite => {\n if((chatInvite as ChatInvite.chatInvitePeek).chat) {\n appChatsManager.saveApiChat((chatInvite as ChatInvite.chatInvitePeek).chat, true);\n }\n\n // console.log(chatInvite);\n\n if(chatInvite._ === 'chatInviteAlready' ||\n chatInvite._ === 'chatInvitePeek'/* && chatInvite.expires > tsNow(true) */) {\n this.setInnerPeer(-chatInvite.chat.id);\n return;\n }\n\n new PopupJoinChatInvite(link.invite, chatInvite).show();\n }, (err) => {\n if(err.type === 'INVITE_HASH_EXPIRED') {\n toast(i18n('InviteExpired'));\n }\n });\n break;\n }\n\n default: {\n this.log.warn('Not supported internal link:', link);\n break;\n }\n }\n }\n\n private addAnchorListener<Params extends {pathnameParams?: any, uriParams?: any}>(options: {\n name: 'showMaskedAlert' | 'execBotCommand' | 'searchByHashtag' | 'addstickers' | 'joinchat' | 'im' |\n 'resolve' | 'privatepost' | 'addstickers', \n protocol?: 'tg',\n callback: (params: Params, element?: HTMLAnchorElement) => boolean | any, \n noPathnameParams?: boolean,\n noUriParams?: boolean\n }) {\n (window as any)[(options.protocol ? options.protocol + '_' : '') + options.name] = (element?: HTMLAnchorElement/* , e: Event */) => {\n cancelEvent(null);\n\n const href = element.href;\n let pathnameParams: any[];\n let uriParams: any;\n\n if(!options.noPathnameParams) pathnameParams = new URL(element.href).pathname.split('/').slice(1);\n if(!options.noUriParams) uriParams = this.parseUriParams(href);\n\n const res = options.callback({pathnameParams, uriParams} as Params, element);\n return res === undefined ? res : false;\n };\n }\n\n private parseUriParams(uri: string, splitted = uri.split('?')) {\n const params: any = {};\n if(!splitted[1]) return params;\n splitted[1].split('&').forEach(item => {\n params[item.split('=')[0]] = decodeURIComponent(item.split('=')[1]);\n });\n\n return params;\n }\n\n private onHashChange = () => {\n const hash = location.hash;\n const splitted = hash.split('?');\n\n const params = this.parseUriParams(hash, splitted);\n\n this.log('hashchange', hash, splitted[0], params);\n\n if(params.tgaddr) {\n appNavigationController.replaceState();\n const {onclick} = RichTextProcessor.wrapUrl(params.tgaddr);\n if(onclick) {\n const a = document.createElement('a');\n a.href = params.tgaddr;\n (window as any)[onclick](a);\n }\n return;\n }\n\n switch(splitted[0]) {\n case '#/im': {\n const p = params.p;\n let postId = params.post !== undefined ? appMessagesIdsManager.generateMessageId(+params.post) : undefined;\n\n switch(p[0]) {\n case '@': {\n this.openUsername(p, postId);\n break;\n }\n\n default: { // peerId\n this.setInnerPeer(postId ? -+p : +p, postId);\n break;\n }\n }\n }\n }\n\n //appNavigationController.replaceState();\n //location.hash = '';\n };\n\n public openUsername(username: string, msgId?: number, threadId?: number, commentId?: number) {\n return appUsersManager.resolveUsername(username).then(peer => {\n const isUser = peer._ === 'user';\n const peerId = isUser ? peer.id : -peer.id;\n\n if(threadId) return this.openThread(peerId, msgId, threadId);\n else if(commentId) return this.openComment(peerId, msgId, commentId);\n else return this.setInnerPeer(peerId, msgId);\n }, (err) => {\n if(err.type === 'USERNAME_NOT_OCCUPIED') {\n toastNew({langPackKey: 'NoUsernameFound'});\n } else if(err.type === 'USERNAME_INVALID') {\n toastNew({langPackKey: 'Alert.UserDoesntExists'});\n }\n });\n }\n\n /**\n * Opens thread when peerId of discussion group is known\n */\n public openThread(peerId: number, lastMsgId: number, threadId: number) {\n return appMessagesManager.wrapSingleMessage(peerId, threadId).then(() => {\n const message = appMessagesManager.getMessageByPeer(peerId, threadId);\n appMessagesManager.generateThreadServiceStartMessage(message);\n\n return this.setInnerPeer(peerId, lastMsgId, 'discussion', threadId);\n });\n }\n\n /**\n * Opens comment directly from original channel\n */\n public openComment(peerId: number, msgId: number, commentId: number) {\n return appMessagesManager.getDiscussionMessage(peerId, msgId).then(message => {\n return this.openThread(message.peerId, commentId, message.mid);\n });\n }\n\n public setCurrentBackground(broadcastEvent = false) {\n const theme = rootScope.getTheme();\n\n if(theme.background.type === 'image' || (theme.background.type === 'default' && theme.background.slug)) {\n const defaultTheme = AppStateManager.STATE_INIT.settings.themes.find(t => t.name === theme.name);\n const isDefaultBackground = theme.background.blur === defaultTheme.background.blur && \n theme.background.slug === defaultTheme.background.slug;\n\n if(!isDefaultBackground) {\n return this.getBackground(theme.background.slug).then((url) => {\n return this.setBackground(url, broadcastEvent);\n }, () => { // * if NO_ENTRY_FOUND\n theme.background = copy(defaultTheme.background); // * reset background\n return this.setBackground('', true);\n });\n }\n }\n \n return this.setBackground('', broadcastEvent);\n }\n\n private getBackground(slug: string) {\n if(this.backgroundPromises[slug]) return this.backgroundPromises[slug];\n return this.backgroundPromises[slug] = appDownloadManager.cacheStorage.getFile('backgrounds/' + slug).then(blob => {\n return URL.createObjectURL(blob);\n });\n }\n\n public setBackground(url: string, broadcastEvent = true): Promise<void> {\n const promises = this.chats.map(chat => chat.setBackground(url));\n return promises[promises.length - 1].then(() => {\n if(broadcastEvent) {\n rootScope.dispatchEvent('background_change');\n }\n });\n }\n\n public saveChatPosition(chat: Chat) {\n if(!(['chat', 'discussion'] as ChatType[]).includes(chat.type) || !chat.peerId) {\n return;\n }\n\n //const bubble = chat.bubbles.getBubbleByPoint('top');\n //if(bubble) {\n //const top = bubble.getBoundingClientRect().top;\n const chatBubbles = chat.bubbles;\n const top = chatBubbles.scrollable.scrollTop;\n\n const key = chat.peerId + (chat.threadId ? '_' + chat.threadId : '');\n\n const chatPositions = stateStorage.getFromCache('chatPositions');\n if(!(chatBubbles.scrollable.getDistanceToEnd() <= 16 && chatBubbles.scrollable.loadedAll.bottom) && Object.keys(chatBubbles.bubbles).length) {\n const position = {\n mids: getObjectKeysAndSort(chatBubbles.bubbles, 'desc'),\n top\n };\n\n chatPositions[key] = position;\n\n this.log('saved chat position:', position);\n } else {\n delete chatPositions[key];\n\n this.log('deleted chat position');\n }\n\n stateStorage.set({chatPositions}, true);\n //}\n }\n\n public getChatSavedPosition(chat: Chat): ChatSavedPosition {\n if(!(['chat', 'discussion'] as ChatType[]).includes(chat.type) || !chat.peerId) {\n return;\n }\n \n const key = chat.peerId + (chat.threadId ? '_' + chat.threadId : '');\n const cache = stateStorage.getFromCache('chatPositions');\n return cache && cache[key];\n }\n\n public applyHighlightningColor() {\n let hsla: string;\n const theme = rootScope.getTheme();\n if(theme.background.highlightningColor) {\n hsla = theme.background.highlightningColor;\n document.documentElement.style.setProperty('--message-highlightning-color', hsla);\n } else {\n document.documentElement.style.removeProperty('--message-highlightning-color');\n }\n\n if(!IS_TOUCH_SUPPORTED && hsla) {\n rootScope.themeColor = hslaStringToHex(hsla);\n }\n }\n\n public applyCurrentTheme(slug?: string, backgroundUrl?: string, broadcastEvent?: boolean) {\n this.applyHighlightningColor();\n\n rootScope.setTheme();\n\n if(backgroundUrl) {\n this.backgroundPromises[slug] = Promise.resolve(backgroundUrl);\n }\n \n return this.setCurrentBackground(broadcastEvent === undefined ? !!slug : broadcastEvent);\n }\n\n private setSettings = () => {\n document.documentElement.style.setProperty('--messages-text-size', rootScope.settings.messagesTextSize + 'px');\n \n document.body.classList.toggle('animation-level-0', !rootScope.settings.animationsEnabled);\n document.body.classList.toggle('animation-level-1', false);\n document.body.classList.toggle('animation-level-2', rootScope.settings.animationsEnabled);\n\n this.chatsSelectTabDebounced = debounce(() => {\n const topbar = this.chat.topbar;\n if(topbar.pinnedMessage) { // * буду молиться богам, чтобы это ничего не сломало, но это исправляет получение пиннеда после анимации\n topbar.pinnedMessage.setCorrectIndex(0);\n }\n\n apiManager.setQueueId(this.chat.bubbles.lazyLoadQueue.queueId);\n }, rootScope.settings.animationsEnabled ? 250 : 0, false, true);\n\n lottieLoader.setLoop(rootScope.settings.stickers.loop);\n animationIntersector.checkAnimations(false);\n \n for(const chat of this.chats) {\n chat.setAutoDownloadMedia();\n }\n };\n\n // * не могу использовать тут TransitionSlider, так как мне нужен отрисованный блок рядом \n // * (или под текущим чатом) чтобы правильно отрендерить чат (напр. scrollTop)\n private chatsSelectTab(tab: HTMLElement, animate?: boolean) {\n if(this.prevTab === tab) {\n return;\n }\n\n if(animate === false && this.prevTab) { // * will be used for Safari iOS history swipe\n disableTransition([tab, this.prevTab].filter(Boolean));\n }\n\n if(this.prevTab) {\n this.prevTab.classList.remove('active');\n this.chatsSelectTabDebounced();\n\n // ! нужно переделать на animation, так как при лаге анимация будет длиться не 250мс\n if(rootScope.settings.animationsEnabled && animate !== false) { \n dispatchHeavyAnimationEvent(pause(250 + 150), 250 + 150);\n }\n\n const prevIdx = whichChild(this.prevTab);\n const idx = whichChild(tab);\n if(idx > prevIdx) {\n appNavigationController.pushItem({\n type: 'chat', \n onPop: (canAnimate) => {\n this.setPeer(0, undefined, canAnimate);\n blurActiveElement();\n }\n });\n }\n }\n\n tab.classList.add('active');\n this.prevTab = tab;\n }\n\n private init() {\n document.addEventListener('paste', this.onDocumentPaste, true);\n \n if(!IS_TOUCH_SUPPORTED) {\n this.attachDragAndDropListeners();\n }\n\n //if(!isTouchSupported) {\n this.markupTooltip = new MarkupTooltip(this);\n this.markupTooltip.handleSelection();\n //}\n }\n\n private attachDragAndDropListeners() {\n const drops: ChatDragAndDrop[] = [];\n let mounted = false;\n const toggle = async(e: DragEvent, mount: boolean) => {\n if(mount === mounted) return;\n\n const _types = e.dataTransfer.types;\n // @ts-ignore\n const isFiles = _types.contains ? _types.contains('Files') : _types.indexOf('Files') >= 0;\n\n if(!isFiles || !this.canDrag()) { // * skip dragging text case\n counter = 0;\n return;\n }\n\n if(mount && !drops.length) {\n const types: string[] = await getFilesFromEvent(e, true);\n const force = isFiles && !types.length; // * can't get file items not from 'drop' on Safari\n \n const foundMedia = types.filter(t => MEDIA_MIME_TYPES_SUPPORTED.has(t)).length;\n const foundDocuments = types.length - foundMedia;\n \n this.log('drag files', types);\n \n if(types.length || force) {\n drops.push(new ChatDragAndDrop(dropsContainer, {\n icon: 'dragfiles',\n header: 'Chat.DropTitle',\n subtitle: 'Chat.DropAsFilesDesc',\n onDrop: (e: DragEvent) => {\n toggle(e, false);\n appImManager.log('drop', e);\n appImManager.onDocumentPaste(e, 'document');\n }\n }));\n }\n \n if((foundMedia && !foundDocuments) || force) {\n drops.push(new ChatDragAndDrop(dropsContainer, {\n icon: 'dragmedia',\n header: 'Chat.DropTitle',\n subtitle: 'Chat.DropQuickDesc',\n onDrop: (e: DragEvent) => {\n toggle(e, false);\n appImManager.log('drop', e);\n appImManager.onDocumentPaste(e, 'media');\n }\n }));\n }\n \n this.chat.container.append(dropsContainer);\n }\n\n //if(!mount) return;\n\n SetTransition(dropsContainer, 'is-visible', mount, 200, () => {\n if(!mount) {\n drops.forEach(drop => {\n drop.destroy();\n });\n\n drops.length = 0;\n }\n });\n\n if(mount) {\n drops.forEach(drop => {\n drop.setPath();\n });\n } else {\n counter = 0;\n }\n\n document.body.classList.toggle('is-dragging', mount);\n mounted = mount;\n };\n\n /* document.body.addEventListener('dragover', (e) => {\n cancelEvent(e);\n }); */\n\n let counter = 0;\n document.body.addEventListener('dragenter', (e) => {\n counter++;\n });\n\n document.body.addEventListener('dragover', (e) => {\n //this.log('dragover', e/* , e.dataTransfer.types[0] */);\n toggle(e, true);\n cancelEvent(e);\n });\n\n document.body.addEventListener('dragleave', (e) => {\n //this.log('dragleave', e, counter);\n //if((e.pageX <= 0 || e.pageX >= appPhotosManager.windowW) || (e.pageY <= 0 || e.pageY >= appPhotosManager.windowH)) {\n counter--;\n if(counter === 0) { \n //if(!findUpClassName(e.target, 'drops-container')) {\n toggle(e, false);\n }\n });\n\n const dropsContainer = document.createElement('div');\n dropsContainer.classList.add('drops-container');\n }\n\n private canDrag() {\n const peerId = this.chat?.peerId;\n return !(!peerId || rootScope.isOverlayActive || !appMessagesManager.canSendToPeer(peerId, this.chat.threadId, 'send_media'));\n }\n\n private onDocumentPaste = (e: ClipboardEvent | DragEvent, attachType?: 'media' | 'document') => {\n if(!this.canDrag()) return;\n\n //console.log('document paste');\n //console.log('item', event.clipboardData.getData());\n\n if(e instanceof DragEvent) {\n const _types = e.dataTransfer.types;\n // @ts-ignore\n const isFiles = _types.contains ? _types.contains('Files') : _types.indexOf('Files') >= 0;\n if(isFiles) {\n cancelEvent(e);\n }\n }\n \n getFilesFromEvent(e).then((files: File[]) => {\n if(files.length) {\n if(/* attachType === 'media' && */files.find(file => !MEDIA_MIME_TYPES_SUPPORTED.has(file.type))) {\n attachType = 'document';\n }\n \n const chatInput = this.chat.input;\n chatInput.willAttachType = attachType || (MEDIA_MIME_TYPES_SUPPORTED.has(files[0].type) ? 'media' : \"document\");\n new PopupNewMedia(this.chat, files, chatInput.willAttachType);\n }\n });\n };\n\n public selectTab(id: number, animate?: boolean) {\n if(animate === false) { // * will be used for Safari iOS history swipe\n disableTransition([appSidebarLeft.sidebarEl, this.columnEl, appSidebarRight.sidebarEl]);\n }\n\n document.body.classList.toggle(LEFT_COLUMN_ACTIVE_CLASSNAME, id === 0);\n\n const prevTabId = this.tabId;\n\n this.log('selectTab', id, prevTabId);\n\n let animationPromise: Promise<any> = rootScope.settings.animationsEnabled ? doubleRaf() : Promise.resolve();\n if(prevTabId !== -1 && prevTabId !== id && rootScope.settings.animationsEnabled && animate !== false) {\n const transitionTime = (mediaSizes.isMobile ? 250 : 200) + 100; // * cause transition time could be > 250ms\n animationPromise = pause(transitionTime);\n dispatchHeavyAnimationEvent(animationPromise, transitionTime);\n\n // ! it's very heavy operation. will blink in firefox\n /* this.columnEl.classList.add('disable-hover');\n animationPromise.finally(() => {\n this.columnEl.classList.remove('disable-hover');\n }); */\n }\n\n this.tabId = id;\n blurActiveElement();\n if(mediaSizes.isMobile && prevTabId === 2 && id < 2) {\n document.body.classList.remove(RIGHT_COLUMN_ACTIVE_CLASSNAME);\n }\n\n if(prevTabId !== -1 && id > prevTabId) {\n if(id < 2 || !appNavigationController.findItemByType('im')) {\n appNavigationController.pushItem({\n type: 'im', \n onPop: (canAnimate) => {\n //this.selectTab(prevTabId, !isSafari);\n this.setPeer(0, undefined, canAnimate);\n }\n });\n }\n }\n\n rootScope.dispatchEvent('im_tab_change', id);\n\n //this._selectTab(id, mediaSizes.isMobile);\n //document.body.classList.toggle(RIGHT_COLUMN_ACTIVE_CLASSNAME, id === 2);\n\n return animationPromise;\n }\n \n public updateStatus() {\n if(!this.myId) return Promise.resolve();\n \n appUsersManager.setUserStatus(this.myId, this.offline);\n return apiManager.invokeApiSingle('account.updateStatus', {offline: this.offline});\n }\n\n private createNewChat() {\n const chat = new Chat(this, \n appChatsManager, \n appDocsManager, \n appInlineBotsManager, \n appMessagesManager, \n appPeersManager, \n appPhotosManager, \n appProfileManager, \n appStickersManager, \n appUsersManager, \n appWebPagesManager, \n appPollsManager, \n apiManager, \n appDraftsManager, \n serverTimeManager, \n stateStorage, \n appNotificationsManager, \n appEmojiManager,\n appMessagesIdsManager\n );\n\n if(this.chats.length) {\n chat.backgroundEl.append(this.chat.backgroundEl.lastElementChild.cloneNode(true));\n }\n\n this.chats.push(chat);\n }\n\n private spliceChats(fromIndex: number, justReturn = true, animate?: boolean, spliced?: Chat[]) {\n if(fromIndex >= this.chats.length) return;\n\n if(this.chats.length > 1 && justReturn) {\n rootScope.dispatchEvent('peer_changing', this.chat);\n }\n\n if(!spliced) {\n spliced = this.chats.splice(fromIndex, this.chats.length - fromIndex);\n }\n\n // * -1 because one item is being sliced when closing the chat by calling .removeByType\n for(let i = 0; i < spliced.length - 1; ++i) {\n appNavigationController.removeByType('chat', true);\n }\n\n // * fix middle chat z-index on animation\n if(spliced.length > 1) {\n spliced.slice(0, -1).forEach(chat => {\n chat.container.remove();\n });\n }\n\n this.chatsSelectTab(this.chat.container, animate);\n\n if(justReturn) {\n rootScope.dispatchEvent('peer_changed', this.chat.peerId);\n\n const searchTab = appSidebarRight.getTab(AppPrivateSearchTab);\n if(searchTab) {\n searchTab.close();\n }\n \n const isSet = appSidebarRight.sharedMediaTab.setPeer(this.chat.peerId, this.chat.threadId);\n if(isSet) {\n appSidebarRight.sharedMediaTab.loadSidebarMedia(true);\n appSidebarRight.sharedMediaTab.fillProfileElements();\n }\n \n /* setTimeout(() => {\n appSidebarRight.sharedMediaTab.loadSidebarMedia(false);\n }); */\n }\n\n spliced.forEach(chat => {\n chat.beforeDestroy();\n });\n \n setTimeout(() => {\n //chat.setPeer(0);\n spliced.forEach(chat => {\n chat.destroy();\n });\n }, 250 + 100);\n }\n\n public setPeer(peerId: number, lastMsgId?: number, animate?: boolean): boolean {\n if(this.init) {\n this.init();\n this.init = null;\n }\n\n const chat = this.chat;\n const chatIndex = this.chats.indexOf(chat);\n\n if(!peerId) {\n if(chatIndex > 0) {\n this.spliceChats(chatIndex, undefined, animate);\n return;\n } else if(mediaSizes.activeScreen === ScreenSize.medium) { // * floating sidebar case\n this.selectTab(+!this.tabId, animate);\n return;\n }\n } else if(chatIndex > 0 && chat.peerId && chat.peerId !== peerId) {\n // const firstChat = this.chats[0];\n // if(firstChat.peerId !== chat.peerId) {\n /* // * slice idx > 0, set background and slice first, so new one will be the first\n const spliced = this.chats.splice(1, this.chats.length - 1);\n this.createNewChat();\n this.chats.splice(0, 1); */\n const spliced = this.chats.splice(1, this.chats.length - 1);\n if(this.chat.peerId === peerId) {\n this.spliceChats(0, true, true, spliced);\n return;\n } else {\n const ret = this.setPeer(peerId, lastMsgId);\n this.spliceChats(0, false, false, spliced);\n return ret;\n }\n // } else {\n // this.spliceChats(1, false, animate);\n // }\n\n //return ret;\n }\n\n // * don't reset peer if returning\n if(peerId === chat.peerId && mediaSizes.activeScreen <= ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {\n this.selectTab(1, animate);\n return false;\n }\n\n if(peerId || mediaSizes.activeScreen !== ScreenSize.mobile) {\n const result = chat.setPeer(peerId, lastMsgId);\n\n // * wait for cached render\n const promise = result?.cached ? result.promise : Promise.resolve();\n if(peerId) {\n promise.then(() => {\n //window.requestAnimationFrame(() => {\n setTimeout(() => { // * setTimeout is better here\n setTimeout(() => {\n this.chatsSelectTab(this.chat.container);\n }, 0);\n this.selectTab(1, animate);\n }, 0);\n });\n }\n }\n\n if(!peerId) {\n this.selectTab(0, animate);\n return false;\n }\n }\n\n public setInnerPeer(peerId: number, lastMsgId?: number, type: ChatType = 'chat', threadId?: number) {\n // * prevent opening already opened peer\n const existingIndex = this.chats.findIndex(chat => chat.peerId === peerId && chat.type === type);\n if(existingIndex !== -1) {\n this.spliceChats(existingIndex + 1);\n return this.setPeer(peerId, lastMsgId);\n }\n\n const chat = this.chat;\n if(chat.inited) { // * use first not inited chat\n this.createNewChat();\n }\n\n if(type) {\n this.chat.setType(type);\n\n if(threadId) {\n this.chat.threadId = threadId;\n }\n }\n\n //this.chatsSelectTab(this.chat.container);\n\n return this.setPeer(peerId, lastMsgId);\n }\n\n public openScheduled(peerId: number) {\n this.setInnerPeer(peerId, undefined, 'scheduled');\n }\n\n private getTypingElement(action: SendMessageAction) {\n const el = document.createElement('span');\n el.classList.add('peer-typing');\n el.dataset.action = action._;\n switch(action._) {\n case 'sendMessageTypingAction': {\n //default: {\n const c = 'peer-typing-text';\n el.classList.add(c);\n for(let i = 0; i < 3; ++i) {\n const dot = document.createElement('span');\n dot.className = c + '-dot';\n el.append(dot);\n }\n break;\n }\n\n case 'sendMessageUploadAudioAction':\n case 'sendMessageUploadDocumentAction':\n case 'sendMessageUploadRoundAction':\n case 'sendMessageUploadVideoAction':\n case 'sendMessageUploadPhotoAction': {\n const c = 'peer-typing-upload';\n el.classList.add(c);\n /* const trail = document.createElement('span');\n trail.className = c + '-trail';\n el.append(trail); */\n break;\n }\n\n case 'sendMessageRecordAudioAction':\n case 'sendMessageRecordRoundAction':\n case 'sendMessageRecordVideoAction': {\n const c = 'peer-typing-record';\n el.classList.add(c);\n break;\n }\n }\n\n return el;\n }\n\n public getPeerTyping(peerId: number, container?: HTMLElement) {\n if(!appUsersManager.isBot(peerId)) {\n const typings = appProfileManager.getPeerTypings(peerId);\n if(!typings || !typings.length) {\n return;\n }\n\n const typing = typings[0];\n\n const langPackKeys: {\n [peerType in 'private' | 'chat' | 'multi']?: Partial<{[action in SendMessageAction['_']]: LangPackKey}>\n } = {\n private: {\n 'sendMessageTypingAction': 'Peer.Activity.User.TypingText',\n 'sendMessageUploadAudioAction': 'Peer.Activity.User.SendingFile',\n 'sendMessageUploadDocumentAction': 'Peer.Activity.User.SendingFile',\n 'sendMessageUploadPhotoAction': 'Peer.Activity.User.SendingPhoto',\n 'sendMessageUploadVideoAction': 'Peer.Activity.User.SendingVideo',\n 'sendMessageUploadRoundAction': 'Peer.Activity.User.SendingVideo',\n 'sendMessageRecordVideoAction': 'Peer.Activity.User.RecordingVideo',\n 'sendMessageRecordAudioAction': 'Peer.Activity.User.RecordingAudio',\n 'sendMessageRecordRoundAction': 'Peer.Activity.User.RecordingVideo',\n 'sendMessageGamePlayAction': 'Peer.Activity.User.PlayingGame'\n },\n chat: {\n 'sendMessageTypingAction': 'Peer.Activity.Chat.TypingText',\n 'sendMessageUploadAudioAction': 'Peer.Activity.Chat.SendingFile',\n 'sendMessageUploadDocumentAction': 'Peer.Activity.Chat.SendingFile',\n 'sendMessageUploadPhotoAction': 'Peer.Activity.Chat.SendingPhoto',\n 'sendMessageUploadVideoAction': 'Peer.Activity.Chat.SendingVideo',\n 'sendMessageUploadRoundAction': 'Peer.Activity.Chat.SendingVideo',\n 'sendMessageRecordVideoAction': 'Peer.Activity.Chat.RecordingVideo',\n 'sendMessageRecordAudioAction': 'Peer.Activity.Chat.RecordingAudio',\n 'sendMessageRecordRoundAction': 'Peer.Activity.Chat.RecordingVideo',\n 'sendMessageGamePlayAction': 'Peer.Activity.Chat.PlayingGame'\n },\n multi: {\n 'sendMessageTypingAction': 'Peer.Activity.Chat.Multi.TypingText1',\n 'sendMessageUploadAudioAction': 'Peer.Activity.Chat.Multi.SendingFile1',\n 'sendMessageUploadDocumentAction': 'Peer.Activity.Chat.Multi.SendingFile1',\n 'sendMessageUploadPhotoAction': 'Peer.Activity.Chat.Multi.SendingPhoto1',\n 'sendMessageUploadVideoAction': 'Peer.Activity.Chat.Multi.SendingVideo1',\n 'sendMessageUploadRoundAction': 'Peer.Activity.Chat.Multi.SendingVideo1',\n 'sendMessageRecordVideoAction': 'Peer.Activity.Chat.Multi.RecordingVideo1',\n 'sendMessageRecordAudioAction': 'Peer.Activity.Chat.Multi.RecordingAudio1',\n 'sendMessageRecordRoundAction': 'Peer.Activity.Chat.Multi.RecordingVideo1',\n 'sendMessageGamePlayAction': 'Peer.Activity.Chat.Multi.PlayingGame1'\n }\n };\n\n const mapa = peerId > 0 ? langPackKeys.private : (typings.length > 1 ? langPackKeys.multi : langPackKeys.chat);\n let action = typing.action;\n\n if(typings.length > 1) {\n const s: any = {};\n typings.forEach(typing => {\n const type = typing.action._;\n if(s[type] === undefined) s[type] = 0;\n ++s[type];\n });\n\n if(Object.keys(s).length > 1) {\n action = {\n _: 'sendMessageTypingAction'\n };\n }\n }\n\n const langPackKey = mapa[action._];\n if(!langPackKey) {\n return;\n }\n\n if(!container) {\n container = document.createElement('span');\n container.classList.add('online', 'peer-typing-container');\n }\n\n let typingElement = container.firstElementChild as HTMLElement;\n if(!typingElement) {\n typingElement = this.getTypingElement(action);\n container.prepend(typingElement);\n } else {\n if(typingElement.dataset.action !== action._) {\n typingElement.replaceWith(this.getTypingElement(action));\n }\n }\n\n let args: any[];\n if(peerId < 0) {\n args = [\n new PeerTitle({peerId: typing.userId, onlyFirstName: true}).element,\n typings.length - 1\n ];\n }\n const descriptionElement = i18n(langPackKey, args);\n descriptionElement.classList.add('peer-typing-description');\n\n if(container.childElementCount > 1) container.lastElementChild.replaceWith(descriptionElement);\n else container.append(descriptionElement);\n return container;\n }\n }\n\n public async getPeerStatus(peerId: number) {\n let subtitle: HTMLElement;\n if(!peerId) return '';\n\n if(peerId < 0) { // not human\n let span = this.getPeerTyping(peerId);\n if(span) {\n return span;\n }\n\n const chatInfo = await appProfileManager.getChatFull(-peerId) as any;\n this.chat.log('chatInfo res:', chatInfo);\n\n const participants_count = chatInfo.participants_count || (chatInfo.participants && chatInfo.participants.participants && chatInfo.participants.participants.length) || 1;\n //if(participants_count) {\n subtitle = appProfileManager.getChatMembersString(-peerId);\n\n if(participants_count < 2) return subtitle;\n /* const onlines = await appChatsManager.getOnlines(chat.id);\n if(onlines > 1) {\n subtitle += ', ' + numberThousandSplitter(onlines) + ' online';\n } */\n \n return subtitle;\n //}\n } else { // user\n const user = appUsersManager.getUser(peerId);\n \n if(rootScope.myId === peerId) {\n return '';\n } else if(user) {\n subtitle = appUsersManager.getUserStatusString(user.id);\n\n if(!appUsersManager.isBot(peerId)) {\n let span = this.getPeerTyping(peerId);\n if(!span && user.status?._ === 'userStatusOnline') {\n span = document.createElement('span');\n span.classList.add('online');\n span.append(subtitle);\n }\n\n if(span) {\n return span;\n }\n }\n \n return subtitle;\n }\n }\n }\n\n public setPeerStatus(peerId: number, element: HTMLElement, needClear: boolean, useWhitespace: boolean, middleware: () => boolean) {\n if(needClear) {\n element.innerHTML = useWhitespace ? '' : ''; // ! HERE U CAN FIND WHITESPACE\n }\n\n // * good good good\n const typingContainer = element.querySelector('.peer-typing-container') as HTMLElement;\n if(typingContainer && this.getPeerTyping(peerId, typingContainer)) {\n return;\n }\n\n this.getPeerStatus(peerId).then((subtitle) => {\n if(!middleware()) {\n return;\n }\n\n replaceContent(element, subtitle || (useWhitespace ? '' : ''));\n });\n }\n}\n\nconst appImManager = new AppImManager();\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appImManager = appImManager);\nexport default appImManager;\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { deferredPromise } from \"../helpers/cancellablePromise\";\nimport mediaSizes from \"../helpers/mediaSizes\";\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\nimport { IS_MOBILE_SAFARI, IS_SAFARI } from \"../environment/userAgent\";\nimport appDocsManager, { MyDocument } from \"../lib/appManagers/appDocsManager\";\nimport appPhotosManager, { MyPhoto } from \"../lib/appManagers/appPhotosManager\";\nimport { logger } from \"../lib/logger\";\nimport VideoPlayer from \"../lib/mediaPlayer\";\nimport rootScope from \"../lib/rootScope\";\nimport animationIntersector from \"./animationIntersector\";\nimport appMediaPlaybackController from \"./appMediaPlaybackController\";\nimport AvatarElement from \"./avatar\";\nimport ButtonIcon from \"./buttonIcon\";\nimport { ButtonMenuItemOptions } from \"./buttonMenu\";\nimport ButtonMenuToggle from \"./buttonMenuToggle\";\nimport { LazyLoadQueueBase } from \"./lazyLoadQueue\";\nimport ProgressivePreloader from \"./preloader\";\nimport SwipeHandler from \"./swipeHandler\";\nimport { formatFullSentTime } from \"../helpers/date\";\nimport appNavigationController from \"./appNavigationController\";\nimport { Message } from \"../layer\";\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\nimport renderImageFromUrl, { renderImageFromUrlPromise } from \"../helpers/dom/renderImageFromUrl\";\nimport getVisibleRect from \"../helpers/dom/getVisibleRect\";\nimport appDownloadManager from \"../lib/appManagers/appDownloadManager\";\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\nimport fillPropertyValue from \"../helpers/fillPropertyValue\";\nimport generatePathData from \"../helpers/generatePathData\";\nimport replaceContent from \"../helpers/dom/replaceContent\";\nimport PeerTitle from \"./peerTitle\";\nimport { doubleRaf, fastRaf } from \"../helpers/schedulers\";\nimport RangeSelector from \"./rangeSelector\";\nimport windowSize from \"../helpers/windowSize\";\nimport ListLoader from \"../helpers/listLoader\";\nimport EventListenerBase from \"../helpers/eventListenerBase\";\n\nconst ZOOM_STEP = 0.5;\nconst ZOOM_INITIAL_VALUE = 1;\nconst ZOOM_MIN_VALUE = 0.5;\nconst ZOOM_MAX_VALUE = 4;\n\n// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию\n// TODO: картинки \"обрезаются\" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)\n// TODO: видео в мобильной вёрстке, если показываются элементы управления: если свайпнуть в сторону, то элементы вернутся на место, т.е. прыгнут - это не ок, надо бы замаскировать\n\nexport const MEDIA_VIEWER_CLASSNAME = 'media-viewer';\n\nexport default class AppMediaViewerBase<\n ContentAdditionType extends string, \n ButtonsAdditionType extends string, \n TargetType extends {element: HTMLElement\n}> extends EventListenerBase<{\n setMoverBefore: () => void,\n setMoverAfter: () => void\n}> {\n protected wholeDiv: HTMLElement;\n protected overlaysDiv: HTMLElement;\n protected author: {[k in 'container' | 'avatarEl' | 'nameEl' | 'date']: HTMLElement} = {} as any;\n protected content: {[k in 'main' | 'container' | 'media' | 'mover' | ContentAdditionType]: HTMLElement} = {} as any;\n protected buttons: {[k in 'download' | 'close' | 'prev' | 'next' | 'mobile-close' | 'zoom' | ButtonsAdditionType]: HTMLElement} = {} as any;\n protected topbar: HTMLElement;\n protected moversContainer: HTMLElement;\n \n protected tempId = 0;\n protected preloader: ProgressivePreloader = null;\n protected preloaderStreamable: ProgressivePreloader = null;\n\n //protected targetContainer: HTMLElement = null;\n //protected loadMore: () => void = null;\n\n protected log: ReturnType<typeof logger>; \n\n protected isFirstOpen = true;\n\n // protected needLoadMore = true;\n\n protected pageEl = document.getElementById('page-chats') as HTMLDivElement;\n\n protected setMoverPromise: Promise<void>;\n protected setMoverAnimationPromise: Promise<void>;\n\n protected lazyLoadQueue: LazyLoadQueueBase;\n\n protected highlightSwitchersTimeout: number;\n\n protected onDownloadClick: (e: MouseEvent) => void;\n protected onPrevClick: (target: TargetType) => void;\n protected onNextClick: (target: TargetType) => void;\n\n protected videoPlayer: VideoPlayer;\n\n protected zoomElements: {\n container: HTMLElement,\n btnOut: HTMLElement,\n btnIn: HTMLElement,\n rangeSelector: RangeSelector\n } = {} as any;\n // protected zoomValue = ZOOM_INITIAL_VALUE;\n protected zoomSwipeHandler: SwipeHandler;\n protected zoomSwipeStartX = 0;\n protected zoomSwipeStartY = 0;\n protected zoomSwipeX = 0;\n protected zoomSwipeY = 0;\n \n protected ctrlKeyDown: boolean;\n\n get target() {\n return this.listLoader.current;\n }\n\n set target(value) {\n this.listLoader.current = value;\n }\n\n constructor(\n protected listLoader: ListLoader<TargetType, any>, \n topButtons: Array<keyof AppMediaViewerBase<ContentAdditionType, ButtonsAdditionType, TargetType>['buttons']>\n ) {\n super(false);\n\n this.log = logger('AMV');\n this.preloader = new ProgressivePreloader();\n this.preloaderStreamable = new ProgressivePreloader({\n cancelable: false,\n streamable: true\n });\n this.preloader.construct();\n this.preloaderStreamable.construct();\n this.lazyLoadQueue = new LazyLoadQueueBase();\n\n this.wholeDiv = document.createElement('div');\n this.wholeDiv.classList.add(MEDIA_VIEWER_CLASSNAME + '-whole');\n\n this.overlaysDiv = document.createElement('div');\n this.overlaysDiv.classList.add('overlays');\n\n const mainDiv = document.createElement('div');\n mainDiv.classList.add(MEDIA_VIEWER_CLASSNAME);\n\n const topbar = this.topbar = document.createElement('div');\n topbar.classList.add(MEDIA_VIEWER_CLASSNAME + '-topbar', MEDIA_VIEWER_CLASSNAME + '-appear');\n\n const topbarLeft = document.createElement('div');\n topbarLeft.classList.add(MEDIA_VIEWER_CLASSNAME + '-topbar-left');\n\n this.buttons['mobile-close'] = ButtonIcon('close', {onlyMobile: true});\n \n // * author\n this.author.container = document.createElement('div');\n this.author.container.classList.add(MEDIA_VIEWER_CLASSNAME + '-author', 'no-select');\n const authorRight = document.createElement('div');\n \n this.author.avatarEl = new AvatarElement();\n this.author.avatarEl.classList.add(MEDIA_VIEWER_CLASSNAME + '-userpic', 'avatar-44');\n \n this.author.nameEl = document.createElement('div');\n this.author.nameEl.classList.add(MEDIA_VIEWER_CLASSNAME + '-name');\n \n this.author.date = document.createElement('div');\n this.author.date.classList.add(MEDIA_VIEWER_CLASSNAME + '-date');\n \n authorRight.append(this.author.nameEl, this.author.date);\n \n this.author.container.append(this.author.avatarEl, authorRight);\n \n // * buttons\n const buttonsDiv = document.createElement('div');\n buttonsDiv.classList.add(MEDIA_VIEWER_CLASSNAME + '-buttons');\n \n topButtons.concat(['download', 'zoom', 'close']).forEach(name => {\n const button = ButtonIcon(name, {noRipple: true});\n this.buttons[name] = button;\n buttonsDiv.append(button);\n });\n\n this.buttons.zoom.classList.add('zoom-in');\n\n // * zoom\n this.zoomElements.container = document.createElement('div');\n this.zoomElements.container.classList.add('zoom-container');\n\n this.zoomElements.btnOut = ButtonIcon('zoomout', {noRipple: true});\n this.zoomElements.btnOut.addEventListener('click', () => this.changeZoom(false));\n this.zoomElements.btnIn = ButtonIcon('zoomin', {noRipple: true});\n this.zoomElements.btnIn.addEventListener('click', () => this.changeZoom(true));\n\n this.zoomElements.rangeSelector = new RangeSelector({\n step: ZOOM_STEP, \n min: ZOOM_MIN_VALUE, \n max: ZOOM_MAX_VALUE, \n withTransition: true\n }, ZOOM_INITIAL_VALUE);\n this.zoomElements.rangeSelector.setListeners();\n this.zoomElements.rangeSelector.setHandlers({\n onScrub: this.setZoomValue,\n onMouseUp: () => this.setZoomValue()\n });\n\n this.zoomElements.container.append(this.zoomElements.btnOut, this.zoomElements.rangeSelector.container, this.zoomElements.btnIn);\n\n this.wholeDiv.append(this.zoomElements.container);\n\n // * content\n this.content.main = document.createElement('div');\n this.content.main.classList.add(MEDIA_VIEWER_CLASSNAME + '-content');\n\n this.content.container = document.createElement('div');\n this.content.container.classList.add(MEDIA_VIEWER_CLASSNAME + '-container');\n\n this.content.media = document.createElement('div');\n this.content.media.classList.add(MEDIA_VIEWER_CLASSNAME + '-media');\n\n this.content.container.append(this.content.media);\n\n this.content.main.append(this.content.container);\n mainDiv.append(this.content.main);\n this.overlaysDiv.append(mainDiv);\n // * overlays end\n \n topbarLeft.append(this.buttons['mobile-close'], this.author.container);\n topbar.append(topbarLeft, buttonsDiv);\n\n this.buttons.prev = document.createElement('div');\n this.buttons.prev.className = `${MEDIA_VIEWER_CLASSNAME}-switcher ${MEDIA_VIEWER_CLASSNAME}-switcher-left`;\n this.buttons.prev.innerHTML = `<span class=\"tgico-down ${MEDIA_VIEWER_CLASSNAME}-prev-button\"></span>`;\n\n this.buttons.next = document.createElement('div');\n this.buttons.next.className = `${MEDIA_VIEWER_CLASSNAME}-switcher ${MEDIA_VIEWER_CLASSNAME}-switcher-right`;\n this.buttons.next.innerHTML = `<span class=\"tgico-down ${MEDIA_VIEWER_CLASSNAME}-next-button\"></span>`;\n\n this.moversContainer = document.createElement('div');\n this.moversContainer.classList.add(MEDIA_VIEWER_CLASSNAME + '-movers');\n\n this.wholeDiv.append(this.overlaysDiv, this.buttons.prev, this.buttons.next, this.topbar, this.moversContainer);\n\n // * constructing html end\n\n this.setNewMover();\n }\n\n protected setListeners() {\n this.buttons.download.addEventListener('click', this.onDownloadClick);\n [this.buttons.close, this.buttons['mobile-close'], this.preloaderStreamable.preloader].forEach(el => {\n el.addEventListener('click', this.close.bind(this));\n });\n\n ([[-1, this.buttons.prev], [1, this.buttons.next]] as [number, HTMLElement][]).forEach(([moveLength, button]) => {\n button.addEventListener('click', (e) => {\n cancelEvent(e);\n if(this.setMoverPromise) return;\n \n this.listLoader.go(moveLength);\n });\n });\n\n this.buttons.zoom.addEventListener('click', () => {\n if(this.isZooming()) this.toggleZoom(false);\n else {\n this.changeZoom(true);\n }\n });\n\n this.wholeDiv.addEventListener('click', this.onClick);\n\n this.listLoader.onJump = (item, older) => {\n if(older) this.onNextClick(item);\n else this.onPrevClick(item);\n };\n\n if(IS_TOUCH_SUPPORTED) {\n const swipeHandler = new SwipeHandler({\n element: this.wholeDiv, \n onSwipe: (xDiff, yDiff) => {\n if(VideoPlayer.isFullScreen()) {\n return;\n }\n //console.log(xDiff, yDiff);\n\n const percents = Math.abs(xDiff) / windowSize.windowW;\n if(percents > .2 || xDiff > 125) {\n //console.log('will swipe', xDiff);\n\n if(xDiff < 0) {\n this.buttons.prev.click();\n } else {\n this.buttons.next.click();\n }\n\n return true;\n }\n\n const percentsY = Math.abs(yDiff) / windowSize.windowH;\n if(percentsY > .2 || yDiff > 125) {\n this.buttons.close.click();\n return true;\n }\n\n return false;\n }, \n verifyTouchTarget: (evt) => {\n // * Fix for seek input\n if((evt.target as HTMLElement).tagName === 'INPUT' || findUpClassName(evt.target, 'media-viewer-caption')) {\n return false;\n }\n\n return true;\n }\n });\n }\n }\n\n protected toggleZoom(enable?: boolean) {\n const isVisible = this.isZooming();\n if(this.zoomElements.rangeSelector.mousedown || this.ctrlKeyDown) {\n enable = true;\n }\n\n if(isVisible === enable) return;\n\n if(enable === undefined) {\n enable = !isVisible;\n }\n\n this.buttons.zoom.classList.toggle('zoom-in', !enable);\n this.zoomElements.container.classList.toggle('is-visible', enable);\n const zoomValue = enable ? this.zoomElements.rangeSelector.value : 1;\n this.setZoomValue(zoomValue);\n this.zoomElements.rangeSelector.setProgress(zoomValue);\n\n if(this.videoPlayer) {\n this.videoPlayer.lockControls(enable ? false : undefined);\n }\n\n if(enable) {\n if(!this.zoomSwipeHandler) {\n let lastDiffX: number, lastDiffY: number;\n const multiplier = -1;\n this.zoomSwipeHandler = new SwipeHandler({\n element: this.moversContainer,\n onFirstSwipe: () => {\n lastDiffX = lastDiffY = 0;\n this.moversContainer.classList.add('no-transition');\n },\n onSwipe: (xDiff, yDiff) => {\n [xDiff, yDiff] = [xDiff * multiplier, yDiff * multiplier];\n this.zoomSwipeX += xDiff - lastDiffX;\n this.zoomSwipeY += yDiff - lastDiffY;\n [lastDiffX, lastDiffY] = [xDiff, yDiff];\n\n this.setZoomValue();\n },\n onReset: () => {\n this.moversContainer.classList.remove('no-transition');\n },\n cursor: 'move'\n });\n } else {\n this.zoomSwipeHandler.setListeners();\n }\n \n this.zoomElements.rangeSelector.setProgress(zoomValue);\n } else if(!enable) {\n this.zoomSwipeHandler.removeListeners();\n }\n }\n\n protected changeZoom(add: boolean) {\n this.zoomElements.rangeSelector.addProgress(ZOOM_STEP * (add ? 1 : -1));\n this.setZoomValue();\n }\n\n protected setZoomValue = (value = this.zoomElements.rangeSelector.value) => {\n // this.zoomValue = value;\n if(value === ZOOM_INITIAL_VALUE) {\n this.zoomSwipeX = 0;\n this.zoomSwipeY = 0;\n }\n\n this.moversContainer.style.transform = `matrix(${value}, 0, 0, ${value}, ${this.zoomSwipeX}, ${this.zoomSwipeY})`;\n\n this.zoomElements.btnOut.classList.toggle('inactive', value === ZOOM_MIN_VALUE);\n this.zoomElements.btnIn.classList.toggle('inactive', value === ZOOM_MAX_VALUE);\n\n this.toggleZoom(value !== ZOOM_INITIAL_VALUE);\n };\n\n protected isZooming() {\n return this.zoomElements.container.classList.contains('is-visible');\n }\n\n protected setBtnMenuToggle(buttons: ButtonMenuItemOptions[]) {\n const btnMenuToggle = ButtonMenuToggle({onlyMobile: true}, 'bottom-left', buttons);\n this.topbar.append(btnMenuToggle);\n }\n\n public close(e?: MouseEvent) {\n if(e) {\n cancelEvent(e);\n }\n\n if(this.setMoverAnimationPromise) return Promise.reject();\n\n appNavigationController.removeByType('media');\n\n this.lazyLoadQueue.clear();\n\n const promise = this.setMoverToTarget(this.target?.element, true).then(({onAnimationEnd}) => onAnimationEnd);\n\n this.listLoader.reset();\n (this.listLoader as any).cleanup && (this.listLoader as any).cleanup();\n this.setMoverPromise = null;\n this.tempId = -1;\n (window as any).appMediaViewer = undefined;\n\n if(this.zoomSwipeHandler) {\n this.zoomSwipeHandler.removeListeners();\n this.zoomSwipeHandler = undefined;\n }\n\n /* if(appSidebarRight.historyTabIDs.slice(-1)[0] === AppSidebarRight.SLIDERITEMSIDS.forward) {\n promise.then(() => {\n appSidebarRight.forwardTab.closeBtn.click();\n });\n } */\n\n window.removeEventListener('keydown', this.onKeyDown);\n window.removeEventListener('keyup', this.onKeyUp);\n window.removeEventListener('wheel', this.onWheel, {capture: true});\n\n promise.finally(() => {\n this.wholeDiv.remove();\n rootScope.isOverlayActive = false;\n animationIntersector.checkAnimations(false);\n });\n\n return promise;\n }\n\n onClick = (e: MouseEvent) => {\n if(this.setMoverAnimationPromise) return;\n\n const target = e.target as HTMLElement;\n if(target.tagName === 'A') return;\n cancelEvent(e);\n\n if(IS_TOUCH_SUPPORTED) {\n if(this.highlightSwitchersTimeout) {\n clearTimeout(this.highlightSwitchersTimeout);\n } else {\n this.wholeDiv.classList.add('highlight-switchers');\n }\n\n this.highlightSwitchersTimeout = window.setTimeout(() => {\n this.wholeDiv.classList.remove('highlight-switchers');\n this.highlightSwitchersTimeout = 0;\n }, 3e3);\n \n return;\n }\n\n const isZooming = this.isZooming();\n let mover: HTMLElement = null;\n const classNames = ['ckin__player', 'media-viewer-buttons', 'media-viewer-author', 'media-viewer-caption', 'zoom-container'];\n if(isZooming) {\n classNames.push('media-viewer-movers');\n }\n\n classNames.find(s => {\n try {\n mover = findUpClassName(target, s);\n if(mover) return true;\n } catch(err) {return false;}\n });\n\n if(/* target === this.mediaViewerDiv */!mover || (!isZooming && (target.tagName === 'IMG' || target.tagName === 'image'))) {\n this.buttons.close.click();\n }\n };\n\n private onKeyDown = (e: KeyboardEvent) => {\n //this.log('onKeyDown', e);\n if(rootScope.overlaysActive > 1) {\n return;\n }\n \n let good = true;\n if(e.key === 'ArrowRight') {\n this.buttons.next.click();\n } else if(e.key === 'ArrowLeft') {\n this.buttons.prev.click();\n } else if(e.key === '-' || e.key === '=') {\n if(this.ctrlKeyDown) {\n this.changeZoom(e.key === '=');\n }\n } else {\n good = false;\n }\n\n if(e.ctrlKey || e.metaKey) {\n this.ctrlKeyDown = true;\n }\n\n if(good) {\n cancelEvent(e);\n }\n };\n\n private onKeyUp = (e: KeyboardEvent) => {\n if(rootScope.overlaysActive > 1) {\n return;\n }\n\n if(!(e.ctrlKey || e.metaKey)) {\n this.ctrlKeyDown = false;\n\n if(this.isZooming()) {\n this.setZoomValue();\n }\n }\n };\n\n private onWheel = (e: WheelEvent) => {\n if(rootScope.overlaysActive > 1 || (findUpClassName(e.target, 'media-viewer-caption') && !this.ctrlKeyDown)) {\n return;\n }\n\n cancelEvent(e);\n\n if(this.ctrlKeyDown) {\n const scrollingUp = e.deltaY < 0;\n // if(!scrollingUp && !this.isZooming()) return;\n this.changeZoom(!!scrollingUp);\n }\n };\n\n protected async setMoverToTarget(target: HTMLElement, closing = false, fromRight = 0) {\n this.dispatchEvent('setMoverBefore');\n\n const mover = this.content.mover;\n\n if(!closing) {\n mover.innerHTML = '';\n //mover.append(this.buttons.prev, this.buttons.next);\n }\n \n const zoomValue = this.isZooming() && closing /* && false */ ? this.zoomElements.rangeSelector.value : ZOOM_INITIAL_VALUE;\n /* if(!(zoomValue > 1 && closing)) */ this.removeCenterFromMover(mover);\n\n const wasActive = fromRight !== 0;\n\n const delay = rootScope.settings.animationsEnabled ? (wasActive ? 350 : 200) : 0;\n //let delay = wasActive ? 350 : 10000;\n\n /* if(wasActive) {\n this.moveTheMover(mover);\n mover = this.setNewMover();\n } */\n\n /* if(DEBUG) {\n this.log('setMoverToTarget', target, closing, wasActive, fromRight);\n } */\n\n let realParent: HTMLElement;\n\n let rect: DOMRect;\n if(target) {\n if(target instanceof AvatarElement || target.classList.contains('grid-item')/* || target.classList.contains('document-ico') */) {\n realParent = target;\n rect = target.getBoundingClientRect();\n } else if(target instanceof SVGImageElement || target.parentElement instanceof SVGForeignObjectElement) {\n realParent = findUpClassName(target, 'attachment');\n rect = realParent.getBoundingClientRect();\n } else if(target.classList.contains('profile-avatars-avatar')) {\n realParent = findUpClassName(target, 'profile-avatars-container');\n rect = realParent.getBoundingClientRect();\n\n // * if not active avatar\n if(closing && target.getBoundingClientRect().left !== rect.left) {\n target = realParent = rect = undefined;\n }\n }\n }\n\n if(!target) {\n target = this.content.media;\n }\n\n if(!rect) {\n realParent = target.parentElement as HTMLElement;\n rect = target.getBoundingClientRect();\n }\n\n let needOpacity = false;\n if(target !== this.content.media && !target.classList.contains('profile-avatars-avatar')) {\n const overflowElement = findUpClassName(realParent, 'scrollable');\n const visibleRect = getVisibleRect(realParent, overflowElement);\n\n if(closing && (!visibleRect || visibleRect.overflow.vertical === 2 || visibleRect.overflow.horizontal === 2)) {\n target = this.content.media;\n realParent = target.parentElement as HTMLElement;\n rect = target.getBoundingClientRect();\n } else if(visibleRect && (visibleRect.overflow.vertical === 1 || visibleRect.overflow.horizontal === 1)) {\n needOpacity = true;\n }\n }\n\n const containerRect = this.content.media.getBoundingClientRect();\n \n let transform = '';\n let left: number;\n let top: number;\n\n if(wasActive) {\n left = fromRight === 1 ? windowSize.windowW : -containerRect.width;\n top = containerRect.top;\n } else {\n left = rect.left;\n top = rect.top;\n }\n\n /* if(zoomValue > 1) { // 33\n // const diffX = (rect.width * zoomValue - rect.width) / 4;\n const diffX = (rect.width * zoomValue - rect.width) / 2;\n const diffY = (rect.height * zoomValue - rect.height) / 4;\n // left -= diffX;\n // top += diffY;\n } */\n\n transform += `translate3d(${left}px,${top}px,0) `;\n\n /* if(wasActive) {\n left = fromRight === 1 ? appPhotosManager.windowW / 2 : -(containerRect.width + appPhotosManager.windowW / 2);\n transform += `translate(${left}px,-50%) `;\n } else {\n left = rect.left - (appPhotosManager.windowW / 2);\n top = rect.top - (appPhotosManager.windowH / 2);\n transform += `translate(${left}px,${top}px) `;\n } */\n\n let aspecter: HTMLDivElement;\n if(target instanceof HTMLImageElement || target instanceof HTMLVideoElement || target.tagName === 'DIV') {\n if(mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter')) {\n aspecter = mover.firstElementChild as HTMLDivElement;\n\n const player = aspecter.querySelector('.ckin__player');\n if(player) {\n const video = player.firstElementChild as HTMLVideoElement;\n aspecter.append(video);\n player.remove();\n }\n\n if(!aspecter.style.cssText) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать\n mover.classList.remove('active');\n this.setFullAspect(aspecter, containerRect, rect);\n void mover.offsetLeft; // reflow\n mover.classList.add('active');\n }\n } else {\n aspecter = document.createElement('div');\n aspecter.classList.add('media-viewer-aspecter'/* , 'disable-hover' */);\n mover.prepend(aspecter);\n }\n \n aspecter.style.cssText = `width: ${rect.width}px; height: ${rect.height}px; transform: scale3d(${containerRect.width / rect.width}, ${containerRect.height / rect.height}, 1);`;\n }\n\n mover.style.width = containerRect.width + 'px';\n mover.style.height = containerRect.height + 'px';\n\n // const scaleX = rect.width / (containerRect.width * zoomValue);\n // const scaleY = rect.height / (containerRect.height * zoomValue);\n const scaleX = rect.width / containerRect.width;\n const scaleY = rect.height / containerRect.height;\n if(!wasActive) {\n transform += `scale3d(${scaleX},${scaleY},1) `;\n }\n\n let borderRadius = window.getComputedStyle(realParent).getPropertyValue('border-radius');\n const brSplitted = fillPropertyValue(borderRadius) as string[];\n borderRadius = brSplitted.map(r => (parseInt(r) / scaleX) + 'px').join(' ');\n if(!wasActive) {\n mover.style.borderRadius = borderRadius;\n }\n //let borderRadius = '0px 0px 0px 0px';\n\n if(closing && zoomValue !== 1) {\n // const width = this.moversContainer.scrollWidth * scaleX;\n // const height = this.moversContainer.scrollHeight * scaleY;\n const willBeLeft = windowSize.windowW / 2 - rect.width / 2;\n const willBeTop = windowSize.windowH / 2 - rect.height / 2;\n const left = rect.left - willBeLeft/* + (width - rect.width) / 2 */;\n const top = rect.top - willBeTop/* + (height - rect.height) / 2 */;\n this.moversContainer.style.transform = `matrix(${scaleX}, 0, 0, ${scaleY}, ${left}, ${top})`;\n } else {\n mover.style.transform = transform;\n }\n\n needOpacity && (mover.style.opacity = '0'/* !closing ? '0' : '' */);\n\n /* if(wasActive) {\n this.log('setMoverToTarget', mover.style.transform);\n } */\n\n let path: SVGPathElement;\n const isOut = target.classList.contains('is-out');\n\n const deferred = this.setMoverAnimationPromise = deferredPromise<void>();\n const ret = {onAnimationEnd: deferred};\n\n const timeout = setTimeout(() => {\n if(!deferred.isFulfilled && !deferred.isRejected) {\n deferred.resolve();\n }\n }, 1000);\n\n deferred.finally(() => {\n this.dispatchEvent('setMoverAfter');\n\n if(this.setMoverAnimationPromise === deferred) {\n this.setMoverAnimationPromise = null;\n }\n \n clearTimeout(timeout);\n });\n\n if(!closing) {\n let mediaElement: HTMLImageElement | HTMLVideoElement;\n let src: string;\n\n if(target instanceof HTMLVideoElement) {\n const elements = Array.from(target.parentElement.querySelectorAll('img')) as HTMLImageElement[];\n if(elements.length) {\n target = elements.pop();\n }\n }\n\n if(target.tagName === 'DIV' || target.tagName === 'AVATAR-ELEMENT') { // useContainerAsTarget\n const images = Array.from(target.querySelectorAll('img')) as HTMLImageElement[];\n const image = images.pop();\n if(image) {\n mediaElement = new Image();\n src = image.src;\n mover.append(mediaElement);\n }\n /* mediaElement = new Image();\n src = target.style.backgroundImage.slice(5, -2); */\n \n } else if(target instanceof HTMLImageElement) {\n mediaElement = new Image();\n src = target.src;\n } else if(target instanceof HTMLVideoElement) {\n mediaElement = document.createElement('video');\n mediaElement.src = target.src;\n } else if(target instanceof SVGSVGElement) {\n const clipId = target.dataset.clipId;\n const newClipId = clipId + '-mv';\n\n const {width, height} = containerRect;\n\n const newSvg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n newSvg.setAttributeNS(null, 'width', '' + width);\n newSvg.setAttributeNS(null, 'height', '' + height);\n\n // нижние два свойства для масштабирования\n newSvg.setAttributeNS(null, 'viewBox', `0 0 ${width} ${height}`);\n newSvg.setAttributeNS(null, 'preserveAspectRatio', 'xMidYMid meet');\n\n newSvg.insertAdjacentHTML('beforeend', target.firstElementChild.outerHTML.replace(clipId, newClipId));\n newSvg.insertAdjacentHTML('beforeend', target.lastElementChild.outerHTML.replace(clipId, newClipId));\n\n // теперь надо выставить новую позицию для хвостика\n const defs = newSvg.firstElementChild;\n const use = defs.firstElementChild.firstElementChild as SVGUseElement;\n if(use instanceof SVGUseElement) {\n let transform = use.getAttributeNS(null, 'transform');\n transform = transform.replace(/translate\\((.+?), (.+?)\\) scale\\((.+?), (.+?)\\)/, (match, x, y, sX, sY) => {\n x = +x;\n if(x !== 2) {\n x = width - (2 / scaleX);\n } else {\n x = 2 / scaleX;\n }\n \n y = height;\n \n return `translate(${x}, ${y}) scale(${+sX / scaleX}, ${+sY / scaleY})`;\n });\n use.setAttributeNS(null, 'transform', transform);\n \n // и новый RECT\n path = defs.firstElementChild.lastElementChild as SVGPathElement;\n\n // код ниже нужен только чтобы скрыть моргание до момента как сработает таймаут\n let d: string;\n const br: [number, number, number, number] = borderRadius.split(' ').map(v => parseInt(v)) as any;\n if(isOut) d = generatePathData(0, 0, width - 9 / scaleX, height, ...br);\n else d = generatePathData(9 / scaleX, 0, width - 9 / scaleX, height, ...br);\n path.setAttributeNS(null, 'd', d);\n }\n\n const foreignObject = newSvg.lastElementChild;\n foreignObject.setAttributeNS(null, 'width', '' + containerRect.width);\n foreignObject.setAttributeNS(null, 'height', '' + containerRect.height);\n \n mover.prepend(newSvg);\n }\n\n if(aspecter) {\n aspecter.style.borderRadius = borderRadius;\n\n if(mediaElement) {\n aspecter.append(mediaElement);\n }\n }\n\n mediaElement = mover.querySelector('video, img');\n if(mediaElement instanceof HTMLImageElement) {\n mediaElement.classList.add('thumbnail');\n if(!aspecter) {\n mediaElement.style.width = containerRect.width + 'px';\n mediaElement.style.height = containerRect.height + 'px';\n }\n\n if(src) {\n await renderImageFromUrlPromise(mediaElement, src);\n }\n }/* else if(mediaElement instanceof HTMLVideoElement && mediaElement.firstElementChild && ((mediaElement.firstElementChild as HTMLSourceElement).src || src)) {\n await new Promise((resolve, reject) => {\n mediaElement.addEventListener('loadeddata', resolve);\n\n if(src) {\n (mediaElement.firstElementChild as HTMLSourceElement).src = src;\n }\n });\n } */\n \n mover.style.display = '';\n\n fastRaf(() => {\n mover.classList.add(wasActive ? 'moving' : 'active');\n });\n } else {\n /* if(mover.classList.contains('center')) {\n mover.classList.remove('center');\n void mover.offsetLeft; // reflow\n } */\n \n if(target instanceof SVGSVGElement) {\n path = mover.querySelector('path');\n\n if(path) {\n this.sizeTailPath(path, containerRect, scaleX, delay, false, isOut, borderRadius);\n }\n }\n\n if(target.classList.contains('media-viewer-media')) {\n mover.classList.add('hiding');\n }\n\n this.wholeDiv.classList.add('backwards');\n setTimeout(() => {\n this.wholeDiv.classList.remove('active');\n }, 0);\n\n //return ret;\n\n setTimeout(() => {\n mover.style.borderRadius = borderRadius;\n\n if(mover.firstElementChild) {\n (mover.firstElementChild as HTMLElement).style.borderRadius = borderRadius;\n }\n }, delay / 2);\n\n setTimeout(() => {\n mover.innerHTML = '';\n mover.classList.remove('moving', 'active', 'hiding');\n mover.style.cssText = 'display: none;';\n\n deferred.resolve();\n }, delay);\n\n mover.classList.remove('opening');\n\n return ret;\n }\n\n mover.classList.add('opening');\n\n //await new Promise((resolve) => setTimeout(resolve, 0));\n //await new Promise((resolve) => window.requestAnimationFrame(resolve));\n // * одного RAF'а недостаточно, иногда анимация с одним не срабатывает (преимущественно на мобильных)\n await doubleRaf();\n\n // чтобы проверить установленную позицию - раскомментировать\n // throw '';\n\n //await new Promise((resolve) => setTimeout(resolve, 5e3));\n\n mover.style.transform = `translate3d(${containerRect.left}px,${containerRect.top}px,0) scale3d(1,1,1)`;\n //mover.style.transform = `translate(-50%,-50%) scale(1,1)`;\n needOpacity && (mover.style.opacity = ''/* closing ? '0' : '' */);\n\n if(aspecter) {\n this.setFullAspect(aspecter, containerRect, rect);\n }\n\n //throw '';\n\n setTimeout(() => {\n mover.style.borderRadius = '';\n\n if(mover.firstElementChild) {\n (mover.firstElementChild as HTMLElement).style.borderRadius = '';\n }\n }, 0/* delay / 2 */);\n\n mover.dataset.timeout = '' + setTimeout(() => {\n mover.classList.remove('moving', 'opening');\n\n if(aspecter) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать\n if(mover.querySelector('video') || true) {\n mover.classList.remove('active');\n aspecter.style.cssText = '';\n void mover.offsetLeft; // reflow\n }\n \n //aspecter.classList.remove('disable-hover');\n }\n\n // эти строки нужны для установки центральной позиции, в случае ресайза это будет нужно\n mover.classList.add('center', 'no-transition');\n /* mover.style.left = mover.style.top = '50%';\n mover.style.transform = 'translate(-50%, -50%)';\n void mover.offsetLeft; // reflow */\n\n // это уже нужно для будущих анимаций\n mover.classList.add('active');\n delete mover.dataset.timeout;\n\n deferred.resolve();\n }, delay);\n\n if(path) {\n this.sizeTailPath(path, containerRect, scaleX, delay, true, isOut, borderRadius);\n }\n\n return ret;\n }\n\n protected setFullAspect(aspecter: HTMLDivElement, containerRect: DOMRect, rect: DOMRect) {\n /* let media = aspecter.firstElementChild;\n let proportion: number;\n if(media instanceof HTMLImageElement) {\n proportion = media.naturalWidth / media.naturalHeight;\n } else if(media instanceof HTMLVideoElement) {\n proportion = media.videoWidth / media.videoHeight;\n } */\n const proportion = containerRect.width / containerRect.height;\n\n let {width, height} = rect;\n /* if(proportion === 1) {\n aspecter.style.cssText = '';\n } else { */\n if(proportion > 0) {\n width = height * proportion;\n } else {\n height = width * proportion;\n }\n\n //this.log('will set style aspecter:', `width: ${width}px; height: ${height}px; transform: scale(${containerRect.width / width}, ${containerRect.height / height});`);\n\n aspecter.style.cssText = `width: ${width}px; height: ${height}px; transform: scale3d(${containerRect.width / width}, ${containerRect.height / height}, 1);`;\n //}\n }\n\n protected sizeTailPath(path: SVGPathElement, rect: DOMRect, scaleX: number, delay: number, upscale: boolean, isOut: boolean, borderRadius: string) {\n const start = Date.now();\n const {width, height} = rect;\n delay = delay / 2;\n\n const br = borderRadius.split(' ').map(v => parseInt(v));\n\n const step = () => {\n const diff = Date.now() - start;\n\n let progress = delay ? diff / delay : 1;\n if(progress > 1) progress = 1;\n if(upscale) progress = 1 - progress;\n\n const _br: [number, number, number, number] = br.map(v => v * progress) as any;\n\n let d: string;\n if(isOut) d = generatePathData(0, 0, width - (9 / scaleX * progress), height, ..._br);\n else d = generatePathData(9 / scaleX * progress, 0, width/* width - (9 / scaleX * progress) */, height, ..._br);\n path.setAttributeNS(null, 'd', d);\n\n if(diff < delay) fastRaf(step);\n };\n \n //window.requestAnimationFrame(step);\n step();\n }\n\n protected removeCenterFromMover(mover: HTMLElement) {\n if(mover.classList.contains('center')) {\n //const rect = mover.getBoundingClientRect();\n const rect = this.content.media.getBoundingClientRect();\n mover.style.transform = `translate3d(${rect.left}px,${rect.top}px,0)`;\n mover.classList.remove('center');\n void mover.offsetLeft; // reflow\n mover.classList.remove('no-transition');\n }\n }\n\n protected moveTheMover(mover: HTMLElement, toLeft = true) {\n const windowW = windowSize.windowW;\n\n this.removeCenterFromMover(mover);\n\n //mover.classList.remove('active');\n mover.classList.add('moving');\n\n if(mover.dataset.timeout) { // и это тоже всё из-за скейла видео, так бы это не нужно было\n clearTimeout(+mover.dataset.timeout);\n }\n\n const rect = mover.getBoundingClientRect();\n\n const newTransform = mover.style.transform.replace(/translate3d\\((.+?),/, (match, p1) => {\n const x = toLeft ? -rect.width : windowW;\n //const x = toLeft ? -(rect.right + (rect.width / 2)) : windowW / 2;\n\n return match.replace(p1, x + 'px');\n });\n\n ////////this.log('set newTransform:', newTransform, mover.style.transform, toLeft);\n mover.style.transform = newTransform;\n\n setTimeout(() => {\n mover.remove();\n }, 350);\n }\n\n protected setNewMover() {\n const newMover = document.createElement('div');\n newMover.classList.add('media-viewer-mover');\n newMover.style.display = 'none';\n\n if(this.content.mover) {\n const oldMover = this.content.mover;\n oldMover.parentElement.append(newMover);\n } else {\n this.moversContainer.append(newMover);\n }\n\n return this.content.mover = newMover;\n }\n\n protected updateMediaSource(target: HTMLElement, url: string, tagName: 'video' | 'img') {\n //if(target instanceof SVGSVGElement) {\n const el = target.tagName.toLowerCase() === tagName ? target : target.querySelector(tagName) as HTMLElement;\n if(el) {\n if(!target.classList.contains('document-ico') && findUpClassName(target, 'attachment')) {\n // two parentElements because element can be contained in aspecter\n const preloader = target.parentElement.parentElement.querySelector('.preloader-container') as HTMLElement;\n if(preloader) {\n if(tagName === 'video') {\n if(preloader.classList.contains('manual')) {\n preloader.click();\n // return;\n }\n \n return;\n }\n \n preloader.remove();\n }\n }\n\n renderImageFromUrl(el, url);\n\n // ! костыль, но он тут даже и не нужен\n if(el.classList.contains('thumbnail') && el.parentElement.classList.contains('media-container-aspecter')) {\n el.classList.remove('thumbnail');\n }\n }\n /* } else {\n\n } */\n }\n\n protected setAuthorInfo(fromId: number, timestamp: number) {\n replaceContent(this.author.date, formatFullSentTime(timestamp));\n\n replaceContent(this.author.nameEl, new PeerTitle({\n peerId: fromId,\n dialog: false,\n onlyFirstName: false,\n plainText: false\n }).element);\n\n let oldAvatar = this.author.avatarEl;\n this.author.avatarEl = (this.author.avatarEl.cloneNode() as AvatarElement);\n this.author.avatarEl.setAttribute('peer', '' + (fromId || rootScope.myId));\n oldAvatar.parentElement.replaceChild(this.author.avatarEl, oldAvatar);\n }\n \n protected async _openMedia(\n media: MyDocument | MyPhoto, \n timestamp: number, \n fromId: number, \n fromRight: number, \n target?: HTMLElement, \n reverse = false, \n prevTargets: TargetType[] = [], \n nextTargets: TargetType[] = [], \n message?: Message.message\n /* , needLoadMore = true */\n ) {\n if(this.setMoverPromise) return this.setMoverPromise;\n\n /* if(DEBUG) {\n this.log('openMedia:', media, fromId, prevTargets, nextTargets);\n } */\n\n this.setAuthorInfo(fromId, timestamp);\n \n const isDocument = media._ === 'document';\n const isVideo = isDocument && media.mime_type && ((['video', 'gif'] as MyDocument['type'][]).includes(media.type) || media.mime_type.indexOf('video/') === 0);\n\n if(this.isFirstOpen) {\n //this.targetContainer = targetContainer;\n // this.needLoadMore = needLoadMore;\n this.isFirstOpen = false;\n this.listLoader.setTargets(prevTargets, nextTargets, reverse);\n (window as any).appMediaViewer = this;\n //this.loadMore = loadMore;\n\n /* if(appSidebarRight.historyTabIDs.slice(-1)[0] === AppSidebarRight.SLIDERITEMSIDS.forward) {\n appSidebarRight.forwardTab.closeBtn.click();\n await new Promise((resolve) => setTimeout(resolve, 200));\n } */\n }\n\n /* if(this.nextTargets.length < 10 && this.loadMore) {\n this.loadMore();\n } */\n\n //if(prevTarget && (!prevTarget.parentElement || !this.isElementVisible(this.targetContainer, prevTarget))) prevTarget = null;\n //if(nextTarget && (!nextTarget.parentElement || !this.isElementVisible(this.targetContainer, nextTarget))) nextTarget = null;\n\n this.buttons.prev.classList.toggle('hide', !this.listLoader.previous.length);\n this.buttons.next.classList.toggle('hide', !this.listLoader.next.length);\n \n const container = this.content.media;\n const useContainerAsTarget = !target || target === container;\n if(useContainerAsTarget) target = container;\n\n this.target = {element: target} as any;\n const tempId = ++this.tempId;\n\n if(container.firstElementChild) {\n container.innerHTML = '';\n }\n \n // ok set\n\n const wasActive = fromRight !== 0;\n if(wasActive) {\n this.moveTheMover(this.content.mover, fromRight === 1);\n this.setNewMover();\n } else {\n window.addEventListener('keydown', this.onKeyDown);\n window.addEventListener('keyup', this.onKeyUp);\n if(!IS_TOUCH_SUPPORTED) window.addEventListener('wheel', this.onWheel, {passive: false, capture: true});\n const mainColumns = document.getElementById('main-columns');\n this.pageEl.insertBefore(this.wholeDiv, mainColumns);\n void this.wholeDiv.offsetLeft; // reflow\n this.wholeDiv.classList.add('active');\n rootScope.isOverlayActive = true;\n animationIntersector.checkAnimations(true);\n\n if(!IS_MOBILE_SAFARI) {\n appNavigationController.pushItem({\n type: 'media',\n onPop: (canAnimate) => {\n if(this.setMoverAnimationPromise) {\n return false;\n }\n \n this.close();\n }\n });\n }\n }\n\n ////////this.log('wasActive:', wasActive);\n\n const mover = this.content.mover;\n\n const maxWidth = windowSize.windowW;\n //const maxWidth = this.pageEl.scrollWidth;\n // TODO: const maxHeight = mediaSizes.isMobile ? appPhotosManager.windowH : appPhotosManager.windowH - 100;\n let padding = 0;\n const windowH = windowSize.windowH;\n if(windowH < 1000000 && !mediaSizes.isMobile) {\n padding = 120;\n }\n const maxHeight = windowH - 120 - padding;\n let thumbPromise: Promise<any> = Promise.resolve();\n const size = appPhotosManager.setAttachmentSize(media, container, maxWidth, maxHeight, mediaSizes.isMobile ? false : true, undefined, !!(isDocument && media.w && media.h)).photoSize;\n if(useContainerAsTarget) {\n const cacheContext = appDownloadManager.getCacheContext(media, size.type);\n let img: HTMLImageElement;\n if(cacheContext.downloaded) {\n img = new Image();\n img.src = cacheContext.url;\n } else {\n const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(media, cacheContext, true);\n if(gotThumb) {\n thumbPromise = gotThumb.loadPromise;\n img = gotThumb.image;\n }\n }\n\n if(img) {\n img.classList.add('thumbnail');\n container.append(img);\n }\n }\n\n // need after setAttachmentSize\n /* if(useContainerAsTarget) {\n target = target.querySelector('img, video') || target;\n } */\n\n const supportsStreaming: boolean = !!(isDocument && media.supportsStreaming);\n const preloader = supportsStreaming ? this.preloaderStreamable : this.preloader;\n\n let setMoverPromise: Promise<void>;\n if(isVideo) {\n ////////this.log('will wrap video', media, size);\n\n // потому что для safari нужно создать элемент из event'а\n // const video = document.createElement('video');\n const useController = message && media.type !== 'gif';\n const video = /* useController ? \n appMediaPlaybackController.addMedia(message, false, true) as HTMLVideoElement : \n */document.createElement('video');\n\n const set = () => this.setMoverToTarget(target, false, fromRight).then(({onAnimationEnd}) => {\n //return; // set and don't move\n //if(wasActive) return;\n //return;\n \n const div = mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter') ? mover.firstElementChild : mover;\n //const video = mover.querySelector('video') || document.createElement('video');\n \n const moverVideo = mover.querySelector('video');\n if(moverVideo) {\n moverVideo.remove();\n }\n \n //video.src = '';\n \n video.setAttribute('playsinline', 'true');\n \n // * fix for playing video if viewer is closed (https://contest.com/javascript-web-bonus/entry1425#issue11629)\n video.addEventListener('timeupdate', () => {\n if(this.tempId !== tempId) {\n video.pause();\n }\n });\n\n video.addEventListener('error', () => {\n if(video.error.code !== 4) {\n this.log.error(\"Error \" + video.error.code + \"; details: \" + video.error.message);\n }\n\n if(preloader) {\n preloader.detach();\n }\n }, {once: true});\n\n this.addEventListener('setMoverAfter', () => {\n video.src = '';\n video.load();\n }, {once: true});\n \n if(IS_SAFARI) {\n // test stream\n // video.controls = true;\n video.autoplay = true;\n }\n \n if(media.type === 'gif') {\n video.muted = true;\n video.autoplay = true;\n video.loop = true;\n }\n \n // if(!video.parentElement) {\n div.append(video);\n // }\n \n const canPlayThrough = new Promise((resolve) => {\n video.addEventListener('canplay', resolve, {once: true});\n });\n \n const createPlayer = () => {\n if(media.type !== 'gif') {\n video.dataset.ckin = 'default';\n video.dataset.overlay = '1';\n\n Promise.all([canPlayThrough, onAnimationEnd]).then(() => {\n if(this.tempId !== tempId) {\n return;\n }\n \n // const play = useController ? appMediaPlaybackController.willBePlayedMedia === video : true;\n const play = true;\n const player = this.videoPlayer = new VideoPlayer(video, play, supportsStreaming);\n player.addEventListener('toggleControls', (show) => {\n this.wholeDiv.classList.toggle('has-video-controls', show);\n });\n\n this.addEventListener('setMoverBefore', () => {\n this.wholeDiv.classList.remove('has-video-controls');\n this.videoPlayer.removeListeners();\n this.videoPlayer = undefined;\n }, {once: true});\n\n if(this.isZooming()) {\n this.videoPlayer.lockControls(false);\n }\n /* div.append(video);\n mover.append(player.wrapper); */\n });\n }\n };\n \n if(supportsStreaming) {\n onAnimationEnd.then(() => {\n if(video.readyState < video.HAVE_FUTURE_DATA) {\n preloader.attach(mover, true);\n }\n \n /* canPlayThrough.then(() => {\n preloader.detach();\n }); */\n });\n \n const attachCanPlay = () => {\n video.addEventListener('canplay', () => {\n //this.log('video waited and progress loaded');\n preloader.detach();\n video.parentElement.classList.remove('is-buffering');\n }, {once: true});\n };\n \n video.addEventListener('waiting', () => {\n const loading = video.networkState === video.NETWORK_LOADING;\n const isntEnoughData = video.readyState < video.HAVE_FUTURE_DATA;\n \n //this.log('video waiting for progress', loading, isntEnoughData);\n if(loading && isntEnoughData) {\n attachCanPlay();\n \n preloader.attach(mover, true);\n \n // поставлю класс для плеера, чтобы убрать большую иконку пока прелоадер на месте\n video.parentElement.classList.add('is-buffering');\n }\n });\n \n attachCanPlay();\n }\n \n //if(!video.src || media.url !== video.src) {\n const load = () => {\n /* if(useController) {\n appMediaPlaybackController.resolveWaitingForLoadMedia(message.peerId, message.mid, message.pFlags.is_scheduled);\n } */\n\n const cacheContext = appDownloadManager.getCacheContext(media);\n const promise: Promise<any> = supportsStreaming ? Promise.resolve() : appDocsManager.downloadDoc(media);\n \n if(!supportsStreaming) {\n onAnimationEnd.then(() => {\n if(!cacheContext.url) {\n preloader.attach(mover, true, promise);\n }\n });\n }\n \n Promise.all([promise, onAnimationEnd]).then(() => {\n if(this.tempId !== tempId) {\n this.log.warn('media viewer changed video');\n return;\n }\n\n if(useController) {\n const rollback = appMediaPlaybackController.setSingleMedia(video, message);\n\n this.addEventListener('setMoverBefore', () => {\n rollback();\n }, {once: true});\n }\n \n const url = cacheContext.url;\n if(target instanceof SVGSVGElement/* && (video.parentElement || !isSafari) */) { // if video exists\n //if(!video.parentElement) {\n div.firstElementChild.lastElementChild.append(video);\n //}\n } else {\n renderImageFromUrl(video, url);\n }\n\n this.updateMediaSource(target, url, 'video');\n\n createPlayer();\n });\n \n return promise;\n };\n \n this.lazyLoadQueue.unshift({load});\n //} else createPlayer();\n });\n\n setMoverPromise = thumbPromise.then(set);\n } else {\n const set = () => this.setMoverToTarget(target, false, fromRight).then(({onAnimationEnd}) => {\n //return; // set and don't move\n //if(wasActive) return;\n //return;\n \n const load = () => {\n const cacheContext = appDownloadManager.getCacheContext(media, size.type);\n const cancellablePromise = isDocument ? appDocsManager.downloadDoc(media) : appPhotosManager.preloadPhoto(media, size);\n \n onAnimationEnd.then(() => {\n if(!cacheContext.url) {\n this.preloader.attachPromise(cancellablePromise);\n //this.preloader.attach(mover, true, cancellablePromise);\n }\n });\n \n Promise.all([onAnimationEnd, cancellablePromise]).then(() => {\n if(this.tempId !== tempId) {\n this.log.warn('media viewer changed photo');\n return;\n }\n \n ///////this.log('indochina', blob);\n \n const url = cacheContext.url;\n if(target instanceof SVGSVGElement) {\n this.updateMediaSource(target, url, 'img');\n this.updateMediaSource(mover, url, 'img');\n \n if(mediaSizes.isMobile) {\n const imgs = mover.querySelectorAll('img');\n if(imgs && imgs.length) {\n imgs.forEach(img => {\n img.classList.remove('thumbnail'); // может здесь это вообще не нужно\n });\n }\n }\n } else {\n const div = mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter') ? mover.firstElementChild : mover;\n const haveImage = div.firstElementChild?.tagName === 'IMG' ? div.firstElementChild as HTMLImageElement : null;\n if(!haveImage || haveImage.src !== url) {\n let image = new Image();\n image.classList.add('thumbnail');\n \n //this.log('will renderImageFromUrl:', image, div, target);\n \n renderImageFromUrl(image, url, () => {\n this.updateMediaSource(target, url, 'img');\n \n if(haveImage) {\n fastRaf(() => {\n haveImage.remove();\n });\n }\n \n div.append(image);\n });\n }\n }\n \n //this.preloader.detach();\n }).catch(err => {\n this.log.error(err);\n this.preloader.attach(mover);\n this.preloader.setManual();\n });\n \n return cancellablePromise;\n };\n \n this.lazyLoadQueue.unshift({load});\n });\n\n setMoverPromise = thumbPromise.then(set);\n }\n\n return this.setMoverPromise = setMoverPromise.catch(() => {\n this.setMoverAnimationPromise = null;\n }).finally(() => {\n this.setMoverPromise = null;\n });\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function getVisibleRect(element: HTMLElement, overflowElement: HTMLElement) {\r\n const rect = element.getBoundingClientRect();\r\n const overflowRect = overflowElement.getBoundingClientRect();\r\n\r\n let {top: overflowTop, bottom: overflowBottom} = overflowRect;\r\n\r\n // * respect sticky headers\r\n const sticky = overflowElement.querySelector('.sticky');\r\n if(sticky) {\r\n const stickyRect = sticky.getBoundingClientRect();\r\n overflowTop = stickyRect.bottom;\r\n }\r\n\r\n if(rect.top >= overflowBottom\r\n || rect.bottom <= overflowTop\r\n || rect.right <= overflowRect.left\r\n || rect.left >= overflowRect.right) {\r\n return null;\r\n }\r\n\r\n const overflow = {\r\n top: false,\r\n right: false,\r\n bottom: false,\r\n left: false,\r\n vertical: 0 as 0 | 1 | 2,\r\n horizontal: 0 as 0 | 1 | 2\r\n };\r\n\r\n // @ts-ignore\r\n const w: any = 'visualViewport' in window ? window.visualViewport : window;\r\n const windowWidth = w.width || w.innerWidth;\r\n const windowHeight = w.height || w.innerHeight;\r\n\r\n return {\r\n rect: {\r\n top: rect.top < overflowTop && overflowTop !== 0 ? (overflow.top = true, ++overflow.vertical, overflowTop) : rect.top,\r\n right: 0,\r\n bottom: rect.bottom > overflowBottom && overflowBottom !== windowHeight ? (overflow.bottom = true, ++overflow.vertical, overflowBottom) : rect.bottom,\r\n left: 0\r\n },\r\n overflow\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport default function fillPropertyValue(str: string) {\r\n let splitted = str.split(' ');\r\n if(splitted.length !== 4) {\r\n if(!splitted[0]) splitted[0] = '0px';\r\n for(let i = splitted.length; i < 4; ++i) {\r\n splitted[i] = splitted[i % 2] || splitted[0] || '0px';\r\n }\r\n }\r\n\r\n return splitted;\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport MEDIA_MIME_TYPES_SUPPORTED from \"../environment/mediaMimeTypesSupport\";\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\nimport setInnerHTML from \"../helpers/dom/setInnerHTML\";\nimport mediaSizes from \"../helpers/mediaSizes\";\nimport SearchListLoader from \"../helpers/searchListLoader\";\nimport { Message } from \"../layer\";\nimport appDocsManager, { MyDocument } from \"../lib/appManagers/appDocsManager\";\nimport appImManager from \"../lib/appManagers/appImManager\";\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\nimport appPhotosManager, { MyPhoto } from \"../lib/appManagers/appPhotosManager\";\nimport RichTextProcessor from \"../lib/richtextprocessor\";\nimport { MediaSearchContext } from \"./appMediaPlaybackController\";\nimport AppMediaViewerBase, { MEDIA_VIEWER_CLASSNAME } from \"./appMediaViewerBase\";\nimport { ButtonMenuItemOptions } from \"./buttonMenu\";\nimport PopupDeleteMessages from \"./popups/deleteMessages\";\nimport PopupForward from \"./popups/forward\";\nimport Scrollable from \"./scrollable\";\nimport appSidebarRight from \"./sidebarRight\";\nimport AppSharedMediaTab from \"./sidebarRight/tabs/sharedMedia\";\n\ntype AppMediaViewerTargetType = {\n element: HTMLElement,\n mid: number,\n peerId: number\n};\nexport default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delete' | 'forward', AppMediaViewerTargetType> {\n protected btnMenuDelete: HTMLElement;\n protected listLoader: SearchListLoader<AppMediaViewerTargetType>;\n\n get searchContext() {\n return this.listLoader.searchContext;\n }\n\n constructor() {\n super(new SearchListLoader({\n processItem: (item) => {\n const isForDocument = this.searchContext.inputFilter._ === 'inputMessagesFilterDocument';\n const {mid, peerId} = item;\n const media: MyPhoto | MyDocument = appMessagesManager.getMediaFromMessage(item);\n\n if(!media) return;\n \n if(isForDocument && !AppMediaViewer.isMediaCompatibleForDocumentViewer(media)) {\n return;\n }\n\n return {element: null as HTMLElement, mid, peerId};\n }\n }), ['delete', 'forward']);\n\n this.listLoader.onEmptied = () => {\n this.close();\n };\n\n /* const stub = document.createElement('div');\n stub.classList.add(MEDIA_VIEWER_CLASSNAME + '-stub');\n this.content.main.prepend(stub); */\n\n this.content.caption = document.createElement('div');\n this.content.caption.classList.add(MEDIA_VIEWER_CLASSNAME + '-caption'/* , 'media-viewer-stub' */);\n\n let captionTimeout: number;\n const setCaptionTimeout = () => {\n if(captionTimeout) {\n clearTimeout(captionTimeout);\n }\n\n captionTimeout = window.setTimeout(() => {\n captionTimeout = undefined;\n this.content.caption.classList.remove('is-focused');\n }, 800);\n };\n this.content.caption.addEventListener('touchstart', () => {\n if(!mediaSizes.isMobile) return;\n\n this.content.caption.classList.add('is-focused');\n \n if(captionTimeout) {\n clearTimeout(captionTimeout);\n captionTimeout = undefined;\n }\n \n document.addEventListener('touchend', setCaptionTimeout, {once: true});\n });\n\n const captionScrollable = new Scrollable(this.content.caption);\n captionScrollable.onAdditionalScroll = setCaptionTimeout;\n\n //this.content.main.append(this.content.caption);\n this.wholeDiv.append(this.content.caption);\n\n attachClickEvent(this.buttons.delete, this.onDeleteClick);\n\n const buttons: ButtonMenuItemOptions[] = [{\n icon: 'forward',\n text: 'Forward',\n onClick: this.onForwardClick\n }, {\n icon: 'download',\n text: 'MediaViewer.Context.Download',\n onClick: this.onDownloadClick\n }, {\n icon: 'delete danger',\n text: 'Delete',\n onClick: this.onDeleteClick\n }];\n\n this.setBtnMenuToggle(buttons);\n this.btnMenuDelete = buttons[buttons.length - 1].element;\n\n // * constructing html end\n \n this.setListeners();\n }\n\n protected setListeners() {\n super.setListeners();\n this.buttons.forward.addEventListener('click', this.onForwardClick);\n this.author.container.addEventListener('click', this.onAuthorClick);\n\n const onCaptionClick = (e: MouseEvent) => {\n if(e.target instanceof HTMLAnchorElement) { // close viewer if it's t.me/ redirect\n const onclick = (e.target as HTMLElement).getAttribute('onclick');\n if(!onclick || onclick.includes('showMaskedAlert')) {\n return;\n }\n\n cancelEvent(e);\n\n this.close().then(() => {\n this.content.caption.removeEventListener('click', onCaptionClick, {capture: true});\n (e.target as HTMLAnchorElement).click();\n });\n\n return false;\n }\n };\n this.content.caption.addEventListener('click', onCaptionClick, {capture: true});\n }\n\n /* public close(e?: MouseEvent) {\n const good = !this.setMoverAnimationPromise;\n const promise = super.close(e);\n\n if(good) { // clear\n this.currentMessageId = 0;\n this.peerId = 0;\n }\n\n return promise;\n } */\n\n protected getMessageByPeer(peerId: number, mid: number) {\n return this.searchContext.isScheduled ? appMessagesManager.getScheduledMessageByPeer(peerId, mid) : appMessagesManager.getMessageByPeer(peerId, mid);\n }\n\n onPrevClick = (target: AppMediaViewerTargetType) => {\n this.openMedia(this.getMessageByPeer(target.peerId, target.mid), target.element, -1);\n };\n\n onNextClick = (target: AppMediaViewerTargetType) => {\n this.openMedia(this.getMessageByPeer(target.peerId, target.mid), target.element, 1);\n };\n\n onDeleteClick = () => {\n const target = this.target;\n new PopupDeleteMessages(target.peerId, [target.mid], 'chat', () => {\n this.target = {element: this.content.media} as any;\n this.close();\n });\n };\n\n onForwardClick = () => {\n const target = this.target;\n if(target.mid) {\n //appSidebarRight.forwardTab.open([target.mid]);\n new PopupForward({\n [target.peerId]: [target.mid]\n }, () => {\n return this.close();\n });\n }\n };\n\n onAuthorClick = (e: MouseEvent) => {\n const {mid, peerId} = this.target;\n if(mid && mid !== Number.MAX_SAFE_INTEGER) {\n const threadId = this.searchContext.threadId;\n this.close(e)\n //.then(() => mediaSizes.isMobile ? appSidebarRight.sharedMediaTab.closeBtn.click() : Promise.resolve())\n .then(() => {\n if(mediaSizes.isMobile) {\n const tab = appSidebarRight.getTab(AppSharedMediaTab);\n if(tab) {\n tab.close();\n }\n }\n\n const message = this.getMessageByPeer(peerId, mid);\n appImManager.setInnerPeer(message.peerId, mid, threadId ? 'discussion' : undefined, threadId);\n });\n }\n };\n\n onDownloadClick = () => {\n const {peerId, mid} = this.target;\n const message = this.getMessageByPeer(peerId, mid);\n if(message.media.photo) {\n appPhotosManager.savePhotoFile(message.media.photo, appImManager.chat.bubbles.lazyLoadQueue.queueId);\n } else {\n let document: MyDocument = null;\n\n if(message.media.webpage) document = message.media.webpage.document;\n else document = message.media.document;\n\n if(document) {\n //console.log('will save document:', document);\n appDocsManager.saveDocFile(document, appImManager.chat.bubbles.lazyLoadQueue.queueId);\n }\n }\n };\n\n private setCaption(message: Message.message) {\n const caption = message.message;\n let html = '';\n if(caption) {\n html = RichTextProcessor.wrapRichText(caption, {\n entities: message.totalEntities\n });\n }\n \n // html = 'Dandelion are a family of flowering plants that grow in many parts of the world.';\n setInnerHTML(this.content.caption.firstElementChild, html);\n this.content.caption.classList.toggle('hide', !caption);\n // this.content.container.classList.toggle('with-caption', !!caption);\n }\n\n public setSearchContext(context: MediaSearchContext) {\n this.listLoader.setSearchContext(context);\n\n return this;\n }\n\n public async openMedia(message: any, target?: HTMLElement, fromRight = 0, reverse = false, \n prevTargets: AppMediaViewerTargetType[] = [], nextTargets: AppMediaViewerTargetType[] = []/* , needLoadMore = true */) {\n if(this.setMoverPromise) return this.setMoverPromise;\n\n const mid = message.mid;\n const fromId = message.fromId;\n const media = appMessagesManager.getMediaFromMessage(message);\n\n this.buttons.forward.classList.toggle('hide', message._ === 'messageService');\n\n const canDeleteMessage = appMessagesManager.canDeleteMessage(message);\n [this.buttons.delete, this.btnMenuDelete].forEach(button => {\n button.classList.toggle('hide', !canDeleteMessage);\n });\n\n this.setCaption(message);\n const promise = super._openMedia(media, message.date, fromId, fromRight, target, reverse, prevTargets, nextTargets, message/* , needLoadMore */);\n this.target.mid = mid;\n this.target.peerId = message.peerId;\n\n return promise;\n }\n\n public static isMediaCompatibleForDocumentViewer(media: MyPhoto | MyDocument) {\n return media._ === 'photo' || MEDIA_MIME_TYPES_SUPPORTED.has(media.mime_type);\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\nimport ListLoader, { ListLoaderOptions } from \"./listLoader\";\n\nexport default class AvatarListLoader<Item extends {photoId: string}> extends ListLoader<Item, any> {\n private peerId: number;\n\n constructor(options: Omit<ListLoaderOptions<Item, any>, 'loadMore'> & {peerId: number}) {\n super({\n ...options,\n loadMore: (anchor, older, loadCount) => {\n if(this.peerId < 0 || !older) return Promise.resolve({count: 0, items: []}); // ! это значит, что открыло аватар чата, но следующих фотографий нет.\n\n const maxId = anchor?.photoId;\n return appPhotosManager.getUserPhotos(this.peerId, maxId, loadCount).then(value => {\n const items = value.photos.map(photoId => {\n return {element: null as HTMLElement, photoId} as any;\n });\n\n return {count: value.count, items};\n });\n }\n });\n\n this.loadedAllUp = true;\n this.peerId = options.peerId;\n }\n}\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport AvatarListLoader from \"../helpers/avatarListLoader\";\nimport appImManager from \"../lib/appManagers/appImManager\";\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\nimport AppMediaViewerBase from \"./appMediaViewerBase\";\n\ntype AppMediaViewerAvatarTargetType = {element: HTMLElement, photoId: string};\nexport default class AppMediaViewerAvatar extends AppMediaViewerBase<'', 'delete', AppMediaViewerAvatarTargetType> {\n public peerId: number;\n\n constructor(peerId: number) {\n super(new AvatarListLoader({peerId}), [/* 'delete' */]);\n\n this.peerId = peerId;\n\n this.setBtnMenuToggle([{\n icon: 'download',\n text: 'MediaViewer.Context.Download',\n onClick: this.onDownloadClick\n }/* , {\n icon: 'delete danger btn-disabled',\n text: 'Delete',\n onClick: () => {}\n } */]);\n\n // * constructing html end\n \n this.setListeners();\n }\n\n onPrevClick = (target: AppMediaViewerAvatarTargetType) => {\n this.openMedia(target.photoId, target.element, -1);\n };\n\n onNextClick = (target: AppMediaViewerAvatarTargetType) => {\n this.openMedia(target.photoId, target.element, 1);\n };\n\n onDownloadClick = () => {\n appPhotosManager.savePhotoFile(appPhotosManager.getPhoto(this.target.photoId), appImManager.chat.bubbles.lazyLoadQueue.queueId);\n };\n\n public async openMedia(photoId: string, target?: HTMLElement, fromRight = 0, prevTargets?: AppMediaViewerAvatarTargetType[], nextTargets?: AppMediaViewerAvatarTargetType[]) {\n if(this.setMoverPromise) return this.setMoverPromise;\n\n const photo = appPhotosManager.getPhoto(photoId);\n const ret = super._openMedia(photo, photo.date, this.peerId, fromRight, target, false, prevTargets, nextTargets);\n this.target.photoId = photo.id;\n\n return ret;\n }\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\r\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport { Message } from \"../layer\";\r\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\r\nimport type { LazyLoadQueueIntersector } from \"./lazyLoadQueue\";\r\nimport { attachClickEvent } from \"../helpers/dom/clickEvent\";\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport appAvatarsManager from \"../lib/appManagers/appAvatarsManager\";\r\nimport AppMediaViewer from \"./appMediaViewer\";\r\nimport AppMediaViewerAvatar from \"./appMediaViewerAvatar\";\r\n\r\nconst onAvatarUpdate = (peerId: number) => {\r\n appAvatarsManager.removeFromAvatarsCache(peerId);\r\n (Array.from(document.querySelectorAll('avatar-element[peer=\"' + peerId + '\"]')) as AvatarElement[]).forEach(elem => {\r\n //console.log('updating avatar:', elem);\r\n elem.update();\r\n });\r\n};\r\n\r\nrootScope.addEventListener('avatar_update', onAvatarUpdate);\r\nrootScope.addEventListener('peer_title_edit', (peerId) => {\r\n if(!appAvatarsManager.isAvatarCached(peerId)) {\r\n onAvatarUpdate(peerId);\r\n }\r\n});\r\n\r\nexport async function openAvatarViewer(target: HTMLElement, peerId: number, middleware: () => boolean, message?: any, prevTargets?: {element: HTMLElement, item: string | Message.messageService}[], nextTargets?: typeof prevTargets) {\r\n let photo = await appProfileManager.getFullPhoto(peerId);\r\n if(!middleware() || !photo) {\r\n return;\r\n }\r\n\r\n const getTarget = () => {\r\n const good = Array.from(target.querySelectorAll('img')).find(img => !img.classList.contains('emoji'));\r\n return good ? target : null;\r\n };\r\n\r\n if(peerId < 0) {\r\n const hadMessage = !!message;\r\n const inputFilter = 'inputMessagesFilterChatPhotos';\r\n if(!message) {\r\n message = await appMessagesManager.getSearch({\r\n peerId, \r\n inputFilter: {_: inputFilter}, \r\n maxId: 0, \r\n limit: 1 \r\n }).then(value => {\r\n //console.log(lol);\r\n // ! by descend\r\n return value.history[0];\r\n });\r\n\r\n if(!middleware()) {\r\n return;\r\n }\r\n }\r\n\r\n if(message) {\r\n // ! гений в деле, костылируем (но это гениально)\r\n const messagePhoto = message.action.photo;\r\n if(messagePhoto.id !== photo.id) {\r\n if(!hadMessage) {\r\n message = appMessagesManager.generateFakeAvatarMessage(peerId, photo);\r\n } else {\r\n \r\n }\r\n }\r\n\r\n const f = (arr: typeof prevTargets) => arr.map(el => ({\r\n element: el.element,\r\n mid: (el.item as Message.messageService).mid,\r\n peerId: (el.item as Message.messageService).peerId\r\n }));\r\n\r\n new AppMediaViewer()\r\n .setSearchContext({\r\n peerId,\r\n inputFilter: {_: inputFilter},\r\n })\r\n .openMedia(message, getTarget(), undefined, undefined, prevTargets ? f(prevTargets) : undefined, nextTargets ? f(nextTargets) : undefined);\r\n\r\n return;\r\n }\r\n }\r\n\r\n if(photo) {\r\n if(typeof(message) === 'string') {\r\n photo = appPhotosManager.getPhoto(message);\r\n }\r\n \r\n const f = (arr: typeof prevTargets) => arr.map(el => ({\r\n element: el.element,\r\n photoId: el.item as string\r\n }));\r\n\r\n new AppMediaViewerAvatar(peerId).openMedia(photo.id, getTarget(), undefined, prevTargets ? f(prevTargets) : undefined, nextTargets ? f(nextTargets) : undefined);\r\n }\r\n}\r\n\r\nconst believeMe: Map<number, Set<AvatarElement>> = new Map();\r\nconst seen: Set<number> = new Set();\r\n\r\nexport default class AvatarElement extends HTMLElement {\r\n private peerId: number;\r\n private isDialog = false;\r\n private peerTitle: string;\r\n public loadPromises: Promise<any>[];\r\n public lazyLoadQueue: LazyLoadQueueIntersector;\r\n private addedToQueue = false;\r\n\r\n connectedCallback() {\r\n // браузер вызывает этот метод при добавлении элемента в документ\r\n // (может вызываться много раз, если элемент многократно добавляется/удаляется)\r\n\r\n this.isDialog = this.getAttribute('dialog') === '1';\r\n if(this.getAttribute('clickable') === '') {\r\n this.setAttribute('clickable', 'set');\r\n let loading = false;\r\n attachClickEvent(this, async(e) => {\r\n cancelEvent(e);\r\n if(loading) return;\r\n //console.log('avatar clicked');\r\n const peerId = this.peerId;\r\n loading = true;\r\n await openAvatarViewer(this, this.peerId, () => this.peerId === peerId);\r\n loading = false;\r\n });\r\n }\r\n }\r\n\r\n disconnectedCallback() {\r\n // браузер вызывает этот метод при удалении элемента из документа\r\n // (может вызываться много раз, если элемент многократно добавляется/удаляется)\r\n const set = believeMe.get(this.peerId);\r\n if(set && set.has(this)) {\r\n set.delete(this);\r\n if(!set.size) {\r\n believeMe.delete(this.peerId);\r\n }\r\n }\r\n\r\n if(this.lazyLoadQueue) {\r\n this.lazyLoadQueue.unobserve(this);\r\n }\r\n }\r\n\r\n static get observedAttributes(): string[] {\r\n return ['peer', 'dialog', 'peer-title'/* массив имён атрибутов для отслеживания их изменений */];\r\n }\r\n\r\n attributeChangedCallback(name: string, oldValue: string, newValue: string) {\r\n //console.log('avatar changed attribute:', name, oldValue, newValue);\r\n // вызывается при изменении одного из перечисленных выше атрибутов\r\n if(name === 'peer') {\r\n if(this.peerId === +newValue) {\r\n return;\r\n }\r\n \r\n this.peerId = appPeersManager.getPeerMigratedTo(+newValue) || +newValue;\r\n\r\n const wasPeerId = +oldValue;\r\n if(wasPeerId) {\r\n const set = believeMe.get(wasPeerId);\r\n if(set) {\r\n set.delete(this);\r\n if(!set.size) {\r\n believeMe.delete(wasPeerId);\r\n }\r\n }\r\n }\r\n\r\n this.update();\r\n } else if(name === 'peer-title') {\r\n this.peerTitle = newValue;\r\n } else if(name === 'dialog') {\r\n this.isDialog = newValue === '1';\r\n }\r\n }\r\n\r\n private r(onlyThumb = false) {\r\n const res = appAvatarsManager.putPhoto(this, this.peerId, this.isDialog, this.peerTitle, onlyThumb);\r\n const promise = res ? res.loadPromise : Promise.resolve();\r\n if(this.loadPromises) {\r\n if(res && res.cached) {\r\n this.loadPromises.push(promise);\r\n }\r\n\r\n promise.finally(() => {\r\n this.loadPromises = undefined;\r\n });\r\n }\r\n\r\n return res;\r\n }\r\n\r\n public update() {\r\n if(this.lazyLoadQueue) {\r\n if(!seen.has(this.peerId)) {\r\n if(this.addedToQueue) return;\r\n this.addedToQueue = true;\r\n \r\n let set = believeMe.get(this.peerId);\r\n if(!set) {\r\n set = new Set();\r\n believeMe.set(this.peerId, set);\r\n }\r\n \r\n set.add(this);\r\n\r\n this.r(true);\r\n\r\n this.lazyLoadQueue.push({\r\n div: this, \r\n load: () => {\r\n seen.add(this.peerId);\r\n return this.update();\r\n }\r\n });\r\n\r\n return;\r\n } else if(this.addedToQueue) {\r\n this.lazyLoadQueue.unobserve(this);\r\n }\r\n } \r\n \r\n seen.add(this.peerId);\r\n \r\n const res = this.r();\r\n const promise = res ? res.loadPromise : Promise.resolve();\r\n\r\n if(this.addedToQueue) {\r\n promise.finally(() => {\r\n this.addedToQueue = false;\r\n });\r\n }\r\n\r\n const set = believeMe.get(this.peerId);\r\n if(set) {\r\n set.delete(this);\r\n const arr = Array.from(set);\r\n believeMe.delete(this.peerId);\r\n \r\n\r\n for(let i = 0, length = arr.length; i < length; ++i) {\r\n arr[i].update();\r\n }\r\n }\r\n\r\n return promise;\r\n }\r\n}\r\n\r\ncustomElements.define('avatar-element', AvatarElement);\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport appDialogsManager from \"../lib/appManagers/appDialogsManager\";\nimport appMessagesManager, {Dialog} from \"../lib/appManagers/appMessagesManager\";\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\nimport rootScope from \"../lib/rootScope\";\nimport { positionMenu, openBtnMenu } from \"./misc\";\nimport ButtonMenu, { ButtonMenuItemOptions } from \"./buttonMenu\";\nimport PopupDeleteDialog from \"./popups/deleteDialog\";\nimport { i18n } from \"../lib/langPack\";\nimport findUpTag from \"../helpers/dom/findUpTag\";\nimport appNotificationsManager from \"../lib/appManagers/appNotificationsManager\";\nimport PopupPeer from \"./popups/peer\";\nimport AppChatFoldersTab from \"./sidebarLeft/tabs/chatFolders\";\nimport appSidebarLeft from \"./sidebarLeft\";\nimport { toastNew } from \"./toast\";\n\nexport default class DialogsContextMenu {\n private element: HTMLElement;\n private buttons: (ButtonMenuItemOptions & {verify: () => boolean})[];\n\n private selectedId: number;\n private filterId: number;\n private dialog: Dialog;\n\n private init() {\n this.buttons = [{\n icon: 'unread',\n text: 'MarkAsUnread',\n onClick: this.onUnreadClick,\n verify: () => {\n const isUnread = !!(this.dialog.pFlags?.unread_mark || this.dialog.unread_count);\n return !isUnread;\n }\n }, {\n icon: 'readchats',\n text: 'MarkAsRead',\n onClick: this.onUnreadClick,\n verify: () => { \n const isUnread = !!(this.dialog.pFlags?.unread_mark || this.dialog.unread_count);\n return isUnread;\n }\n }, {\n icon: 'pin',\n text: 'ChatList.Context.Pin',\n onClick: this.onPinClick,\n verify: () => {\n const isPinned = this.filterId > 1 ? appMessagesManager.filtersStorage.getFilter(this.filterId).pinned_peers.includes(this.dialog.peerId) : !!this.dialog.pFlags?.pinned;\n return !isPinned;\n }\n }, {\n icon: 'unpin',\n text: 'ChatList.Context.Unpin',\n onClick: this.onPinClick,\n verify: () => {\n const isPinned = this.filterId > 1 ? appMessagesManager.filtersStorage.getFilter(this.filterId).pinned_peers.includes(this.dialog.peerId) : !!this.dialog.pFlags?.pinned;\n return isPinned;\n }\n }, {\n icon: 'mute',\n text: 'ChatList.Context.Mute',\n onClick: this.onMuteClick,\n verify: () => {\n return this.selectedId !== rootScope.myId && !appNotificationsManager.isPeerLocalMuted(this.dialog.peerId); \n }\n }, {\n icon: 'unmute',\n text: 'ChatList.Context.Unmute',\n onClick: this.onUnmuteClick,\n verify: () => {\n return this.selectedId !== rootScope.myId && appNotificationsManager.isPeerLocalMuted(this.dialog.peerId); \n }\n }, {\n icon: 'archive',\n text: 'Archive',\n onClick: this.onArchiveClick,\n verify: () => this.filterId === 0 && this.selectedId !== rootScope.myId\n }, {\n icon: 'unarchive',\n text: 'Unarchive',\n onClick: this.onArchiveClick,\n verify: () => this.filterId === 1 && this.selectedId !== rootScope.myId\n }, {\n icon: 'delete danger',\n text: 'Delete',\n onClick: this.onDeleteClick,\n verify: () => true\n }];\n\n this.element = ButtonMenu(this.buttons);\n this.element.id = 'dialogs-contextmenu';\n this.element.classList.add('contextmenu');\n document.getElementById('page-chats').append(this.element);\n }\n\n private onArchiveClick = () => {\n let dialog = appMessagesManager.getDialogOnly(this.selectedId);\n if(dialog) {\n appMessagesManager.editPeerFolders([dialog.peerId], +!dialog.folder_id);\n }\n };\n\n private onPinClick = () => {\n appMessagesManager.toggleDialogPin(this.selectedId, this.filterId).catch(err => {\n if(err.type === 'PINNED_DIALOGS_TOO_MUCH') {\n if(this.filterId >= 1) {\n toastNew({langPackKey: 'PinFolderLimitReached'});\n } else {\n new PopupPeer('pinned-dialogs-too-much', {\n buttons: [{\n langKey: 'OK',\n isCancel: true\n }, {\n langKey: 'FiltersSetupPinAlert',\n callback: () => {\n new AppChatFoldersTab(appSidebarLeft).open();\n }\n }],\n descriptionLangKey: 'PinToTopLimitReached2',\n descriptionLangArgs: [i18n('Chats', [rootScope.config.pinned_dialogs_count_max])]\n }).show();\n }\n }\n });\n };\n\n private onUnmuteClick = () => {\n appMessagesManager.mutePeer(this.selectedId, false);\n };\n \n private onMuteClick = () => {\n appMessagesManager.mutePeer(this.selectedId, true);\n };\n\n private onUnreadClick = () => {\n const dialog = appMessagesManager.getDialogOnly(this.selectedId);\n if(!dialog) return;\n\n if(dialog.unread_count) {\n appMessagesManager.readHistory(this.selectedId, dialog.top_message);\n appMessagesManager.markDialogUnread(this.selectedId, true);\n } else {\n appMessagesManager.markDialogUnread(this.selectedId);\n }\n };\n\n private onDeleteClick = () => {\n new PopupDeleteDialog(this.selectedId/* , 'delete' */);\n };\n\n onContextMenu = (e: MouseEvent | Touch) => {\n if(this.init) {\n this.init();\n this.init = null;\n }\n\n let li: HTMLElement = null;\n \n try {\n li = findUpTag(e.target, 'LI');\n } catch(e) {}\n \n if(!li) return;\n\n if(e instanceof MouseEvent) e.preventDefault();\n if(this.element.classList.contains('active')) {\n return false;\n }\n if(e instanceof MouseEvent) e.cancelBubble = true;\n\n this.filterId = appDialogsManager.filterId;\n\n this.selectedId = +li.dataset.peerId;\n this.dialog = appMessagesManager.getDialogOnly(this.selectedId);\n\n this.buttons.forEach(button => {\n const good = button.verify();\n\n button.element.classList.toggle('hide', !good);\n });\n\n // delete button\n this.buttons[this.buttons.length - 1].element.lastChild.replaceWith(i18n(appPeersManager.getDeleteButtonText(this.selectedId)));\n\n li.classList.add('menu-open');\n positionMenu(e, this.element);\n openBtnMenu(this.element, () => {\n li.classList.remove('menu-open');\n this.selectedId = this.dialog = this.filterId = undefined;\n });\n };\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nexport enum ConnectionStatus {\r\n Connected,\r\n Connecting,\r\n Closed,\r\n TimedOut\r\n};\r\n\r\nexport type ConnectionStatusChange = {\r\n _: 'networkerStatus', \r\n status: ConnectionStatus,\r\n dcId: number,\r\n name: string,\r\n isFileNetworker: boolean,\r\n isFileDownload: boolean,\r\n isFileUpload: boolean,\r\n retryAt?: number\r\n};\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport { Message } from \"../layer\";\n/* import findUpClassName from \"../helpers/dom/findUpClassName\";\nimport rootScope from \"../lib/rootScope\";\nimport Transition from \"./transition\"; */\n\nexport enum SENDING_STATUS {\n Error = -1,\n Pending,\n Sent,\n Read\n}\n\nexport function getSendingStatus(message: Message.message | Message.messageService) {\n return message.pFlags.is_outgoing ? \n SENDING_STATUS.Pending : (\n message.pFlags.unread ? \n SENDING_STATUS.Sent : \n SENDING_STATUS.Read\n );\n}\n\nexport function setSendingStatus(\n container: HTMLElement, \n message?: Message.message | Message.messageService, \n disableAnimationIfRippleFound?: boolean\n) {\n let className: 'check' | 'checks' | 'sending';\n if(message?.pFlags.out) {\n if(message.pFlags.is_outgoing) {\n className = 'sending';\n } else if(message.pFlags.unread) {\n className = 'check';\n } else {\n className = 'checks';\n }\n }\n\n if(!className) {\n container.textContent = '';\n return;\n }\n \n const iconClassName = 'tgico-' + className;\n const lastElement = container.lastElementChild as HTMLElement;\n if(lastElement && lastElement.classList.contains(iconClassName)) {\n return;\n }\n \n const element = document.createElement('i');\n element.classList.add('sending-status-icon', /* 'transition-item', */ iconClassName);\n container.append(element);\n\n if(lastElement) {\n lastElement.remove();\n }\n\n /* if(!lastElement) {\n element.classList.add('active');\n return;\n }\n\n const select = Transition(container, undefined, 350, () => {\n lastElement.remove();\n }, false, true, false);\n\n let animate = rootScope.settings.animationsEnabled && className !== 'sending' && !lastElement.classList.contains('tgico-sending');\n if(disableAnimationIfRippleFound && animate) {\n const parent = findUpClassName(container, 'rp');\n if(parent.querySelector('.c-ripple__circle') || parent.matches(':hover')) {\n animate = false;\n }\n }\n\n select(element, animate, lastElement); */\n\n /* SetTransition(lastElement, 'is-visible', false, 350, () => {\n // lastElement.remove();\n }, 2);\n SetTransition(element, 'is-visible', true, 350, undefined, 2); */\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport App from \"../config/app\";\r\nimport DEBUG from \"../config/debug\";\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport apiUpdatesManager from \"../lib/appManagers/apiUpdatesManager\";\r\nimport { LangPackKey, i18n } from \"../lib/langPack\";\r\nimport { logger } from \"../lib/logger\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport Button from \"./button\";\r\nimport ProgressivePreloader from \"./preloader\";\r\nimport SetTransition from \"./singleTransition\";\r\nimport sessionStorage from '../lib/sessionStorage';\r\nimport { ConnectionStatus } from \"../lib/mtproto/connectionStatus\";\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport apiManager from \"../lib/mtproto/mtprotoworker\";\r\n\r\nexport default class ConnectionStatusComponent {\r\n public static CHANGE_STATE_DELAY = 1000;\r\n\r\n private statusContainer: HTMLElement;\r\n private statusEl: HTMLElement;\r\n private statusPreloader: ProgressivePreloader;\r\n\r\n private currentLangPackKey: LangPackKey;\r\n\r\n private hadConnect = false;\r\n private retryAt: number;\r\n private connecting = false;\r\n private timedOut = false;\r\n private updating = false;\r\n\r\n private log: ReturnType<typeof logger>;\r\n\r\n private setFirstConnectionTimeout: number;\r\n private setStateTimeout: number;\r\n\r\n constructor(chatsContainer: HTMLElement) {\r\n this.log = logger('CS');\r\n \r\n this.statusContainer = document.createElement('div');\r\n this.statusContainer.classList.add('connection-status');\r\n\r\n this.statusEl = Button('btn-primary bg-warning connection-status-button', {noRipple: true});\r\n this.statusPreloader = new ProgressivePreloader({cancelable: false});\r\n this.statusPreloader.constructContainer({color: 'transparent', bold: true});\r\n this.statusContainer.append(this.statusEl);\r\n\r\n chatsContainer.prepend(this.statusContainer);\r\n\r\n rootScope.addEventListener('connection_status_change', (e) => {\r\n const status = e;\r\n console.log(status);\r\n\r\n this.setConnectionStatus();\r\n });\r\n\r\n rootScope.addEventListener('state_synchronizing', (e) => {\r\n const channelId = e;\r\n if(!channelId) {\r\n this.updating = true;\r\n DEBUG && this.log('updating', this.updating);\r\n this.setState();\r\n }\r\n });\r\n\r\n rootScope.addEventListener('state_synchronized', (e) => {\r\n const channelId = e;\r\n DEBUG && this.log('state_synchronized', channelId);\r\n if(!channelId) {\r\n this.updating = false;\r\n DEBUG && this.log('updating', this.updating);\r\n this.setState();\r\n }\r\n });\r\n\r\n this.setFirstConnectionTimeout = window.setTimeout(this.setConnectionStatus, ConnectionStatusComponent.CHANGE_STATE_DELAY + 1e3);\r\n\r\n /* let bool = true;\r\n document.addEventListener('dblclick', () => {\r\n rootScope.dispatchEvent('connection_status_change', {\r\n dcId: 2,\r\n isFileDownload: false,\r\n isFileNetworker: false,\r\n isFileUpload: false,\r\n name: \"NET-2\",\r\n status: bool ? (bool = false, ConnectionStatus.Closed) : (bool = true, ConnectionStatus.Connected),\r\n _: \"networkerStatus\"\r\n });\r\n }); */\r\n }\r\n\r\n private setConnectionStatus = () => {\r\n sessionStorage.get('dc').then(baseDcId => {\r\n if(!baseDcId) {\r\n baseDcId = App.baseDcId;\r\n }\r\n \r\n if(this.setFirstConnectionTimeout) {\r\n clearTimeout(this.setFirstConnectionTimeout);\r\n this.setFirstConnectionTimeout = 0;\r\n }\r\n\r\n const status = rootScope.connectionStatus['NET-' + baseDcId];\r\n const online = status && status.status === ConnectionStatus.Connected;\r\n\r\n if(this.connecting && online) {\r\n apiUpdatesManager.forceGetDifference();\r\n }\r\n\r\n if(online && !this.hadConnect) {\r\n this.hadConnect = true;\r\n }\r\n \r\n this.timedOut = status && status.status === ConnectionStatus.TimedOut;\r\n this.connecting = !online;\r\n this.retryAt = status && status.retryAt;\r\n DEBUG && this.log('connecting', this.connecting);\r\n this.setState();\r\n });\r\n };\r\n\r\n private setStatusText = (langPackKey: LangPackKey, args?: any[]) => {\r\n if(this.currentLangPackKey === langPackKey) return;\r\n this.currentLangPackKey = langPackKey;\r\n replaceContent(this.statusEl, i18n(langPackKey, args));\r\n this.statusPreloader.attach(this.statusEl);\r\n };\r\n\r\n private getA(langPackKey: LangPackKey, callback: () => void) {\r\n const a = document.createElement('a');\r\n a.classList.add('force-reconnect');\r\n a.append(i18n(langPackKey));\r\n a.addEventListener('click', (e) => {\r\n cancelEvent(e);\r\n callback();\r\n });\r\n\r\n return a;\r\n }\r\n\r\n private setState = () => {\r\n const timeout = ConnectionStatusComponent.CHANGE_STATE_DELAY;\r\n if(this.connecting) {\r\n if(this.timedOut) {\r\n const a = this.getA('ConnectionStatus.ForceReconnect', () => apiManager.forceReconnect());\r\n this.setStatusText('ConnectionStatus.TimedOut', [a]);\r\n } else if(this.hadConnect) {\r\n if(this.retryAt !== undefined) {\r\n const timerSpan = document.createElement('span');\r\n const retryAt = this.retryAt;\r\n const setTime = () => {\r\n const now = Date.now();\r\n timerSpan.innerText = '' + Math.round((retryAt - now) / 1000);\r\n if(now > retryAt) {\r\n clearInterval(interval);\r\n }\r\n };\r\n const interval = setInterval(setTime, 1e3);\r\n setTime();\r\n \r\n const a = this.getA('ConnectionStatus.Reconnect', () => apiManager.forceReconnectTimeout());\r\n this.setStatusText('ConnectionStatus.ReconnectIn', [timerSpan, a]);\r\n } else {\r\n this.setStatusText('ConnectionStatus.Reconnecting');\r\n }\r\n } else {\r\n this.setStatusText('ConnectionStatus.Waiting');\r\n }\r\n } else if(this.updating) {\r\n this.setStatusText('Updating');\r\n }\r\n\r\n DEBUG && this.log('setState', this.connecting || this.updating);\r\n window.requestAnimationFrame(() => {\r\n if(this.setStateTimeout) clearTimeout(this.setStateTimeout);\r\n\r\n const cb = () => {\r\n SetTransition(this.statusContainer, 'is-shown', this.connecting || this.updating, 200);\r\n this.setStateTimeout = 0;\r\n DEBUG && this.log('setState: isShown:', this.connecting || this.updating);\r\n };\r\n\r\n this.setStateTimeout = window.setTimeout(cb, timeout);\r\n //cb();\r\n /* if(timeout) this.setStateTimeout = window.setTimeout(cb, timeout);\r\n else cb(); */\r\n });\r\n };\r\n}\r\n","/*\n * https://github.com/morethanwords/tweb\n * Copyright (C) 2019-2021 Eduard Kuzmenko\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\n */\n\nimport type DialogsStorage from \"../storages/dialogs\";\nimport type {MyDialogFilter as DialogFilter, MyDialogFilter} from \"../storages/filters\";\nimport type { LazyLoadQueueIntersector } from \"../../components/lazyLoadQueue\";\nimport AvatarElement from \"../../components/avatar\";\nimport DialogsContextMenu from \"../../components/dialogsContextMenu\";\nimport { horizontalMenu } from \"../../components/horizontalMenu\";\nimport { attachContextMenuListener, putPreloader } from \"../../components/misc\";\nimport { ripple } from \"../../components/ripple\";\n//import Scrollable from \"../../components/scrollable\";\nimport Scrollable, { ScrollableX, SliceSides } from \"../../components/scrollable\";\nimport { formatDateAccordingToTodayNew } from \"../../helpers/date\";\nimport { IS_SAFARI } from \"../../environment/userAgent\";\nimport { logger, LogTypes } from \"../logger\";\nimport { RichTextProcessor } from \"../richtextprocessor\";\nimport rootScope from \"../rootScope\";\nimport apiUpdatesManager from \"./apiUpdatesManager\";\nimport appPeersManager from './appPeersManager';\nimport appImManager from \"./appImManager\";\nimport appMessagesManager, { Dialog, MyMessage } from \"./appMessagesManager\";\nimport appStateManager, { State } from \"./appStateManager\";\nimport appUsersManager from \"./appUsersManager\";\nimport Button from \"../../components/button\";\nimport SetTransition from \"../../components/singleTransition\";\nimport appDraftsManager, { MyDraftMessage } from \"./appDraftsManager\";\nimport DEBUG, { MOUNT_CLASS_TO } from \"../../config/debug\";\nimport appNotificationsManager from \"./appNotificationsManager\";\nimport PeerTitle from \"../../components/peerTitle\";\nimport I18n, { FormatterArguments, i18n, LangPackKey, _i18n } from \"../langPack\";\nimport findUpTag from \"../../helpers/dom/findUpTag\";\nimport lottieLoader from \"../lottieLoader\";\nimport { wrapLocalSticker, wrapPhoto } from \"../../components/wrappers\";\nimport AppEditFolderTab from \"../../components/sidebarLeft/tabs/editFolder\";\nimport appSidebarLeft, { SettingSection } from \"../../components/sidebarLeft\";\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\nimport positionElementByIndex from \"../../helpers/dom/positionElementByIndex\";\nimport replaceContent from \"../../helpers/dom/replaceContent\";\nimport ConnectionStatusComponent from \"../../components/connectionStatus\";\nimport appChatsManager from \"./appChatsManager\";\nimport { renderImageFromUrlPromise } from \"../../helpers/dom/renderImageFromUrl\";\nimport { fastRaf, fastRafConventional, fastRafPromise } from \"../../helpers/schedulers\";\nimport SortedUserList from \"../../components/sortedUserList\";\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\nimport handleTabSwipe from \"../../helpers/dom/handleTabSwipe\";\nimport windowSize from \"../../helpers/windowSize\";\nimport isInDOM from \"../../helpers/dom/isInDOM\";\nimport appPhotosManager, { MyPhoto } from \"./appPhotosManager\";\nimport { MyDocument } from \"./appDocsManager\";\nimport { setSendingStatus } from \"../../components/sendingStatus\";\nimport SortedList, { SortedElementBase } from \"../../helpers/sortedList\";\nimport debounce from \"../../helpers/schedulers/debounce\";\nimport generateVerifiedIcon from \"../../components/generateVerifiedIcon\";\n\nexport type DialogDom = {\n avatarEl: AvatarElement,\n captionDiv: HTMLDivElement,\n titleSpan: HTMLSpanElement,\n titleSpanContainer: HTMLSpanElement,\n statusSpan: HTMLSpanElement,\n lastTimeSpan: HTMLSpanElement,\n unreadBadge: HTMLElement,\n mentionsBadge?: HTMLElement,\n lastMessageSpan: HTMLSpanElement,\n containerEl: HTMLElement,\n listEl: HTMLLIElement,\n subtitleEl: HTMLElement\n};\n\ninterface SortedDialog extends SortedElementBase {\n dom: DialogDom,\n loadPromises?: Promise<any>[]\n}\n\nclass SortedDialogList extends SortedList<SortedDialog> {\n constructor(public list: HTMLUListElement, public indexKey: ReturnType<DialogsStorage['getDialogIndexKey']>) {\n super({\n getIndex: (id) => appMessagesManager.getDialogOnly(id)[this.indexKey],\n onDelete: (element) => {\n element.dom.listEl.remove();\n appDialogsManager.onListLengthChange();\n },\n onSort: (element, idx) => {\n const willChangeLength = element.dom.listEl.parentElement !== this.list;\n positionElementByIndex(element.dom.listEl, this.list, idx);\n\n if(willChangeLength) {\n appDialogsManager.onListLengthChange();\n }\n },\n onElementCreate: (base, batch) => {\n const loadPromises: Promise<any>[] = batch ? [] : undefined;\n\n const {dom} = appDialogsManager.addListDialog({dialog: base.id, loadPromises, isBatch: batch});\n (base as SortedDialog).dom = dom;\n\n if(loadPromises?.length) {\n (base as SortedDialog).loadPromises = loadPromises;\n Promise.all(loadPromises).finally(() => {\n delete (base as SortedDialog).loadPromises;\n });\n }\n\n return base as SortedDialog;\n },\n updateElementWith: fastRafConventional\n });\n }\n\n public clear() {\n this.list.innerHTML = '';\n super.clear();\n }\n}\n\n//const testScroll = false;\n//let testTopSlice = 1;\n\nexport class AppDialogsManager {\n private chatsContainer = document.getElementById('chatlist-container') as HTMLDivElement;\n private chatsPreloader: HTMLElement;\n\n private loadDialogsPromise: Promise<any>;\n\n private scroll: Scrollable = null;\n \n private log = logger('DIALOGS', LogTypes.Log | LogTypes.Error | LogTypes.Warn | LogTypes.Debug);\n\n private contextMenu = new DialogsContextMenu();\n\n public sortedList: SortedDialogList;\n public sortedLists: {[filterId: number]: SortedDialogList} = {};\n public scrollables: {[filterId: number]: Scrollable} = {};\n public filterId: number;\n private folders: {[k in 'menu' | 'container' | 'menuScrollContainer']: HTMLElement} = {\n menu: document.getElementById('folders-tabs'),\n menuScrollContainer: null,\n container: document.getElementById('folders-container')\n };\n private filtersRendered: {\n [filterId: string]: {\n menu: HTMLElement, \n container: HTMLElement,\n unread: HTMLElement,\n title: HTMLElement\n }\n } = {};\n private showFiltersPromise: Promise<void>;\n private allUnreadCount: HTMLElement;\n\n private accumulateArchivedTimeout: number;\n\n //private topOffsetIndex = 0;\n\n private sliceTimeout: number;\n\n private lastActiveElements: Set<HTMLElement> = new Set();\n\n private offsets: {top: number, bottom: number} = {top: 0, bottom: 0};\n \n private loadContacts: () => void;\n private processContact: (peerId: number) => void;\n\n private indexKey: ReturnType<DialogsStorage['getDialogIndexKey']>;\n\n public onListLengthChange: () => Promise<void>;\n\n constructor() {\n this.chatsPreloader = putPreloader(null, true);\n\n this.allUnreadCount = this.folders.menu.querySelector('.badge');\n \n this.folders.menuScrollContainer = this.folders.menu.parentElement;\n\n const bottomPart = document.createElement('div');\n bottomPart.classList.add('connection-status-bottom');\n bottomPart.append(this.folders.container);\n\n /* if(isTouchSupported && isSafari) {\n let allowUp: boolean, allowDown: boolean, slideBeginY: number;\n const container = this.scroll.container;\n container.addEventListener('touchstart', (event) => {\n allowUp = container.scrollTop > 0;\n allowDown = (container.scrollTop < container.scrollHeight - container.clientHeight);\n // @ts-ignore\n slideBeginY = event.pageY;\n });\n \n container.addEventListener('touchmove', (event: any) => {\n var up = (event.pageY > slideBeginY);\n var down = (event.pageY < slideBeginY);\n slideBeginY = event.pageY;\n if((up && allowUp) || (down && allowDown)) {\n event.stopPropagation();\n } else if(up || down) {\n event.preventDefault();\n }\n });\n } */\n\n if(IS_TOUCH_SUPPORTED) {\n handleTabSwipe(this.folders.container, (next) => {\n const prevId = selectTab.prevId();\n selectTab(next ? prevId + 1 : prevId - 1);\n });\n }\n\n this.setFilterId(0);\n this.addFilter({\n id: this.filterId,\n title: '',\n titleEl: i18n('ChatList.Filter.AllChats'),\n orderIndex: 0\n });\n\n this.sortedList = this.sortedLists[this.filterId];\n this.scroll = this.scrollables[this.filterId];\n\n /* if(testScroll) {\n let i = 0;\n let add = () => {\n let li = document.createElement('li');\n li.dataset.id = '' + i;\n li.id = '' + i;\n li.innerHTML = `<div class=\"rp\"><avatar-element style=\"background-color: rgb(166, 149, 231); font-size: 0px;\"><img src=\"assets/img/pepe.jpg\"></avatar-element><div class=\"user-caption\"><p><span class=\"user-title\">${i}</span><span><span class=\"message-status\"></span><span class=\"message-time\">18:33</span></span></p><p><span class=\"user-last-message\"><b>-_-_-_-: </b>qweasd</span><span></span></p></div></div>`;\n i++;\n this.scroll.append(li);\n };\n for(let i = 0; i < 500; ++i) {\n add();\n }\n (window as any).addElement = add;\n } */\n\n rootScope.addEventListener('user_update', (userId) => {\n //console.log('updating user:', user, dialog);\n \n const dom = this.getDialogDom(userId);\n if(dom && !appUsersManager.isBot(userId) && userId !== rootScope.myId) {\n const user = appUsersManager.getUser(userId);\n const online = user.status?._ === 'userStatusOnline';\n dom.avatarEl.classList.toggle('is-online', online);\n }\n });\n\n /* rootScope.$on('dialog_top', (e) => {\n const dialog = e;\n\n this.setLastMessage(dialog);\n this.setDialogPosition(dialog);\n\n this.setFiltersUnreadCount();\n }); */\n\n rootScope.addEventListener('dialog_flush', ({peerId}) => {\n const dialog = appMessagesManager.getDialogOnly(peerId);\n if(dialog) {\n this.setLastMessage(dialog, undefined, undefined, undefined, undefined, undefined, true);\n this.validateDialogForFilter(dialog);\n this.setFiltersUnreadCount();\n }\n });\n\n rootScope.addEventListener('dialogs_multiupdate', (dialogs) => {\n for(const id in dialogs) {\n const dialog = dialogs[id];\n this.updateDialog(dialog);\n\n if(this.processContact) {\n this.processContact(+id);\n }\n\n this.validateDialogForFilter(dialog);\n }\n\n this.setFiltersUnreadCount();\n });\n\n rootScope.addEventListener('dialog_drop', ({peerId}) => {\n this.deleteDialog(peerId);\n this.setFiltersUnreadCount();\n\n if(this.processContact) {\n this.processContact(peerId);\n }\n });\n\n rootScope.addEventListener('dialog_unread', ({peerId}) => {\n const dialog = appMessagesManager.getDialogOnly(peerId);\n if(dialog) {\n this.setUnreadMessages(dialog);\n this.validateDialogForFilter(dialog);\n this.setFiltersUnreadCount();\n }\n });\n\n rootScope.addEventListener('dialog_notify_settings', (dialog) => {\n this.setUnreadMessages(dialog); // возможно это не нужно, но нужно менять is-muted\n });\n\n rootScope.addEventListener('dialog_draft', ({dialog, drop, peerId}) => {\n if(drop) {\n this.sortedList.delete(peerId);\n } else {\n this.updateDialog(dialog);\n }\n\n if(this.processContact) {\n this.processContact(peerId);\n }\n });\n\n rootScope.addEventListener('peer_changed', (peerId) => {\n //const perf = performance.now();\n for(const element of this.lastActiveElements) {\n if(+element.dataset.peerId !== peerId) {\n element.classList.remove('active');\n this.lastActiveElements.delete(element);\n }\n }\n\n const elements = Array.from(document.querySelectorAll(`[data-autonomous=\"0\"] li[data-peer-id=\"${peerId}\"]`)) as HTMLElement[];\n elements.forEach(element => {\n element.classList.add('active');\n this.lastActiveElements.add(element);\n });\n //this.log('peer_changed total time:', performance.now() - perf);\n });\n\n rootScope.addEventListener('filter_update', (filter) => {\n if(!this.filtersRendered[filter.id]) {\n this.addFilter(filter);\n return;\n } else if(filter.id === this.filterId) { // это нет тут смысла вызывать, так как будет dialogs_multiupdate\n //this.validateForFilter();\n const folder = appMessagesManager.dialogsStorage.getFolder(filter.id);\n this.validateListForFilter();\n for(let i = 0, length = folder.length; i < length; ++i) {\n const dialog = folder[i];\n this.updateDialog(dialog);\n }\n this.setFiltersUnreadCount();\n }\n\n const elements = this.filtersRendered[filter.id];\n elements.title.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);\n });\n\n rootScope.addEventListener('filter_delete', (filter) => {\n const elements = this.filtersRendered[filter.id];\n if(!elements) return;\n\n // set tab\n //(this.folders.menu.firstElementChild.children[Math.max(0, filter.id - 2)] as HTMLElement).click();\n (this.folders.menu.firstElementChild as HTMLElement).click();\n\n elements.container.remove();\n elements.menu.remove();\n \n delete this.sortedLists[filter.id];\n delete this.scrollables[filter.id];\n delete this.filtersRendered[filter.id];\n\n if(Object.keys(this.filtersRendered).length <= 1) {\n this.folders.menuScrollContainer.classList.add('hide');\n }\n });\n\n rootScope.addEventListener('filter_order', (order) => {\n const containerToAppend = this.folders.menu as HTMLElement;\n order.forEach((filterId) => {\n const filter = appMessagesManager.filtersStorage.getFilter(filterId);\n const renderedFilter = this.filtersRendered[filterId];\n\n const sortedList = this.sortedLists[filterId];\n sortedList.indexKey = appMessagesManager.dialogsStorage.getDialogIndexKey(filterId);\n\n positionElementByIndex(renderedFilter.menu, containerToAppend, filter.orderIndex);\n positionElementByIndex(renderedFilter.container, this.folders.container, filter.orderIndex);\n });\n\n this.indexKey = appMessagesManager.dialogsStorage.getDialogIndexKey(this.filterId);\n\n /* if(this.filterId) {\n const tabIndex = order.indexOf(this.filterId) + 1;\n selectTab.prevId = tabIndex;\n } */\n });\n\n rootScope.addEventListener('peer_typings', ({peerId, typings}) => {\n const dialog = appMessagesManager.getDialogOnly(peerId);\n if(!dialog) return;\n\n if(typings.length) {\n this.setTyping(dialog);\n } else {\n this.unsetTyping(dialog);\n }\n });\n\n rootScope.addEventListener('state_cleared', () => {\n //setTimeout(() => \n appStateManager.getState().then((state) => {\n appUsersManager.clear();\n appChatsManager.clear();\n \n const filtersStorage = appMessagesManager.filtersStorage;\n const filters = filtersStorage.filters;\n for(const filterId in filters) { // delete filters\n rootScope.dispatchEvent('updateDialogFilter', {\n _: 'updateDialogFilter',\n id: +filterId,\n });\n }\n\n appMessagesManager.clear();\n\n /* const clearPromises: Promise<any>[] = [];\n for(const name in appStateManager.storagesResults) {\n const results = appStateManager.storagesResults[name as keyof AppStateManager['storages']];\n const storage = appStateManager.storages[name as keyof AppStateManager['storages']];\n results.length = 0;\n clearPromises.push(storage.clear());\n } */\n\n this.validateListForFilter();\n\n this.onStateLoaded(state);\n })//, 5000);\n });\n\n const foldersScrollable = new ScrollableX(this.folders.menuScrollContainer);\n bottomPart.prepend(this.folders.menuScrollContainer);\n const selectTab = horizontalMenu(this.folders.menu, this.folders.container, (id, tabContent) => {\n /* if(id !== 0) {\n id += 1;\n } */\n\n id = +tabContent.dataset.filterId || 0;\n\n if(this.filterId === id) return;\n\n this.sortedLists[id].clear();\n this.setFilterId(id);\n this.onTabChange();\n }, () => {\n for(const folderId in this.sortedLists) {\n if(+folderId !== this.filterId) {\n this.sortedLists[folderId].clear();\n }\n }\n }, undefined, foldersScrollable);\n\n //selectTab(0);\n (this.folders.menu.firstElementChild as HTMLElement).click();\n appMessagesManager.construct();\n appStateManager.getState().then((state) => {\n return this.onStateLoaded(state);\n }).then(() => {\n // return;\n \n const isLoadedMain = appMessagesManager.dialogsStorage.isDialogsLoaded(0);\n const isLoadedArchive = appMessagesManager.dialogsStorage.isDialogsLoaded(1);\n const wasLoaded = isLoadedMain || isLoadedArchive;\n const a: Promise<any> = isLoadedMain ? Promise.resolve() : appMessagesManager.getConversationsAll('', 0);\n const b: Promise<any> = isLoadedArchive ? Promise.resolve() : appMessagesManager.getConversationsAll('', 1);\n a.finally(() => {\n b.then(() => {\n this.accumulateArchivedUnread();\n\n if(wasLoaded) {\n (apiUpdatesManager.updatesState.syncLoading || Promise.resolve()).then(() => {\n appMessagesManager.refreshConversations();\n });\n }\n });\n });\n });\n\n new ConnectionStatusComponent(this.chatsContainer);\n this.chatsContainer.append(bottomPart);\n\n setTimeout(() => {\n lottieLoader.loadLottieWorkers();\n }, 200);\n\n this.onListLengthChange = debounce(this._onListLengthChange, 100, false, true);\n }\n\n public get chatList() {\n return this.sortedList.list;\n }\n\n public setFilterId(filterId: number) {\n this.filterId = filterId;\n this.indexKey = appMessagesManager.dialogsStorage ? appMessagesManager.dialogsStorage.getDialogIndexKey(this.filterId) : 'index';\n rootScope.filterId = filterId;\n }\n\n private async onStateLoaded(state: State) {\n appNotificationsManager.getNotifyPeerTypeSettings();\n \n const renderFiltersPromise = appMessagesManager.filtersStorage.getDialogFilters().then((filters) => {\n for(const filter of filters) {\n this.addFilter(filter);\n }\n });\n\n if(state.filters && Object.keys(state.filters).length) {\n await renderFiltersPromise;\n if(this.showFiltersPromise) {\n await this.showFiltersPromise;\n }\n }\n\n if(appStateManager.storagesResults.dialogs.length) {\n appDraftsManager.addMissedDialogs();\n }\n\n return this.onChatsScroll();\n }\n\n /* private getOffset(side: 'top' | 'bottom'): {index: number, pos: number} {\n if(!this.scroll.loadedAll[side]) {\n const element = (side === 'top' ? this.chatList.firstElementChild : this.chatList.lastElementChild) as HTMLElement;\n if(element) {\n const peerId = +element.dataset.peerId;\n const dialog = appMessagesManager.getDialogByPeerId(peerId);\n return {index: dialog[0].index, pos: dialog[1]};\n }\n }\n\n return {index: 0, pos: -1};\n } */\n private getOffsetIndex(side: 'top' | 'bottom') {\n return {index: this.scroll.loadedAll[side] ? 0 : this.offsets[side]};\n }\n\n private isDialogMustBeInViewport(dialog: Dialog) {\n if(dialog.migratedTo !== undefined || !this.testDialogForFilter(dialog)) return false;\n //return true;\n const topOffset = this.getOffsetIndex('top');\n const bottomOffset = this.getOffsetIndex('bottom');\n \n if(!topOffset.index && !bottomOffset.index) {\n return true;\n }\n \n const index = dialog[this.indexKey];\n return (!topOffset.index || index <= topOffset.index) && (!bottomOffset.index || index >= bottomOffset.index);\n }\n\n private deleteDialog(peerId: number) {\n this.sortedList.delete(peerId);\n }\n\n private updateDialog(dialog: Dialog) {\n if(this.isDialogMustBeInViewport(dialog)) {\n if(!this.sortedList.has(dialog.peerId)) {\n this.sortedList.add(dialog.peerId);\n return;\n }\n } else {\n this.deleteDialog(dialog.peerId);\n return;\n }\n\n const dom = this.getDialogDom(dialog.peerId);\n if(dom) {\n this.setLastMessage(dialog, undefined, dom, undefined, undefined, undefined, true);\n this.sortedList.update(dialog.peerId);\n }\n }\n\n public onTabChange = () => {\n this.scroll = this.scrollables[this.filterId];\n this.scroll.loadedAll.top = true;\n this.scroll.loadedAll.bottom = false;\n this.offsets.top = this.offsets.bottom = 0;\n this.loadDialogsPromise = undefined;\n this.sortedList = this.sortedLists[this.filterId];\n this.onChatsScroll();\n };\n\n private setFilterUnreadCount(filterId: number, folder?: Dialog[]) {\n const unreadSpan = filterId === 0 ? this.allUnreadCount : this.filtersRendered[filterId]?.unread;\n if(!unreadSpan) {\n return;\n }\n\n folder = folder || appMessagesManager.dialogsStorage.getFolder(filterId);\n let mutedCount = 0;\n let notMutedCount = 0;\n folder.forEach(dialog => {\n const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);\n\n if(isMuted && filterId === 0) {\n return;\n }\n\n const value = +!!dialog.unread_count || +dialog.pFlags.unread_mark || 0; // * unread_mark can be undefined\n if(isMuted) mutedCount += value;\n else notMutedCount += value;\n });\n \n unreadSpan.classList.toggle('badge-gray', mutedCount && !notMutedCount);\n \n const sum = mutedCount + notMutedCount;\n unreadSpan.innerText = sum ? '' + sum : '';\n }\n\n private setFiltersUnreadCount() {\n for(const filterId in this.filtersRendered) {\n this.setFilterUnreadCount(+filterId);\n }\n\n this.setFilterUnreadCount(0);\n }\n\n /**\n * Удалит неподходящие чаты из списка, но не добавит их(!)\n */\n private validateListForFilter() {\n const filter = appMessagesManager.filtersStorage.getFilter(this.filterId);\n this.sortedList.getAll().forEach((element) => {\n const dialog = appMessagesManager.getDialogOnly(element.id);\n if(!this.testDialogForFilter(dialog, filter || null)) {\n this.deleteDialog(element.id);\n }\n });\n }\n\n /**\n * Удалит неподходящий чат из списка, но не добавит его(!)\n */\n private validateDialogForFilter(dialog: Dialog, filter?: MyDialogFilter) {\n if(!this.getDialogDom(dialog.peerId)) {\n return;\n }\n\n if(!this.testDialogForFilter(dialog, filter)) {\n this.deleteDialog(dialog.peerId);\n }\n }\n\n public testDialogForFilter(dialog: Dialog, filter = appMessagesManager.filtersStorage.getFilter(this.filterId)) {\n if(!dialog || \n (filter && !appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) || \n (!filter && this.filterId !== dialog.folder_id)) {\n return false;\n }\n\n return true;\n }\n\n public generateScrollable(list: HTMLUListElement, filterId: number) {\n const scrollable = new Scrollable(null, 'CL', 500);\n scrollable.container.addEventListener('scroll', this.onChatsRegularScroll);\n scrollable.container.dataset.filterId = '' + filterId;\n scrollable.onScrolledTop = this.onChatsScrollTop;\n scrollable.onScrolledBottom = this.onChatsScroll;\n scrollable.setVirtualContainer(list);\n\n const sortedDialogList = new SortedDialogList(list, appMessagesManager.dialogsStorage ? appMessagesManager.dialogsStorage.getDialogIndexKey(filterId) : 'index');\n\n this.scrollables[filterId] = scrollable;\n this.sortedLists[filterId] = sortedDialogList;\n\n // list.classList.add('hide');\n // scrollable.container.style.backgroundColor = '#' + (Math.random() * (16 ** 6 - 1) | 0).toString(16);\n\n return scrollable;\n }\n\n private addFilter(filter: Pick<DialogFilter, 'title' | 'id' | 'orderIndex'> & Partial<{titleEl: HTMLElement}>) {\n if(this.filtersRendered[filter.id]) return;\n\n const menuTab = document.createElement('div');\n menuTab.classList.add('menu-horizontal-div-item');\n const span = document.createElement('span');\n const titleSpan = document.createElement('span');\n titleSpan.classList.add('text-super');\n if(filter.titleEl) titleSpan.append(filter.titleEl);\n else titleSpan.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);\n const unreadSpan = document.createElement('div');\n unreadSpan.classList.add('badge', 'badge-20', 'badge-primary');\n const i = document.createElement('i');\n span.append(titleSpan, unreadSpan, i);\n menuTab.append(span);\n ripple(menuTab);\n\n const containerToAppend = this.folders.menu as HTMLElement;\n positionElementByIndex(menuTab, containerToAppend, filter.orderIndex);\n //containerToAppend.append(li);\n\n const ul = this.createChatList();\n const scrollable = this.generateScrollable(ul, filter.id);\n\n scrollable.container.classList.add('tabs-tab', 'chatlist-parts');\n\n /* const parts = document.createElement('div');\n parts.classList.add('chatlist-parts'); */\n \n const top = document.createElement('div');\n top.classList.add('chatlist-top');\n \n const bottom = document.createElement('div');\n bottom.classList.add('chatlist-bottom');\n\n top.append(ul);\n scrollable.container.append(top, bottom);\n /* parts.append(top, bottom);\n scrollable.container.append(parts); */\n \n const div = scrollable.container;\n //this.folders.container.append(div);\n positionElementByIndex(scrollable.container, this.folders.container, filter.orderIndex);\n\n this.setListClickListener(ul, null, true);\n\n this.filtersRendered[filter.id] = {\n menu: menuTab,\n container: div,\n unread: unreadSpan,\n title: titleSpan\n };\n\n if(!this.showFiltersPromise && Object.keys(this.filtersRendered).length > 1) {\n this.showFiltersPromise = new Promise<void>((resolve) => {\n window.setTimeout(() => {\n this.showFiltersPromise = undefined;\n if(Object.keys(this.filtersRendered).length > 1) {\n this.folders.menuScrollContainer.classList.remove('hide');\n this.setFiltersUnreadCount();\n }\n resolve();\n }, 0);\n });\n }\n }\n\n private loadDialogs(side: SliceSides) {\n /* if(testScroll) {\n return;\n } */\n \n if(this.loadDialogsPromise/* || 1 === 1 */) return this.loadDialogsPromise;\n\n const promise = new Promise<void>(async(resolve) => {\n const {chatList, filterId} = this;\n\n //return;\n \n // let loadCount = 30/*this.chatsLoadCount */;\n let loadCount = windowSize.windowH / 72 * 1.25 | 0;\n let offsetIndex = 0;\n \n const {index: currentOffsetIndex} = this.getOffsetIndex(side);\n if(currentOffsetIndex) {\n if(side === 'top') {\n const storage = appMessagesManager.dialogsStorage.getFolder(filterId, true);\n const index = storage.findIndex(dialog => dialog[this.indexKey] <= currentOffsetIndex);\n const needIndex = Math.max(0, index - loadCount);\n loadCount = index - needIndex;\n offsetIndex = storage[needIndex][this.indexKey] + 1;\n } else {\n offsetIndex = currentOffsetIndex;\n }\n }\n \n //let offset = storage[storage.length - 1]?.index || 0;\n \n try {\n //console.time('getDialogs time');\n \n const getConversationsResult = appMessagesManager.getConversations('', offsetIndex, loadCount, filterId, true);\n if(!getConversationsResult.cached && !chatList.childElementCount) {\n const container = chatList.parentElement;\n container.append(this.chatsPreloader);\n }\n \n const result = await getConversationsResult.promise;\n \n if(this.loadDialogsPromise !== promise) {\n return;\n }\n \n //console.timeEnd('getDialogs time');\n \n // * loaded all\n //if(!result.dialogs.length || chatList.childElementCount === result.count) {\n // !result.dialogs.length не подходит, так как при супердревном диалоге getConversations его не выдаст.\n //if(chatList.childElementCount === result.count) {\n if(side === 'bottom') {\n if(result.isEnd) {\n this.scroll.loadedAll[side] = true;\n }\n } else if(result.isTopEnd) {\n this.scroll.loadedAll[side] = true;\n }\n \n if(result.dialogs.length) {\n const dialogs = side === 'top' ? result.dialogs.slice().reverse() : result.dialogs;\n \n const loadPromises: Promise<any>[] = [];\n\n const callbacks: (() => void)[] = [];\n const cccc = (callback: () => void) => {\n callbacks.push(callback);\n };\n\n dialogs.forEach((dialog) => {\n const element = this.sortedList.add(dialog.peerId, true, cccc, false);\n if(element.loadPromises) {\n loadPromises.push(...element.loadPromises);\n }\n });\n\n await Promise.all(loadPromises).finally();\n\n callbacks.forEach(callback => callback());\n } else {\n this.onListLengthChange();\n }\n\n const offsetDialog = result.dialogs[side === 'top' ? 0 : result.dialogs.length - 1];\n if(offsetDialog) {\n this.offsets[side] = offsetDialog[this.indexKey];\n }\n\n this.log.debug('getDialogs ' + loadCount + ' dialogs by offset:', offsetIndex, result, chatList.childElementCount);\n \n setTimeout(() => {\n this.scroll.onScroll();\n }, 0);\n } catch(err) {\n this.log.error(err);\n }\n \n if(this.chatsPreloader.parentElement) {\n this.chatsPreloader.remove();\n }\n \n resolve();\n }).finally(() => {\n this.loadDialogsPromise = undefined;\n });\n\n return this.loadDialogsPromise = promise;\n }\n\n private generateEmptyPlaceholder(options: {\n title: LangPackKey,\n subtitle?: LangPackKey,\n subtitleArgs?: FormatterArguments,\n classNameType: string\n }) {\n const BASE_CLASS = 'empty-placeholder';\n const container = document.createElement('div');\n container.classList.add(BASE_CLASS, BASE_CLASS + '-' + options.classNameType);\n \n const header = document.createElement('div');\n header.classList.add(BASE_CLASS + '-header');\n _i18n(header, options.title);\n\n const subtitle = document.createElement('div');\n subtitle.classList.add(BASE_CLASS + '-subtitle');\n if(options.subtitle) {\n _i18n(subtitle, options.subtitle, options.subtitleArgs);\n }\n\n container.append(header, subtitle);\n\n return {container, header, subtitle};\n }\n\n private checkIfPlaceholderNeeded() {\n if(this.filterId === 1) {\n return;\n }\n\n const chatList = this.chatList;\n const part = chatList.parentElement as HTMLElement;\n let placeholderContainer = (Array.from(part.children) as HTMLElement[]).find(el => el.matches('.empty-placeholder'));\n const needPlaceholder = this.scroll.loadedAll.bottom && !chatList.childElementCount/* || true */;\n // chatList.style.display = 'none';\n\n if(needPlaceholder && placeholderContainer) {\n return;\n } else if(!needPlaceholder) {\n if(placeholderContainer) {\n part.classList.remove('with-placeholder');\n placeholderContainer.remove();\n }\n\n return;\n }\n\n let placeholder: ReturnType<AppDialogsManager['generateEmptyPlaceholder']>;\n if(!this.filterId) {\n placeholder = this.generateEmptyPlaceholder({\n title: 'ChatList.Main.EmptyPlaceholder.Title',\n classNameType: 'dialogs'\n });\n \n placeholderContainer = placeholder.container;\n \n const img = document.createElement('img');\n img.classList.add('empty-placeholder-dialogs-icon');\n \n Promise.all([\n appUsersManager.getContacts().then(users => {\n let key: LangPackKey, args: FormatterArguments;\n\n if(users.length/* && false */) {\n key = 'ChatList.Main.EmptyPlaceholder.Subtitle';\n args = [i18n('Contacts.Count', [users.length])];\n } else {\n key = 'ChatList.Main.EmptyPlaceholder.SubtitleNoContacts';\n args = [];\n }\n\n const subtitleEl = new I18n.IntlElement({\n key,\n args,\n element: placeholder.subtitle\n });\n }),\n renderImageFromUrlPromise(img, 'assets/img/EmptyChats.svg'),\n fastRafPromise()\n ]).then(() => {\n placeholderContainer.classList.add('visible');\n });\n\n placeholderContainer.prepend(img);\n } else {\n placeholder = this.generateEmptyPlaceholder({\n title: 'FilterNoChatsToDisplay',\n subtitle: 'FilterNoChatsToDisplayInfo',\n classNameType: 'folder'\n });\n\n placeholderContainer = placeholder.container;\n\n placeholderContainer.prepend(wrapLocalSticker({\n emoji: '📂',\n width: 128,\n height: 128\n }).container)\n\n const button = Button('btn-primary btn-color-primary btn-control tgico', {\n text: 'FilterHeaderEdit',\n icon: 'settings'\n });\n\n attachClickEvent(button, () => {\n new AppEditFolderTab(appSidebarLeft).open(appMessagesManager.filtersStorage.getFilter(this.filterId));\n });\n\n placeholderContainer.append(button);\n }\n\n part.append(placeholderContainer);\n part.classList.add('with-placeholder');\n }\n\n public _onListLengthChange = () => {\n this.checkIfPlaceholderNeeded();\n\n if(this.filterId > 0) return;\n\n const chatList = this.chatList;\n const count = chatList.childElementCount;\n\n const parts = chatList.parentElement.parentElement;\n const bottom = chatList.parentElement.nextElementSibling as HTMLElement;\n const hasContacts = !!bottom.childElementCount;\n if(count >= 10) {\n if(hasContacts) {\n parts.classList.remove('with-contacts');\n bottom.innerHTML = '';\n this.loadContacts = undefined;\n this.processContact = undefined;\n }\n\n return;\n } else if(hasContacts) return;\n\n parts.classList.add('with-contacts');\n\n const section = new SettingSection({\n name: 'Contacts',\n noDelimiter: true,\n fakeGradientDelimiter: true\n });\n\n section.container.classList.add('hide');\n\n appUsersManager.getContacts(undefined, undefined, 'online').then(contacts => {\n const sortedUserList = new SortedUserList({avatarSize: 42, new: true});\n this.loadContacts = () => {\n const pageCount = windowSize.windowH / 60 | 0;\n const arr = contacts.splice(0, pageCount).filter(this.verifyUserIdForContacts);\n\n arr.forEach((peerId) => {\n sortedUserList.add(peerId);\n });\n\n if(!contacts.length) {\n this.loadContacts = undefined;\n }\n };\n\n this.loadContacts();\n\n this.processContact = (peerId) => {\n if(peerId < 0) {\n return;\n }\n\n const good = this.verifyUserIdForContacts(peerId);\n const added = sortedUserList.has(peerId);\n if(!added && good) sortedUserList.add(peerId);\n else if(added && !good) sortedUserList.delete(peerId);\n };\n\n const list = sortedUserList.list;\n list.classList.add('chatlist-new');\n this.setListClickListener(list);\n section.content.append(list);\n section.container.classList.remove('hide');\n });\n\n bottom.append(section.container);\n };\n\n private verifyUserIdForContacts = (peerId: number) => {\n const dialog = appMessagesManager.getDialogOnly(peerId);\n return !dialog;\n };\n\n public onChatsRegularScroll = () => {\n // return;\n\n if(this.sliceTimeout) clearTimeout(this.sliceTimeout);\n this.sliceTimeout = window.setTimeout(() => {\n this.sliceTimeout = undefined;\n\n if(!this.chatList.childElementCount || this.processContact) {\n return;\n }\n\n /* const observer = new IntersectionObserver((entries) => {\n const \n });\n\n Array.from(this.chatList.children).forEach(el => {\n observer.observe(el);\n }); */\n\n fastRafConventional(() => {\n\n const perf = performance.now();\n\n const scrollTopWas = this.scroll.scrollTop;\n\n const firstElementChild = this.chatList.firstElementChild;\n const rectContainer = this.scroll.container.getBoundingClientRect();\n const rectTarget = firstElementChild.getBoundingClientRect();\n const children = Array.from(this.scroll.splitUp.children) as HTMLElement[];\n\n // const padding = 8;\n // const offsetTop = this.folders.container.offsetTop;\n let offsetTop = this.scroll.splitUp.offsetTop;\n if(offsetTop && scrollTopWas < offsetTop) offsetTop -= scrollTopWas;\n // const offsetTop = scrollTopWas < padding ? padding - scrollTopWas : 0;\n const firstY = rectContainer.y + offsetTop;\n const lastY = rectContainer.y/* - 8 */; // 8px - .chatlist padding-bottom\n \n const firstElement = findUpTag(document.elementFromPoint(Math.ceil(rectTarget.x), Math.ceil(firstY + 1)), firstElementChild.tagName) as HTMLElement;\n const lastElement = findUpTag(document.elementFromPoint(Math.ceil(rectTarget.x), Math.floor(lastY + rectContainer.height - 1)), firstElementChild.tagName) as HTMLElement;\n\n //alert('got element:' + rect.y);\n\n if(!firstElement || !lastElement) {\n return;\n }\n\n //alert('got element:' + !!firstElement);\n\n const firstElementRect = firstElement.getBoundingClientRect();\n const elementOverflow = firstElementRect.y - firstY;\n\n const sliced: HTMLElement[] = [];\n const firstIndex = children.indexOf(firstElement);\n const lastIndex = children.indexOf(lastElement);\n\n const saveLength = 10;\n\n const sliceFromStart = IS_SAFARI ? [] : children.slice(0, Math.max(0, firstIndex - saveLength));\n const sliceFromEnd = children.slice(lastIndex + saveLength);\n\n /* if(sliceFromStart.length !== sliceFromEnd.length) {\n console.log('not equal', sliceFromStart.length, sliceFromEnd.length);\n }\n\n if(sliceFromStart.length > sliceFromEnd.length) {\n const diff = sliceFromStart.length - sliceFromEnd.length;\n sliceFromStart.splice(0, diff);\n } else if(sliceFromEnd.length > sliceFromStart.length) {\n const diff = sliceFromEnd.length - sliceFromStart.length;\n sliceFromEnd.splice(sliceFromEnd.length - diff, diff);\n } */\n\n if(sliceFromStart.length) {\n this.scroll.loadedAll.top = false;\n }\n\n if(sliceFromEnd.length) {\n this.scroll.loadedAll.bottom = false;\n }\n\n sliced.push(...sliceFromStart);\n sliced.push(...sliceFromEnd);\n\n sliced.forEach(el => {\n const peerId = +el.dataset.peerId;\n this.deleteDialog(peerId);\n });\n\n this.setOffsets();\n\n //this.log('[slicer] elements', firstElement, lastElement, rect, sliced, sliceFromStart.length, sliceFromEnd.length);\n\n //this.log('[slicer] reset scrollTop', this.scroll.scrollTop, firstElement.offsetTop, firstElementRect.y, rect.y, elementOverflow);\n\n //alert('left length:' + children.length);\n\n this.scroll.scrollTop = firstElement.offsetTop - elementOverflow;\n\n this.log('slice time', performance.now() - perf);\n /* const firstElementRect = firstElement.getBoundingClientRect();\n const scrollTop = */\n\n //this.scroll.scrollIntoView(firstElement, false);\n });\n }, 200);\n };\n\n private setOffsets() {\n const chatList = this.chatList;\n const firstDialog = this.getDialogFromElement(chatList.firstElementChild as HTMLElement);\n const lastDialog = this.getDialogFromElement(chatList.lastElementChild as HTMLElement);\n\n this.offsets.top = firstDialog[this.indexKey];\n this.offsets.bottom = lastDialog[this.indexKey];\n }\n\n private getDialogFromElement(element: HTMLElement) {\n return appMessagesManager.getDialogOnly(+element.dataset.peerId);\n }\n\n public onChatsScrollTop = () => {\n this.onChatsScroll('top');\n };\n \n public onChatsScroll = (side: SliceSides = 'bottom') => {\n if(this.scroll.loadedAll[side]) {\n if(this.loadContacts) {\n this.loadContacts();\n }\n\n return;\n } else if(this.loadDialogsPromise) return this.loadDialogsPromise;\n\n this.log('onChatsScroll', side);\n return this.loadDialogs(side);\n };\n\n public setListClickListener(list: HTMLUListElement, onFound?: () => void, withContext = false, autonomous = false, openInner = false) {\n let lastActiveListElement: HTMLElement;\n\n const setPeerFunc = (openInner ? appImManager.setInnerPeer : appImManager.setPeer).bind(appImManager);\n\n list.dataset.autonomous = '' + +autonomous;\n list.addEventListener('mousedown', (e) => {\n if(e.button !== 0) return;\n //cancelEvent(e);\n\n this.log('dialogs click list');\n const target = e.target as HTMLElement;\n const elem = findUpTag(target, 'LI');\n\n if(!elem) {\n return;\n }\n\n if(autonomous) {\n const sameElement = lastActiveListElement === elem;\n if(lastActiveListElement && !sameElement) {\n lastActiveListElement.classList.remove('active');\n }\n\n if(elem) {\n elem.classList.add('active');\n lastActiveListElement = elem;\n this.lastActiveElements.add(elem);\n }\n }\n\n if(elem) {\n if(onFound) onFound();\n\n const peerId = +elem.dataset.peerId;\n const lastMsgId = +elem.dataset.mid || undefined;\n\n setPeerFunc(peerId, lastMsgId);\n } else {\n setPeerFunc(0);\n }\n }, {capture: true});\n\n if(DEBUG) {\n list.addEventListener('dblclick', (e) => {\n const li = findUpTag(e.target, 'LI');\n if(li) {\n const peerId = +li.dataset.peerId;\n this.log('debug dialog:', appMessagesManager.getDialogByPeerId(peerId));\n }\n });\n }\n\n if(withContext) {\n attachContextMenuListener(list, this.contextMenu.onContextMenu);\n }\n }\n\n public createChatList(options: {\n // avatarSize?: number,\n // handheldsSize?: number,\n // size?: number,\n new?: boolean\n } = {}) {\n const list = document.createElement('ul');\n list.classList.add('chatlist'/* , \n 'chatlist-avatar-' + (options.avatarSize || 54) *//* , 'chatlist-' + (options.size || 72) */);\n\n if(options.new) {\n list.classList.add('chatlist-new');\n }\n\n /* if(options.handheldsSize) {\n list.classList.add('chatlist-handhelds-' + options.handheldsSize);\n } */\n\n return list;\n }\n\n public setLastMessage(\n dialog: Dialog, \n lastMessage?: any, \n dom?: DialogDom, \n highlightWord?: string, \n loadPromises?: Promise<any>[],\n isBatch = false,\n setUnread = false\n ) {\n ///////console.log('setlastMessage:', lastMessage);\n if(!dom) {\n dom = this.getDialogDom(dialog.peerId);\n\n if(!dom) {\n //this.log.error('no dom for dialog:', dialog, lastMessage, dom, highlightWord);\n return;\n }\n }\n\n let draftMessage: MyDraftMessage;\n if(!lastMessage) {\n if(dialog.draft && dialog.draft._ === 'draftMessage') {\n draftMessage = dialog.draft;\n }\n \n lastMessage = appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);\n }\n\n if(lastMessage._ === 'messageEmpty'/* || (lastMessage._ === 'messageService' && !lastMessage.rReply) */) {\n dom.lastMessageSpan.innerHTML = '';\n dom.lastTimeSpan.innerHTML = '';\n delete dom.listEl.dataset.mid;\n\n if(setUnread) {\n this.setUnreadMessages(dialog, dom, isBatch);\n }\n\n return;\n }\n\n const peerId = dialog.peerId;\n //let peerId = appMessagesManager.getMessagePeer(lastMessage);\n\n //console.log('setting last message:', lastMessage);\n\n /* if(!dom.lastMessageSpan.classList.contains('user-typing')) */ {\n\n let mediaContainer: HTMLElement;\n if(!lastMessage.deleted && !draftMessage) {\n const media: MyDocument | MyPhoto = appMessagesManager.getMediaFromMessage(lastMessage);\n if(media && (media._ === 'photo' || (['video', 'gif'] as MyDocument['type'][]).includes(media.type))) {\n const size = appPhotosManager.choosePhotoSize(media, 20, 20);\n\n if(size._ !== 'photoSizeEmpty') {\n mediaContainer = document.createElement('div');\n mediaContainer.classList.add('dialog-subtitle-media');\n \n wrapPhoto({\n photo: media,\n message: lastMessage,\n container: mediaContainer,\n withoutPreloader: true,\n size,\n loadPromises\n });\n\n if((media as MyDocument).type === 'video') {\n const playIcon = document.createElement('span');\n playIcon.classList.add('tgico-play');\n\n mediaContainer.append(playIcon);\n }\n }\n }\n }\n\n const withoutMediaType = !!mediaContainer && !!lastMessage?.message;\n\n let fragment: DocumentFragment;\n if(highlightWord && lastMessage.message) {\n fragment = appMessagesManager.wrapMessageForReply(lastMessage, undefined, undefined, false, highlightWord, withoutMediaType);\n } else if(draftMessage) {\n fragment = appMessagesManager.wrapMessageForReply(draftMessage);\n } else if(!lastMessage.deleted) {\n fragment = appMessagesManager.wrapMessageForReply(lastMessage, undefined, undefined, false, undefined, withoutMediaType);\n } else { // rare case\n fragment = document.createDocumentFragment();\n }\n\n if(mediaContainer) {\n fragment.prepend(mediaContainer);\n }\n\n replaceContent(dom.lastMessageSpan, fragment);\n \n /* if(lastMessage.from_id === auth.id) { // You: */\n if(draftMessage) {\n const bold = document.createElement('b');\n bold.classList.add('danger');\n bold.append(i18n('Draft'), ': ');\n dom.lastMessageSpan.prepend(bold);\n } else if(peerId < 0 && peerId !== lastMessage.fromId && !lastMessage.action) {\n const sender = appPeersManager.getPeer(lastMessage.fromId);\n if(sender && sender.id) {\n const senderBold = document.createElement('b');\n\n if(sender.id === rootScope.myId) {\n senderBold.append(i18n('FromYou'));\n } else {\n //str = sender.first_name || sender.last_name || sender.username;\n senderBold.append(new PeerTitle({\n peerId: lastMessage.fromId,\n onlyFirstName: true,\n }).element);\n }\n\n senderBold.append(': ');\n //console.log(sender, senderBold.innerText);\n dom.lastMessageSpan.prepend(senderBold);\n } //////// else console.log('no sender', lastMessage, peerId);\n }\n }\n\n if(!lastMessage.deleted || draftMessage/* && lastMessage._ !== 'draftMessage' */) {\n const date = draftMessage ? Math.max(draftMessage.date, lastMessage.date || 0) : lastMessage.date;\n replaceContent(dom.lastTimeSpan, formatDateAccordingToTodayNew(new Date(date * 1000)));\n } else dom.lastTimeSpan.textContent = '';\n\n if(setUnread !== null) {\n if(setUnread) {\n this.setUnreadMessages(dialog, dom, isBatch);\n } else { // means search\n dom.listEl.dataset.mid = lastMessage.mid;\n }\n }\n }\n\n private setUnreadMessages(dialog: Dialog, dom = this.getDialogDom(dialog.peerId), isBatch = false) {\n if(dialog.folder_id === 1) {\n this.accumulateArchivedUnread();\n }\n\n if(!dom) {\n //this.log.error('setUnreadMessages no dom!', dialog);\n return;\n }\n\n if(!isBatch) {\n const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);\n const wasMuted = dom.listEl.classList.contains('is-muted');\n if(isMuted !== wasMuted) {\n SetTransition(dom.listEl, 'is-muted', isMuted, 200);\n }\n }\n\n let setStatusMessage: MyMessage;\n if(dialog.draft?._ !== 'draftMessage') {\n const lastMessage: MyMessage = appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);\n if(!lastMessage.deleted && lastMessage.pFlags.out && lastMessage.peerId !== rootScope.myId) {\n setStatusMessage = lastMessage;\n }\n }\n\n setSendingStatus(dom.statusSpan, setStatusMessage, true);\n\n const filter = appMessagesManager.filtersStorage.getFilter(this.filterId);\n let isPinned: boolean;\n if(filter) {\n isPinned = filter.pinned_peers.indexOf(dialog.peerId) !== -1;\n } else {\n isPinned = !!dialog.pFlags.pinned;\n }\n\n const hasUnreadBadge = isPinned || !!dialog.unread_count || dialog.pFlags.unread_mark;\n // dom.messageEl.classList.toggle('has-badge', hasBadge);\n\n const isUnreadBadgeMounted = isInDOM(dom.unreadBadge);\n if(hasUnreadBadge && !isUnreadBadgeMounted) {\n dom.subtitleEl.append(dom.unreadBadge);\n }\n\n const hasMentionsBadge = dialog.unread_mentions_count > 1;\n const isMentionBadgeMounted = dom.mentionsBadge && isInDOM(dom.mentionsBadge);\n if(hasMentionsBadge) {\n if(!dom.mentionsBadge) {\n dom.mentionsBadge = document.createElement('div');\n dom.mentionsBadge.className = 'dialog-subtitle-badge badge badge-24 mention mention-badge';\n dom.mentionsBadge.innerText = '@';\n dom.subtitleEl.insertBefore(dom.mentionsBadge, dom.lastMessageSpan.nextSibling);\n }\n }\n\n const transitionDuration = isBatch ? 0 : 200;\n\n SetTransition(dom.unreadBadge, 'is-visible', hasUnreadBadge, transitionDuration, hasUnreadBadge ? undefined : () => {\n dom.unreadBadge.remove();\n }, !isUnreadBadgeMounted ? 2 : 0);\n\n if(dom.mentionsBadge) {\n SetTransition(dom.mentionsBadge, 'is-visible', hasMentionsBadge, transitionDuration, hasMentionsBadge ? undefined : () => {\n dom.mentionsBadge.remove();\n delete dom.mentionsBadge;\n }, !isMentionBadgeMounted ? 2 : 0);\n }\n\n if(!hasUnreadBadge) {\n return;\n }\n\n if(isPinned) {\n dom.unreadBadge.classList.add('tgico-chatspinned', 'tgico');\n } else {\n dom.unreadBadge.classList.remove('tgico-chatspinned', 'tgico');\n }\n\n let isUnread = true, isMention = false;\n if(dialog.unread_mentions_count && dialog.unread_count === 1) {\n dom.unreadBadge.innerText = '@';\n isMention = true;\n // dom.unreadBadge.classList.add('tgico-mention', 'tgico');\n } else if(dialog.unread_count || dialog.pFlags.unread_mark) {\n //dom.unreadMessagesSpan.innerText = '' + (dialog.unread_count ? formatNumber(dialog.unread_count, 1) : ' ');\n dom.unreadBadge.innerText = '' + (dialog.unread_count || ' ');\n } else {\n dom.unreadBadge.innerText = '';\n isUnread = false;\n }\n\n dom.unreadBadge.classList.toggle('unread', isUnread);\n dom.unreadBadge.classList.toggle('mention', isMention);\n }\n\n private accumulateArchivedUnread() {\n if(this.accumulateArchivedTimeout) return;\n this.accumulateArchivedTimeout = window.setTimeout(() => {\n this.accumulateArchivedTimeout = 0;\n const dialogs = appMessagesManager.dialogsStorage.getFolder(1);\n const sum = dialogs.reduce((acc, dialog) => acc + dialog.unread_count, 0);\n rootScope.dispatchEvent('dialogs_archived_unread', {count: sum});\n }, 0);\n }\n\n private getDialogDom(peerId: number) {\n // return this.doms[peerId];\n const element = this.sortedList.get(peerId);\n return element?.dom;\n }\n\n private getDialog(dialog: Dialog | number): Dialog {\n if(typeof(dialog) === 'number') {\n const originalDialog = appMessagesManager.getDialogOnly(dialog);\n if(!originalDialog) {\n return {\n peerId: dialog,\n peer: appPeersManager.getOutputPeer(dialog),\n pFlags: {}\n } as any;\n }\n\n return originalDialog;\n }\n \n return dialog;\n }\n\n public addListDialog(options: Parameters<AppDialogsManager['addDialogNew']>[0] & {isBatch?: boolean}) {\n const dialog = this.getDialog(options.dialog);\n\n options.autonomous = false;\n\n const ret = this.addDialogNew(options);\n\n if(ret) {\n const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);\n if(isMuted) {\n ret.dom.listEl.classList.add('is-muted');\n }\n\n this.setLastMessage(dialog, undefined, ret.dom, undefined, options.loadPromises, options.isBatch, true);\n }\n\n return ret;\n }\n\n public addDialogNew(options: {\n dialog: Dialog | number,\n container?: Parameters<AppDialogsManager['addDialog']>[1],\n drawStatus?: boolean,\n rippleEnabled?: boolean,\n onlyFirstName?: boolean,\n meAsSaved?: boolean,\n append?: boolean,\n avatarSize?: number,\n autonomous?: boolean,\n lazyLoadQueue?: LazyLoadQueueIntersector,\n loadPromises?: Promise<any>[]\n }) {\n return this.addDialog(options.dialog, options.container, options.drawStatus, options.rippleEnabled, options.onlyFirstName, options.meAsSaved, options.append, options.avatarSize, options.autonomous, options.lazyLoadQueue, options.loadPromises);\n }\n\n public addDialog(_dialog: Dialog | number, \n container?: HTMLElement | Scrollable | DocumentFragment | false, \n drawStatus = true, \n rippleEnabled = true, \n onlyFirstName = false, \n meAsSaved = true, \n append = true, \n avatarSize = 54, \n autonomous = !!container, \n lazyLoadQueue?: LazyLoadQueueIntersector,\n loadPromises?: Promise<any>[]) {\n const dialog = this.getDialog(_dialog);\n const peerId = dialog.peerId;\n\n const avatarEl = new AvatarElement();\n avatarEl.loadPromises = loadPromises;\n avatarEl.lazyLoadQueue = lazyLoadQueue;\n avatarEl.setAttribute('dialog', meAsSaved ? '1' : '0');\n avatarEl.setAttribute('peer', '' + peerId);\n avatarEl.classList.add('dialog-avatar', 'avatar-' + avatarSize);\n\n if(drawStatus && peerId !== rootScope.myId) {\n if(peerId > 0) {\n const user = appUsersManager.getUser(peerId);\n //console.log('found user', user);\n\n if(user.status && user.status._ === 'userStatusOnline') {\n avatarEl.classList.add('is-online');\n }\n }\n }\n\n const captionDiv = document.createElement('div');\n captionDiv.classList.add('user-caption');\n\n const titleSpanContainer = document.createElement('span');\n titleSpanContainer.classList.add('user-title');\n\n const peerTitle = new PeerTitle({\n peerId,\n dialog: meAsSaved,\n onlyFirstName,\n plainText: false\n });\n\n titleSpanContainer.append(peerTitle.element);\n //p.classList.add('')\n\n // в других случаях иконка верификации не нужна (а первый - это главные чатлисты)\n //if(!container) {\n \n // for muted icon\n titleSpanContainer.classList.add('tgico'); // * эта строка будет актуальна только для !container, но ладно\n \n const peer = appPeersManager.getPeer(peerId);\n if(peer?.pFlags?.verified) {\n titleSpanContainer.append(generateVerifiedIcon());\n }\n //}\n \n const span = document.createElement('span');\n span.classList.add('user-last-message');\n span.setAttribute('dir', 'auto');\n\n //captionDiv.append(titleSpan);\n //captionDiv.append(span);\n\n const li = document.createElement('li');\n if(rippleEnabled) {\n ripple(li);\n }\n\n li.append(avatarEl, captionDiv);\n li.dataset.peerId = '' + peerId;\n\n const statusSpan = document.createElement('span');\n statusSpan.classList.add('message-status', 'sending-status'/* , 'transition', 'reveal' */);\n\n const lastTimeSpan = document.createElement('span');\n lastTimeSpan.classList.add('message-time');\n\n const unreadBadge = document.createElement('div');\n unreadBadge.className = 'dialog-subtitle-badge badge badge-24';\n\n const titleP = document.createElement('p');\n titleP.classList.add('dialog-title');\n\n const rightSpan = document.createElement('span');\n rightSpan.classList.add('dialog-title-details');\n rightSpan.append(statusSpan, lastTimeSpan);\n titleP.append(titleSpanContainer, rightSpan);\n\n const subtitleEl = document.createElement('p');\n subtitleEl.classList.add('dialog-subtitle');\n subtitleEl.append(span);\n\n captionDiv.append(titleP, subtitleEl);\n\n const dom: DialogDom = {\n avatarEl,\n captionDiv,\n titleSpan: peerTitle.element,\n titleSpanContainer,\n statusSpan,\n lastTimeSpan,\n unreadBadge,\n lastMessageSpan: span,\n containerEl: li,\n listEl: li,\n subtitleEl\n };\n\n /* let good = false;\n for(const folderId in this.chatLists) {\n if(this.chatLists[folderId] === container) {\n good = true;\n }\n } */\n if(container) {\n const method = append ? 'append' : 'prepend';\n container[method](li);\n }\n\n if(!autonomous && appImManager.chat?.peerId === peerId) {\n li.classList.add('active');\n this.lastActiveElements.add(li);\n } \n \n return {dom, dialog};\n }\n\n public setTyping(dialog: Dialog) {\n const dom = this.getDialogDom(dialog.peerId);\n if(!dom) {\n return;\n }\n\n let typingElement = dom.lastMessageSpan.querySelector('.peer-typing-container') as HTMLElement;\n if(typingElement) {\n appImManager.getPeerTyping(dialog.peerId, typingElement);\n } else {\n typingElement = appImManager.getPeerTyping(dialog.peerId);\n replaceContent(dom.lastMessageSpan, typingElement);\n dom.lastMessageSpan.classList.add('user-typing');\n }\n }\n\n public unsetTyping(dialog: Dialog) {\n const dom = this.getDialogDom(dialog.peerId);\n if(!dom) {\n return;\n }\n\n dom.lastMessageSpan.classList.remove('user-typing');\n this.setLastMessage(dialog, null, dom, undefined, undefined, undefined, null);\n }\n}\n\nconst appDialogsManager = new AppDialogsManager();\nMOUNT_CLASS_TO.appDialogsManager = appDialogsManager;\nexport default appDialogsManager;\n","!function(e,t){\"object\"==typeof exports&&\"object\"==typeof module?module.exports=t():\"function\"==typeof define&&define.amd?define([],t):\"object\"==typeof exports?exports.Recorder=t():e.Recorder=t()}(\"undefined\"!=typeof self?self:this,(function(){return function(e){var t={};function o(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,o),n.l=!0,n.exports}return o.m=e,o.c=t,o.d=function(e,t,i){o.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},o.r=function(e){\"undefined\"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:\"Module\"}),Object.defineProperty(e,\"__esModule\",{value:!0})},o.t=function(e,t){if(1&t&&(e=o(e)),8&t)return e;if(4&t&&\"object\"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(o.r(i),Object.defineProperty(i,\"default\",{enumerable:!0,value:e}),2&t&&\"string\"!=typeof e)for(var n in e)o.d(i,n,function(t){return e[t]}.bind(null,n));return i},o.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(t,\"a\",t),t},o.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},o.p=\"\",o(o.s=0)}([function(e,t,o){\"use strict\";(function(t){var o=t.AudioContext||t.webkitAudioContext,i=function(e){if(!i.isRecordingSupported())throw new Error(\"Recording is not supported in this browser\");e||(e={}),this.state=\"inactive\",this.config=Object.assign({bufferLength:4096,encoderApplication:2049,encoderFrameSize:20,encoderPath:\"encoderWorker.min.js\",encoderSampleRate:48e3,maxFramesPerPage:40,mediaTrackConstraints:!0,monitorGain:0,numberOfChannels:1,recordingGain:1,resampleQuality:3,streamPages:!1,reuseWorker:!1,wavBitDepth:16},e),this.encodedSamplePosition=0};i.isRecordingSupported=function(){return o&&t.navigator&&t.navigator.mediaDevices&&t.navigator.mediaDevices.getUserMedia&&t.WebAssembly},i.prototype.clearStream=function(){this.stream&&(this.stream.getTracks?this.stream.getTracks().forEach((function(e){e.stop()})):this.stream.stop(),delete this.stream),this.audioContext&&this.closeAudioContext&&(this.audioContext.close(),delete this.audioContext)},i.prototype.encodeBuffers=function(e){if(\"recording\"===this.state){for(var t=[],o=0;o<e.numberOfChannels;o++)t[o]=e.getChannelData(o);this.encoder.postMessage({command:\"encode\",buffers:t})}},i.prototype.initAudioContext=function(e){return e&&e.context?(this.audioContext=e.context,this.closeAudioContext=!1):(this.audioContext=new o,this.closeAudioContext=!0),this.audioContext},i.prototype.initAudioGraph=function(){this.encodeBuffers=function(){delete this.encodeBuffers},this.scriptProcessorNode=this.audioContext.createScriptProcessor(this.config.bufferLength,this.config.numberOfChannels,this.config.numberOfChannels),this.scriptProcessorNode.connect(this.audioContext.destination),this.scriptProcessorNode.onaudioprocess=e=>{this.encodeBuffers(e.inputBuffer)},this.monitorGainNode=this.audioContext.createGain(),this.setMonitorGain(this.config.monitorGain),this.monitorGainNode.connect(this.audioContext.destination),this.recordingGainNode=this.audioContext.createGain(),this.setRecordingGain(this.config.recordingGain),this.recordingGainNode.connect(this.scriptProcessorNode)},i.prototype.initSourceNode=function(e){return e&&e.context?t.Promise.resolve(e):t.navigator.mediaDevices.getUserMedia({audio:this.config.mediaTrackConstraints}).then(e=>(this.stream=e,this.audioContext.createMediaStreamSource(e)))},i.prototype.loadWorker=function(){this.encoder||(this.encoder=new t.Worker(this.config.encoderPath))},i.prototype.initWorker=function(){var e=(this.config.streamPages?this.streamPage:this.storePage).bind(this);return this.recordedPages=[],this.totalLength=0,this.loadWorker(),new Promise((t,o)=>{var i=o=>{switch(o.data.message){case\"ready\":t();break;case\"page\":this.encodedSamplePosition=o.data.samplePosition,e(o.data.page);break;case\"done\":this.encoder.removeEventListener(\"message\",i),this.finish()}};this.encoder.addEventListener(\"message\",i),this.encoder.postMessage(Object.assign({command:\"init\",originalSampleRate:this.audioContext.sampleRate,wavSampleRate:this.audioContext.sampleRate},this.config))})},i.prototype.pause=function(e){if(\"recording\"===this.state){if(this.state=\"paused\",e&&this.config.streamPages){var t=this.encoder;return new Promise((e,o)=>{var i=o=>{\"flushed\"===o.data.message&&(t.removeEventListener(\"message\",i),this.onpause(),e())};t.addEventListener(\"message\",i),t.postMessage({command:\"flush\"})})}return this.onpause(),Promise.resolve()}},i.prototype.resume=function(){\"paused\"===this.state&&(this.state=\"recording\",this.onresume())},i.prototype.setRecordingGain=function(e){this.config.recordingGain=e,this.recordingGainNode&&this.audioContext&&this.recordingGainNode.gain.setTargetAtTime(e,this.audioContext.currentTime,.01)},i.prototype.setMonitorGain=function(e){this.config.monitorGain=e,this.monitorGainNode&&this.audioContext&&this.monitorGainNode.gain.setTargetAtTime(e,this.audioContext.currentTime,.01)},i.prototype.start=function(e){if(\"inactive\"===this.state)return this.initAudioContext(e),this.initAudioGraph(),this.encodedSamplePosition=0,this.initWorker().then(()=>this.initSourceNode(e)).then(e=>{this.sourceNode=e,this.state=\"recording\",this.onstart(),this.encoder.postMessage({command:\"getHeaderPages\"}),this.sourceNode.connect(this.monitorGainNode),this.sourceNode.connect(this.recordingGainNode)})},i.prototype.stop=function(){if(\"inactive\"!==this.state){this.state=\"inactive\",this.monitorGainNode.disconnect(),this.scriptProcessorNode.disconnect(),this.recordingGainNode.disconnect(),this.sourceNode.disconnect(),this.clearStream();var e=this.encoder;return new Promise(t=>{var o=i=>{\"done\"===i.data.message&&(e.removeEventListener(\"message\",o),t())};e.addEventListener(\"message\",o),e.postMessage({command:\"done\"}),this.config.reuseWorker||e.postMessage({command:\"close\"})})}return Promise.resolve()},i.prototype.destroyWorker=function(){\"inactive\"===this.state&&this.encoder&&(this.encoder.postMessage({command:\"close\"}),delete this.encoder)},i.prototype.storePage=function(e){this.recordedPages.push(e),this.totalLength+=e.length},i.prototype.streamPage=function(e){this.ondataavailable(e)},i.prototype.finish=function(){if(!this.config.streamPages){var e=new Uint8Array(this.totalLength);this.recordedPages.reduce((function(t,o){return e.set(o,t),t+o.length}),0),this.ondataavailable(e)}this.onstop(),this.config.reuseWorker||delete this.encoder},i.prototype.ondataavailable=function(){},i.prototype.onpause=function(){},i.prototype.onresume=function(){},i.prototype.onstart=function(){},i.prototype.onstop=function(){},e.exports=i}).call(this,o(1))},function(e,t){var o;o=function(){return this}();try{o=o||new Function(\"return this\")()}catch(e){\"object\"==typeof window&&(o=window)}e.exports=o}])}));","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\r\nimport sequentialDom from \"../helpers/sequentialDom\";\r\nimport {IS_TOUCH_SUPPORTED} from \"../environment/touchSupport\";\r\nimport rootScope from \"../lib/rootScope\";\r\n\r\nlet rippleClickId = 0;\r\nexport function ripple(elem: HTMLElement, callback: (id: number) => Promise<boolean | void> = () => Promise.resolve(), onEnd: (id: number) => void = null, prepend = false) {\r\n //return;\r\n if(elem.querySelector('.c-ripple')) return;\r\n elem.classList.add('rp');\r\n \r\n let r = document.createElement('div');\r\n r.classList.add('c-ripple');\r\n\r\n const isSquare = elem.classList.contains('rp-square');\r\n if(isSquare) {\r\n r.classList.add('is-square');\r\n }\r\n\r\n elem[prepend ? 'prepend' : 'append'](r);\r\n\r\n let handler: () => void;\r\n //let animationEndPromise: Promise<number>;\r\n const drawRipple = (clientX: number, clientY: number) => {\r\n const startTime = Date.now();\r\n const elem = document.createElement('div');\r\n\r\n const clickId = rippleClickId++;\r\n \r\n //console.log('ripple drawRipple');\r\n \r\n const duration = +window.getComputedStyle(r).getPropertyValue('--ripple-duration').replace('s', '') * 1000;\r\n //console.log('ripple duration', duration);\r\n\r\n handler = () => {\r\n //handler = () => animationEndPromise.then((duration) => {\r\n //console.log('ripple animation was:', duration);\r\n\r\n //const duration = isSquare || mediaSizes.isMobile ? 200 : 700;\r\n //return;\r\n let elapsedTime = Date.now() - startTime;\r\n const cb = () => {\r\n //console.log('ripple elapsedTime total pre-remove:', Date.now() - startTime);\r\n sequentialDom.mutate(() => {\r\n elem.remove();\r\n });\r\n \r\n if(onEnd) onEnd(clickId);\r\n };\r\n if(elapsedTime < duration) {\r\n let delay = Math.max(duration - elapsedTime, duration / 2);\r\n setTimeout(() => elem.classList.add('hiding'), Math.max(delay - duration / 2, 0));\r\n\r\n setTimeout(cb, delay);\r\n } else {\r\n elem.classList.add('hiding');\r\n setTimeout(cb, duration / 2);\r\n }\r\n\r\n if(!IS_TOUCH_SUPPORTED) {\r\n window.removeEventListener('contextmenu', handler);\r\n }\r\n\r\n handler = null;\r\n touchStartFired = false;\r\n };\r\n //});\r\n\r\n callback && callback(clickId);\r\n\r\n /* callback().then((bad) => {\r\n if(bad) {\r\n span.remove();\r\n return;\r\n } */\r\n \r\n //console.log('ripple after promise', Date.now() - startTime);\r\n //console.log('ripple tooSlow:', tooSlow);\r\n /* if(tooSlow) {\r\n span.remove();\r\n return;\r\n } */\r\n\r\n window.requestAnimationFrame(() => {\r\n const rect = r.getBoundingClientRect();\r\n elem.classList.add('c-ripple__circle');\r\n\r\n const clickX = clientX - rect.left;\r\n const clickY = clientY - rect.top;\r\n\r\n const radius = Math.sqrt((Math.abs(clickY - rect.height / 2) + rect.height / 2) ** 2 + (Math.abs(clickX - rect.width / 2) + rect.width / 2) ** 2);\r\n const size = radius;\r\n\r\n // center of circle\r\n const x = clickX - size / 2;\r\n const y = clickY - size / 2;\r\n\r\n //console.log('ripple click', offsetFromCenter, size, clickX, clickY);\r\n\r\n elem.style.width = elem.style.height = size + 'px';\r\n elem.style.left = x + 'px';\r\n elem.style.top = y + 'px';\r\n\r\n // нижний код выполняется с задержкой\r\n /* animationEndPromise = new Promise((resolve) => {\r\n span.addEventListener('animationend', () => {\r\n // 713 -> 700\r\n resolve(((Date.now() - startTime) / 100 | 0) * 100);\r\n }, {once: true});\r\n }); */\r\n \r\n // нижний код не всегда включает анимацию ПРИ КЛИКЕ НА ТАЧПАД БЕЗ ТАПТИК ЭНЖИНА\r\n /* span.style.display = 'none';\r\n r.append(span);\r\n duration = +window.getComputedStyle(span).getPropertyValue('animation-duration').replace('s', '') * 1000;\r\n span.style.display = ''; */\r\n\r\n r.append(elem);\r\n\r\n //r.classList.add('active');\r\n //handler();\r\n });\r\n //});\r\n };\r\n\r\n const isRippleUnneeded = (e: Event) => e.target !== elem && (\r\n ['BUTTON', 'A'].includes((e.target as HTMLElement).tagName) \r\n || findUpClassName(e.target as HTMLElement, 'c-ripple') !== r\r\n );\r\n\r\n // TODO: rename this variable\r\n let touchStartFired = false;\r\n if(IS_TOUCH_SUPPORTED) {\r\n let touchEnd = () => {\r\n handler && handler();\r\n };\r\n \r\n elem.addEventListener('touchstart', (e) => {\r\n if(!rootScope.settings.animationsEnabled) {\r\n return;\r\n }\r\n\r\n //console.log('ripple touchstart', e);\r\n if(e.touches.length > 1 || touchStartFired || isRippleUnneeded(e)) {\r\n return;\r\n }\r\n \r\n //console.log('touchstart', e);\r\n touchStartFired = true;\r\n \r\n let {clientX, clientY} = e.touches[0];\r\n drawRipple(clientX, clientY);\r\n elem.addEventListener('touchend', touchEnd, {once: true});\r\n \r\n window.addEventListener('touchmove', (e) => {\r\n e.cancelBubble = true;\r\n e.stopPropagation();\r\n touchEnd();\r\n elem.removeEventListener('touchend', touchEnd);\r\n }, {once: true});\r\n }, {passive: true});\r\n } else {\r\n elem.addEventListener('mousedown', (e) => {\r\n if(![0, 2].includes(e.button)) { // only left and right buttons\r\n return;\r\n }\r\n\r\n if(!rootScope.settings.animationsEnabled) {\r\n return;\r\n }\r\n //console.log('ripple mousedown', e, e.target, findUpClassName(e.target as HTMLElement, 'c-ripple') === r);\r\n\r\n if(elem.dataset.ripple === '0' || isRippleUnneeded(e)) {\r\n return;\r\n } else if(touchStartFired) {\r\n touchStartFired = false;\r\n return;\r\n }\r\n \r\n let {clientX, clientY} = e;\r\n drawRipple(clientX, clientY);\r\n window.addEventListener('mouseup', handler, {once: true, passive: true});\r\n window.addEventListener('contextmenu', handler, {once: true, passive: true});\r\n }, {passive: true});\r\n }\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport type ListenerSetter from \"../listenerSetter\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../../environment/touchSupport\";\r\nimport simulateEvent from \"./dispatchEvent\";\r\n\r\nexport const CLICK_EVENT_NAME: 'mousedown' /* | 'touchend' */ | 'click' = (IS_TOUCH_SUPPORTED ? 'mousedown' : 'click') as any;\r\nexport type AttachClickOptions = AddEventListenerOptions & Partial<{listenerSetter: ListenerSetter, touchMouseDown: true}>;\r\nexport function attachClickEvent(elem: HTMLElement | Window, callback: (e: /* TouchEvent | */MouseEvent) => void, options: AttachClickOptions = {}) {\r\n const add = options.listenerSetter ? options.listenerSetter.add(elem) : elem.addEventListener.bind(elem);\r\n // const remove = options.listenerSetter ? options.listenerSetter.removeManual.bind(options.listenerSetter, elem) : elem.removeEventListener.bind(elem);\r\n\r\n options.touchMouseDown = true;\r\n /* if(options.touchMouseDown && CLICK_EVENT_NAME === 'touchend') {\r\n add('mousedown', callback, options);\r\n } else if(CLICK_EVENT_NAME === 'touchend') {\r\n const o = {...options, once: true};\r\n\r\n const onTouchStart = (e: TouchEvent) => {\r\n const onTouchMove = (e: TouchEvent) => {\r\n remove('touchmove', onTouchMove, o);\r\n remove('touchend', onTouchEnd, o);\r\n };\r\n \r\n const onTouchEnd = (e: TouchEvent) => {\r\n remove('touchmove', onTouchMove, o);\r\n callback(e);\r\n if(options.once) {\r\n remove('touchstart', onTouchStart);\r\n }\r\n };\r\n \r\n add('touchend', onTouchEnd, o);\r\n add('touchmove', onTouchMove, o);\r\n };\r\n\r\n add('touchstart', onTouchStart);\r\n } else {\r\n add(CLICK_EVENT_NAME, callback, options);\r\n } */\r\n add(CLICK_EVENT_NAME, callback, options);\r\n}\r\n\r\nexport function detachClickEvent(elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options?: AddEventListenerOptions) {\r\n // if(CLICK_EVENT_NAME === 'touchend') {\r\n // elem.removeEventListener('touchstart', callback, options);\r\n // } else {\r\n elem.removeEventListener(CLICK_EVENT_NAME, callback, options);\r\n // }\r\n}\r\n\r\nexport function simulateClickEvent(elem: HTMLElement) {\r\n simulateEvent(elem, CLICK_EVENT_NAME);\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { i18n, LangPackKey } from \"../lib/langPack\";\r\nimport { ripple } from \"./ripple\";\r\n\r\nconst Button = (className: string, options: Partial<{\r\n noRipple: true, \r\n onlyMobile: true, \r\n icon: string, \r\n rippleSquare: true, \r\n text: LangPackKey, \r\n disabled: boolean,\r\n asDiv: boolean\r\n}> = {}) => {\r\n const button: HTMLButtonElement = document.createElement(options.asDiv ? 'div' : 'button') as any;\r\n button.className = className + (options.icon ? ' tgico-' + options.icon : '');\r\n\r\n if(!options.noRipple) {\r\n if(options.rippleSquare) {\r\n button.classList.add('rp-square');\r\n }\r\n\r\n ripple(button);\r\n }\r\n\r\n if(options.onlyMobile) {\r\n button.classList.add('only-handhelds');\r\n }\r\n\r\n if(options.disabled) {\r\n button.setAttribute('disabled', 'true');\r\n }\r\n\r\n if(options.text) {\r\n button.append(i18n(options.text));\r\n }\r\n\r\n return button;\r\n};\r\n\r\nexport default Button;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { MOUNT_CLASS_TO } from \"../config/debug\";\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport { CLICK_EVENT_NAME } from \"../helpers/dom/clickEvent\";\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\nimport mediaSizes from \"../helpers/mediaSizes\";\r\nimport { IS_TOUCH_SUPPORTED } from \"../environment/touchSupport\";\r\nimport { IS_APPLE, IS_MOBILE_SAFARI } from \"../environment/userAgent\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport appNavigationController from \"./appNavigationController\";\r\n\r\nexport function putPreloader(elem: Element, returnDiv = false): HTMLElement {\r\n const html = `\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"preloader-circular\" viewBox=\"25 25 50 50\">\r\n <circle class=\"preloader-path\" cx=\"50\" cy=\"50\" r=\"20\" fill=\"none\" stroke-miterlimit=\"10\"/>\r\n </svg>`;\r\n\r\n if(returnDiv) {\r\n const div = document.createElement('div');\r\n div.classList.add('preloader');\r\n div.innerHTML = html;\r\n\r\n if(elem) {\r\n elem.appendChild(div);\r\n }\r\n\r\n return div;\r\n }\r\n \r\n elem.insertAdjacentHTML('beforeend', html);\r\n return elem.lastElementChild as HTMLElement;\r\n}\r\n\r\nMOUNT_CLASS_TO.putPreloader = putPreloader;\r\n\r\nexport function setButtonLoader(elem: HTMLButtonElement, icon = 'check') {\r\n elem.classList.remove('tgico-' + icon);\r\n elem.disabled = true;\r\n putPreloader(elem);\r\n\r\n return () => {\r\n elem.innerHTML = '';\r\n elem.classList.add('tgico-' + icon);\r\n elem.removeAttribute('disabled');\r\n };\r\n}\r\n\r\n/* export function parseMenuButtonsTo(to: {[name: string]: HTMLElement}, elements: HTMLCollection | NodeListOf<HTMLElement>) {\r\n Array.from(elements).forEach(el => {\r\n const match = el.className.match(/(?:^|\\s)menu-(.+?)(?:$|\\s)/);\r\n if(!match) return;\r\n to[match[1]] = el as HTMLElement;\r\n });\r\n} */\r\n\r\nlet onMouseMove = (e: MouseEvent) => {\r\n let rect = openedMenu.getBoundingClientRect();\r\n let {clientX, clientY} = e;\r\n \r\n let diffX = clientX >= rect.right ? clientX - rect.right : rect.left - clientX;\r\n let diffY = clientY >= rect.bottom ? clientY - rect.bottom : rect.top - clientY;\r\n \r\n if(diffX >= 100 || diffY >= 100) {\r\n closeBtnMenu();\r\n //openedMenu.parentElement.click();\r\n }\r\n //console.log('mousemove', diffX, diffY);\r\n};\r\n\r\nconst onClick = (e: MouseEvent | TouchEvent) => {\r\n //cancelEvent(e);\r\n closeBtnMenu();\r\n};\r\n\r\n// ! no need in this due to the same handler in appNavigationController\r\n/* const onKeyDown = (e: KeyboardEvent) => {\r\n if(e.key === 'Escape') {\r\n closeBtnMenu();\r\n cancelEvent(e);\r\n }\r\n}; */\r\n\r\nexport const closeBtnMenu = () => {\r\n if(openedMenu) {\r\n openedMenu.classList.remove('active');\r\n openedMenu.parentElement.classList.remove('menu-open');\r\n //openedMenu.previousElementSibling.remove(); // remove overlay\r\n if(menuOverlay) menuOverlay.remove();\r\n openedMenu = null;\r\n\r\n rootScope.dispatchEvent('context_menu_toggle', false);\r\n }\r\n \r\n if(openedMenuOnClose) {\r\n openedMenuOnClose();\r\n openedMenuOnClose = null;\r\n }\r\n\r\n if(!IS_TOUCH_SUPPORTED) {\r\n window.removeEventListener('mousemove', onMouseMove);\r\n //window.removeEventListener('keydown', onKeyDown, {capture: true});\r\n window.removeEventListener('contextmenu', onClick);\r\n }\r\n\r\n document.removeEventListener(CLICK_EVENT_NAME, onClick);\r\n\r\n if(!IS_MOBILE_SAFARI) {\r\n appNavigationController.removeByType('menu');\r\n }\r\n};\r\n\r\nwindow.addEventListener('resize', () => {\r\n if(openedMenu) {\r\n closeBtnMenu();\r\n }\r\n \r\n /* if(openedMenu && (openedMenu.style.top || openedMenu.style.left)) {\r\n const rect = openedMenu.getBoundingClientRect();\r\n const {innerWidth, innerHeight} = window;\r\n\r\n console.log(innerWidth, innerHeight, rect);\r\n } */\r\n});\r\n\r\nlet openedMenu: HTMLElement = null, openedMenuOnClose: () => void = null, menuOverlay: HTMLElement = null;\r\nexport function openBtnMenu(menuElement: HTMLElement, onClose?: () => void) {\r\n closeBtnMenu();\r\n\r\n if(!IS_MOBILE_SAFARI) {\r\n appNavigationController.pushItem({\r\n type: 'menu',\r\n onPop: (canAnimate) => {\r\n closeBtnMenu();\r\n }\r\n });\r\n }\r\n \r\n openedMenu = menuElement;\r\n openedMenu.classList.add('active');\r\n openedMenu.parentElement.classList.add('menu-open');\r\n\r\n if(!menuOverlay) {\r\n menuOverlay = document.createElement('div');\r\n menuOverlay.classList.add('btn-menu-overlay');\r\n\r\n // ! because this event must be canceled, and can't cancel on menu click (below)\r\n menuOverlay.addEventListener(CLICK_EVENT_NAME, (e) => {\r\n cancelEvent(e);\r\n onClick(e);\r\n });\r\n }\r\n\r\n openedMenu.parentElement.insertBefore(menuOverlay, openedMenu);\r\n\r\n //document.body.classList.add('disable-hover');\r\n \r\n openedMenuOnClose = onClose;\r\n\r\n if(!IS_TOUCH_SUPPORTED) {\r\n window.addEventListener('mousemove', onMouseMove);\r\n //window.addEventListener('keydown', onKeyDown, {capture: true});\r\n window.addEventListener('contextmenu', onClick, {once: true});\r\n }\r\n\r\n /* // ! because this event must be canceled, and can't cancel on menu click (below)\r\n overlay.addEventListener(CLICK_EVENT_NAME, (e) => {\r\n cancelEvent(e);\r\n onClick(e);\r\n }); */\r\n \r\n // ! safari iOS doesn't handle window click event on overlay, idk why\r\n document.addEventListener(CLICK_EVENT_NAME, onClick);\r\n\r\n rootScope.dispatchEvent('context_menu_toggle', true);\r\n}\r\n\r\nconst PADDING_TOP = 8;\r\nconst PADDING_LEFT = 8;\r\nexport function positionMenu({pageX, pageY}: MouseEvent | Touch, elem: HTMLElement, side?: 'left' | 'right' | 'center') {\r\n //let {clientX, clientY} = e;\r\n\r\n // * side mean the OPEN side\r\n\r\n let {scrollWidth: menuWidth, scrollHeight: menuHeight} = elem;\r\n //let {innerWidth: windowWidth, innerHeight: windowHeight} = window;\r\n const rect = document.body.getBoundingClientRect();\r\n const windowWidth = rect.width;\r\n const windowHeight = rect.height;\r\n\r\n side = mediaSizes.isMobile ? 'right' : 'left';\r\n let verticalSide: 'top' /* | 'bottom' */ | 'center' = 'top';\r\n\r\n const getSides = () => {\r\n return {\r\n x: {\r\n left: pageX,\r\n right: pageX - menuWidth\r\n },\r\n intermediateX: side === 'right' ? PADDING_LEFT : windowWidth - menuWidth - PADDING_LEFT,\r\n //intermediateX: clientX < windowWidth / 2 ? PADDING_LEFT : windowWidth - menuWidth - PADDING_LEFT,\r\n y: {\r\n top: pageY,\r\n bottom: pageY - menuHeight\r\n },\r\n //intermediateY: verticalSide === 'top' ? PADDING_TOP : windowHeight - menuHeight - PADDING_TOP,\r\n intermediateY: pageY < windowHeight / 2 ? PADDING_TOP : windowHeight - menuHeight - PADDING_TOP,\r\n };\r\n };\r\n\r\n const sides = getSides();\r\n\r\n const possibleSides = {\r\n x: {\r\n left: sides.x.left + menuWidth + PADDING_LEFT <= windowWidth,\r\n right: sides.x.right >= PADDING_LEFT\r\n },\r\n y: {\r\n top: sides.y.top + menuHeight + PADDING_TOP <= windowHeight,\r\n bottom: sides.y.bottom - PADDING_TOP >= PADDING_TOP\r\n }\r\n };\r\n\r\n /* if(side === undefined) {\r\n if((clientX + menuWidth + PADDING_LEFT) > windowWidth) {\r\n side = 'right';\r\n }\r\n } */\r\n\r\n {\r\n /* const x = sides.x;\r\n\r\n const s = Object.keys(x) as (keyof typeof possibleSides.x)[];\r\n if(side) {\r\n s.findAndSplice(s => s === side);\r\n s.unshift(side);\r\n }\r\n\r\n const possibleSide = s.find(s => possibleSides.x[s]); */\r\n let left: number;\r\n /* if(possibleSide) {\r\n left = x[possibleSide];\r\n side = possibleSide;\r\n } else {\r\n left = sides.intermediateX;\r\n side = undefined;\r\n } */\r\n left = possibleSides.x[side] ? sides.x[side] : (side = 'center', sides.intermediateX);\r\n \r\n elem.style.left = left + 'px';\r\n }\r\n\r\n /* if((clientY + menuHeight + PADDING_TOP) > windowHeight) {\r\n elem.style.top = clamp(clientY - menuHeight, PADDING_TOP, windowHeight - menuHeight - PADDING_TOP) + 'px';\r\n // elem.style.top = (innerHeight - scrollHeight - PADDING_TOP) + 'px';\r\n verticalSide = 'bottom';\r\n } else {\r\n elem.style.top = Math.max(PADDING_TOP, clientY) + 'px';\r\n verticalSide = 'top';\r\n } */\r\n\r\n {\r\n let top: number;\r\n\r\n top = possibleSides.y[verticalSide] ? sides.y[verticalSide] : (verticalSide = 'center', sides.intermediateY);\r\n \r\n elem.style.top = top + 'px';\r\n }\r\n \r\n elem.className = elem.className.replace(/(top|center|bottom)-(left|center|right)/g, '');\r\n elem.classList.add(\r\n //(verticalSide === 'center' ? verticalSide : (verticalSide === 'bottom' ? 'top' : 'bottom')) +\r\n (verticalSide === 'center' ? verticalSide : 'bottom') +\r\n '-' +\r\n (side === 'center' ? side : (side === 'left' ? 'right' : 'left')));\r\n}\r\n\r\nlet _cancelContextMenuOpening = false, _cancelContextMenuOpeningTimeout = 0;\r\nexport function cancelContextMenuOpening() {\r\n if(_cancelContextMenuOpeningTimeout) {\r\n clearTimeout(_cancelContextMenuOpeningTimeout);\r\n }\r\n \r\n _cancelContextMenuOpeningTimeout = window.setTimeout(() => {\r\n _cancelContextMenuOpeningTimeout = 0;\r\n _cancelContextMenuOpening = false;\r\n }, .4e3);\r\n\r\n _cancelContextMenuOpening = true;\r\n}\r\n\r\nexport function attachContextMenuListener(element: HTMLElement, callback: (e: Touch | MouseEvent) => void, listenerSetter?: ListenerSetter) {\r\n const add = listenerSetter ? listenerSetter.add(element) : element.addEventListener.bind(element);\r\n const remove = listenerSetter ? listenerSetter.removeManual.bind(listenerSetter, element) : element.removeEventListener.bind(element);\r\n\r\n if(IS_APPLE && IS_TOUCH_SUPPORTED) {\r\n let timeout: number;\r\n\r\n const options: EventListenerOptions = {capture: true};\r\n\r\n const onCancel = () => {\r\n clearTimeout(timeout);\r\n // @ts-ignore\r\n remove('touchmove', onCancel, options);\r\n // @ts-ignore\r\n remove('touchend', onCancel, options);\r\n // @ts-ignore\r\n remove('touchcancel', onCancel, options);\r\n };\r\n\r\n add('touchstart', (e: TouchEvent) => {\r\n if(e.touches.length > 1) {\r\n onCancel();\r\n return;\r\n }\r\n \r\n add('touchmove', onCancel, options);\r\n add('touchend', onCancel, options);\r\n add('touchcancel', onCancel, options);\r\n\r\n timeout = window.setTimeout(() => {\r\n if(_cancelContextMenuOpening) {\r\n onCancel();\r\n return;\r\n }\r\n\r\n callback(e.touches[0]);\r\n onCancel();\r\n\r\n if(openedMenu) {\r\n element.addEventListener('touchend', cancelEvent, {once: true}); // * fix instant closing\r\n }\r\n }, .4e3);\r\n });\r\n\r\n /* if(!isSafari) {\r\n add('contextmenu', (e: any) => {\r\n cancelEvent(e);\r\n }, {passive: false, capture: true});\r\n } */\r\n } else {\r\n add('contextmenu', IS_TOUCH_SUPPORTED ? (e: any) => {\r\n callback(e);\r\n\r\n if(openedMenu) {\r\n element.addEventListener('touchend', cancelEvent, {once: true}); // * fix instant closing\r\n }\r\n } : callback);\r\n }\r\n};\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { MOUNT_CLASS_TO } from \"../config/debug\";\r\nimport { IS_MOBILE_SAFARI } from \"../environment/userAgent\";\r\nimport { logger } from \"../lib/logger\";\r\nimport { doubleRaf } from \"../helpers/schedulers\";\r\nimport blurActiveElement from \"../helpers/dom/blurActiveElement\";\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\n\r\nexport type NavigationItem = {\r\n type: 'left' | 'right' | 'im' | 'chat' | 'popup' | 'media' | 'menu' | \r\n 'esg' | 'multiselect' | 'input-helper' | 'autocomplete-helper' | 'markup' | 'global-search' | 'voice',\r\n onPop: (canAnimate: boolean) => boolean | void,\r\n onEscape?: () => boolean,\r\n noHistory?: boolean,\r\n noBlurOnPop?: boolean,\r\n};\r\n\r\nexport class AppNavigationController {\r\n private navigations: Array<NavigationItem> = [];\r\n private id = Date.now();\r\n private manual = false;\r\n private log = logger('NC');\r\n private debug = true;\r\n private currentHash = window.location.hash;\r\n public onHashChange: () => void;\r\n\r\n constructor() {\r\n let isPossibleSwipe = false;\r\n window.addEventListener('popstate', (e) => {\r\n this.debug && this.log('popstate', e, isPossibleSwipe);\r\n\r\n if(window.location.hash !== this.currentHash) {\r\n this.onHashChange && this.onHashChange();\r\n this.replaceState();\r\n return;\r\n }\r\n this.currentHash = window.location.hash;\r\n\r\n const id: number = e.state;\r\n if(id !== this.id/* && !this.navigations.length */) {\r\n this.pushState();\r\n return;\r\n }\r\n\r\n const item = this.navigations.pop();\r\n if(!item) {\r\n this.pushState();\r\n return;\r\n }\r\n\r\n this.manual = !isPossibleSwipe;\r\n this.handleItem(item);\r\n //this.pushState(); // * prevent adding forward arrow\r\n });\r\n\r\n window.addEventListener('keydown', (e) => {\r\n const item = this.navigations[this.navigations.length - 1];\r\n if(!item) return;\r\n if(e.key === 'Escape' && (item.onEscape ? item.onEscape() : true)) {\r\n cancelEvent(e);\r\n this.back(item.type);\r\n }\r\n }, {capture: true, passive: false});\r\n\r\n if(IS_MOBILE_SAFARI) {\r\n const options = {passive: true};\r\n window.addEventListener('touchstart', (e) => {\r\n if(e.touches.length > 1) return;\r\n this.debug && this.log('touchstart');\r\n\r\n const detach = () => {\r\n window.removeEventListener('touchend', onTouchEnd);\r\n window.removeEventListener('touchmove', onTouchMove);\r\n };\r\n\r\n let moved = false;\r\n const onTouchMove = (e: TouchEvent) => {\r\n this.debug && this.log('touchmove');\r\n if(e.touches.length > 1) {\r\n detach();\r\n return;\r\n }\r\n\r\n moved = true;\r\n };\r\n\r\n const onTouchEnd = (e: TouchEvent) => {\r\n this.debug && this.log('touchend');\r\n if(e.touches.length > 1 || !moved) {\r\n detach();\r\n return;\r\n }\r\n\r\n isPossibleSwipe = true;\r\n doubleRaf().then(() => {\r\n isPossibleSwipe = false;\r\n });\r\n\r\n detach();\r\n };\r\n\r\n window.addEventListener('touchend', onTouchEnd, options);\r\n window.addEventListener('touchmove', onTouchMove, options);\r\n }, options);\r\n }\r\n\r\n history.scrollRestoration = 'manual';\r\n\r\n this.pushState(); // * push init state\r\n }\r\n\r\n private handleItem(item: NavigationItem) {\r\n const good = item.onPop(!this.manual ? false : undefined);\r\n this.debug && this.log('popstate, navigation:', item, this.navigations);\r\n if(good === false) {\r\n this.pushItem(item);\r\n } else if(!item.noBlurOnPop) {\r\n blurActiveElement(); // no better place for it\r\n }\r\n\r\n this.manual = false;\r\n }\r\n\r\n public findItemByType(type: NavigationItem['type']) {\r\n for(let i = this.navigations.length - 1; i >= 0; --i) {\r\n const item = this.navigations[i];\r\n if(item.type === type) {\r\n return {item, index: i};\r\n }\r\n }\r\n }\r\n\r\n public back(type?: NavigationItem['type']) {\r\n if(type) {\r\n const ret = this.findItemByType(type);\r\n if(ret) {\r\n this.manual = true;\r\n // ! commented because 'popstate' event will be fired with delay\r\n //if(ret.index !== (this.navigations.length - 1)) {\r\n this.navigations.splice(ret.index, 1);\r\n this.handleItem(ret.item);\r\n return;\r\n //}\r\n }\r\n }\r\n\r\n history.back();\r\n }\r\n\r\n public pushItem(item: NavigationItem) {\r\n this.navigations.push(item);\r\n this.debug && this.log('pushstate', item, this.navigations);\r\n\r\n if(!item.noHistory) {\r\n this.pushState();\r\n }\r\n }\r\n\r\n private pushState() {\r\n this.manual = false;\r\n history.pushState(this.id, '');\r\n }\r\n\r\n public replaceState() {\r\n history.replaceState(this.id, '', location.origin + location.pathname);\r\n }\r\n\r\n public removeItem(item: NavigationItem) {\r\n this.navigations.findAndSplice(i => i === item);\r\n }\r\n\r\n public removeByType(type: NavigationItem['type'], single = false) {\r\n for(let i = this.navigations.length - 1; i >= 0; --i) {\r\n const item = this.navigations[i];\r\n if(item.type === type) {\r\n this.navigations.splice(i, 1);\r\n\r\n if(single) {\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\nconst appNavigationController = new AppNavigationController();\r\nMOUNT_CLASS_TO.appNavigationController = appNavigationController;\r\nexport default appNavigationController;\r\n","export default function simulateEvent(elem: HTMLElement, name: string) {\n const event = new Event(name, {bubbles: true, cancelable: true});\n elem.dispatchEvent(event);\n}\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { fastRaf } from \"./schedulers\";\r\nimport { CancellablePromise, deferredPromise } from \"./cancellablePromise\";\r\nimport { MOUNT_CLASS_TO } from \"../config/debug\";\r\nimport isInDOM from \"./dom/isInDOM\";\r\n\r\nclass SequentialDom {\r\n private promises: Partial<{\r\n read: CancellablePromise<void>,\r\n write: CancellablePromise<void>\r\n }> = {};\r\n private raf = fastRaf.bind(null);\r\n private scheduled = false;\r\n\r\n private do(kind: keyof SequentialDom['promises'], callback?: VoidFunction) {\r\n let promise = this.promises[kind];\r\n if(!promise) {\r\n this.scheduleFlush();\r\n promise = this.promises[kind] = deferredPromise<void>();\r\n }\r\n\r\n if(callback !== undefined) {\r\n promise.then(() => callback());\r\n }\r\n \r\n return promise;\r\n }\r\n\r\n public measure(callback?: VoidFunction) {\r\n return this.do('read', callback);\r\n }\r\n\r\n public mutate(callback?: VoidFunction) {\r\n return this.do('write', callback);\r\n }\r\n\r\n /**\r\n * Will fire instantly if element is not connected\r\n * @param element \r\n * @param callback \r\n */\r\n public mutateElement(element: HTMLElement, callback?: VoidFunction) {\r\n const promise = isInDOM(element) ? this.mutate() : Promise.resolve();\r\n\r\n if(callback !== undefined) {\r\n promise.then(() => callback());\r\n }\r\n\r\n return promise;\r\n }\r\n\r\n private scheduleFlush() {\r\n if(!this.scheduled) {\r\n this.scheduled = true;\r\n\r\n this.raf(() => {\r\n this.promises.read && this.promises.read.resolve();\r\n this.promises.write && this.promises.write.resolve();\r\n\r\n this.scheduled = false;\r\n this.promises = {};\r\n });\r\n }\r\n }\r\n}\r\n\r\nconst sequentialDom = new SequentialDom();\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.sequentialDom = sequentialDom);\r\nexport default sequentialDom;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n * \r\n * Originally from:\r\n * https://github.com/zhukov/webogram\r\n * Copyright (C) 2014 Igor Zhukov <igor.beatle@gmail.com>\r\n * https://github.com/zhukov/webogram/blob/master/LICENSE\r\n */\r\n\r\nimport type { AccountPassword, AccountUpdatePasswordSettings, InputCheckPasswordSRP, PasswordKdfAlgo } from '../../layer';\r\nimport { MOUNT_CLASS_TO } from '../../config/debug';\r\nimport appUsersManager from '../appManagers/appUsersManager';\r\nimport apiManager from './mtprotoworker';\r\n\r\nexport class PasswordManager {\r\n public getState(): Promise<AccountPassword> {\r\n return apiManager.invokeApi('account.getPassword').then((result) => {\r\n return result;\r\n });\r\n }\r\n\r\n public updateSettings(settings: {\r\n hint?: string,\r\n email?: string,\r\n newPassword?: string,\r\n currentPassword?: string\r\n } = {}) {\r\n //state = Object.assign({}, state);\r\n //state.new_algo = Object.assign({}, state.new_algo);\r\n\r\n return this.getState().then(state => {\r\n let currentHashPromise: Promise<InputCheckPasswordSRP>;\r\n let newHashPromise: Promise<Uint8Array>;\r\n const params: AccountUpdatePasswordSettings = {\r\n password: null,\r\n new_settings: {\r\n _: 'account.passwordInputSettings',\r\n hint: settings.hint,\r\n email: settings.email\r\n }\r\n };\r\n \r\n if(settings.currentPassword) {\r\n currentHashPromise = apiManager.invokeCrypto('computeSRP', settings.currentPassword, state, false) as any;\r\n } else {\r\n currentHashPromise = Promise.resolve({\r\n _: 'inputCheckPasswordEmpty'\r\n });\r\n }\r\n \r\n // * https://core.telegram.org/api/srp#setting-a-new-2fa-password, but still there is a mistake, TDesktop passes 'new_algo' everytime\r\n const newAlgo = state.new_algo as PasswordKdfAlgo.passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow;\r\n const salt1 = new Uint8Array(newAlgo.salt1.length + 32);\r\n salt1.randomize();\r\n salt1.set(newAlgo.salt1, 0);\r\n newAlgo.salt1 = salt1;\r\n \r\n if(settings.newPassword) {\r\n newHashPromise = apiManager.invokeCrypto('computeSRP', settings.newPassword, state, true) as any;\r\n } else {\r\n newHashPromise = Promise.resolve(new Uint8Array());\r\n }\r\n \r\n return Promise.all([currentHashPromise, newHashPromise]).then((hashes) => {\r\n params.password = hashes[0];\r\n params.new_settings.new_algo = newAlgo;\r\n params.new_settings.new_password_hash = hashes[1];\r\n \r\n return apiManager.invokeApi('account.updatePasswordSettings', params);\r\n });\r\n });\r\n }\r\n\r\n public check(password: string, state: AccountPassword, options: any = {}) {\r\n return apiManager.invokeCrypto('computeSRP', password, state, false).then((inputCheckPassword) => {\r\n //console.log('SRP', inputCheckPassword);\r\n return apiManager.invokeApi('auth.checkPassword', {\r\n password: inputCheckPassword as InputCheckPasswordSRP.inputCheckPasswordSRP\r\n }, options).then(auth => {\r\n if(auth._ === 'auth.authorization') {\r\n appUsersManager.saveApiUser(auth.user);\r\n apiManager.setUserAuth(auth.user.id);\r\n }\r\n\r\n return auth;\r\n });\r\n });\r\n }\r\n\r\n public confirmPasswordEmail(code: string) {\r\n return apiManager.invokeApi('account.confirmPasswordEmail', {code});\r\n }\r\n\r\n public resendPasswordEmail() {\r\n return apiManager.invokeApi('account.resendPasswordEmail');\r\n }\r\n\r\n public cancelPasswordEmail() {\r\n return apiManager.invokeApi('account.cancelPasswordEmail');\r\n }\r\n\r\n /* public requestRecovery(options: any = {}) {\r\n return apiManager.invokeApi('auth.requestPasswordRecovery', {}, options);\r\n }\r\n\r\n public recover(code: any, options: any = {}) {\r\n return apiManager.invokeApi('auth.recoverPassword', {\r\n code\r\n }, options);\r\n } */\r\n}\r\n\r\nconst passwordManager = new PasswordManager();\r\nMOUNT_CLASS_TO.passwordManager = passwordManager;\r\nexport default passwordManager;\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport InputField, { InputFieldOptions } from \"./inputField\";\r\n\r\nexport default class PasswordInputField extends InputField {\r\n public passwordVisible = false;\r\n public toggleVisible: HTMLElement;\r\n public onVisibilityClickAdditional: () => void;\r\n\r\n constructor(options: InputFieldOptions = {}) {\r\n super({\r\n plainText: true,\r\n ...options\r\n });\r\n\r\n const input = this.input as HTMLInputElement;\r\n input.type = 'password';\r\n input.setAttribute('required', '');\r\n input.autocomplete = 'off';\r\n /* input.readOnly = true;\r\n\r\n input.addEventListener('focus', () => {\r\n input.removeAttribute('readonly');\r\n }, {once: true}); */\r\n\r\n // * https://stackoverflow.com/a/35949954/6758968\r\n const stealthy = document.createElement('input');\r\n stealthy.classList.add('stealthy');\r\n stealthy.tabIndex = -1;\r\n stealthy.type = 'password';\r\n input.parentElement.prepend(stealthy);\r\n input.parentElement.insertBefore(stealthy.cloneNode(), input.nextSibling);\r\n\r\n const toggleVisible = this.toggleVisible = document.createElement('span');\r\n toggleVisible.classList.add('toggle-visible', 'tgico');\r\n\r\n this.container.classList.add('input-field-password');\r\n this.container.append(toggleVisible);\r\n\r\n toggleVisible.addEventListener('click', this.onVisibilityClick);\r\n toggleVisible.addEventListener('touchend', this.onVisibilityClick);\r\n }\r\n\r\n public onVisibilityClick = (e: Event) => {\r\n cancelEvent(e);\r\n this.passwordVisible = !this.passwordVisible;\r\n\r\n this.toggleVisible.classList.toggle('eye-hidden', this.passwordVisible);\r\n (this.input as HTMLInputElement).type = this.passwordVisible ? 'text' : 'password';\r\n this.onVisibilityClickAdditional && this.onVisibilityClickAdditional();\r\n };\r\n}\r\n","/*\r\n * https://github.com/morethanwords/tweb\r\n * Copyright (C) 2019-2021 Eduard Kuzmenko\r\n * https://github.com/morethanwords/tweb/blob/master/LICENSE\r\n */\r\n\r\nimport lottieLoader, { RLottiePlayer } from \"../../lib/lottieLoader\";\r\nimport PasswordInputField from \"../passwordInputField\";\r\n\r\nexport default class PasswordMonkey {\r\n public container: HTMLElement;\r\n public animation: RLottiePlayer;\r\n public needFrame = 0;\r\n protected loadPromise: Promise<void>;\r\n\r\n constructor(protected passwordInputField: PasswordInputField, protected size: number) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('media-sticker-wrapper');\r\n }\r\n\r\n public load() {\r\n if(this.loadPromise) return this.loadPromise;\r\n return this.loadPromise = lottieLoader.loadAnimationFromURL({\r\n container: this.container,\r\n loop: false,\r\n autoplay: false,\r\n width: this.size,\r\n height: this.size,\r\n noCache: true\r\n //}, 'assets/img/TwoFactorSetupMonkeyClose.tgs').then(_animation => {\r\n }, 'assets/img/TwoFactorSetupMonkeyPeek.tgs').then(_animation => {\r\n //return;\r\n this.animation = _animation;\r\n this.animation.addEventListener('enterFrame', currentFrame => {\r\n //console.log('enterFrame', currentFrame, this.needFrame);\r\n\r\n if((this.animation.direction === 1 && currentFrame >= this.needFrame) ||\r\n (this.animation.direction === -1 && currentFrame <= this.needFrame)) {\r\n this.animation.setSpeed(1);\r\n this.animation.pause();\r\n } \r\n });\r\n\r\n this.passwordInputField.onVisibilityClickAdditional = () => {\r\n if(this.passwordInputField.passwordVisible) {\r\n this.animation.setDirection(1);\r\n this.animation.curFrame = 0;\r\n this.needFrame = 16;\r\n this.animation.play();\r\n } else {\r\n this.animation.setDirection(-1);\r\n this.animation.curFrame = 16;\r\n this.needFrame = 0;\r\n this.animation.play();\r\n }\r\n };\r\n\r\n return lottieLoader.waitForFirstFrame(_animation);\r\n });\r\n }\r\n\r\n public remove() {\r\n if(this.animation) {\r\n this.animation.remove();\r\n }\r\n }\r\n}\r\n"],"sourceRoot":""}