tweb/public/17.24cbb3aa46ec14099174.chunk.js.map
Eduard Kuzmenko 7381aaa97b Build
2021-07-18 16:42:20 +03:00

1 line
1.9 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/appSearch.ts","webpack:///./src/components/inputSearch.ts","webpack:///./src/helpers/listenerSetter.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/lib/mediaPlayer.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/components/usernameInputField.ts","webpack:///./src/components/popups/peer.ts","webpack:///./src/components/sidebarRight/tabs/chatType.ts","webpack:///./src/helpers/listLoader.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/swipeHandler.ts","webpack:///./src/components/sidebarLeft/tabs/addMembers.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/components/sortedUserList.ts","webpack:///./src/components/appSearchSuper..ts","webpack:///./src/components/buttonMenu.ts","webpack:///./src/components/buttonMenuToggle.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/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/popups/forward.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/helpers/dom/setInnerHTML.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/components/popups/deleteMessages.ts","webpack:///./src/components/popups/unpinMessage.ts","webpack:///./src/components/popups/sendNow.ts","webpack:///./src/helpers/dom/cancelSelection.ts","webpack:///./src/helpers/dom/isSelectionEmpty.ts","webpack:///./src/components/chat/contextMenu.ts","webpack:///./src/components/chat/sendContextMenu.ts","webpack:///./src/components/popups/createPoll.ts","webpack:///./src/helpers/dom/isSendShortcutPressed.ts","webpack:///./src/helpers/dom/placeCaretAtEnd.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/input.ts","webpack:///./src/helpers/dom/setRichFocus.ts","webpack:///./src/components/chat/selection.ts","webpack:///./src/helpers/dom/getSelectedText.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/components/popups/joinChatInvite.ts","webpack:///./src/lib/appManagers/appImManager.ts","webpack:///./src/components/appMediaViewer.ts","webpack:///./src/helpers/dom/getVisibleRect.ts","webpack:///./src/helpers/fillPropertyValue.ts","webpack:///./src/components/avatar.ts","webpack:///./src/components/dialogsContextMenu.ts","webpack:///./src/lib/mtproto/connectionStatus.ts","webpack:///./src/components/connectionStatus.ts","webpack:///./src/lib/appManagers/appDialogsManager.ts","webpack:///./public/recorder.min.js","webpack:///./src/lib/appManagers/appDownloadManager.ts","webpack:///./src/components/popups/index.ts","webpack:///./src/lib/mtproto/passwordManager.ts","webpack:///./src/components/passwordInputField.ts","webpack:///./src/helpers/fileName.ts","webpack:///./src/components/monkeys/password.ts","webpack:///./src/components/monkeys/tracking.ts","webpack:///./src/components/codeInputField.ts","webpack:///./src/lib/cropper.ts","webpack:///./src/components/popups/avatar.ts"],"names":["name","type","clearable","className","clickable","autonomous","onFound","this","list","createChatList","container","document","createElement","nameEl","classList","add","append","style","display","setListClickListener","undefined","innerHTML","childElementCount","setActive","clear","searchInput","searchGroups","onSearch","minMsgId","loadedCount","foundCount","searchPromise","searchTimeout","query","listsContainer","peerId","threadId","scrollable","i","messages","setVirtualContainer","onChange","value","reset","searchMore","onScrolledBottom","trim","window","setTimeout","all","input","focus","Promise","resolve","maxId","getSearch","inputFilter","_","limit","then","res","count","history","length","mid","shift","searchGroup","forEach","message","fromId","dialog","dom","addDialogNew","drawStatus","avatarSize","meAsSaved","listEl","dataset","setLastMessage","toggle","replaceContent","catch","err","console","error","placeholder","prevValue","timeout","onInput","clearTimeout","onClearClick","onClear","inputField","plainText","remove","searchIcon","clearBtn","addEventListener","removeEventListener","ListenerSetter","listeners","Set","element","event","callback","options","listener","addManual","once","onceCallback","onceFired","delete","_listener","icon","slider","destroyable","_constructor","header","closeBtn","noRipple","title","content","addTab","listenerSetter","closeTab","args","init","result","selectTab","tabs","removeAll","key","super","eventListener","dispatchEvent","cleanup","onCloseAfterTimeout","historyTabIds","canHideFirst","onCloseBtnClick","appNavigationController","findItemByType","navigationType","back","id","animate","isNavigation","closingId","pop","onCloseTab","tab","_selectTab","Map","tabsContainer","sidebarEl","querySelector","Array","from","querySelectorAll","el","get","onOpen","onOpenAfterTimeout","pushItem","onPop","canAnimate","push","findAndSplice","tabConstructor","preserveTab","removeTabFromHistory","find","t","getTab","removeByType","onClose","parentElement","canvas","open","getContext","clearRect","width","height","uploadAvatar","setTitle","avatarEdit","_upload","inputWrapper","groupNameInputField","label","maxLength","nextBtn","contains","disabled","createChat","userIds","chatId","inputFile","editPhoto","chatsContainer","userId","rippleEnabled","lastMessageSpan","getUserStatusString","textContent","appMediaPlaybackController","media","waitingMediaForLoad","onPause","e","rootScope","onEnded","nextMid","currentPeerId","resolveWaitingForLoadMedia","play","cssText","body","doc","autoload","storage","setAttribute","volume","playingMedia","paused","pause","loadSiblingsMedia","onError","deferred","supportsStreaming","downloadDoc","handleSafariStreamable","cacheContext","appDownloadManager","getCacheContext","src","url","currentTime","duration","promise","safariBuffering","prevMid","backLimit","m","filter","Boolean","getMessageByPeer","addMedia","willBePlayedMedia","attachGrabListeners","onStart","onMove","onEnd","onMouseMove","x","pageX","y","pageY","onMouseUp","onMouseDown","button","onTouchMove","preventDefault","touches","clientX","clientY","isTouch","onTouchEnd","onTouchStart","passive","step","min","max","mousedown","events","scrub","rect","getBoundingClientRect","seek","setFilled","onScrub","filled","setProgress","stepStr","index","indexOf","decimals","_removeListeners","percents","offsetX","left","toFixed","streamable","stopAndScrubTimeout","progressRAF","onLoadedData","onPlay","r","requestAnimationFrame","cancelAnimationFrame","setLoadProgress","onProgress","filledLoad","prepend","setSeekMax","setListeners","setHandlers","scrubTime","isSafariBuffering","buf","buffered","numRanges","nearestStart","end","start","removeListeners","lastVolume","video","onFullScreen","webkitFullscreenElement","wrapper","parentNode","insertBefore","appendChild","skin","ckin","stylePlayer","controls","progress","muted","autoplay","finally","initDuration","player","html","buildControls","timeDuration","insertAdjacentHTML","fullScreenButton","timeElapsed","String","toHHMMSS","volumeDiv","volumeSvg","firstElementChild","onMuteClick","cancelEvent","volumeProgress","Math","setVolume","d","togglePlay","showControlsTimeout","showControls","code","toggleFullScreen","split","eventName","round","fullscreenElement","mozFullScreenElement","msFullscreenElement","webkitEnterFullscreen","enterFullscreen","isFullScreen","cancelFullScreen","mozCancelFullScreen","webkitCancelFullScreen","msExitFullscreen","requestFullscreen","mozRequestFullScreen","webkitRequestFullscreen","msRequestFullscreen","wrapVoiceMessage","audioEl","webpage","isOut","myId","isUnread","pFlags","media_unread","out","barHeightMax","mediaSizes","isMobile","svg","createElementNS","setAttributeNS","timeDiv","waveform","attributes","attribute","Uint8Array","valueCount","dataView","DataView","buffer","byteIndex","bitShift","getUint16","decodeWaveform","slice","normValue","wfSize","barCount","maxValue","maxDelta","barX","sumI","bar_value","barWidth","rects","children","interval","lastIndex","audio","node","clearInterval","setInterval","isNaN","addAudioListener","readMessages","mousemove","MouseEvent","target","targetTouches","mids","elem","HTMLElement","withTime","voiceAsMusic","showSender","attachedHandlers","isRealVoice","isVoice","isOutgoing","is_outgoing","uploading","preloader","durationStr","downloadDiv","onTypeLoad","senderTitle","getSenderToPeerText","subtitle","audioTitle","file_name","audioPerformer","wrapPlainText","formatDate","date","titleAdditionHTML","Date","fontWeight","subtitleDiv","launched","progressLine","lastChild","replaceWith","onPlaying","wrapAudio","audioTimeDiv","onLoad","onTypeDisconnect","getTimeStr","innerText","attach","getDownloadPromise","cancelable","load","download","onClick","construct","setManual","setDownloadFunction","noAutoDownload","willBePlayed","readyState","capture","isConnected","customElements","define","DivAndCaption","fill","border","wrapReplyDivAndCaption","titleEl","subtitleEl","mediaEl","wrapEmojiText","setMedia","wrapMessageForReply","photo","boxSize","backgroundImage","wrapSticker","div","lazyLoadQueue","chat","bubbles","group","CHAT_ANIMATION_GROUP","size","choosePhotoSize","downloaded","sizes","thumbs","bytes","renderImageFromUrl","getPreviewURLFromThumb","preloadPhoto","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","w","h0","h","w0","w2","w1","h1","h2","map","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","isChanged","inputFields","isValid","handleChange","avatarElem","doNotEditAvatar","freezed","radioField","checkboxField","subtitleLangKey","subtitleLangArgs","havePadding","isToggle","titleRight","noCheckboxSubtitle","checked","titleLangKey","c","navigationTab","ripple","RadioFormFromRows","rows","radios","form","RadioForm","copyTextToClipboard","text","navigator","clipboard","writeText","textArea","top","position","select","execCommand","removeChild","fallbackCopyTextToClipboard","stateKey","appStateManager","getState","state","setByKey","main","langKey","setValueSilently","Event","toastEl","toast","toastNew","langPackKey","checkUsernameDebounced","checkUsername","bind","getValue","originalValue","setState","Neutral","isUsernameValid","setError","invalidText","head","username","checkUsernamePromise","invokeApi","channel","getChannelInput","available","Valid","availableText","takenText","buttons","overlayClosable","avatarEl","titleLangArgs","p","descriptionLangKey","descriptionLangArgs","description","fragment","createDocumentFragment","checkboxes","o","withRipple","original","nextElementSibling","isBroadcast","section","random","privateRow","publicRow","a","privateSection","publicSection","reverse","getChat","linkRow","chatFull","exported_invite","link","format","btnRevoke","toggleDisability","getChatInviteLink","show","caption","noDelimiter","changed","linkInputField","applyBtn","migrateChat","channelId","updateUsername","close","setOriginalValue","loading","loaded","getPromise","done","checkForTriggers","loadAllDialogsPromise","loadedAllDialogs","selected","folderId","offsetIndex","loadedWhat","renderedPeerIds","peerType","multiSelect","tempIds","selfPresence","needSwitchList","includes","cachedContacts","getMoreResults","f","renderResultsFunc","renderResults","peerIds","splitUp","notRendered","has","topContainer","selectedContainer","selectedScrollable","delimiter","findUpClassName","li","click","findUpAttribute","checkbox","debouncedInput","debounce","appendTo","getResultsPromise","onFirstRender","testSelfSearch","dialogs","archived","pageCount","windowH","tempId","getTempId","getConversations","newOffsetIndex","chatRightsAction","filterByRights","renderSaved","isEnd","getMoreDialogs","contacts","getMoreContacts","canSendToUser","hasRights","getContacts","searchContacts","searchResult","resultPeerIds","my_results","concat","results","arr","splice","channelParticipants","getChannelParticipants","q","participants","participant","getParticipantPeerId","u","promises","getConversationsAll","getMoreChannelParticipants","isNonContactUser","containerEl","getChatMembersString","scroll","onlyFirstName","insertAdjacentElement","scrollIntoViewNew","offsetWidth","onAnimationEnd","settings","animationsEnabled","values","Static","closable","selector","getSelected","onSelect","hide","peerTypes","destroyListener","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","LOAD_COUNT","loader","onScroll","getDialogType","peerTitleElement","callbackLeave","flush","leave","flushHistory","callbackDelete","descriptionArgs","isDanger","textArgs","getChatFull","isChannel","chatNameInputField","descriptionInputField","about","editPeer","chatTypeRow","setChatTypeSubtitle","permissionsRow","setPermissionsLength","reduce","acc","editTitle","editAbout","race","removeAttribute","deleteChannel","migrateFrom","migrateTo","_init","nameInputField","lastNameInputField","user","getUser","first_name","last_name","notificationsCheckboxField","isTrusted","mutePeer","enabled","isMuted","notify_settings","notificationsRow","isPeerLocalMuted","profileNameDiv","profileSubtitleDiv","addContact","phone","deleteContacts","getEvent","attachGlobalListenerTo","hadMove","xDown","yDown","handleMove","cursor","onReset","handleStart","_e","verifyTouchTarget","xUp","yUp","xDiff","yDiff","onFirstSwipe","onSwipe","skippable","attachToPromise","removeLoader","ret","selectedPeerIds","addInitial","setText","PARALLAX_SUPPORTED","previous","next","loadCount","loadedAllUp","loadedAllDown","items","item","current","unshift","onJump","older","loadPromiseDown","loadPromiseUp","anchor","loadMore","processed","processItem","photoId","avatar","BASE_CLASS","getPhoto","action","img","Image","draggable","getPeerPhoto","appAvatarsManager","putAvatar","avatars","gradient","arrowPrevious","arrowNext","checkScrollTop","scrollTop","cancel","freeze","clickX","listLoader","targets","idx","prevTargets","nextTargets","openAvatarViewer","toRight","right","distance","offsetLeft","go","cancelNextClick","lastDiffX","minX","lastX","SCALE","transform","TRANSLATE_TEMPLATE","replace","addIndex","ceil","getUserPhotos","photos","Number","MAX_SAFE_INTEGER","chat_photo","generateFakeAvatarMessage","activeTab","photo_id","setPeerStatus","needClear","bio","tagName","getProfileByPeerId","full","getPeer","notifications","setBio","setPeerStatusInterval","setBioTimeout","oldAvatars","setPeer","cleaned","cleanupHTML","setAvatar","getPeerUsername","formatUserPhone","override","getProfile","userFull","rAbout","wrapRichText","canSetNext","historiesStorage","newCloseBtn","animatedCloseIcon","transitionContainer","transitionFirstItem","editBtn","transitionLastItem","secondTitle","cloneNode","profile","onAdditionalScroll","searchSuper","nav","isSharedMedia","transition","cleanScrollPositions","isHeavyAnimationInProgress","mediaTabs","onChangeTab","mediaTab","btnAddMembers","showConfirmation","b","inviteToChannel","addChatUser","filtered","filterMessagesByType","usedFromHistory","performSearchResult","findIndex","canViewMembers","loadMutex","peerChanged","setQuery","historyStorage","fillProfileElements","isContact","admin_rights","deactivated","single","justLoad","AppSharedMediaTab","getElementById","to","medium","mobile","toggleSidebar","sharedMediaTab","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","onHide","maxOffset","isQuiz","isRetracted","isPublic","isMultiple","chosingIndexes","sentVote","getTotalLength","pollId","descKey","is_scheduled","public_voters","multiple_choice","multipleSelect","regular","descDiv","typeDiv","avatarsDiv","close_period","close_date","timeLeftDiv","quizTimer","strokeWidth","radius","circumference","PI","circle","period","closeTime","serverTimeOffset","quizInterval","time","now","timeLeft","color","stroke","strokeDashoffset","strokeDasharray","getResults","answerDivs","svgLines","numberDivs","footerDiv","viewResults","votersCountDiv","isTabExists","sendVoteBtn","sendVotes","setVotersCount","clickHandler","solution","solution_entities","toggleHint","textEl","entities","bubblesContainer","setQuizHint","correctResult","correct","chosen","answerIndex","foundIndex","indexes","sendVotePromise","sendVote","initQuizHint","timeEl","setResults","recent_voters","maxPercents","setLineProgress","cb","getPercentValue","iterate","fullTime","times","votersCount","multiplier","getStickerSetPromises","getStickersByEmoticonsPromises","getStickerSet","saveById","addMultipleEventsListeners","updateNewStickerSet","saveStickerSet","stickerset","set","getGreetingStickersTimeout","getGreetingSticker","justPreload","getGreetingStickersPromise","getStickersByEmoticon","docs","greetingStickers","sort","saveDoc","params","overwrite","cachedSet","documents","refreshTime","useCache","saveStickers","stickerSet","getStickerSetInput","invokeApiHashable","stickers","emoji","getFromCache","pack","packs","emoticon","getDoc","newSet","Object","assign","setToCache","needSave","installed_date","thumb","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","docId","appStickersManager","wrapVideo","boxWidth","boxHeight","withTail","middleware","noInfo","onlyPreview","withoutPreloader","loadPromises","noPlayButton","isAlbumItem","canAutoplay","autoPlay","gifs","videos","spanTime","spanPlay","needPlayButton","mime_type","photoRes","wrapPhoto","loadPromise","globalVideo","divRound","baseVal","ctx","setPeerPromise","isInDOM","onTimeUpdate","onPaused","onFrame","drawImage","foreignObject","images","getAttributeNS","gotThumb","getThumb","poster","aspecter","attachMethod","loadFunc","reject","detach","queueId","animationIntersector","addAnimation","loop","render","timestamp","monthShort","withYear","month","getMonth","str","getDate","getFullYear","getHours","getMinutes","wrapDocument","searchContext","audioElement","extSplitted","ext","isArray","docDiv","icoDiv","imgs","wrapped","fileName","_downloadDiv","saveDocFile","noBlur","noThumb","noFadeIn","setAttachmentSize","thumbImage","image","isFit","loadThumbPromise","photoSize","getStrippedThumbIfNeeded","needFadeIn","sequentialDom","mutateElement","mutate","renderPromise","onlyThumb","withThumb","stickerType","loadLottieWorkers","Error","toneIndex","haveThumbCached","stickerCachedThumbs","afterRender","getPathFromPhotoPathSize","webpWorkerController","isWebpSupported","stickerThumbConverted","convert","getThumbURL","json","animation","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","users","sorted","doTimeout","updateList","good","SORT_INTERVAL","sortedUser","status","getUserStatusForSort","batch","prevTabId","urlsToRevoke","nextRates","loadedChats","firstLoad","log","logger","monthContainers","mediaTabsMap","asChatList","groupByMonth","hideEmptyTabs","onTransitionStart","onTransitionEnd","navScrollableContainer","navScrollable","tabsMenu","menuTab","span","contentTab","searchGroupMedia","horizontalMenu","tabContent","skipScroll","newMediaTab","fromMediaTab","offsetTop","scrollHeight","rect2","inputMessagesFilterPhotoVideo","warn","setSearchContext","copySearchContext","openMedia","useHeavyAnimationCheck","lock","unlockAndRefresh","elemsToAppend","sharedMediaDiv","entity","totalEntities","display_url","sliced","match","matchUrl","same","hostname","rDescription","previewDiv","getAbbreviation","rTitle","sender","method","details","monthContainer","getMonthContainerByTimestamp","afterPerforming","parent","child","inputMessagesFilterEmpty","showMembersCount","participants_count","regExp","RegExp","cleanSearchText","titleSpan","formatted","arg","globalContacts","isShort","minDate","renderRecentSearch","recent","recentSearch","getTopPeers","peers","people","renderParticipants","membersList","setInnerPeer","deleted","loadMembers","loadChats","logStr","used","slicedLength","ids","nextRate","maxDate","next_rate","filters","counters","getSearchCounters","firstMediaTab","counter","membersTab","toLoad","loadType","setHours","setDate","dateTimestamp","getTime","containers","haveTimestamps","clean","goFirst","revokeObjectURL","empty","newInputFilter","context","ButtonMenuItem","keepOpen","ButtonMenuToggleHandler","openedMenu","PrivacyType","direction","asDiv","btnMenu","appPrivacyManager","privacy","updatePrivacy","rules","inputKey","privacyRules","saveApiUsers","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","s","chatKey","usersKey","splitted","getUserInput","setPrivacy","phoneSection","nextSibling","getAnimatedEmojiSticker","stickerContainer","inputContent","btnReturn","sliceTabsUntilTab","canFocus","isFirstInput","isFirst","email","codeInputField","onFill","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","isNew","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","cancelBubble","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","onDeleteClick","deleteButton","clearAllDrafts","auths","rgbaToHsla","g","l","hslaToRgba","hue2rgb","hexaToRgba","hexa","parseInt","rgbaToHexa","rgba","toString","hslaStringToHexa","hsla","alpha","val","endsWith","hslaStringToRgba","highlightningColor","hue","saturation","lightness","elements","onGrabStart","documentElement","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","uploadTempId","clicked","onUploadClick","file","dc_id","file_reference","wallpaper","slug","upload","addNotifyListener","_wallpaper","newDoc","newCacheContext","setBackgroundDocument","isUpload","tryAgainOnFail","addWallPaper","onResetClick","defaultTheme","themes","blurCheckboxField","blur","onGridClick","saveToCache","fetch","response","cacheStorage","save","_tempId","onReady","imageUrl","naturalWidth","naturalHeight","pixel","pixels","getImageData","data","pixelsLength","outPixel","Uint8ClampedArray","averageColor","uploadButton","colorButton","resetButton","accountWallpapers","wallpapers","pattern","stickerSetInput","onFooterClick","stickersFooter","toggleStickerSet","onStickersClick","fileId","sendMessageWithDocument","h6","setOnlyOnePlayableGroup","stickersDiv","btn","loadStickerSet","esgSticker","initialValue","minValue","nameDiv","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","href","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","loadAnimationFromURL","waitForFirstFrame","wrapDraftText","ul","renderMore","_length","firstTime","onEditOpen","onCreateOpen","filtersRendered","dialogFilter","keys","folder","channels","isAnyGroup","filterId","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","alive","inputSearch","openContacts","_contacts","renderPage","chatLists","chatList","generateScrollable","scrollables","wasFilterId","onTabChange","appSidebarLeft","sidebarHeader","onContactsClick","backBtn","btnArchive","verify","themeCheckboxField","menuButtons","openUsername","sessionStorage","kz_version","isMainDomain","toolsBtn","btnMenuFooter","suffix","version","newBtnMenu","initSearch","archivedCount","requestPeer","searchContainer","pickedElements","selectedPeerId","selectedMinDate","selectedMaxDate","updatePicked","setProperty","removeProperty","helper","unselectEntity","renderEntity","dates","dateData","getAttribute","peopleContainer","hideNewBtnMenuTimeout","onFocus","clearRecentSearchBtn","detailsMap","newGroupDiff","bubble","updateGroup","viaBotId","fwdFromId","removeBubble","insertObject","foundBubble","foundAtIndex","foundMidOnSameTimestamp","_timestamp","_mid","bubbleGroup","insertIndex","last","initDate","onPick","noButtons","selectedDate","onPrevClick","selectedMonth","setMonth","minMonth","prevBtn","onNextClick","maxMonth","onDateClick","selectedEl","setTimeTitle","setFullYear","controlsDiv","monthTitle","monthsContainer","handleTimeInput","onOverflow","maxString","hoursInputField","minutesInputField","number","setMinutes","btnConfirm","popupCenterer","noTitle","timeOptions","minute","hour","sendDate","dateOptions","day","year","IntlDateElement","firstChild","weekday","firstDate","weekStartDate","getDay","renderElement","dayIndex","clonedDate","showOverflowMonths","lines","fromPeerId","initMessagesForward","StickyIntersector","handler","observeHeaders","observeElements","headersObserver","IntersectionObserver","entries","entry","targetInfo","boundingClientRect","stickyTarget","rootBoundsInfo","rootBounds","bottom","threshold","root","elementsObserver","isIntersecting","sentinel","headerSentinel","addSentinel","observe","disconnect","unobserve","updated","postKey","replies","leftPart","recent_repliers","getHistoryStorage","channel_id","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","appMessagesManager","wrapSingleMessage","needUpdate","replyMid","getElementByPoint","verticalSide","horizontalSide","floor","elementFromPoint","reflowScrollableElement","setInnerHTML","EMOJI_LANG_PACK","keywords","langCode","langPackCode","keywordLangPacks","indexedLangPacks","getKeywordsPromises","storageKey","stateStorage","from_version","keywordsDifference","packKeywords","keyword","emoticons","getEmojiKeywords","lastRequestedLangCode","getRecentEmojis","indexObject","emojis","indexEmojis","search","POPULAR_EMOJI","getRecentEmojisPromise","recentEmoji","appEmojiManager","loadedURLs","appendEmoji","unify","spanEmoji","kek","emojiSupported","wrapSingleEmoji","fixEmoji","opacity","getEmojiFromElement","nodeType","nodeValue","onContentClick","messageInput","inputHTML","inserted","getSelection","savedRange","getSavedRange","sel","removeAllRanges","addRange","getRangeAt","rangeCount","deleteContents","insertNode","setStart","createRange","setStartAfter","collapse","divs","Emoji","category","titleDiv","itemsDiv","unified","menu","previousElementSibling","emojiScroll","recentItemsDiv","stickyIntersector","observeStickyHeaderChanges","menuOnClick","scrollPromise","processVisibleDiv","getAnimations","checkAnimation","intersector","isVisible","processInvisibleDiv","visible","gifWidth","gifHeight","willUseWidth","calcImageInBox","gifsContainer","onMediaClick","masonry","EMOTICONSSTICKERGROUP","addLazyLoadQueueRepeat","regularLazyLoadQueue","animatedDivs","checkAnimationContainer","renderSticker","mounted","queueCategoryPush","categoryDiv","categoryTitle","superStickerRenderer","recentDiv","categoryPush","menuWrapper","menuScroll","inlineResults","botId","geo","getInputPeerById","geo_point","lat","long","stopTime","noErrorBox","botResults","queryId","query_id","qId","savePhoto","msg_id","getServerMessageId","callbackAnswer","noLinks","noLinebreaks","nextOffset","loadedAll","onGifsClick","gifsDiv","checkAnimations","newSearch","gifBotPeerId","resolveUsername","getInlineResults","setsDiv","countDiv","stickerDiv","renderFeatured","getFeaturedStickers","coveredSets","filterRendered","renderSet","searchStickerSets","forceClose","inited","onMouseOut","displayTimeout","isActive","toElement","findUpAsChild","willBeActive","onmouseout","onmouseover","tabId","onSelectTabClick","searchButton","deleteBtn","checkRights","tabsEl","tabsElements","canSendStickers","toggleAttribute","canSendGifs","blurActiveElement","chatInput","activeElement","lockIntersectionGroup","unlockIntersectionGroup","unlock","refresh","emojiTab","stickersTab","gifsTab","0","1","2","getVisible","clearVisible","prevId","jumpedTo","stuck","which","scrollLeft","clearDraft","emoticonsDropdown","IGNORE_ACTIONS","TEST_SCROLL","appUsersManager","appInlineBotsManager","appPhotosManager","appProfileManager","unreadOut","skippedMids","dateMessages","scrolledDown","isScrollingTimeout","unreaded","unreadedSeen","loadedTopTimes","loadedBottomTimes","messagesQueuePromise","messagesQueue","messagesQueueOnRender","messagesQueueOnRenderAdditional","firstUnreadBubble","replyFollowHistory","isFirstLoad","passEntities","onBubblesClick","chatInner","onDatePick","selection","isSelecting","selectedText","toggleByBubble","contactDiv","appImManager","bubbleMid","reply_to_top_id","generateThreadServiceStartMessage","filterMessages","getDiscussionMessage","savedFrom","msgId","isVideoComponentElement","messageId","hasAspecter","parents","albumItem","isReplyClick","replyToMid","reply_to_msg_id","getDistanceToEnd","topbar","pinnedMessage","setCorrectIndex","lastScrollDirection","requestHistory","setMessageId","setScroll","bubbleGroups","getMessagesStorage","setBubblePosition","scrollingToNewBubble","scrollToBubbleEnd","deleteMessagesByIds","tempMessage","getMountedBubble","repliesElement","grouped_id","newPoll","renderMessage","scrollToBubbleIfLast","updatePosition","deleteEmptyDateGroups","deletedMids","renderedId","renderMaxId","groupedMessagesStorage","getMiddleware","obj","highlightBubble","canWriteToPeer","initMessageReply","dateMessage","renderNewMessagesByIds","msgIdsByPeer","msgIds","msgs","setUnreadCount","updateUnreadByDialog","finishPeerChange","updateMessageInput","isScrolledDown","setMessagesQueuePromise","performHistoryResult","unreadedObserver","onUnreadedInViewport","wasHeight","offsetHeight","resizing","skip","scrolled","part","rAF","onResizeEnd","setEndRAF","ResizeObserver","contentRect","realDiff","_part","needScrollTop","readUnreaded","readPromise","idle","focusPromise","bubblesMaxId","readHistory","onUpdate","getScheduledMessagesStorage","bad","getGroupedBubble","getHistoryTopPromise","getHistoryBottomPromise","getHistory","setLoaded","onScrolledTop","loadMoreHistory","readOutboxMaxId","permanent","emptyPlaceholderMid","deleteSelectedMids","replyTo","forceDirection","forceDuration","dateGroup","lastDateGroup","getLastDateGroup","scrollToBubble","lastElem","lastTime","firstTimestamp","datasetKey","dateElement","today","bubbleContent","serviceMsg","bubblesToo","attachedUnreadBubble","fetchNewPromise","onAnimateLadder","resolveLadderAnimation","lastMsgId","samePeer","topMessage","pinnedMessages","isTarget","savedPosition","getChatSavedPosition","getReadMaxIdIfUnread","isJump","apiManager","setQueueId","messageEntityBotCommand","isBot","additionMsgId","maxBubbleId","getBubbleByPoint","oldChatInner","cached","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","isMegagroup","contentWrapper","wasClassNames","classNames","transitionDelay","originalMid","unread","chat_id","wrapMessageActionTextNew","renderMessagesQueue","is_single","messageMessage","messageMedia","getAlbumText","richText","canHaveTail","needToSetHTML","emojiEntities","strLength","curr","big","reply_markup","containerDiv","rowDiv","buttonEl","htmlToDocumentFragment","column","callbackButtonClick","messageWithReplies","getMessageWithReplies","withReplies","nameContainer","processingWebPage","noAutoDownloadMedia","previewResizer","preview","quote","quoteTextDiv","site_name","textDiv","isSquare","emojiSticker","animatedSticker","staticSticker","newNameContainer","getMidsByMid","wrapGroupedDocuments","lastContainer","texts","phone_number","wrapPoll","toggleBubbleCheckbox","needName","isForwardFromChannel","from_id","isHidden","from_name","getPeerColorById","goto","generateTail","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","use","onConfirm","revoke","deleteScheduledMessages","deleteMessages","titleArgs","canRevoke","unpin","canUnpin","canPinMessage","oneSide","silent","unpinAllMessages","hidePinnedMessages","updatePinnedMessage","buttonText","pinButtonText","sendScheduledMessages","cancelSelection","isSelectionEmpty","selectionRange","START_TO_END","attachTo","appPollsManager","appDocsManager","onSendScheduledClick","selectionSendNowBtn","onReplyClick","onEditClick","initMessageEditing","onCopyClick","selectedMids","onCopyAnchorLinkClick","onCopyLinkClick","onPinClick","onUnpinClick","onRetractVote","onStopPoll","stopPoll","onForwardClick","selectionForwardBtn","isTargetAGroupedItem","onSelectClick","onClearSelectionClick","selectionDeleteBtn","onContextMenu","selectedMid","isSelectable","canSelectBubble","isTextSelected","isAnchorTarget","groupedItem","withSelection","changedTouches","hasAttribute","notDirect","scheduleSending","editMessage","scheduleDate","onMessageSent","canEditMessage","canDeleteMessage","sendMenuButtons","onSilentClick","onScheduleClick","sendMenu","openSide","onContextElement","withConfirm","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","validate","force","quizSolutionEntities","btnClose","inputMediaPoll","getInputMediaPoll","sendOther","replyToMsgId","helperType","clearHelper","questionField","isSendShortcutPressed","isComposing","sendShortcut","shiftKey","ctrlKey","metaKey","secondaryKey","placeCaretAtEnd","selectNodeContents","createTextRange","textRange","moveToElementText","files","willAttachType","wasInputValue","willAttach","sendFileDetails","onKeyDown","attachFile","itemDiv","isVideo","source","objectURL","videoWidth","videoHeight","thumbBlob","thumbURL","onload","isPhoto","isAudio","finish","onerror","mediaContainer","config","caption_length_max","showLengthOn","messageInputField","groupCheckboxField","attachFiles","isMedia","firstType","sendAlbum","sendText","sendFile","foundPhotos","foundVideos","albumsLength","albumContainer","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","getRichValueWithCaret","field","withEntities","selNode","selOffset","startContainer","endContainer","startOffset","endOffset","getRichElementValue","caretPos","substr","combineSameEntities","onEmojiSelected","firstChar","getBothEmojiKeywords","searchEmojis","listElement","BASE","BASE_CLASS_LIST_ELEMENT","sendMessage","botInfos","commands","botInfo","botCommand","command","found","helpers","preserveHelper","insertAtCaret","topMsgId","trimmed","getMentions","onBodyTouchStart","btnHover","attachButtonListener","checkAvailability","touchListener","replyMarkup","getReplyMarkup","appChatsManager","appWebPagesManager","appDraftsManager","serverTimeManager","appNotificationsManager","lastUrl","lastTimeType","replyElements","willSendWebPage","forwardingMids","forwardingFromPeerId","recording","recordCanceled","recordStartTime","lockRedo","canRedoFromHTML","undoHistory","executedHistory","canUndoFromHTML","onCancelRecordClick","recorder","stop","opusDecodeController","setKeepAlive","onEmoticonsOpen","toggleClass","btnToggleEmoticons","onEmoticonsClose","openScheduled","prepareDocumentExecute","undoRedo","needHTML","sameHTMLTimes","currentHTML","handleMarkdownShortcut","formatKeys","markupTooltip","showLinkEditor","applyMarkdown","onMessageInput","richValue","markdownEntities","parseMarkdown","mergeEntities","parseEntities","urlEntities","saveWebPage","setTopInfo","noWebPage","helperFunc","setTyping","editMsgId","saveDraftDebounced","checkAutocomplete","updateSendBtn","autocomplete","getEmojiEntityFromEmoji","onBtnSendClick","sourceNode","analyser","createAnalyser","connect","fftSize","frequencyData","frequencyBinCount","getByteFrequencyData","recordRippleEl","ms","recordTimeEl","onHelperCancel","needReturn","onHelperClick","helperWaitingForward","inputContainer","rowsWrapper","tail","fakeRowsWrapper","fakeSelectionWrapper","goDownBtn","onGoDownClick","cancelBtn","dac","newMessageWrapper","inputMessageContainer","goDownUnreadBadge","btnScheduled","btnToggleReplyMarkup","replyKeyboard","attachMenuButtons","fileInput","attachMenu","multiple","autocompleteHelperController","stickersHelper","emojiHelper","commandsHelper","mentionsHelper","btnCancelRecord","btnSendContainer","btnSend","attachMessageInputField","previousQuery","onFakeInput","draft","setDraft","saveDraft","encoderSampleRate","monitorGain","numberOfChannels","recordingGain","reuseWorker","touchMouseDown","onstop","ondataavailable","typedArray","dataBlob","Blob","decode","isVoiceMessage","pinnedControlBtn","fakeContainer","fakePinnedControlBtn","originalChat","pinnedMessageContainer","unread_count","no_webpage","syncDraft","helperToo","clearInput","fromUpdate","getDraft","setInputValue","rMessage","oldInputField","inputFake","attachMessageInputListeners","childNodes","readAllHistory","commandsMap","bold","italic","underline","strikethrough","monospace","saveExecuted","executed","haveThisType","isCollapsed","tag","commonAncestorContainer","matches","setActiveMarkupButton","insertText","insertEntity","isHelper","fullValue","prefix","AUTO_COMPLETE_REG_EXP","matchIndex","newValue","hadEntities","insertLength","addEntities","caret","selectNode","noCollapse","setRichFocus","_value","foundHelper","suggest","checkEmoticon","checkQuery","canSetDraft","fixSafariStickyInput","clearReply","unicode","pushRecentEmoji","webPage","forwardMessages","pushRecentSticker","replyFragment","smth","peerTitles","getPeerTitle","firstMessage","usingFullAlbum","albumMids","getMidsByMessage","callerFunc","toggleSelection","isGroupedBubbleSelected","getBubbleGroupedItems","forwarded_count_max","groupContainer","isGroupedSelected","isGroupedMidsSelected","updateBubbleSelection","seen","selecting","canceledSelection","removeManual","documentListenerOptions","isBubbleSelected","hasCheckbox","getCheckboxInputFromBubble","isGrouped","forceSelection","selectionCountEl","cantForward","cantDelete","cantSend","toggleCheckboxes","wasSelecting","borderRadius","forwards","fakeSelectionRect","fakeRowsRect","widthFrom","widthTo","scale","initTranslateX","br","selectionInputWrapper","selectionContainer","btnCancel","updateContainer","isSelected","groupedCheckboxInput","divAndCaption","CLASSNAME_BASE","needClose","maxActive","setUtilsWidth","toggleEl","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","new","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","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","chatAudio","resize","setUtilsRAF","chatUtils","chatInfo","btnBack","person","avatarElement","btnMore","getDeleteButtonText","btnJoin","btnPinned","btnMute","btnSearch","followPinnedMessage","activeScreen","onBtnBackClick","isFirstChat","chatContextMenuHintWasShown","joinChannel","setMutedState","isTopMessage","hiddenPinnedMessages","byCurrent","destroy","wasPeerId","newPinnedMessage","appSearch","beginSearch","btnPickDate","selectedIndex","selectResult","upBtn","downBtn","foundCountEl","renderedCount","onResultsClick","onUpClick","onDownClick","footer","dateBtn","wasAlreadyUsed","backgroundEl","Log","Warn","Debug","_item","prev","contextMenu","constructUtils","constructPeerHelpers","constructPinnedHelpers","constructDiscussionHelpers","constructScheduledHelpers","searchTab","setAutoDownloadMedia","setLoadMutex","loadSidebarMedia","autoDownload","setPrefix","getMessageFromStorage","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","chatInvite","broadcast","updates","processUpdateMessage","putPhoto","peopleCount","FOCUS_EVENT_NAME","columnEl","offline","updateStatusInterval","backgroundPromises","onHashChange","parseUriParams","postId","post","setSettings","chatsSelectTabDebounced","setLoop","onDocumentPaste","attachType","canDrag","DragEvent","_types","dataTransfer","isIDLE","updateStatus","createNewChat","chatsSelectTab","saveChatPosition","popup","singleInstance","activateInstance","addAnchorListener","noParams","hashtag","parsePathname","saveApiChat","pathname","uri","decodeURIComponent","broadcastEvent","STATE_INIT","getBackground","setBackground","getFile","chatBubbles","chatPositions","themeColor","hslaStringToHex","themeColorElem","backgroundUrl","applyHighlightningColor","setTheme","setCurrentBackground","prevTab","prevIdx","IGNORE_KEYS","overlayIsActive","goodMid","renderNewMessages","deleteDeletedMessages","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","lastTarget","isFirstOpen","loadMediaPromiseUp","loadMediaPromiseDown","loadedAllMediaUp","loadedAllMediaDown","needLoadMore","pageEl","setMoverAnimationPromise","highlightSwitchersTimeout","wholeDiv","mover","MEDIA_VIEWER_CLASSNAME","overlaysDiv","mainDiv","onlyMobile","setNewMover","onDownloadClick","setMoverPromise","windowW","evt","btnMenuToggle","setMoverToTarget","closing","fromRight","videoPlayer","removeCenterFromMover","wasActive","realParent","SVGImageElement","SVGForeignObjectElement","needOpacity","visibleRect","overflowElement","overflowRect","overflowTop","overflowBottom","sticky","overflow","vertical","horizontal","visualViewport","windowHeight","innerWidth","innerHeight","getVisibleRect","HTMLImageElement","HTMLVideoElement","setFullAspect","scaleX","scaleY","getComputedStyle","getPropertyValue","brSplitted","fillPropertyValue","SVGSVGElement","sizeTailPath","mediaElement","clipId","newClipId","newSvg","outerHTML","SVGUseElement","sX","sY","proportion","upscale","_br","toLeft","newTransform","p1","newMover","timeStr","dateStr","oldAvatar","replaceChild","setAuthorInfo","useContainerAsTarget","loadMoreMedia","moveTheMover","mainColumns","scrollWidth","thumbPromise","moverVideo","canPlayThrough","createPlayer","overlay","HAVE_FUTURE_DATA","attachCanPlay","networkState","NETWORK_LOADING","isntEnoughData","updateMediaSource","cancellablePromise","attachPromise","haveImage","currentMessageId","onAuthorClick","savePhotoFile","incrementMessageId","getMediaFromMessage","setBtnMenuToggle","_openMedia","setCaption","currentPhotoId","onAvatarUpdate","removeFromAvatarsCache","getFullPhoto","getTarget","hadMessage","believeMe","isDialog","addedToQueue","oldValue","getPeerMigratedTo","peerTitle","onArchiveClick","selectedId","editPeerFolders","folder_id","toggleDialogPin","pinned_dialogs_count_max","onUnmuteClick","onUnreadClick","top_message","ConnectionStatus","hadConnect","connecting","timedOut","updating","setConnectionStatus","baseDcId","setFirstConnectionTimeout","connectionStatus","online","Connected","forceGetDifference","TimedOut","retryAt","setStatusText","currentLangPackKey","statusEl","statusPreloader","CHANGE_STATE_DELAY","getA","forceReconnect","timerSpan","forceReconnectTimeout","setStateTimeout","statusContainer","constructContainer","doms","menuScrollContainer","lastActiveElements","offsets","loadDialogsPromise","loadDialogs","onListLengthChange","placeholderContainer","needPlaceholder","generateEmptyPlaceholder","classNameType","wrapLocalSticker","onChatsRegularScroll","sliceTimeout","reorderDialogsTimeout","scrollTopWas","rectContainer","rectTarget","firstY","firstElement","lastElement","elementOverflow","firstIndex","sliceFromStart","sliceFromEnd","deleteDialog","setOffsets","onChatsScrollTop","onChatsScroll","chatsPreloader","allUnreadCount","bottomPart","addFilter","getDialogDom","validateForFilter","setFiltersUnreadCount","updateDialog","setUnreadMessages","order","containerToAppend","renderedFilter","unsetTyping","onStateLoaded","foldersScrollable","isLoadedMain","isDialogsLoaded","isLoadedArchive","wasLoaded","accumulateArchivedUnread","updatesState","syncLoading","refreshConversations","getNotifyPeerTypeSettings","renderFiltersPromise","showFiltersPromise","storagesResults","addMissedDialogs","migratedTo","topOffset","getOffsetIndex","bottomOffset","isDialogMustBeInViewport","getDialogByPeerId","reorderDialogs","unreadSpan","mutedCount","notMutedCount","setFilterUnreadCount","_peerId","currentOffsetIndex","needIndex","getConversationPromise","offsetDialog","subtitleArgs","firstDialog","getDialogFromElement","lastDialog","withContext","openInner","lastActiveListElement","setPeerFunc","sameElement","currentOrder","peerIdByIndex","lastMessage","highlightWord","draftMessage","lastTimeSpan","senderBold","statusSpan","unreadMessagesSpan","isPinned","accumulateArchivedTimeout","addDialog","_dialog","originalDialog","testDialogForFilter","captionDiv","titleSpanContainer","verified","generateVerifiedIcon","titleP","rightSpan","messageP","use2","appDialogsManager","self","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","totalLength","samplePosition","page","originalSampleRate","sampleRate","wavSampleRate","onpause","resume","onresume","gain","setTargetAtTime","onstart","destroyWorker","Function","downloads","progressCallbacks","uploadId","thumbsCache","callbacks","notifyAll","cancelDownload","clearDownload","getNewDeferred","worker","onlyCache","downloadFile","tryDownload","uploadFile","onRemove","clickEvent","createEvent","initMouseEvent","discFileName","createDownloadAnchor","thumbSize","PopupElement","onOverlayClick","buttonsElements","langArgs","addCancelButton","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","getFileNameByLocation","thumb_size","volume_id","local_id","getFileURL","encodeURIComponent","JSON","stringify","PasswordMonkey","needFrame","noCache","_animation","currentFrame","setSpeed","setDirection","curFrame","TrackingMonkey","playAnimation","frame","idleAnimation","CodeInputField","lastLength","setLabel","originalImage","cropComponent","cropImage","event_state","cropLeft","cropTop","cropWidth","cropHeight","scaledRatio","overlayColor","CROPWIDTH","CROPHEIGHT","updateCropSize","updateCropImage","startMoving","keyHandler","imgZoom","zoom","newWidth","clientWidth","newHeight","clientHeight","fromCharCode","charCode","stopPropagation","container_width","container_height","container_left","container_top","mouse_x","scrollX","mouse_y","scrollY","saveEventState","moving","endMoving","currentTouch","complete","crop","removeHandlers","cropper","cropContainer","contents","btnSubmit","toBlob","darkenCanvas","onCrop","postCanvas","fillStyle","fillRect"],"mappings":"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","file":"17.24cbb3aa46ec14099174.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 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) {\r\n this.peerId = peerId;\r\n this.threadId = threadId;\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 type EventListenerBase from \"./eventListenerBase\";\r\n\r\nexport type Listener = {\r\n element: ListenerElement, \r\n event: ListenerEvent, \r\n callback: ListenerCallback, \r\n options?: ListenerOptions,\r\n\r\n onceFired?: true, // will be set only when options.once is set\r\n onceCallback?: () => void,\r\n};\r\n\r\nexport type ListenerElement = Window | Document | HTMLElement | Element | EventListenerBase<any>;\r\nexport type ListenerEvent = string;\r\nexport type ListenerCallback = Function;\r\nexport type ListenerOptions = AddEventListenerOptions;\r\n\r\n/* const originalAddEventListener = HTMLElement.prototype.addEventListener;\r\nHTMLElement.prototype.addEventListener = function(this, name: string, callback: EventListenerOrEventListenerObject, options: AddEventListenerOptions) {\r\n console.log('nu zdarova', name);\r\n originalAddEventListener.call(this, name, callback, options);\r\n\r\n if(options?.ls) {\r\n return options.ls.addFromElement(this, name, callback as any, options);\r\n }\r\n}; */\r\n\r\nexport default class ListenerSetter {\r\n private listeners: Set<Listener> = new Set();\r\n\r\n public add<T extends ListenerElement>(element: T): T['addEventListener'] {\r\n return ((event: string, callback: Function, options: ListenerOptions) => {\r\n const listener: Listener = {element, event, callback, options};\r\n this.addManual(listener);\r\n return listener;\r\n }) as any;\r\n }\r\n\r\n /* public addFromElement<T extends ListenerElement>(element: T, event: ListenerEvent, callback: ListenerCallback, options: ListenerOptions) {\r\n const listener: Listener = {element, event, callback, options};\r\n this.addManual(listener);\r\n return listener;\r\n } */\r\n\r\n public addManual(listener: Listener) {\r\n // @ts-ignore\r\n listener.element.addEventListener(listener.event, listener.callback, listener.options);\r\n\r\n if(listener.options?.once) { // remove listener when its called\r\n listener.onceCallback = () => {\r\n this.remove(listener);\r\n listener.onceFired = true;\r\n };\r\n \r\n // @ts-ignore\r\n listener.element.addEventListener(listener.event, listener.onceCallback, listener.options);\r\n }\r\n\r\n this.listeners.add(listener);\r\n }\r\n\r\n public remove(listener: Listener) {\r\n if(!listener.onceFired) {\r\n // @ts-ignore\r\n listener.element.removeEventListener(listener.event, listener.callback, listener.options);\r\n\r\n if(listener.onceCallback) {\r\n // @ts-ignore\r\n listener.element.removeEventListener(listener.event, listener.onceCallback, listener.options);\r\n }\r\n }\r\n\r\n this.listeners.delete(listener);\r\n }\r\n\r\n public removeManual<T extends ListenerElement>(\r\n element: T, \r\n event: ListenerEvent, \r\n callback: ListenerCallback, \r\n options?: ListenerOptions\r\n ) {\r\n let listener: Listener;\r\n for(const _listener of this.listeners) {\r\n if(_listener.element === element && \r\n _listener.event === event && \r\n _listener.callback === callback && \r\n _listener.options === options) {\r\n listener = _listener;\r\n break;\r\n }\r\n }\r\n\r\n if(listener) {\r\n this.remove(listener);\r\n }\r\n }\r\n\r\n public removeAll() {\r\n this.listeners.forEach(listener => {\r\n this.remove(listener);\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 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', {icon: className, ...options});\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('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 { isSafari } from \"../helpers/userAgent\";\r\nimport { MOUNT_CLASS_TO } from \"../config/debug\";\r\nimport appDownloadManager from \"../lib/appManagers/appDownloadManager\";\r\n\r\n// TODO: если удалить сообщение, и при этом аудио будет играть - оно не остановится, и можно будет по нему перейти вникуда\r\n\r\n// TODO: Safari: проверить стрим, включить его и сразу попробовать включить видео или другую песню\r\n// TODO: Safari: попробовать замаскировать подгрузку последнего чанка\r\n// TODO: Safari: пофиксить момент, когда заканчивается песня и пытаешься включить её заново - прогресс сразу в конце\r\n\r\ntype HTMLMediaElement = HTMLAudioElement | HTMLVideoElement;\r\n\r\ntype MediaType = 'voice' | 'audio' | 'round';\r\n\r\nclass AppMediaPlaybackController {\r\n private container: HTMLElement;\r\n private media: {\r\n [peerId: string]: {\r\n [mid: string]: HTMLMediaElement\r\n }\r\n } = {};\r\n private playingMedia: HTMLMediaElement;\r\n\r\n private waitingMediaForLoad: {\r\n [peerId: string]: {\r\n [mid: string]: CancellablePromise<void>\r\n }\r\n } = {};\r\n \r\n public willBePlayedMedia: HTMLMediaElement;\r\n\r\n private currentPeerId: number;\r\n private prevMid: number;\r\n private nextMid: number;\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\r\n public addMedia(peerId: number, doc: MyDocument, mid: number, autoload = true): HTMLMediaElement {\r\n const storage = this.media[peerId] ?? (this.media[peerId] = {});\r\n if(storage[mid]) return storage[mid];\r\n\r\n const media = document.createElement(doc.type === 'round' ? '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 media.dataset.mid = '' + mid;\r\n media.dataset.type = doc.type;\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('playing', () => {\r\n this.currentPeerId = peerId;\r\n\r\n //console.log('appMediaPlaybackController: video playing', this.currentPeerId, this.playingMedia, media);\r\n\r\n if(this.playingMedia !== media) {\r\n if(this.playingMedia && !this.playingMedia.paused) {\r\n this.playingMedia.pause();\r\n }\r\n \r\n this.playingMedia = media;\r\n this.loadSiblingsMedia(peerId, doc.type as MediaType, mid);\r\n }\r\n\r\n // audio_pause не успеет сработать без таймаута\r\n setTimeout(() => {\r\n rootScope.dispatchEvent('audio_play', {peerId, doc, mid});\r\n }, 0);\r\n });\r\n\r\n media.addEventListener('pause', this.onPause);\r\n media.addEventListener('ended', this.onEnded);\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 waitingStorage = this.waitingMediaForLoad[peerId] ?? (this.waitingMediaForLoad[peerId] = {});\r\n waitingStorage[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 ((!doc.supportsStreaming ? appDocsManager.downloadDoc(doc) : Promise.resolve()) as Promise<any>).then(() => {\r\n if(doc.type === 'audio' && doc.supportsStreaming && isSafari) {\r\n this.handleSafariStreamable(media);\r\n }\r\n \r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n media.src = cacheContext.url;\r\n });\r\n }, onError);\r\n \r\n return storage[mid] = media;\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) {\r\n const storage = this.waitingMediaForLoad[peerId] ?? (this.waitingMediaForLoad[peerId] = {});\r\n const promise = storage[mid];\r\n if(promise) {\r\n promise.resolve();\r\n delete storage[mid];\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 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('audio_pause');\r\n };\r\n\r\n onEnded = (e?: Event) => {\r\n this.onPause(e);\r\n\r\n //console.log('on media end');\r\n\r\n if(this.nextMid) {\r\n const media = this.media[this.currentPeerId][this.nextMid];\r\n\r\n /* if(isSafari) {\r\n media.autoplay = true;\r\n } */\r\n\r\n this.resolveWaitingForLoadMedia(this.currentPeerId, this.nextMid);\r\n\r\n setTimeout(() => {\r\n media.play()//.catch(() => {});\r\n }, 0);\r\n }\r\n };\r\n\r\n private loadSiblingsMedia(peerId: number, type: MediaType, mid: number) {\r\n const media = this.playingMedia;\r\n this.prevMid = this.nextMid = 0;\r\n\r\n return appMessagesManager.getSearch({\r\n peerId, \r\n query: '', \r\n inputFilter: {\r\n //_: type === 'audio' ? 'inputMessagesFilterMusic' : (type === 'round' ? 'inputMessagesFilterRoundVideo' : 'inputMessagesFilterVoice')\r\n _: type === 'audio' ? 'inputMessagesFilterMusic' : 'inputMessagesFilterRoundVoice'\r\n },\r\n maxId: mid,\r\n limit: 3,\r\n backLimit: 2\r\n }).then(value => {\r\n if(this.playingMedia !== media) {\r\n return;\r\n }\r\n \r\n for(const {mid: m} of value.history) {\r\n if(m > mid) {\r\n this.nextMid = m;\r\n } else if(m < mid) {\r\n this.prevMid = m;\r\n break;\r\n }\r\n }\r\n\r\n [this.prevMid, this.nextMid].filter(Boolean).forEach(mid => {\r\n const message = appMessagesManager.getMessageByPeer(peerId, mid);\r\n this.addMedia(peerId, message.media.document, mid, false);\r\n });\r\n \r\n //console.log('loadSiblingsAudio', audio, type, mid, value, this.prevMid, this.nextMid);\r\n });\r\n }\r\n \r\n public toggle() {\r\n if(!this.playingMedia) return;\r\n\r\n if(this.playingMedia.paused) {\r\n this.playingMedia.play();\r\n } else {\r\n this.playingMedia.pause();\r\n }\r\n }\r\n\r\n public pause() {\r\n if(!this.playingMedia || this.playingMedia.paused) return;\r\n this.playingMedia.pause();\r\n }\r\n\r\n public willBePlayed(media: HTMLMediaElement) {\r\n this.willBePlayedMedia = media;\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};\r\n\r\nexport default function attachGrabListeners(element: HTMLElement, onStart: (position: GrabEvent) => void, onMove: (position: GrabEvent) => void, onEnd: (position: GrabEvent) => void) {\r\n // * Mouse\r\n const onMouseMove = (event: MouseEvent) => {\r\n onMove({x: event.pageX, y: event.pageY});\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});\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});\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});\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});\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});\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\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 constructor(protected step: number, protected value: number, protected min: number, protected max: number) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('progress-line');\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 = '' + 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 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.events?.onMouseDown && this.events.onMouseDown(event);\r\n };\r\n\r\n protected onMouseUp = (event: GrabEvent) => {\r\n this.mousedown = false;\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.setFilled(value);\r\n this.seek.value = '' + value;\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 this.filled.style.width = (percents * 100) + '%';\r\n //this.filled.style.transform = 'scaleX(' + scaleX + ')';\r\n }\r\n\r\n protected scrub(event: GrabEvent) {\r\n const offsetX = clamp(event.x - this.rect.left, 0, this.rect.width);\r\n\r\n let value = this.min + (offsetX / this.rect.width * (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","/*\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 appMediaPlaybackController from \"../components/appMediaPlaybackController\";\r\nimport { isAppleMobile } from \"../helpers/userAgent\";\r\nimport { isTouchSupported } from \"../helpers/touchSupport\";\r\nimport RangeSelector from \"../components/rangeSelector\";\r\nimport { onVideoLoad } from \"../helpers/files\";\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\n\r\nexport class MediaProgressLine extends RangeSelector {\r\n private filledLoad: HTMLDivElement;\r\n \r\n private stopAndScrubTimeout = 0;\r\n private progressRAF = 0;\r\n\r\n constructor(private media: HTMLAudioElement | HTMLVideoElement, private streamable = false) {\r\n super(1000 / 60 / 1000, 0, 0, 1);\r\n\r\n if(streamable) {\r\n this.filledLoad = document.createElement('div');\r\n this.filledLoad.classList.add('progress-line__filled', 'progress-line__loaded');\r\n this.container.prepend(this.filledLoad);\r\n //this.setLoadProgress();\r\n }\r\n\r\n if(!media.paused || media.currentTime > 0) {\r\n this.onPlay();\r\n }\r\n\r\n this.setSeekMax();\r\n this.setListeners();\r\n this.setHandlers({\r\n onMouseDown: () => {\r\n //super.onMouseDown(e);\r\n \r\n //Таймер для того, чтобы стопать видео, если зажал мышку и не отпустил клик\r\n if(this.stopAndScrubTimeout) { // возможно лишнее\r\n clearTimeout(this.stopAndScrubTimeout);\r\n }\r\n \r\n this.stopAndScrubTimeout = window.setTimeout(() => {\r\n !this.media.paused && this.media.pause();\r\n this.stopAndScrubTimeout = 0;\r\n }, 150);\r\n },\r\n\r\n onMouseUp: () => {\r\n //super.onMouseUp(e);\r\n \r\n if(this.stopAndScrubTimeout) {\r\n clearTimeout(this.stopAndScrubTimeout);\r\n this.stopAndScrubTimeout = 0;\r\n }\r\n \r\n this.media.paused && this.media.play();\r\n }\r\n })\r\n }\r\n\r\n onLoadedData = () => {\r\n this.max = this.media.duration;\r\n this.seek.setAttribute('max', '' + this.max);\r\n };\r\n\r\n onEnded = () => {\r\n this.setProgress();\r\n };\r\n\r\n onPlay = () => {\r\n let r = () => {\r\n this.setProgress();\r\n\r\n this.progressRAF = this.media.paused ? 0 : window.requestAnimationFrame(r);\r\n };\r\n\r\n if(this.progressRAF) {\r\n window.cancelAnimationFrame(this.progressRAF);\r\n }\r\n\r\n if(this.streamable) {\r\n this.setLoadProgress();\r\n }\r\n\r\n this.progressRAF = window.requestAnimationFrame(r);\r\n };\r\n\r\n onProgress = (e: Event) => {\r\n this.setLoadProgress();\r\n };\r\n\r\n protected scrub(e: MouseEvent) {\r\n const scrubTime = super.scrub(e);\r\n this.media.currentTime = scrubTime;\r\n return scrubTime;\r\n }\r\n\r\n protected setLoadProgress() {\r\n if(appMediaPlaybackController.isSafariBuffering(this.media)) return;\r\n const buf = this.media.buffered;\r\n const numRanges = buf.length;\r\n\r\n const currentTime = this.media.currentTime;\r\n let nearestStart = 0, end = 0;\r\n for(let i = 0; i < numRanges; ++i) {\r\n const start = buf.start(i);\r\n if(currentTime >= start && start >= nearestStart) {\r\n nearestStart = start;\r\n end = buf.end(i);\r\n }\r\n\r\n //console.log('onProgress range:', i, buf.start(i), buf.end(i), this.media);\r\n }\r\n\r\n //console.log('onProgress correct range:', nearestStart, end, this.media);\r\n\r\n const percents = this.media.duration ? end / this.media.duration : 0;\r\n this.filledLoad.style.width = (percents * 100) + '%';\r\n //this.filledLoad.style.transform = 'scaleX(' + percents + ')';\r\n }\r\n\r\n protected setSeekMax() {\r\n this.max = this.media.duration || 0;\r\n if(this.max > 0) {\r\n this.onLoadedData();\r\n } else {\r\n this.media.addEventListener('loadeddata', this.onLoadedData);\r\n }\r\n }\r\n\r\n public setProgress() {\r\n if(appMediaPlaybackController.isSafariBuffering(this.media)) return;\r\n const currentTime = this.media.currentTime;\r\n\r\n super.setProgress(currentTime);\r\n }\r\n\r\n public setListeners() {\r\n super.setListeners();\r\n this.media.addEventListener('ended', this.onEnded);\r\n this.media.addEventListener('play', this.onPlay);\r\n this.streamable && this.media.addEventListener('progress', this.onProgress);\r\n }\r\n\r\n public removeListeners() {\r\n super.removeListeners();\r\n\r\n this.media.removeEventListener('loadeddata', this.onLoadedData);\r\n this.media.removeEventListener('ended', this.onEnded);\r\n this.media.removeEventListener('play', this.onPlay);\r\n this.streamable && this.media.removeEventListener('progress', this.onProgress);\r\n\r\n if(this.stopAndScrubTimeout) {\r\n clearTimeout(this.stopAndScrubTimeout);\r\n }\r\n\r\n if(this.progressRAF) {\r\n window.cancelAnimationFrame(this.progressRAF);\r\n }\r\n }\r\n}\r\n\r\nlet lastVolume = 1, muted = !lastVolume;\r\nexport default class VideoPlayer {\r\n private wrapper: HTMLDivElement;\r\n private progress: MediaProgressLine;\r\n private skin: string;\r\n\r\n private listenerSetter: ListenerSetter;\r\n\r\n /* private videoParent: HTMLElement;\r\n private videoWhichChild: number; */\r\n\r\n constructor(private video: HTMLVideoElement, play = false, streamable = false, duration?: number) {\r\n this.wrapper = document.createElement('div');\r\n this.wrapper.classList.add('ckin__player');\r\n\r\n this.listenerSetter = new ListenerSetter();\r\n\r\n video.parentNode.insertBefore(this.wrapper, video);\r\n this.wrapper.appendChild(video);\r\n\r\n this.skin = video.dataset.ckin ?? 'default';\r\n\r\n this.stylePlayer(duration);\r\n\r\n if(this.skin === 'default') {\r\n const controls = this.wrapper.querySelector('.default__controls.ckin__controls') as HTMLDivElement;\r\n this.progress = new MediaProgressLine(video, streamable);\r\n controls.prepend(this.progress.container);\r\n }\r\n\r\n if(play/* && video.paused */) {\r\n const promise = video.play();\r\n promise.catch((err: Error) => {\r\n if(err.name === 'NotAllowedError') {\r\n video.muted = true;\r\n video.autoplay = true;\r\n video.play();\r\n }\r\n }).finally(() => { // due to autoplay, play will not call\r\n this.wrapper.classList.toggle('is-playing', !this.video.paused);\r\n });\r\n //(this.wrapper.querySelector('.toggle') as HTMLButtonElement).click();\r\n }\r\n }\r\n\r\n private stylePlayer(initDuration: number) {\r\n const {wrapper: player, video, skin} = this;\r\n\r\n player.classList.add(skin);\r\n \r\n const html = this.buildControls();\r\n player.insertAdjacentHTML('beforeend', html);\r\n let timeDuration: HTMLElement;\r\n \r\n if(skin === 'default') {\r\n const toggle = player.querySelectorAll('.toggle') as NodeListOf<HTMLElement>;\r\n const fullScreenButton = player.querySelector('.fullscreen') as HTMLElement;\r\n const timeElapsed = player.querySelector('#time-elapsed');\r\n timeDuration = player.querySelector('#time-duration') as HTMLElement;\r\n timeDuration.innerHTML = String(video.duration | 0).toHHMMSS();\r\n\r\n const volumeDiv = document.createElement('div');\r\n volumeDiv.classList.add('player-volume');\r\n\r\n volumeDiv.innerHTML = `\r\n <svg class=\"player-volume__icon\" focusable=\"false\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"></svg>\r\n `;\r\n const volumeSvg = volumeDiv.firstElementChild as SVGSVGElement;\r\n\r\n const onMuteClick = (e?: Event) => {\r\n e && cancelEvent(e);\r\n video.muted = !video.muted;\r\n };\r\n\r\n this.listenerSetter.add(volumeSvg)('click', onMuteClick);\r\n\r\n const volumeProgress = new RangeSelector(0.01, 1, 0, 1);\r\n volumeProgress.setListeners();\r\n volumeProgress.setHandlers({\r\n onScrub: currentTime => {\r\n const value = Math.max(Math.min(currentTime, 1), 0);\r\n\r\n //console.log('volume scrub:', currentTime, value);\r\n\r\n video.muted = false;\r\n video.volume = value;\r\n }\r\n });\r\n volumeDiv.append(volumeProgress.container);\r\n\r\n const setVolume = () => {\r\n const volume = video.volume;\r\n let d: string;\r\n if(!volume || video.muted) {\r\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`;\r\n } else if(volume > .5) {\r\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`;\r\n } else if(volume > 0 && volume < .25) {\r\n d = `M7 9v6h4l5 5V4l-5 5H7z`;\r\n } else {\r\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`;\r\n }\r\n\r\n try {\r\n volumeSvg.innerHTML = `<path d=\"${d}\"></path>`;\r\n } catch(err) {}\r\n\r\n if(!volumeProgress.mousedown) {\r\n volumeProgress.setProgress(video.muted ? 0 : volume);\r\n }\r\n };\r\n \r\n // не вызовется повторно если на 1 установить 1\r\n this.listenerSetter.add(video)('volumechange', () => {\r\n muted = video.muted;\r\n lastVolume = video.volume;\r\n setVolume();\r\n });\r\n\r\n video.volume = lastVolume;\r\n video.muted = muted;\r\n\r\n setVolume();\r\n\r\n // volume end\r\n\r\n const leftControls = player.querySelector('.left-controls');\r\n leftControls.insertBefore(volumeDiv, timeElapsed.parentElement);\r\n\r\n Array.from(toggle).forEach((button) => {\r\n this.listenerSetter.add(button)('click', () => {\r\n this.togglePlay();\r\n });\r\n });\r\n\r\n this.listenerSetter.add(video)('click', () => {\r\n if(!isTouchSupported) {\r\n this.togglePlay();\r\n }\r\n });\r\n\r\n let showControlsTimeout = 0;\r\n\r\n const showControls = () => {\r\n if(showControlsTimeout) clearTimeout(showControlsTimeout);\r\n else player.classList.add('show-controls');\r\n\r\n showControlsTimeout = window.setTimeout(() => {\r\n showControlsTimeout = 0;\r\n player.classList.remove('show-controls');\r\n }, 3e3);\r\n };\r\n\r\n if(isTouchSupported) {\r\n this.listenerSetter.add(player)('click', () => {\r\n showControls();\r\n });\r\n\r\n this.listenerSetter.add(player)('touchstart', () => {\r\n player.classList.add('show-controls');\r\n clearTimeout(showControlsTimeout);\r\n });\r\n\r\n this.listenerSetter.add(player)('touchend', () => {\r\n if(player.classList.contains('is-playing')) {\r\n showControls();\r\n }\r\n });\r\n } else {\r\n this.listenerSetter.add(this.wrapper)('mousemove', () => {\r\n showControls();\r\n });\r\n\r\n this.listenerSetter.add(document)('keydown', (e: KeyboardEvent) => {\r\n if(e.code === 'KeyF') {\r\n this.toggleFullScreen(fullScreenButton);\r\n } else if(e.code === 'KeyM') {\r\n onMuteClick();\r\n } else if(e.code === 'Space') {\r\n this.togglePlay();\r\n }\r\n });\r\n }\r\n \r\n /* player.addEventListener('click', (e) => {\r\n if(e.target !== player) {\r\n return;\r\n }\r\n\r\n this.togglePlay();\r\n }); */\r\n \r\n /* video.addEventListener('play', () => {\r\n }); */\r\n\r\n this.listenerSetter.add(video)('dblclick', () => {\r\n if(!isTouchSupported) {\r\n this.toggleFullScreen(fullScreenButton);\r\n }\r\n });\r\n\r\n this.listenerSetter.add(fullScreenButton)('click', (e) => {\r\n this.toggleFullScreen(fullScreenButton);\r\n });\r\n\r\n 'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange'.split(' ').forEach(eventName => {\r\n this.listenerSetter.add(player)(eventName, this.onFullScreen, false);\r\n });\r\n\r\n this.listenerSetter.add(video)('timeupdate', () => {\r\n timeElapsed.innerHTML = String(video.currentTime | 0).toHHMMSS();\r\n });\r\n\r\n this.listenerSetter.add(video)('play', () => {\r\n this.wrapper.classList.add('played');\r\n }, {once: true});\r\n }\r\n\r\n this.listenerSetter.add(video)('play', () => {\r\n this.wrapper.classList.add('is-playing');\r\n });\r\n\r\n this.listenerSetter.add(video)('pause', () => {\r\n this.wrapper.classList.remove('is-playing');\r\n });\r\n \r\n if(video.duration || initDuration) {\r\n timeDuration.innerHTML = String(Math.round(video.duration || initDuration)).toHHMMSS();\r\n } else {\r\n onVideoLoad(video).then(() => {\r\n timeDuration.innerHTML = String(Math.round(video.duration)).toHHMMSS();\r\n });\r\n }\r\n }\r\n\r\n public togglePlay() {\r\n this.video[this.video.paused ? 'play' : 'pause']();\r\n }\r\n\r\n private buildControls() {\r\n const skin = this.skin;\r\n if(skin === 'default') {\r\n return `\r\n <button class=\"${skin}__button--big toggle tgico\" title=\"Toggle Play\"></button>\r\n <div class=\"${skin}__gradient-bottom ckin__controls\"></div>\r\n <div class=\"${skin}__controls ckin__controls\">\r\n <div class=\"bottom-controls\">\r\n <div class=\"left-controls\">\r\n <button class=\"${skin}__button toggle tgico\" title=\"Toggle Video\"></button>\r\n <div class=\"time\">\r\n <time id=\"time-elapsed\">0:00</time>\r\n <span> / </span>\r\n <time id=\"time-duration\">0:00</time>\r\n </div>\r\n </div>\r\n <div class=\"right-controls\">\r\n <button class=\"${skin}__button fullscreen tgico-fullscreen\" title=\"Full Screen\"></button>\r\n </div>\r\n </div>\r\n </div>`;\r\n }\r\n }\r\n\r\n public static isFullScreen(): boolean {\r\n // @ts-ignore\r\n return !!(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement);\r\n }\r\n \r\n public toggleFullScreen(fullScreenButton: HTMLElement) {\r\n // alternative standard method\r\n const player = this.wrapper;\r\n\r\n // * https://caniuse.com/#feat=fullscreen\r\n if(isAppleMobile) {\r\n const video = this.video as any;\r\n video.webkitEnterFullscreen();\r\n video.enterFullscreen();\r\n return;\r\n }\r\n \r\n if(!VideoPlayer.isFullScreen()) {\r\n player.classList.add('ckin__fullscreen');\r\n\r\n /* const videoParent = this.video.parentElement;\r\n const videoWhichChild = whichChild(this.video);\r\n const needVideoRemount = videoParent !== player;\r\n\r\n if(needVideoRemount) {\r\n this.videoParent = videoParent;\r\n this.videoWhichChild = videoWhichChild;\r\n player.prepend(this.video);\r\n } */\r\n \r\n if(player.requestFullscreen) {\r\n player.requestFullscreen();\r\n // @ts-ignore\r\n } else if(player.mozRequestFullScreen) {\r\n // @ts-ignore\r\n player.mozRequestFullScreen(); // Firefox\r\n // @ts-ignore\r\n } else if(player.webkitRequestFullscreen) {\r\n // @ts-ignore\r\n player.webkitRequestFullscreen(); // Chrome and Safari\r\n // @ts-ignore\r\n } else if(player.msRequestFullscreen) {\r\n // @ts-ignore\r\n player.msRequestFullscreen();\r\n }\r\n \r\n fullScreenButton.classList.remove('tgico-fullscreen');\r\n fullScreenButton.classList.add('tgico-smallscreen');\r\n fullScreenButton.setAttribute('title', 'Exit Full Screen');\r\n } else {\r\n player.classList.remove('ckin__fullscreen');\r\n\r\n /* if(this.videoParent) {\r\n const {videoWhichChild, videoParent} = this;\r\n if(!videoWhichChild) {\r\n videoParent.prepend(this.video);\r\n } else {\r\n videoParent.insertBefore(this.video, videoParent.children[videoWhichChild]);\r\n }\r\n\r\n this.videoParent = null;\r\n this.videoWhichChild = -1;\r\n } */\r\n \r\n // @ts-ignore\r\n if(document.cancelFullScreen) {\r\n // @ts-ignore\r\n document.cancelFullScreen();\r\n // @ts-ignore\r\n } else if(document.mozCancelFullScreen) {\r\n // @ts-ignore\r\n document.mozCancelFullScreen();\r\n // @ts-ignore\r\n } else if(document.webkitCancelFullScreen) {\r\n // @ts-ignore\r\n document.webkitCancelFullScreen();\r\n // @ts-ignore\r\n } else if(document.msExitFullscreen) {\r\n // @ts-ignore\r\n document.msExitFullscreen();\r\n }\r\n \r\n fullScreenButton.classList.remove('tgico-smallscreen');\r\n fullScreenButton.classList.add('tgico-fullscreen');\r\n fullScreenButton.setAttribute('title', 'Full Screen');\r\n }\r\n }\r\n \r\n onFullScreen = () => {\r\n // @ts-ignore\r\n const isFullscreenNow = document.webkitFullscreenElement !== null;\r\n if(!isFullscreenNow) {\r\n this.wrapper.classList.remove('ckin__fullscreen');\r\n }\r\n };\r\n\r\n public removeListeners() {\r\n this.listenerSetter.removeAll();\r\n this.progress.removeListeners();\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 appDocsManager, {MyDocument} from \"../lib/appManagers/appDocsManager\";\r\nimport { RichTextProcessor } from \"../lib/richtextprocessor\";\r\nimport { formatDate } from \"./wrappers\";\r\nimport ProgressivePreloader from \"./preloader\";\r\nimport { MediaProgressLine } from \"../lib/mediaPlayer\";\r\nimport appMediaPlaybackController from \"./appMediaPlaybackController\";\r\nimport { DocumentAttribute } from \"../layer\";\r\nimport mediaSizes from \"../helpers/mediaSizes\";\r\nimport { isSafari } from \"../helpers/userAgent\";\r\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport './middleEllipsis';\r\nimport { SearchSuperContext } from \"./appSearchSuper.\";\r\nimport { formatDateAccordingToToday } from \"../helpers/date\";\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent, detachClickEvent } from \"../helpers/dom/clickEvent\";\r\n\r\nrootScope.addEventListener('messages_media_read', e => {\r\n const {mids, peerId} = e;\r\n\r\n mids.forEach(mid => {\r\n (Array.from(document.querySelectorAll('audio-element[message-id=\"' + mid + '\"][peer-id=\"' + peerId + '\"]')) as AudioElement[]).forEach(elem => {\r\n //console.log('updating avatar:', elem);\r\n elem.classList.remove('is-unread');\r\n });\r\n });\r\n});\r\n\r\n// https://github.com/LonamiWebs/Telethon/blob/4393ec0b83d511b6a20d8a20334138730f084375/telethon/utils.py#L1285\r\nexport function decodeWaveform(waveform: Uint8Array | number[]) {\r\n if(!(waveform instanceof Uint8Array)) {\r\n waveform = new Uint8Array(waveform);\r\n }\r\n\r\n const bitCount = waveform.length * 8;\r\n const valueCount = bitCount / 5 | 0;\r\n if(!valueCount) {\r\n return new Uint8Array([]);\r\n }\r\n\r\n let result: Uint8Array;\r\n try {\r\n const dataView = new DataView(waveform.buffer);\r\n result = new Uint8Array(valueCount);\r\n for(let i = 0; i < valueCount; i++) {\r\n const byteIndex = i * 5 / 8 | 0;\r\n const bitShift = i * 5 % 8;\r\n const value = dataView.getUint16(byteIndex, true);\r\n result[i] = (value >> bitShift) & 0b00011111;\r\n }\r\n } catch(err) {\r\n result = new Uint8Array([]);\r\n }\r\n\r\n /* var byteIndex = (valueCount - 1) / 8 | 0;\r\n var bitShift = (valueCount - 1) % 8;\r\n if(byteIndex === waveform.length - 1) {\r\n var value = waveform[byteIndex];\r\n } else {\r\n var value = dataView.getUint16(byteIndex, true);\r\n }\r\n console.log('decoded waveform, setting last value:', value, byteIndex, bitShift);\r\n result[valueCount - 1] = (value >> bitShift) & 0b00011111; */\r\n return result;\r\n}\r\n\r\nfunction wrapVoiceMessage(audioEl: AudioElement) {\r\n audioEl.classList.add('is-voice');\r\n\r\n const message = audioEl.message;\r\n const doc = (message.media.document || message.media.webpage.document) as MyDocument;\r\n const isOut = message.fromId === rootScope.myId && message.peerId !== rootScope.myId;\r\n let isUnread = message && message.pFlags.media_unread;\r\n if(isUnread) {\r\n audioEl.classList.add('is-unread');\r\n }\r\n\r\n if(message.pFlags.out) {\r\n audioEl.classList.add('is-out');\r\n }\r\n\r\n const barWidth = 2;\r\n const barMargin = 2; //mediaSizes.isMobile ? 2 : 1;\r\n const barHeightMin = 4; //mediaSizes.isMobile ? 3 : 2;\r\n const barHeightMax = mediaSizes.isMobile ? 16 : 23;\r\n const availW = 150; //mediaSizes.isMobile ? 152 : 190;\r\n\r\n const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n svg.classList.add('audio-waveform');\r\n svg.setAttributeNS(null, 'width', '' + availW);\r\n svg.setAttributeNS(null, 'height', '' + barHeightMax);\r\n svg.setAttributeNS(null, 'viewBox', `0 0 ${availW} ${barHeightMax}`);\r\n\r\n const timeDiv = document.createElement('div');\r\n timeDiv.classList.add('audio-time');\r\n audioEl.append(svg, timeDiv);\r\n\r\n let waveform = (doc.attributes.find(attribute => attribute._ === 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio).waveform || new Uint8Array([]);\r\n waveform = decodeWaveform(waveform.slice(0, 63));\r\n\r\n //console.log('decoded waveform:', waveform);\r\n\r\n const normValue = Math.max(...waveform);\r\n const wfSize = waveform.length ? waveform.length : 100;\r\n const barCount = Math.min((availW / (barWidth + barMargin)) | 0, wfSize);\r\n\r\n let maxValue = 0;\r\n const maxDelta = barHeightMax - barHeightMin;\r\n\r\n let html = '';\r\n for(let i = 0, barX = 0, sumI = 0; i < wfSize; ++i) {\r\n const value = waveform[i] || 0;\r\n if((sumI + barCount) >= wfSize) { // draw bar\r\n sumI = sumI + barCount - wfSize;\r\n\t\t\tif(sumI < (barCount + 1) / 2) {\r\n\t\t\t\tif(maxValue < value) maxValue = value;\r\n }\r\n \r\n const bar_value = Math.max(((maxValue * maxDelta) + ((normValue + 1) / 2)) / (normValue + 1), barHeightMin);\r\n \r\n const h = `\r\n <rect x=\"${barX}\" y=\"${barHeightMax - bar_value}\" width=\"${barWidth}\" height=\"${bar_value}\" rx=\"1\" ry=\"1\"></rect>\r\n `;\r\n html += h;\r\n\r\n barX += barWidth + barMargin;\r\n\r\n if(sumI < (barCount + 1) / 2) {\r\n maxValue = 0;\r\n } else {\r\n maxValue = value;\r\n }\r\n } else {\r\n if(maxValue < value) maxValue = value;\r\n\r\n sumI += barCount;\r\n }\r\n }\r\n\r\n svg.insertAdjacentHTML('beforeend', html);\r\n const rects = Array.from(svg.children) as HTMLElement[];\r\n\r\n let progress = audioEl.querySelector('.audio-waveform') as HTMLDivElement;\r\n \r\n const onLoad = () => {\r\n let interval = 0;\r\n let lastIndex = 0;\r\n\r\n let audio = audioEl.audio;\r\n\r\n if(!audio.paused || (audio.currentTime > 0 && audio.currentTime !== audio.duration)) {\r\n lastIndex = Math.round(audio.currentTime / audio.duration * barCount);\r\n rects.slice(0, lastIndex + 1).forEach(node => node.classList.add('active'));\r\n }\r\n\r\n let start = () => {\r\n clearInterval(interval);\r\n interval = window.setInterval(() => {\r\n if(lastIndex > svg.childElementCount || isNaN(audio.duration) || audio.paused) {\r\n clearInterval(interval);\r\n return;\r\n }\r\n\r\n lastIndex = Math.round(audio.currentTime / audio.duration * barCount);\r\n \r\n //svg.children[lastIndex].setAttributeNS(null, 'fill', '#000');\r\n //svg.children[lastIndex].classList.add('active'); #Иногда пропускает полоски..\r\n rects.slice(0, lastIndex + 1).forEach(node => node.classList.add('active'));\r\n //++lastIndex;\r\n //console.log('lastIndex:', lastIndex, audio.currentTime);\r\n //}, duration * 1000 / svg.childElementCount | 0/* 63 * duration / 10 */);\r\n }, 20);\r\n };\r\n\r\n if(!audio.paused) {\r\n start();\r\n }\r\n\r\n audioEl.addAudioListener('playing', () => {\r\n if(isUnread && !isOut && audioEl.classList.contains('is-unread')) {\r\n audioEl.classList.remove('is-unread');\r\n appMessagesManager.readMessages(audioEl.message.peerId, [audioEl.message.mid]);\r\n isUnread = false;\r\n }\r\n\r\n //rects.forEach(node => node.classList.remove('active'));\r\n start();\r\n });\r\n\r\n audioEl.addAudioListener('pause', () => {\r\n clearInterval(interval);\r\n });\r\n \r\n audioEl.addAudioListener('ended', () => {\r\n clearInterval(interval);\r\n rects.forEach(node => node.classList.remove('active'));\r\n });\r\n \r\n let mousedown = false, mousemove = false;\r\n progress.addEventListener('mouseleave', (e) => {\r\n if(mousedown) {\r\n audio.play();\r\n mousedown = false;\r\n }\r\n mousemove = false;\r\n })\r\n progress.addEventListener('mousemove', (e) => {\r\n mousemove = true;\r\n if(mousedown) scrub(e);\r\n });\r\n progress.addEventListener('mousedown', (e) => {\r\n e.preventDefault();\r\n if(!audio.paused) {\r\n audio.pause();\r\n }\r\n \r\n scrub(e);\r\n mousedown = true;\r\n });\r\n progress.addEventListener('mouseup', (e) => {\r\n if (mousemove && mousedown) {\r\n audio.play();\r\n mousedown = false;\r\n }\r\n });\r\n attachClickEvent(progress, (e) => {\r\n cancelEvent(e);\r\n if(!audio.paused) scrub(e);\r\n });\r\n \r\n function scrub(e: MouseEvent | TouchEvent) {\r\n let offsetX: number;\r\n if(e instanceof MouseEvent) {\r\n offsetX = e.offsetX;\r\n } else { // touch\r\n const rect = (e.target as HTMLElement).getBoundingClientRect();\r\n offsetX = e.targetTouches[0].pageX - rect.left;\r\n }\r\n \r\n const scrubTime = offsetX / availW /* width */ * audio.duration;\r\n lastIndex = Math.round(scrubTime / audio.duration * barCount);\r\n \r\n rects.slice(0, lastIndex + 1).forEach(node => node.classList.add('active'));\r\n for(let i = lastIndex + 1; i < rects.length; ++i) {\r\n rects[i].classList.remove('active')\r\n }\r\n audio.currentTime = scrubTime;\r\n }\r\n \r\n return () => {\r\n clearInterval(interval);\r\n progress.remove();\r\n progress = null;\r\n audio = null;\r\n };\r\n };\r\n\r\n return onLoad;\r\n}\r\n\r\nfunction wrapAudio(audioEl: AudioElement) {\r\n const withTime = audioEl.withTime;\r\n\r\n const message = audioEl.message;\r\n const doc: MyDocument = message.media.document || message.media.webpage.document;\r\n\r\n const senderTitle = audioEl.showSender ? appMessagesManager.getSenderToPeerText(message) : '';\r\n\r\n let title = doc.type === 'voice' ? senderTitle : (doc.audioTitle || doc.file_name);\r\n let subtitle: string;\r\n \r\n if(doc.type === 'voice') {\r\n subtitle = '';\r\n } else {\r\n subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : '';\r\n if(withTime) {\r\n subtitle += (subtitle ? ' • ' : '') + formatDate(doc.date);\r\n } else if(!subtitle) {\r\n subtitle = 'Unknown Artist';\r\n }\r\n\r\n if(audioEl.showSender) {\r\n subtitle += ' • ' + senderTitle;\r\n } else {\r\n subtitle = ' • ' + subtitle;\r\n }\r\n }\r\n\r\n let titleAdditionHTML = '';\r\n if(audioEl.showSender) {\r\n titleAdditionHTML = `<div class=\"sent-time\">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;\r\n }\r\n\r\n const html = `\r\n <div class=\"audio-details\">\r\n <div class=\"audio-title\"><middle-ellipsis-element data-font-weight=\"${audioEl.dataset.fontWeight}\">${title}</middle-ellipsis-element>${titleAdditionHTML}</div>\r\n <div class=\"audio-subtitle\"><div class=\"audio-time\"></div>${subtitle || '<div></div>'}</div>\r\n </div>`;\r\n \r\n audioEl.insertAdjacentHTML('beforeend', html);\r\n\r\n const onLoad = () => {\r\n const subtitleDiv = audioEl.querySelector('.audio-subtitle') as HTMLDivElement;\r\n let launched = false;\r\n\r\n let progressLine = new MediaProgressLine(audioEl.audio, doc.supportsStreaming);\r\n\r\n audioEl.addAudioListener('ended', () => {\r\n audioEl.classList.remove('audio-show-progress');\r\n // Reset subtitle\r\n subtitleDiv.lastChild.replaceWith(subtitle);\r\n launched = false;\r\n });\r\n\r\n const onPlaying = () => {\r\n if(!launched) {\r\n audioEl.classList.add('audio-show-progress');\r\n launched = true;\r\n\r\n if(progressLine) {\r\n subtitleDiv.lastChild.replaceWith(progressLine.container);\r\n }\r\n }\r\n };\r\n\r\n audioEl.addAudioListener('playing', onPlaying);\r\n\r\n if(!audioEl.audio.paused || audioEl.audio.currentTime > 0) {\r\n onPlaying();\r\n }\r\n\r\n return () => {\r\n progressLine.removeListeners();\r\n progressLine.container.remove();\r\n progressLine = null;\r\n };\r\n };\r\n\r\n return onLoad;\r\n}\r\n\r\nexport default class AudioElement extends HTMLElement {\r\n public audio: HTMLAudioElement;\r\n public preloader: ProgressivePreloader;\r\n public message: any;\r\n public withTime = false;\r\n public voiceAsMusic = false;\r\n public searchContext: SearchSuperContext;\r\n public showSender = false;\r\n public noAutoDownload: boolean;\r\n\r\n private attachedHandlers: {[name: string]: any[]} = {};\r\n private onTypeDisconnect: () => void;\r\n public onLoad: (autoload?: boolean) => void;\r\n\r\n constructor() {\r\n super();\r\n // элемент создан\r\n }\r\n\r\n public render() {\r\n this.classList.add('audio');\r\n\r\n const doc = this.message.media.document || this.message.media.webpage.document;\r\n const isRealVoice = doc.type === 'voice';\r\n const isVoice = !this.voiceAsMusic && isRealVoice;\r\n const isOutgoing = this.message.pFlags.is_outgoing;\r\n const uploading = isOutgoing && this.preloader;\r\n\r\n const durationStr = String(doc.duration | 0).toHHMMSS();\r\n\r\n this.innerHTML = `<div class=\"audio-toggle audio-ico\"> \r\n <div class=\"part one\" x=\"0\" y=\"0\" fill=\"#fff\"></div>\r\n <div class=\"part two\" x=\"0\" y=\"0\" fill=\"#fff\"></div>\r\n </div>`;\r\n\r\n const downloadDiv = document.createElement('div');\r\n downloadDiv.classList.add('audio-download');\r\n\r\n if(uploading) {\r\n this.append(downloadDiv);\r\n }\r\n\r\n const onTypeLoad = isVoice ? wrapVoiceMessage(this) : wrapAudio(this);\r\n \r\n const audioTimeDiv = this.querySelector('.audio-time') as HTMLDivElement;\r\n audioTimeDiv.innerHTML = durationStr;\r\n\r\n const onLoad = this.onLoad = (autoload = true) => {\r\n this.onLoad = undefined;\r\n\r\n const audio = this.audio = appMediaPlaybackController.addMedia(this.message.peerId, this.message.media.document || this.message.media.webpage.document, this.message.mid, autoload);\r\n\r\n this.onTypeDisconnect = onTypeLoad();\r\n \r\n const toggle = this.querySelector('.audio-toggle') as HTMLDivElement;\r\n\r\n const getTimeStr = () => String(audio.currentTime | 0).toHHMMSS() + (isVoice ? (' / ' + durationStr) : '');\r\n\r\n const onPlaying = () => {\r\n audioTimeDiv.innerText = getTimeStr();\r\n toggle.classList.toggle('playing', !audio.paused);\r\n };\r\n\r\n if(!audio.paused || (audio.currentTime > 0 && audio.currentTime !== audio.duration)) {\r\n onPlaying();\r\n }\r\n\r\n attachClickEvent(toggle, (e) => {\r\n cancelEvent(e);\r\n if(audio.paused) audio.play().catch(() => {});\r\n else audio.pause();\r\n });\r\n\r\n this.addAudioListener('ended', () => {\r\n toggle.classList.remove('playing');\r\n });\r\n\r\n this.addAudioListener('timeupdate', () => {\r\n if(appMediaPlaybackController.isSafariBuffering(audio)) return;\r\n audioTimeDiv.innerText = getTimeStr();\r\n });\r\n\r\n this.addAudioListener('pause', () => {\r\n toggle.classList.remove('playing');\r\n });\r\n\r\n this.addAudioListener('playing', onPlaying);\r\n };\r\n\r\n if(!isOutgoing) {\r\n let preloader: ProgressivePreloader = this.preloader;\r\n\r\n const getDownloadPromise = () => appDocsManager.downloadDoc(doc);\r\n\r\n if(isRealVoice) {\r\n if(!preloader) {\r\n preloader = new ProgressivePreloader({\r\n cancelable: true\r\n });\r\n }\r\n\r\n const load = () => {\r\n const download = getDownloadPromise();\r\n preloader.attach(downloadDiv, false, download);\r\n\r\n if(!downloadDiv.parentElement) {\r\n this.append(downloadDiv);\r\n }\r\n\r\n (download as Promise<any>).then(() => {\r\n detachClickEvent(this, onClick);\r\n onLoad();\r\n\r\n downloadDiv.classList.add('downloaded');\r\n setTimeout(() => {\r\n downloadDiv.remove();\r\n }, 200);\r\n });\r\n\r\n return {download};\r\n };\r\n\r\n preloader.construct();\r\n preloader.setManual();\r\n preloader.attach(downloadDiv);\r\n preloader.setDownloadFunction(load);\r\n\r\n const onClick = (e?: Event) => {\r\n preloader.onClick(e);\r\n };\r\n \r\n attachClickEvent(this, onClick);\r\n\r\n if(!this.noAutoDownload) {\r\n onClick();\r\n }\r\n } else {\r\n if(doc.supportsStreaming) {\r\n onLoad(false);\r\n }\r\n\r\n //if(appMediaPlaybackController.mediaExists(mid)) { // чтобы показать прогресс, если аудио уже было скачано\r\n //onLoad();\r\n //} else {\r\n const r = (e: Event) => {\r\n if(!this.audio) {\r\n onLoad(false);\r\n }\r\n\r\n if(this.audio.src) {\r\n return;\r\n }\r\n //onLoad();\r\n //cancelEvent(e);\r\n appMediaPlaybackController.resolveWaitingForLoadMedia(this.message.peerId, this.message.mid);\r\n \r\n appMediaPlaybackController.willBePlayed(this.audio); // prepare for loading audio\r\n \r\n if(!preloader) {\r\n if(doc.supportsStreaming) {\r\n preloader = new ProgressivePreloader({\r\n cancelable: false\r\n });\r\n\r\n preloader.attach(downloadDiv, false);\r\n } else {\r\n preloader = new ProgressivePreloader({\r\n cancelable: true\r\n });\r\n\r\n const load = () => {\r\n const download = getDownloadPromise();\r\n preloader.attach(downloadDiv, false, download);\r\n return {download};\r\n };\r\n\r\n preloader.setDownloadFunction(load);\r\n load();\r\n }\r\n }\r\n\r\n if(isSafari) {\r\n this.audio.autoplay = true;\r\n this.audio.play().catch(() => {});\r\n }\r\n\r\n this.append(downloadDiv);\r\n \r\n new Promise<void>((resolve) => {\r\n if(this.audio.readyState >= 2) resolve();\r\n else this.addAudioListener('canplay', resolve);\r\n }).then(() => {\r\n downloadDiv.classList.add('downloaded');\r\n setTimeout(() => {\r\n downloadDiv.remove();\r\n }, 200);\r\n \r\n //setTimeout(() => {\r\n // release loaded audio\r\n if(appMediaPlaybackController.willBePlayedMedia === this.audio) {\r\n this.audio.play();\r\n appMediaPlaybackController.willBePlayedMedia = null;\r\n }\r\n //}, 10e3);\r\n });\r\n };\r\n\r\n if(!this.audio?.src) {\r\n attachClickEvent(this, r, {once: true, capture: true, passive: false});\r\n }\r\n //}\r\n }\r\n } else if(uploading) {\r\n this.preloader.attach(downloadDiv, false);\r\n //onLoad();\r\n }\r\n }\r\n\r\n /* connectedCallback() {\r\n // браузер вызывает этот метод при добавлении элемента в документ\r\n // (может вызываться много раз, если элемент многократно добавляется/удаляется)\r\n } */\r\n\r\n public addAudioListener(name: string, callback: any) {\r\n if(!this.attachedHandlers[name]) this.attachedHandlers[name] = [];\r\n this.attachedHandlers[name].push(callback);\r\n this.audio.addEventListener(name, callback);\r\n }\r\n\r\n disconnectedCallback() {\r\n if(this.isConnected) {\r\n return;\r\n }\r\n \r\n // браузер вызывает этот метод при удалении элемента из документа\r\n // (может вызываться много раз, если элемент многократно добавляется/удаляется)\r\n if(this.onTypeDisconnect) {\r\n this.onTypeDisconnect();\r\n this.onTypeDisconnect = null;\r\n }\r\n\r\n for(let name in this.attachedHandlers) {\r\n for(let callback of this.attachedHandlers[name]) {\r\n this.audio.removeEventListener(name, callback);\r\n }\r\n \r\n delete this.attachedHandlers[name];\r\n }\r\n\r\n this.preloader = null;\r\n }\r\n}\r\n\r\ncustomElements.define(\"audio-element\", AudioElement);\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 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 renderImageFromUrl from \"../../helpers/dom/renderImageFromUrl\";\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\nimport { limitSymbols } from \"../../helpers/string\";\r\nimport appDownloadManager from \"../../lib/appManagers/appDownloadManager\";\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 { wrapSticker } from \"../wrappers\";\r\n\r\nexport function wrapReplyDivAndCaption(options: {\r\n title: string | HTMLElement,\r\n titleEl: HTMLElement,\r\n subtitle: string | HTMLElement,\r\n subtitleEl: HTMLElement,\r\n message: any,\r\n mediaEl: HTMLElement\r\n}) {\r\n let {title, titleEl, subtitle, subtitleEl, mediaEl, message} = 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 let media = message && message.media;\r\n let setMedia = false;\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'].indexOf(media.document.type) !== -1)) {\r\n /* const middlewareOriginal = appImManager.chat.bubbles.getMiddleware();\r\n const middleware = () => {\r\n \r\n }; */\r\n\r\n const boxSize = 32;\r\n if(media.document?.type === 'sticker') {\r\n if(mediaEl.style.backgroundImage) {\r\n mediaEl.style.backgroundImage = ''; \r\n }\r\n\r\n setMedia = true;\r\n wrapSticker({\r\n doc: media.document,\r\n div: mediaEl,\r\n lazyLoadQueue: appImManager.chat.bubbles.lazyLoadQueue,\r\n group: CHAT_ANIMATION_GROUP,\r\n //onlyThumb: media.document.sticker === 2,\r\n width: boxSize,\r\n height: boxSize\r\n });\r\n } else {\r\n if(mediaEl.firstElementChild) {\r\n mediaEl.innerHTML = '';\r\n }\r\n\r\n const photo = media.photo || media.document;\r\n\r\n const size = appPhotosManager.choosePhotoSize(photo, boxSize, boxSize/* mediaSizes.active.regular.width, mediaSizes.active.regular.height */);\r\n const cacheContext = appDownloadManager.getCacheContext(photo, size.type);\r\n\r\n if(!cacheContext.downloaded) {\r\n const sizes = photo.sizes || photo.thumbs;\r\n if(sizes && sizes[0].bytes) {\r\n setMedia = true;\r\n renderImageFromUrl(mediaEl, appPhotosManager.getPreviewURLFromThumb(photo, sizes[0]));\r\n }\r\n }\r\n\r\n if(size._ !== 'photoSizeEmpty') {\r\n setMedia = true;\r\n appPhotosManager.preloadPhoto(photo, size)\r\n .then(() => {\r\n renderImageFromUrl(mediaEl, cacheContext.url);\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 if(typeof(subtitle) === 'string') {\r\n subtitle = limitSymbols(subtitle, 140);\r\n subtitle = RichTextProcessor.wrapEmojiText(subtitle);\r\n replaceContent(subtitleEl, subtitle);\r\n }\r\n }\r\n \r\n return setMedia;\r\n}\r\n\r\nexport default class ReplyContainer extends DivAndCaption<(title: string | HTMLElement, subtitle: string | HTMLElement, message?: any) => void> {\r\n private mediaEl: HTMLElement;\r\n\r\n constructor(protected className: string) {\r\n super(className, (title: string | HTMLElement, subtitle: string | HTMLElement = '', message?: any) => {\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 constructor(options: {\r\n peerId: number,\r\n inputFields: EditPeer['inputFields'],\r\n listenerSetter: ListenerSetter,\r\n doNotEditAvatar?: boolean,\r\n }) {\r\n safeAssign(this, options);\r\n\r\n this.nextBtn = ButtonCorner({icon: 'check'});\r\n\r\n this.avatarElem = document.createElement('avatar-element') as AvatarElement;\r\n this.avatarElem.classList.add('avatar-placeholder', 'avatar-120');\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 this.inputFields.forEach(inputField => {\r\n this.listenerSetter.add(inputField.input)('input', this.handleChange);\r\n });\r\n }\r\n\r\n public isChanged = () => {\r\n return !!this.uploadAvatar || !!this.inputFields.find(inputField => inputField.isValid());\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\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,\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 }> = {}) {\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 this.subtitle.innerHTML = options.subtitle;\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 ripple(this.container, undefined, undefined, true);\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","/*\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\";\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","/*\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 AvatarElement from \"../avatar\";\r\nimport PopupElement, { addCancelButton, PopupButton, PopupOptions } from \".\";\r\nimport { i18n, LangPackKey } from \"../../lib/langPack\";\r\nimport CheckboxField, { CheckboxFieldOptions } from \"../checkboxField\";\r\n\r\nexport type PopupPeerButtonCallbackCheckboxes = Set<LangPackKey>;\r\nexport type PopupPeerButtonCallback = (checkboxes?: PopupPeerButtonCallbackCheckboxes) => void;\r\nexport type PopupPeerCheckboxOptions = CheckboxFieldOptions & {checkboxField?: CheckboxField};\r\n\r\nexport type PopupPeerOptions = PopupOptions & Partial<{\r\n peerId: number,\r\n title: string,\r\n titleLangKey?: LangPackKey,\r\n titleLangArgs?: any[],\r\n description: string,\r\n descriptionLangKey?: LangPackKey,\r\n descriptionLangArgs?: any[],\r\n buttons: Array<Omit<PopupButton, 'callback'> & Partial<{callback: PopupPeerButtonCallback}>>,\r\n checkboxes: Array<PopupPeerCheckboxOptions>\r\n}>;\r\nexport default class PopupPeer extends PopupElement {\r\n constructor(private className: string, options: PopupPeerOptions = {}) {\r\n super('popup-peer' + (className ? ' ' + className : ''), addCancelButton(options.buttons), {overlayClosable: true, ...options});\r\n\r\n if(options.peerId) {\r\n let avatarEl = new AvatarElement();\r\n avatarEl.setAttribute('dialog', '1');\r\n avatarEl.setAttribute('peer', '' + options.peerId);\r\n avatarEl.classList.add('avatar-32');\r\n this.header.prepend(avatarEl);\r\n }\r\n\r\n if(options.titleLangKey || !options.title) this.title.append(i18n(options.titleLangKey || 'AppName', options.titleLangArgs));\r\n else this.title.innerText = options.title || '';\r\n\r\n let p = document.createElement('p');\r\n p.classList.add('popup-description');\r\n if(options.descriptionLangKey) p.append(i18n(options.descriptionLangKey, options.descriptionLangArgs));\r\n else p.innerHTML = options.description;\r\n\r\n const fragment = document.createDocumentFragment();\r\n fragment.append(p);\r\n\r\n if(options.checkboxes) {\r\n this.container.classList.add('have-checkbox');\r\n \r\n options.checkboxes.forEach(o => {\r\n o.withRipple = true;\r\n const checkboxField = new CheckboxField(o);\r\n o.checkboxField = checkboxField;\r\n fragment.append(checkboxField.label);\r\n });\r\n\r\n options.buttons.forEach(button => {\r\n if(button.callback) {\r\n const original = button.callback;\r\n button.callback = () => {\r\n const c: Set<LangPackKey> = new Set();\r\n options.checkboxes.forEach(o => {\r\n if(o.checkboxField.checked) {\r\n c.add(o.text);\r\n }\r\n });\r\n original(c);\r\n };\r\n }\r\n });\r\n }\r\n\r\n this.container.insertBefore(fragment, this.header.nextElementSibling);\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 { 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","/*\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 appChatsManager, { ChatRights } from \"../lib/appManagers/appChatsManager\";\r\nimport appDialogsManager from \"../lib/appManagers/appDialogsManager\";\r\nimport appMessagesManager, { Dialog } from \"../lib/appManagers/appMessagesManager\";\r\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\r\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport Scrollable from \"./scrollable\";\r\nimport { FocusDirection } from \"../helpers/fastSmoothScroll\";\r\nimport CheckboxField from \"./checkboxField\";\r\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\r\nimport { safeAssign } from \"../helpers/object\";\r\nimport { i18n, LangPackKey, _i18n } from \"../lib/langPack\";\r\nimport findUpAttribute from \"../helpers/dom/findUpAttribute\";\r\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\r\nimport PeerTitle from \"./peerTitle\";\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport { filterUnique } from \"../helpers/array\";\r\nimport debounce from \"../helpers/schedulers/debounce\";\r\n\r\ntype PeerType = 'contacts' | 'dialogs' | 'channelParticipants';\r\n\r\n// TODO: правильная сортировка для addMembers, т.е. для peerType: 'contacts', потому что там идут сначала контакты - потом неконтакты, а должно всё сортироваться по имени\r\n\r\nlet loadedAllDialogs = false, loadAllDialogsPromise: Promise<any>;\r\nexport default class AppSelectPeers {\r\n public container = document.createElement('div');\r\n public list = appDialogsManager.createChatList(/* {\r\n handheldsSize: 66,\r\n avatarSize: 48\r\n } */);\r\n public chatsContainer = document.createElement('div');\r\n public scrollable: Scrollable;\r\n public selectedScrollable: Scrollable;\r\n \r\n public selectedContainer: HTMLElement;\r\n public input: HTMLInputElement;\r\n \r\n //public selected: {[peerId: number]: HTMLElement} = {};\r\n public selected = new Set<any>();\r\n\r\n public freezed = false;\r\n\r\n private folderId = 0;\r\n private offsetIndex = 0;\r\n private promise: Promise<any>;\r\n\r\n private query = '';\r\n private cachedContacts: number[];\r\n\r\n private loadedWhat: Partial<{[k in 'dialogs' | 'archived' | 'contacts' | 'channelParticipants']: true}> = {};\r\n\r\n private renderedPeerIds: Set<number> = new Set();\r\n\r\n private appendTo: HTMLElement;\r\n private onChange: (length: number) => void;\r\n private peerType: PeerType[] = ['dialogs'];\r\n private renderResultsFunc: (peerIds: number[]) => void;\r\n private chatRightsAction: ChatRights;\r\n private multiSelect = true;\r\n private rippleEnabled = true;\r\n private avatarSize = 48;\r\n\r\n private tempIds: {[k in keyof AppSelectPeers['loadedWhat']]: number} = {};\r\n private peerId = 0;\r\n\r\n private placeholder: LangPackKey;\r\n\r\n private selfPresence: LangPackKey = 'Presence.YourChat';\r\n \r\n private needSwitchList = false;\r\n \r\n constructor(options: {\r\n appendTo: AppSelectPeers['appendTo'], \r\n onChange?: AppSelectPeers['onChange'], \r\n peerType?: AppSelectPeers['peerType'], \r\n peerId?: number,\r\n onFirstRender?: () => void, \r\n renderResultsFunc?: AppSelectPeers['renderResultsFunc'], \r\n chatRightsAction?: AppSelectPeers['chatRightsAction'], \r\n multiSelect?: AppSelectPeers['multiSelect'],\r\n rippleEnabled?: boolean,\r\n avatarSize?: AppSelectPeers['avatarSize'],\r\n placeholder?: LangPackKey,\r\n selfPresence?: LangPackKey\r\n }) {\r\n safeAssign(this, options);\r\n\r\n this.container.classList.add('selector');\r\n\r\n const f = (this.renderResultsFunc || this.renderResults).bind(this);\r\n this.renderResultsFunc = (peerIds: number[]) => {\r\n if(this.needSwitchList) {\r\n this.scrollable.splitUp.replaceWith(this.list);\r\n this.scrollable.setVirtualContainer(this.list);\r\n this.needSwitchList = false;\r\n }\r\n \r\n peerIds = peerIds.filter(peerId => {\r\n const notRendered = !this.renderedPeerIds.has(peerId);\r\n if(notRendered) this.renderedPeerIds.add(peerId);\r\n return notRendered;\r\n });\r\n\r\n return f(peerIds);\r\n };\r\n\r\n this.input = document.createElement('input');\r\n this.input.classList.add('selector-search-input');\r\n if(this.placeholder) {\r\n _i18n(this.input, this.placeholder, undefined, 'placeholder');\r\n } else {\r\n _i18n(this.input, 'SendMessageTo', undefined, 'placeholder');\r\n }\r\n\r\n this.input.type = 'text';\r\n\r\n if(this.multiSelect) {\r\n let topContainer = document.createElement('div');\r\n topContainer.classList.add('selector-search-container');\r\n \r\n this.selectedContainer = document.createElement('div');\r\n this.selectedContainer.classList.add('selector-search');\r\n \r\n this.selectedContainer.append(this.input);\r\n topContainer.append(this.selectedContainer);\r\n this.selectedScrollable = new Scrollable(topContainer);\r\n \r\n let delimiter = document.createElement('hr');\r\n\r\n this.selectedContainer.addEventListener('click', (e) => {\r\n if(this.freezed) return;\r\n let target = e.target as HTMLElement;\r\n target = findUpClassName(target, 'selector-user');\r\n \r\n if(!target) return;\r\n \r\n const peerId = target.dataset.key;\r\n const li = this.chatsContainer.querySelector('[data-peer-id=\"' + peerId + '\"]') as HTMLElement;\r\n if(!li) {\r\n this.remove(+peerId || peerId);\r\n } else {\r\n li.click();\r\n }\r\n });\r\n\r\n this.container.append(topContainer, delimiter);\r\n }\r\n\r\n this.chatsContainer.classList.add('chatlist-container');\r\n this.chatsContainer.append(this.list);\r\n this.scrollable = new Scrollable(this.chatsContainer);\r\n this.scrollable.setVirtualContainer(this.list);\r\n\r\n this.chatsContainer.addEventListener('click', (e) => {\r\n const target = findUpAttribute(e.target, 'data-peer-id') as HTMLElement;\r\n cancelEvent(e);\r\n\r\n if(!target) return;\r\n if(this.freezed) return;\r\n\r\n let key: any = target.dataset.peerId;\r\n key = +key || key;\r\n\r\n if(!this.multiSelect) {\r\n this.add(key);\r\n return;\r\n }\r\n\r\n //target.classList.toggle('active');\r\n if(this.selected.has(key)) {\r\n this.remove(key);\r\n } else {\r\n this.add(key);\r\n }\r\n\r\n const checkbox = target.querySelector('input') as HTMLInputElement;\r\n checkbox.checked = !checkbox.checked;\r\n });\r\n\r\n const debouncedInput = debounce(this.onInput, 200, false, true);\r\n this.input.addEventListener('input', debouncedInput);\r\n\r\n this.scrollable.onScrolledBottom = () => {\r\n this.getMoreResults();\r\n };\r\n\r\n this.container.append(this.chatsContainer);\r\n this.appendTo.append(this.container);\r\n\r\n // WARNING TIMEOUT\r\n setTimeout(() => {\r\n let getResultsPromise = this.getMoreResults() as Promise<any>;\r\n if(options.onFirstRender) {\r\n getResultsPromise.then(() => {\r\n options.onFirstRender();\r\n });\r\n }\r\n }, 0);\r\n }\r\n\r\n private onInput = () => {\r\n const value = this.input.value;\r\n if(this.query !== value) {\r\n if(this.peerType.includes('contacts')) {\r\n this.cachedContacts = null;\r\n }\r\n \r\n if(this.peerType.includes('dialogs')) {\r\n this.folderId = 0;\r\n this.offsetIndex = 0;\r\n }\r\n\r\n for(let i in this.tempIds) {\r\n // @ts-ignore\r\n ++this.tempIds[i];\r\n }\r\n\r\n this.list = appDialogsManager.createChatList();\r\n\r\n this.promise = null;\r\n this.loadedWhat = {};\r\n this.query = value;\r\n this.renderedPeerIds.clear();\r\n this.needSwitchList = true;\r\n \r\n //console.log('selectPeers input:', this.query);\r\n this.getMoreResults();\r\n }\r\n };\r\n\r\n private renderSaved() {\r\n if(!this.offsetIndex && this.folderId === 0 && this.peerType.includes('dialogs') && (!this.query || appUsersManager.testSelfSearch(this.query))) {\r\n this.renderResultsFunc([rootScope.myId]);\r\n }\r\n }\r\n\r\n private getTempId(type: keyof AppSelectPeers['tempIds']) {\r\n if(this.tempIds[type] === undefined) {\r\n this.tempIds[type] = 0;\r\n }\r\n\r\n return ++this.tempIds[type];\r\n }\r\n\r\n private async getMoreDialogs(): Promise<any> {\r\n if(this.promise) return this.promise;\r\n\r\n if(this.loadedWhat.dialogs && this.loadedWhat.archived) {\r\n return;\r\n }\r\n \r\n // в десктопе - сначала без группы, потом архивные, потом контакты без сообщений\r\n const pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;\r\n\r\n const tempId = this.getTempId('dialogs');\r\n const promise = appMessagesManager.getConversations(this.query, this.offsetIndex, pageCount, this.folderId);\r\n this.promise = promise;\r\n const value = await promise;\r\n if(this.tempIds.dialogs !== tempId) {\r\n return;\r\n }\r\n\r\n this.promise = null;\r\n\r\n let dialogs = value.dialogs as Dialog[];\r\n if(dialogs.length) {\r\n const newOffsetIndex = dialogs[dialogs.length - 1].index || 0;\r\n\r\n dialogs = dialogs.slice();\r\n dialogs.findAndSplice(d => d.peerId === rootScope.myId); // no my account\r\n\r\n if(this.chatRightsAction) {\r\n dialogs = dialogs.filter(d => this.filterByRights(d.peerId));\r\n }\r\n\r\n this.renderSaved();\r\n\r\n this.offsetIndex = newOffsetIndex;\r\n\r\n this.renderResultsFunc(dialogs.map(dialog => dialog.peerId));\r\n }\r\n \r\n if(value.isEnd) {\r\n if(!this.loadedWhat.dialogs) {\r\n this.renderSaved();\r\n\r\n this.loadedWhat.dialogs = true;\r\n this.offsetIndex = 0;\r\n this.folderId = 1;\r\n\r\n return this.getMoreDialogs();\r\n } else {\r\n this.loadedWhat.archived = true;\r\n\r\n if(!this.loadedWhat.contacts && this.peerType.includes('contacts')) {\r\n return this.getMoreContacts();\r\n }\r\n }\r\n }\r\n }\r\n\r\n private filterByRights(peerId: number) {\r\n return (\r\n peerId > 0 && \r\n (this.chatRightsAction !== 'send_messages' || appUsersManager.canSendToUser(peerId))\r\n ) || appChatsManager.hasRights(-peerId, this.chatRightsAction);\r\n }\r\n\r\n private async getMoreContacts() {\r\n if(this.promise) return this.promise;\r\n\r\n if(this.loadedWhat.contacts) {\r\n return;\r\n }\r\n\r\n if(!this.cachedContacts) {\r\n /* const promises: Promise<any>[] = [appUsersManager.getContacts(this.query)];\r\n if(!this.peerType.includes('dialogs')) {\r\n promises.push(appMessagesManager.getConversationsAll());\r\n }\r\n\r\n this.promise = Promise.all(promises);\r\n this.cachedContacts = (await this.promise)[0].slice(); */\r\n const tempId = this.getTempId('contacts');\r\n const promise = Promise.all([\r\n appUsersManager.getContacts(this.query),\r\n this.query ? appUsersManager.searchContacts(this.query) : undefined\r\n ]);\r\n\r\n this.promise = promise;\r\n const [cachedContacts, searchResult] = await promise;\r\n if(this.tempIds.contacts !== tempId) {\r\n return;\r\n }\r\n\r\n if(searchResult) {\r\n let resultPeerIds = searchResult.my_results.concat(searchResult.results);\r\n\r\n if(this.chatRightsAction) {\r\n resultPeerIds = resultPeerIds.filter(peerId => this.filterByRights(peerId));\r\n }\r\n\r\n if(!this.peerType.includes('dialogs')) {\r\n resultPeerIds = resultPeerIds.filter(peerId => peerId > 0);\r\n }\r\n\r\n this.cachedContacts = filterUnique(cachedContacts.concat(resultPeerIds));\r\n } else this.cachedContacts = cachedContacts.slice();\r\n\r\n this.cachedContacts.findAndSplice(userId => userId === rootScope.myId); // no my account\r\n this.promise = null;\r\n }\r\n\r\n if(this.cachedContacts.length) {\r\n const pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;\r\n const arr = this.cachedContacts.splice(0, pageCount);\r\n this.renderResultsFunc(arr);\r\n }\r\n \r\n if(!this.cachedContacts.length) {\r\n this.loadedWhat.contacts = true;\r\n\r\n // need to load non-contacts\r\n /* if(!this.peerType.includes('dialogs')) {\r\n return this.getMoreDialogs();\r\n } */\r\n }\r\n }\r\n\r\n private async getMoreChannelParticipants() {\r\n if(this.promise) return this.promise;\r\n\r\n if(this.loadedWhat.channelParticipants) {\r\n return;\r\n }\r\n\r\n const pageCount = 50; // same as in group permissions to use cache\r\n\r\n const tempId = this.getTempId('channelParticipants');\r\n const promise = appProfileManager.getChannelParticipants(-this.peerId, {_: 'channelParticipantsSearch', q: this.query}, pageCount, this.list.childElementCount);\r\n const participants = await promise;\r\n if(this.tempIds.channelParticipants !== tempId) {\r\n return;\r\n }\r\n \r\n const peerIds = participants.participants.map(participant => {\r\n return appChatsManager.getParticipantPeerId(participant);\r\n });\r\n peerIds.findAndSplice(u => u === rootScope.myId);\r\n this.renderResultsFunc(peerIds);\r\n\r\n if(this.list.childElementCount >= participants.count || participants.participants.length < pageCount) {\r\n this.loadedWhat.channelParticipants = true;\r\n }\r\n }\r\n\r\n checkForTriggers = () => {\r\n this.scrollable.checkForTriggers();\r\n };\r\n\r\n private getMoreResults() {\r\n const get = () => {\r\n const promises: Promise<any>[] = [];\r\n\r\n if(!loadedAllDialogs && (this.peerType.includes('dialogs')/* || this.peerType.includes('contacts') */)) {\r\n if(!loadAllDialogsPromise) {\r\n loadAllDialogsPromise = appMessagesManager.getConversationsAll()\r\n .then(() => {\r\n loadedAllDialogs = true;\r\n }).finally(() => {\r\n loadAllDialogsPromise = null;\r\n });\r\n }\r\n\r\n promises.push(loadAllDialogsPromise);\r\n }\r\n \r\n if((this.peerType.includes('dialogs')/* || this.loadedWhat.contacts */) && !this.loadedWhat.archived) { // to load non-contacts\r\n promises.push(this.getMoreDialogs());\r\n \r\n if(!this.loadedWhat.archived) {\r\n return promises;\r\n }\r\n }\r\n \r\n if(this.peerType.includes('contacts') && !this.loadedWhat.contacts) {\r\n promises.push(this.getMoreContacts());\r\n }\r\n\r\n if(this.peerType.includes('channelParticipants') && !this.loadedWhat.channelParticipants) {\r\n promises.push(this.getMoreChannelParticipants());\r\n }\r\n \r\n return promises;\r\n };\r\n \r\n const promises = get();\r\n const promise = Promise.all(promises);\r\n if(promises.length) {\r\n promise.then(this.checkForTriggers);\r\n }\r\n\r\n return promise;\r\n }\r\n\r\n private renderResults(peerIds: number[]) {\r\n //console.log('will renderResults:', peerIds);\r\n\r\n // оставим только неконтакты с диалогов\r\n if(!this.peerType.includes('dialogs') && this.loadedWhat.contacts) {\r\n peerIds = peerIds.filter(peerId => {\r\n return appUsersManager.isNonContactUser(peerId);\r\n });\r\n }\r\n\r\n peerIds.forEach(peerId => {\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId,\r\n container: this.scrollable,\r\n drawStatus: false,\r\n rippleEnabled: this.rippleEnabled,\r\n avatarSize: this.avatarSize\r\n });\r\n\r\n if(this.multiSelect) {\r\n const selected = this.selected.has(peerId);\r\n const checkboxField = new CheckboxField();\r\n\r\n if(selected) {\r\n //dom.listEl.classList.add('active');\r\n checkboxField.input.checked = true;\r\n }\r\n\r\n dom.containerEl.prepend(checkboxField.label);\r\n }\r\n\r\n let subtitleEl: HTMLElement;\r\n if(peerId < 0) {\r\n subtitleEl = appProfileManager.getChatMembersString(-peerId);\r\n } else if(peerId === rootScope.myId) {\r\n subtitleEl = i18n(this.selfPresence);\r\n } else {\r\n subtitleEl = appUsersManager.getUserStatusString(peerId);\r\n }\r\n\r\n dom.lastMessageSpan.append(subtitleEl);\r\n });\r\n }\r\n\r\n public add(peerId: any, title?: string | HTMLElement, scroll = true) {\r\n //console.trace('add');\r\n this.selected.add(peerId);\r\n\r\n if(!this.multiSelect) {\r\n this.onChange(this.selected.size);\r\n return;\r\n }\r\n\r\n if(this.query.trim()) {\r\n this.input.value = '';\r\n this.onInput();\r\n }\r\n\r\n const div = document.createElement('div');\r\n div.classList.add('selector-user', 'scale-in');\r\n\r\n const avatarEl = document.createElement('avatar-element');\r\n avatarEl.classList.add('selector-user-avatar', 'tgico');\r\n avatarEl.setAttribute('dialog', '1');\r\n avatarEl.classList.add('avatar-32');\r\n\r\n div.dataset.key = '' + peerId;\r\n if(typeof(peerId) === 'number') {\r\n if(title === undefined) {\r\n title = new PeerTitle({peerId, onlyFirstName: true, dialog: true}).element;\r\n }\r\n\r\n avatarEl.setAttribute('peer', '' + peerId);\r\n }\r\n\r\n if(title) {\r\n if(typeof(title) === 'string') {\r\n div.innerHTML = title;\r\n } else {\r\n replaceContent(div, title);\r\n div.append(title);\r\n }\r\n }\r\n\r\n div.insertAdjacentElement('afterbegin', avatarEl);\r\n\r\n this.selectedContainer.insertBefore(div, this.input);\r\n //this.selectedScrollable.scrollTop = this.selectedScrollable.scrollHeight;\r\n this.onChange && this.onChange(this.selected.size);\r\n \r\n if(scroll) {\r\n this.selectedScrollable.scrollIntoViewNew(this.input, 'center');\r\n }\r\n \r\n return div;\r\n }\r\n\r\n public remove(key: any) {\r\n if(!this.multiSelect) return;\r\n //const div = this.selected[peerId];\r\n const div = this.selectedContainer.querySelector(`[data-key=\"${key}\"]`) as HTMLElement;\r\n div.classList.remove('scale-in');\r\n void div.offsetWidth;\r\n div.classList.add('scale-out');\r\n\r\n const onAnimationEnd = () => {\r\n this.selected.delete(key);\r\n div.remove();\r\n this.onChange && this.onChange(this.selected.size);\r\n };\r\n\r\n if(rootScope.settings.animationsEnabled) {\r\n div.addEventListener('animationend', onAnimationEnd, {once: true});\r\n } else {\r\n onAnimationEnd();\r\n }\r\n }\r\n\r\n public getSelected() {\r\n return [...this.selected];\r\n }\r\n\r\n public addInitial(values: any[]) {\r\n values.forEach(value => {\r\n this.add(value, undefined, false);\r\n });\r\n\r\n window.requestAnimationFrame(() => { // ! not the best place for this raf though it works\r\n this.selectedScrollable.scrollIntoViewNew(this.input, 'center', undefined, undefined, FocusDirection.Static);\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 { isTouchSupported } from \"../../helpers/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 peerId = this.selector.getSelected()[0];\r\n \r\n this.selector = null;\r\n \r\n if(options.onSelect) {\r\n const res = options.onSelect(peerId);\r\n if(res instanceof Promise) {\r\n await res;\r\n }\r\n }\r\n \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(!isTouchSupported) {\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","/*\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 toggleDisability from \"../../../helpers/dom/toggleDisability\";\r\nimport { deepEqual } from \"../../../helpers/object\";\r\nimport { ChannelParticipant } 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 Button from \"../../button\";\r\nimport { SettingSection } from \"../../sidebarLeft\";\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport { ChatPermissions } from \"./groupPermissions\";\r\n\r\nexport default class AppUserPermissionsTab extends SliderSuperTabEventable {\r\n public participant: ChannelParticipant;\r\n public chatId: number;\r\n public userId: number;\r\n\r\n protected init() {\r\n this.container.classList.add('edit-peer-container', 'user-permissions-container');\r\n this.setTitle('UserRestrictions');\r\n\r\n let destroyListener: () => void;\r\n\r\n {\r\n const section = new SettingSection({\r\n name: 'UserRestrictionsCanDo',\r\n });\r\n \r\n const div = document.createElement('div');\r\n div.classList.add('chatlist-container');\r\n section.content.insertBefore(div, section.title);\r\n\r\n const list = appDialogsManager.createChatList();\r\n div.append(list);\r\n\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: this.userId,\r\n container: list,\r\n drawStatus: false,\r\n rippleEnabled: true,\r\n avatarSize: 48\r\n });\r\n\r\n dom.lastMessageSpan.append(appUsersManager.getUserStatusString(this.userId));\r\n\r\n const p = new ChatPermissions({\r\n chatId: this.chatId,\r\n listenerSetter: this.listenerSetter,\r\n appendTo: section.content,\r\n participant: this.participant._ === 'channelParticipantBanned' ? this.participant : undefined\r\n });\r\n\r\n destroyListener = () => {\r\n //appChatsManager.editChatDefaultBannedRights(this.chatId, p.takeOut());\r\n const rights = p.takeOut();\r\n if(this.participant._ === 'channelParticipantBanned' && deepEqual(this.participant.banned_rights.pFlags, rights.pFlags)) {\r\n return;\r\n }\r\n\r\n appChatsManager.editBanned(this.chatId, this.participant, rights);\r\n };\r\n\r\n this.eventListener.addEventListener('destroy', destroyListener, {once: true});\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n \r\n {\r\n const section = new SettingSection({});\r\n\r\n if(this.participant._ === 'channelParticipantBanned') {\r\n const btnDeleteException = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'GroupPermission.Delete'});\r\n\r\n attachClickEvent(btnDeleteException, () => {\r\n const toggle = toggleDisability([btnDeleteException], true);\r\n appChatsManager.clearChannelParticipantBannedRights(this.chatId, this.participant).then(() => {\r\n this.eventListener.removeEventListener('destroy', destroyListener);\r\n this.close();\r\n }, () => {\r\n toggle();\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n \r\n section.content.append(btnDeleteException);\r\n }\r\n\r\n const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'deleteuser', text: 'UserRestrictionsBlock'});\r\n\r\n attachClickEvent(btnDelete, () => {\r\n const toggle = toggleDisability([btnDelete], true);\r\n appChatsManager.kickFromChannel(this.chatId, this.participant).then(() => {\r\n this.eventListener.removeEventListener('destroy', destroyListener);\r\n this.close();\r\n });\r\n /* new PopupPeer('popup-group-kick-user', {\r\n peerId: -this.chatId,\r\n title: 'Ban User?',\r\n description: `Are you sure you want to ban <b>${appPeersManager.getPeerTitle(this.userId)}</b>`,\r\n buttons: addCancelButton([{\r\n text: 'BAN',\r\n callback: () => {\r\n const toggle = toggleDisability([btnDelete], true);\r\n\r\n appChatsManager.kickFromChannel(this.chatId, this.participant).then(() => {\r\n this.eventListener.removeEventListener('destroy', destroyListener);\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 { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport findUpTag from \"../../../helpers/dom/findUpTag\";\r\nimport replaceContent from \"../../../helpers/dom/replaceContent\";\r\nimport ListenerSetter from \"../../../helpers/listenerSetter\";\r\nimport ScrollableLoader from \"../../../helpers/listLoader\";\r\nimport { ChannelParticipant, Chat, ChatBannedRights, Update } from \"../../../layer\";\r\nimport appChatsManager, { ChatRights } from \"../../../lib/appManagers/appChatsManager\";\r\nimport appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport appPeersManager from \"../../../lib/appManagers/appPeersManager\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport I18n, { i18n, join, LangPackKey } from \"../../../lib/langPack\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport PopupPickUser from \"../../popups/pickUser\";\r\nimport Row from \"../../row\";\r\nimport { SettingSection } from \"../../sidebarLeft\";\r\nimport { SliderSuperTabEventable } from \"../../sliderTab\";\r\nimport { toast } from \"../../toast\";\r\nimport AppUserPermissionsTab from \"./userPermissions\";\r\n\r\nexport class ChatPermissions {\r\n public v: Array<{\r\n flags: ChatRights[],\r\n text: LangPackKey,\r\n exceptionText: LangPackKey,\r\n checkboxField?: CheckboxField,\r\n }>;\r\n private toggleWith: Partial<{[chatRight in ChatRights]: ChatRights[]}>;\r\n\r\n constructor(options: {\r\n chatId: number,\r\n listenerSetter: ListenerSetter,\r\n appendTo: HTMLElement,\r\n participant?: ChannelParticipant.channelParticipantBanned\r\n }) {\r\n this.v = [\r\n {flags: ['send_messages'], text: 'UserRestrictionsSend', exceptionText: 'UserRestrictionsNoSend'},\r\n {flags: ['send_media'], text: 'UserRestrictionsSendMedia', exceptionText: 'UserRestrictionsNoSendMedia'},\r\n {flags: ['send_stickers', 'send_gifs'], text: 'UserRestrictionsSendStickers', exceptionText: 'UserRestrictionsNoSendStickers'},\r\n {flags: ['send_polls'], text: 'UserRestrictionsSendPolls', exceptionText: 'UserRestrictionsNoSendPolls'},\r\n {flags: ['embed_links'], text: 'UserRestrictionsEmbedLinks', exceptionText: 'UserRestrictionsNoEmbedLinks'},\r\n {flags: ['invite_users'], text: 'UserRestrictionsInviteUsers', exceptionText: 'UserRestrictionsNoInviteUsers'},\r\n {flags: ['pin_messages'], text: 'UserRestrictionsPinMessages', exceptionText: 'UserRestrictionsNoPinMessages'},\r\n {flags: ['change_info'], text: 'UserRestrictionsChangeInfo', exceptionText: 'UserRestrictionsNoChangeInfo'}\r\n ];\r\n\r\n this.toggleWith = {\r\n 'send_messages': ['send_media', 'send_stickers', 'send_polls', 'embed_links']\r\n };\r\n\r\n const chat: Chat.chat = appChatsManager.getChat(options.chatId);\r\n const defaultBannedRights = chat.default_banned_rights;\r\n const rights = options.participant ? appChatsManager.combineParticipantBannedRights(options.chatId, options.participant.banned_rights) : defaultBannedRights;\r\n \r\n for(const info of this.v) {\r\n const mainFlag = info.flags[0];\r\n info.checkboxField = new CheckboxField({\r\n text: info.text,\r\n checked: appChatsManager.hasRights(options.chatId, mainFlag, rights),\r\n restriction: true,\r\n withRipple: true\r\n });\r\n\r\n // @ts-ignore\r\n if(options.participant && defaultBannedRights.pFlags[mainFlag]) {\r\n info.checkboxField.input.disabled = true;\r\n \r\n /* options.listenerSetter.add(info.checkboxField.input)('change', (e) => {\r\n if(!e.isTrusted) {\r\n return;\r\n }\r\n\r\n cancelEvent(e);\r\n toast('This option is disabled for all members in Group Permissions.');\r\n info.checkboxField.checked = false;\r\n }); */\r\n\r\n attachClickEvent(info.checkboxField.label, (e) => {\r\n toast(I18n.format('UserRestrictionsDisabled', true));\r\n }, {listenerSetter: options.listenerSetter});\r\n }\r\n\r\n if(this.toggleWith[mainFlag]) {\r\n options.listenerSetter.add(info.checkboxField.input)('change', () => {\r\n if(!info.checkboxField.checked) {\r\n const other = this.v.filter(i => this.toggleWith[mainFlag].includes(i.flags[0]));\r\n other.forEach(info => {\r\n info.checkboxField.checked = false;\r\n });\r\n }\r\n });\r\n }\r\n\r\n options.appendTo.append(info.checkboxField.label);\r\n }\r\n }\r\n\r\n public takeOut() {\r\n const rights: ChatBannedRights = {\r\n _: 'chatBannedRights',\r\n until_date: 0x7FFFFFFF,\r\n pFlags: {}\r\n };\r\n\r\n for(const info of this.v) {\r\n const banned = !info.checkboxField.checked;\r\n if(banned) {\r\n info.flags.forEach(flag => {\r\n // @ts-ignore\r\n rights.pFlags[flag] = true;\r\n });\r\n }\r\n }\r\n\r\n return rights;\r\n }\r\n}\r\n\r\nexport default class AppGroupPermissionsTab extends SliderSuperTabEventable {\r\n public chatId: number;\r\n\r\n protected async init() {\r\n this.container.classList.add('edit-peer-container', 'group-permissions-container');\r\n this.setTitle('ChannelPermissions');\r\n\r\n let chatPermissions: ChatPermissions;\r\n {\r\n const section = new SettingSection({\r\n name: 'ChannelPermissionsHeader',\r\n });\r\n\r\n chatPermissions = new ChatPermissions({\r\n chatId: this.chatId,\r\n listenerSetter: this.listenerSetter,\r\n appendTo: section.content,\r\n });\r\n\r\n this.eventListener.addEventListener('destroy', () => {\r\n appChatsManager.editChatDefaultBannedRights(this.chatId, chatPermissions.takeOut());\r\n }, {once: true});\r\n\r\n this.scrollable.append(section.container);\r\n }\r\n \r\n {\r\n const section = new SettingSection({\r\n name: 'PrivacyExceptions'\r\n });\r\n\r\n const addExceptionRow = new Row({\r\n titleLangKey: 'ChannelAddException',\r\n subtitleLangKey: 'Loading',\r\n icon: 'adduser',\r\n clickable: () => {\r\n new PopupPickUser({\r\n peerTypes: ['channelParticipants'],\r\n onSelect: (peerId) => {\r\n setTimeout(() => {\r\n openPermissions(peerId);\r\n }, 0);\r\n },\r\n placeholder: 'ExceptionModal.Search.Placeholder',\r\n peerId: -this.chatId,\r\n });\r\n }\r\n });\r\n\r\n const openPermissions = async(peerId: number) => {\r\n let participant: AppUserPermissionsTab['participant'];\r\n try {\r\n participant = await appProfileManager.getChannelParticipant(this.chatId, peerId) as any;\r\n } catch(err) {\r\n toast('User is no longer participant');\r\n return;\r\n }\r\n\r\n const tab = new AppUserPermissionsTab(this.slider);\r\n tab.participant = participant;\r\n tab.chatId = this.chatId;\r\n tab.userId = peerId;\r\n tab.open();\r\n };\r\n\r\n section.content.append(addExceptionRow.container);\r\n\r\n /* const removedUsersRow = new Row({\r\n titleLangKey: 'ChannelBlockedUsers',\r\n subtitleLangKey: 'NoBlockedUsers',\r\n icon: 'deleteuser',\r\n clickable: true\r\n });\r\n\r\n section.content.append(removedUsersRow.container); */\r\n\r\n const c = section.generateContentElement();\r\n c.classList.add('chatlist-container');\r\n \r\n const list = appDialogsManager.createChatList();\r\n c.append(list);\r\n\r\n attachClickEvent(list, (e) => {\r\n const target = findUpTag(e.target, 'LI');\r\n if(!target) return;\r\n\r\n const peerId = +target.dataset.peerId;\r\n openPermissions(peerId);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n const setSubtitle = (li: Element, participant: ChannelParticipant.channelParticipantBanned) => {\r\n const bannedRights = participant.banned_rights;//appChatsManager.combineParticipantBannedRights(this.chatId, participant.banned_rights);\r\n const defaultBannedRights = (appChatsManager.getChat(this.chatId) as Chat.channel).default_banned_rights;\r\n //const combinedRights = appChatsManager.combineParticipantBannedRights(this.chatId, bannedRights);\r\n\r\n const cantWhat: LangPackKey[] = []/* , canWhat: LangPackKey[] = [] */;\r\n chatPermissions.v.forEach(info => {\r\n const mainFlag = info.flags[0];\r\n // @ts-ignore\r\n if(bannedRights.pFlags[mainFlag] && !defaultBannedRights.pFlags[mainFlag]) {\r\n cantWhat.push(info.exceptionText);\r\n // @ts-ignore\r\n }/* else if(!combinedRights.pFlags[mainFlag]) {\r\n canWhat.push(info.exceptionText);\r\n } */\r\n });\r\n\r\n const el = li.querySelector('.user-last-message') as HTMLElement;\r\n\r\n if(cantWhat.length) {\r\n el.innerHTML = '';\r\n el.append(...join(cantWhat.map(t => i18n(t)), false));\r\n }/* else if(canWhat.length) {\r\n str = 'Can ' + canWhat.join(canWhat.length === 2 ? ' and ' : ', ');\r\n } */\r\n \r\n el.classList.toggle('hide', !cantWhat.length);\r\n };\r\n\r\n const add = (participant: ChannelParticipant.channelParticipantBanned, append: boolean) => {\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: appPeersManager.getPeerId(participant.peer),\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 setSubtitle(dom.listEl, participant);\r\n\r\n //dom.titleSpan.innerHTML = 'Chinaza Akachi';\r\n //dom.lastMessageSpan.innerHTML = 'Can Add Users and Pin Messages';\r\n };\r\n\r\n this.listenerSetter.add(rootScope)('updateChannelParticipant', (update: Update.updateChannelParticipant) => {\r\n const needAdd = update.new_participant?._ === 'channelParticipantBanned' && !update.new_participant.banned_rights.pFlags.view_messages;\r\n const li = list.querySelector(`[data-peer-id=\"${update.user_id}\"]`);\r\n if(needAdd) {\r\n if(!li) {\r\n add(update.new_participant as ChannelParticipant.channelParticipantBanned, false);\r\n } else {\r\n setSubtitle(li, update.new_participant as ChannelParticipant.channelParticipantBanned);\r\n }\r\n\r\n if(update.prev_participant?._ !== 'channelParticipantBanned') {\r\n ++exceptionsCount;\r\n }\r\n } else {\r\n if(li) {\r\n li.remove();\r\n }\r\n\r\n if(update.prev_participant?._ === 'channelParticipantBanned') {\r\n --exceptionsCount;\r\n }\r\n }\r\n\r\n setLength();\r\n });\r\n\r\n const setLength = () => {\r\n replaceContent(addExceptionRow.subtitle, i18n(exceptionsCount ? 'Permissions.ExceptionsCount' : 'Permissions.NoExceptions', [exceptionsCount]));\r\n };\r\n\r\n let exceptionsCount = 0;\r\n const LOAD_COUNT = 50;\r\n const loader = new ScrollableLoader({\r\n scrollable: this.scrollable,\r\n getPromise: () => {\r\n return appProfileManager.getChannelParticipants(this.chatId, {_: 'channelParticipantsBanned', q: ''}, LOAD_COUNT, list.childElementCount).then(res => {\r\n for(const participant of res.participants) {\r\n add(participant as ChannelParticipant.channelParticipantBanned, true);\r\n }\r\n\r\n exceptionsCount = res.count;\r\n setLength();\r\n\r\n return res.participants.length < LOAD_COUNT || res.count === list.childElementCount;\r\n });\r\n }\r\n });\r\n\r\n this.scrollable.append(section.container);\r\n\r\n await loader.load();\r\n }\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n this.scrollable.onScroll();\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 appChatsManager from \"../../lib/appManagers/appChatsManager\";\r\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager, { PeerType } from \"../../lib/appManagers/appPeersManager\";\r\nimport { LangPackKey } from \"../../lib/langPack\";\r\nimport PeerTitle from \"../peerTitle\";\r\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerOptions } from \"./peer\";\r\n\r\nexport default class PopupDeleteDialog {\r\n constructor(peerId: number, peerType: PeerType = appPeersManager.getDialogType(peerId), onSelect?: (promise: Promise<any>) => void) {\r\n const peerTitleElement = new PeerTitle({\r\n peerId,\r\n onlyFirstName: true\r\n }).element;\r\n\r\n /* const callbackFlush = (checked: PopupPeerButtonCallbackCheckboxes) => {\r\n const promise = appMessagesManager.flushHistory(peerId, checkboxes ? !checked[checkboxes[0].text] : undefined);\r\n onSelect && onSelect(promise);\r\n }; */\r\n\r\n const callbackLeave = (checked: PopupPeerButtonCallbackCheckboxes, flush = checkboxes && !!checked.size) => {\r\n let promise = appChatsManager.leave(-peerId);\r\n \r\n if(flush) {\r\n promise = promise.finally(() => {\r\n return appMessagesManager.flushHistory(peerId);\r\n }) as any;\r\n }\r\n \r\n onSelect && onSelect(promise);\r\n };\r\n\r\n const callbackDelete = (checked: PopupPeerButtonCallbackCheckboxes) => {\r\n let promise: Promise<any>;\r\n\r\n if(peerId > 0) {\r\n promise = appMessagesManager.flushHistory(peerId, false, checkboxes ? !!checked.size : undefined);\r\n } else {\r\n if(checked.size) {\r\n promise = appChatsManager.delete(-peerId);\r\n } else {\r\n return callbackLeave(checked);\r\n }\r\n }\r\n \r\n onSelect && onSelect(promise);\r\n };\r\n\r\n let title: LangPackKey, description: LangPackKey, descriptionArgs: any[], buttons: PopupPeerOptions['buttons'], checkboxes: PopupPeerOptions['checkboxes'];\r\n switch(peerType) {\r\n case 'channel': {\r\n title = 'LeaveChannelMenu';\r\n description = 'ChannelLeaveAlertWithName';\r\n descriptionArgs = [peerTitleElement];\r\n buttons = [{\r\n langKey: 'LeaveChannel',\r\n isDanger: true,\r\n callback: callbackLeave\r\n }];\r\n\r\n break;\r\n }\r\n\r\n /* case 'megagroup': {\r\n title = 'Leave Group?';\r\n description = `Are you sure you want to leave this group?`;\r\n buttons = [{\r\n text: 'LEAVE ' + peerTitleElement,\r\n isDanger: true,\r\n callback: callbackLeave\r\n }];\r\n\r\n break;\r\n } */\r\n\r\n case 'chat': {\r\n title = 'DeleteChatUser';\r\n description = 'AreYouSureDeleteThisChatWithUser';\r\n descriptionArgs = [peerTitleElement];\r\n\r\n checkboxes = [{\r\n text: 'DeleteMessagesOptionAlso',\r\n textArgs: [\r\n new PeerTitle({\r\n peerId,\r\n onlyFirstName: true\r\n }).element\r\n ]\r\n }];\r\n\r\n buttons = [{\r\n langKey: 'DeleteChatUser',\r\n isDanger: true,\r\n callback: callbackDelete\r\n }];\r\n\r\n break;\r\n }\r\n\r\n case 'saved': {\r\n title = 'DeleteChatUser';\r\n description = 'AreYouSureDeleteThisChatSavedMessages';\r\n buttons = [{\r\n langKey: 'DeleteChatUser',\r\n isDanger: true,\r\n callback: callbackDelete\r\n }];\r\n\r\n break;\r\n }\r\n\r\n case 'megagroup':\r\n case 'group': {\r\n if(appChatsManager.hasRights(-peerId, 'delete_chat')) {\r\n title = 'DeleteMegaMenu';\r\n description = 'AreYouSureDeleteAndExit';\r\n buttons = [{\r\n langKey: 'DeleteMegaMenu',\r\n isDanger: true,\r\n callback: callbackDelete\r\n }];\r\n\r\n checkboxes = [{\r\n text: 'DeleteChat.DeleteGroupForAll'\r\n }];\r\n } else {\r\n title = 'LeaveMegaMenu';\r\n description = 'AreYouSureDeleteAndExitName';\r\n descriptionArgs = [peerTitleElement];\r\n buttons = [{\r\n langKey: 'DeleteChatUser',\r\n isDanger: true,\r\n callback: (checkboxes) => callbackLeave(checkboxes, true)\r\n }];\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n new PopupPeer('popup-delete-chat', {\r\n peerId,\r\n titleLangKey: title,\r\n descriptionLangKey: description,\r\n descriptionLangArgs: descriptionArgs,\r\n buttons,\r\n checkboxes\r\n }).show();\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 Button from \"../../button\";\r\nimport appChatsManager, { ChatRights } from \"../../../lib/appManagers/appChatsManager\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport { Chat } 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 { addCancelButton } from \"../../popups\";\r\nimport PopupPeer from \"../../popups/peer\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport toggleDisability from \"../../../helpers/dom/toggleDisability\";\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 {\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 ? 'Channel.ChannelNameHolder' : 'CreateGroup.NameHolder',\r\n name: 'chat-name',\r\n maxLength: 255\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(appChatsManager.hasRights(-this.peerId, 'change_info')) {\r\n const signMessagesCheckboxField = new CheckboxField({\r\n text: 'PeerInfo.SignMessages',\r\n checked: false\r\n });\r\n\r\n section.content.append(signMessagesCheckboxField.label);\r\n } */\r\n }\r\n\r\n /* {\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(appChatsManager.hasRights(this.chatId, 'change_permissions')) {\r\n const showChatHistoryCheckboxField = new CheckboxField({\r\n text: 'Show chat history for new members',\r\n withRipple: true\r\n });\r\n \r\n if(appChatsManager.isChannel(this.chatId) && !(chatFull as ChatFull.channelFull).pFlags.hidden_prehistory) {\r\n showChatHistoryCheckboxField.checked = true;\r\n }\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' : 'DeleteMega'});\r\n\r\n attachClickEvent(btnDelete, () => {\r\n if(isBroadcast) {\r\n new PopupPeer('popup-delete-channel', {\r\n peerId: -this.chatId,\r\n titleLangKey: 'ChannelDeleteMenu',\r\n descriptionLangKey: 'AreYouSureDeleteAndExitChannel',\r\n buttons: addCancelButton([{\r\n langKey: 'ChannelDeleteMenu',\r\n callback: () => {\r\n const toggle = toggleDisability([btnDelete], true);\r\n \r\n },\r\n isDanger: true\r\n }, {\r\n langKey: 'DeleteChannelForAll',\r\n callback: () => {\r\n const toggle = toggleDisability([btnDelete], true);\r\n \r\n appChatsManager.deleteChannel(this.chatId).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 } else {\r\n new PopupDeleteDialog(-this.chatId, 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 }\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 this.setTitle('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: 'EditProfile.FirstNameLabel',\r\n name: 'contact-name',\r\n maxLength: 70\r\n });\r\n this.lastNameInputField = new InputField({\r\n label: 'Login.Register.LastName.Placeholder',\r\n name: 'contact-lastname',\r\n maxLength: 70\r\n });\r\n \r\n const user = appUsersManager.getUser(this.peerId);\r\n\r\n this.nameInputField.setOriginalValue(user.first_name);\r\n this.lastNameInputField.setOriginalValue(user.last_name);\r\n\r\n inputWrapper.append(this.nameInputField.container, this.lastNameInputField.container);\r\n \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 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 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 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, notificationsRow.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 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 {\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 { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport { safeAssign } from \"../helpers/object\";\r\nimport { isTouchSupported } from \"../helpers/touchSupport\";\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\nexport default class SwipeHandler {\r\n private element: HTMLElement;\r\n private onSwipe: (xDiff: number, yDiff: number) => boolean;\r\n private verifyTouchTarget: (evt: TouchEvent | MouseEvent) => boolean;\r\n private onFirstSwipe: () => void;\r\n private onReset: () => void;\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 }) {\r\n safeAssign(this, options);\r\n\r\n if(!isTouchSupported) {\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 reset = (e?: Event) => {\r\n /* if(e) {\r\n cancelEvent(e);\r\n } */\r\n\r\n if(isTouchSupported) {\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(isTouchSupported) {\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) {\r\n return this.reset();\r\n }\r\n\r\n cancelEvent(_e);\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(!isTouchSupported) {\r\n this.element.style.cursor = 'grabbing';\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 if(this.onSwipe(xDiff, yDiff)) {\r\n this.reset();\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}","/*\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 appMessagesManager, { AppMessagesManager } from \"../../../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager from \"../../../lib/appManagers/appPeersManager\";\r\nimport appProfileManager from \"../../../lib/appManagers/appProfileManager\";\r\nimport appUsersManager, { User } from \"../../../lib/appManagers/appUsersManager\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport AppSearchSuper, { SearchSuperType } from \"../../appSearchSuper.\";\r\nimport AvatarElement, { openAvatarViewer } from \"../../avatar\";\r\nimport SidebarSlider, { SliderSuperTab } from \"../../slider\";\r\nimport CheckboxField from \"../../checkboxField\";\r\nimport appSidebarRight from \"..\";\r\nimport { TransitionSlider } from \"../../transition\";\r\nimport appNotificationsManager from \"../../../lib/appManagers/appNotificationsManager\";\r\nimport AppEditChatTab from \"./editChat\";\r\nimport PeerTitle from \"../../peerTitle\";\r\nimport AppEditContactTab from \"./editContact\";\r\nimport appChatsManager, { Channel } from \"../../../lib/appManagers/appChatsManager\";\r\nimport { Chat, Message, MessageAction, ChatFull, Photo } from \"../../../layer\";\r\nimport Button from \"../../button\";\r\nimport ButtonIcon from \"../../buttonIcon\";\r\nimport I18n, { i18n, LangPackKey } from \"../../../lib/langPack\";\r\nimport { SettingSection } from \"../../sidebarLeft\";\r\nimport Row from \"../../row\";\r\nimport { copyTextToClipboard } from \"../../../helpers/clipboard\";\r\nimport { toast, toastNew } from \"../../toast\";\r\nimport { fastRaf } from \"../../../helpers/schedulers\";\r\nimport { safeAssign } from \"../../../helpers/object\";\r\nimport { forEachReverse } from \"../../../helpers/array\";\r\nimport appPhotosManager from \"../../../lib/appManagers/appPhotosManager\";\r\nimport renderImageFromUrl from \"../../../helpers/dom/renderImageFromUrl\";\r\nimport SwipeHandler from \"../../swipeHandler\";\r\nimport { MOUNT_CLASS_TO } from \"../../../config/debug\";\r\nimport AppAddMembersTab from \"../../sidebarLeft/tabs/addMembers\";\r\nimport PopupPickUser from \"../../popups/pickUser\";\r\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerCheckboxOptions } from \"../../popups/peer\";\r\nimport Scrollable from \"../../scrollable\";\r\nimport { isTouchSupported } from \"../../../helpers/touchSupport\";\r\nimport { isFirefox } from \"../../../helpers/userAgent\";\r\nimport appDownloadManager from \"../../../lib/appManagers/appDownloadManager\";\r\nimport ButtonCorner from \"../../buttonCorner\";\r\nimport { cancelEvent } from \"../../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../../helpers/dom/clickEvent\";\r\nimport replaceContent from \"../../../helpers/dom/replaceContent\";\r\nimport appAvatarsManager from \"../../../lib/appManagers/appAvatarsManager\";\r\n\r\nlet setText = (text: string, row: Row) => {\r\n //fastRaf(() => {\r\n row.title.innerHTML = text;\r\n row.container.style.display = '';\r\n //});\r\n};\r\n\r\nconst PARALLAX_SUPPORTED = !isFirefox;\r\n\r\ntype ListLoaderResult<T> = {count: number, items: any[]};\r\nclass ListLoader<T> {\r\n public current: T;\r\n public previous: T[] = [];\r\n public next: T[] = [];\r\n public count: number;\r\n\r\n public tempId = 0;\r\n public loadMore: (anchor: T, older: boolean) => Promise<ListLoaderResult<T>>;\r\n public processItem: (item: any) => false | T;\r\n public onJump: (item: T, older: boolean) => void;\r\n public loadCount = 50;\r\n public reverse = false; // reverse means next = higher msgid\r\n\r\n public loadedAllUp = false;\r\n public loadedAllDown = false;\r\n public loadPromiseUp: Promise<void>;\r\n public loadPromiseDown: Promise<void>;\r\n\r\n constructor(options: {\r\n loadMore: ListLoader<T>['loadMore'],\r\n loadCount: ListLoader<T>['loadCount'],\r\n processItem?: ListLoader<T>['processItem'],\r\n onJump: ListLoader<T>['onJump'],\r\n }) {\r\n safeAssign(this, options);\r\n\r\n\r\n }\r\n\r\n get index() {\r\n return this.count !== undefined ? this.previous.length : -1;\r\n }\r\n\r\n public go(length: number) {\r\n let items: T[], item: T;\r\n if(length > 0) {\r\n items = this.next.splice(0, length);\r\n item = items.pop();\r\n if(!item) {\r\n return;\r\n }\r\n\r\n this.previous.push(this.current, ...items);\r\n } else {\r\n items = this.previous.splice(this.previous.length + length, -length);\r\n item = items.shift();\r\n if(!item) {\r\n return;\r\n }\r\n\r\n this.next.unshift(...items, this.current);\r\n }\r\n\r\n this.current = item;\r\n this.onJump(item, length > 0);\r\n }\r\n\r\n public load(older: boolean) {\r\n if(older && this.loadedAllDown) return Promise.resolve();\r\n else if(!older && this.loadedAllUp) return Promise.resolve();\r\n\r\n if(older && this.loadPromiseDown) return this.loadPromiseDown;\r\n else if(!older && this.loadPromiseUp) return this.loadPromiseUp;\r\n\r\n /* const loadCount = 50;\r\n const backLimit = older ? 0 : loadCount; */\r\n \r\n let anchor: T;\r\n if(older) {\r\n anchor = this.reverse ? this.previous[0] : this.next[this.next.length - 1];\r\n } else {\r\n anchor = this.reverse ? this.next[this.next.length - 1] : this.previous[0];\r\n }\r\n\r\n const promise = this.loadMore(anchor, older).then(result => {\r\n if(result.items.length < this.loadCount) {\r\n if(older) this.loadedAllDown = true;\r\n else this.loadedAllUp = true;\r\n }\r\n\r\n if(this.count === undefined) {\r\n this.count = result.count || result.items.length;\r\n }\r\n\r\n const method = older ? result.items.forEach.bind(result.items) : forEachReverse.bind(null, result.items);\r\n method((item: any) => {\r\n const processed = this.processItem ? this.processItem(item) : item;\r\n\r\n if(!processed) return;\r\n\r\n if(older) {\r\n if(this.reverse) this.previous.unshift(processed);\r\n else this.next.push(processed);\r\n } else {\r\n if(this.reverse) this.next.push(processed);\r\n else this.previous.unshift(processed);\r\n }\r\n });\r\n }, () => {}).then(() => {\r\n if(older) this.loadPromiseDown = null;\r\n else this.loadPromiseUp = null;\r\n });\r\n\r\n if(older) this.loadPromiseDown = promise;\r\n else this.loadPromiseUp = promise;\r\n\r\n return promise;\r\n }\r\n}\r\n\r\nclass PeerProfileAvatars {\r\n private static BASE_CLASS = 'profile-avatars';\r\n private static SCALE = PARALLAX_SUPPORTED ? 2 : 1;\r\n private static TRANSLATE_TEMPLATE = PARALLAX_SUPPORTED ? `translate3d({x}, 0, -1px) scale(${PeerProfileAvatars.SCALE})` : 'translate({x}, 0)';\r\n public container: HTMLElement;\r\n public avatars: HTMLElement;\r\n public gradient: HTMLElement;\r\n public info: HTMLElement;\r\n public arrowPrevious: HTMLElement;\r\n public arrowNext: HTMLElement;\r\n private tabs: HTMLDivElement;\r\n private listLoader: ListLoader<string | Message.messageService>;\r\n private peerId: number;\r\n\r\n constructor(public scrollable: Scrollable) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add(PeerProfileAvatars.BASE_CLASS + '-container');\r\n\r\n this.avatars = document.createElement('div');\r\n this.avatars.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatars');\r\n\r\n this.gradient = document.createElement('div');\r\n this.gradient.classList.add(PeerProfileAvatars.BASE_CLASS + '-gradient');\r\n\r\n this.info = document.createElement('div');\r\n this.info.classList.add(PeerProfileAvatars.BASE_CLASS + '-info');\r\n\r\n this.tabs = document.createElement('div');\r\n this.tabs.classList.add(PeerProfileAvatars.BASE_CLASS + '-tabs');\r\n\r\n this.arrowPrevious = document.createElement('div');\r\n this.arrowPrevious.classList.add(PeerProfileAvatars.BASE_CLASS + '-arrow');\r\n\r\n /* const previousIcon = document.createElement('i');\r\n previousIcon.classList.add(PeerProfileAvatars.BASE_CLASS + '-arrow-icon', 'tgico-previous');\r\n this.arrowBack.append(previousIcon); */\r\n \r\n this.arrowNext = document.createElement('div');\r\n this.arrowNext.classList.add(PeerProfileAvatars.BASE_CLASS + '-arrow', PeerProfileAvatars.BASE_CLASS + '-arrow-next');\r\n\r\n /* const nextIcon = document.createElement('i');\r\n nextIcon.classList.add(PeerProfileAvatars.BASE_CLASS + '-arrow-icon', 'tgico-next');\r\n this.arrowNext.append(nextIcon); */\r\n\r\n this.container.append(this.avatars, this.gradient, this.info, this.tabs, this.arrowPrevious, this.arrowNext);\r\n\r\n const checkScrollTop = () => {\r\n if(this.scrollable.scrollTop !== 0) {\r\n this.scrollable.scrollIntoViewNew(this.scrollable.container.firstElementChild as HTMLElement, 'start');\r\n return false;\r\n }\r\n\r\n return true;\r\n };\r\n\r\n const SWITCH_ZONE = 1 / 3;\r\n let cancel = false;\r\n let freeze = false;\r\n attachClickEvent(this.container, async(_e) => {\r\n if(freeze) {\r\n cancelEvent(_e);\r\n return;\r\n }\r\n\r\n if(cancel) {\r\n cancel = false;\r\n return;\r\n }\r\n\r\n if(!checkScrollTop()) {\r\n return;\r\n }\r\n\r\n const rect = this.container.getBoundingClientRect();\r\n\r\n const e = (_e as TouchEvent).touches ? (_e as TouchEvent).touches[0] : _e as MouseEvent;\r\n const x = e.pageX;\r\n\r\n const clickX = x - rect.left;\r\n if((!this.listLoader.previous.length && !this.listLoader.next.length) \r\n || (clickX > (rect.width * SWITCH_ZONE) && clickX < (rect.width - rect.width * SWITCH_ZONE))) {\r\n const peerId = this.peerId;\r\n\r\n const targets: {element: HTMLElement, item: string | Message.messageService}[] = [];\r\n this.listLoader.previous.concat(this.listLoader.current, this.listLoader.next).forEach((item, idx) => {\r\n targets.push({\r\n element: /* null */this.avatars.children[idx] as HTMLElement,\r\n item\r\n });\r\n });\r\n\r\n const prevTargets = targets.slice(0, this.listLoader.previous.length);\r\n const nextTargets = targets.slice(this.listLoader.previous.length + 1);\r\n\r\n const target = this.avatars.children[this.listLoader.previous.length] as HTMLElement;\r\n freeze = true;\r\n openAvatarViewer(target, peerId, () => peerId === this.peerId, this.listLoader.current, prevTargets, nextTargets);\r\n freeze = false;\r\n } else {\r\n const centerX = rect.right - (rect.width / 2);\r\n const toRight = x > centerX;\r\n \r\n // this.avatars.classList.remove('no-transition');\r\n // fastRaf(() => {\r\n this.avatars.classList.add('no-transition');\r\n void this.avatars.offsetLeft; // reflow\r\n\r\n let distance: number;\r\n if(this.listLoader.index === 0 && !toRight) distance = this.listLoader.count - 1;\r\n else if(this.listLoader.index === (this.listLoader.count - 1) && toRight) distance = -(this.listLoader.count - 1);\r\n else distance = toRight ? 1 : -1;\r\n this.listLoader.go(distance);\r\n\r\n fastRaf(() => {\r\n this.avatars.classList.remove('no-transition');\r\n });\r\n // });\r\n }\r\n });\r\n\r\n const cancelNextClick = () => {\r\n cancel = true;\r\n document.body.addEventListener(isTouchSupported ? 'touchend' : 'click', (e) => {\r\n cancel = false;\r\n }, {once: true});\r\n };\r\n\r\n let width = 0, x = 0, lastDiffX = 0, lastIndex = 0, minX = 0;\r\n const swipeHandler = new SwipeHandler({\r\n element: this.avatars, \r\n onSwipe: (xDiff, yDiff) => {\r\n lastDiffX = xDiff;\r\n let lastX = x + xDiff * -PeerProfileAvatars.SCALE;\r\n if(lastX > 0) lastX = 0;\r\n else if(lastX < minX) lastX = minX;\r\n\r\n this.avatars.style.transform = PeerProfileAvatars.TRANSLATE_TEMPLATE.replace('{x}', lastX + 'px');\r\n //console.log(xDiff, yDiff);\r\n return false;\r\n }, \r\n verifyTouchTarget: (e) => {\r\n if(!checkScrollTop()) {\r\n cancelNextClick();\r\n cancelEvent(e);\r\n return false;\r\n } else if(this.container.classList.contains('is-single') || freeze) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }, \r\n onFirstSwipe: () => {\r\n const rect = this.avatars.getBoundingClientRect();\r\n width = rect.width;\r\n minX = -width * (this.tabs.childElementCount - 1);\r\n\r\n /* lastIndex = whichChild(this.tabs.querySelector('.active'));\r\n x = -width * lastIndex; */\r\n x = rect.left - this.container.getBoundingClientRect().left;\r\n \r\n this.avatars.style.transform = PeerProfileAvatars.TRANSLATE_TEMPLATE.replace('{x}', x + 'px');\r\n\r\n this.container.classList.add('is-swiping');\r\n this.avatars.classList.add('no-transition');\r\n void this.avatars.offsetLeft; // reflow\r\n },\r\n onReset: () => {\r\n const addIndex = Math.ceil(Math.abs(lastDiffX) / (width / PeerProfileAvatars.SCALE)) * (lastDiffX >= 0 ? 1 : -1);\r\n cancelNextClick();\r\n \r\n //console.log(addIndex);\r\n\r\n this.avatars.classList.remove('no-transition');\r\n fastRaf(() => {\r\n this.listLoader.go(addIndex);\r\n this.container.classList.remove('is-swiping');\r\n });\r\n }\r\n });\r\n }\r\n\r\n public setPeer(peerId: number) {\r\n this.peerId = peerId;\r\n\r\n const photo = appPeersManager.getPeerPhoto(peerId);\r\n if(!photo) {\r\n return;\r\n }\r\n\r\n const loadCount = 50;\r\n const listLoader: PeerProfileAvatars['listLoader'] = this.listLoader = new ListLoader<string | Message.messageService>({\r\n loadCount,\r\n loadMore: (anchor, older) => {\r\n if(peerId > 0) {\r\n return appPhotosManager.getUserPhotos(peerId, (anchor || listLoader.current) as any, loadCount).then(result => {\r\n return {\r\n count: result.count,\r\n items: result.photos\r\n };\r\n });\r\n } else {\r\n const promises: [Promise<ChatFull>, ReturnType<AppMessagesManager['getSearch']>] = [] as any;\r\n if(!listLoader.current) {\r\n promises.push(appProfileManager.getChatFull(-peerId));\r\n }\r\n \r\n promises.push(appMessagesManager.getSearch({\r\n peerId,\r\n maxId: Number.MAX_SAFE_INTEGER,\r\n inputFilter: {\r\n _: 'inputMessagesFilterChatPhotos'\r\n },\r\n limit: loadCount,\r\n backLimit: 0\r\n }));\r\n\r\n return Promise.all(promises).then((result) => {\r\n const value = result.pop() as typeof result[1];\r\n\r\n if(!listLoader.current) {\r\n const chatFull = result[0];\r\n const message = value.history.findAndSplice(m => {\r\n return ((m as Message.messageService).action as MessageAction.messageActionChannelEditPhoto).photo.id === chatFull.chat_photo.id;\r\n }) as Message.messageService;\r\n \r\n listLoader.current = message || appMessagesManager.generateFakeAvatarMessage(this.peerId, chatFull.chat_photo);\r\n }\r\n\r\n //console.log('avatars loaded:', value);\r\n return {\r\n count: value.count,\r\n items: value.history\r\n };\r\n });\r\n }\r\n },\r\n processItem: this.processItem,\r\n onJump: (item, older) => {\r\n const id = this.listLoader.index;\r\n //const nextId = Math.max(0, id);\r\n const x = 100 * PeerProfileAvatars.SCALE * id;\r\n this.avatars.style.transform = PeerProfileAvatars.TRANSLATE_TEMPLATE.replace('{x}', `-${x}%`);\r\n\r\n const activeTab = this.tabs.querySelector('.active');\r\n if(activeTab) activeTab.classList.remove('active');\r\n\r\n const tab = this.tabs.children[id] as HTMLElement;\r\n tab.classList.add('active');\r\n }\r\n });\r\n\r\n if(photo._ === 'userProfilePhoto') {\r\n listLoader.current = photo.photo_id;\r\n }\r\n\r\n this.processItem(listLoader.current);\r\n\r\n listLoader.load(true);\r\n }\r\n\r\n public addTab() {\r\n const tab = document.createElement('div');\r\n tab.classList.add(PeerProfileAvatars.BASE_CLASS + '-tab');\r\n this.tabs.append(tab);\r\n\r\n if(this.tabs.childElementCount === 1) {\r\n tab.classList.add('active');\r\n }\r\n\r\n this.container.classList.toggle('is-single', this.tabs.childElementCount <= 1);\r\n }\r\n\r\n public processItem = (photoId: string | Message.messageService) => {\r\n const avatar = document.createElement('div');\r\n avatar.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatar');\r\n\r\n let photo: Photo.photo;\r\n if(photoId) {\r\n photo = typeof(photoId) === 'string' ? \r\n appPhotosManager.getPhoto(photoId) : \r\n (photoId.action as MessageAction.messageActionChannelEditPhoto).photo as Photo.photo;\r\n }\r\n\r\n const img = new Image();\r\n img.classList.add(PeerProfileAvatars.BASE_CLASS + '-avatar-image');\r\n img.draggable = false;\r\n\r\n if(photo) {\r\n const size = appPhotosManager.choosePhotoSize(photo, 420, 420, false);\r\n appPhotosManager.preloadPhoto(photo, size).then(() => {\r\n const cacheContext = appDownloadManager.getCacheContext(photo, size.type);\r\n renderImageFromUrl(img, cacheContext.url, () => {\r\n avatar.append(img);\r\n });\r\n });\r\n } else {\r\n const photo = appPeersManager.getPeerPhoto(this.peerId);\r\n appAvatarsManager.putAvatar(avatar, this.peerId, photo, 'photo_big', img);\r\n }\r\n\r\n this.avatars.append(avatar);\r\n\r\n this.addTab();\r\n\r\n return photoId;\r\n };\r\n}\r\n\r\nclass PeerProfile {\r\n public element: HTMLElement;\r\n public avatars: PeerProfileAvatars;\r\n private avatar: AvatarElement;\r\n private section: SettingSection;\r\n private name: HTMLDivElement;\r\n private subtitle: HTMLDivElement;\r\n private bio: Row;\r\n private username: Row;\r\n private phone: Row;\r\n private notifications: Row;\r\n \r\n private cleaned: boolean;\r\n private setBioTimeout: number;\r\n private setPeerStatusInterval: number;\r\n\r\n private peerId = 0;\r\n private threadId: number;\r\n\r\n constructor(public scrollable: Scrollable) {\r\n if(!PARALLAX_SUPPORTED) {\r\n this.scrollable.container.classList.add('no-parallax');\r\n }\r\n }\r\n\r\n public init() {\r\n this.init = null;\r\n\r\n this.element = document.createElement('div');\r\n this.element.classList.add('profile-content');\r\n\r\n this.section = new SettingSection({\r\n noDelimiter: true\r\n });\r\n\r\n this.avatar = new AvatarElement();\r\n this.avatar.classList.add('profile-avatar', 'avatar-120');\r\n this.avatar.setAttribute('dialog', '1');\r\n this.avatar.setAttribute('clickable', '');\r\n\r\n this.name = document.createElement('div');\r\n this.name.classList.add('profile-name');\r\n\r\n this.subtitle = document.createElement('div');\r\n this.subtitle.classList.add('profile-subtitle');\r\n\r\n this.bio = new Row({\r\n title: ' ',\r\n subtitleLangKey: 'UserBio',\r\n icon: 'info',\r\n clickable: (e) => {\r\n if((e.target as HTMLElement).tagName === 'A') {\r\n return;\r\n }\r\n \r\n appProfileManager.getProfileByPeerId(this.peerId).then(full => {\r\n copyTextToClipboard(full.about);\r\n toast(I18n.format('BioCopied', true));\r\n });\r\n }\r\n });\r\n\r\n this.bio.title.classList.add('pre-wrap');\r\n\r\n this.username = new Row({\r\n title: ' ',\r\n subtitleLangKey: 'Username',\r\n icon: 'username',\r\n clickable: () => {\r\n const peer: Channel | User = appPeersManager.getPeer(this.peerId);\r\n copyTextToClipboard('@' + peer.username);\r\n toast(I18n.format('UsernameCopied', true));\r\n }\r\n });\r\n\r\n this.phone = new Row({\r\n title: ' ',\r\n subtitleLangKey: 'Phone',\r\n icon: 'phone',\r\n clickable: () => {\r\n const peer: User = appUsersManager.getUser(this.peerId);\r\n copyTextToClipboard('+' + peer.phone);\r\n toast(I18n.format('PhoneCopied', true));\r\n }\r\n });\r\n\r\n this.notifications = new Row({\r\n checkboxField: new CheckboxField({toggle: true}),\r\n titleLangKey: 'Notifications',\r\n icon: 'unmute'\r\n });\r\n \r\n this.section.content.append(this.phone.container, this.username.container, this.bio.container, this.notifications.container);\r\n\r\n const delimiter = document.createElement('div');\r\n delimiter.classList.add('gradient-delimiter');\r\n\r\n this.element.append(this.section.container, delimiter);\r\n\r\n this.notifications.checkboxField.input.addEventListener('change', (e) => {\r\n if(!e.isTrusted) {\r\n return;\r\n }\r\n\r\n //let checked = this.notificationsCheckbox.checked;\r\n appMessagesManager.mutePeer(this.peerId);\r\n });\r\n\r\n rootScope.addEventListener('dialog_notify_settings', (dialog) => {\r\n if(this.peerId === dialog.peerId) {\r\n const muted = appNotificationsManager.isPeerLocalMuted(this.peerId, false);\r\n this.notifications.checkboxField.checked = !muted;\r\n }\r\n });\r\n\r\n rootScope.addEventListener('peer_typings', (e) => {\r\n const {peerId} = e;\r\n\r\n if(this.peerId === peerId) {\r\n this.setPeerStatus();\r\n }\r\n });\r\n\r\n rootScope.addEventListener('peer_bio_edit', (peerId) => {\r\n if(peerId === this.peerId) {\r\n this.setBio(true);\r\n }\r\n });\r\n\r\n rootScope.addEventListener('user_update', (e) => {\r\n const userId = e;\r\n\r\n if(this.peerId === userId) {\r\n this.setPeerStatus();\r\n }\r\n });\r\n\r\n this.setPeerStatusInterval = window.setInterval(this.setPeerStatus, 60e3);\r\n }\r\n\r\n public setPeerStatus = (needClear = false) => {\r\n if(!this.peerId) return;\r\n\r\n const peerId = this.peerId;\r\n appImManager.setPeerStatus(this.peerId, this.subtitle, needClear, true, () => peerId === this.peerId);\r\n };\r\n\r\n public cleanupHTML() {\r\n this.bio.container.style.display = 'none';\r\n this.phone.container.style.display = 'none';\r\n this.username.container.style.display = 'none';\r\n this.notifications.container.style.display = '';\r\n this.notifications.checkboxField.checked = true;\r\n if(this.setBioTimeout) {\r\n window.clearTimeout(this.setBioTimeout);\r\n this.setBioTimeout = 0;\r\n }\r\n }\r\n\r\n public setAvatar() {\r\n if(this.peerId !== rootScope.myId) {\r\n const photo = appPeersManager.getPeerPhoto(this.peerId);\r\n\r\n if(photo) {\r\n const oldAvatars = this.avatars;\r\n this.avatars = new PeerProfileAvatars(this.scrollable);\r\n this.avatars.setPeer(this.peerId);\r\n this.avatars.info.append(this.name, this.subtitle);\r\n \r\n this.avatar.remove();\r\n \r\n if(oldAvatars) oldAvatars.container.replaceWith(this.avatars.container);\r\n else this.element.prepend(this.avatars.container);\r\n\r\n if(PARALLAX_SUPPORTED) {\r\n this.scrollable.container.classList.add('parallax');\r\n }\r\n\r\n return;\r\n }\r\n }\r\n\r\n if(PARALLAX_SUPPORTED) {\r\n this.scrollable.container.classList.remove('parallax');\r\n }\r\n\r\n if(this.avatars) {\r\n this.avatars.container.remove();\r\n this.avatars = undefined;\r\n }\r\n\r\n this.avatar.setAttribute('peer', '' + this.peerId);\r\n\r\n this.section.content.prepend(this.avatar, this.name, this.subtitle);\r\n }\r\n\r\n public fillProfileElements() {\r\n if(!this.cleaned) return;\r\n this.cleaned = false;\r\n \r\n const peerId = this.peerId;\r\n\r\n this.cleanupHTML();\r\n\r\n this.setAvatar();\r\n\r\n // username\r\n if(peerId !== rootScope.myId) {\r\n let username = appPeersManager.getPeerUsername(peerId);\r\n if(username) {\r\n setText(appPeersManager.getPeerUsername(peerId), this.username);\r\n }\r\n \r\n const muted = appNotificationsManager.isPeerLocalMuted(peerId, false);\r\n this.notifications.checkboxField.checked = !muted;\r\n } else {\r\n window.requestAnimationFrame(() => {\r\n this.notifications.container.style.display = 'none';\r\n });\r\n }\r\n \r\n //let membersLi = this.profileTabs.firstElementChild.children[0] as HTMLLIElement;\r\n if(peerId > 0) {\r\n //membersLi.style.display = 'none';\r\n\r\n let user = appUsersManager.getUser(peerId);\r\n if(user.phone && peerId !== rootScope.myId) {\r\n setText(appUsersManager.formatUserPhone(user.phone), this.phone);\r\n }\r\n }/* else {\r\n //membersLi.style.display = appPeersManager.isBroadcast(peerId) ? 'none' : '';\r\n } */\r\n\r\n this.setBio();\r\n\r\n replaceContent(this.name, new PeerTitle({\r\n peerId,\r\n dialog: true\r\n }).element);\r\n\r\n this.setPeerStatus(true);\r\n }\r\n\r\n public setBio(override?: true) {\r\n if(this.setBioTimeout) {\r\n window.clearTimeout(this.setBioTimeout);\r\n this.setBioTimeout = 0;\r\n }\r\n\r\n const peerId = this.peerId;\r\n const threadId = this.threadId;\r\n\r\n if(!peerId) {\r\n return;\r\n }\r\n\r\n let promise: Promise<boolean>;\r\n if(peerId > 0) {\r\n promise = appProfileManager.getProfile(peerId, override).then(userFull => {\r\n if(this.peerId !== peerId || this.threadId !== threadId) {\r\n //this.log.warn('peer changed');\r\n return false;\r\n }\r\n \r\n if(userFull.rAbout && peerId !== rootScope.myId) {\r\n setText(userFull.rAbout, this.bio);\r\n }\r\n \r\n //this.log('userFull', userFull);\r\n return true;\r\n });\r\n } else {\r\n promise = appProfileManager.getChatFull(-peerId, override).then((chatFull) => {\r\n if(this.peerId !== peerId || this.threadId !== threadId) {\r\n //this.log.warn('peer changed');\r\n return false;\r\n }\r\n \r\n //this.log('chatInfo res 2:', chatFull);\r\n \r\n if(chatFull.about) {\r\n setText(RichTextProcessor.wrapRichText(chatFull.about), this.bio);\r\n }\r\n\r\n return true;\r\n });\r\n }\r\n\r\n promise.then((canSetNext) => {\r\n if(canSetNext) {\r\n this.setBioTimeout = window.setTimeout(() => this.setBio(true), 60e3);\r\n }\r\n });\r\n }\r\n\r\n public setPeer(peerId: number, threadId = 0) {\r\n if(this.peerId === peerId && this.threadId === peerId) return;\r\n\r\n if(this.init) {\r\n this.init();\r\n }\r\n\r\n this.peerId = peerId;\r\n this.threadId = threadId;\r\n \r\n this.cleaned = true;\r\n }\r\n}\r\n\r\n// TODO: отредактированное сообщение не изменится\r\nexport default class AppSharedMediaTab extends SliderSuperTab {\r\n private editBtn: HTMLElement;\r\n\r\n private peerId = 0;\r\n private threadId = 0;\r\n\r\n private historiesStorage: {\r\n [peerId: number]: Partial<{\r\n [type in SearchSuperType]: {mid: number, peerId: number}[]\r\n }>\r\n } = {};\r\n\r\n private searchSuper: AppSearchSuper;\r\n\r\n private profile: PeerProfile;\r\n peerChanged: boolean;\r\n\r\n constructor(slider: SidebarSlider) {\r\n super(slider, false);\r\n }\r\n\r\n public init() {\r\n //const perf = performance.now();\r\n\r\n this.container.classList.add('shared-media-container', 'profile-container');\r\n\r\n // * header\r\n const newCloseBtn = Button('btn-icon sidebar-close-button', {noRipple: true});\r\n this.closeBtn.replaceWith(newCloseBtn);\r\n this.closeBtn = newCloseBtn;\r\n\r\n const animatedCloseIcon = document.createElement('div');\r\n animatedCloseIcon.classList.add('animated-close-icon');\r\n newCloseBtn.append(animatedCloseIcon);\r\n\r\n const transitionContainer = document.createElement('div');\r\n transitionContainer.className = 'transition slide-fade';\r\n \r\n const transitionFirstItem = document.createElement('div');\r\n transitionFirstItem.classList.add('transition-item');\r\n\r\n this.title.append(i18n('Profile'));\r\n this.editBtn = ButtonIcon('edit');\r\n //const moreBtn = ButtonIcon('more');\r\n\r\n transitionFirstItem.append(this.title, this.editBtn/* , moreBtn */);\r\n\r\n const transitionLastItem = document.createElement('div');\r\n transitionLastItem.classList.add('transition-item');\r\n\r\n const secondTitle: HTMLElement = this.title.cloneNode() as any;\r\n secondTitle.append(i18n('PeerInfo.SharedMedia'));\r\n\r\n transitionLastItem.append(secondTitle);\r\n\r\n transitionContainer.append(transitionFirstItem, transitionLastItem);\r\n\r\n this.header.append(transitionContainer);\r\n\r\n // * body\r\n\r\n this.profile = new PeerProfile(this.scrollable);\r\n this.profile.init();\r\n \r\n this.scrollable.append(this.profile.element);\r\n\r\n const HEADER_HEIGHT = 56;\r\n this.scrollable.onAdditionalScroll = () => {\r\n const rect = this.searchSuper.nav.getBoundingClientRect(); \r\n if(!rect.width) return;\r\n\r\n const top = rect.top - 1;\r\n const isSharedMedia = top <= HEADER_HEIGHT;\r\n animatedCloseIcon.classList.toggle('state-back', isSharedMedia);\r\n this.searchSuper.container.classList.toggle('is-full-viewport', isSharedMedia);\r\n transition(+isSharedMedia);\r\n\r\n if(!isSharedMedia) {\r\n this.searchSuper.cleanScrollPositions();\r\n }\r\n };\r\n\r\n const transition = TransitionSlider(transitionContainer, 'slide-fade', 400, null, false);\r\n\r\n transition(0);\r\n\r\n attachClickEvent(this.closeBtn, (e) => {\r\n if(this.closeBtn.firstElementChild.classList.contains('state-back')) {\r\n this.scrollable.scrollIntoViewNew(this.scrollable.container.firstElementChild as HTMLElement, 'start');\r\n transition(0);\r\n animatedCloseIcon.classList.remove('state-back');\r\n } else if(!this.scrollable.isHeavyAnimationInProgress) {\r\n appSidebarRight.onCloseBtnClick();\r\n }\r\n });\r\n\r\n attachClickEvent(this.editBtn, (e) => {\r\n let tab: AppEditChatTab | AppEditContactTab;\r\n if(this.peerId < 0) {\r\n tab = new AppEditChatTab(appSidebarRight);\r\n } else {\r\n tab = new AppEditContactTab(appSidebarRight);\r\n }\r\n\r\n if(tab) {\r\n if(tab instanceof AppEditChatTab) {\r\n tab.chatId = -this.peerId;\r\n } else {\r\n tab.peerId = this.peerId;\r\n }\r\n \r\n tab.open();\r\n }\r\n });\r\n\r\n //this.container.prepend(this.closeBtn.parentElement);\r\n\r\n this.searchSuper = new AppSearchSuper({\r\n mediaTabs: [{\r\n inputFilter: 'inputMessagesFilterEmpty',\r\n name: 'PeerMedia.Members',\r\n type: 'members'\r\n }, {\r\n inputFilter: 'inputMessagesFilterPhotoVideo',\r\n name: 'SharedMediaTab2',\r\n type: 'media'\r\n }, {\r\n inputFilter: 'inputMessagesFilterDocument',\r\n name: 'SharedFilesTab2',\r\n type: 'files'\r\n }, {\r\n inputFilter: 'inputMessagesFilterUrl',\r\n name: 'SharedLinksTab2',\r\n type: 'links'\r\n }, {\r\n inputFilter: 'inputMessagesFilterMusic',\r\n name: 'SharedMusicTab2',\r\n type: 'music'\r\n }, {\r\n inputFilter: 'inputMessagesFilterVoice',\r\n name: 'SharedVoiceTab2',\r\n type: 'voice'\r\n }], \r\n scrollable: this.scrollable,\r\n onChangeTab: (mediaTab) => {\r\n let timeout = mediaTab.type === 'members' && rootScope.settings.animationsEnabled ? 250 : 0;\r\n setTimeout(() => {\r\n btnAddMembers.classList.toggle('is-hidden', mediaTab.type !== 'members');\r\n }, timeout);\r\n }\r\n });\r\n\r\n this.profile.element.append(this.searchSuper.container);\r\n\r\n const btnAddMembers = ButtonCorner({icon: 'addmember_filled'});\r\n this.content.append(btnAddMembers);\r\n\r\n btnAddMembers.addEventListener('click', () => {\r\n const id = -this.peerId;\r\n const isChannel = appChatsManager.isChannel(id);\r\n\r\n const showConfirmation = (peerIds: number[], callback: (checked: PopupPeerButtonCallbackCheckboxes) => void) => {\r\n let titleLangKey: LangPackKey, titleLangArgs: any[],\r\n descriptionLangKey: LangPackKey, descriptionLangArgs: any[],\r\n checkboxes: PopupPeerCheckboxOptions[];\r\n\r\n if(peerIds.length > 1) {\r\n titleLangKey = 'AddMembersAlertTitle';\r\n titleLangArgs = [i18n('Members', [peerIds.length])];\r\n descriptionLangKey = 'AddMembersAlertCountText';\r\n descriptionLangArgs = peerIds.map(peerId => {\r\n const b = document.createElement('b');\r\n b.append(new PeerTitle({peerId}).element);\r\n return b;\r\n });\r\n\r\n if(!isChannel) {\r\n checkboxes = [{\r\n text: 'AddMembersForwardMessages',\r\n checked: true\r\n }];\r\n }\r\n } else {\r\n titleLangKey = 'AddOneMemberAlertTitle';\r\n descriptionLangKey = 'AddMembersAlertNamesText';\r\n const b = document.createElement('b');\r\n b.append(new PeerTitle({\r\n peerId: peerIds[0]\r\n }).element);\r\n descriptionLangArgs = [b];\r\n\r\n if(!isChannel) {\r\n checkboxes = [{\r\n text: 'AddOneMemberForwardMessages',\r\n textArgs: [new PeerTitle({\r\n peerId: peerIds[0],\r\n onlyFirstName: true\r\n }).element],\r\n checked: true\r\n }];\r\n }\r\n }\r\n\r\n descriptionLangArgs.push(new PeerTitle({\r\n peerId: -id\r\n }).element);\r\n\r\n new PopupPeer('popup-add-members', {\r\n peerId: -id,\r\n titleLangKey,\r\n descriptionLangKey,\r\n descriptionLangArgs,\r\n buttons: [{\r\n langKey: 'Add',\r\n callback\r\n }],\r\n checkboxes\r\n }).show();\r\n };\r\n\r\n const onError = (err: any) => {\r\n if(err.type === 'USER_PRIVACY_RESTRICTED') {\r\n toastNew({langPackKey: 'InviteToGroupError'});\r\n }\r\n };\r\n \r\n if(isChannel) {\r\n const tab = new AppAddMembersTab(this.slider);\r\n tab.open({\r\n peerId: this.peerId,\r\n type: 'channel',\r\n skippable: false,\r\n takeOut: (peerIds) => {\r\n showConfirmation(peerIds, () => {\r\n const promise = appChatsManager.inviteToChannel(id, peerIds);\r\n promise.catch(onError);\r\n tab.attachToPromise(promise);\r\n });\r\n\r\n return false;\r\n },\r\n title: 'GroupAddMembers',\r\n placeholder: 'SendMessageTo'\r\n });\r\n } else {\r\n new PopupPickUser({\r\n peerTypes: ['contacts'],\r\n placeholder: 'Search',\r\n onSelect: (peerId) => {\r\n setTimeout(() => {\r\n showConfirmation([peerId], (checked) => {\r\n appChatsManager.addChatUser(id, peerId, checked.size ? undefined : 0)\r\n .catch(onError);\r\n });\r\n }, 0);\r\n },\r\n });\r\n }\r\n });\r\n\r\n //console.log('construct shared media time:', performance.now() - perf);\r\n }\r\n\r\n public renderNewMessages(peerId: number, mids: number[]) {\r\n if(this.init) return; // * not inited yet\r\n\r\n if(!this.historiesStorage[peerId]) return;\r\n \r\n mids = mids.slice().reverse(); // ! because it will be ascend sorted array\r\n for(const mediaTab of this.searchSuper.mediaTabs) {\r\n const inputFilter = mediaTab.inputFilter;\r\n const filtered = this.searchSuper.filterMessagesByType(mids.map(mid => appMessagesManager.getMessageByPeer(peerId, mid)), inputFilter);\r\n if(filtered.length) {\r\n if(this.historiesStorage[peerId][inputFilter]) {\r\n this.historiesStorage[peerId][inputFilter].unshift(...filtered.map(message => ({mid: message.mid, peerId: message.peerId})));\r\n }\r\n\r\n if(this.peerId === peerId && this.searchSuper.usedFromHistory[inputFilter] !== -1) {\r\n this.searchSuper.usedFromHistory[inputFilter] += filtered.length;\r\n this.searchSuper.performSearchResult(filtered, mediaTab, false);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n }\r\n\r\n public deleteDeletedMessages(peerId: number, mids: number[]) {\r\n if(this.init) return; // * not inited yet\r\n\r\n if(!this.historiesStorage[peerId]) return;\r\n\r\n for(const mid of mids) {\r\n for(const type of this.searchSuper.mediaTabs) {\r\n const inputFilter = type.inputFilter;\r\n\r\n if(!this.historiesStorage[peerId][inputFilter]) continue;\r\n\r\n const history = this.historiesStorage[peerId][inputFilter];\r\n const idx = history.findIndex(m => m.mid === mid);\r\n if(idx !== -1) {\r\n history.splice(idx, 1);\r\n\r\n if(this.peerId === peerId) {\r\n const container = this.searchSuper.tabs[inputFilter];\r\n const div = container.querySelector(`div[data-mid=\"${mid}\"][data-peer-id=\"${peerId}\"]`);\r\n if(div) {\r\n div.remove();\r\n }\r\n \r\n if(this.searchSuper.usedFromHistory[inputFilter] >= (idx + 1)) {\r\n this.searchSuper.usedFromHistory[inputFilter]--;\r\n }\r\n }\r\n\r\n break;\r\n }\r\n }\r\n }\r\n\r\n this.scrollable.onScroll();\r\n }\r\n\r\n public cleanupHTML() {\r\n // const perf = performance.now();\r\n this.profile.cleanupHTML();\r\n \r\n this.editBtn.style.display = 'none';\r\n\r\n this.searchSuper.cleanupHTML(true);\r\n\r\n this.container.classList.toggle('can-add-members', this.searchSuper.canViewMembers() && appChatsManager.hasRights(-this.peerId, 'invite_users'));\r\n\r\n // console.log('cleanupHTML shared media time:', performance.now() - perf);\r\n }\r\n\r\n public setLoadMutex(promise: Promise<any>) {\r\n this.searchSuper.loadMutex = promise;\r\n }\r\n\r\n public setPeer(peerId: number, threadId = 0) {\r\n if(this.peerId === peerId && this.threadId === threadId) return false;\r\n\r\n this.peerId = peerId;\r\n this.threadId = threadId;\r\n this.peerChanged = true;\r\n\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n this.searchSuper.setQuery({\r\n peerId, \r\n //threadId, \r\n historyStorage: this.historiesStorage[peerId] ?? (this.historiesStorage[peerId] = {})\r\n });\r\n\r\n this.profile.setPeer(peerId, threadId);\r\n \r\n return true;\r\n }\r\n\r\n public fillProfileElements() {\r\n if(!this.peerChanged) {\r\n return;\r\n }\r\n\r\n this.peerChanged = false;\r\n\r\n this.cleanupHTML();\r\n\r\n this.profile.fillProfileElements();\r\n\r\n if(this.peerId > 0) {\r\n if(this.peerId !== rootScope.myId && appUsersManager.isContact(this.peerId)) {\r\n this.editBtn.style.display = '';\r\n }\r\n } else {\r\n const chat: Chat = appChatsManager.getChat(-this.peerId);\r\n if((chat._ === 'chat' || (chat as Chat.channel).admin_rights) && !(chat as Chat.chat).pFlags.deactivated) {\r\n this.editBtn.style.display = '';\r\n }\r\n }\r\n }\r\n\r\n public loadSidebarMedia(single: boolean, justLoad = false) {\r\n this.searchSuper.load(single, justLoad);\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n this.scrollable.onScroll();\r\n }\r\n}\r\n\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.AppSharedMediaTab = AppSharedMediaTab);\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 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\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 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 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 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 { isTouchSupported } from \"../helpers/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\n\r\nlet lineTotalLength = 0;\r\n//const 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\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 }, isTouchSupported ? 5000 : 7000);\r\n};\r\n\r\nexport default class PollElement extends HTMLElement {\r\n private 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 maxOffset = -46.5;\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 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 }\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 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 ${mediaSizes.active.regular.width} 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 //this.maxLength = width + tailLength + this.maxOffset + -13.7; // 13 - position left\r\n\r\n if(poll.chosenIndexes.length || this.isClosed) {\r\n this.performResults(results, poll.chosenIndexes, false);\r\n } else if(!this.isClosed) {\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\" 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 this.sendVoteBtn.classList.toggle('hide', !!this.chosenIndexes.length);\r\n if(!this.chosenIndexes.length) {\r\n this.votersCountDiv.classList.add('hide');\r\n this.viewResults.classList.add('hide');\r\n } else if(this.isPublic) {\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 } else {\r\n this.votersCountDiv.classList.toggle('hide', !this.chosenIndexes.length);\r\n }\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 = (percents * this.maxLengths[index]) + ', 485.9';\r\n svg.style.strokeDasharray = (multiplier * this.maxPercents[index] * 100) + '%, 485.9';\r\n svg.style.strokeDashoffset = '' + multiplier * this.maxOffset;\r\n }\r\n }\r\n\r\n // у элемента могут быть ещё другие методы и свойства\r\n}\r\n\r\ncustomElements.define(\"poll-element\", PollElement);\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 { Document, InputFileLocation, InputStickerSet, MessagesAllStickers, MessagesFeaturedStickers, MessagesFoundStickerSets, MessagesRecentStickers, MessagesStickers, MessagesStickerSet, PhotoSize, StickerPack, StickerSet, StickerSetCovered } from '../../layer';\r\nimport { Modify } from '../../types';\r\nimport apiManager from '../mtproto/mtprotoworker';\r\nimport rootScope from '../rootScope';\r\nimport appDocsManager from './appDocsManager';\r\nimport AppStorage from '../storage';\r\nimport { MOUNT_CLASS_TO } from '../../config/debug';\r\nimport { forEachReverse } from '../../helpers/array';\r\nimport DATABASE_STATE from '../../config/databases/state';\r\n\r\nconst CACHE_TIME = 3600e3;\r\n\r\nexport type MyStickerSetInput = {\r\n id: string,\r\n access_hash?: string\r\n};\r\n\r\nexport class AppStickersManager {\r\n private storage = new AppStorage<Record<string, MessagesStickerSet>, typeof DATABASE_STATE>(DATABASE_STATE, 'stickerSets');\r\n\r\n private getStickerSetPromises: {[setId: string]: Promise<MessagesStickerSet>} = {};\r\n private getStickersByEmoticonsPromises: {[emoticon: string]: Promise<Document[]>} = {};\r\n\r\n private greetingStickers: Document.document[];\r\n private getGreetingStickersTimeout: number;\r\n private getGreetingStickersPromise: Promise<void>;\r\n \r\n constructor() {\r\n this.getStickerSet({id: 'emoji'}, {saveById: true});\r\n\r\n rootScope.addMultipleEventsListeners({\r\n updateNewStickerSet: (update) => {\r\n this.saveStickerSet(update.stickerset, update.stickerset.set.id);\r\n rootScope.dispatchEvent('stickers_installed', update.stickerset.set);\r\n }\r\n });\r\n\r\n this.getGreetingStickersTimeout = window.setTimeout(() => {\r\n this.getGreetingStickersTimeout = undefined;\r\n this.getGreetingSticker(true);\r\n }, 5000);\r\n }\r\n\r\n public getGreetingSticker(justPreload = false) {\r\n if(this.getGreetingStickersTimeout) {\r\n clearTimeout(this.getGreetingStickersTimeout);\r\n this.getGreetingStickersTimeout = undefined;\r\n }\r\n\r\n if(!this.getGreetingStickersPromise) {\r\n this.getGreetingStickersPromise = this.getStickersByEmoticon('👋⭐️', false).then(docs => {\r\n this.greetingStickers = docs.slice() as Document.document[];\r\n this.greetingStickers.sort((a, b) => Math.random() - Math.random());\r\n });\r\n }\r\n \r\n return this.getGreetingStickersPromise.then(() => {\r\n let doc: Document.document;\r\n if(!justPreload) {\r\n doc = this.greetingStickers.shift();\r\n this.greetingStickers.push(doc);\r\n }\r\n\r\n appDocsManager.downloadDoc(this.greetingStickers[0]); // preload next sticker\r\n\r\n return doc;\r\n });\r\n }\r\n\r\n public saveStickers(docs: Document[]) {\r\n forEachReverse(docs, (doc, idx) => {\r\n doc = appDocsManager.saveDoc(doc);\r\n\r\n if(!doc) docs.splice(idx, 1);\r\n else docs[idx] = doc;\r\n });\r\n }\r\n\r\n public async getStickerSet(set: MyStickerSetInput, params: Partial<{\r\n overwrite: boolean,\r\n useCache: boolean,\r\n saveById: boolean\r\n }> = {}): Promise<MessagesStickerSet> {\r\n const id = set.id;\r\n if(this.getStickerSetPromises[id]) {\r\n return this.getStickerSetPromises[id];\r\n }\r\n\r\n return this.getStickerSetPromises[id] = new Promise(async(resolve) => {\r\n if(!params.overwrite) {\r\n const cachedSet = await this.storage.get(id);\r\n if(cachedSet && cachedSet.documents?.length && ((Date.now() - cachedSet.refreshTime) < CACHE_TIME || params.useCache)) {\r\n this.saveStickers(cachedSet.documents);\r\n resolve(cachedSet);\r\n delete this.getStickerSetPromises[id];\r\n return;\r\n }\r\n }\r\n\r\n try {\r\n const stickerSet = await apiManager.invokeApi('messages.getStickerSet', {\r\n stickerset: this.getStickerSetInput(set)\r\n });\r\n \r\n const saveById = params.saveById ? id : stickerSet.set.id;\r\n this.saveStickerSet(stickerSet, saveById);\r\n \r\n resolve(stickerSet);\r\n } catch(err) {\r\n resolve(null);\r\n }\r\n \r\n delete this.getStickerSetPromises[id];\r\n });\r\n }\r\n\r\n public async getRecentStickers(): Promise<Modify<MessagesRecentStickers.messagesRecentStickers, {\r\n stickers: Document[]\r\n }>> {\r\n const res = await apiManager.invokeApiHashable('messages.getRecentStickers') as MessagesRecentStickers.messagesRecentStickers;\r\n\r\n this.saveStickers(res.stickers);\r\n\r\n return res;\r\n }\r\n\r\n public getAnimatedEmojiSticker(emoji: string) {\r\n const stickerSet = this.storage.getFromCache('emoji');\r\n if(!stickerSet || !stickerSet.documents) return undefined;\r\n\r\n emoji = emoji.replace(/\\ufe0f/g, '').replace(/🏻|🏼|🏽|🏾|🏿/g, '');\r\n const pack = stickerSet.packs.find(p => p.emoticon === emoji);\r\n return pack ? appDocsManager.getDoc(pack.documents[0]) : undefined;\r\n }\r\n \r\n public saveStickerSet(res: Omit<MessagesStickerSet.messagesStickerSet, '_'>, id: string) {\r\n //console.log('stickers save set', res);w\r\n\r\n const newSet: MessagesStickerSet = {\r\n _: 'messages.stickerSet',\r\n set: res.set,\r\n packs: res.packs,\r\n documents: res.documents as Document[]\r\n };\r\n \r\n let stickerSet = this.storage.getFromCache(id);\r\n if(stickerSet) {\r\n Object.assign(stickerSet, newSet);\r\n } else {\r\n stickerSet = this.storage.setToCache(id, newSet);\r\n }\r\n\r\n this.saveStickers(res.documents);\r\n \r\n //console.log('stickers wrote', this.stickerSets);\r\n const needSave = stickerSet.set.installed_date || id === 'emoji';\r\n stickerSet.refreshTime = Date.now();\r\n this.storage.set({[id]: stickerSet}, !needSave);\r\n }\r\n\r\n public getStickerSetThumbDownloadOptions(stickerSet: StickerSet.stickerSet) {\r\n const thumb = stickerSet.thumbs.find(thumb => thumb._ === 'photoSize') as PhotoSize.photoSize;\r\n const dcId = stickerSet.thumb_dc_id;\r\n\r\n const isAnimated = stickerSet.pFlags?.animated;\r\n\r\n const input: InputFileLocation.inputStickerSetThumb = {\r\n _: 'inputStickerSetThumb',\r\n stickerset: this.getStickerSetInput(stickerSet),\r\n thumb_version: stickerSet.thumb_version\r\n };\r\n\r\n return {dcId, location: input, size: thumb.size, mimeType: isAnimated ? 'application/x-tgsticker' : 'image/webp'};\r\n }\r\n\r\n /* public getStickerSetThumbURL(stickerSet: MTStickerSet) {\r\n const thumb = stickerSet.thumb;\r\n const dcId = stickerSet.thumb_dc_id;\r\n\r\n const isAnimated = stickerSet.pFlags?.animated;\r\n\r\n const input: inputStickerSetThumb = {\r\n _: 'inputStickerSetThumb',\r\n stickerset: this.getStickerSetInput(stickerSet),\r\n volume_id: thumb.location.volume_id,\r\n local_id: thumb.location.local_id\r\n };\r\n\r\n const url = getFileURL('document', this.getStickerSetThumbDownloadOptions(stickerSet));\r\n return url;\r\n\r\n //return promise;\r\n } */\r\n\r\n public getStickerSetInput(set: MyStickerSetInput): InputStickerSet {\r\n if(set.id === 'emoji') {\r\n return {\r\n _: 'inputStickerSetAnimatedEmoji'\r\n };\r\n } else if(!set.access_hash) {\r\n return {\r\n _: 'inputStickerSetShortName',\r\n short_name: set.id\r\n };\r\n } else {\r\n return {\r\n _: 'inputStickerSetID',\r\n id: set.id,\r\n access_hash: set.access_hash\r\n };\r\n }\r\n }\r\n\r\n public async getFeaturedStickers() {\r\n const res = await apiManager.invokeApiHashable('messages.getFeaturedStickers') as MessagesFeaturedStickers.messagesFeaturedStickers;\r\n \r\n res.sets.forEach(covered => {\r\n this.saveStickerSet({set: covered.set, documents: [], packs: []}, covered.set.id);\r\n });\r\n\r\n return res.sets;\r\n }\r\n\r\n public async toggleStickerSet(set: StickerSet.stickerSet) {\r\n if(set.installed_date) {\r\n const res = await apiManager.invokeApi('messages.uninstallStickerSet', {\r\n stickerset: this.getStickerSetInput(set)\r\n });\r\n\r\n if(res) {\r\n delete set.installed_date;\r\n rootScope.dispatchEvent('stickers_deleted', set);\r\n this.storage.delete(set.id, true);\r\n return true;\r\n }\r\n } else {\r\n const res = await apiManager.invokeApi('messages.installStickerSet', {\r\n stickerset: this.getStickerSetInput(set),\r\n archived: false\r\n });\r\n\r\n if(res) {\r\n set.installed_date = Date.now() / 1000 | 0;\r\n rootScope.dispatchEvent('stickers_installed', set);\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n public async searchStickerSets(query: string, excludeFeatured = true) {\r\n const flags = excludeFeatured ? 1 : 0;\r\n const res = await apiManager.invokeApiHashable('messages.searchStickerSets', {\r\n flags,\r\n exclude_featured: excludeFeatured || undefined,\r\n q: query\r\n }) as MessagesFoundStickerSets.messagesFoundStickerSets;\r\n\r\n res.sets.forEach(covered => {\r\n this.saveStickerSet({set: covered.set, documents: [], packs: []}, covered.set.id);\r\n });\r\n\r\n const foundSaved: StickerSetCovered[] = [];\r\n const cache = this.storage.getCache();\r\n for(let id in cache) {\r\n const {set} = cache[id];\r\n\r\n if(set.title.toLowerCase().includes(query.toLowerCase()) && !res.sets.find(c => c.set.id === set.id)) {\r\n foundSaved.push({_: 'stickerSetCovered', set, cover: null});\r\n }\r\n }\r\n\r\n return res.sets.concat(foundSaved);\r\n }\r\n\r\n public getAllStickers() {\r\n return apiManager.invokeApiHashable('messages.getAllStickers');\r\n }\r\n\r\n public preloadStickerSets() {\r\n return this.getAllStickers().then(allStickers => {\r\n return Promise.all((allStickers as MessagesAllStickers.messagesAllStickers).sets.map(set => this.getStickerSet(set, {useCache: true})));\r\n });\r\n }\r\n\r\n public getStickersByEmoticon(emoticon: string, includeOurStickers = true) {\r\n if(this.getStickersByEmoticonsPromises[emoticon]) return this.getStickersByEmoticonsPromises[emoticon];\r\n\r\n return this.getStickersByEmoticonsPromises[emoticon] = Promise.all([\r\n apiManager.invokeApiHashable('messages.getStickers', {\r\n emoticon\r\n }),\r\n includeOurStickers ? this.preloadStickerSets() : [],\r\n includeOurStickers ? this.getRecentStickers().then(res => res.packs) : []\r\n ]).then(([messagesStickers, installedSets, recentStickers]) => {\r\n const foundStickers = (messagesStickers as MessagesStickers.messagesStickers).stickers.map(sticker => appDocsManager.saveDoc(sticker));\r\n const cachedStickersAnimated: Document.document[] = [], cachedStickersStatic: Document.document[] = [];\r\n\r\n //console.log('getStickersByEmoticon', messagesStickers, installedSets, recentStickers);\r\n\r\n const iteratePacks = (packs: StickerPack.stickerPack[]) => {\r\n for(const pack of packs) {\r\n if(pack.emoticon.includes(emoticon)) {\r\n for(const docId of pack.documents) {\r\n const doc = appDocsManager.getDoc(docId);\r\n (doc.animated ? cachedStickersAnimated : cachedStickersStatic).push(doc);\r\n }\r\n }\r\n }\r\n };\r\n\r\n iteratePacks(recentStickers);\r\n\r\n for(const set of installedSets) {\r\n iteratePacks(set.packs);\r\n }\r\n\r\n const stickers = [...new Set(cachedStickersAnimated.concat(cachedStickersStatic, foundStickers))]/* .filter(doc => !doc.animated) */;\r\n\r\n return stickers;\r\n });\r\n }\r\n}\r\n\r\nconst appStickersManager = new AppStickersManager();\r\nMOUNT_CLASS_TO.appStickersManager = appStickersManager;\r\nexport default appStickersManager;\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/chat';\r\nimport { getEmojiToneIndex } from '../vendor/emoji';\r\nimport { readBlobAsText } from '../helpers/blob';\r\nimport { deferredPromise } from '../helpers/cancellablePromise';\r\nimport { formatDateAccordingToToday, months } from '../helpers/date';\r\nimport mediaSizes from '../helpers/mediaSizes';\r\nimport { formatBytes } from '../helpers/number';\r\nimport { isSafari } from '../helpers/userAgent';\r\nimport { 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 from './appMediaPlaybackController';\r\nimport AudioElement 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 { onVideoLoad } 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 } from '../helpers/dom/clickEvent';\r\nimport isInDOM from '../helpers/dom/isInDOM';\r\nimport lottieLoader from '../lib/lottieLoader';\r\n\r\nconst MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB\r\n\r\nexport function wrapVideo({doc, container, message, boxWidth, boxHeight, withTail, isOut, middleware, lazyLoadQueue, noInfo, group, onlyPreview, withoutPreloader, loadPromises, noPlayButton, noAutoDownload, size}: {\r\n doc: MyDocument, \r\n container?: HTMLElement, \r\n message?: any, \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}) {\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) {\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 globalVideo = appMediaPlaybackController.addMedia(message.peerId, doc, message.mid, !noAutoDownload) as HTMLVideoElement;\r\n \r\n const divRound = document.createElement('div');\r\n divRound.classList.add('media-round', 'z-depth-1');\r\n\r\n divRound.innerHTML = `<svg class=\"progress-ring\" width=\"200px\" height=\"200px\">\r\n <circle class=\"progress-ring__circle\" stroke=\"white\" stroke-opacity=\"0.3\" stroke-width=\"3.5\" cx=\"100\" cy=\"100\" r=\"93\" fill=\"transparent\" transform=\"rotate(-90, 100, 100)\"/>\r\n </svg>`;\r\n\r\n const circle = divRound.querySelector('.progress-ring__circle') as SVGCircleElement;\r\n const radius = circle.r.baseVal.value;\r\n const circumference = 2 * Math.PI * radius;\r\n circle.style.strokeDasharray = circumference + ' ' + circumference;\r\n circle.style.strokeDashoffset = '' + circumference;\r\n \r\n spanTime.classList.add('tgico');\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 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', onTimeUpdate);\r\n globalVideo.removeEventListener('pause', onPaused);\r\n });\r\n };\r\n\r\n const onFrame = () => {\r\n ctx.drawImage(globalVideo, 0, 0);\r\n\r\n const offset = circumference - globalVideo.currentTime / globalVideo.duration * circumference;\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) return;\r\n\r\n if(!isInDOM(globalVideo)) {\r\n clear();\r\n return;\r\n }\r\n\r\n spanTime.innerText = (globalVideo.duration - globalVideo.currentTime + '').toHHMMSS(false);\r\n };\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\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 globalVideo.addEventListener('play', onPlay);\r\n globalVideo.addEventListener('timeupdate', onTimeUpdate);\r\n globalVideo.addEventListener('pause', onPaused);\r\n\r\n attachClickEvent(canvas, (e) => {\r\n cancelEvent(e);\r\n\r\n if(globalVideo.paused) {\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) {\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 } 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 let preloader: ProgressivePreloader;\r\n if(message?.media?.preloader) { // means upload\r\n preloader = message.media.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 let f = 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) {\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(isSafari ? 'timeupdate' : 'canplay', () => {\r\n preloader.detach();\r\n }, {once: true});\r\n }\r\n }\r\n }\r\n\r\n video.addEventListener('error', (e) => {\r\n console.error(\"Error \" + video.error.code + \"; details: \" + video.error.message);\r\n preloader.detach();\r\n }, {once: true});\r\n\r\n if(!noAutoDownload && f) {\r\n f();\r\n f = null;\r\n }\r\n\r\n noAutoDownload = undefined;\r\n\r\n const deferred = deferredPromise<void>();\r\n loadPromise.then(() => {\r\n if(middleware && !middleware()) {\r\n deferred.resolve();\r\n return;\r\n }\r\n\r\n if(doc.type === 'round') {\r\n appMediaPlaybackController.resolveWaitingForLoadMedia(message.peerId, message.mid);\r\n }\r\n\r\n onVideoLoad(video).then(() => {\r\n if(group) {\r\n animationIntersector.addAnimation(video, group);\r\n }\r\n \r\n deferred.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.addEventListener('error', (e) => {\r\n deferred.resolve();\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 renderImageFromUrl(video, cacheContext.url);\r\n }, () => {});\r\n\r\n return {download: loadPromise, render: deferred};\r\n };\r\n\r\n if(preloader) {\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\nexport const formatDate = (timestamp: number, monthShort = false, withYear = true) => {\r\n const date = new Date(timestamp * 1000);\r\n \r\n let month = months[date.getMonth()];\r\n if(monthShort) month = month.slice(0, 3);\r\n\r\n let str = month + ' ' + date.getDate();\r\n if(withYear) {\r\n str += ', ' + date.getFullYear();\r\n }\r\n \r\n return str + ' at ' + date.getHours() + ':' + ('0' + date.getMinutes()).slice(-2);\r\n};\r\n\r\nexport function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showSender, searchContext, loadPromises, noAutoDownload}: {\r\n message: any, \r\n withTime?: boolean,\r\n fontWeight?: number,\r\n voiceAsMusic?: boolean,\r\n showSender?: boolean,\r\n searchContext?: SearchSuperContext,\r\n loadPromises?: Promise<any>[],\r\n noAutoDownload?: boolean,\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') {\r\n const audioElement = new AudioElement();\r\n audioElement.setAttribute('message-id', '' + message.mid);\r\n audioElement.setAttribute('peer-id', '' + message.peerId);\r\n audioElement.withTime = withTime;\r\n audioElement.message = message;\r\n audioElement.noAutoDownload = noAutoDownload;\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 \r\n if(uploading) {\r\n audioElement.preloader = message.media.preloader;\r\n }\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) ? extSplitted.pop().toLowerCase() : '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')) {\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 });\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.file_name || 'Unknown.file';\r\n let size = formatBytes(doc.size);\r\n \r\n if(withTime) {\r\n size += ' · ' + formatDate(doc.date);\r\n }\r\n\r\n if(showSender) {\r\n size += ' · ' + appMessagesManager.getSenderToPeerText(message);\r\n }\r\n\r\n let titleAdditionHTML = '';\r\n if(showSender) {\r\n titleAdditionHTML = `<div class=\"sent-time\">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;\r\n }\r\n \r\n docDiv.innerHTML = `\r\n ${cacheContext.downloaded && !uploading ? '' : `<div class=\"document-download\"></div>`}\r\n <div class=\"document-name\"><middle-ellipsis-element data-font-weight=\"${fontWeight}\">${fileName}</middle-ellipsis-element>${titleAdditionHTML}</div>\r\n <div class=\"document-size\">${size}</div>\r\n `;\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 = () => {\r\n const doc = appDocsManager.getDoc(docDiv.dataset.docId);\r\n let download: DownloadBlob;\r\n if(doc.type === 'pdf') {\r\n download = appDocsManager.downloadDoc(doc, appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : 0);\r\n download.then(() => {\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n window.open(cacheContext.url);\r\n });\r\n } else {\r\n download = appDocsManager.saveDocFile(doc, appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : 0);\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(!(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();\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}: {\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}) {\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 //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 if(needFadeIn) {\r\n image.classList.add('fade-in');\r\n }\r\n\r\n let preloader: ProgressivePreloader;\r\n if(message?.media?.preloader) { // means upload\r\n preloader = message.media.preloader;\r\n preloader.attach(container);\r\n noAutoDownload = undefined;\r\n } else {\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 noAutoDownload = undefined;\r\n\r\n return promise;\r\n };\r\n\r\n const onLoad = (): Promise<void> => {\r\n if(middleware && !middleware()) return Promise.resolve();\r\n\r\n return new Promise((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, cacheContext.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 let loadPromise: Promise<any>;\r\n const load = () => {\r\n if(noAutoDownload && !withoutPreloader) {\r\n preloader.construct();\r\n preloader.setManual();\r\n }\r\n\r\n const promise = getDownloadPromise();\r\n\r\n if(!cacheContext.downloaded && !withoutPreloader && (size as PhotoSize.photoSize).w >= 150 && (size as PhotoSize.photoSize).h >= 150) {\r\n preloader.attach(container, false, promise);\r\n }\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 preloader.setDownloadFunction(load);\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 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((webpWorkerController.isWebpSupported() || 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: string | HTMLElement, subtitle: string | HTMLElement, 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}: {\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}) {\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 });\r\n\r\n const container = document.createElement('div');\r\n container.classList.add('document-container');\r\n container.dataset.mid = '' + mid;\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(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","/*\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 appDialogsManager, { DialogDom } from \"../lib/appManagers/appDialogsManager\";\r\nimport { getHeavyAnimationPromise } from \"../hooks/useHeavyAnimationCheck\";\r\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\r\nimport { insertInDescendSortedArray } from \"../helpers/array\";\r\nimport isInDOM from \"../helpers/dom/isInDOM\";\r\nimport positionElementByIndex from \"../helpers/dom/positionElementByIndex\";\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\n\r\ntype SortedUser = {\r\n peerId: number, \r\n status: number, \r\n dom: DialogDom\r\n};\r\nexport default class SortedUserList {\r\n public static SORT_INTERVAL = 30e3;\r\n public list: HTMLUListElement;\r\n public users: Map<number, SortedUser>;\r\n public sorted: Array<SortedUser>;\r\n public lazyLoadQueue: LazyLoadQueueIntersector;\r\n\r\n constructor() {\r\n this.list = appDialogsManager.createChatList();\r\n\r\n this.users = new Map();\r\n this.sorted = [];\r\n\r\n let timeout: number;\r\n const doTimeout = () => {\r\n timeout = window.setTimeout(() => {\r\n this.updateList().then((good) => {\r\n if(good) {\r\n doTimeout();\r\n }\r\n });\r\n }, SortedUserList.SORT_INTERVAL);\r\n };\r\n\r\n doTimeout();\r\n }\r\n\r\n public async updateList() {\r\n if(!isInDOM(this.list)) {\r\n return false;\r\n }\r\n\r\n await getHeavyAnimationPromise();\r\n\r\n if(!isInDOM(this.list)) {\r\n return false;\r\n }\r\n\r\n this.users.forEach(user => {\r\n this.update(user.peerId, true);\r\n });\r\n\r\n this.sorted.forEach((sortedUser, idx) => {\r\n positionElementByIndex(sortedUser.dom.listEl, this.list, idx);\r\n });\r\n\r\n return true;\r\n }\r\n\r\n public add(peerId: number) {\r\n if(this.users.has(peerId)) {\r\n return;\r\n }\r\n\r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId,\r\n container: false,\r\n drawStatus: false,\r\n avatarSize: 48,\r\n autonomous: true,\r\n meAsSaved: false,\r\n rippleEnabled: false,\r\n lazyLoadQueue: this.lazyLoadQueue\r\n });\r\n\r\n const sortedUser: SortedUser = {\r\n peerId,\r\n status: appUsersManager.getUserStatusForSort(peerId),\r\n dom\r\n };\r\n\r\n this.users.set(peerId, sortedUser);\r\n this.update(peerId);\r\n }\r\n\r\n public update(peerId: number, batch = false) {\r\n const sortedUser = this.users.get(peerId);\r\n sortedUser.status = appUsersManager.getUserStatusForSort(peerId);\r\n const status = appUsersManager.getUserStatusString(peerId);\r\n replaceContent(sortedUser.dom.lastMessageSpan, status);\r\n\r\n const idx = insertInDescendSortedArray(this.sorted, sortedUser, 'status');\r\n if(!batch) {\r\n positionElementByIndex(sortedUser.dom.listEl, this.list, idx);\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 { formatDateAccordingToToday, months } from \"../helpers/date\";\r\nimport { copy, getObjectKeysAndSort, safeAssign } from \"../helpers/object\";\r\nimport { escapeRegExp, limitSymbols } from \"../helpers/string\";\r\nimport appChatsManager from \"../lib/appManagers/appChatsManager\";\r\nimport appDialogsManager from \"../lib/appManagers/appDialogsManager\";\r\nimport appMessagesManager, { MyInputMessagesFilter, MyMessage } from \"../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\r\nimport appStateManager from \"../lib/appManagers/appStateManager\";\r\nimport appUsersManager from \"../lib/appManagers/appUsersManager\";\r\nimport { logger } from \"../lib/logger\";\r\nimport RichTextProcessor from \"../lib/richtextprocessor\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport AppMediaViewer from \"./appMediaViewer\";\r\nimport { SearchGroup, SearchGroupType } from \"./appSearch\";\r\nimport { horizontalMenu } from \"./horizontalMenu\";\r\nimport LazyLoadQueue from \"./lazyLoadQueue\";\r\nimport { putPreloader, formatPhoneNumber } from \"./misc\";\r\nimport { ripple } from \"./ripple\";\r\nimport Scrollable, { ScrollableX } from \"./scrollable\";\r\nimport { wrapDocument, wrapPhoto, wrapVideo } from \"./wrappers\";\r\nimport useHeavyAnimationCheck, { getHeavyAnimationPromise } from \"../hooks/useHeavyAnimationCheck\";\r\nimport { isSafari } from \"../helpers/userAgent\";\r\nimport { LangPackKey, i18n } from \"../lib/langPack\";\r\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\r\nimport { getMiddleware } from \"../helpers/middleware\";\r\nimport appProfileManager from \"../lib/appManagers/appProfileManager\";\r\nimport { ChannelParticipant, ChatFull, ChatParticipant, ChatParticipants } from \"../layer\";\r\nimport SortedUserList from \"./sortedUserList\";\r\nimport findUpTag from \"../helpers/dom/findUpTag\";\r\nimport appSidebarRight from \"./sidebarRight\";\r\nimport mediaSizes from \"../helpers/mediaSizes\";\r\nimport appImManager from \"../lib/appManagers/appImManager\";\r\nimport positionElementByIndex from \"../helpers/dom/positionElementByIndex\";\r\nimport cleanSearchText from \"../helpers/cleanSearchText\";\r\n\r\n//const testScroll = false;\r\n\r\nexport type SearchSuperType = MyInputMessagesFilter/* | 'members' */;\r\nexport type SearchSuperContext = {\r\n peerId: number,\r\n inputFilter: MyInputMessagesFilter,\r\n query?: string,\r\n maxId?: number,\r\n folderId?: number,\r\n threadId?: number,\r\n date?: number,\r\n nextRate?: number,\r\n minDate?: number,\r\n maxDate?: number\r\n};\r\n\r\nexport type SearchSuperMediaType = 'members' | 'media' | 'files' | 'links' | 'music' | 'chats' | 'voice';\r\nexport type SearchSuperMediaTab = {\r\n inputFilter: SearchSuperType,\r\n name: LangPackKey,\r\n type: SearchSuperMediaType,\r\n contentTab?: HTMLElement,\r\n menuTab?: HTMLElement,\r\n scroll?: {scrollTop: number, scrollHeight: number}\r\n};\r\n\r\nexport default class AppSearchSuper {\r\n public tabs: {[t in SearchSuperType]: HTMLDivElement} = {} as any;\r\n\r\n public mediaTab: SearchSuperMediaTab;\r\n\r\n public container: HTMLElement;\r\n public nav: HTMLElement;\r\n private navScrollableContainer: HTMLDivElement;\r\n private tabsContainer: HTMLElement;\r\n private tabsMenu: HTMLElement;\r\n private prevTabId = -1;\r\n \r\n private lazyLoadQueue = new LazyLoadQueue();\r\n public middleware = getMiddleware();\r\n\r\n public historyStorage: Partial<{[type in SearchSuperType]: {mid: number, peerId: number}[]}> = {};\r\n public usedFromHistory: Partial<{[type in SearchSuperType]: number}> = {};\r\n public urlsToRevoke: string[] = [];\r\n\r\n private searchContext: SearchSuperContext;\r\n public loadMutex: Promise<any> = Promise.resolve();\r\n\r\n private nextRates: Partial<{[type in SearchSuperType]: number}> = {};\r\n private loadPromises: Partial<{[type in SearchSuperType]: Promise<void>}> = {};\r\n private loaded: Partial<{[type in SearchSuperType]: boolean}> = {};\r\n private loadedChats = false;\r\n private firstLoad = true;\r\n\r\n private log = logger('SEARCH-SUPER');\r\n public selectTab: ReturnType<typeof horizontalMenu>;\r\n \r\n private monthContainers: Partial<{\r\n [type in SearchSuperType]: {\r\n [timestamp: number]: {\r\n container: HTMLElement,\r\n items: HTMLElement\r\n }\r\n }\r\n }> = {};\r\n\r\n private searchGroupMedia: SearchGroup;\r\n\r\n public mediaTabsMap: Map<SearchSuperMediaType, SearchSuperMediaTab> = new Map();\r\n\r\n private membersList: SortedUserList;\r\n\r\n private skipScroll: boolean;\r\n\r\n // * arguments\r\n public mediaTabs: SearchSuperMediaTab[];\r\n public scrollable: Scrollable;\r\n public searchGroups?: {[group in SearchGroupType]: SearchGroup};\r\n public asChatList? = false;\r\n public groupByMonth? = true;\r\n public hideEmptyTabs? = true;\r\n public onChangeTab?: (mediaTab: SearchSuperMediaTab) => void;\r\n public showSender? = false;\r\n\r\n constructor(options: Pick<AppSearchSuper, 'mediaTabs' | 'scrollable' | 'searchGroups' | 'asChatList' | 'groupByMonth' | 'hideEmptyTabs' | 'onChangeTab' | 'showSender'>) {\r\n safeAssign(this, options);\r\n\r\n this.container = document.createElement('div');\r\n this.container.classList.add('search-super');\r\n\r\n const navScrollableContainer = this.navScrollableContainer = document.createElement('div');\r\n navScrollableContainer.classList.add('search-super-tabs-scrollable', 'menu-horizontal-scrollable', 'sticky');\r\n\r\n const navScrollable = new ScrollableX(navScrollableContainer);\r\n\r\n const nav = this.nav = document.createElement('nav');\r\n nav.classList.add('search-super-tabs', 'menu-horizontal-div');\r\n this.tabsMenu = nav;\r\n\r\n navScrollable.container.append(nav);\r\n\r\n for(const mediaTab of this.mediaTabs) {\r\n const menuTab = document.createElement('div');\r\n menuTab.classList.add('menu-horizontal-div-item');\r\n const span = document.createElement('span');\r\n const i = document.createElement('i');\r\n\r\n span.append(i18n(mediaTab.name));\r\n span.append(i);\r\n\r\n menuTab.append(span);\r\n\r\n ripple(menuTab);\r\n\r\n this.tabsMenu.append(menuTab);\r\n\r\n this.mediaTabsMap.set(mediaTab.type, mediaTab);\r\n\r\n mediaTab.menuTab = menuTab;\r\n }\r\n\r\n this.tabsContainer = document.createElement('div');\r\n this.tabsContainer.classList.add('search-super-tabs-container', 'tabs-container');\r\n\r\n for(const mediaTab of this.mediaTabs) {\r\n const container = document.createElement('div');\r\n container.classList.add('search-super-container-' + mediaTab.type);\r\n\r\n const content = document.createElement('div');\r\n content.classList.add('search-super-content-' + mediaTab.type);\r\n\r\n container.append(content);\r\n\r\n this.tabsContainer.append(container);\r\n\r\n this.tabs[mediaTab.inputFilter] = content;\r\n\r\n mediaTab.contentTab = content;\r\n }\r\n\r\n this.container.append(navScrollableContainer, this.tabsContainer);\r\n\r\n // * construct end\r\n\r\n this.searchGroupMedia = new SearchGroup(false, 'messages', true);\r\n\r\n this.scrollable.onScrolledBottom = () => {\r\n if(this.mediaTab.contentTab && this.mediaTab.contentTab.childElementCount/* && false */) {\r\n //this.log('onScrolledBottom will load media');\r\n this.load(true);\r\n }\r\n };\r\n //this.scroll.attachSentinels(undefined, 400);\r\n\r\n this.selectTab = horizontalMenu(this.tabsMenu, this.tabsContainer, (id, tabContent, animate) => {\r\n if(this.prevTabId === id && !this.skipScroll) {\r\n this.scrollable.scrollIntoViewNew(this.container, 'start');\r\n return;\r\n }\r\n \r\n const newMediaTab = this.mediaTabs[id];\r\n if(this.onChangeTab) {\r\n this.onChangeTab(newMediaTab);\r\n }\r\n \r\n const fromMediaTab = this.mediaTab;\r\n this.mediaTab = newMediaTab;\r\n\r\n if(this.prevTabId !== -1 && animate) {\r\n this.onTransitionStart();\r\n }\r\n\r\n if(this.skipScroll) {\r\n this.skipScroll = false;\r\n } else {\r\n const offsetTop = this.container.offsetTop;\r\n let scrollTop = this.scrollable.scrollTop;\r\n if(scrollTop < offsetTop) {\r\n this.scrollable.scrollIntoViewNew(this.container, 'start');\r\n scrollTop = offsetTop;\r\n }\r\n \r\n fromMediaTab.scroll = {scrollTop: scrollTop, scrollHeight: this.scrollable.scrollHeight};\r\n \r\n if(newMediaTab.scroll === undefined) {\r\n const rect = this.container.getBoundingClientRect();\r\n const rect2 = this.container.parentElement.getBoundingClientRect();\r\n const diff = rect.y - rect2.y;\r\n \r\n if(scrollTop > diff) {\r\n newMediaTab.scroll = {scrollTop: diff, scrollHeight: 0};\r\n }\r\n }\r\n \r\n if(newMediaTab.scroll) {\r\n const diff = fromMediaTab.scroll.scrollTop - newMediaTab.scroll.scrollTop;\r\n //console.log('what you gonna do', this.goingHard, diff);\r\n \r\n //this.scrollable.scrollTop = scrollTop;\r\n if(diff/* && diff < 0 */) {\r\n /* if(diff > -(fromMediaTab.contentTab.scrollHeight + this.nav.scrollHeight)) {\r\n fromMediaTab.contentTab.style.transform = `translateY(${diff}px)`;\r\n this.scrollable.scrollTop = scrollTop - diff;\r\n } else { */\r\n newMediaTab.contentTab.style.transform = `translateY(${diff}px)`;\r\n //}\r\n }\r\n }\r\n }\r\n \r\n /* if(this.prevTabId !== -1 && nav.offsetTop) {\r\n this.scrollable.scrollTop -= nav.offsetTop;\r\n } */\r\n\r\n /* this.log('setVirtualContainer', id, this.sharedMediaSelected, this.sharedMediaSelected.childElementCount);\r\n this.scroll.setVirtualContainer(this.sharedMediaSelected); */\r\n\r\n if(this.prevTabId !== -1 && !newMediaTab.contentTab.childElementCount) { // quick brown fix\r\n //this.contentContainer.classList.remove('loaded');\r\n this.load(true);\r\n }\r\n\r\n this.prevTabId = id;\r\n }, () => {\r\n this.scrollable.onScroll();\r\n \r\n //console.log('what y', this.tabSelected.style.transform);\r\n if(this.mediaTab.scroll !== undefined) {\r\n this.mediaTab.contentTab.style.transform = '';\r\n this.scrollable.scrollTop = this.mediaTab.scroll.scrollTop;\r\n }\r\n\r\n this.onTransitionEnd();\r\n }, undefined, navScrollable);\r\n\r\n this.tabs.inputMessagesFilterPhotoVideo.addEventListener('click', (e) => {\r\n const target = findUpClassName(e.target as HTMLDivElement, 'grid-item');\r\n \r\n const mid = +target.dataset.mid;\r\n if(!mid) {\r\n this.log.warn('no messageId by click on target:', target);\r\n return;\r\n }\r\n\r\n const peerId = +target.dataset.peerId;\r\n\r\n const targets = (Array.from(this.tabs.inputMessagesFilterPhotoVideo.querySelectorAll('.grid-item')) as HTMLElement[]).map(el => {\r\n return {element: el, mid: +el.dataset.mid, peerId: +el.dataset.peerId};\r\n });\r\n\r\n //const ids = Object.keys(this.mediaDivsByIds).map(k => +k).sort((a, b) => a - b);\r\n const idx = targets.findIndex(item => item.mid === mid && item.peerId === peerId);\r\n \r\n const message = appMessagesManager.getMessageByPeer(peerId, mid);\r\n new AppMediaViewer()\r\n .setSearchContext(this.copySearchContext(this.mediaTab.inputFilter))\r\n .openMedia(message, target, 0, false, targets.slice(0, idx), targets.slice(idx + 1));\r\n });\r\n\r\n this.mediaTab = this.mediaTabs[0];\r\n\r\n useHeavyAnimationCheck(() => {\r\n this.lazyLoadQueue.lock();\r\n }, () => {\r\n this.lazyLoadQueue.unlockAndRefresh(); // ! maybe not so efficient\r\n });\r\n }\r\n\r\n private onTransitionStart = () => {\r\n this.container.classList.add('sliding');\r\n };\r\n\r\n private onTransitionEnd = () => {\r\n this.container.classList.remove('sliding');\r\n };\r\n\r\n public filterMessagesByType(messages: any[], type: SearchSuperType): MyMessage[] {\r\n if(type === 'inputMessagesFilterEmpty') return messages;\r\n\r\n if(type !== 'inputMessagesFilterUrl') {\r\n messages = messages.filter(message => !!message.media);\r\n }\r\n\r\n /* if(!this.peerId) {\r\n messages = messages.filter(message => {\r\n if(message.peerId === rootScope.myId) {\r\n return true;\r\n }\r\n\r\n const dialog = appMessagesManager.getDialogByPeerId(message.fromId)[0];\r\n return dialog && dialog.folder_id === 0;\r\n });\r\n } */\r\n\r\n let filtered: any[] = [];\r\n\r\n switch(type) {\r\n case 'inputMessagesFilterPhotoVideo': {\r\n for(let message of messages) {\r\n let media = message.media.photo || message.media.document || (message.media.webpage && message.media.webpage.document);\r\n if(!media) {\r\n //this.log('no media!', message);\r\n continue;\r\n }\r\n \r\n if(media._ === 'document' && media.type !== 'video'/* && media.type !== 'gif' */) {\r\n //this.log('broken video', media);\r\n continue;\r\n }\r\n\r\n filtered.push(message);\r\n }\r\n \r\n break;\r\n }\r\n\r\n case 'inputMessagesFilterDocument': {\r\n for(let message of messages) {\r\n if(!message.media.document || ['voice', 'audio', 'gif', 'sticker', 'round'].includes(message.media.document.type)) {\r\n continue;\r\n }\r\n \r\n filtered.push(message);\r\n }\r\n break;\r\n }\r\n\r\n case 'inputMessagesFilterUrl': {\r\n //this.log('inputMessagesFilterUrl', messages);\r\n for(let message of messages) {\r\n //if((message.media.webpage && message.media.webpage._ !== 'webPageEmpty')) {\r\n filtered.push(message);\r\n //}\r\n }\r\n \r\n break;\r\n }\r\n\r\n case 'inputMessagesFilterMusic': {\r\n for(let message of messages) {\r\n if(!message.media.document || message.media.document.type !== 'audio') {\r\n continue;\r\n }\r\n\r\n filtered.push(message);\r\n }\r\n\r\n break;\r\n }\r\n\r\n case 'inputMessagesFilterVoice': {\r\n for(let message of messages) {\r\n if(!message.media.document || message.media.document.type !== 'voice') {\r\n continue;\r\n }\r\n\r\n filtered.push(message);\r\n }\r\n\r\n break;\r\n }\r\n\r\n default:\r\n break;\r\n }\r\n\r\n return filtered;\r\n }\r\n \r\n public async performSearchResult(messages: any[], mediaTab: SearchSuperMediaTab, append = true) {\r\n const elemsToAppend: {element: HTMLElement, message: any}[] = [];\r\n const sharedMediaDiv: HTMLElement = mediaTab.contentTab;\r\n const promises: Promise<any>[] = [];\r\n const middleware = this.middleware.get();\r\n let inputFilter = mediaTab.inputFilter;\r\n\r\n await getHeavyAnimationPromise();\r\n \r\n let searchGroup: SearchGroup;\r\n if(inputFilter === 'inputMessagesFilterPhotoVideo' && !!this.searchContext.query.trim()) {\r\n inputFilter = 'inputMessagesFilterEmpty';\r\n searchGroup = this.searchGroupMedia;\r\n sharedMediaDiv.append(searchGroup.container);\r\n } else if(inputFilter === 'inputMessagesFilterEmpty') {\r\n searchGroup = this.searchGroups.messages;\r\n }\r\n\r\n // https://core.telegram.org/type/MessagesFilter\r\n switch(inputFilter) {\r\n case 'inputMessagesFilterEmpty': {\r\n for(const message of messages) {\r\n const {dialog, dom} = appDialogsManager.addDialogNew({\r\n dialog: message.peerId, \r\n container: searchGroup.list, \r\n drawStatus: false,\r\n avatarSize: 54\r\n });\r\n appDialogsManager.setLastMessage(dialog, message, dom, this.searchContext.query);\r\n }\r\n\r\n if(searchGroup.list.childElementCount) {\r\n searchGroup.setActive();\r\n }\r\n break;\r\n }\r\n\r\n case 'inputMessagesFilterPhotoVideo': {\r\n for(const message of messages) {\r\n const media = message.media.photo || message.media.document || (message.media.webpage && message.media.webpage.document);\r\n\r\n const div = document.createElement('div');\r\n div.classList.add('grid-item');\r\n //this.log(message, photo);\r\n\r\n let wrapped: ReturnType<typeof wrapPhoto>;\r\n const size = appPhotosManager.choosePhotoSize(media, 200, 200);\r\n if(media._ !== 'photo') {\r\n wrapped = wrapVideo({\r\n doc: media,\r\n message,\r\n container: div,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n middleware,\r\n onlyPreview: true,\r\n withoutPreloader: true,\r\n noPlayButton: true,\r\n size\r\n }).thumb;\r\n } else {\r\n wrapped = wrapPhoto({\r\n photo: media,\r\n message,\r\n container: div,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n middleware,\r\n withoutPreloader: true,\r\n noBlur: true,\r\n size\r\n });\r\n }\r\n\r\n [wrapped.images.thumb, wrapped.images.full].filter(Boolean).forEach(image => {\r\n image.classList.add('grid-item-media');\r\n });\r\n\r\n promises.push(wrapped.loadPromises.thumb);\r\n\r\n elemsToAppend.push({element: div, message});\r\n }\r\n \r\n break;\r\n }\r\n \r\n case 'inputMessagesFilterVoice':\r\n case 'inputMessagesFilterMusic':\r\n case 'inputMessagesFilterDocument': {\r\n for(const message of messages) {\r\n const showSender = this.showSender || message.media.document.type === 'voice';\r\n const div = wrapDocument({\r\n message,\r\n withTime: !showSender,\r\n fontWeight: 400,\r\n voiceAsMusic: true,\r\n showSender: showSender,\r\n searchContext: this.copySearchContext(inputFilter)\r\n });\r\n\r\n if(['audio', 'voice'].includes(message.media.document.type)) {\r\n div.classList.add('audio-48');\r\n }\r\n\r\n elemsToAppend.push({element: div, message});\r\n }\r\n break;\r\n }\r\n \r\n case 'inputMessagesFilterUrl': {\r\n for(let message of messages) {\r\n let webpage: any;\r\n\r\n if(message.media?.webpage && message.media.webpage._ !== 'webPageEmpty') {\r\n webpage = message.media.webpage;\r\n } else {\r\n const entity = message.totalEntities ? message.totalEntities.find((e: any) => e._ === 'messageEntityUrl' || e._ === 'messageEntityTextUrl') : null;\r\n let url: string, display_url: string, sliced: string;\r\n\r\n if(!entity) {\r\n //this.log.error('NO ENTITY:', message);\r\n const match = RichTextProcessor.matchUrl(message.message);\r\n if(!match) {\r\n //this.log.error('NO ENTITY AND NO MATCH:', message);\r\n continue;\r\n }\r\n\r\n url = match[0];\r\n } else {\r\n sliced = message.message.slice(entity.offset, entity.offset + entity.length);\r\n }\r\n\r\n if(entity?._ === 'messageEntityTextUrl') {\r\n url = entity.url;\r\n //display_url = sliced;\r\n } else {\r\n url = url || sliced;\r\n }\r\n\r\n display_url = url;\r\n\r\n const same = message.message === url;\r\n if(!url.match(/^(ftp|http|https):\\/\\//)) {\r\n display_url = 'https://' + url;\r\n url = url.includes('@') ? url : 'https://' + url;\r\n }\r\n\r\n display_url = new URL(display_url).hostname;\r\n\r\n webpage = {\r\n url,\r\n display_url\r\n };\r\n\r\n if(!same) {\r\n webpage.description = message.message;\r\n webpage.rDescription = RichTextProcessor.wrapRichText(limitSymbols(message.message, 150, 180));\r\n }\r\n }\r\n\r\n let div = document.createElement('div');\r\n \r\n let previewDiv = document.createElement('div');\r\n previewDiv.classList.add('preview');\r\n \r\n //this.log('wrapping webpage', webpage);\r\n \r\n if(webpage.photo) {\r\n const res = wrapPhoto({\r\n container: previewDiv,\r\n message: null,\r\n photo: webpage.photo,\r\n boxWidth: 0,\r\n boxHeight: 0,\r\n withoutPreloader: true,\r\n lazyLoadQueue: this.lazyLoadQueue,\r\n middleware,\r\n size: appPhotosManager.choosePhotoSize(webpage.photo, 60, 60, false),\r\n loadPromises: promises,\r\n noBlur: true\r\n });\r\n } else {\r\n previewDiv.classList.add('empty');\r\n previewDiv.innerHTML = RichTextProcessor.getAbbreviation(webpage.title || webpage.display_url || webpage.description || webpage.url, true);\r\n }\r\n \r\n let title = webpage.rTitle || '';\r\n let subtitle = webpage.rDescription || '';\r\n let url = RichTextProcessor.wrapRichText(webpage.url || '');\r\n \r\n if(!title) {\r\n //title = new URL(webpage.url).hostname;\r\n title = RichTextProcessor.wrapPlainText(webpage.display_url.split('/', 1)[0]);\r\n }\r\n\r\n let sender = this.showSender ? `<div class=\"subtitle sender\">${appMessagesManager.getSenderToPeerText(message)}</div>` : '';\r\n\r\n let titleAdditionHTML = '';\r\n if(this.showSender) {\r\n titleAdditionHTML = `<div class=\"sent-time\">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;\r\n }\r\n\r\n div.append(previewDiv);\r\n div.insertAdjacentHTML('beforeend', `\r\n <div class=\"title\">${title}${titleAdditionHTML}</div>\r\n <div class=\"subtitle\">${subtitle}</div>\r\n <div class=\"url\">${url}</div>\r\n ${sender}\r\n `);\r\n \r\n if(div.innerText.trim().length) {\r\n elemsToAppend.push({element: div, message});\r\n }\r\n \r\n }\r\n \r\n break;\r\n }\r\n\r\n default:\r\n //this.log.warn('death is my friend', messages);\r\n break;\r\n }\r\n\r\n if(this.loadMutex) {\r\n promises.push(this.loadMutex);\r\n }\r\n\r\n if(promises.length) {\r\n await Promise.all(promises);\r\n if(!middleware()) {\r\n //this.log.warn('peer changed');\r\n return;\r\n }\r\n }\r\n \r\n if(elemsToAppend.length) {\r\n const method = append ? 'append' : 'prepend';\r\n elemsToAppend.forEach(details => {\r\n const {element, message} = details;\r\n const monthContainer = this.getMonthContainerByTimestamp(this.groupByMonth ? message.date : 0, inputFilter);\r\n element.classList.add('search-super-item');\r\n element.dataset.mid = '' + message.mid;\r\n element.dataset.peerId = '' + message.peerId;\r\n monthContainer.items[method](element);\r\n });\r\n }\r\n \r\n //if(type !== 'inputMessagesFilterEmpty') {\r\n this.afterPerforming(inputFilter === 'inputMessagesFilterEmpty' ? 1 : messages.length, sharedMediaDiv);\r\n //}\r\n }\r\n\r\n private afterPerforming(length: number, contentTab: HTMLElement) {\r\n if(contentTab) {\r\n const parent = contentTab.parentElement;\r\n Array.from(parent.children).slice(1).forEach(child => {\r\n child.remove();\r\n });\r\n\r\n //this.contentContainer.classList.add('loaded');\r\n\r\n if(!length && !contentTab.childElementCount) {\r\n const div = document.createElement('div');\r\n div.innerText = 'Nothing interesting here yet...';\r\n div.classList.add('position-center', 'text-center', 'content-empty', 'no-select');\r\n\r\n parent.append(div);\r\n }\r\n }\r\n }\r\n\r\n private loadChats() {\r\n const renderedPeerIds: Set<number> = new Set();\r\n const middleware = this.middleware.get();\r\n\r\n for(let i in this.searchGroups) {\r\n const group = this.searchGroups[i as SearchGroupType];\r\n this.tabs.inputMessagesFilterEmpty.append(group.container);\r\n group.clear();\r\n }\r\n\r\n const query = this.searchContext.query;\r\n if(query) {\r\n const setResults = (results: number[], group: SearchGroup, showMembersCount = false) => {\r\n results.forEach((peerId) => {\r\n if(renderedPeerIds.has(peerId)) {\r\n return;\r\n }\r\n \r\n renderedPeerIds.add(peerId);\r\n \r\n const peer = appPeersManager.getPeer(peerId);\r\n \r\n //////////this.log('contacts peer', peer);\r\n \r\n const {dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId, \r\n container: group.list, \r\n drawStatus: false,\r\n avatarSize: 48,\r\n autonomous: group.autonomous\r\n });\r\n \r\n if(showMembersCount && (peer.participants_count || peer.participants)) {\r\n const regExp = new RegExp(`(${escapeRegExp(query)}|${escapeRegExp(cleanSearchText(query))})`, 'gi');\r\n dom.titleSpan.innerHTML = dom.titleSpan.innerHTML.replace(regExp, '<i>$1</i>');\r\n dom.lastMessageSpan.append(appProfileManager.getChatMembersString(-peerId));\r\n } else if(peerId === rootScope.myId) {\r\n dom.lastMessageSpan.append(i18n('Presence.YourChat'));\r\n } else {\r\n let username = appPeersManager.getPeerUsername(peerId);\r\n if(!username) {\r\n const user = appUsersManager.getUser(peerId);\r\n if(user && user.phone) {\r\n username = '+' + formatPhoneNumber(user.phone).formatted;\r\n }\r\n } else {\r\n username = '@' + username;\r\n }\r\n \r\n dom.lastMessageSpan.innerHTML = '<i>' + username + '</i>';\r\n }\r\n });\r\n \r\n group.toggle();\r\n };\r\n \r\n const onLoad = <T>(arg: T) => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n \r\n //this.loadedContacts = true;\r\n \r\n return arg;\r\n };\r\n \r\n return Promise.all([\r\n appUsersManager.getContacts(query, true)\r\n .then(onLoad)\r\n .then((contacts) => {\r\n if(contacts) {\r\n setResults(contacts, this.searchGroups.contacts, true);\r\n }\r\n }),\r\n \r\n appUsersManager.searchContacts(query, 20)\r\n .then(onLoad)\r\n .then((contacts) => {\r\n if(contacts) {\r\n setResults(contacts.my_results, this.searchGroups.contacts, true);\r\n setResults(contacts.results/* .concat(contacts.results, contacts.results, contacts.results) */, this.searchGroups.globalContacts);\r\n\r\n if(this.searchGroups.globalContacts.nameEl.lastElementChild) {\r\n this.searchGroups.globalContacts.nameEl.lastElementChild.remove();\r\n }\r\n\r\n this.searchGroups.globalContacts.container.classList.add('is-short');\r\n \r\n if(this.searchGroups.globalContacts.list.childElementCount > 3) {\r\n const showMore = document.createElement('div');\r\n showMore.classList.add('search-group__show-more');\r\n showMore.innerText = 'Show more';\r\n this.searchGroups.globalContacts.nameEl.append(showMore);\r\n showMore.addEventListener('click', () => {\r\n const isShort = this.searchGroups.globalContacts.container.classList.toggle('is-short');\r\n showMore.innerText = isShort ? 'Show more' : 'Show less';\r\n });\r\n }\r\n }\r\n }),\r\n \r\n appMessagesManager.getConversations(query, 0, 20, 0)\r\n .then(onLoad)\r\n .then(value => {\r\n if(value) {\r\n setResults(value.dialogs.map(d => d.peerId), this.searchGroups.contacts, true);\r\n }\r\n })\r\n ]);\r\n } else if(!this.searchContext.peerId && !this.searchContext.minDate) {\r\n const renderRecentSearch = (setActive = true) => {\r\n return appStateManager.getState().then(state => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n \r\n this.searchGroups.recent.list.innerHTML = '';\r\n \r\n state.recentSearch.slice(0, 20).forEach(peerId => {\r\n let {dialog, dom} = appDialogsManager.addDialogNew({\r\n dialog: peerId,\r\n container: this.searchGroups.recent.list,\r\n drawStatus: false,\r\n meAsSaved: true,\r\n avatarSize: 48,\r\n autonomous: true\r\n });\r\n \r\n dom.lastMessageSpan.append(peerId > 0 ? appUsersManager.getUserStatusString(peerId) : appProfileManager.getChatMembersString(-peerId));\r\n });\r\n \r\n if(!state.recentSearch.length) {\r\n this.searchGroups.recent.clear();\r\n } else if(setActive) {\r\n this.searchGroups.recent.setActive();\r\n }\r\n });\r\n };\r\n\r\n return Promise.all([\r\n appUsersManager.getTopPeers().then(peers => {\r\n if(!middleware()) return;\r\n\r\n const idx = peers.indexOf(rootScope.myId);\r\n if(idx !== -1) {\r\n peers = peers.slice();\r\n peers.splice(idx, 1);\r\n }\r\n //console.log('got top categories:', categories);\r\n if(peers.length) {\r\n peers.forEach((peerId) => {\r\n appDialogsManager.addDialogNew({\r\n dialog: peerId, \r\n container: this.searchGroups.people.list, \r\n drawStatus: false,\r\n onlyFirstName: true,\r\n avatarSize: 54,\r\n autonomous: false\r\n });\r\n });\r\n }\r\n \r\n this.searchGroups.people.setActive();\r\n }),\r\n\r\n renderRecentSearch()\r\n ]);\r\n } else return Promise.resolve();\r\n }\r\n\r\n private loadMembers(mediaTab: SearchSuperMediaTab) {\r\n const id = -this.searchContext.peerId;\r\n const middleware = this.middleware.get();\r\n let promise: Promise<void>;\r\n\r\n const renderParticipants = async(participants: (ChatParticipant | ChannelParticipant)[]) => {\r\n if(this.loadMutex) {\r\n await this.loadMutex;\r\n\r\n if(!middleware()) {\r\n return;\r\n }\r\n }\r\n \r\n if(!this.membersList) {\r\n this.membersList = new SortedUserList();\r\n this.membersList.lazyLoadQueue = this.lazyLoadQueue;\r\n this.membersList.list.addEventListener('click', (e) => {\r\n const li = findUpTag(e.target, 'LI');\r\n if(!li) {\r\n return;\r\n }\r\n\r\n const peerId = +li.dataset.peerId;\r\n let promise: Promise<any> = Promise.resolve();\r\n if(mediaSizes.isMobile) {\r\n promise = appSidebarRight.toggleSidebar(false);\r\n }\r\n \r\n promise.then(() => {\r\n appImManager.setInnerPeer(peerId);\r\n });\r\n });\r\n mediaTab.contentTab.append(this.membersList.list);\r\n this.afterPerforming(1, mediaTab.contentTab);\r\n }\r\n\r\n participants.forEach(participant => {\r\n const peerId = appChatsManager.getParticipantPeerId(participant);\r\n if(peerId < 0) {\r\n return;\r\n }\r\n\r\n const user = appUsersManager.getUser(peerId);\r\n if(user.pFlags.deleted) {\r\n return;\r\n }\r\n\r\n this.membersList.add(peerId);\r\n });\r\n };\r\n\r\n if(appChatsManager.isChannel(id)) {\r\n const LOAD_COUNT = !this.membersList ? 50 : 200;\r\n promise = appProfileManager.getChannelParticipants(id, undefined, LOAD_COUNT, this.nextRates[mediaTab.inputFilter]).then(participants => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n let list = mediaTab.contentTab.firstElementChild as HTMLUListElement;\r\n this.nextRates[mediaTab.inputFilter] = (list ? list.childElementCount : 0) + participants.participants.length;\r\n\r\n if(participants.participants.length < LOAD_COUNT) {\r\n this.loaded[mediaTab.inputFilter] = true;\r\n }\r\n\r\n return renderParticipants(participants.participants);\r\n });\r\n } else {\r\n promise = (appProfileManager.getChatFull(id) as Promise<ChatFull.chatFull>).then(chatFull => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n //console.log('anymore', chatFull);\r\n this.loaded[mediaTab.inputFilter] = true;\r\n const participants = chatFull.participants;\r\n if(participants._ === 'chatParticipantsForbidden') {\r\n return;\r\n }\r\n \r\n return renderParticipants(participants.participants);\r\n });\r\n }\r\n\r\n return this.loadPromises[mediaTab.inputFilter] = promise.finally(() => { \r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n this.loadPromises[mediaTab.inputFilter] = null;\r\n });\r\n }\r\n\r\n private loadType(mediaTab: SearchSuperMediaTab, justLoad: boolean, loadCount: number, middleware: () => boolean) {\r\n const type = mediaTab.inputFilter;\r\n\r\n if(this.loadPromises[type]) {\r\n return this.loadPromises[type];\r\n }\r\n\r\n if(mediaTab.type === 'members') {\r\n return this.loadMembers(mediaTab);\r\n }\r\n\r\n const history = this.historyStorage[type] ?? (this.historyStorage[type] = []);\r\n\r\n if(type === 'inputMessagesFilterEmpty' && !history.length) {\r\n if(!this.loadedChats) {\r\n this.loadChats();\r\n this.loadedChats = true;\r\n }\r\n\r\n if(!this.searchContext.query.trim() && !this.searchContext.peerId && !this.searchContext.minDate) {\r\n this.loaded[type] = true;\r\n return Promise.resolve();\r\n }\r\n }\r\n\r\n const logStr = 'load [' + type + ']: ';\r\n\r\n // render from cache\r\n if(history.length && this.usedFromHistory[type] < history.length && !justLoad) {\r\n let messages: any[] = [];\r\n let used = Math.max(0, this.usedFromHistory[type]);\r\n let slicedLength = 0;\r\n\r\n do {\r\n let ids = history.slice(used, used + loadCount);\r\n //this.log(logStr + 'will render from cache', used, history, ids, loadCount);\r\n used += ids.length;\r\n slicedLength += ids.length;\r\n\r\n messages.push(...this.filterMessagesByType(ids.map(m => appMessagesManager.getMessageByPeer(m.peerId, m.mid)), type));\r\n } while(slicedLength < loadCount && used < history.length);\r\n \r\n // если перебор\r\n /* if(slicedLength > loadCount) {\r\n let diff = messages.length - loadCount;\r\n messages = messages.slice(0, messages.length - diff);\r\n used -= diff;\r\n } */\r\n\r\n this.usedFromHistory[type] = used;\r\n //if(messages.length) {\r\n return this.performSearchResult(messages, mediaTab).finally(() => {\r\n setTimeout(() => {\r\n this.scrollable.checkForTriggers();\r\n }, 0);\r\n });\r\n //}\r\n\r\n return Promise.resolve();\r\n }\r\n \r\n let maxId = history.length ? history[history.length - 1].mid : 0;\r\n \r\n //this.log(logStr + 'search house of glass pre', type, maxId);\r\n \r\n //let loadCount = history.length ? 50 : 15;\r\n return this.loadPromises[type] = appMessagesManager.getSearch({\r\n peerId: this.searchContext.peerId, \r\n query: this.searchContext.query,\r\n inputFilter: {_: type},\r\n maxId, \r\n limit: loadCount,\r\n nextRate: this.nextRates[type] ?? (this.nextRates[type] = 0),\r\n threadId: this.searchContext.threadId,\r\n folderId: this.searchContext.folderId,\r\n minDate: this.searchContext.minDate,\r\n maxDate: this.searchContext.maxDate\r\n }).then(value => {\r\n history.push(...value.history.map(m => ({mid: m.mid, peerId: m.peerId})));\r\n \r\n this.log(logStr + 'search house of glass', type, value);\r\n\r\n if(!middleware()) {\r\n //this.log.warn('peer changed');\r\n return;\r\n }\r\n\r\n // ! Фикс случая, когда не загружаются документы при открытой панели разработчиков (происходит из-за того, что не совпадают критерии отбора документов в getSearch)\r\n if(value.history.length < loadCount) {\r\n //if((value.count || history.length === value.count) && history.length >= value.count) {\r\n //this.log(logStr + 'loaded all media', value, loadCount);\r\n this.loaded[type] = true;\r\n }\r\n\r\n this.nextRates[type] = value.next_rate;\r\n\r\n if(justLoad) {\r\n return Promise.resolve();\r\n }\r\n\r\n this.usedFromHistory[type] = history.length;\r\n\r\n if(!this.loaded[type]) {\r\n (this.loadPromises[type] || Promise.resolve()).then(() => {\r\n setTimeout(() => {\r\n if(!middleware()) return;\r\n //this.log('will preload more');\r\n if(this.mediaTab === mediaTab) {\r\n const promise = this.load(true, true);\r\n if(promise) {\r\n promise.then(() => {\r\n if(!middleware()) return;\r\n //this.log('preloaded more');\r\n setTimeout(() => {\r\n this.scrollable.checkForTriggers();\r\n }, 0);\r\n });\r\n }\r\n }\r\n }, 0);\r\n });\r\n }\r\n\r\n //if(value.history.length) {\r\n return this.performSearchResult(this.filterMessagesByType(value.history, type), mediaTab);\r\n //}\r\n }).catch(err => {\r\n this.log.error('load error:', err);\r\n }).finally(() => {\r\n this.loadPromises[type] = null;\r\n });\r\n }\r\n \r\n public async load(single = false, justLoad = false) {\r\n // if(testScroll/* || 1 === 1 */) {\r\n // return;\r\n // }\r\n\r\n //return;\r\n \r\n const peerId = this.searchContext.peerId;\r\n this.log('load', single, peerId, this.loadPromises);\r\n const middleware = this.middleware.get();\r\n\r\n if(this.firstLoad) {\r\n if(this.hideEmptyTabs) {\r\n const mediaTabs = this.mediaTabs.filter(mediaTab => mediaTab.inputFilter !== 'inputMessagesFilterEmpty')\r\n const filters = mediaTabs.map(mediaTab => ({_: mediaTab.inputFilter}));\r\n\r\n const counters = await appMessagesManager.getSearchCounters(peerId, filters);\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n if(this.loadMutex) {\r\n await this.loadMutex;\r\n\r\n if(!middleware()) {\r\n return;\r\n }\r\n }\r\n\r\n let firstMediaTab: SearchSuperMediaTab;\r\n let count = 0;\r\n mediaTabs.forEach(mediaTab => {\r\n const counter = counters.find(c => c.filter._ === mediaTab.inputFilter);\r\n\r\n mediaTab.menuTab.classList.toggle('hide', !counter.count);\r\n mediaTab.menuTab.classList.remove('active');\r\n //mediaTab.contentTab.classList.toggle('hide', !counter.count);\r\n\r\n if(counter.count && firstMediaTab === undefined) {\r\n firstMediaTab = mediaTab;\r\n }\r\n\r\n if(counter.count) ++count;\r\n });\r\n\r\n const membersTab = this.mediaTabsMap.get('members');\r\n const canViewMembers = this.canViewMembers();\r\n membersTab.menuTab.classList.toggle('hide', !canViewMembers);\r\n\r\n if(canViewMembers) {\r\n firstMediaTab = membersTab;\r\n }\r\n\r\n this.container.classList.toggle('hide', !firstMediaTab);\r\n this.container.parentElement.classList.toggle('search-empty', !firstMediaTab);\r\n if(firstMediaTab) {\r\n this.skipScroll = true;\r\n this.selectTab(this.mediaTabs.indexOf(firstMediaTab), false);\r\n firstMediaTab.menuTab.classList.add('active');\r\n\r\n this.navScrollableContainer.classList.toggle('hide', count <= 1);\r\n }\r\n }\r\n\r\n this.firstLoad = false;\r\n }\r\n \r\n let toLoad = single ? [this.mediaTab] : this.mediaTabs.filter(t => t !== this.mediaTab);\r\n toLoad = toLoad.filter(mediaTab => {\r\n const inputFilter = mediaTab.inputFilter;\r\n return !this.loaded[inputFilter] || (this.historyStorage[inputFilter] && this.usedFromHistory[inputFilter] < this.historyStorage[inputFilter].length);\r\n });\r\n\r\n if(peerId > 0) {\r\n toLoad.findAndSplice(mediaTab => mediaTab.type === 'members');\r\n }\r\n\r\n if(!toLoad.length) {\r\n return;\r\n }\r\n\r\n const loadCount = justLoad ? 50 : Math.round((appPhotosManager.windowH / 130 | 0) * 3 * 1.25); // that's good for all types\r\n\r\n const promises: Promise<any>[] = toLoad.map(mediaTab => {\r\n return this.loadType(mediaTab, justLoad, loadCount, middleware)\r\n });\r\n\r\n return Promise.all(promises).catch(err => {\r\n this.log.error('Load error all promises:', err);\r\n });\r\n }\r\n \r\n public getMonthContainerByTimestamp(timestamp: number, type: SearchSuperType) {\r\n const date = new Date(timestamp * 1000);\r\n date.setHours(0, 0, 0);\r\n date.setDate(1);\r\n const dateTimestamp = date.getTime();\r\n const containers = this.monthContainers[type] ?? (this.monthContainers[type] = {});\r\n if(!(dateTimestamp in containers)) {\r\n const str = months[date.getMonth()] + ' ' + date.getFullYear();\r\n \r\n const container = document.createElement('div');\r\n container.className = 'search-super-month';\r\n\r\n const name = document.createElement('div');\r\n name.classList.add('search-super-month-name');\r\n name.innerText = str;\r\n container.append(name);\r\n\r\n const items = document.createElement('div');\r\n items.classList.add('search-super-month-items');\r\n\r\n container.append(name, items);\r\n\r\n const haveTimestamps = getObjectKeysAndSort(containers, 'desc');\r\n let i = 0;\r\n for(; i < haveTimestamps.length; ++i) {\r\n const t = haveTimestamps[i];\r\n if(dateTimestamp > t) {\r\n break;\r\n }\r\n }\r\n \r\n containers[dateTimestamp] = {container, items};\r\n positionElementByIndex(container, this.tabs[type], i);\r\n }\r\n\r\n return containers[dateTimestamp];\r\n }\r\n\r\n public canViewMembers() {\r\n return this.searchContext.peerId < 0 && !appChatsManager.isBroadcast(-this.searchContext.peerId) && appChatsManager.hasRights(-this.searchContext.peerId, 'view_participants');\r\n }\r\n\r\n public cleanup() {\r\n this.loadPromises = {};\r\n this.loaded = {};\r\n this.loadedChats = false;\r\n this.nextRates = {};\r\n this.firstLoad = true;\r\n\r\n this.lazyLoadQueue.clear();\r\n\r\n this.mediaTabs.forEach(mediaTab => {\r\n this.usedFromHistory[mediaTab.inputFilter] = -1;\r\n });\r\n\r\n // * must go to first tab (это костыль)\r\n /* const membersTab = this.mediaTabsMap.get('members');\r\n if(membersTab) {\r\n const tab = this.canViewMembers() ? membersTab : this.mediaTabs[this.mediaTabs.indexOf(membersTab) + 1];\r\n this.mediaTab = tab;\r\n } */\r\n\r\n this.middleware.clean();\r\n this.cleanScrollPositions();\r\n this.membersList = undefined;\r\n }\r\n\r\n public cleanScrollPositions() {\r\n this.mediaTabs.forEach(mediaTab => {\r\n mediaTab.scroll = undefined;\r\n });\r\n }\r\n\r\n public cleanupHTML(goFirst = false) {\r\n if(this.urlsToRevoke.length) {\r\n this.urlsToRevoke.forEach(url => {\r\n URL.revokeObjectURL(url);\r\n });\r\n this.urlsToRevoke.length = 0;\r\n }\r\n\r\n this.mediaTabs.forEach((tab) => {\r\n tab.contentTab.innerHTML = '';\r\n\r\n if(this.hideEmptyTabs) {\r\n //tab.menuTab.classList.add('hide');\r\n this.container.classList.add('hide');\r\n this.container.parentElement.classList.add('search-empty');\r\n }\r\n\r\n if(tab.type === 'chats') {\r\n return;\r\n }\r\n \r\n if(!this.historyStorage[tab.inputFilter]) {\r\n const parent = tab.contentTab.parentElement;\r\n //if(!testScroll) {\r\n if(!parent.querySelector('.preloader')) {\r\n putPreloader(parent, true);\r\n }\r\n //}\r\n\r\n const empty = parent.querySelector('.content-empty');\r\n if(empty) {\r\n empty.remove();\r\n }\r\n }\r\n });\r\n\r\n /* if(goFirst) {\r\n const membersTab = this.mediaTabsMap.get('members');\r\n if(membersTab) {\r\n let idx = this.canViewMembers() ? 0 : 1;\r\n membersTab.menuTab.classList.toggle('hide', idx !== 0);\r\n\r\n this.selectTab(idx, false);\r\n } else {\r\n this.selectTab(0, false);\r\n }\r\n } */\r\n\r\n this.monthContainers = {};\r\n this.searchGroupMedia.clear();\r\n this.scrollable.scrollTop = 0;\r\n\r\n /* if(testScroll) {\r\n for(let i = 0; i < 1500; ++i) {\r\n let div = document.createElement('div');\r\n div.insertAdjacentHTML('beforeend', `<img class=\"media-image\" src=\"assets/img/camomile.jpg\">`);\r\n div.classList.add('grid-item');\r\n div.dataset.id = '' + (i / 3 | 0);\r\n //div.innerText = '' + (i / 3 | 0);\r\n this.tabs.inputMessagesFilterPhotoVideo.append(div);\r\n }\r\n } */\r\n }\r\n\r\n private copySearchContext(newInputFilter: MyInputMessagesFilter) {\r\n const context = copy(this.searchContext);\r\n context.inputFilter = newInputFilter;\r\n context.nextRate = this.nextRates[newInputFilter];\r\n return context;\r\n }\r\n\r\n public setQuery({peerId, query, threadId, historyStorage, folderId, minDate, maxDate}: {\r\n peerId: number, \r\n query?: string, \r\n threadId?: number, \r\n historyStorage?: AppSearchSuper['historyStorage'], \r\n folderId?: number,\r\n minDate?: number,\r\n maxDate?: number\r\n }) {\r\n this.searchContext = {\r\n peerId: peerId || 0,\r\n query: query || '',\r\n inputFilter: this.mediaTab.inputFilter,\r\n threadId,\r\n folderId,\r\n minDate,\r\n maxDate\r\n };\r\n \r\n this.historyStorage = historyStorage ?? {};\r\n\r\n this.cleanup();\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 { AttachClickOptions, attachClickEvent, CLICK_EVENT_NAME } from \"../helpers/dom/clickEvent\";\r\nimport ListenerSetter from \"../helpers/listenerSetter\";\r\nimport { i18n, LangPackKey } from \"../lib/langPack\";\r\nimport CheckboxField from \"./checkboxField\";\r\nimport { closeBtnMenu } from \"./misc\";\r\nimport { ripple } from \"./ripple\";\r\n\r\nexport type ButtonMenuItemOptions = {\r\n icon: string, \r\n text: LangPackKey, \r\n onClick: (e: MouseEvent | TouchEvent) => void, \r\n element?: HTMLElement,\r\n options?: AttachClickOptions,\r\n checkboxField?: CheckboxField,\r\n keepOpen?: boolean\r\n /* , cancelEvent?: true */\r\n};\r\n\r\nconst ButtonMenuItem = (options: ButtonMenuItemOptions) => {\r\n if(options.element) return options.element;\r\n\r\n const {icon, text, onClick} = options;\r\n const el = document.createElement('div');\r\n el.className = 'btn-menu-item tgico-' + icon;\r\n ripple(el);\r\n const t = i18n(text);\r\n t.classList.add('btn-menu-item-text');\r\n el.append(t);\r\n\r\n if(options.checkboxField) {\r\n el.append(options.checkboxField.label);\r\n attachClickEvent(el, () => {\r\n options.checkboxField.checked = !options.checkboxField.checked;\r\n }, options.options);\r\n }\r\n\r\n const keepOpen = !!options.checkboxField || !!options.keepOpen;\r\n\r\n // * cancel mobile keyboard close\r\n attachClickEvent(el, CLICK_EVENT_NAME !== 'click' || keepOpen ? (e) => {\r\n cancelEvent(e);\r\n onClick(e);\r\n\r\n if(!keepOpen) {\r\n closeBtnMenu();\r\n }\r\n } : onClick, options.options);\r\n\r\n return options.element = el;\r\n};\r\n\r\nconst ButtonMenu = (buttons: ButtonMenuItemOptions[], listenerSetter?: ListenerSetter) => {\r\n const el = document.createElement('div');\r\n el.classList.add('btn-menu');\r\n\r\n if(listenerSetter) {\r\n buttons.forEach(b => {\r\n if(b.options) {\r\n b.options.listenerSetter = listenerSetter;\r\n } else {\r\n b.options = {listenerSetter};\r\n }\r\n });\r\n }\r\n\r\n const items = buttons.map(ButtonMenuItem);\r\n\r\n el.append(...items);\r\n\r\n return el;\r\n};\r\n\r\nexport default ButtonMenu;\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 { 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","/*\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[]}): HTMLElement[] {\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 { isMobileSafari } from \"../userAgent\";\r\n\r\nexport function canFocus(isFirstInput: boolean) {\r\n return !isMobileSafari || !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 { formatDateAccordingToToday } 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 : formatDateAccordingToToday(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\";\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 || (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\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 this.stickersFooter.removeEventListener('click', this.onFooterClick);\r\n this.stickersDiv.removeEventListener('click', this.onStickersClick);\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 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 onFooterClick = () => {\r\n const toggle = toggleDisability([this.stickersFooter], 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 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 button.addEventListener('click', this.onFooterClick);\r\n\r\n if(set.documents.length) {\r\n this.stickersDiv.addEventListener('click', this.onStickersClick);\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 { isApple } from \"../../../helpers/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(step, initialValue, minValue, maxValue);\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', [isApple ? '⌘' : '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('EditProfile.Username.Help'));\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.filters[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: 'Channel.ChannelNameHolder',\r\n maxLength: 128\r\n });\r\n\r\n this.channelDescriptionInputField = new InputField({\r\n label: 'Channel.DescriptionPlaceholder',\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","/*\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 appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport appUsersManager from \"../../../lib/appManagers/appUsersManager\";\r\nimport appPhotosManager from \"../../../lib/appManagers/appPhotosManager\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport InputSearch from \"../../inputSearch\";\r\nimport { isMobile } from \"../../../helpers/userAgent\";\r\nimport { canFocus } from \"../../../helpers/dom/canFocus\";\r\n\r\n// TODO: поиск по людям глобальный, если не нашло в контактах никого\r\n\r\nexport default class AppContactsTab extends SliderSuperTab {\r\n private list: HTMLUListElement;\r\n private promise: Promise<void>;\r\n\r\n private inputSearch: InputSearch;\r\n private alive = true;\r\n \r\n init() {\r\n this.container.id = 'contacts-container';\r\n\r\n this.list = appDialogsManager.createChatList(/* {avatarSize: 48, handheldsSize: 66} */);\r\n this.list.id = 'contacts';\r\n this.list.classList.add('contacts-container');\r\n\r\n appDialogsManager.setListClickListener(this.list, () => {\r\n (this.container.querySelector('.sidebar-close-button') as HTMLElement).click();\r\n }, undefined, true);\r\n\r\n this.inputSearch = new InputSearch('Search', (value) => {\r\n this.list.innerHTML = '';\r\n this.openContacts(value);\r\n });\r\n\r\n this.title.replaceWith(this.inputSearch.container);\r\n\r\n this.scrollable.append(this.list);\r\n\r\n // preload contacts\r\n // appUsersManager.getContacts();\r\n }\r\n\r\n onClose() {\r\n this.alive = false;\r\n /* // need to clear, and left 1 page for smooth slide\r\n let pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;\r\n (Array.from(this.list.children) as HTMLElement[]).slice(pageCount).forEach(el => el.remove()); */\r\n }\r\n\r\n onOpenAfterTimeout() {\r\n if(isMobile || !canFocus(true)) return;\r\n this.inputSearch.input.focus();\r\n }\r\n\r\n public openContacts(query?: string) {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n if(this.promise) return this.promise;\r\n this.scrollable.onScrolledBottom = null;\r\n\r\n this.promise = appUsersManager.getContacts(query).then(_contacts => {\r\n this.promise = null;\r\n\r\n if(!this.alive) {\r\n //console.warn('user closed contacts before it\\'s loaded');\r\n return;\r\n }\r\n\r\n const contacts = [..._contacts];\r\n\r\n if(!query) {\r\n contacts.findAndSplice(u => u === rootScope.myId);\r\n }\r\n /* if(query && 'saved messages'.includes(query.toLowerCase())) {\r\n contacts.unshift(rootScope.myID);\r\n } */\r\n\r\n let sorted = contacts\r\n .map(userId => {\r\n let user = appUsersManager.getUser(userId);\r\n let status = appUsersManager.getUserStatusForSort(user.status);\r\n\r\n return {user, status};\r\n })\r\n .sort((a, b) => b.status - a.status);\r\n\r\n let renderPage = () => {\r\n let pageCount = appPhotosManager.windowH / 72 * 1.25 | 0;\r\n let arr = sorted.splice(0, pageCount); // надо splice!\r\n\r\n arr.forEach(({user}) => {\r\n let {dialog, dom} = appDialogsManager.addDialogNew({\r\n dialog: user.id,\r\n container: this.list,\r\n drawStatus: false,\r\n avatarSize: 48,\r\n autonomous: true\r\n });\r\n \r\n let status = appUsersManager.getUserStatusString(user.id);\r\n dom.lastMessageSpan.append(status);\r\n });\r\n\r\n if(!sorted.length) renderPage = undefined;\r\n };\r\n\r\n renderPage();\r\n this.scrollable.onScrolledBottom = () => {\r\n if(renderPage) {\r\n renderPage();\r\n } else {\r\n this.scrollable.onScrolledBottom = null;\r\n }\r\n };\r\n });\r\n }\r\n\r\n public open() {\r\n this.openContacts();\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 appDialogsManager from \"../../../lib/appManagers/appDialogsManager\";\r\nimport { SliderSuperTab } from \"../../slider\";\r\n\r\nexport default class AppArchivedTab extends SliderSuperTab {\r\n private static filterId = 1;\r\n private wasFilterId: number;\r\n\r\n init() {\r\n this.container.id = 'chats-archived-container';\r\n this.setTitle('ArchivedChats');\r\n\r\n if(!appDialogsManager.chatLists[AppArchivedTab.filterId]) {\r\n const chatList = appDialogsManager.createChatList();\r\n appDialogsManager.generateScrollable(chatList, AppArchivedTab.filterId);\r\n appDialogsManager.setListClickListener(chatList, null, true);\r\n //appDialogsManager.setListClickListener(archivedChatList, null, true); // * to test peer changing\r\n }\r\n\r\n const scrollable = appDialogsManager.scrollables[AppArchivedTab.filterId];\r\n this.scrollable.container.replaceWith(scrollable.container);\r\n this.scrollable = scrollable;\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.wasFilterId = appDialogsManager.filterId;\r\n appDialogsManager.filterId = AppArchivedTab.filterId;\r\n appDialogsManager.onTabChange();\r\n }\r\n\r\n // вообще, так делать нельзя, но нет времени чтобы переделать главный чатлист на слайд...\r\n onOpenAfterTimeout() {\r\n appDialogsManager.chatLists[this.wasFilterId].innerHTML = '';\r\n }\r\n\r\n onClose() {\r\n appDialogsManager.filterId = this.wasFilterId;\r\n appDialogsManager.onTabChange();\r\n }\r\n\r\n onCloseAfterTimeout() {\r\n appDialogsManager.chatLists[AppArchivedTab.filterId].innerHTML = '';\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 { formatNumber } from \"../../helpers/number\";\r\nimport appImManager from \"../../lib/appManagers/appImManager\";\r\nimport appStateManager from \"../../lib/appManagers/appStateManager\";\r\nimport appUsersManager from \"../../lib/appManagers/appUsersManager\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport { SearchGroup } from \"../appSearch\";\r\nimport \"../avatar\";\r\nimport Scrollable, { ScrollableX } from \"../scrollable\";\r\nimport InputSearch from \"../inputSearch\";\r\nimport SidebarSlider from \"../slider\";\r\nimport { TransitionSlider } from \"../transition\";\r\nimport AppNewGroupTab from \"./tabs/newGroup\";\r\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport AppSearchSuper from \"../appSearchSuper.\";\r\nimport { DateData, fillTipDates } from \"../../helpers/date\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport AppSettingsTab from \"./tabs/settings\";\r\nimport AppNewChannelTab from \"./tabs/newChannel\";\r\nimport AppContactsTab from \"./tabs/contacts\";\r\nimport AppArchivedTab from \"./tabs/archivedTab\";\r\nimport AppAddMembersTab from \"./tabs/addMembers\";\r\nimport { i18n_, LangPackKey } from \"../../lib/langPack\";\r\nimport { ButtonMenuItemOptions } from \"../buttonMenu\";\r\nimport CheckboxField from \"../checkboxField\";\r\nimport { isMobileSafari } from \"../../helpers/userAgent\";\r\nimport appNavigationController from \"../appNavigationController\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport PeerTitle from \"../peerTitle\";\r\nimport App from \"../../config/app\";\r\nimport ButtonMenuToggle from \"../buttonMenuToggle\";\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\nimport sessionStorage from \"../../lib/sessionStorage\";\r\n\r\nexport const LEFT_COLUMN_ACTIVE_CLASSNAME = 'is-left-column-shown';\r\n\r\nexport class AppSidebarLeft extends SidebarSlider {\r\n private toolsBtn: HTMLButtonElement;\r\n private backBtn: HTMLButtonElement;\r\n //private searchInput = document.getElementById('global-search') as HTMLInputElement;\r\n private inputSearch: InputSearch;\r\n \r\n public archivedCount: HTMLSpanElement;\r\n\r\n private newBtnMenu: HTMLElement;\r\n\r\n //private log = logger('SL');\r\n\r\n private searchGroups: {[k in 'contacts' | 'globalContacts' | 'messages' | 'people' | 'recent']: SearchGroup} = {} as any;\r\n private searchSuper: AppSearchSuper;\r\n\r\n constructor() {\r\n super({\r\n sidebarEl: document.getElementById('column-left') as HTMLDivElement,\r\n navigationType: 'left'\r\n });\r\n\r\n //this._selectTab(0); // make first tab as default\r\n\r\n this.inputSearch = new InputSearch('Search');\r\n const sidebarHeader = this.sidebarEl.querySelector('.item-main .sidebar-header');\r\n sidebarHeader.append(this.inputSearch.container);\r\n\r\n const onNewGroupClick = () => {\r\n new AppAddMembersTab(this).open({\r\n peerId: 0,\r\n type: 'chat',\r\n skippable: false,\r\n takeOut: (peerIds) => {\r\n new AppNewGroupTab(this).open(peerIds);\r\n },\r\n title: 'GroupAddMembers',\r\n placeholder: 'SendMessageTo'\r\n });\r\n };\r\n\r\n const onContactsClick = () => {\r\n new AppContactsTab(this).open();\r\n };\r\n\r\n //this.toolsBtn = this.sidebarEl.querySelector('.sidebar-tools-button') as HTMLButtonElement;\r\n this.backBtn = this.sidebarEl.querySelector('.sidebar-back-button') as HTMLButtonElement;\r\n\r\n const btnArchive: ButtonMenuItemOptions & {verify?: () => boolean} = {\r\n icon: 'archive',\r\n text: 'ArchivedChats',\r\n onClick: () => {\r\n new AppArchivedTab(this).open();\r\n },\r\n verify: () => {\r\n const folder = appMessagesManager.dialogsStorage.getFolder(1);\r\n return !!folder.length;\r\n }\r\n };\r\n\r\n const themeCheckboxField = new CheckboxField({\r\n toggle: true,\r\n checked: rootScope.getTheme().name === 'night'\r\n });\r\n themeCheckboxField.input.addEventListener('change', () => {\r\n rootScope.settings.theme = themeCheckboxField.input.checked ? 'night' : 'day';\r\n appStateManager.pushToState('settings', rootScope.settings);\r\n appImManager.applyCurrentTheme();\r\n });\r\n\r\n rootScope.addEventListener('theme_change', () => {\r\n themeCheckboxField.setValueSilently(rootScope.getTheme().name === 'night');\r\n });\r\n\r\n const menuButtons: (ButtonMenuItemOptions & {verify?: () => boolean})[] = [{\r\n icon: 'saved',\r\n text: 'SavedMessages',\r\n onClick: () => {\r\n setTimeout(() => { // menu doesn't close if no timeout (lol)\r\n appImManager.setPeer(appImManager.myId);\r\n }, 0);\r\n }\r\n }, btnArchive, {\r\n icon: 'user',\r\n text: 'Contacts',\r\n onClick: onContactsClick\r\n }, {\r\n icon: 'settings',\r\n text: 'Settings',\r\n onClick: () => {\r\n new AppSettingsTab(this).open();\r\n }\r\n }, {\r\n icon: 'darkmode',\r\n text: 'DarkMode',\r\n onClick: () => {\r\n \r\n },\r\n checkboxField: themeCheckboxField\r\n }, {\r\n icon: 'animations',\r\n text: 'Animations',\r\n onClick: () => {\r\n \r\n },\r\n checkboxField: new CheckboxField({\r\n toggle: true, \r\n checked: true,\r\n stateKey: 'settings.animationsEnabled',\r\n })\r\n }, {\r\n icon: 'help',\r\n text: 'TelegramFeatures',\r\n onClick: () => {\r\n appImManager.openUsername('TelegramTips');\r\n }\r\n }, {\r\n icon: 'bug',\r\n text: 'ReportBug',\r\n onClick: () => {\r\n const a = document.createElement('a');\r\n a.target = '_blank';\r\n a.href = 'https://bugs.telegram.org/?tag_ids=40&sort=time';\r\n document.body.append(a);\r\n a.click();\r\n setTimeout(() => {\r\n a.remove();\r\n }, 0);\r\n }\r\n }, {\r\n icon: 'char z',\r\n text: 'ChatList.Menu.SwitchTo.Z',\r\n onClick: () => {\r\n sessionStorage.set({kz_version: 'Z'}).then(() => {\r\n location.href = 'https://web.telegram.org/z/';\r\n });\r\n },\r\n verify: () => App.isMainDomain\r\n }, {\r\n icon: 'char w',\r\n text: 'ChatList.Menu.SwitchTo.Webogram',\r\n onClick: () => {\r\n location.href = 'https://web.telegram.org/?legacy=1';\r\n },\r\n verify: () => App.isMainDomain\r\n }];\r\n\r\n this.toolsBtn = ButtonMenuToggle({}, 'bottom-right', menuButtons, (e) => {\r\n menuButtons.forEach(button => {\r\n if(button.verify) {\r\n button.element.classList.toggle('hide', !button.verify());\r\n }\r\n });\r\n });\r\n this.toolsBtn.classList.remove('tgico-more');\r\n this.toolsBtn.classList.add('sidebar-tools-button', 'is-visible');\r\n\r\n this.backBtn.parentElement.insertBefore(this.toolsBtn, this.backBtn);\r\n\r\n const btnMenu = this.toolsBtn.querySelector('.btn-menu') as HTMLElement;\r\n\r\n const btnMenuFooter = document.createElement('div');\r\n btnMenuFooter.classList.add('btn-menu-footer');\r\n const t = document.createElement('span');\r\n t.classList.add('btn-menu-footer-text');\r\n t.innerHTML = 'Telegram Web' + App.suffix + ' alpha ' + App.version;\r\n btnMenuFooter.append(t); \r\n btnMenu.classList.add('has-footer');\r\n btnMenu.append(btnMenuFooter);\r\n\r\n this.newBtnMenu = ButtonMenuToggle({}, 'top-left', [{\r\n icon: 'newchannel',\r\n text: 'NewChannel',\r\n onClick: () => {\r\n new AppNewChannelTab(this).open();\r\n }\r\n }, {\r\n icon: 'newgroup',\r\n text: 'NewGroup',\r\n onClick: onNewGroupClick\r\n }, {\r\n icon: 'newprivate',\r\n text: 'NewPrivateChat',\r\n onClick: onContactsClick\r\n }]);\r\n this.newBtnMenu.className = 'btn-circle rp btn-corner z-depth-1 btn-menu-toggle animated-button-icon';\r\n this.newBtnMenu.insertAdjacentHTML('afterbegin', `\r\n <span class=\"tgico tgico-newchat_filled\"></span>\r\n <span class=\"tgico tgico-close\"></span>\r\n `);\r\n this.newBtnMenu.id = 'new-menu';\r\n sidebarHeader.nextElementSibling.append(this.newBtnMenu);\r\n\r\n this.inputSearch.input.addEventListener('focus', () => this.initSearch(), {once: true});\r\n\r\n //parseMenuButtonsTo(this.newButtons, this.newBtnMenu.firstElementChild.children);\r\n\r\n this.archivedCount = document.createElement('span');\r\n this.archivedCount.className = 'archived-count badge badge-24 badge-gray';\r\n\r\n btnArchive.element.append(this.archivedCount);\r\n\r\n rootScope.addEventListener('dialogs_archived_unread', (e) => {\r\n this.archivedCount.innerText = '' + formatNumber(e.count, 1);\r\n this.archivedCount.classList.toggle('hide', !e.count);\r\n });\r\n\r\n appUsersManager.getTopPeers();\r\n\r\n appStateManager.getState().then(state => {\r\n const recentSearch = state.recentSearch || [];\r\n for(let i = 0, length = recentSearch.length; i < length; ++i) {\r\n appStateManager.requestPeer(recentSearch[i], 'recentSearch');\r\n }\r\n });\r\n }\r\n\r\n private initSearch() {\r\n const searchContainer = this.sidebarEl.querySelector('#search-container') as HTMLDivElement;\r\n\r\n const scrollable = new Scrollable(searchContainer);\r\n\r\n const close = () => {\r\n //setTimeout(() => {\r\n this.backBtn.click();\r\n //}, 0);\r\n };\r\n\r\n this.searchGroups = {\r\n contacts: new SearchGroup('Search.Chats', 'contacts', undefined, undefined, undefined, undefined, close),\r\n globalContacts: new SearchGroup('Search.Global', 'contacts', undefined, undefined, undefined, undefined, close),\r\n messages: new SearchGroup('Search.Messages', 'messages'),\r\n people: new SearchGroup(false, 'contacts', true, 'search-group-people', true, false, close),\r\n recent: new SearchGroup('Recent', 'contacts', true, 'search-group-recent', true, true, close)\r\n };\r\n\r\n const searchSuper = this.searchSuper = new AppSearchSuper({\r\n mediaTabs: [{\r\n inputFilter: 'inputMessagesFilterEmpty',\r\n name: 'FilterChats',\r\n type: 'chats'\r\n }, {\r\n inputFilter: 'inputMessagesFilterPhotoVideo',\r\n name: 'SharedMediaTab2',\r\n type: 'media'\r\n }, {\r\n inputFilter: 'inputMessagesFilterUrl',\r\n name: 'SharedLinksTab2',\r\n type: 'links'\r\n }, {\r\n inputFilter: 'inputMessagesFilterDocument',\r\n name: 'SharedFilesTab2',\r\n type: 'files'\r\n }, {\r\n inputFilter: 'inputMessagesFilterMusic',\r\n name: 'SharedMusicTab2',\r\n type: 'music'\r\n }, {\r\n inputFilter: 'inputMessagesFilterVoice',\r\n name: 'SharedVoiceTab2',\r\n type: 'voice'\r\n }], \r\n scrollable, \r\n searchGroups: this.searchGroups, \r\n asChatList: true,\r\n hideEmptyTabs: false,\r\n showSender: true\r\n });\r\n\r\n searchContainer.prepend(searchSuper.nav.parentElement.parentElement);\r\n scrollable.container.append(searchSuper.container);\r\n\r\n const resetSearch = () => {\r\n searchSuper.setQuery({\r\n peerId: 0, \r\n folderId: 0\r\n });\r\n searchSuper.selectTab(0);\r\n searchSuper.load(true); \r\n };\r\n\r\n resetSearch();\r\n\r\n let pickedElements: HTMLElement[] = [];\r\n let selectedPeerId = 0;\r\n let selectedMinDate = 0;\r\n let selectedMaxDate = 0;\r\n const updatePicked = () => {\r\n //(this.inputSearch.input as HTMLInputElement).placeholder = pickedElements.length ? 'Search' : 'Telegram Search';\r\n this.inputSearch.container.classList.toggle('is-picked-twice', pickedElements.length === 2);\r\n this.inputSearch.container.classList.toggle('is-picked', !!pickedElements.length);\r\n\r\n if(pickedElements.length) {\r\n this.inputSearch.input.style.setProperty('--paddingLeft', (pickedElements[pickedElements.length - 1].getBoundingClientRect().right - this.inputSearch.input.getBoundingClientRect().left) + 'px');\r\n } else {\r\n this.inputSearch.input.style.removeProperty('--paddingLeft');\r\n }\r\n };\r\n\r\n const helper = document.createElement('div');\r\n helper.classList.add('search-helper');\r\n helper.addEventListener('click', (e) => {\r\n const target = findUpClassName(e.target, 'selector-user');\r\n if(!target) {\r\n return;\r\n }\r\n\r\n const key = target.dataset.key;\r\n if(key.indexOf('date_') === 0) {\r\n const [_, minDate, maxDate] = key.split('_');\r\n selectedMinDate = +minDate;\r\n selectedMaxDate = +maxDate;\r\n } else {\r\n selectedPeerId = +key;\r\n }\r\n\r\n target.addEventListener('click', () => {\r\n unselectEntity(target);\r\n });\r\n\r\n this.inputSearch.container.append(target);\r\n this.inputSearch.onChange(this.inputSearch.value = '');\r\n pickedElements.push(target);\r\n updatePicked();\r\n });\r\n\r\n searchSuper.nav.parentElement.append(helper);\r\n\r\n const renderEntity = (peerId: any, title?: string | HTMLElement) => {\r\n const div = document.createElement('div');\r\n div.classList.add('selector-user'/* , 'scale-in' */);\r\n\r\n const avatarEl = document.createElement('avatar-element');\r\n avatarEl.classList.add('selector-user-avatar', 'tgico');\r\n avatarEl.setAttribute('dialog', '1');\r\n avatarEl.classList.add('avatar-30');\r\n\r\n div.dataset.key = '' + peerId;\r\n if(typeof(peerId) === 'number') {\r\n if(title === undefined) {\r\n title = new PeerTitle({peerId, onlyFirstName: true}).element;\r\n }\r\n\r\n avatarEl.setAttribute('peer', '' + peerId);\r\n } else {\r\n avatarEl.classList.add('tgico-calendarfilter');\r\n }\r\n\r\n if(title) {\r\n if(typeof(title) === 'string') {\r\n div.innerHTML = title;\r\n } else {\r\n replaceContent(div, title);\r\n div.append(title);\r\n }\r\n }\r\n\r\n div.insertAdjacentElement('afterbegin', avatarEl);\r\n\r\n return div;\r\n };\r\n\r\n const unselectEntity = (target: HTMLElement) => {\r\n const key = target.dataset.key;\r\n if(key.indexOf('date_') === 0) {\r\n selectedMinDate = selectedMaxDate = 0;\r\n } else {\r\n selectedPeerId = 0;\r\n }\r\n \r\n target.remove();\r\n pickedElements.findAndSplice(t => t === target);\r\n\r\n setTimeout(() => {\r\n updatePicked();\r\n this.inputSearch.onChange(this.inputSearch.value);\r\n }, 0);\r\n };\r\n\r\n this.inputSearch.onClear = () => {\r\n pickedElements.forEach(el => {\r\n unselectEntity(el);\r\n });\r\n };\r\n\r\n this.inputSearch.onChange = (value) => {\r\n searchSuper.cleanupHTML();\r\n searchSuper.setQuery({\r\n peerId: selectedPeerId, \r\n folderId: selectedPeerId ? undefined : 0,\r\n query: value,\r\n minDate: selectedMinDate,\r\n maxDate: selectedMaxDate\r\n });\r\n searchSuper.load(true);\r\n\r\n helper.innerHTML = '';\r\n searchSuper.nav.classList.remove('hide');\r\n if(!value) {\r\n }\r\n \r\n if(!selectedPeerId && value.trim()) {\r\n const middleware = searchSuper.middleware.get();\r\n Promise.all([\r\n appMessagesManager.getConversationsAll(value).then(dialogs => dialogs.map(d => d.peerId)),\r\n appUsersManager.getContacts(value, true)\r\n ]).then(results => {\r\n if(!middleware()) return;\r\n const peerIds = new Set(results[0].concat(results[1]));\r\n \r\n peerIds.forEach(peerId => {\r\n helper.append(renderEntity(peerId));\r\n });\r\n \r\n searchSuper.nav.classList.toggle('hide', !!helper.innerHTML);\r\n //console.log('got peerIds by value:', value, [...peerIds]);\r\n });\r\n }\r\n \r\n if(!selectedMinDate && value.trim()) {\r\n const dates: DateData[] = [];\r\n fillTipDates(value, dates);\r\n dates.forEach(dateData => {\r\n helper.append(renderEntity('date_' + dateData.minDate + '_' + dateData.maxDate, dateData.title));\r\n });\r\n\r\n searchSuper.nav.classList.toggle('hide', !!helper.innerHTML);\r\n }\r\n };\r\n\r\n searchSuper.tabs.inputMessagesFilterEmpty.addEventListener('mousedown', (e) => {\r\n const target = findUpTag(e.target, 'LI') as HTMLElement;\r\n if(!target) {\r\n return;\r\n }\r\n\r\n const searchGroup = findUpClassName(target, 'search-group');\r\n if(!searchGroup || searchGroup.classList.contains('search-group-recent') || searchGroup.classList.contains('search-group-people')) {\r\n return;\r\n }\r\n\r\n const peerId = +target.getAttribute('data-peer-id');\r\n appStateManager.getState().then(state => {\r\n const recentSearch = state.recentSearch || [];\r\n if(recentSearch[0] !== peerId) {\r\n recentSearch.findAndSplice(p => p === peerId);\r\n recentSearch.unshift(peerId);\r\n if(recentSearch.length > 20) {\r\n recentSearch.length = 20;\r\n }\r\n \r\n appStateManager.pushToState('recentSearch', recentSearch);\r\n for(const peerId of recentSearch) {\r\n appStateManager.requestPeer(peerId, 'recentSearch');\r\n }\r\n }\r\n });\r\n }, {capture: true});\r\n\r\n let peopleContainer = document.createElement('div');\r\n peopleContainer.classList.add('search-group-scrollable');\r\n peopleContainer.append(this.searchGroups.people.list);\r\n this.searchGroups.people.container.append(peopleContainer);\r\n let peopleScrollable = new ScrollableX(peopleContainer);\r\n\r\n let first = true;\r\n let hideNewBtnMenuTimeout: number;\r\n //const transition = Transition.bind(null, searchContainer.parentElement, 150);\r\n const transition = TransitionSlider(searchContainer.parentElement, 'zoom-fade', 150, (id) => {\r\n if(hideNewBtnMenuTimeout) clearTimeout(hideNewBtnMenuTimeout);\r\n\r\n if(id === 0 && !first) {\r\n searchSuper.selectTab(0, false);\r\n this.inputSearch.onClearClick();\r\n hideNewBtnMenuTimeout = window.setTimeout(() => {\r\n hideNewBtnMenuTimeout = 0;\r\n this.newBtnMenu.classList.remove('is-hidden');\r\n }, 150);\r\n }\r\n\r\n first = false;\r\n });\r\n\r\n transition(0);\r\n\r\n const activeClassName = 'is-visible';\r\n const onFocus = () => {\r\n this.toolsBtn.classList.remove(activeClassName);\r\n this.backBtn.classList.add(activeClassName);\r\n this.newBtnMenu.classList.add('is-hidden');\r\n this.toolsBtn.parentElement.firstElementChild.classList.toggle('state-back', true);\r\n\r\n if(!isMobileSafari && !appNavigationController.findItemByType('global-search')) {\r\n appNavigationController.pushItem({\r\n onPop: () => {\r\n close();\r\n },\r\n type: 'global-search'\r\n });\r\n }\r\n\r\n transition(1);\r\n };\r\n\r\n this.inputSearch.input.addEventListener('focus', onFocus);\r\n onFocus();\r\n\r\n this.backBtn.addEventListener('click', (e) => {\r\n this.toolsBtn.classList.add(activeClassName);\r\n this.backBtn.classList.remove(activeClassName);\r\n this.toolsBtn.parentElement.firstElementChild.classList.toggle('state-back', false);\r\n\r\n appNavigationController.removeByType('global-search');\r\n\r\n transition(0);\r\n });\r\n\r\n const clearRecentSearchBtn = document.createElement('button');\r\n clearRecentSearchBtn.classList.add('btn-icon', 'tgico-close');\r\n this.searchGroups.recent.nameEl.append(clearRecentSearchBtn);\r\n clearRecentSearchBtn.addEventListener('click', () => {\r\n this.searchGroups.recent.clear();\r\n appStateManager.pushToState('recentSearch', []);\r\n });\r\n }\r\n}\r\n\r\nexport class SettingSection {\r\n public container: HTMLElement;\r\n public content: HTMLElement;\r\n public title: HTMLElement;\r\n public caption: HTMLElement;\r\n\r\n constructor(options: {\r\n name?: LangPackKey, \r\n caption?: LangPackKey | true,\r\n noDelimiter?: boolean\r\n }) {\r\n this.container = document.createElement('div');\r\n this.container.classList.add('sidebar-left-section');\r\n\r\n if(!options.noDelimiter) {\r\n const hr = document.createElement('hr');\r\n this.container.append(hr);\r\n } else {\r\n this.container.classList.add('no-delimiter');\r\n }\r\n\r\n this.content = this.generateContentElement();\r\n\r\n if(options.name) {\r\n this.title = document.createElement('div');\r\n this.title.classList.add('sidebar-left-h2', 'sidebar-left-section-name');\r\n i18n_({element: this.title, key: options.name});\r\n this.content.append(this.title);\r\n }\r\n\r\n if(options.caption) {\r\n this.caption = this.generateContentElement();\r\n this.caption.classList.add('sidebar-left-section-caption');\r\n\r\n if(options.caption !== true) {\r\n i18n_({element: this.caption, key: options.caption});\r\n }\r\n }\r\n }\r\n\r\n public generateContentElement() {\r\n const content = document.createElement('div');\r\n content.classList.add('sidebar-left-section-content');\r\n this.container.append(content);\r\n return content;\r\n }\r\n}\r\n\r\nexport const generateSection = (appendTo: Scrollable, name?: LangPackKey, caption?: LangPackKey) => {\r\n const section = new SettingSection({name, caption});\r\n appendTo.append(section.container);\r\n return section.content;\r\n};\r\n\r\nconst appSidebarLeft = new AppSidebarLeft();\r\nMOUNT_CLASS_TO.appSidebarLeft = appSidebarLeft;\r\nexport default appSidebarLeft;\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\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 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 this.prevBtn.addEventListener('click', this.onPrevClick);\r\n\r\n this.nextBtn = document.createElement('button');\r\n this.nextBtn.classList.add('btn-icon', 'tgico-down', 'date-picker-next');\r\n this.nextBtn.addEventListener('click', this.onNextClick);\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 this.monthsContainer.addEventListener('click', this.onDateClick);\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 inputField.input.addEventListener('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 this.btnConfirm.addEventListener('click', () => {\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 }, {once: true});\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\nimport appImManager from \"../../lib/appManagers/appImManager\";\r\nimport PopupPickUser from \"./pickUser\";\r\n\r\nexport default class PopupForward extends PopupPickUser {\r\n constructor(fromPeerId: number, mids: number[], onSelect?: () => Promise<void> | void, onClose?: () => void) {\r\n super({\r\n peerTypes: ['dialogs', 'contacts'],\r\n onSelect: async(peerId) => {\r\n if(onSelect) {\r\n const res = onSelect();\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(fromPeerId, mids.slice());\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","/*\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\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: string;\r\n if(replies) {\r\n if(replies.replies) {\r\n text = replies.replies + ' ' + (replies.replies > 1 ? 'Comments' : 'Comment');\r\n } else {\r\n text = 'Leave a Comment';\r\n }\r\n } else {\r\n text = 'View in chat';\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 textSpan.innerHTML = 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","/*\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 { getFullDate } from \"../../helpers/date\";\r\nimport { formatNumber } from \"../../helpers/number\";\r\nimport { i18n } from \"../../lib/langPack\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport { LazyLoadQueueIntersector } from \"../lazyLoadQueue\";\r\nimport PeerTitle from \"../peerTitle\";\r\nimport { wrapReply } from \"../wrappers\";\r\nimport Chat from \"./chat\";\r\nimport RepliesElement from \"./replies\";\r\n\r\nexport namespace MessageRender {\r\n /* export const setText = () => {\r\n\r\n }; */\r\n\r\n export const setTime = (chat: Chat, message: any, bubble: HTMLElement, bubbleContainer: HTMLElement, messageDiv: HTMLElement) => {\r\n const date = new Date(message.date * 1000);\r\n let time = ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2);\r\n\r\n if(message.views) {\r\n const postAuthor = message.post_author || message.fwd_from?.post_author;\r\n\r\n bubble.classList.add('channel-post');\r\n time = formatNumber(message.views, 1) + ' <i class=\"tgico-channelviews time-icon\"></i> ' + (postAuthor ? RichTextProcessor.wrapEmojiText(postAuthor) + ', ' : '') + time;\r\n \r\n if(!message.fwd_from?.saved_from_msg_id) {\r\n const forward = document.createElement('div');\r\n forward.classList.add('bubble-beside-button', 'forward');\r\n forward.innerHTML = `\r\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\">\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 bubbleContainer.append(forward);\r\n bubble.classList.add('with-beside-button');\r\n }\r\n }\r\n\r\n if(message.edit_date && chat.type !== 'scheduled' && !message.pFlags.edit_hide) {\r\n bubble.classList.add('is-edited');\r\n time = '<i class=\"edited\">edited</i> ' + time;\r\n }\r\n\r\n if(chat.type !== 'pinned' && message.pFlags.pinned) {\r\n bubble.classList.add('is-pinned');\r\n time = '<i class=\"tgico-pinnedchat time-icon\"></i>' + time;\r\n }\r\n\r\n const title = getFullDate(date) \r\n + (message.edit_date ? `\\nEdited: ${getFullDate(new Date(message.edit_date * 1000))}` : '')\r\n + (message.fwd_from ? `\\nOriginal: ${getFullDate(new Date(message.fwd_from.date * 1000))}` : '');\r\n\r\n const timeSpan = document.createElement('span');\r\n timeSpan.classList.add('time', 'tgico');\r\n timeSpan.title = title;\r\n timeSpan.innerHTML = `${time}<div class=\"inner tgico\" title=\"${title}\">${time}</div>`;\r\n\r\n messageDiv.append(timeSpan);\r\n\r\n return timeSpan;\r\n };\r\n\r\n export const renderReplies = ({bubble, bubbleContainer, message, messageDiv, loadPromises, lazyLoadQueue}: {\r\n bubble: HTMLElement,\r\n bubbleContainer: HTMLElement,\r\n message: any,\r\n messageDiv: HTMLElement,\r\n loadPromises?: Promise<any>[],\r\n lazyLoadQueue?: LazyLoadQueueIntersector\r\n }) => {\r\n const isFooter = !bubble.classList.contains('sticker') && !bubble.classList.contains('emoji-big') && !bubble.classList.contains('round');\r\n const repliesFooter = new RepliesElement();\r\n repliesFooter.message = message;\r\n repliesFooter.type = isFooter ? 'footer' : 'beside';\r\n repliesFooter.loadPromises = loadPromises;\r\n repliesFooter.lazyLoadQueue = lazyLoadQueue;\r\n repliesFooter.init();\r\n bubbleContainer.prepend(repliesFooter);\r\n return isFooter;\r\n };\r\n\r\n export const setReply = ({chat, bubble, bubbleContainer, message}: {\r\n chat: Chat,\r\n bubble: HTMLElement,\r\n bubbleContainer?: HTMLElement,\r\n message: any\r\n }) => {\r\n const isReplacing = !bubbleContainer;\r\n if(isReplacing) {\r\n bubbleContainer = bubble.querySelector('.bubble-content');\r\n }\r\n\r\n const currentReplyDiv = isReplacing ? bubbleContainer.querySelector('.reply') : null;\r\n if(!message.reply_to_mid) {\r\n if(currentReplyDiv) {\r\n currentReplyDiv.remove();\r\n }\r\n\r\n bubble.classList.remove('is-reply');\r\n return;\r\n }\r\n\r\n\r\n const replyToPeerId = message.reply_to.reply_to_peer_id ? chat.appPeersManager.getPeerId(message.reply_to.reply_to_peer_id) : chat.peerId;\r\n\r\n let originalMessage = chat.appMessagesManager.getMessageByPeer(replyToPeerId, message.reply_to_mid);\r\n let originalPeerTitle: string | HTMLElement;\r\n \r\n /////////this.log('message to render reply', originalMessage, originalPeerTitle, bubble, message);\r\n \r\n // need to download separately\r\n if(originalMessage._ === 'messageEmpty') {\r\n //////////this.log('message to render reply empty, need download', message, message.reply_to_mid);\r\n chat.appMessagesManager.wrapSingleMessage(replyToPeerId, message.reply_to_mid);\r\n chat.bubbles.needUpdate.push({replyToPeerId, replyMid: message.reply_to_mid, mid: message.mid});\r\n \r\n originalPeerTitle = i18n('Loading');\r\n } else {\r\n originalPeerTitle = new PeerTitle({\r\n peerId: originalMessage.fromId || originalMessage.fwdFromId,\r\n dialog: false,\r\n onlyFirstName: false,\r\n plainText: false\r\n }).element;\r\n }\r\n\r\n const wrapped = wrapReply(originalPeerTitle, undefined, originalMessage);\r\n if(currentReplyDiv) {\r\n currentReplyDiv.replaceWith(wrapped);\r\n } else {\r\n bubbleContainer.append(wrapped);\r\n }\r\n //bubbleContainer.insertBefore(, nameContainer);\r\n bubble.classList.add('is-reply');\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\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","/*\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: HTMLElement, html: string) {\r\n elem.setAttribute('dir', 'auto');\r\n elem.innerHTML = html;\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 App from \"../../config/app\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport { validateInitObject } from \"../../helpers/object\";\r\nimport I18n from \"../langPack\";\r\nimport { isObject } from \"../mtproto/bin_utils\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport rootScope from \"../rootScope\";\r\nimport SearchIndex from \"../searchIndex\";\r\nimport stateStorage from \"../stateStorage\";\r\nimport appStateManager from \"./appStateManager\";\r\n\r\ntype EmojiLangPack = {\r\n keywords: {\r\n [keyword: string]: string[],\r\n },\r\n version: number,\r\n langCode: string\r\n};\r\n\r\nconst EMOJI_LANG_PACK: EmojiLangPack = {\r\n keywords: {},\r\n version: 0,\r\n langCode: App.langPackCode\r\n};\r\n\r\nconst RECENT_MAX_LENGTH = 36;\r\n\r\nexport class AppEmojiManager {\r\n private static POPULAR_EMOJI = [\"😂\", \"😘\", \"❤️\", \"😍\", \"😊\", \"😁\", \"👍\", \"☺️\", \"😔\", \"😄\", \"😭\", \"💋\", \"😒\", \"😳\", \"😜\", \"🙈\", \"😉\", \"😃\", \"😢\", \"😝\", \"😱\", \"😡\", \"😏\", \"😞\", \"😅\", \"😚\", \"🙊\", \"😌\", \"😀\", \"😋\", \"😆\", \"👌\", \"😐\", \"😕\"];\r\n private keywordLangPacks: {\r\n [langCode: string]: EmojiLangPack\r\n } = {};\r\n\r\n private index: SearchIndex<EmojiLangPack['keywords'][keyof EmojiLangPack['keywords']]>;\r\n private indexedLangPacks: {[langCode: string]: boolean} = {};\r\n\r\n private getKeywordsPromises: {[langCode: string]: Promise<EmojiLangPack>} = {};\r\n\r\n private recent: string[];\r\n private getRecentEmojisPromise: Promise<AppEmojiManager['recent']>;\r\n\r\n /* public getPopularEmoji() {\r\n return stateStorage.get('emojis_popular').then(popEmojis => {\r\n var result = []\r\n if (popEmojis && popEmojis.length) {\r\n for (var i = 0, len = popEmojis.length; i < len; i++) {\r\n result.push({code: popEmojis[i][0], rate: popEmojis[i][1]})\r\n }\r\n callback(result)\r\n return\r\n }\r\n\r\n return stateStorage.get('emojis_recent').then(recentEmojis => {\r\n recentEmojis = recentEmojis || popular || []\r\n var shortcut\r\n var code\r\n for (var i = 0, len = recentEmojis.length; i < len; i++) {\r\n shortcut = recentEmojis[i]\r\n if (Array.isArray(shortcut)) {\r\n shortcut = shortcut[0]\r\n }\r\n if (shortcut && typeof shortcut === 'string') {\r\n if (shortcut.charAt(0) == ':') {\r\n shortcut = shortcut.substr(1, shortcut.length - 2)\r\n }\r\n if (code = shortcuts[shortcut]) {\r\n result.push({code: code, rate: 1})\r\n }\r\n }\r\n }\r\n callback(result)\r\n });\r\n });\r\n }\r\n\r\n function pushPopularEmoji (code) {\r\n getPopularEmoji(function (popularEmoji) {\r\n var exists = false\r\n var count = popularEmoji.length\r\n var result = []\r\n for (var i = 0; i < count; i++) {\r\n if (popularEmoji[i].code == code) {\r\n exists = true\r\n popularEmoji[i].rate++\r\n }\r\n result.push([popularEmoji[i].code, popularEmoji[i].rate])\r\n }\r\n if (exists) {\r\n result.sort(function (a, b) {\r\n return b[1] - a[1]\r\n })\r\n } else {\r\n if (result.length > 41) {\r\n result = result.slice(0, 41)\r\n }\r\n result.push([code, 1])\r\n }\r\n ConfigStorage.set({emojis_popular: result})\r\n })\r\n } */\r\n\r\n public getEmojiKeywords(langCode: string = App.langPackCode) {\r\n const promise = this.getKeywordsPromises[langCode];\r\n if(promise) {\r\n return promise;\r\n }\r\n\r\n const storageKey: any = 'emojiKeywords_' + langCode;\r\n return this.getKeywordsPromises[langCode] = stateStorage.get(storageKey).then((pack: EmojiLangPack) => {\r\n if(!isObject(pack)) {\r\n pack = {} as any;\r\n }\r\n\r\n validateInitObject(EMOJI_LANG_PACK, pack);\r\n\r\n // important\r\n pack.langCode = langCode;\r\n this.keywordLangPacks[langCode] = pack;\r\n\r\n return apiManager.invokeApi('messages.getEmojiKeywordsDifference', {\r\n lang_code: pack.langCode,\r\n from_version: pack.version\r\n }).then((keywordsDifference) => {\r\n pack.version = keywordsDifference.version;\r\n \r\n const packKeywords = pack.keywords;\r\n const keywords = keywordsDifference.keywords;\r\n for(let i = 0, length = keywords.length; i < length; ++i) {\r\n const {keyword, emoticons} = keywords[i];\r\n packKeywords[keyword] = emoticons;\r\n }\r\n\r\n stateStorage.set({\r\n [storageKey]: pack\r\n });\r\n\r\n return pack;\r\n }, () => {\r\n return pack;\r\n });\r\n });\r\n }\r\n\r\n public getBothEmojiKeywords() {\r\n const promises: Promise<any>[] = [\r\n this.getEmojiKeywords()\r\n ];\r\n\r\n if(I18n.lastRequestedLangCode !== App.langPackCode) {\r\n promises.push(this.getEmojiKeywords(I18n.lastRequestedLangCode));\r\n }\r\n\r\n if(!this.recent) {\r\n promises.push(this.getRecentEmojis());\r\n }\r\n\r\n return Promise.all(promises);\r\n }\r\n\r\n public indexEmojis() {\r\n if(!this.index) {\r\n this.index = new SearchIndex(false, false, 2);\r\n }\r\n\r\n for(const langCode in this.keywordLangPacks) {\r\n if(this.indexedLangPacks[langCode]) {\r\n continue;\r\n }\r\n\r\n const pack = this.keywordLangPacks[langCode];\r\n const keywords = pack.keywords;\r\n\r\n for(const keyword in keywords) {\r\n const emoticons = keywords[keyword];\r\n this.index.indexObject(emoticons, keyword);\r\n }\r\n\r\n this.indexedLangPacks[langCode] = true;\r\n }\r\n }\r\n\r\n public searchEmojis(q: string) {\r\n this.indexEmojis();\r\n\r\n q = q.toLowerCase().replace(/_/g, ' ');\r\n \r\n //const perf = performance.now();\r\n let emojis: Array<string>;\r\n if(q.trim()) {\r\n const set = this.index.search(q);\r\n emojis = Array.from(set).reduce((acc, v) => acc.concat(v), []);\r\n } else {\r\n emojis = this.recent.concat(AppEmojiManager.POPULAR_EMOJI).slice(0, RECENT_MAX_LENGTH);\r\n }\r\n\r\n emojis = Array.from(new Set(emojis));\r\n //console.log('searchEmojis', q, 'time', performance.now() - perf);\r\n\r\n /* for(let i = 0, length = emojis.length; i < length; ++i) {\r\n if(emojis[i].includes(zeroWidthJoiner) && !emojis[i].includes('\\ufe0f')) {\r\n emojis[i] += '\\ufe0f';\r\n }\r\n } */\r\n\r\n return emojis;\r\n }\r\n\r\n public getRecentEmojis() {\r\n if(this.getRecentEmojisPromise) return this.getRecentEmojisPromise;\r\n return this.getRecentEmojisPromise = appStateManager.getState().then(state => {\r\n return this.recent = Array.isArray(state.recentEmoji) ? state.recentEmoji : [];\r\n });\r\n }\r\n\r\n public pushRecentEmoji(emoji: string) {\r\n this.getRecentEmojis().then(recent => {\r\n recent.findAndSplice(e => e === emoji);\r\n recent.unshift(emoji);\r\n if(recent.length > RECENT_MAX_LENGTH) {\r\n recent.length = RECENT_MAX_LENGTH;\r\n }\r\n\r\n appStateManager.pushToState('recentEmoji', recent);\r\n rootScope.dispatchEvent('emoji_recent', emoji);\r\n });\r\n }\r\n}\r\n\r\nconst appEmojiManager = new AppEmojiManager();\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appEmojiManager = appEmojiManager);\r\nexport default appEmojiManager;\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 } from \"..\";\r\nimport { cancelEvent } from \"../../../helpers/dom/cancelEvent\";\r\nimport findUpClassName from \"../../../helpers/dom/findUpClassName\";\r\nimport { fastRaf, pause } from \"../../../helpers/schedulers\";\r\nimport { isTouchSupported } from \"../../../helpers/touchSupport\";\r\nimport appEmojiManager from \"../../../lib/appManagers/appEmojiManager\";\r\nimport appImManager from \"../../../lib/appManagers/appImManager\";\r\nimport Config from \"../../../lib/config\";\r\nimport { i18n, LangPackKey } from \"../../../lib/langPack\";\r\nimport { RichTextProcessor } from \"../../../lib/richtextprocessor\";\r\nimport rootScope from \"../../../lib/rootScope\";\r\nimport { emojiFromCodePoints } from \"../../../vendor/emoji\";\r\nimport { putPreloader } from \"../../misc\";\r\nimport Scrollable from \"../../scrollable\";\r\nimport StickyIntersector from \"../../stickyIntersector\";\r\n\r\nconst loadedURLs: Set<string> = new Set();\r\nexport function appendEmoji(emoji: string, container: HTMLElement, prepend = false, unify = false) {\r\n //const emoji = details.unified;\r\n //const emoji = (details.unified as string).split('-')\r\n //.reduce((prev, curr) => prev + String.fromCodePoint(parseInt(curr, 16)), '');\r\n\r\n const spanEmoji = document.createElement('span');\r\n spanEmoji.classList.add('super-emoji');\r\n\r\n let kek: string;\r\n if(unify && !RichTextProcessor.emojiSupported) {\r\n kek = RichTextProcessor.wrapSingleEmoji(emoji);\r\n } else {\r\n emoji = RichTextProcessor.fixEmoji(emoji);\r\n kek = RichTextProcessor.wrapEmojiText(emoji);\r\n }\r\n\r\n /* if(!kek.includes('emoji')) {\r\n console.log(emoji, kek, spanEmoji, emoji.length, new TextEncoder().encode(emoji), emojiUnicode(emoji));\r\n return;\r\n } */\r\n\r\n //console.log(kek);\r\n\r\n spanEmoji.innerHTML = kek;\r\n\r\n if(spanEmoji.children.length > 1) {\r\n const first = spanEmoji.firstElementChild;\r\n spanEmoji.innerHTML = '';\r\n spanEmoji.append(first);\r\n }\r\n\r\n if(spanEmoji.firstElementChild && !RichTextProcessor.emojiSupported) {\r\n const image = spanEmoji.firstElementChild as HTMLImageElement;\r\n \r\n const url = image.src;\r\n if(!loadedURLs.has(url)) {\r\n image.setAttribute('loading', 'lazy');\r\n const placeholder = document.createElement('span');\r\n placeholder.classList.add('emoji-placeholder');\r\n\r\n if(rootScope.settings.animationsEnabled) {\r\n image.style.opacity = '0';\r\n placeholder.style.opacity = '1';\r\n }\r\n\r\n image.addEventListener('load', () => {\r\n fastRaf(() => {\r\n if(rootScope.settings.animationsEnabled) {\r\n image.style.opacity = '';\r\n placeholder.style.opacity = '';\r\n }\r\n\r\n spanEmoji.classList.remove('empty');\r\n\r\n loadedURLs.add(url);\r\n });\r\n }, {once: true});\r\n\r\n spanEmoji.append(placeholder);\r\n }\r\n }\r\n\r\n //spanEmoji = spanEmoji.firstElementChild as HTMLSpanElement;\r\n //spanEmoji.setAttribute('emoji', emoji);\r\n if(prepend) container.prepend(spanEmoji);\r\n else container.appendChild(spanEmoji);\r\n}\r\n\r\nexport function getEmojiFromElement(element: HTMLElement) {\r\n if(!findUpClassName(element, 'super-emoji')) return '';\r\n\r\n if(element.nodeType === 3) return element.nodeValue;\r\n if(element.tagName === 'SPAN' && !element.classList.contains('emoji') && element.firstElementChild) {\r\n element = element.firstElementChild as HTMLElement;\r\n }\r\n \r\n return element.getAttribute('alt') || element.innerText;\r\n}\r\n\r\nexport default class EmojiTab implements EmoticonsTab {\r\n private content: HTMLElement;\r\n\r\n private recentItemsDiv: HTMLElement;\r\n\r\n private scroll: Scrollable;\r\n private stickyIntersector: StickyIntersector;\r\n\r\n init() {\r\n this.content = document.getElementById('content-emoji') as HTMLDivElement;\r\n\r\n const categories: LangPackKey[] = [\r\n 'Emoji.SmilesAndPeople', \r\n 'Emoji.AnimalsAndNature', \r\n 'Emoji.FoodAndDrink', \r\n 'Emoji.TravelAndPlaces', \r\n 'Emoji.ActivityAndSport', \r\n 'Emoji.Objects', \r\n /* 'Emoji.Symbols', */\r\n 'Emoji.Flags', \r\n 'Skin Tones' as any\r\n ];\r\n const divs: {\r\n [category in LangPackKey]?: HTMLDivElement\r\n } = {};\r\n\r\n const sorted: Map<LangPackKey, string[]> = new Map([\r\n [\r\n 'Emoji.Recent',\r\n []\r\n ]\r\n ]);\r\n\r\n for(const emoji in Config.Emoji) {\r\n const details = Config.Emoji[emoji];\r\n const i = '' + details;\r\n const category = categories[+i[0] - 1];\r\n if(!category) continue; // maybe it's skin tones\r\n\r\n let s = sorted.get(category);\r\n if(!s) {\r\n s = [];\r\n sorted.set(category, s);\r\n }\r\n \r\n s[+i.slice(1) || 0] = emoji;\r\n }\r\n\r\n //console.log('emoticons sorted:', sorted);\r\n\r\n //Object.keys(sorted).forEach(c => sorted[c].sort((a, b) => a - b));\r\n\r\n sorted.delete(categories.pop());\r\n\r\n //console.time('emojiParse');\r\n sorted.forEach((emojis, category) => {\r\n const div = document.createElement('div');\r\n div.classList.add('emoji-category');\r\n\r\n const titleDiv = document.createElement('div');\r\n titleDiv.classList.add('category-title');\r\n titleDiv.append(i18n(category));\r\n\r\n const itemsDiv = document.createElement('div');\r\n itemsDiv.classList.add('super-emojis');\r\n\r\n div.append(titleDiv, itemsDiv);\r\n\r\n emojis.forEach(unified => {\r\n /* if(emojiUnicode(emoji) === '1f481-200d-2642') {\r\n console.log('append emoji', emoji, emojiUnicode(emoji));\r\n } */\r\n\r\n let emoji = emojiFromCodePoints(unified);\r\n //if(emoji.includes('🕵')) {\r\n //console.log('toCodePoints', toCodePoints(emoji));\r\n //emoji = emoji.replace(/(\\u200d[\\u2640\\u2642\\u2695])(?!\\ufe0f)/, '\\ufe0f$1');\r\n // const zwjIndex = emoji.indexOf('\\u200d');\r\n // if(zwjIndex !== -1 && !emoji.includes('\\ufe0f')) {\r\n // /* if(zwjIndex !== (emoji.length - 1)) {\r\n // emoji = emoji.replace(/(\\u200d)/g, '\\ufe0f$1');\r\n // } */\r\n\r\n // emoji += '\\ufe0f';\r\n // //emoji += '\\ufe0f';\r\n // }\r\n\r\n //debugger;\r\n //}\r\n\r\n appendEmoji(emoji/* .replace(/[\\ufe0f\\u2640\\u2642\\u2695]/g, '') */, itemsDiv, false/* , false */);\r\n\r\n /* if(category === 'Smileys & Emotion') {\r\n console.log('appended emoji', emoji, itemsDiv.children[itemsDiv.childElementCount - 1].innerHTML, emojiUnicode(emoji));\r\n } */\r\n });\r\n\r\n divs[category] = div;\r\n });\r\n\r\n //console.timeEnd('emojiParse');\r\n\r\n const menu = this.content.previousElementSibling as HTMLElement;\r\n const emojiScroll = this.scroll = new Scrollable(this.content, 'EMOJI');\r\n\r\n //emojiScroll.setVirtualContainer(emojiScroll.container);\r\n\r\n const preloader = putPreloader(this.content, true);\r\n\r\n Promise.all([\r\n pause(200),\r\n appEmojiManager.getRecentEmojis()\r\n ]).then(([_, recent]) => {\r\n preloader.remove();\r\n\r\n this.recentItemsDiv = divs['Emoji.Recent'].querySelector('.super-emojis');\r\n for(const emoji of recent) {\r\n appendEmoji(emoji, this.recentItemsDiv);\r\n }\r\n\r\n this.recentItemsDiv.parentElement.classList.toggle('hide', !this.recentItemsDiv.childElementCount);\r\n\r\n categories.unshift('Emoji.Recent');\r\n categories.map(category => {\r\n const div = divs[category];\r\n \r\n if(!div) {\r\n console.error('no div by category:', category);\r\n }\r\n \r\n emojiScroll.container.append(div);\r\n this.stickyIntersector.observeStickyHeaderChanges(div);\r\n return div;\r\n });\r\n });\r\n\r\n this.content.addEventListener('click', this.onContentClick);\r\n this.stickyIntersector = EmoticonsDropdown.menuOnClick(menu, emojiScroll);\r\n this.init = null;\r\n\r\n rootScope.addEventListener('emoji_recent', (emoji) => {\r\n const children = Array.from(this.recentItemsDiv.children) as HTMLElement[];\r\n for(let i = 0, length = children.length; i < length; ++i) {\r\n const el = children[i];\r\n const _emoji = getEmojiFromElement(el);\r\n if(emoji === _emoji) {\r\n if(i === 0) {\r\n return;\r\n }\r\n\r\n el.remove();\r\n }\r\n }\r\n\r\n appendEmoji(emoji, this.recentItemsDiv, true);\r\n this.recentItemsDiv.parentElement.classList.remove('hide');\r\n });\r\n }\r\n\r\n onContentClick = (e: MouseEvent) => {\r\n cancelEvent(e);\r\n \r\n const emoji = getEmojiFromElement(e.target as HTMLElement);\r\n if(!emoji) {\r\n return;\r\n }\r\n\r\n const messageInput = appImManager.chat.input.messageInput;\r\n let inputHTML = messageInput.innerHTML;\r\n\r\n const html = RichTextProcessor.wrapEmojiText(emoji);\r\n let inserted = false;\r\n if(window.getSelection) {\r\n const savedRange = isTouchSupported ? undefined : emoticonsDropdown.getSavedRange();\r\n let sel = window.getSelection();\r\n if(savedRange) {\r\n sel.removeAllRanges();\r\n sel.addRange(savedRange);\r\n }\r\n\r\n if(sel.getRangeAt && sel.rangeCount) {\r\n var el = document.createElement('div');\r\n el.innerHTML = html;\r\n var node = el.firstChild;\r\n var range = sel.getRangeAt(0);\r\n range.deleteContents();\r\n //range.insertNode(document.createTextNode(' '));\r\n range.insertNode(node);\r\n range.setStart(node, 0);\r\n inserted = true;\r\n \r\n setTimeout(() => {\r\n range = document.createRange();\r\n range.setStartAfter(node);\r\n range.collapse(true);\r\n sel.removeAllRanges();\r\n sel.addRange(range);\r\n }, 0);\r\n }\r\n }\r\n\r\n if(!inserted || messageInput.innerHTML === inputHTML) {\r\n messageInput.insertAdjacentHTML('beforeend', html);\r\n }\r\n \r\n // Append to input\r\n const event = new Event('input', {bubbles: true, cancelable: true});\r\n messageInput.dispatchEvent(event);\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 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\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\r\n constructor(private element: HTMLElement, private group: string, private scrollable: Scrollable) {\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 let timeout = 0;\r\n // memory leak\r\n scrollable.container.addEventListener('scroll', () => {\r\n if(timeout) {\r\n clearTimeout(timeout);\r\n } else {\r\n this.scrollPromise = deferredPromise<void>();\r\n //animationIntersector.checkAnimations(true, group);\r\n }\r\n\r\n timeout = window.setTimeout(() => {\r\n timeout = 0;\r\n this.scrollPromise.resolve();\r\n //animationIntersector.checkAnimations(false, group);\r\n }, 150);\r\n });\r\n }\r\n\r\n 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 processInvisibleDiv = async(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 new Promise((resolve) => {\r\n window.requestAnimationFrame(() => window.requestAnimationFrame(resolve));\r\n });\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) {\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 this.element.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\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 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.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\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 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);\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 } from \"../../layer\";\r\nimport appPeersManager from \"./appPeersManager\";\r\nimport apiManagerProxy from \"../mtproto/mtprotoworker\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport appDocsManager from \"./appDocsManager\";\r\nimport appPhotosManager from \"./appPhotosManager\";\r\nimport appUsersManager from \"./appUsersManager\";\r\nimport appMessagesManager from \"./appMessagesManager\";\r\n\r\nexport class AppInlineBotsManager {\r\n private inlineResults: {[qId: string]: BotInlineResult} = {};\r\n\r\n public getInlineResults(peerId: number, botId: number, query = '', offset = '', geo?: any) {\r\n return apiManagerProxy.invokeApi('messages.getInlineBotResults', {\r\n bot: appUsersManager.getUserInput(botId),\r\n peer: appPeersManager.getInputPeerById(peerId),\r\n query: query,\r\n geo_point: (geo && {_: 'inputGeoPoint', lat: geo['lat'], long: geo['long']}) || undefined,\r\n offset\r\n }, {/* timeout: 1, */stopTime: -1, noErrorBox: true}).then(botResults => {\r\n const queryId = botResults.query_id;\r\n /* delete botResults._;\r\n delete 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 const qId = queryId + '_' + result.id;\r\n /* result.qID = qID;\r\n result.botID = botID;\r\n \r\n result.rTitle = RichTextProcessor.wrapRichText(result.title, {noLinebreaks: true, noLinks: true});\r\n result.rDescription = RichTextProcessor.wrapRichText(result.description, {noLinebreaks: true, noLinks: true});\r\n result.initials = ((result as botInlineResult).url || result.title || result.type || '').substr(0, 1); */\r\n\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[qId] = result;\r\n });\r\n\r\n return botResults;\r\n });\r\n }\r\n \r\n /* function getPopularBots () {\r\n return Storage.get('inline_bots_popular').then(function (bots) {\r\n var result = []\r\n var i, len\r\n var userId\r\n if (bots && bots.length) {\r\n var now = tsNow(true)\r\n for (i = 0, len = bots.length; i < len; i++) {\r\n if ((now - bots[i][3]) > 14 * 86400) {\r\n continue\r\n }\r\n userId = bots[i][0]\r\n if (!AppUsersManager.hasUser(userId)) {\r\n AppUsersManager.saveApiUser(bots[i][1])\r\n }\r\n result.push({id: userId, rate: bots[i][2], date: bots[i][3]})\r\n }\r\n }\r\n return result\r\n })\r\n }\r\n \r\n function pushPopularBot (id) {\r\n getPopularBots().then(function (bots) {\r\n var exists = false\r\n var count = bots.length\r\n var result = []\r\n for (var i = 0; i < count; i++) {\r\n if (bots[i].id === id) {\r\n exists = true\r\n bots[i].rate++\r\n bots[i].date = tsNow(true)\r\n }\r\n var user = AppUsersManager.getUser(bots[i].id)\r\n result.push([bots[i].id, user, bots[i].rate, bots[i].date])\r\n }\r\n if (exists) {\r\n result.sort(function (a, b) {\r\n return b[2] - a[2]\r\n })\r\n } else {\r\n if (result.length > 15) {\r\n result = result.slice(0, 15)\r\n }\r\n result.push([id, AppUsersManager.getUser(id), 1, tsNow(true)])\r\n }\r\n ConfigStorage.set({inline_bots_popular: result})\r\n \r\n rootScope.$broadcast('inline_bots_popular')\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 function switchToPM (fromPeerID, botID, startParam) {\r\n var peerString = AppPeersManager.getPeerString(fromPeerID)\r\n var setHash = {}\r\n setHash['inline_switch_pm' + botID] = {peer: peerString, time: tsNow()}\r\n Storage.set(setHash)\r\n rootScope.$broadcast('history_focus', {peerString: AppPeersManager.getPeerString(botID)})\r\n AppMessagesManager.startBot(botID, 0, startParam)\r\n }\r\n \r\n function checkSwitchReturn (botID) {\r\n var bot = AppUsersManager.getUser(botID)\r\n if (!bot || !bot.pFlags.bot || !bot.bot_inline_placeholder) {\r\n return qSync.when(false)\r\n }\r\n var key = 'inline_switch_pm' + botID\r\n return Storage.get(key).then(function (peerData) {\r\n if (peerData) {\r\n Storage.remove(key)\r\n if (tsNow() - peerData.time < 3600000) {\r\n return peerData.peer\r\n }\r\n }\r\n return false\r\n })\r\n }\r\n \r\n function switchInlineQuery (botID, toPeerString, query) {\r\n rootScope.$broadcast('history_focus', {\r\n peerString: toPeerString,\r\n attachment: {\r\n _: 'inline_query',\r\n mention: '@' + AppUsersManager.getUser(botID).username,\r\n query: query\r\n }\r\n })\r\n }\r\n \r\n function switchInlineButtonClick (id, button) {\r\n var message = AppMessagesManager.getMessage(id)\r\n var botID = message.viaBotId || message.fromId\r\n if (button.pFlags && button.pFlags.same_peer) {\r\n var peerId = AppMessagesManager.getMessagePeer(message)\r\n var toPeerString = AppPeersManager.getPeerString(peerId)\r\n switchInlineQuery(botID, toPeerString, button.query)\r\n return\r\n }\r\n return checkSwitchReturn(botID).then(function (retPeerString) {\r\n if (retPeerString) {\r\n return switchInlineQuery(botID, retPeerString, button.query)\r\n }\r\n PeersSelectService.selectPeer({\r\n canSend: true\r\n }).then(function (toPeerString) {\r\n return switchInlineQuery(botID, toPeerString, button.query)\r\n })\r\n })\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: appMessagesManager.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 function sendInlineResult (peerId, qID, options) {\r\n var inlineResult = inlineResults[qID]\r\n if (inlineResult === undefined) {\r\n return false\r\n }\r\n pushPopularBot(inlineResult.botID)\r\n var splitted = qID.split('_')\r\n var queryID = splitted.shift()\r\n var resultID = splitted.join('_')\r\n options = options || {}\r\n options.viaBotId = inlineResult.botID\r\n options.queryID = queryID\r\n options.resultID = resultID\r\n if (inlineResult.send_message.reply_markup) {\r\n options.reply_markup = 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 var caption = ''\r\n var inputMedia = false\r\n switch (inlineResult.send_message._) {\r\n case 'botInlineMessageMediaAuto':\r\n caption = inlineResult.send_message.caption\r\n if (inlineResult._ === 'botInlineMediaResult') {\r\n var doc = inlineResult.document\r\n var photo = inlineResult.photo\r\n if (doc) {\r\n inputMedia = {\r\n _: 'inputMediaDocument',\r\n id: {_: 'inputDocument', id: doc.id, access_hash: doc.access_hash},\r\n caption: caption\r\n }\r\n } else {\r\n inputMedia = {\r\n _: 'inputMediaPhoto',\r\n id: {_: 'inputPhoto', id: photo.id, access_hash: photo.access_hash},\r\n caption: caption\r\n }\r\n }\r\n }\r\n break\r\n \r\n case 'botInlineMessageMediaGeo':\r\n inputMedia = {\r\n _: 'inputMediaGeoPoint',\r\n geo_point: {\r\n _: 'inputGeoPoint',\r\n 'lat': inlineResult.send_message.geo['lat'],\r\n 'long': inlineResult.send_message.geo['long']\r\n }\r\n }\r\n break\r\n \r\n case 'botInlineMessageMediaVenue':\r\n inputMedia = {\r\n _: 'inputMediaVenue',\r\n geo_point: {\r\n _: 'inputGeoPoint',\r\n 'lat': inlineResult.send_message.geo['lat'],\r\n 'long': inlineResult.send_message.geo['long']\r\n },\r\n title: inlineResult.send_message.title,\r\n address: inlineResult.send_message.address,\r\n provider: inlineResult.send_message.provider,\r\n venue_id: inlineResult.send_message.venue_id\r\n }\r\n break\r\n \r\n case 'botInlineMessageMediaContact':\r\n inputMedia = {\r\n _: 'inputMediaContact',\r\n phone_number: inlineResult.send_message.phone_number,\r\n first_name: inlineResult.send_message.first_name,\r\n last_name: inlineResult.send_message.last_name\r\n }\r\n break\r\n }\r\n if (!inputMedia) {\r\n inputMedia = {\r\n _: 'messageMediaPending',\r\n type: inlineResult.type,\r\n file_name: inlineResult.title || inlineResult.content_url || inlineResult.url,\r\n size: 0,\r\n progress: {percent: 30, total: 0}\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\nexport default appInlineBotsManager;","/*\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.lazyLoadQueue.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 { isTouchSupported } from \"./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(isTouchSupported) {\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(!isTouchSupported) {\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 }, isTouchSupported ? 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 }, isTouchSupported ? 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","/*\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 { isTouchSupported } from \"../../helpers/touchSupport\";\r\nimport appChatsManager from \"../../lib/appManagers/appChatsManager\";\r\nimport appImManager from \"../../lib/appManagers/appImManager\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport animationIntersector from \"../animationIntersector\";\r\nimport { horizontalMenu } from \"../horizontalMenu\";\r\nimport LazyLoadQueue, { LazyLoadQueueIntersector } from \"../lazyLoadQueue\";\r\nimport Scrollable, { ScrollableX } from \"../scrollable\";\r\nimport appSidebarRight from \"../sidebarRight\";\r\nimport StickyIntersector from \"../stickyIntersector\";\r\nimport EmojiTab from \"./tabs/emoji\";\r\nimport GifsTab from \"./tabs/gifs\";\r\nimport StickersTab from \"./tabs/stickers\";\r\nimport { pause } from \"../../helpers/schedulers\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport AppGifsTab from \"../sidebarRight/tabs/gifs\";\r\nimport AppStickersTab from \"../sidebarRight/tabs/stickers\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport blurActiveElement from \"../../helpers/dom/blurActiveElement\";\r\nimport whichChild from \"../../helpers/dom/whichChild\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport DropdownHover from \"../../helpers/dropdownHover\";\r\n\r\nexport const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';\r\n\r\nexport interface EmoticonsTab {\r\n init: () => void,\r\n onCloseAfterTimeout?: () => void\r\n}\r\n\r\nexport class EmoticonsDropdown extends DropdownHover {\r\n public static lazyLoadQueue = new LazyLoadQueue();\r\n\r\n private emojiTab: EmojiTab;\r\n public stickersTab: StickersTab;\r\n private gifsTab: GifsTab;\r\n\r\n private container: HTMLElement;\r\n private tabsEl: HTMLElement;\r\n private tabId = -1;\r\n\r\n private tabs: {[id: number]: EmoticonsTab};\r\n\r\n private searchButton: HTMLElement;\r\n private deleteBtn: HTMLElement;\r\n\r\n private selectTab: ReturnType<typeof horizontalMenu>;\r\n\r\n private savedRange: Range;\r\n\r\n constructor() {\r\n super({\r\n element: document.getElementById('emoji-dropdown') as HTMLDivElement\r\n });\r\n\r\n this.addEventListener('open', async() => {\r\n if(isTouchSupported) {\r\n //appImManager.chat.input.saveScroll();\r\n if(blurActiveElement()) {\r\n await pause(100);\r\n }\r\n }\r\n\r\n if(this.element.parentElement !== appImManager.chat.input.chatInput) {\r\n appImManager.chat.input.chatInput.append(this.element);\r\n }\r\n\r\n const sel = document.getSelection();\r\n if(sel.rangeCount && document.activeElement === appImManager.chat.input.messageInput) {\r\n this.savedRange = sel.getRangeAt(0);\r\n } else {\r\n this.savedRange = undefined;\r\n }\r\n\r\n EmoticonsDropdown.lazyLoadQueue.lock();\r\n //EmoticonsDropdown.lazyLoadQueue.unlock();\r\n animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);\r\n });\r\n\r\n this.addEventListener('opened', () => {\r\n animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);\r\n EmoticonsDropdown.lazyLoadQueue.unlock();\r\n EmoticonsDropdown.lazyLoadQueue.refresh();\r\n\r\n this.container.classList.remove('disable-hover');\r\n });\r\n\r\n this.addEventListener('close', () => {\r\n EmoticonsDropdown.lazyLoadQueue.lock();\r\n //EmoticonsDropdown.lazyLoadQueue.lock();\r\n\r\n // нужно залочить группу и выключить стикеры\r\n animationIntersector.lockIntersectionGroup(EMOTICONSSTICKERGROUP);\r\n animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);\r\n });\r\n\r\n this.addEventListener('closed', () => {\r\n // теперь можно убрать visible, чтобы они не включились после фокуса\r\n animationIntersector.unlockIntersectionGroup(EMOTICONSSTICKERGROUP);\r\n EmoticonsDropdown.lazyLoadQueue.unlock();\r\n EmoticonsDropdown.lazyLoadQueue.refresh();\r\n\r\n this.container.classList.remove('disable-hover');\r\n\r\n this.savedRange = undefined;\r\n });\r\n }\r\n\r\n protected init() {\r\n this.emojiTab = new EmojiTab();\r\n this.stickersTab = new StickersTab();\r\n this.gifsTab = new GifsTab();\r\n\r\n this.tabs = {\r\n 0: this.emojiTab,\r\n 1: this.stickersTab,\r\n 2: this.gifsTab\r\n };\r\n\r\n this.container = this.element.querySelector('.emoji-container .tabs-container') as HTMLDivElement;\r\n this.tabsEl = this.element.querySelector('.emoji-tabs') as HTMLUListElement;\r\n this.selectTab = horizontalMenu(this.tabsEl, this.container, this.onSelectTabClick, () => {\r\n const tab = this.tabs[this.tabId];\r\n if(tab.init) {\r\n tab.init();\r\n }\r\n\r\n tab.onCloseAfterTimeout && tab.onCloseAfterTimeout();\r\n animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);\r\n });\r\n\r\n this.searchButton = this.element.querySelector('.emoji-tabs-search');\r\n this.searchButton.addEventListener('click', () => {\r\n if(this.tabId === 1) {\r\n if(!appSidebarRight.isTabExists(AppStickersTab)) {\r\n new AppStickersTab(appSidebarRight).open();\r\n }\r\n } else {\r\n if(!appSidebarRight.isTabExists(AppGifsTab)) {\r\n new AppGifsTab(appSidebarRight).open();\r\n }\r\n }\r\n });\r\n\r\n this.deleteBtn = this.element.querySelector('.emoji-tabs-delete');\r\n this.deleteBtn.addEventListener('click', (e) => {\r\n const input = appImManager.chat.input.messageInput;\r\n if((input.lastChild as any)?.tagName) {\r\n input.lastElementChild.remove();\r\n } else if(input.lastChild) {\r\n if(!input.lastChild.textContent.length) {\r\n input.lastChild.remove();\r\n } else {\r\n input.lastChild.textContent = input.lastChild.textContent.slice(0, -1);\r\n }\r\n }\r\n\r\n const event = new Event('input', {bubbles: true, cancelable: true});\r\n appImManager.chat.input.messageInput.dispatchEvent(event);\r\n //appSidebarRight.stickersTab.init();\r\n\r\n cancelEvent(e);\r\n });\r\n\r\n (this.tabsEl.children[1] as HTMLLIElement).click(); // set emoji tab\r\n if(this.tabs[0].init) {\r\n this.tabs[0].init(); // onTransitionEnd не вызовется, т.к. это первая открытая вкладка\r\n }\r\n\r\n rootScope.addEventListener('peer_changed', this.checkRights);\r\n this.checkRights();\r\n\r\n return super.init();\r\n }\r\n\r\n private onSelectTabClick = (id: number) => {\r\n if(this.tabId === id) {\r\n return;\r\n }\r\n \r\n animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);\r\n\r\n this.tabId = id;\r\n this.searchButton.classList.toggle('hide', this.tabId === 0);\r\n this.deleteBtn.classList.toggle('hide', this.tabId !== 0);\r\n };\r\n\r\n private checkRights = () => {\r\n const peerId = appImManager.chat.peerId;\r\n const children = this.tabsEl.children;\r\n const tabsElements = Array.from(children) as HTMLElement[];\r\n\r\n const canSendStickers = peerId > 0 || appChatsManager.hasRights(peerId, 'send_stickers');\r\n tabsElements[2].toggleAttribute('disabled', !canSendStickers);\r\n\r\n const canSendGifs = peerId > 0 || appChatsManager.hasRights(peerId, 'send_gifs');\r\n tabsElements[3].toggleAttribute('disabled', !canSendGifs);\r\n\r\n const active = this.tabsEl.querySelector('.active');\r\n if(active && whichChild(active) !== 1 && (!canSendStickers || !canSendGifs)) {\r\n this.selectTab(0, false);\r\n }\r\n };\r\n\r\n public static menuOnClick = (menu: HTMLElement, scroll: Scrollable, menuScroll?: ScrollableX) => {\r\n let prevId = 0;\r\n let jumpedTo = -1;\r\n\r\n const setActive = (id: number) => {\r\n if(id === prevId) {\r\n return false;\r\n }\r\n\r\n menu.children[prevId].classList.remove('active');\r\n menu.children[id].classList.add('active');\r\n prevId = id;\r\n\r\n return true;\r\n };\r\n\r\n const stickyIntersector = new StickyIntersector(scroll.container, (stuck, target) => {\r\n //console.log('sticky scrollTOp', stuck, target, scroll.container.scrollTop);\r\n\r\n if(Math.abs(jumpedTo - scroll.container.scrollTop) <= 1) {\r\n return;\r\n } else {\r\n jumpedTo = -1;\r\n }\r\n\r\n const which = whichChild(target);\r\n if(!stuck && which) { // * due to stickyIntersector\r\n return;\r\n }\r\n\r\n setActive(which);\r\n\r\n if(menuScroll) {\r\n if(which < menu.childElementCount - 4) {\r\n menuScroll.container.scrollLeft = (which - 3) * 47;\r\n } else {\r\n menuScroll.container.scrollLeft = which * 47;\r\n }\r\n }\r\n });\r\n\r\n menu.addEventListener('click', (e) => {\r\n let target = e.target as HTMLElement;\r\n target = findUpClassName(target, 'menu-horizontal-div-item');\r\n\r\n if(!target) {\r\n return;\r\n }\r\n\r\n const which = whichChild(target);\r\n\r\n /* if(menuScroll) {\r\n menuScroll.scrollIntoView(target, false, 0);\r\n } */\r\n\r\n if(!setActive(which)) {\r\n return;\r\n }\r\n\r\n const element = (scroll.splitUp || scroll.container).children[which] as HTMLElement;\r\n const offsetTop = element.offsetTop + 1; // * due to stickyIntersector\r\n\r\n scroll.container.scrollTop = jumpedTo = offsetTop;\r\n\r\n //console.log('set scrollTop:', offsetTop);\r\n });\r\n\r\n return stickyIntersector;\r\n };\r\n\r\n public static onMediaClick = (e: {target: EventTarget | Element}, clearDraft = false) => {\r\n let target = e.target as HTMLElement;\r\n target = findUpTag(target, 'DIV');\r\n\r\n if(!target) return;\r\n \r\n const fileId = target.dataset.docId;\r\n if(!fileId) return;\r\n\r\n if(appImManager.chat.input.sendMessageWithDocument(fileId, undefined, clearDraft)) {\r\n /* dropdown.classList.remove('active');\r\n toggleEl.classList.remove('active'); */\r\n if(emoticonsDropdown.container) {\r\n emoticonsDropdown.forceClose = true;\r\n emoticonsDropdown.container.classList.add('disable-hover');\r\n emoticonsDropdown.toggle(false);\r\n }\r\n } else {\r\n console.warn('got no doc by id:', fileId);\r\n }\r\n };\r\n\r\n public addLazyLoadQueueRepeat(lazyLoadQueue: LazyLoadQueueIntersector, processInvisibleDiv: (div: HTMLElement) => void) {\r\n this.addEventListener('close', () => {\r\n lazyLoadQueue.lock();\r\n });\r\n\r\n this.addEventListener('closed', () => {\r\n const divs = lazyLoadQueue.intersector.getVisible();\r\n\r\n for(const div of divs) {\r\n processInvisibleDiv(div);\r\n }\r\n\r\n lazyLoadQueue.intersector.clearVisible();\r\n });\r\n\r\n this.addEventListener('opened', () => {\r\n lazyLoadQueue.unlockAndRefresh();\r\n });\r\n }\r\n\r\n public getSavedRange() {\r\n return this.savedRange;\r\n }\r\n}\r\n\r\nconst emoticonsDropdown = new EmoticonsDropdown();\r\nMOUNT_CLASS_TO.emoticonsDropdown = emoticonsDropdown;\r\nexport default emoticonsDropdown;\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 { 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 Chat from \"./chat\";\r\nimport { CHAT_ANIMATION_GROUP } from \"../../lib/appManagers/appImManager\";\r\nimport { getObjectKeysAndSort } from \"../../helpers/object\";\r\nimport { isTouchSupported } from \"../../helpers/touchSupport\";\r\nimport { logger } from \"../../lib/logger\";\r\nimport rootScope, { BroadcastEvents } from \"../../lib/rootScope\";\r\nimport AppMediaViewer from \"../appMediaViewer\";\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 { isAndroid, isApple, isMobile, isSafari } from \"../../helpers/userAgent\";\r\nimport I18n, { i18n, langPack } from \"../../lib/langPack\";\r\nimport AvatarElement from \"../avatar\";\r\nimport { formatPhoneNumber } from \"../misc\";\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, Update } 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 { CancellablePromise, 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\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 scrollingToNewBubble: 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 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 ) {\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', (e) => {\r\n const {storage, peerId, mid} = e;\r\n \r\n if(mid && peerId === this.peerId && 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.scrollingToNewBubble) {\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', (e) => {\r\n let peerId: number = e.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[message-id=\"${tempId}\"], .document[data-doc-id=\"${tempId}\"]`) as HTMLElement;\r\n if(element) {\r\n if(element instanceof AudioElement) {\r\n element.setAttribute('doc-id', message.media.document.id);\r\n element.setAttribute('message-id', '' + mid);\r\n element.message = message;\r\n element.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.renderMessage(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', (e) => {\r\n fastRaf(() => {\r\n const {storage, peerId, mid} = e;\r\n \r\n if(peerId !== this.peerId || storage !== this.chat.getMessagesStorage()) return;\r\n const mounted = this.getMountedBubble(mid);\r\n if(!mounted) return;\r\n\r\n const updatePosition = this.chat.type === 'scheduled';\r\n this.renderMessage(mounted.message, true, false, mounted.bubble, updatePosition);\r\n this.scrollToBubbleIfLast(mounted.bubble);\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', (e) => {\r\n //fastRaf(() => { // ! can't use delayed smth here, need original bubble to be edited\r\n const {peerId, groupId, deletedMids} = e;\r\n \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.renderMessage(this.chat.getMessage(renderMaxId), true, false, this.bubbles[renderedId], false);\r\n //});\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('messages_downloaded', (e) => {\r\n const {peerId, mids} = e;\r\n\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 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(!isMobile) {\r\n this.listenerSetter.add(this.bubblesContainer)('dblclick', (e) => {\r\n if(this.chat.selection.isSelecting || !this.appMessagesManager.canWriteToPeer(this.peerId, this.chat.threadId)) {\r\n return;\r\n }\r\n \r\n const bubble = (e.target as HTMLElement).classList.contains('bubble') ? e.target as HTMLElement : null;\r\n if(bubble && !bubble.classList.contains('bubble-first')) {\r\n const mid = +bubble.dataset.mid\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', (e) => {\r\n const {peerId, storage, mid} = e;\r\n\r\n if(peerId !== this.peerId || 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', (e) => {\r\n const {peerId, msgs} = e;\r\n\r\n const mids = Object.keys(msgs).map(s => +s);\r\n\r\n if(peerId === this.peerId) {\r\n this.deleteMessagesByIds(mids);\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('dialog_unread', (e) => {\r\n const info = e;\r\n\r\n if(info.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', (e) => {\r\n const dialogs = e;\r\n\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', (e) => {\r\n const chatId: number = e;\r\n if(this.peerId === -chatId) {\r\n const hadRights = this.chatInner.classList.contains('has-rights');\r\n const hasRights = this.appMessagesManager.canWriteToPeer(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.renderMessage(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.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 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 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(Object.keys(this.appMessagesManager.getScheduledMessagesStorage(this.peerId)).length);\r\n };\r\n\r\n this.listenerSetter.add(rootScope)('scheduled_new', (e) => {\r\n const {peerId, mid} = e;\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', (e) => {\r\n const {peerId, mids} = e;\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 // ! 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(isTouchSupported && 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.toggleByBubble(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\r\n this.appMessagesManager.wrapSingleMessage(peerId, threadId).then(() => {\r\n this.appMessagesManager.generateThreadServiceStartMessage(this.appMessagesManager.getMessageByPeer(peerId, threadId));\r\n this.chat.appImManager.setInnerPeer(peerId, message.fwd_from.saved_from_msg_id, 'discussion', threadId);\r\n });\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(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';\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 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 let messageId = +findUpClassName(target, 'album-item')?.dataset.mid || +bubble.dataset.mid;\r\n let 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 let targets: {element: HTMLElement, mid: number, peerId: number}[] = [];\r\n let 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 let message = this.chat.getMessage(id);\r\n \r\n return message.media && (message.media.photo || (message.media.document && (message.media.document.type === 'video' || message.media.document.type === 'gif')) || (message.media.webpage && (message.media.webpage.document || message.media.webpage.photo)));\r\n }).sort((a, b) => a - b);\r\n\r\n ids.forEach(id => {\r\n let withTail = this.bubbles[id].classList.contains('with-media-tail');\r\n let str = '.album-item video, .album-item img, .preview video, .preview img, ';\r\n if(withTail) {\r\n str += '.bubble__media-container';\r\n } else {\r\n str += '.attachment video, .attachment img';\r\n }\r\n\r\n const hasAspecter = !!this.bubbles[id].querySelector('.media-container-aspecter');\r\n let elements = this.bubbles[id].querySelectorAll(str) as NodeListOf<HTMLElement>;\r\n const parents: Set<HTMLElement> = new Set();\r\n Array.from(elements).forEach((element: HTMLElement) => {\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?.dataset.mid || id,\r\n peerId: this.peerId\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: 'inputMessagesFilterPhotoVideo'\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 new PopupForward(this.peerId, [mid]);\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 = (this.appPhotosManager.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 in group) {\r\n if(this.bubbles[mid]) {\r\n const maxId = Math.max(...Object.keys(group).map(id => +id)); // * 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(!isTouchSupported) {\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(isTouchSupported) {\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 //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(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 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 this.scrollToBubbleEnd();\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 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?: HTMLElement) {\r\n if(!bubble) {\r\n const lastDateGroup = this.getLastDateGroup();\r\n if(lastDateGroup) {\r\n bubble = lastDateGroup.lastElementChild as HTMLElement;\r\n }\r\n }\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.scrollingToNewBubble = bubble;\r\n this.scrollToBubble(bubble, 'end').then(() => {\r\n this.scrollingToNewBubble = null;\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().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(!(dateTimestamp in this.dateMessages)) {\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 if(today.getTime() === date.getTime()) {\r\n dateElement = i18n(this.chat.type === 'scheduled' ? 'Chat.Date.ScheduledForToday' : 'Date.Today');\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(this.chat.type === 'scheduled') {\r\n dateElement = i18n('Chat.Date.ScheduledFor', [dateElement]);\r\n }\r\n }\r\n\r\n /* if(this.chat.type === 'scheduled') {\r\n str = 'Scheduled for ' + str;\r\n } */\r\n \r\n const div = document.createElement('div');\r\n div.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 div.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\r\n const haveTimestamps = getObjectKeysAndSort(this.dateMessages, 'asc');\r\n let i = 0;\r\n for(; i < haveTimestamps.length; ++i) {\r\n const t = haveTimestamps[i];\r\n if(dateTimestamp < t) {\r\n break;\r\n }\r\n }\r\n \r\n this.dateMessages[dateTimestamp] = {\r\n div,\r\n container,\r\n firstTimestamp: date.getTime()\r\n };\r\n\r\n container.append(div);\r\n\r\n positionElementByIndex(container, this.chatInner, i);\r\n\r\n /* if(reverse) {\r\n this.chatInner.prepend(container);\r\n } else {\r\n this.chatInner.append(container);\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.stickyIntersector && this.stickyIntersector.disconnect();\r\n\r\n delete this.lazyLoadQueue;\r\n this.unreadedObserver && delete this.unreadedObserver;\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 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 ////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()) {\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.canWriteToPeer(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 this.bubbleGroups.addBubble(bubble, message, reverse);\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 public 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(...Object.keys(storage).map(i => +i));\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 || (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.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 \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 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.reply_markup && message.reply_markup._ === 'replyInlineMarkup' && message.reply_markup.rows && message.reply_markup.rows.length) {\r\n const rows = message.reply_markup.rows;\r\n\r\n const containerDiv = document.createElement('div');\r\n containerDiv.classList.add('reply-markup');\r\n rows.forEach((row: any) => {\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: any) => {\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 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.innerHTML = 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')) 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 bubble.classList.add('hide-name', 'photo');\r\n \r\n const storage = this.appMessagesManager.groupedMessagesStorage[message.grouped_id];\r\n if(message.grouped_id && Object.keys(storage).length !== 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 = !isAndroid && 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 = messageMedia.webpage;\r\n ////////this.log('messageMediaWebPage', webpage);\r\n if(webpage._ === 'webPageEmpty') {\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 if(webpage.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 let doc: any = null;\r\n if(webpage.document) {\r\n doc = webpage.document;\r\n \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 });\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 if(previewResizer) {\r\n quote.append(previewResizer);\r\n }\r\n \r\n let quoteTextDiv = document.createElement('div');\r\n quoteTextDiv.classList.add('quote-text');\r\n\r\n if(webpage.site_name) {\r\n let nameEl = document.createElement('a');\r\n nameEl.classList.add('webpage-name');\r\n nameEl.setAttribute('target', '_blank');\r\n nameEl.href = webpage.url || '#';\r\n setInnerHTML(nameEl, RichTextProcessor.wrapEmojiText(webpage.site_name));\r\n quoteTextDiv.append(nameEl);\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 }\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 }\r\n\r\n quote.append(quoteTextDiv);\r\n\r\n if(webpage.photo && !doc) {\r\n bubble.classList.add('photo');\r\n\r\n const size = webpage.photo.sizes[webpage.photo.sizes.length - 1];\r\n let isSquare = false;\r\n if(size.w === size.h && quoteTextDiv.childElementCount) {\r\n bubble.classList.add('is-square-photo');\r\n isSquare = true;\r\n this.appPhotosManager.setAttachmentSize(webpage.photo, preview, 80, 80, false);\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: webpage.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 messageDiv.insertBefore(box, messageDiv.lastElementChild);\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 let 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 \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\r\n break;\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 if(doc.type === 'round' || !messageMessage) {\r\n canHaveTail = false;\r\n }\r\n \r\n bubble.classList.add('hide-name', doc.type === 'round' ? 'round' : 'video');\r\n const storage = this.appMessagesManager.groupedMessagesStorage[message.grouped_id];\r\n if(message.grouped_id && Object.keys(storage).length !== 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 = !isAndroid && !isApple && doc.type !== 'round' && 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 });\r\n }\r\n \r\n break;\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 });\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 break;\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(this.chat.selection.isSelecting) {\r\n this.chat.selection.toggleBubbleCheckbox(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 if(needName || message.fwd_from || message.reply_to_mid) { // chat\r\n let title: HTMLSpanElement;\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 } 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')) {\r\n let nameDiv = document.createElement('div');\r\n nameDiv.classList.add('name');\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')) {\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) {\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 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(!bubble.classList.contains('sticker') && 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 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.renderMessage(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(isSafari/* && !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.appMessagesManager.getServerMessageId(m)), \r\n bottomIds.map(m => this.appMessagesManager.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(!isSafari) {\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.renderMessage(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.canWriteToPeer(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.appMessagesManager.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, this.appPhotosManager.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","/*\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 appChatsManager from \"../../lib/appManagers/appChatsManager\";\r\nimport appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport { addCancelButton } from \".\";\r\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerOptions } from \"./peer\";\r\nimport { ChatType } from \"../chat/chat\";\r\nimport { i18n, LangPackKey } from \"../../lib/langPack\";\r\nimport PeerTitle from \"../peerTitle\";\r\n\r\nexport default class PopupDeleteMessages {\r\n constructor(peerId: number, mids: number[], type: ChatType, onConfirm?: () => void) {\r\n const peerTitleElement = new PeerTitle({\r\n peerId,\r\n onlyFirstName: true\r\n }).element;\r\n\r\n mids = mids.slice();\r\n const callback = (checked: PopupPeerButtonCallbackCheckboxes, revoke?: boolean) => {\r\n onConfirm && onConfirm();\r\n if(type === 'scheduled') {\r\n appMessagesManager.deleteScheduledMessages(peerId, mids);\r\n } else {\r\n appMessagesManager.deleteMessages(peerId, mids, !!checked.size || revoke);\r\n }\r\n };\r\n\r\n let title: LangPackKey, titleArgs: any[], description: LangPackKey, descriptionArgs: any[], buttons: PopupPeerOptions['buttons'], checkboxes: PopupPeerOptions['checkboxes'] = [];\r\n if(mids.length === 1) {\r\n title = 'DeleteSingleMessagesTitle';\r\n } else {\r\n title = 'DeleteMessagesTitle';\r\n titleArgs = [i18n('messages', [mids.length])];\r\n }\r\n \r\n description = mids.length === 1 ? 'AreYouSureDeleteSingleMessage' : 'AreYouSureDeleteFewMessages';\r\n\r\n buttons = [{\r\n langKey: 'Delete',\r\n isDanger: true,\r\n callback\r\n }];\r\n\r\n if(peerId === rootScope.myId || type === 'scheduled') {\r\n \r\n } else {\r\n if(peerId > 0) {\r\n checkboxes.push({\r\n text: 'DeleteMessagesOptionAlso',\r\n textArgs: [peerTitleElement]\r\n });\r\n } else {\r\n const chat = appChatsManager.getChat(-peerId);\r\n\r\n const hasRights = appChatsManager.hasRights(-peerId, 'delete_messages');\r\n if(chat._ === 'chat') {\r\n const canRevoke = hasRights ? mids.slice() : mids.filter(mid => {\r\n const message = appMessagesManager.getMessageByPeer(peerId, mid);\r\n return message.fromId === rootScope.myId;\r\n });\r\n\r\n if(canRevoke.length) {\r\n if(canRevoke.length === mids.length) {\r\n checkboxes.push({\r\n text: 'DeleteForAll'\r\n });\r\n } else {\r\n checkboxes.push({\r\n text: 'DeleteMessagesOption'\r\n });\r\n\r\n description = 'DeleteMessagesTextGroup';\r\n descriptionArgs = [i18n('messages', [canRevoke.length])];\r\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}\".`;\r\n }\r\n }\r\n } else {\r\n buttons[0].callback = (checked) => callback(checked, true);\r\n }\r\n }\r\n }\r\n\r\n addCancelButton(buttons);\r\n\r\n const popup = new PopupPeer('popup-delete-chat', {\r\n peerId,\r\n titleLangKey: title,\r\n titleLangArgs: titleArgs,\r\n descriptionLangKey: description,\r\n descriptionLangArgs: descriptionArgs,\r\n buttons,\r\n checkboxes\r\n });\r\n\r\n popup.show();\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 appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport { addCancelButton } from \".\";\r\nimport PopupPeer, { PopupPeerButtonCallbackCheckboxes, PopupPeerOptions } from \"./peer\";\r\nimport appPeersManager from \"../../lib/appManagers/appPeersManager\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport { LangPackKey } from \"../../lib/langPack\";\r\nimport appChatsManager from \"../../lib/appManagers/appChatsManager\";\r\nimport PeerTitle from \"../peerTitle\";\r\n\r\nexport default class PopupPinMessage {\r\n constructor(peerId: number, mid: number, unpin?: true, onConfirm?: () => void) {\r\n let title: LangPackKey, description: LangPackKey, buttons: PopupPeerOptions['buttons'] = [], checkboxes: PopupPeerOptions['checkboxes'] = [];\r\n\r\n const canUnpin = appPeersManager.canPinMessage(peerId);\r\n\r\n const callback = (checked: PopupPeerButtonCallbackCheckboxes, oneSide?: boolean, silent?: boolean) => {\r\n setTimeout(() => { // * костыль, потому что document.elementFromPoint вернёт popup-peer пока он будет закрываться\r\n let promise: Promise<any>;\r\n if(unpin && !mid) {\r\n if(canUnpin) {\r\n promise = appMessagesManager.unpinAllMessages(peerId);\r\n } else {\r\n promise = appMessagesManager.hidePinnedMessages(peerId);\r\n }\r\n } else {\r\n promise = appMessagesManager.updatePinnedMessage(peerId, mid, unpin, silent, oneSide);\r\n }\r\n\r\n if(onConfirm) {\r\n promise.then(onConfirm);\r\n }\r\n }, 300);\r\n };\r\n\r\n if(unpin) {\r\n let buttonText: LangPackKey = 'UnpinMessage';\r\n if(!mid) {\r\n if(canUnpin) {\r\n title = 'Popup.Unpin.AllTitle';\r\n description = 'Chat.UnpinAllMessagesConfirmation';\r\n } else {\r\n title = 'Popup.Unpin.HideTitle';\r\n description = 'Popup.Unpin.HideDescription';\r\n buttonText = 'Popup.Unpin.Hide';\r\n }\r\n } else {\r\n title = 'UnpinMessageAlertTitle';\r\n description = 'Chat.Confirm.Unpin';\r\n }\r\n \r\n buttons.push({\r\n langKey: buttonText,\r\n isDanger: true,\r\n callback\r\n });\r\n } else {\r\n title = 'PinMessageAlertTitle';\r\n const pinButtonText: LangPackKey = 'PinMessage';\r\n \r\n if(peerId < 0) {\r\n buttons.push({\r\n langKey: pinButtonText,\r\n callback: (checked) => callback(checked, false, !checked.size)\r\n });\r\n\r\n if(appChatsManager.isBroadcast(-peerId)) {\r\n description = 'PinMessageAlertChannel';\r\n } else {\r\n description = 'PinMessageAlert';\r\n \r\n checkboxes.push({\r\n text: 'PinNotify',\r\n checked: true\r\n });\r\n }\r\n } else {\r\n description = 'PinMessageAlertChat';\r\n\r\n if(peerId === rootScope.myId) {\r\n buttons.push({\r\n langKey: pinButtonText,\r\n callback\r\n });\r\n } else {\r\n buttons.push({\r\n langKey: pinButtonText,\r\n callback: (checked) => callback(checked, !checked.size)\r\n });\r\n\r\n checkboxes.push({\r\n text: 'PinAlsoFor',\r\n textArgs: [new PeerTitle({peerId, onlyFirstName: true}).element],\r\n checked: true\r\n });\r\n }\r\n }\r\n }\r\n\r\n addCancelButton(buttons);\r\n\r\n const popup = new PopupPeer('popup-delete-chat', {\r\n peerId,\r\n titleLangKey: title,\r\n descriptionLangKey: description,\r\n buttons,\r\n checkboxes\r\n });\r\n\r\n popup.show();\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 appMessagesManager from \"../../lib/appManagers/appMessagesManager\";\r\nimport { PopupButton } from \".\";\r\nimport PopupPeer from \"./peer\";\r\n\r\nexport default class PopupSendNow {\r\n constructor(peerId: number, mids: number[], onConfirm?: () => void) {\r\n let title: string, description: string, buttons: PopupButton[] = [];\r\n\r\n title = `Send Message${mids.length > 1 ? 's' : ''} Now`;\r\n description = mids.length > 1 ? 'Send ' + mids.length + ' messages now?' : 'Send message now?';\r\n\r\n const callback = () => {\r\n onConfirm && onConfirm();\r\n appMessagesManager.sendScheduledMessages(peerId, mids);\r\n };\r\n\r\n buttons.push({\r\n langKey: 'Send',\r\n callback\r\n });\r\n\r\n const popup = new PopupPeer('popup-delete-chat', {\r\n peerId,\r\n title,\r\n description,\r\n buttons\r\n });\r\n\r\n popup.show();\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 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","/*\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","/*\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 { AppChatsManager } from \"../../lib/appManagers/appChatsManager\";\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 { AppStateManager } from \"../../lib/appManagers/appStateManager\";\r\nimport type Chat from \"./chat\";\r\nimport { isTouchSupported } from \"../../helpers/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, { i18n, LangPackKey } from \"../../lib/langPack\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport cancelSelection from \"../../helpers/dom/cancelSelection\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport isSelectionEmpty from \"../../helpers/dom/isSelectionEmpty\";\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 target: HTMLElement;\r\n private isTargetAGroupedItem: boolean;\r\n private isTextSelected: boolean;\r\n private isAnchorTarget: 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 ) {\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 // * если открыть контекстное меню для альбома не по бабблу, и последний элемент не выбран, чтобы показать остальные пункты\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 = chat.selection.selectedMids.has(mid) ? mid : mids.find(mid => chat.selection.selectedMids.has(mid));\r\n if(selectedMid) {\r\n mid = selectedMid;\r\n }\r\n }\r\n }\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' && (this.target as HTMLAnchorElement).target === '_blank';\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.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 || isTouchSupported || 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(isTouchSupported/* && 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 }\r\n }, {listenerSetter: this.chat.bubbles.listenerSetter});\r\n\r\n attachContextMenuListener(attachTo, (e) => {\r\n if(chat.selection.isSelecting) return;\r\n\r\n // * these two lines will fix instant text selection on iOS Safari\r\n document.body.classList.add('no-select'); // * need no-select on body because chat-input transforms in channels\r\n attachTo.addEventListener('touchend', (e) => {\r\n cancelEvent(e); // ! this one will fix propagation to document loader button, etc\r\n document.body.classList.remove('no-select');\r\n\r\n //this.chat.bubbles.onBubblesClick(e);\r\n }, {once: true, capture: true});\r\n\r\n cancelSelection();\r\n //cancelEvent(e as any);\r\n const bubble = findUpClassName(e.target, 'grouped-item') || findUpClassName(e.target, 'bubble');\r\n if(bubble) {\r\n chat.selection.toggleByBubble(bubble);\r\n }\r\n }, 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.chat.selection.selectedMids.has(this.mid) && !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.canWriteToPeer(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\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: () => this.chat.selection.selectedMids.has(this.mid) && !![...this.chat.selection.selectedMids].find(mid => !!this.chat.getMessage(mid).message),\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: '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 return doc && doc.type && !(['gif', 'photo', 'video', 'sticker'] as MyDocument['type'][]).includes(doc.type);\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.chat.selection.selectedMids.has(this.mid) && \r\n !this.chat.selection.selectionForwardBtn.hasAttribute('disabled'),\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.chat.selection.selectedMids.has(this.mid) && 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.chat.selection.selectedMids.has(this.mid),\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.chat.selection.selectedMids.has(this.mid) && !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 this.chat.selection.selectionSendNowBtn.click();\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 ? [...this.chat.selection.selectedMids].sort((a, b) => a - b) : [this.mid];\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 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 const username = this.appPeersManager.getPeerUsername(this.peerId);\r\n const msgId = this.appMessagesManager.getServerMessageId(this.mid);\r\n let url = 'https://t.me/';\r\n let key: LangPackKey;\r\n if(username) {\r\n url += username + '/' + msgId;\r\n key = 'LinkCopied';\r\n } else {\r\n url += 'c/' + Math.abs(this.peerId) + '/' + msgId;\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 this.chat.selection.selectionForwardBtn.click();\r\n } else {\r\n new PopupForward(this.peerId, this.isTargetAGroupedItem ? [this.mid] : this.chat.getMidsByMid(this.mid));\r\n }\r\n };\r\n\r\n private onSelectClick = () => {\r\n this.chat.selection.toggleByBubble(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 this.chat.selection.selectionDeleteBtn.click();\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, 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\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: 'NewPoll.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.questionInputField.input.addEventListener('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.multipleCheckboxField.input.addEventListener('change', () => {\r\n const checked = this.multipleCheckboxField.input.checked;\r\n this.quizCheckboxField.input.toggleAttribute('disabled', checked);\r\n });\r\n\r\n this.quizCheckboxField.input.addEventListener('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.questionInputField.input.addEventListener('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 this.btnConfirm.addEventListener('click', this.onSubmitClick);\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.btnClose.click();\r\n this.btnConfirm.removeEventListener('click', this.onSubmitClick);\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 questionField.input.addEventListener('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 questionField.input.addEventListener('click', cancelEvent);\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 radioField.input.addEventListener('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 deleteBtn.addEventListener('click', this.onDeleteClick, {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","/*\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 { isMobile, isApple } from \"../userAgent\";\r\n\r\nexport default function isSendShortcutPressed(e: KeyboardEvent) {\r\n if(e.key === 'Enter' && !isMobile && !e.isComposing) {\r\n /* if(e.ctrlKey || e.metaKey) {\r\n this.messageInput.innerHTML += '<br>';\r\n placeCaretAtEnd(this.message)\r\n return;\r\n } */\r\n\r\n if(rootScope.settings.sendShortcut === 'enter') {\r\n if(e.shiftKey || e.ctrlKey || e.metaKey) {\r\n return;\r\n }\r\n\r\n return true;\r\n } else {\r\n const secondaryKey = isApple ? e.metaKey : e.ctrlKey;\r\n if(e.shiftKey || (isApple ? e.ctrlKey : e.metaKey)) {\r\n return;\r\n }\r\n\r\n if(secondaryKey) {\r\n return true;\r\n }\r\n }\r\n }\r\n\r\n return false;\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 { isTouchSupported } from \"../touchSupport\";\r\n\r\nexport default function placeCaretAtEnd(el: HTMLElement) {\r\n if(isTouchSupported) {\r\n return;\r\n }\r\n \r\n el.focus();\r\n if(typeof window.getSelection !== \"undefined\" && typeof document.createRange !== \"undefined\") {\r\n var range = document.createRange();\r\n range.selectNodeContents(el);\r\n range.collapse(false);\r\n var sel = window.getSelection();\r\n sel.removeAllRanges();\r\n sel.addRange(range);\r\n // @ts-ignore\r\n } else if(typeof document.body.createTextRange !== \"undefined\") {\r\n // @ts-ignore\r\n var textRange = document.body.createTextRange();\r\n textRange.moveToElementText(el);\r\n textRange.collapse(false);\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/chat\";\r\nimport InputField from \"../inputField\";\r\nimport PopupElement from \".\";\r\nimport Scrollable from \"../scrollable\";\r\nimport { toast } from \"../toast\";\r\nimport { prepareAlbum, wrapDocument } from \"../wrappers\";\r\nimport CheckboxField from \"../checkboxField\";\r\nimport SendContextMenu from \"../chat/sendContextMenu\";\r\nimport { createPosterFromVideo, onVideoLoad } from \"../../helpers/files\";\r\nimport { MyDocument } from \"../../lib/appManagers/appDocsManager\";\r\nimport I18n, { i18n, LangPackKey } from \"../../lib/langPack\";\r\nimport appDownloadManager from \"../../lib/appManagers/appDownloadManager\";\r\nimport calcImageInBox from \"../../helpers/calcImageInBox\";\r\nimport isSendShortcutPressed from \"../../helpers/dom/isSendShortcutPressed\";\r\nimport placeCaretAtEnd from \"../../helpers/dom/placeCaretAtEnd\";\r\nimport rootScope from \"../../lib/rootScope\";\r\n\r\ntype SendFileParams = Partial<{\r\n file: File,\r\n objectURL: string,\r\n thumbBlob: Blob,\r\n thumbURL: string,\r\n width: number,\r\n height: number,\r\n duration: number\r\n}>;\r\n\r\n// TODO: .gif upload as video\r\n\r\nexport default class PopupNewMedia extends PopupElement {\r\n private input: HTMLElement;\r\n private mediaContainer: HTMLElement;\r\n private groupCheckboxField: CheckboxField;\r\n private wasInputValue = '';\r\n\r\n private willAttach: Partial<{\r\n type: 'media' | 'document',\r\n isMedia: true,\r\n group: boolean,\r\n sendFileDetails: SendFileParams[]\r\n }> = {\r\n sendFileDetails: [],\r\n group: false\r\n };\r\n private inputField: InputField;\r\n\r\n constructor(private chat: Chat, files: File[], willAttachType: PopupNewMedia['willAttach']['type']) {\r\n super('popup-send-photo popup-new-media', null, {closable: true, withConfirm: 'Modal.Send'});\r\n\r\n this.willAttach.type = willAttachType;\r\n\r\n this.btnConfirm.addEventListener('click', () => this.send());\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.mediaContainer = document.createElement('div');\r\n this.mediaContainer.classList.add('popup-photo');\r\n const scrollable = new Scrollable(null);\r\n scrollable.container.append(this.mediaContainer);\r\n \r\n this.inputField = new InputField({\r\n placeholder: 'PreviewSender.CaptionPlaceholder',\r\n label: 'Caption',\r\n name: 'photo-caption',\r\n maxLength: rootScope.config.caption_length_max,\r\n showLengthOn: 80\r\n });\r\n this.input = this.inputField.input;\r\n\r\n this.inputField.value = this.wasInputValue = this.chat.input.messageInputField.value;\r\n this.chat.input.messageInputField.value = '';\r\n\r\n this.container.append(scrollable.container);\r\n\r\n if(files.length > 1) {\r\n this.groupCheckboxField = new CheckboxField({\r\n text: 'PreviewSender.GroupItems', \r\n name: 'group-items'\r\n });\r\n this.container.append(this.groupCheckboxField.label, this.inputField.container);\r\n \r\n this.groupCheckboxField.input.checked = true;\r\n this.willAttach.group = true;\r\n\r\n this.groupCheckboxField.input.addEventListener('change', () => {\r\n const checked = this.groupCheckboxField.input.checked;\r\n \r\n this.willAttach.group = checked;\r\n this.willAttach.sendFileDetails.length = 0;\r\n\r\n //this.mediaContainer.innerHTML = '';\r\n //this.container.classList.remove('is-media', 'is-document', 'is-album');\r\n this.attachFiles(files);\r\n });\r\n }\r\n \r\n this.container.append(this.inputField.container);\r\n\r\n this.attachFiles(files);\r\n }\r\n\r\n private onKeyDown = (e: KeyboardEvent) => {\r\n const target = e.target as HTMLElement;\r\n if(target !== this.input) {\r\n if(target.tagName === 'INPUT' || target.hasAttribute('contenteditable')) {\r\n return;\r\n }\r\n\r\n this.input.focus();\r\n placeCaretAtEnd(this.input);\r\n }\r\n \r\n if(isSendShortcutPressed(e)) {\r\n this.btnConfirm.click();\r\n }\r\n };\r\n\r\n public send(force = false) {\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 let caption = this.inputField.value;\r\n if(caption.length > rootScope.config.caption_length_max) {\r\n toast(I18n.format('Error.PreviewSender.CaptionTooLong', true));\r\n return;\r\n }\r\n\r\n this.hide();\r\n const willAttach = this.willAttach;\r\n willAttach.isMedia = willAttach.type === 'media' ? true : undefined;\r\n\r\n //console.log('will send files with options:', willAttach);\r\n\r\n const peerId = this.chat.peerId;\r\n const input = this.chat.input;\r\n const silent = input.sendSilent;\r\n const scheduleDate = input.scheduleDate;\r\n\r\n if(willAttach.sendFileDetails.length > 1 && willAttach.group) {\r\n for(let i = 0; i < willAttach.sendFileDetails.length;) {\r\n let firstType = willAttach.sendFileDetails[i].file.type.split('/')[0];\r\n for(var k = 0; k < 10 && i < willAttach.sendFileDetails.length; ++i, ++k) {\r\n const type = willAttach.sendFileDetails[i].file.type.split('/')[0];\r\n if(firstType !== type) {\r\n break;\r\n }\r\n }\r\n\r\n const w = {...willAttach};\r\n w.sendFileDetails = willAttach.sendFileDetails.slice(i - k, i);\r\n\r\n this.chat.appMessagesManager.sendAlbum(peerId, w.sendFileDetails.map(d => d.file), Object.assign({\r\n caption,\r\n replyToMsgId: input.replyToMsgId,\r\n threadId: this.chat.threadId,\r\n isMedia: willAttach.isMedia,\r\n silent,\r\n scheduleDate,\r\n clearDraft: true as true\r\n }, w));\r\n\r\n caption = undefined;\r\n input.replyToMsgId = this.chat.threadId;\r\n }\r\n } else {\r\n if(caption) {\r\n if(willAttach.sendFileDetails.length > 1) {\r\n this.chat.appMessagesManager.sendText(peerId, caption, {\r\n replyToMsgId: input.replyToMsgId, \r\n threadId: this.chat.threadId,\r\n silent, \r\n scheduleDate,\r\n clearDraft: true\r\n });\r\n caption = '';\r\n //input.replyToMsgId = undefined;\r\n }\r\n }\r\n \r\n const promises = willAttach.sendFileDetails.map(params => {\r\n const promise = this.chat.appMessagesManager.sendFile(peerId, params.file, Object.assign({\r\n //isMedia: willAttach.isMedia, \r\n isMedia: willAttach.isMedia, \r\n caption,\r\n replyToMsgId: input.replyToMsgId,\r\n threadId: this.chat.threadId,\r\n silent,\r\n scheduleDate,\r\n clearDraft: true as true\r\n }, params));\r\n\r\n caption = '';\r\n return promise;\r\n });\r\n\r\n input.replyToMsgId = this.chat.threadId;\r\n }\r\n\r\n //Promise.all(promises);\r\n\r\n //appMessagesManager.sendFile(appImManager.peerId, willAttach.file, willAttach);\r\n \r\n input.onMessageSent();\r\n }\r\n\r\n public attachFile = (file: File) => {\r\n const willAttach = this.willAttach;\r\n return new Promise<HTMLDivElement>((resolve) => {\r\n const params: SendFileParams = {};\r\n params.file = file;\r\n //console.log('selected file:', file, typeof(file), willAttach);\r\n const itemDiv = document.createElement('div');\r\n switch(willAttach.type) {\r\n case 'media': {\r\n const isVideo = file.type.indexOf('video/') === 0;\r\n\r\n itemDiv.classList.add('popup-item-media');\r\n\r\n if(isVideo) {\r\n const video = document.createElement('video');\r\n const source = document.createElement('source');\r\n source.src = params.objectURL = URL.createObjectURL(file);\r\n video.autoplay = true;\r\n video.controls = false;\r\n video.muted = true;\r\n video.setAttribute('playsinline', 'true');\r\n\r\n video.addEventListener('timeupdate', () => {\r\n video.pause();\r\n }, {once: true});\r\n\r\n onVideoLoad(video).then(() => {\r\n params.width = video.videoWidth;\r\n params.height = video.videoHeight;\r\n params.duration = Math.floor(video.duration);\r\n\r\n itemDiv.append(video);\r\n createPosterFromVideo(video).then(blob => {\r\n params.thumbBlob = blob;\r\n params.thumbURL = URL.createObjectURL(blob);\r\n resolve(itemDiv);\r\n });\r\n });\r\n\r\n video.append(source);\r\n } else {\r\n const img = new Image();\r\n img.src = params.objectURL = URL.createObjectURL(file);\r\n img.onload = () => {\r\n params.width = img.naturalWidth;\r\n params.height = img.naturalHeight;\r\n\r\n itemDiv.append(img);\r\n resolve(itemDiv);\r\n };\r\n }\r\n \r\n break;\r\n }\r\n\r\n case 'document': {\r\n const isPhoto = file.type.indexOf('image/') !== -1;\r\n const isAudio = file.type.indexOf('audio/') !== -1;\r\n if(isPhoto || isAudio) {\r\n params.objectURL = URL.createObjectURL(file);\r\n }\r\n\r\n const doc = {\r\n _: 'document',\r\n file: file,\r\n file_name: file.name || '',\r\n size: file.size,\r\n type: isPhoto ? 'photo' : 'doc'\r\n } as MyDocument;\r\n\r\n const cacheContext = appDownloadManager.getCacheContext(doc);\r\n cacheContext.url = params.objectURL;\r\n cacheContext.downloaded = file.size;\r\n\r\n const docDiv = wrapDocument({\r\n message: {\r\n _: 'message',\r\n pFlags: {\r\n is_outgoing: true\r\n },\r\n mid: 0,\r\n peerId: 0,\r\n media: {\r\n _: 'messageMediaDocument',\r\n document: doc\r\n }\r\n } as any\r\n });\r\n\r\n const finish = () => {\r\n itemDiv.append(docDiv);\r\n resolve(itemDiv);\r\n };\r\n\r\n if(isPhoto) {\r\n const img = new Image();\r\n img.src = params.objectURL;\r\n img.onload = () => {\r\n params.width = img.naturalWidth;\r\n params.height = img.naturalHeight;\r\n\r\n finish();\r\n };\r\n\r\n img.onerror = finish;\r\n } else {\r\n finish();\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n willAttach.sendFileDetails.push(params);\r\n });\r\n };\r\n\r\n public attachFiles(files: File[]) {\r\n const container = this.container;\r\n const willAttach = this.willAttach;\r\n\r\n /* if(files.length > 10 && willAttach.type === 'media') {\r\n willAttach.type = 'document';\r\n } */\r\n\r\n files = files.filter(file => {\r\n if(willAttach.type === 'media') {\r\n return ['image/', 'video/'].find(s => file.type.indexOf(s) === 0);\r\n } else {\r\n return true;\r\n }\r\n });\r\n\r\n Promise.all(files.map(this.attachFile)).then(results => {\r\n this.container.classList.remove('is-media', 'is-document', 'is-album');\r\n this.mediaContainer.innerHTML = '';\r\n\r\n if(files.length) {\r\n let key: LangPackKey;\r\n const args: any[] = [];\r\n if(willAttach.type === 'document') {\r\n key = 'PreviewSender.SendFile';\r\n args.push(files.length);\r\n container.classList.add('is-document');\r\n } else {\r\n container.classList.add('is-media');\r\n \r\n let foundPhotos = 0;\r\n let foundVideos = 0;\r\n files.forEach(file => {\r\n if(file.type.indexOf('image/') === 0) ++foundPhotos;\r\n else if(file.type.indexOf('video/') === 0) ++foundVideos;\r\n });\r\n \r\n const sum = foundPhotos + foundVideos;\r\n if(sum > 1 && willAttach.group) {\r\n key = 'PreviewSender.SendAlbum';\r\n const albumsLength = Math.ceil(sum / 10);\r\n args.push(albumsLength);\r\n } else if(foundPhotos) {\r\n key = 'PreviewSender.SendPhoto';\r\n args.push(foundPhotos);\r\n } else if(foundVideos) {\r\n key = 'PreviewSender.SendVideo';\r\n args.push(foundVideos);\r\n }\r\n }\r\n\r\n this.title.textContent = '';\r\n this.title.append(i18n(key, args));\r\n }\r\n\r\n if(willAttach.type === 'media') {\r\n if(willAttach.sendFileDetails.length > 1 && willAttach.group) {\r\n container.classList.add('is-album');\r\n\r\n for(let i = 0; i < results.length; i += 10) {\r\n const albumContainer = document.createElement('div');\r\n albumContainer.classList.add('popup-album');\r\n\r\n albumContainer.append(...results.slice(i, i + 10));\r\n prepareAlbum({\r\n container: albumContainer,\r\n items: willAttach.sendFileDetails.slice(i, i + 10).map(o => ({w: o.width, h: o.height})),\r\n maxWidth: 380,\r\n minWidth: 100,\r\n spacing: 4\r\n });\r\n\r\n this.mediaContainer.append(albumContainer);\r\n }\r\n\r\n //console.log('chatInput album layout:', layout);\r\n } else {\r\n for(let i = 0; i < results.length; ++i) {\r\n const params = willAttach.sendFileDetails[i];\r\n const div = results[i];\r\n const size = calcImageInBox(params.width, params.height, 380, 320);\r\n div.style.width = size.width + 'px';\r\n div.style.height = size.height + 'px';\r\n this.mediaContainer.append(div);\r\n }\r\n }\r\n } else {\r\n this.mediaContainer.append(...results);\r\n }\r\n\r\n // show now\r\n if(!this.element.classList.contains('active')) {\r\n document.body.addEventListener('keydown', this.onKeyDown);\r\n this.onClose = () => {\r\n if(this.wasInputValue) {\r\n this.chat.input.messageInputField.value = this.wasInputValue;\r\n }\r\n\r\n document.body.removeEventListener('keydown', this.onKeyDown);\r\n };\r\n this.show();\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 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\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: Set<ArrowKey> = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight']);\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 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 { isMobile } from \"../../helpers/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(!isMobile && !this.navigationItem) {\r\n this.navigationItem = {\r\n type: 'autocomplete-helper',\r\n onPop: () => this.toggle(true),\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 }\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 && this.resetTarget) {\r\n this.resetTarget();\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 if(!fromController) {\r\n this.controller.hideOtherHelpers();\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 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>).then(resolve, 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 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\nexport default class PopupSchedule extends PopupDatePicker {\r\n constructor(initDate: Date, onPick: (timestamp: number) => void) {\r\n super(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: (() => {\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 withTime: true,\r\n showOverflowMonths: 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}\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');\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","/*\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 { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\r\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\r\nimport type { BotInfo } from \"../../layer\";\r\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\r\nimport AutocompletePeerHelper from \"./autocompletePeerHelper\";\r\nimport SearchIndex from \"../../lib/searchIndex\";\r\n\r\nexport default class CommandsHelper extends AutocompletePeerHelper {\r\n constructor(appendTo: HTMLElement, \r\n controller: AutocompleteHelperController, \r\n chatInput: ChatInput, \r\n private appProfileManager: AppProfileManager,\r\n private appUsersManager: AppUsersManager) {\r\n super(appendTo, \r\n controller,\r\n 'commands-helper',\r\n (target) => {\r\n const innerHTML = target.querySelector(`.${AutocompletePeerHelper.BASE_CLASS_LIST_ELEMENT}-name`).innerHTML;\r\n chatInput.messageInput.innerHTML = innerHTML;\r\n chatInput.sendMessage();\r\n }\r\n );\r\n }\r\n\r\n public checkQuery(query: string, peerId: number) {\r\n if(!this.appUsersManager.isBot(peerId)) {\r\n return false;\r\n }\r\n\r\n const middleware = this.controller.getMiddleware();\r\n this.appProfileManager.getProfileByPeerId(peerId).then(full => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n const botInfos: BotInfo.botInfo[] = [].concat(full.bot_info);\r\n const index = new SearchIndex<string>(false, false);\r\n \r\n const commands: Map<string, {peerId: number, name: string, description: string}> = new Map();\r\n botInfos.forEach(botInfo => {\r\n botInfo.commands.forEach(botCommand => {\r\n const c = '/' + botCommand.command;\r\n commands.set(botCommand.command, {\r\n peerId: botInfo.user_id, \r\n name: c, \r\n description: botCommand.description\r\n });\r\n\r\n index.indexObject(botCommand.command, c);\r\n });\r\n });\r\n\r\n const found = index.search(query);\r\n const filtered = Array.from(found).map(command => commands.get(command));\r\n this.render(filtered);\r\n // console.log('found commands', found, filtered);\r\n });\r\n\r\n return 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 { 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","/*\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 { MessageEntity } from \"../../layer\";\r\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\r\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\r\nimport AutocompleteHelperController from \"./autocompleteHelperController\";\r\nimport AutocompletePeerHelper from \"./autocompletePeerHelper\";\r\n\r\nexport default class MentionsHelper extends AutocompletePeerHelper {\r\n constructor(appendTo: HTMLElement, \r\n controller: AutocompleteHelperController, \r\n chatInput: ChatInput, \r\n private appProfileManager: AppProfileManager,\r\n private appUsersManager: AppUsersManager) {\r\n super(appendTo, \r\n controller,\r\n 'mentions-helper',\r\n (target) => {\r\n const user = appUsersManager.getUser(+(target as HTMLElement).dataset.peerId);\r\n let str = '', entity: MessageEntity;\r\n if(user.username) {\r\n str = '@' + user.username;\r\n } else {\r\n str = user.first_name || user.last_name;\r\n entity = {\r\n _: 'messageEntityMentionName',\r\n length: str.length,\r\n offset: 0,\r\n user_id: user.id\r\n };\r\n }\r\n\r\n str += ' ';\r\n chatInput.insertAtCaret(str, entity);\r\n }\r\n );\r\n }\r\n\r\n public checkQuery(query: string, peerId: number, topMsgId: number) {\r\n const trimmed = query.trim(); // check that there is no whitespace\r\n if(peerId > 0 || query.length !== trimmed.length) return false;\r\n\r\n this.appProfileManager.getMentions(-peerId, trimmed, topMsgId).then(peerIds => {\r\n const username = trimmed.slice(1).toLowerCase();\r\n this.render(peerIds.map(peerId => {\r\n const user = this.appUsersManager.getUser(peerId);\r\n if(user.username && user.username.toLowerCase() === username) { // hide full matched suggestion\r\n return;\r\n }\r\n\r\n return {\r\n peerId,\r\n description: user.username ? '@' + user.username : undefined\r\n };\r\n }).filter(Boolean));\r\n });\r\n\r\n return 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 { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\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 { isTouchSupported } from \"../../helpers/touchSupport\";\r\nimport findUpAsChild from \"../../helpers/dom/findUpAsChild\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\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\r\n constructor(options: {\r\n listenerSetter: ListenerSetter,\r\n appMessagesManager: AppMessagesManager,\r\n appendTo: HTMLElement,\r\n btnHover: HTMLElement\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 && this.checkAvailability() && this.isActive()) {\r\n this.render();\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(isTouchSupported) {\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 private getReplyMarkup(): ReplyMarkup {\r\n return this.appMessagesManager.getHistoryStorage(this.peerId).reply_markup ?? {\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';\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 }\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 Chat from './chat';\r\nimport Recorder from '../../../public/recorder.min';\r\nimport { isTouchSupported } from \"../../helpers/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, BotInfo, BotCommand } from '../../layer';\r\nimport StickersHelper from './stickersHelper';\r\nimport ButtonIcon from '../buttonIcon';\r\nimport DivAndCaption from '../divAndCaption';\r\nimport ButtonMenuToggle from '../buttonMenuToggle';\r\nimport ListenerSetter 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 { debounce } from '../../helpers/schedulers';\r\nimport { tsNow } from '../../helpers/date';\r\nimport appNavigationController from '../appNavigationController';\r\nimport { isMobile, isMobileSafari } from '../../helpers/userAgent';\r\nimport { i18n } 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 } 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\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) => boolean})[];\r\n\r\n private sendMenu: SendMenu;\r\n\r\n private replyElements: {\r\n container?: HTMLElement,\r\n cancelBtn?: HTMLButtonElement,\r\n titleEl?: HTMLElement,\r\n subtitleEl?: HTMLElement\r\n } = {};\r\n\r\n private willSendWebPage: any = null;\r\n private forwardingMids: number[] = [];\r\n private forwardingFromPeerId: number = 0;\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\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 listenerSetter: ListenerSetter;\r\n\r\n private pinnedControlBtn: HTMLButtonElement;\r\n\r\n private goDownBtn: HTMLButtonElement;\r\n private goDownUnreadBadge: HTMLElement;\r\n private btnScheduled: 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 constructor(private chat: Chat, \r\n private appMessagesManager: AppMessagesManager, \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 ) {\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-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 const dac = new DivAndCaption('reply');\r\n\r\n this.replyElements.titleEl = dac.title;\r\n this.replyElements.subtitleEl = dac.subtitle;\r\n\r\n this.replyElements.container.append(this.replyElements.cancelBtn, dac.container);\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.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', (e) => {\r\n const peerId = e.peerId;\r\n\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', (e) => {\r\n const peerId = e.peerId;\r\n\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 });\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 this.fileInput.setAttribute('accept', 'image/*, video/*');\r\n this.willAttachType = 'media';\r\n this.fileInput.click();\r\n },\r\n verify: (peerId: number) => peerId > 0 || this.appChatsManager.hasRights(peerId, '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: number) => peerId > 0 || this.appChatsManager.hasRights(peerId, '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: number) => peerId < 0 && this.appChatsManager.hasRights(peerId, '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.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.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', (e) => {\r\n const {peerId, threadId, draft} = e;\r\n if(this.chat.threadId !== threadId || this.chat.peerId !== peerId) return;\r\n this.setDraft(draft);\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 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.recordCanceled) return;\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 let peerId = this.chat.peerId;\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: this.replyToMsgId,\r\n threadId: this.chat.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 = isTouchSupported ? 'flip-icon' : 'active';\r\n this.btnToggleEmoticons.classList.toggle(toggleClass, true);\r\n };\r\n\r\n private onEmoticonsClose = () => {\r\n const toggleClass = isTouchSupported ? 'flip-icon' : 'active';\r\n this.btnToggleEmoticons.classList.toggle(toggleClass, false);\r\n };\r\n\r\n public scheduleSending = (callback: () => void = this.sendMessage.bind(this, true), initDate = new Date()) => {\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 }).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\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) {\r\n if(!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 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 canWrite = this.appMessagesManager.canWriteToPeer(this.chat.peerId, this.chat.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 visible = this.attachMenuButtons.filter(button => {\r\n const good = button.verify(this.chat.peerId);\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.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.attachMessageInputListeners();\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(isTouchSupported) {\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') {\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 apiManager.invokeApi('messages.getWebPage', {\r\n url,\r\n hash: 0\r\n }).then((webpage) => {\r\n webpage = this.appWebPagesManager.saveWebPage(webpage);\r\n if(webpage._ === 'webPage') {\r\n if(this.lastUrl !== url) return;\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\r\n delete this.noWebPage;\r\n this.willSendWebPage = webpage;\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 this.appImManager.markupTooltip.hide();\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 const matches = value.match(ChatInput.AUTO_COMPLETE_REG_EXP);\r\n if(!matches) {\r\n this.previousQuery = undefined;\r\n this.autocompleteHelperController.hideOtherHelpers();\r\n return;\r\n }\r\n\r\n if(this.previousQuery === matches[0]) {\r\n return;\r\n }\r\n \r\n this.previousQuery = matches[0];\r\n\r\n let foundHelper: AutocompleteHelper;\r\n const entity = entities[0];\r\n\r\n const 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.chat.peerId > 0 || this.appChatsManager.hasRights(this.chat.peerId, '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 \r\n //let query = cleanSearchText(query);\r\n\r\n //console.log('autocomplete matches', matches);\r\n\r\n if(firstChar === '@') { // mentions\r\n const topMsgId = this.chat.threadId ? this.appMessagesManager.getServerMessageId(this.chat.threadId) : undefined;\r\n if(this.mentionsHelper.checkQuery(query, 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 if(!value.match(/^\\s*:(.+):\\s*$/) && !value.match(/:[;!@#$%^&*()-=|]/)) {\r\n foundHelper = this.emojiHelper;\r\n this.emojiHelper.checkQuery(query, firstChar);\r\n }\r\n }\r\n\r\n this.autocompleteHelperController.hideOtherHelpers(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.forwardingMids.length || 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.appChatsManager.hasRights(this.chat.peerId, '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 this.recorder.start().then(() => {\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 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 window.requestAnimationFrame(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 fromId = this.forwardingFromPeerId;\r\n const mids = this.forwardingMids.slice();\r\n const helperFunc = this.helperFunc;\r\n this.clearHelper();\r\n let selected = false;\r\n new PopupForward(fromId, mids, () => {\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) {\r\n if(document.activeElement === this.messageInput && isMobileSafari) {\r\n const i = document.createElement('input');\r\n document.body.append(i);\r\n fixSafariStickyInput(i);\r\n this.messageInputField.value = '';\r\n fixSafariStickyInput(this.messageInput);\r\n i.remove();\r\n } else {\r\n this.messageInputField.value = '';\r\n }\r\n\r\n if(isTouchSupported) {\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) {\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.forwardingMids.length) 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 this.appMessagesManager.editMessage(this.chat.getMessage(this.editMsgId), value, {\r\n entities,\r\n noWebPage: this.noWebPage\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.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.forwardingMids.length) {\r\n const mids = this.forwardingMids.slice();\r\n const fromPeerId = this.forwardingFromPeerId;\r\n const peerId = this.chat.peerId;\r\n const silent = this.sendSilent;\r\n const scheduleDate = this.scheduleDate;\r\n setTimeout(() => {\r\n this.appMessagesManager.forwardMessages(peerId, fromPeerId, mids, {\r\n silent,\r\n scheduleDate: scheduleDate\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.appChatsManager.hasRights(this.chat.peerId, flag)) {\r\n toast(POSTING_MEDIA_NOT_ALLOWED);\r\n return;\r\n }\r\n\r\n if(this.chat.type === 'scheduled' && !force) {\r\n this.scheduleSending(() => this.sendMessageWithDocument(document, true));\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 // ! костыль\r\n const replyFragment = this.appMessagesManager.wrapMessageForReply(message, undefined, [message.mid]);\r\n this.setTopInfo('edit', f, 'Editing', undefined, input, message);\r\n const subtitleEl = this.replyElements.container.querySelector('.reply-subtitle');\r\n subtitleEl.textContent = '';\r\n subtitleEl.append(replyFragment);\r\n\r\n this.editMsgId = mid;\r\n input = undefined;\r\n };\r\n f();\r\n }\r\n\r\n public initMessagesForward(fromPeerId: number, mids: number[]) {\r\n const f = () => {\r\n //const peerTitles: string[]\r\n const smth: Set<string | number> = new Set(mids.map(mid => {\r\n const message = this.appMessagesManager.getMessageByPeer(fromPeerId, mid);\r\n if(message.fwd_from && message.fwd_from.from_name && !message.fromId && !message.fwdFromId) {\r\n return message.fwd_from.from_name;\r\n } else {\r\n return message.fromId;\r\n }\r\n }));\r\n\r\n const onlyFirstName = smth.size > 1;\r\n const peerTitles = [...smth].map(smth => {\r\n return typeof(smth) === 'number' ? \r\n this.appPeersManager.getPeerTitle(smth, true, onlyFirstName) : \r\n (onlyFirstName ? smth.split(' ')[0] : smth);\r\n });\r\n\r\n const title = peerTitles.length < 3 ? peerTitles.join(' and ') : peerTitles[0] + ' and ' + (peerTitles.length - 1) + ' others';\r\n const firstMessage = this.appMessagesManager.getMessageByPeer(fromPeerId, mids[0]);\r\n\r\n let usingFullAlbum = true;\r\n if(firstMessage.grouped_id) {\r\n const albumMids = this.appMessagesManager.getMidsByMessage(firstMessage);\r\n if(albumMids.length !== mids.length || albumMids.find(mid => !mids.includes(mid))) {\r\n usingFullAlbum = false;\r\n }\r\n }\r\n\r\n const replyFragment = this.appMessagesManager.wrapMessageForReply(firstMessage, undefined, mids);\r\n if(usingFullAlbum || mids.length === 1) {\r\n this.setTopInfo('forward', f, title);\r\n\r\n // ! костыль\r\n const subtitleEl = this.replyElements.container.querySelector('.reply-subtitle');\r\n subtitleEl.textContent = '';\r\n subtitleEl.append(replyFragment);\r\n } else {\r\n this.setTopInfo('forward', f, title, mids.length + ' ' + (mids.length > 1 ? 'forwarded messages' : 'forwarded message'));\r\n }\r\n\r\n this.forwardingMids = mids.slice();\r\n this.forwardingFromPeerId = fromPeerId;\r\n };\r\n \r\n f();\r\n }\r\n\r\n public initMessageReply(mid: number) {\r\n const message = this.chat.getMessage(mid);\r\n const f = () => {\r\n this.setTopInfo('reply', f, this.appPeersManager.getPeerTitle(message.fromId, true), 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.forwardingMids.length = 0;\r\n this.forwardingFromPeerId = 0;\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 clear && this.clearInput();\r\n this.messageInputField.value = value || '';\r\n window.requestAnimationFrame(() => {\r\n focus && placeCaretAtEnd(this.messageInput);\r\n this.messageInput.scrollTop = this.messageInput.scrollHeight;\r\n });\r\n }\r\n\r\n public setTopInfo(type: ChatInputHelperType, callerFunc: () => void, title = '', subtitle = '', input?: string, 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 if(this.replyElements.container.lastElementChild.tagName === 'DIV') {\r\n this.replyElements.container.lastElementChild.remove();\r\n this.replyElements.container.append(wrapReply(title, subtitle, message));\r\n }\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(!isMobile) {\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 { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type ChatBubbles from \"./bubbles\";\r\nimport type ChatInput from \"./input\";\r\nimport type Chat from \"./chat\";\r\nimport { isTouchSupported } from \"../../helpers/touchSupport\";\r\nimport Button from \"../button\";\r\nimport ButtonIcon from \"../buttonIcon\";\r\nimport CheckboxField from \"../checkboxField\";\r\nimport PopupDeleteMessages from \"../popups/deleteMessages\";\r\nimport PopupForward from \"../popups/forward\";\r\nimport { toast } from \"../toast\";\r\nimport SetTransition from \"../singleTransition\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport PopupSendNow from \"../popups/sendNow\";\r\nimport appNavigationController from \"../appNavigationController\";\r\nimport { isMobileSafari } from \"../../helpers/userAgent\";\r\nimport I18n, { i18n, _i18n } from \"../../lib/langPack\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport blurActiveElement from \"../../helpers/dom/blurActiveElement\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport cancelSelection from \"../../helpers/dom/cancelSelection\";\r\nimport getSelectedText from \"../../helpers/dom/getSelectedText\";\r\nimport rootScope from \"../../lib/rootScope\";\r\n\r\n//const MIN_CLICK_MOVE = 32; // minimum bubble height\r\n\r\nexport default class ChatSelection {\r\n public selectedMids: Set<number> = new Set();\r\n public isSelecting = false;\r\n\r\n private selectionInputWrapper: HTMLElement;\r\n private selectionContainer: HTMLElement;\r\n private selectionCountEl: HTMLElement;\r\n public selectionSendNowBtn: HTMLElement;\r\n public selectionForwardBtn: HTMLElement;\r\n public selectionDeleteBtn: HTMLElement;\r\n\r\n public selectedText: string;\r\n\r\n private listenerSetter: ListenerSetter;\r\n\r\n constructor(private chat: Chat, private bubbles: ChatBubbles, private input: ChatInput, private appMessagesManager: AppMessagesManager) {\r\n const bubblesContainer = bubbles.bubblesContainer;\r\n this.listenerSetter = bubbles.listenerSetter;\r\n\r\n if(isTouchSupported) {\r\n this.listenerSetter.add(bubblesContainer)('touchend', (e) => {\r\n if(!this.isSelecting) return;\r\n this.selectedText = getSelectedText();\r\n });\r\n return;\r\n }\r\n\r\n this.listenerSetter.add(bubblesContainer)('mousedown', (e) => {\r\n //console.log('selection mousedown', e);\r\n const bubble = findUpClassName(e.target, 'bubble');\r\n // LEFT BUTTON\r\n // проверка внизу нужна для того, чтобы не активировать селект если target потомок .bubble\r\n if(e.button !== 0\r\n || (\r\n !this.selectedMids.size \r\n && !(e.target as HTMLElement).classList.contains('bubble')\r\n && !(e.target as HTMLElement).classList.contains('document-selection')\r\n && bubble\r\n )\r\n ) {\r\n return;\r\n }\r\n \r\n const seen: Set<number> = new Set();\r\n let selecting: boolean;\r\n\r\n /* let good = false;\r\n const {x, y} = e; */\r\n\r\n /* const bubbles = appImManager.bubbles;\r\n for(const mid in bubbles) {\r\n const bubble = bubbles[mid];\r\n bubble.addEventListener('mouseover', () => {\r\n console.log('mouseover');\r\n }, {once: true});\r\n } */\r\n\r\n //const foundTargets: Map<HTMLElement, true> = new Map();\r\n let canceledSelection = false;\r\n const onMouseMove = (e: MouseEvent) => {\r\n if(!canceledSelection) {\r\n cancelSelection();\r\n canceledSelection = true;\r\n }\r\n /* if(!good) {\r\n if(Math.abs(e.x - x) > MIN_CLICK_MOVE || Math.abs(e.y - y) > MIN_CLICK_MOVE) {\r\n good = true;\r\n } else {\r\n return;\r\n }\r\n } */\r\n\r\n /* if(foundTargets.has(e.target as HTMLElement)) return;\r\n foundTargets.set(e.target as HTMLElement, true); */\r\n const bubble = findUpClassName(e.target, 'grouped-item') || findUpClassName(e.target, 'bubble');\r\n if(!bubble) {\r\n //console.error('found no bubble', e);\r\n return;\r\n }\r\n\r\n const mid = +bubble.dataset.mid;\r\n if(!mid) return;\r\n\r\n // * cancel selecting if selecting message text\r\n if(e.target !== bubble && !(e.target as HTMLElement).classList.contains('document-selection') && selecting === undefined && !this.selectedMids.size) {\r\n this.listenerSetter.removeManual(bubblesContainer, 'mousemove', onMouseMove);\r\n this.listenerSetter.removeManual(document, 'mouseup', onMouseUp, documentListenerOptions);\r\n return;\r\n }\r\n\r\n if(!seen.has(mid)) {\r\n const isBubbleSelected = this.selectedMids.has(mid);\r\n if(selecting === undefined) {\r\n //bubblesContainer.classList.add('no-select');\r\n selecting = !isBubbleSelected;\r\n }\r\n\r\n seen.add(mid);\r\n\r\n if((selecting && !isBubbleSelected) || (!selecting && isBubbleSelected)) {\r\n if(!this.selectedMids.size) {\r\n if(seen.size === 2) {\r\n [...seen].forEach(mid => {\r\n const mounted = this.bubbles.getMountedBubble(mid);\r\n if(mounted) {\r\n this.toggleByBubble(mounted.bubble);\r\n }\r\n })\r\n }\r\n } else {\r\n this.toggleByBubble(bubble);\r\n }\r\n }\r\n }\r\n //console.log('onMouseMove', target);\r\n };\r\n\r\n const onMouseUp = (e: MouseEvent) => {\r\n if(seen.size) {\r\n window.addEventListener('click', (e) => {\r\n cancelEvent(e);\r\n }, {capture: true, once: true, passive: false});\r\n }\r\n\r\n this.listenerSetter.removeManual(bubblesContainer, 'mousemove', onMouseMove);\r\n //bubblesContainer.classList.remove('no-select');\r\n\r\n // ! CANCEL USER SELECTION !\r\n cancelSelection();\r\n };\r\n\r\n const documentListenerOptions = {once: true};\r\n this.listenerSetter.add(bubblesContainer)('mousemove', onMouseMove);\r\n this.listenerSetter.add(document)('mouseup', onMouseUp, documentListenerOptions);\r\n });\r\n }\r\n\r\n public toggleBubbleCheckbox(bubble: HTMLElement, show: boolean) {\r\n if(!this.canSelectBubble(bubble)) return;\r\n\r\n const hasCheckbox = !!this.getCheckboxInputFromBubble(bubble);\r\n const isGrouped = bubble.classList.contains('is-grouped');\r\n if(show) {\r\n if(hasCheckbox) return;\r\n \r\n const checkboxField = new CheckboxField({\r\n name: bubble.dataset.mid, \r\n round: true\r\n });\r\n checkboxField.label.classList.add('bubble-select-checkbox');\r\n\r\n // * if it is a render of new message\r\n if(this.isSelecting) { // ! avoid breaking animation on start\r\n const mid = +bubble.dataset.mid;\r\n if(this.selectedMids.has(mid) && (!isGrouped || this.isGroupedMidsSelected(mid))) {\r\n checkboxField.input.checked = true;\r\n bubble.classList.add('is-selected');\r\n }\r\n }\r\n\r\n if(bubble.classList.contains('document-container')) {\r\n bubble.querySelector('.document, audio-element').append(checkboxField.label);\r\n } else {\r\n bubble.prepend(checkboxField.label);\r\n }\r\n } else if(hasCheckbox) {\r\n this.getCheckboxInputFromBubble(bubble).parentElement.remove();\r\n }\r\n\r\n if(isGrouped) {\r\n this.bubbles.getBubbleGroupedItems(bubble).forEach(item => this.toggleBubbleCheckbox(item, show));\r\n }\r\n }\r\n\r\n private getCheckboxInputFromBubble(bubble: HTMLElement): HTMLInputElement {\r\n /* let perf = performance.now();\r\n let checkbox = bubble.firstElementChild.tagName === 'LABEL' && bubble.firstElementChild.firstElementChild as HTMLInputElement;\r\n console.log('getCheckboxInputFromBubble firstElementChild time:', performance.now() - perf);\r\n\r\n perf = performance.now();\r\n checkbox = bubble.querySelector('label input');\r\n console.log('getCheckboxInputFromBubble querySelector time:', performance.now() - perf); */\r\n /* let perf = performance.now();\r\n let contains = bubble.classList.contains('document-container');\r\n console.log('getCheckboxInputFromBubble classList time:', performance.now() - perf);\r\n\r\n perf = performance.now();\r\n contains = bubble.className.includes('document-container');\r\n console.log('getCheckboxInputFromBubble className time:', performance.now() - perf); */\r\n\r\n return bubble.classList.contains('document-container') ? \r\n bubble.querySelector('label input') : \r\n bubble.firstElementChild.tagName === 'LABEL' && bubble.firstElementChild.firstElementChild as HTMLInputElement;\r\n }\r\n\r\n private updateContainer(forceSelection = false) {\r\n if(!this.selectedMids.size && !forceSelection) return;\r\n this.selectionCountEl.textContent = '';\r\n this.selectionCountEl.append(i18n('Chat.Selection.MessagesCount', [this.selectedMids.size]));\r\n\r\n let cantForward = !this.selectedMids.size, cantDelete = !this.selectedMids.size, cantSend = !this.selectedMids.size;\r\n for(const mid of this.selectedMids.values()) {\r\n const message = this.appMessagesManager.getMessageByPeer(this.bubbles.peerId, mid);\r\n if(!cantForward) {\r\n if(message.action) {\r\n cantForward = true;\r\n }\r\n }\r\n \r\n\r\n if(!cantDelete) {\r\n const canDelete = this.appMessagesManager.canDeleteMessage(this.chat.getMessage(mid));\r\n if(!canDelete) {\r\n cantDelete = true;\r\n }\r\n }\r\n\r\n if(cantForward && cantDelete) break;\r\n }\r\n\r\n this.selectionSendNowBtn && this.selectionSendNowBtn.toggleAttribute('disabled', cantSend);\r\n this.selectionForwardBtn && this.selectionForwardBtn.toggleAttribute('disabled', cantForward);\r\n this.selectionDeleteBtn.toggleAttribute('disabled', cantDelete);\r\n }\r\n\r\n public toggleSelection(toggleCheckboxes = true, forceSelection = false) {\r\n const wasSelecting = this.isSelecting;\r\n this.isSelecting = this.selectedMids.size > 0 || forceSelection;\r\n\r\n if(wasSelecting === this.isSelecting) return;\r\n \r\n const bubblesContainer = this.bubbles.bubblesContainer;\r\n //bubblesContainer.classList.toggle('is-selecting', !!this.selectedMids.size);\r\n\r\n /* if(bubblesContainer.classList.contains('is-chat-input-hidden')) {\r\n const scrollable = this.appImManager.scrollable;\r\n if(scrollable.isScrolledDown) {\r\n scrollable.scrollTo(scrollable.scrollHeight, 'top', true, true, 200);\r\n }\r\n } */\r\n\r\n if(!isTouchSupported) {\r\n bubblesContainer.classList.toggle('no-select', this.isSelecting);\r\n\r\n if(wasSelecting) {\r\n // ! CANCEL USER SELECTION !\r\n cancelSelection();\r\n }\r\n }/* else {\r\n if(!wasSelecting) {\r\n bubblesContainer.classList.add('no-select');\r\n setTimeout(() => {\r\n cancelSelection();\r\n bubblesContainer.classList.remove('no-select');\r\n cancelSelection();\r\n }, 100);\r\n }\r\n } */\r\n\r\n blurActiveElement();\r\n\r\n let transform = '', borderRadius = '';\r\n const forwards = !!this.selectedMids.size || forceSelection;\r\n if(forwards) {\r\n const p = this.input.rowsWrapper.parentElement;\r\n const fakeSelectionWrapper = p.querySelector('.fake-selection-wrapper');\r\n const fakeRowsWrapper = p.querySelector('.fake-rows-wrapper');\r\n const fakeSelectionRect = fakeSelectionWrapper.getBoundingClientRect();\r\n const fakeRowsRect = fakeRowsWrapper.getBoundingClientRect();\r\n const widthFrom = fakeRowsRect.width;\r\n const widthTo = fakeSelectionRect.width;\r\n\r\n if(widthFrom !== widthTo) {\r\n const scale = (widthTo/* - 8 */) / widthFrom;\r\n const initTranslateX = (widthFrom - widthTo) / 2;\r\n const needTranslateX = fakeSelectionRect.left - fakeRowsRect.left - initTranslateX;\r\n transform = `translateX(${needTranslateX}px) scaleX(${scale})`;\r\n\r\n if(scale < 1) {\r\n const br = 12;\r\n borderRadius = '' + (br + br * (1 - scale)) + 'px';\r\n }\r\n //scale = widthTo / widthFrom;\r\n }\r\n }\r\n\r\n SetTransition(this.input.rowsWrapper, 'is-centering', forwards, 200);\r\n this.input.rowsWrapper.style.transform = transform;\r\n this.input.rowsWrapper.style.borderRadius = borderRadius;\r\n SetTransition(bubblesContainer, 'is-selecting', forwards, 200, () => {\r\n if(!this.isSelecting) {\r\n this.selectionInputWrapper.remove();\r\n this.selectionInputWrapper = this.selectionContainer = this.selectionSendNowBtn = this.selectionForwardBtn = this.selectionDeleteBtn = null;\r\n this.selectedText = undefined;\r\n }\r\n \r\n window.requestAnimationFrame(() => {\r\n this.bubbles.onScroll();\r\n });\r\n });\r\n\r\n if(!isMobileSafari) {\r\n if(forwards) {\r\n appNavigationController.pushItem({\r\n type: 'multiselect',\r\n onPop: () => {\r\n this.cancelSelection();\r\n }\r\n });\r\n } else {\r\n appNavigationController.removeByType('multiselect');\r\n }\r\n }\r\n\r\n //const chatInput = this.appImManager.chatInput;\r\n\r\n if(this.isSelecting) {\r\n if(!this.selectionContainer) {\r\n this.selectionInputWrapper = document.createElement('div');\r\n this.selectionInputWrapper.classList.add('chat-input-wrapper', 'selection-wrapper');\r\n\r\n this.selectionContainer = document.createElement('div');\r\n this.selectionContainer.classList.add('selection-container');\r\n\r\n const btnCancel = ButtonIcon('close', {noRipple: true});\r\n this.listenerSetter.add(btnCancel)('click', this.cancelSelection, {once: true});\r\n\r\n this.selectionCountEl = document.createElement('div');\r\n this.selectionCountEl.classList.add('selection-container-count');\r\n\r\n if(this.chat.type === 'scheduled') {\r\n this.selectionSendNowBtn = Button('btn-primary btn-transparent btn-short text-bold selection-container-send', {icon: 'send2'});\r\n this.selectionSendNowBtn.append(i18n('MessageScheduleSend'));\r\n this.listenerSetter.add(this.selectionSendNowBtn)('click', () => {\r\n new PopupSendNow(this.bubbles.peerId, [...this.selectedMids], () => {\r\n this.cancelSelection();\r\n })\r\n });\r\n } else {\r\n this.selectionForwardBtn = Button('btn-primary btn-transparent text-bold selection-container-forward', {icon: 'forward'});\r\n this.selectionForwardBtn.append(i18n('Forward'));\r\n this.listenerSetter.add(this.selectionForwardBtn)('click', () => {\r\n new PopupForward(this.bubbles.peerId, [...this.selectedMids], () => {\r\n this.cancelSelection();\r\n });\r\n });\r\n }\r\n\r\n this.selectionDeleteBtn = Button('btn-primary btn-transparent danger text-bold selection-container-delete', {icon: 'delete'});\r\n this.selectionDeleteBtn.append(i18n('Delete'));\r\n this.listenerSetter.add(this.selectionDeleteBtn)('click', () => {\r\n new PopupDeleteMessages(this.bubbles.peerId, [...this.selectedMids], this.chat.type, () => {\r\n this.cancelSelection();\r\n });\r\n });\r\n\r\n this.selectionContainer.append(...[btnCancel, this.selectionCountEl, this.selectionSendNowBtn, this.selectionForwardBtn, this.selectionDeleteBtn].filter(Boolean));\r\n\r\n this.selectionInputWrapper.style.opacity = '0';\r\n this.selectionInputWrapper.append(this.selectionContainer);\r\n this.input.rowsWrapper.parentElement.append(this.selectionInputWrapper);\r\n\r\n void this.selectionInputWrapper.offsetLeft; // reflow\r\n this.selectionInputWrapper.style.opacity = '';\r\n }\r\n }\r\n\r\n if(toggleCheckboxes) {\r\n for(const mid in this.bubbles.bubbles) {\r\n const bubble = this.bubbles.bubbles[mid];\r\n this.toggleBubbleCheckbox(bubble, this.isSelecting);\r\n }\r\n }\r\n\r\n if(forceSelection) {\r\n this.updateContainer(forceSelection);\r\n }\r\n }\r\n\r\n public cancelSelection = () => {\r\n for(const mid of this.selectedMids) {\r\n const mounted = this.bubbles.getMountedBubble(mid);\r\n if(mounted) {\r\n //this.toggleByBubble(mounted.message.grouped_id ? mounted.bubble.querySelector(`.grouped-item[data-mid=\"${mid}\"]`) : mounted.bubble);\r\n this.toggleByBubble(mounted.bubble);\r\n }\r\n /* const bubble = this.appImManager.bubbles[mid];\r\n if(bubble) {\r\n this.toggleByBubble(bubble);\r\n } */\r\n }\r\n\r\n this.selectedMids.clear();\r\n this.toggleSelection();\r\n cancelSelection();\r\n };\r\n\r\n public cleanup() {\r\n this.selectedMids.clear();\r\n this.toggleSelection(false);\r\n }\r\n\r\n private updateBubbleSelection(bubble: HTMLElement, isSelected: boolean) {\r\n this.toggleBubbleCheckbox(bubble, true);\r\n const input = this.getCheckboxInputFromBubble(bubble);\r\n input.checked = isSelected;\r\n\r\n this.toggleSelection();\r\n this.updateContainer();\r\n SetTransition(bubble, 'is-selected', isSelected, 200);\r\n }\r\n\r\n private isGroupedBubbleSelected(bubble: HTMLElement) {\r\n const groupedCheckboxInput = this.getCheckboxInputFromBubble(bubble);\r\n return groupedCheckboxInput?.checked;\r\n }\r\n\r\n private isGroupedMidsSelected(mid: number) {\r\n const mids = this.chat.getMidsByMid(mid);\r\n const selectedMids = mids.filter(mid => this.selectedMids.has(mid));\r\n return mids.length === selectedMids.length;\r\n }\r\n\r\n public toggleByBubble = (bubble: HTMLElement) => {\r\n if(!this.canSelectBubble(bubble)) return;\r\n\r\n const mid = +bubble.dataset.mid;\r\n\r\n const isGrouped = bubble.classList.contains('is-grouped');\r\n if(isGrouped) {\r\n if(!this.isGroupedBubbleSelected(bubble)) {\r\n const mids = this.chat.getMidsByMid(mid);\r\n mids.forEach(mid => this.selectedMids.delete(mid));\r\n }\r\n\r\n this.bubbles.getBubbleGroupedItems(bubble).forEach(this.toggleByBubble);\r\n return;\r\n }\r\n\r\n const found = this.selectedMids.has(mid);\r\n if(found) {\r\n this.selectedMids.delete(mid);\r\n } else {\r\n const diff = rootScope.config.forwarded_count_max - this.selectedMids.size - 1;\r\n if(diff < 0) {\r\n toast(I18n.format('Chat.Selection.LimitToast', true));\r\n return;\r\n /* const it = this.selectedMids.values();\r\n do {\r\n const mid = it.next().value;\r\n const mounted = this.appImManager.getMountedBubble(mid);\r\n if(mounted) {\r\n this.toggleByBubble(mounted.bubble);\r\n } else {\r\n const mids = this.appMessagesManager.getMidsByMid(mid);\r\n for(const mid of mids) {\r\n this.selectedMids.delete(mid);\r\n }\r\n }\r\n } while(this.selectedMids.size > MAX_SELECTION_LENGTH); */\r\n }\r\n\r\n this.selectedMids.add(mid);\r\n }\r\n\r\n const isGroupedItem = bubble.classList.contains('grouped-item');\r\n if(isGroupedItem) {\r\n const groupContainer = findUpClassName(bubble, 'bubble');\r\n const isGroupedSelected = this.isGroupedBubbleSelected(groupContainer);\r\n const isGroupedMidsSelected = this.isGroupedMidsSelected(mid);\r\n\r\n const willChange = isGroupedMidsSelected || isGroupedSelected;\r\n if(willChange) {\r\n this.updateBubbleSelection(groupContainer, isGroupedMidsSelected);\r\n }\r\n }\r\n\r\n this.updateBubbleSelection(bubble, !found);\r\n };\r\n\r\n /**\r\n * ! Call this method only to handle deleted messages\r\n */\r\n public deleteSelectedMids(mids: number[]) {\r\n mids.forEach(mid => {\r\n this.selectedMids.delete(mid);\r\n });\r\n\r\n this.updateContainer();\r\n this.toggleSelection();\r\n }\r\n\r\n public canSelectBubble(bubble: HTMLElement) {\r\n return !bubble.classList.contains('service') && !bubble.classList.contains('is-sending') && !bubble.classList.contains('bubble-first');\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 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","/*\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\n\r\n//const classNames: string[] = [];\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 private close: HTMLElement;\r\n protected wrapper: HTMLElement;\r\n\r\n constructor(protected topbar: ChatTopbar, protected chat: Chat, public listenerSetter: ListenerSetter, protected className: string, public divAndCaption: DivAndCaption<(title: string | HTMLElement, subtitle: string | HTMLElement, message?: any) => void>, onClose?: () => void | Promise<boolean>) {\r\n /* const prev = this.divAndCaption.fill;\r\n this.divAndCaption.fill = (mid, title, subtitle) => {\r\n this.divAndCaption.container.dataset.mid = '' + mid;\r\n prev(mid, title, subtitle);\r\n }; */\r\n\r\n //classNames.push(`is-pinned-${className}-shown`);\r\n\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.close = document.createElement('button');\r\n this.close.classList.add(CLASSNAME_BASE + '-close', `pinned-${className}-close`, 'btn-icon', 'tgico-close');\r\n\r\n //divAndCaption.container.prepend(this.close);\r\n\r\n this.wrapper = document.createElement('div');\r\n this.wrapper.classList.add(CLASSNAME_BASE + '-wrapper');\r\n this.wrapper.append(...Array.from(divAndCaption.container.children));\r\n ripple(this.wrapper);\r\n \r\n divAndCaption.container.append(this.close, this.wrapper);\r\n\r\n attachClickEvent(this.close, (e) => {\r\n cancelEvent(e);\r\n\r\n ((onClose ? 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 this.divAndCaption.container.classList.toggle('is-floating', mediaSizes.isMobile);\r\n this.topbar.container.classList.toggle('is-pinned-floating', mediaSizes.isMobile);\r\n\r\n const scrollable = this.chat.bubbles.scrollable;\r\n\r\n const scrollTop = mediaSizes.isMobile /* && !appImManager.scrollable.isScrolledDown */ ? scrollable.scrollTop : undefined;\r\n this.divAndCaption.container.classList.toggle('hide', hide);\r\n const className = `is-pinned-${this.className}-shown`;\r\n this.topbar.container.classList.toggle(className, !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.setUtilsWidth();\r\n }\r\n\r\n public fill(title: string | HTMLElement, subtitle: string | HTMLElement, message: any) {\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","/*\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 ChatTopbar from \"./topbar\";\r\nimport { RichTextProcessor } from \"../../lib/richtextprocessor\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport appMediaPlaybackController from \"../appMediaPlaybackController\";\r\nimport DivAndCaption from \"../divAndCaption\";\r\nimport { formatDate } from \"../wrappers\";\r\nimport PinnedContainer from \"./pinnedContainer\";\r\nimport Chat from \"./chat\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\nimport PeerTitle from \"../peerTitle\";\r\n\r\nexport default class ChatAudio extends PinnedContainer {\r\n private toggleEl: HTMLElement;\r\n\r\n constructor(protected topbar: ChatTopbar, protected chat: Chat, protected appMessagesManager: AppMessagesManager) {\r\n super(topbar, chat, topbar.listenerSetter, 'audio', new DivAndCaption('pinned-audio', (title: string | HTMLElement, subtitle: string | HTMLElement) => {\r\n replaceContent(this.divAndCaption.title, title);\r\n replaceContent(this.divAndCaption.subtitle, subtitle);\r\n }), () => {\r\n if(this.toggleEl.classList.contains('flip-icon')) {\r\n appMediaPlaybackController.toggle();\r\n }\r\n });\r\n\r\n this.divAndCaption.border.remove();\r\n\r\n this.toggleEl = document.createElement('button');\r\n this.toggleEl.classList.add('pinned-audio-ico', 'tgico', 'btn-icon');\r\n attachClickEvent(this.toggleEl, (e) => {\r\n cancelEvent(e);\r\n appMediaPlaybackController.toggle();\r\n }, {listenerSetter: this.topbar.listenerSetter});\r\n\r\n this.wrapper.prepend(this.toggleEl);\r\n\r\n this.topbar.listenerSetter.add(rootScope)('audio_play', (e) => {\r\n const {doc, mid, peerId} = e;\r\n\r\n let title: string | HTMLElement, subtitle: string;\r\n const message = appMessagesManager.getMessageByPeer(peerId, mid);\r\n if(doc.type === 'voice' || doc.type === 'round') {\r\n title = new PeerTitle({\r\n peerId: message.fromId,\r\n onlyFirstName: true\r\n }).element;\r\n\r\n //subtitle = 'Voice message';\r\n subtitle = formatDate(message.date, false, false);\r\n } else {\r\n title = doc.audioTitle || doc.file_name;\r\n subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : 'Unknown Artist';\r\n }\r\n\r\n this.fill(title, subtitle, message);\r\n this.toggleEl.classList.add('flip-icon');\r\n this.toggle(false);\r\n });\r\n\r\n this.topbar.listenerSetter.add(rootScope)('audio_pause', () => {\r\n this.toggleEl.classList.remove('flip-icon');\r\n });\r\n }\r\n}\r\n","// https://github.com/evgeny-nadymov/telegram-react/blob/master/src/Components/ColumnMiddle/PinnedMessageBorder.js\r\n\r\nenum BAR_HEIGHTS {\r\n ONE = 32,\r\n TWO = 15,\r\n THREE = 10,\r\n FOUR = 8,\r\n MORE = 8\r\n};\r\n\r\nconst GAP = 1;\r\nconst WIDTH = 2;\r\nconst BASE_CLASS = 'pinned-message-border';\r\n\r\nexport default class PinnedMessageBorder {\r\n private border: HTMLElement;\r\n private wrapper: HTMLElement;\r\n private svg: SVGSVGElement;\r\n private defs: SVGDefsElement;\r\n private clipPath: SVGClipPathElement;\r\n private path: SVGPathElement;\r\n private mark: HTMLElement;\r\n\r\n private count: number;\r\n private index: number;\r\n\r\n private drawRect = (x: number, y: number, width: number, height: number, radius: number) => {\r\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`;\r\n };\r\n\r\n private getClipPath = (id: string, barHeight: number, count: number) => {\r\n const radius = 1;\r\n\r\n let d = '';\r\n /* if(count === 3) {\r\n d = this.drawRect(0, 0, WIDTH, barHeight, radius)\r\n + this.drawRect(0, barHeight + GAP, WIDTH, barHeight + 1, radius)\r\n + this.drawRect(0, barHeight * 2 + GAP * 2 + 1, WIDTH, barHeight, radius);\r\n } */if(count === 2) {\r\n d = this.drawRect(0, 0, WIDTH, barHeight, radius) + this.drawRect(0, barHeight + GAP * 2, WIDTH, barHeight, radius);\r\n } else {\r\n for(let i = 0; i < count; ++i) {\r\n d += this.drawRect(0, (barHeight + GAP) * i, WIDTH, barHeight, radius);\r\n }\r\n }\r\n\r\n if(!this.clipPath) {\r\n this.clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');\r\n this.path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\r\n\r\n this.clipPath.append(this.path);\r\n }\r\n\r\n this.clipPath.id = id;\r\n this.path.setAttributeNS(null, 'd', d);\r\n\r\n return this.clipPath;\r\n };\r\n\r\n private getBarHeight = (count: number, index: number) => {\r\n let barHeight: number;\r\n if(count <= 1) {\r\n barHeight = BAR_HEIGHTS.ONE;\r\n } else if(count === 2) {\r\n barHeight = BAR_HEIGHTS.TWO;\r\n } else if(count === 3) {\r\n barHeight = BAR_HEIGHTS.THREE;\r\n } else if(count === 4) {\r\n barHeight = BAR_HEIGHTS.FOUR;\r\n } else if(count > 3) {\r\n barHeight = BAR_HEIGHTS.MORE;\r\n }\r\n\r\n return barHeight;\r\n };\r\n\r\n private getMarkHeight = (count: number, index: number) => {\r\n let markHeight: number;\r\n if(count <= 1) {\r\n markHeight = BAR_HEIGHTS.ONE;\r\n } else if(count === 2) {\r\n markHeight = BAR_HEIGHTS.TWO;\r\n } else if(count === 3) {\r\n markHeight = BAR_HEIGHTS.THREE;\r\n } else if(count === 4) {\r\n markHeight = BAR_HEIGHTS.FOUR;\r\n } else if(count > 3) {\r\n markHeight = BAR_HEIGHTS.MORE;\r\n }\r\n\r\n return markHeight;\r\n };\r\n\r\n private getMarkTranslateY = (index: number, barHeight: number, count: number) => {\r\n if(count === 1) {\r\n return 0;\r\n } else if(count === 2) {\r\n return !index ? 0 : barHeight + GAP;\r\n }\r\n\r\n if(count === 3) {\r\n if(!index) {\r\n return 0;\r\n } else if(index === 1) {\r\n return barHeight + GAP;\r\n }\r\n\r\n return barHeight * 2 + GAP * 2 + 1;\r\n } else {\r\n return (barHeight + GAP) * index;\r\n }\r\n };\r\n\r\n private getTrackTranslateY = (index: number, count: number, barHeight: number, trackHeight: number) => {\r\n if(count <= 4) {\r\n return 0;\r\n }\r\n\r\n if(index <= 1) {\r\n return 0;\r\n } else if(index >= (count - 2)) {\r\n return trackHeight - BAR_HEIGHTS.ONE - barHeight;\r\n }\r\n\r\n // return (index + 1) * barHeight + index * GAP;\r\n return (index - 2) * barHeight + index * GAP;\r\n //return (barHeight + GAP * 2) / 2 + (index - 2) * (barHeight + GAP);\r\n };\r\n\r\n private getTrackHeight = (count: number, barHeight: number) => {\r\n return count <= 3 ? BAR_HEIGHTS.ONE : barHeight * count + GAP * (count - 1);\r\n };\r\n\r\n public render(count: number, index: number) {\r\n if(!this.border) {\r\n this.border = document.createElement('div');\r\n this.border.classList.add(BASE_CLASS);\r\n\r\n this.wrapper = document.createElement('div');\r\n this.border.append(this.wrapper);\r\n }\r\n \r\n if(count === 1) {\r\n if(this.count !== count) {\r\n this.wrapper.className = BASE_CLASS + '-wrapper-1';\r\n this.border.classList.remove(BASE_CLASS + '-mask');\r\n this.wrapper.innerHTML = this.wrapper.style.cssText = '';\r\n }\r\n\r\n return this.border;\r\n }\r\n\r\n const barHeight = this.getBarHeight(count, index);\r\n const markHeight = this.getMarkHeight(count, index);\r\n const trackHeight = this.getTrackHeight(count, barHeight);\r\n\r\n const clipPathId = `clipPath_${count}`;\r\n const clipPath = this.getClipPath(clipPathId, barHeight, count);\r\n\r\n const markTranslateY = this.getMarkTranslateY(index, barHeight, count);\r\n const trackTranslateY = this.getTrackTranslateY(index, count, barHeight, trackHeight);\r\n\r\n this.border.classList.toggle(BASE_CLASS + '-mask', count > 4);\r\n\r\n if(index <= 1) {\r\n this.border.classList.add('mask-bottom');\r\n this.border.classList.remove('mask-top');\r\n } else if(index >= (count - 2)) {\r\n this.border.classList.add('mask-top');\r\n this.border.classList.remove('mask-bottom');\r\n } else {\r\n this.border.classList.add('mask-top', 'mask-bottom');\r\n }\r\n\r\n this.wrapper.className = BASE_CLASS + '-wrapper';\r\n this.wrapper.style.cssText = `clip-path: url(#${clipPathId}); width: 2px; height: ${trackHeight}px; transform: translateY(-${trackTranslateY}px);`;\r\n \r\n if(!this.svg) {\r\n this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\r\n this.svg.setAttributeNS(null, 'height', '0');\r\n this.svg.setAttributeNS(null, 'width', '0');\r\n \r\n this.defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');\r\n this.defs.append(clipPath);\r\n\r\n this.svg.append(this.defs);\r\n\r\n this.mark = document.createElement('div');\r\n this.mark.classList.add(BASE_CLASS + '-mark');\r\n }\r\n\r\n if(!this.svg.parentElement) {\r\n this.wrapper.append(this.svg, this.mark);\r\n }\r\n\r\n this.mark.style.cssText = `height: ${markHeight}px; transform: translateY(${markTranslateY}px);`;\r\n \r\n this.count = count;\r\n this.index = index;\r\n\r\n return this.border;\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 { 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 { debounce } from \"../../helpers/schedulers\";\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\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 this.pinnedMessageContainer = new PinnedContainer(topbar, chat, this.listenerSetter, 'message', new ReplyContainer('pinned-message'), 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 this.pinnedMessageBorder = new PinnedMessageBorder();\r\n this.pinnedMessageContainer.divAndCaption.border.replaceWith(this.pinnedMessageBorder.render(1, 0));\r\n\r\n this.animatedSubtitle = new AnimatedSuper();\r\n this.pinnedMessageContainer.divAndCaption.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 this.pinnedMessageContainer.divAndCaption.content.prepend(this.animatedMedia.container);\r\n\r\n this.animatedCounter = new AnimatedCounter(true);\r\n this.pinnedMessageContainer.divAndCaption.title.append(i18n('PinnedMessage'), ' ', this.animatedCounter.container);\r\n\r\n this.btnOpen = ButtonIcon('pinlist pinned-container-close pinned-message-pinlist', {noRipple: true});\r\n this.pinnedMessageContainer.divAndCaption.container.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', (e) => {\r\n const peerId = e.peerId;\r\n\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', (e) => {\r\n const {peerId, maxId} = e;\r\n\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 _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 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 });\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 { isTouchSupported } from \"../touchSupport\";\r\n\r\nexport default function handleScrollSideEvent(elem: HTMLElement, side: 'top' | 'bottom', callback: () => void, listenerSetter: ListenerSetter) {\r\n if(isTouchSupported) {\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","/*\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, Channel } from \"../../lib/appManagers/appChatsManager\";\r\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\r\nimport type { AppSidebarRight } from \"../sidebarRight\";\r\nimport type Chat from \"./chat\";\r\nimport { RIGHT_COLUMN_ACTIVE_CLASSNAME } from \"../sidebarRight\";\r\nimport mediaSizes, { ScreenSize } from \"../../helpers/mediaSizes\";\r\nimport { isSafari } from \"../../helpers/userAgent\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport AvatarElement from \"../avatar\";\r\nimport Button from \"../button\";\r\nimport ButtonIcon from \"../buttonIcon\";\r\nimport ButtonMenuToggle from \"../buttonMenuToggle\";\r\nimport ChatAudio from \"./audio\";\r\nimport ChatPinnedMessage from \"./pinnedMessage\";\r\nimport { ButtonMenuItemOptions } from \"../buttonMenu\";\r\nimport ListenerSetter from \"../../helpers/listenerSetter\";\r\nimport appStateManager from \"../../lib/appManagers/appStateManager\";\r\nimport PopupDeleteDialog from \"../popups/deleteDialog\";\r\nimport appNavigationController from \"../appNavigationController\";\r\nimport { LEFT_COLUMN_ACTIVE_CLASSNAME } from \"../sidebarLeft\";\r\nimport PeerTitle from \"../peerTitle\";\r\nimport { i18n } from \"../../lib/langPack\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport blurActiveElement from \"../../helpers/dom/blurActiveElement\";\r\nimport { cancelEvent } from \"../../helpers/dom/cancelEvent\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport { toast } from \"../toast\";\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\n\r\nexport default class ChatTopbar {\r\n public container: HTMLDivElement;\r\n private btnBack: HTMLButtonElement;\r\n private chatInfo: HTMLDivElement;\r\n private avatarElement: AvatarElement;\r\n private title: HTMLDivElement;\r\n private subtitle: HTMLDivElement;\r\n private chatUtils: HTMLDivElement;\r\n private btnJoin: HTMLButtonElement;\r\n private btnPinned: HTMLButtonElement;\r\n private btnMute: HTMLButtonElement;\r\n private btnSearch: HTMLButtonElement;\r\n private btnMore: HTMLButtonElement;\r\n \r\n private chatAudio: ChatAudio;\r\n public pinnedMessage: ChatPinnedMessage;\r\n\r\n private setUtilsRAF: number;\r\n public peerId: number;\r\n private wasPeerId: number;\r\n private setPeerStatusInterval: number;\r\n\r\n public listenerSetter: ListenerSetter;\r\n\r\n private menuButtons: (ButtonMenuItemOptions & {verify: () => boolean})[] = [];\r\n\r\n constructor(private chat: Chat, private appSidebarRight: AppSidebarRight, private appMessagesManager: AppMessagesManager, private appPeersManager: AppPeersManager, private appChatsManager: AppChatsManager, private appNotificationsManager: AppNotificationsManager) {\r\n this.listenerSetter = new ListenerSetter();\r\n }\r\n\r\n public construct() {\r\n //this.chat.log.error('Topbar construction');\r\n\r\n this.container = document.createElement('div');\r\n this.container.classList.add('sidebar-header', 'topbar');\r\n\r\n this.btnBack = ButtonIcon('left sidebar-close-button', {noRipple: true});\r\n\r\n // * chat info section\r\n this.chatInfo = document.createElement('div');\r\n this.chatInfo.classList.add('chat-info');\r\n\r\n const person = document.createElement('div');\r\n person.classList.add('person');\r\n\r\n const content = document.createElement('div');\r\n content.classList.add('content');\r\n\r\n const top = document.createElement('div');\r\n top.classList.add('top');\r\n\r\n this.title = document.createElement('div');\r\n this.title.classList.add('user-title');\r\n\r\n top.append(this.title);\r\n\r\n const bottom = document.createElement('div');\r\n bottom.classList.add('bottom');\r\n\r\n if(this.subtitle) {\r\n bottom.append(this.subtitle);\r\n }\r\n\r\n content.append(top, bottom);\r\n if(this.avatarElement) {\r\n person.append(this.avatarElement);\r\n }\r\n\r\n person.append(content);\r\n this.chatInfo.append(person);\r\n\r\n // * chat utils section\r\n this.chatUtils = document.createElement('div');\r\n this.chatUtils.classList.add('chat-utils');\r\n\r\n this.chatAudio = new ChatAudio(this, this.chat, this.appMessagesManager);\r\n\r\n if(this.menuButtons.length) {\r\n this.btnMore = ButtonMenuToggle({listenerSetter: this.listenerSetter}, 'bottom-left', this.menuButtons, (e) => {\r\n cancelEvent(e);\r\n this.menuButtons.forEach(button => {\r\n button.element.classList.toggle('hide', !button.verify());\r\n });\r\n\r\n // delete button\r\n this.menuButtons[this.menuButtons.length - 1].element.lastChild.replaceWith(i18n(this.appPeersManager.getDeleteButtonText(this.peerId)));\r\n });\r\n }\r\n\r\n this.chatUtils.append(...[this.chatAudio ? this.chatAudio.divAndCaption.container : null, this.pinnedMessage ? this.pinnedMessage.pinnedMessageContainer.divAndCaption.container : null, this.btnJoin, this.btnPinned, this.btnMute, this.btnSearch, this.btnMore].filter(Boolean));\r\n\r\n this.container.append(this.btnBack, this.chatInfo, this.chatUtils);\r\n\r\n // * construction end\r\n\r\n // * fix topbar overflow section\r\n\r\n this.listenerSetter.add(window)('resize', this.onResize);\r\n mediaSizes.addEventListener('changeScreen', this.onChangeScreen);\r\n\r\n attachClickEvent(this.container, (e) => {\r\n const container: HTMLElement = findUpClassName(e.target, 'pinned-container');\r\n blurActiveElement();\r\n if(container) {\r\n cancelEvent(e);\r\n \r\n const mid = +container.dataset.mid;\r\n const peerId = +container.dataset.peerId;\r\n if(container.classList.contains('pinned-message')) {\r\n //if(!this.pinnedMessage.locked) {\r\n this.pinnedMessage.followPinnedMessage(mid);\r\n //}\r\n } else {\r\n this.chat.appImManager.setInnerPeer(peerId, mid);\r\n }\r\n } else {\r\n if(mediaSizes.activeScreen === ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {\r\n onBtnBackClick();\r\n } else if(findUpTag(e.target, 'AVATAR-ELEMENT')) {\r\n this.appSidebarRight.toggleSidebar(!document.body.classList.contains(RIGHT_COLUMN_ACTIVE_CLASSNAME));\r\n } else {\r\n this.appSidebarRight.toggleSidebar(true);\r\n }\r\n }\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n const onBtnBackClick = (e?: Event) => {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n\r\n //const item = appNavigationController.findItemByType('chat');\r\n // * return manually to chat by arrow, since can't get back to\r\n if(mediaSizes.activeScreen === ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {\r\n this.chat.appImManager.setPeer(this.peerId);\r\n } else {\r\n const isFirstChat = this.chat.appImManager.chats.indexOf(this.chat) === 0;\r\n appNavigationController.back(isFirstChat ? 'im' : 'chat');\r\n return;\r\n\r\n if(mediaSizes.activeScreen === ScreenSize.medium && !appNavigationController.findItemByType('chat')) {\r\n this.chat.appImManager.setPeer(0);\r\n blurActiveElement();\r\n } else {\r\n appNavigationController.back('chat');\r\n }\r\n }\r\n };\r\n\r\n attachClickEvent(this.btnBack, onBtnBackClick, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n public constructUtils() {\r\n this.menuButtons = [{\r\n icon: 'search',\r\n text: 'Search',\r\n onClick: () => {\r\n this.chat.initSearch()\r\n },\r\n verify: () => mediaSizes.isMobile\r\n }, /* {\r\n icon: 'pinlist',\r\n text: 'Pinned Messages',\r\n onClick: () => this.openPinned(false),\r\n verify: () => mediaSizes.isMobile\r\n }, */ {\r\n icon: 'mute',\r\n text: 'ChatList.Context.Mute',\r\n onClick: () => {\r\n this.appMessagesManager.mutePeer(this.peerId);\r\n },\r\n verify: () => this.chat.type === 'chat' && rootScope.myId !== this.peerId && !this.appNotificationsManager.isPeerLocalMuted(this.peerId, false)\r\n }, {\r\n icon: 'unmute',\r\n text: 'ChatList.Context.Unmute',\r\n onClick: () => {\r\n this.appMessagesManager.mutePeer(this.peerId);\r\n },\r\n verify: () => this.chat.type === 'chat' && rootScope.myId !== this.peerId && this.appNotificationsManager.isPeerLocalMuted(this.peerId, false)\r\n }, {\r\n icon: 'select',\r\n text: 'Chat.Menu.SelectMessages',\r\n onClick: () => {\r\n const selection = this.chat.selection;\r\n selection.toggleSelection(true, true);\r\n appStateManager.getState().then(state => {\r\n if(state.chatContextMenuHintWasShown) {\r\n return;\r\n }\r\n\r\n const original = selection.toggleByBubble.bind(selection);\r\n selection.toggleByBubble = (bubble) => {\r\n appStateManager.pushToState('chatContextMenuHintWasShown', true);\r\n toast(i18n('Chat.Menu.Hint'));\r\n\r\n selection.toggleByBubble = original;\r\n selection.toggleByBubble(bubble);\r\n };\r\n });\r\n },\r\n verify: () => !this.chat.selection.isSelecting && !!Object.keys(this.chat.bubbles.bubbles).length\r\n }, {\r\n icon: 'select',\r\n text: 'Chat.Menu.ClearSelection',\r\n onClick: () => {\r\n this.chat.selection.cancelSelection();\r\n },\r\n verify: () => this.chat.selection.isSelecting\r\n }, {\r\n icon: 'delete danger',\r\n text: 'Delete',\r\n onClick: () => {\r\n new PopupDeleteDialog(this.peerId);\r\n },\r\n verify: () => this.chat.type === 'chat' && !!this.appMessagesManager.getDialogOnly(this.peerId)\r\n }];\r\n\r\n this.btnSearch = ButtonIcon('search');\r\n attachClickEvent(this.btnSearch, (e) => {\r\n cancelEvent(e);\r\n this.chat.initSearch();\r\n }, {listenerSetter: this.listenerSetter});\r\n }\r\n\r\n public constructPeerHelpers() {\r\n this.avatarElement = new AvatarElement();\r\n this.avatarElement.setAttribute('dialog', '1');\r\n //this.avatarElement.setAttribute('clickable', '');\r\n this.avatarElement.classList.add('avatar-42', 'person-avatar');\r\n\r\n this.subtitle = document.createElement('div');\r\n this.subtitle.classList.add('info');\r\n\r\n this.pinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);\r\n\r\n this.btnJoin = Button('btn-primary btn-color-primary chat-join hide');\r\n this.btnPinned = ButtonIcon('pinlist');\r\n this.btnMute = ButtonIcon('mute');\r\n\r\n attachClickEvent(this.btnPinned, (e) => {\r\n cancelEvent(e);\r\n blurActiveElement();\r\n this.openPinned(true);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n attachClickEvent(this.btnMute, (e) => {\r\n cancelEvent(e);\r\n blurActiveElement();\r\n this.appMessagesManager.mutePeer(this.peerId);\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n attachClickEvent(this.btnJoin, (e) => {\r\n cancelEvent(e);\r\n\r\n blurActiveElement();\r\n const middleware = this.chat.bubbles.getMiddleware();\r\n this.btnJoin.setAttribute('disabled', 'true');\r\n\r\n const chatId = -this.peerId;\r\n let promise: Promise<any>;\r\n if(this.appChatsManager.isChannel(chatId)) {\r\n promise = this.appChatsManager.joinChannel(chatId);\r\n } else {\r\n promise = this.appChatsManager.addChatUser(chatId, rootScope.myId);\r\n }\r\n\r\n promise.finally(() => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n this.btnJoin.removeAttribute('disabled');\r\n });\r\n }, {listenerSetter: this.listenerSetter});\r\n\r\n this.listenerSetter.add(rootScope)('chat_update', (e) => {\r\n const chatId: number = e;\r\n if(this.peerId === -chatId) {\r\n const chat = this.appChatsManager.getChat(chatId) as Channel/* | Chat */;\r\n \r\n this.btnJoin.classList.toggle('hide', !(chat as Channel)?.pFlags?.left);\r\n this.setUtilsWidth();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('dialog_notify_settings', (dialog) => {\r\n if(dialog.peerId === this.peerId) {\r\n this.setMutedState();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('peer_typings', (e) => {\r\n const {peerId} = e;\r\n\r\n if(this.peerId === peerId) {\r\n this.setPeerStatus();\r\n }\r\n });\r\n\r\n this.listenerSetter.add(rootScope)('user_update', (e) => {\r\n const userId = e;\r\n\r\n if(this.peerId === userId) {\r\n this.setPeerStatus();\r\n }\r\n });\r\n\r\n if(this.pinnedMessage) {\r\n this.chat.addEventListener('setPeer', (mid, isTopMessage) => {\r\n const middleware = this.chat.bubbles.getMiddleware();\r\n appStateManager.getState().then((state) => {\r\n if(!middleware()) return;\r\n \r\n this.pinnedMessage.hidden = !!state.hiddenPinnedMessages[this.chat.peerId];\r\n \r\n if(isTopMessage) {\r\n this.pinnedMessage.unsetScrollDownListener();\r\n this.pinnedMessage.testMid(mid, 0); // * because slider will not let get bubble by document.elementFromPoint\r\n } else if(!this.pinnedMessage.locked) {\r\n this.pinnedMessage.handleFollowingPinnedMessage();\r\n this.pinnedMessage.testMid(mid);\r\n }\r\n });\r\n });\r\n }\r\n\r\n this.setPeerStatusInterval = window.setInterval(this.setPeerStatus, 60e3);\r\n\r\n return this;\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\r\n if(peerId !== this.peerId) return;\r\n\r\n if(mids) {\r\n this.setTitle();\r\n }\r\n });\r\n }\r\n \r\n public constructDiscussionHelpers() {\r\n this.pinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);\r\n }\r\n\r\n public openPinned(byCurrent: boolean) {\r\n this.chat.appImManager.setInnerPeer(this.peerId, byCurrent ? +this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.dataset.mid : 0, 'pinned');\r\n }\r\n\r\n private onResize = () => {\r\n this.setUtilsWidth(true);\r\n };\r\n\r\n private onChangeScreen = (from: ScreenSize, to: ScreenSize) => {\r\n this.container.classList.toggle('is-pinned-floating', mediaSizes.isMobile);\r\n this.chatAudio && this.chatAudio.divAndCaption.container.classList.toggle('is-floating', to === ScreenSize.mobile);\r\n this.pinnedMessage && this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.classList.toggle('is-floating', to === ScreenSize.mobile);\r\n this.setUtilsWidth(true);\r\n };\r\n\r\n public destroy() {\r\n //this.chat.log.error('Topbar destroying');\r\n\r\n this.listenerSetter.removeAll();\r\n mediaSizes.removeEventListener('changeScreen', this.onChangeScreen);\r\n window.clearInterval(this.setPeerStatusInterval);\r\n \r\n if(this.pinnedMessage) {\r\n this.pinnedMessage.destroy(); // * возможно это можно не делать\r\n }\r\n\r\n delete this.chatAudio;\r\n delete this.pinnedMessage;\r\n }\r\n\r\n public setPeer(peerId: number) {\r\n this.wasPeerId = this.peerId;\r\n this.peerId = peerId;\r\n\r\n this.container.style.display = peerId ? '' : 'none';\r\n }\r\n\r\n public finishPeerChange(isTarget: boolean, isJump: boolean, lastMsgId: number) {\r\n const peerId = this.peerId;\r\n\r\n if(this.avatarElement) {\r\n this.avatarElement.setAttribute('peer', '' + peerId);\r\n this.avatarElement.update();\r\n }\r\n\r\n const isBroadcast = this.appPeersManager.isBroadcast(peerId);\r\n\r\n this.btnMute && this.btnMute.classList.toggle('hide', !isBroadcast);\r\n if(this.btnJoin) {\r\n replaceContent(this.btnJoin, i18n(this.appChatsManager.isChannel(-peerId) ? 'Chat.Subscribe' : 'ChannelJoin'));\r\n this.btnJoin.classList.toggle('hide', !this.appChatsManager.getChat(-peerId)?.pFlags?.left);\r\n }\r\n this.setUtilsWidth();\r\n\r\n const middleware = this.chat.bubbles.getMiddleware();\r\n if(this.pinnedMessage) { // * replace with new one\r\n if(this.chat.type === 'chat') {\r\n if(this.wasPeerId) { // * change\r\n const newPinnedMessage = new ChatPinnedMessage(this, this.chat, this.appMessagesManager, this.appPeersManager);\r\n this.pinnedMessage.pinnedMessageContainer.divAndCaption.container.replaceWith(newPinnedMessage.pinnedMessageContainer.divAndCaption.container);\r\n this.pinnedMessage.destroy();\r\n //this.pinnedMessage.pinnedMessageContainer.toggle(true);\r\n this.pinnedMessage = newPinnedMessage;\r\n }\r\n \r\n appStateManager.getState().then((state) => {\r\n if(!middleware()) return;\r\n \r\n this.pinnedMessage.hidden = !!state.hiddenPinnedMessages[peerId];\r\n \r\n if(!isTarget) {\r\n this.pinnedMessage.setCorrectIndex(0);\r\n }\r\n });\r\n } else if(this.chat.type === 'discussion') {\r\n this.pinnedMessage.pinnedMid = this.chat.threadId;\r\n this.pinnedMessage.count = 1;\r\n this.pinnedMessage.pinnedIndex = 0;\r\n this.pinnedMessage._setPinnedMessage();\r\n }\r\n }\r\n\r\n window.requestAnimationFrame(() => {\r\n this.setTitle();\r\n this.setPeerStatus(true);\r\n this.setMutedState();\r\n });\r\n }\r\n\r\n public setTitle(count?: number) {\r\n let titleEl: HTMLElement;\r\n if(this.chat.type === 'pinned') {\r\n if(count === undefined) titleEl = i18n('Loading');\r\n else titleEl = i18n('PinnedMessagesCount', [count]);\r\n\r\n if(count === undefined) {\r\n this.appMessagesManager.getSearchCounters(this.peerId, [{_: 'inputMessagesFilterPinned'}], false).then(result => {\r\n const count = result[0].count;\r\n this.setTitle(count);\r\n\r\n // ! костыль х2, это нужно делать в другом месте\r\n if(!count) {\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 } else if(this.chat.type === 'scheduled') {\r\n if(this.peerId === rootScope.myId) {\r\n //title = [count > 1 ? count : false, 'Reminders'].filter(Boolean).join(' ');\r\n titleEl = i18n('Reminders');\r\n } else {\r\n titleEl = i18n('ScheduledMessages');\r\n //title = [count > 1 ? count : false, 'Scheduled Messages'].filter(Boolean).join(' ');\r\n }\r\n \r\n if(count === undefined) {\r\n this.appMessagesManager.getScheduledMessages(this.peerId).then(mids => {\r\n this.setTitle(mids.length);\r\n });\r\n }\r\n } else if(this.chat.type === 'discussion') {\r\n if(count === undefined) titleEl = i18n('Loading');\r\n else titleEl = i18n('Chat.Title.Comments', [count]);\r\n\r\n if(count === undefined) {\r\n Promise.all([\r\n this.appMessagesManager.getHistory(this.peerId, 0, 1, 0, this.chat.threadId),\r\n Promise.resolve()\r\n ]).then(() => {\r\n const count = this.appMessagesManager.getHistoryStorage(this.peerId, this.chat.threadId).count;\r\n if(count === null) {\r\n setTimeout(() => {\r\n this.setTitle();\r\n }, 30);\r\n } else {\r\n this.setTitle(count);\r\n }\r\n });\r\n }\r\n } else if(this.chat.type === 'chat') {\r\n titleEl = new PeerTitle({\r\n peerId: this.peerId,\r\n dialog: true,\r\n }).element;\r\n }\r\n \r\n this.title.textContent = '';\r\n this.title.append(titleEl);\r\n }\r\n\r\n public setMutedState() {\r\n if(!this.btnMute) return;\r\n\r\n const peerId = this.peerId;\r\n let muted = this.appNotificationsManager.isPeerLocalMuted(peerId, false);\r\n if(this.appPeersManager.isBroadcast(peerId)) { // not human\r\n this.btnMute.classList.remove('tgico-mute', 'tgico-unmute');\r\n this.btnMute.classList.add(muted ? 'tgico-unmute' : 'tgico-mute');\r\n this.btnMute.style.display = '';\r\n } else {\r\n this.btnMute.style.display = 'none';\r\n }\r\n }\r\n\r\n // ! У МЕНЯ ПРОСТО СГОРЕЛО, САФАРИ КОНЧЕННЫЙ БРАУЗЕР - ЕСЛИ НЕ СКРЫВАТЬ БЛОК, ТО ПРИ ПЕРЕВОРОТЕ ЭКРАНА НА АЙФОНЕ БЛОК БУДЕТ НЕПРАВИЛЬНО ШИРИНЫ, ДАЖЕ БЕЗ ЭТОЙ ФУНКЦИИ!\r\n public setUtilsWidth = (resize = false) => {\r\n //return;\r\n if(this.setUtilsRAF) window.cancelAnimationFrame(this.setUtilsRAF);\r\n\r\n if(isSafari && resize) {\r\n this.chatUtils.classList.add('hide');\r\n }\r\n\r\n //mutationObserver.disconnect();\r\n this.setUtilsRAF = window.requestAnimationFrame(() => {\r\n \r\n //mutationRAF = window.requestAnimationFrame(() => {\r\n \r\n //setTimeout(() => {\r\n if(isSafari && resize) {\r\n this.chatUtils.classList.remove('hide');\r\n }\r\n /* this.chatInfo.style.removeProperty('--utils-width');\r\n void this.chatInfo.offsetLeft; // reflow */\r\n const width = /* chatUtils.scrollWidth */this.chatUtils.getBoundingClientRect().width;\r\n this.chat.log('utils width:', width);\r\n this.chatInfo.style.setProperty('--utils-width', width + 'px');\r\n //this.chatInfo.classList.toggle('have-utils-width', !!width);\r\n //}, 0);\r\n \r\n this.setUtilsRAF = 0;\r\n\r\n //mutationObserver.observe(chatUtils, observeOptions);\r\n //});\r\n });\r\n };\r\n\r\n public setPeerStatus = (needClear = false) => {\r\n if(!this.subtitle) return;\r\n\r\n const peerId = this.peerId;\r\n this.chat.appImManager.setPeerStatus(this.peerId, this.subtitle, needClear, false, () => peerId === this.peerId);\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 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 onDatePick: (timestamp: number) => void;\r\n\r\n onOpenAfterTimeout() {\r\n this.appSearch.beginSearch(this.peerId, this.threadId);\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 if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n query && (this.inputSearch.inputField.value = query);\r\n\r\n if(this.peerId !== 0) {\r\n this.appSearch.beginSearch(this.peerId, this.threadId);\r\n return ret;\r\n }\r\n\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 appSidebarRight.toggleSidebar(true);\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}","/*\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 } from \"../../lib/appManagers/appDocsManager\";\r\nimport type { AppImManager } from \"../../lib/appManagers/appImManager\";\r\nimport type { AppInlineBotsManager } from \"../../lib/appManagers/appInlineBotsManager\";\r\nimport type { AppMessagesManager } from \"../../lib/appManagers/appMessagesManager\";\r\nimport type { AppPeersManager } from \"../../lib/appManagers/appPeersManager\";\r\nimport type { AppPhotosManager } from \"../../lib/appManagers/appPhotosManager\";\r\nimport type { AppPollsManager } from \"../../lib/appManagers/appPollsManager\";\r\nimport type { AppProfileManager } from \"../../lib/appManagers/appProfileManager\";\r\nimport type { AppStickersManager } from \"../../lib/appManagers/appStickersManager\";\r\nimport type { AppUsersManager } from \"../../lib/appManagers/appUsersManager\";\r\nimport type { AppWebPagesManager } from \"../../lib/appManagers/appWebPagesManager\";\r\nimport type { ApiManagerProxy } from \"../../lib/mtproto/mtprotoworker\";\r\nimport type { AppDraftsManager } from \"../../lib/appManagers/appDraftsManager\";\r\nimport type { AppEmojiManager } from \"../../lib/appManagers/appEmojiManager\";\r\nimport type { ServerTimeManager } from \"../../lib/mtproto/serverTimeManager\";\r\nimport type { State } from \"../../lib/appManagers/appStateManager\";\r\nimport type stateStorage from '../../lib/stateStorage';\r\nimport EventListenerBase from \"../../helpers/eventListenerBase\";\r\nimport { logger, LogTypes } from \"../../lib/logger\";\r\nimport rootScope from \"../../lib/rootScope\";\r\nimport appSidebarRight from \"../sidebarRight\";\r\nimport ChatBubbles from \"./bubbles\";\r\nimport ChatContextMenu from \"./contextMenu\";\r\nimport ChatInput from \"./input\";\r\nimport ChatSelection from \"./selection\";\r\nimport ChatTopbar from \"./topbar\";\r\nimport { REPLIES_PEER_ID } from \"../../lib/mtproto/mtproto_config\";\r\nimport SetTransition from \"../singleTransition\";\r\nimport { fastRaf } from \"../../helpers/schedulers\";\r\nimport AppPrivateSearchTab from \"../sidebarRight/tabs/search\";\r\nimport renderImageFromUrl from \"../../helpers/dom/renderImageFromUrl\";\r\nimport mediaSizes from \"../../helpers/mediaSizes\";\r\nimport ChatSearch from \"./search\";\r\n\r\nexport type ChatType = 'chat' | 'pinned' | 'replies' | 'discussion' | 'scheduled';\r\n\r\nexport default class Chat extends EventListenerBase<{\r\n setPeer: (mid: number, isTopMessage: boolean) => void\r\n}> {\r\n public container: HTMLElement;\r\n public backgroundEl: HTMLElement;\r\n\r\n public topbar: ChatTopbar;\r\n public bubbles: ChatBubbles;\r\n public input: ChatInput;\r\n public selection: ChatSelection;\r\n public contextMenu: ChatContextMenu;\r\n\r\n public wasAlreadyUsed = false;\r\n // public initPeerId = 0;\r\n public peerId = 0;\r\n public threadId: number;\r\n public setPeerPromise: Promise<void>;\r\n public peerChanged: boolean;\r\n\r\n public log: ReturnType<typeof logger>;\r\n\r\n public type: ChatType = 'chat';\r\n\r\n public noAutoDownloadMedia: boolean;\r\n\r\n public inited = false;\r\n \r\n constructor(public appImManager: AppImManager, \r\n public appChatsManager: AppChatsManager, \r\n public appDocsManager: AppDocsManager, \r\n public appInlineBotsManager: AppInlineBotsManager, \r\n public appMessagesManager: AppMessagesManager, \r\n public appPeersManager: AppPeersManager, \r\n public appPhotosManager: AppPhotosManager, \r\n public appProfileManager: AppProfileManager, \r\n public appStickersManager: AppStickersManager, \r\n public appUsersManager: AppUsersManager, \r\n public appWebPagesManager: AppWebPagesManager, \r\n public appPollsManager: AppPollsManager, \r\n public apiManager: ApiManagerProxy, \r\n public appDraftsManager: AppDraftsManager, \r\n public serverTimeManager: ServerTimeManager, \r\n public storage: typeof stateStorage, \r\n public appNotificationsManager: AppNotificationsManager,\r\n public appEmojiManager: AppEmojiManager\r\n ) {\r\n super();\r\n\r\n this.container = document.createElement('div');\r\n this.container.classList.add('chat');\r\n\r\n this.backgroundEl = document.createElement('div');\r\n this.backgroundEl.classList.add('chat-background');\r\n\r\n // * constructor end\r\n\r\n this.log = logger('CHAT', LogTypes.Log | LogTypes.Warn | LogTypes.Debug | LogTypes.Error);\r\n //this.log.error('Chat construction');\r\n\r\n this.container.append(this.backgroundEl);\r\n this.appImManager.chatsContainer.append(this.container);\r\n }\r\n\r\n public setBackground(url: string): Promise<void> {\r\n const theme = rootScope.getTheme();\r\n\r\n let item: HTMLElement;\r\n if(theme.background.type === 'color' && document.documentElement.style.cursor === 'grabbing') {\r\n const _item = this.backgroundEl.lastElementChild as HTMLElement;\r\n if(_item && _item.dataset.type === theme.background.type) {\r\n item = _item;\r\n }\r\n }\r\n \r\n if(!item) {\r\n item = document.createElement('div');\r\n item.classList.add('chat-background-item');\r\n item.dataset.type = theme.background.type;\r\n }\r\n\r\n if(theme.background.type === 'color') {\r\n item.style.backgroundColor = theme.background.color;\r\n item.style.backgroundImage = 'none';\r\n }\r\n\r\n return new Promise<void>((resolve) => {\r\n const cb = () => {\r\n const prev = this.backgroundEl.lastElementChild as HTMLElement;\r\n\r\n if(prev === item) {\r\n resolve();\r\n return;\r\n }\r\n\r\n this.backgroundEl.append(item);\r\n\r\n // * одного недостаточно, при обновлении страницы все равно фон появляется неплавно\r\n // ! с requestAnimationFrame лучше, но все равно иногда моргает, так что использую два фаста.\r\n fastRaf(() => {\r\n fastRaf(() => {\r\n SetTransition(item, 'is-visible', true, 200, prev ? () => {\r\n prev.remove();\r\n } : null);\r\n });\r\n });\r\n\r\n resolve();\r\n };\r\n\r\n if(url) {\r\n renderImageFromUrl(item, url, cb);\r\n } else {\r\n cb();\r\n }\r\n });\r\n }\r\n\r\n public setType(type: ChatType) {\r\n this.type = type;\r\n\r\n if(this.type === 'scheduled') {\r\n this.getMessagesStorage = () => this.appMessagesManager.getScheduledMessagesStorage(this.peerId);\r\n //this.getMessage = (mid) => this.appMessagesManager.getMessageFromStorage(this.appMessagesManager.getScheduledMessagesStorage(this.peerId), mid);\r\n }\r\n }\r\n\r\n public init(/* peerId: number */) {\r\n // this.initPeerId = peerId;\r\n\r\n this.topbar = new ChatTopbar(this, appSidebarRight, this.appMessagesManager, this.appPeersManager, this.appChatsManager, this.appNotificationsManager);\r\n this.bubbles = new ChatBubbles(this, this.appMessagesManager, this.appStickersManager, this.appUsersManager, this.appInlineBotsManager, this.appPhotosManager, this.appPeersManager, this.appProfileManager);\r\n this.input = new ChatInput(this, this.appMessagesManager, this.appDocsManager, this.appChatsManager, this.appPeersManager, this.appWebPagesManager, this.appImManager, this.appDraftsManager, this.serverTimeManager, this.appNotificationsManager, this.appEmojiManager);\r\n this.selection = new ChatSelection(this, this.bubbles, this.input, this.appMessagesManager);\r\n this.contextMenu = new ChatContextMenu(this.bubbles.bubblesContainer, this, this.appMessagesManager, this.appPeersManager, this.appPollsManager, this.appDocsManager);\r\n\r\n if(this.type === 'chat') {\r\n this.topbar.constructUtils();\r\n this.topbar.constructPeerHelpers();\r\n } else if(this.type === 'pinned') {\r\n this.topbar.constructPinnedHelpers();\r\n } else if(this.type === 'discussion') {\r\n this.topbar.constructUtils();\r\n this.topbar.constructDiscussionHelpers();\r\n }\r\n\r\n this.topbar.construct();\r\n this.input.construct();\r\n\r\n if(this.type === 'chat') { // * гений в деле, разный порядок из-за разной последовательности действий\r\n this.bubbles.constructPeerHelpers();\r\n this.input.constructPeerHelpers();\r\n } else if(this.type === 'pinned') {\r\n this.bubbles.constructPinnedHelpers();\r\n this.input.constructPinnedHelpers();\r\n } else if(this.type === 'scheduled') {\r\n this.bubbles.constructScheduledHelpers();\r\n this.input.constructPeerHelpers();\r\n } else if(this.type === 'discussion') {\r\n this.bubbles.constructPeerHelpers();\r\n this.input.constructPeerHelpers();\r\n }\r\n\r\n this.container.classList.add('type-' + this.type);\r\n this.container.append(this.topbar.container, this.bubbles.bubblesContainer, this.input.chatInput);\r\n\r\n this.bubbles.listenerSetter.add(rootScope)('dialog_migrate', ({migrateFrom, migrateTo}) => {\r\n if(this.peerId === migrateFrom) {\r\n this.setPeer(migrateTo);\r\n }\r\n });\r\n\r\n this.bubbles.listenerSetter.add(rootScope)('dialog_drop', (e) => {\r\n if(e.peerId === this.peerId) {\r\n this.appImManager.setPeer(0);\r\n }\r\n });\r\n }\r\n\r\n public beforeDestroy() {\r\n this.bubbles.cleanup();\r\n }\r\n\r\n public destroy() {\r\n //const perf = performance.now();\r\n\r\n this.topbar.destroy();\r\n this.bubbles.destroy();\r\n this.input.destroy();\r\n\r\n delete this.topbar;\r\n delete this.bubbles;\r\n delete this.input;\r\n delete this.selection;\r\n delete this.contextMenu;\r\n\r\n this.container.remove();\r\n\r\n //this.log.error('Chat destroy time:', performance.now() - perf);\r\n }\r\n\r\n public cleanup(helperToo = true) {\r\n this.input.cleanup(helperToo);\r\n this.selection.cleanup();\r\n }\r\n\r\n public setPeer(peerId: number, lastMsgId?: number) {\r\n if(!peerId) {\r\n this.inited = false;\r\n } else if(!this.inited) {\r\n if(this.init) {\r\n this.init(/* peerId */);\r\n this.init = null;\r\n }\r\n\r\n this.inited = true;\r\n }\r\n\r\n const samePeer = this.peerId === peerId;\r\n if(!samePeer) {\r\n rootScope.dispatchEvent('peer_changing', this);\r\n this.peerId = peerId;\r\n } else if(this.setPeerPromise) {\r\n return;\r\n }\r\n\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 appSidebarRight.toggleSidebar(false);\r\n this.cleanup(true);\r\n this.topbar.setPeer(peerId);\r\n this.bubbles.setPeer(peerId);\r\n rootScope.dispatchEvent('peer_changed', peerId);\r\n\r\n return;\r\n }\r\n\r\n // set new\r\n if(!samePeer) {\r\n const searchTab = appSidebarRight.getTab(AppPrivateSearchTab);\r\n if(searchTab) {\r\n searchTab.close();\r\n }\r\n\r\n appSidebarRight.sharedMediaTab.setPeer(peerId, this.threadId);\r\n this.input.clearHelper(); // костыль\r\n this.selection.cleanup(); // TODO: REFACTOR !!!!!!\r\n this.setAutoDownloadMedia();\r\n }\r\n\r\n this.peerChanged = samePeer;\r\n\r\n const result = this.bubbles.setPeer(peerId, lastMsgId);\r\n if(!result) {\r\n return;\r\n }\r\n\r\n const {promise} = result;\r\n\r\n //console.timeEnd('appImManager setPeer pre promise');\r\n \r\n const setPeerPromise = this.setPeerPromise = promise.finally(() => {\r\n if(this.setPeerPromise === setPeerPromise) {\r\n this.setPeerPromise = null;\r\n }\r\n });\r\n\r\n if(!samePeer) {\r\n appSidebarRight.sharedMediaTab.setLoadMutex(this.setPeerPromise);\r\n appSidebarRight.sharedMediaTab.loadSidebarMedia(true);\r\n }\r\n /* this.setPeerPromise.then(() => {\r\n appSidebarRight.sharedMediaTab.loadSidebarMedia(false);\r\n }); */\r\n\r\n return result;\r\n }\r\n\r\n public setAutoDownloadMedia() {\r\n let type: keyof State['settings']['autoDownload'];\r\n if(this.peerId < 0) {\r\n if(this.appPeersManager.isBroadcast(this.peerId)) {\r\n type = 'channels';\r\n } else {\r\n type = 'groups';\r\n }\r\n } else {\r\n if(this.appUsersManager.isContact(this.peerId)) {\r\n type = 'contacts';\r\n } else {\r\n type = 'private';\r\n }\r\n }\r\n\r\n this.noAutoDownloadMedia = !rootScope.settings.autoDownload[type];\r\n }\r\n\r\n public setMessageId(messageId?: number) {\r\n return this.setPeer(this.peerId, messageId);\r\n }\r\n\r\n public finishPeerChange(isTarget: boolean, isJump: boolean, lastMsgId: number) {\r\n if(this.peerChanged) return;\r\n\r\n let peerId = this.peerId;\r\n this.peerChanged = true;\r\n\r\n this.cleanup(false);\r\n\r\n this.topbar.setPeer(peerId);\r\n this.topbar.finishPeerChange(isTarget, isJump, lastMsgId);\r\n this.bubbles.finishPeerChange();\r\n this.input.finishPeerChange();\r\n\r\n appSidebarRight.sharedMediaTab.fillProfileElements();\r\n\r\n this.log.setPrefix('CHAT-' + peerId + '-' + this.type);\r\n\r\n rootScope.dispatchEvent('peer_changed', peerId);\r\n this.wasAlreadyUsed = true;\r\n }\r\n\r\n public getMessagesStorage() {\r\n return this.appMessagesManager.getMessagesStorage(this.peerId);\r\n }\r\n\r\n public getMessage(mid: number) {\r\n return this.appMessagesManager.getMessageFromStorage(this.getMessagesStorage(), mid);\r\n //return this.appMessagesManager.getMessageByPeer(this.peerId, mid);\r\n }\r\n\r\n public getMidsByMid(mid: number) {\r\n return this.appMessagesManager.getMidsByMessage(this.getMessage(mid));\r\n }\r\n\r\n public isAnyGroup() {\r\n return this.peerId === rootScope.myId || this.peerId === REPLIES_PEER_ID || this.appPeersManager.isAnyGroup(this.peerId);\r\n }\r\n\r\n public initSearch(query?: string) {\r\n if(!this.peerId) return;\r\n\r\n if(mediaSizes.isMobile) {\r\n new ChatSearch(this.topbar, this, query);\r\n } else {\r\n let tab = appSidebarRight.getTab(AppPrivateSearchTab);\r\n if(!tab) {\r\n tab = new AppPrivateSearchTab(appSidebarRight);\r\n }\r\n\r\n tab.open(this.peerId, this.threadId, this.bubbles.onDatePick, query);\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 { AppImManager } from \"../../lib/appManagers/appImManager\";\r\nimport RichTextProcessor from \"../../lib/richtextprocessor\";\r\nimport ButtonIcon from \"../buttonIcon\";\r\nimport { clamp } from \"../../helpers/number\";\r\nimport { isTouchSupported } from \"../../helpers/touchSupport\";\r\nimport { isApple, isMobile } from \"../../helpers/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(!isMobile) {\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(isTouchSupported) {\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(isTouchSupported && !isApple) {\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(isTouchSupported) {\r\n if(isApple) {\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","/*\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","/*\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 apiManager from '../mtproto/apiManager';\r\nimport animationIntersector from '../../components/animationIntersector';\r\nimport appSidebarLeft, { LEFT_COLUMN_ACTIVE_CLASSNAME } from \"../../components/sidebarLeft\";\r\nimport appSidebarRight, { RIGHT_COLUMN_ACTIVE_CLASSNAME } from '../../components/sidebarRight';\r\nimport mediaSizes, { ScreenSize } from '../../helpers/mediaSizes';\r\nimport { logger, LogTypes } from \"../logger\";\r\nimport apiManager from '../mtproto/mtprotoworker';\r\nimport rootScope from '../rootScope';\r\nimport apiUpdatesManager from './apiUpdatesManager';\r\nimport appUsersManager from \"./appUsersManager\";\r\nimport Chat, { ChatType } from '../../components/chat/chat';\r\nimport appChatsManager from './appChatsManager';\r\nimport appDocsManager from './appDocsManager';\r\nimport appInlineBotsManager from './appInlineBotsManager';\r\nimport appMessagesManager from './appMessagesManager';\r\nimport appPeersManager from './appPeersManager';\r\nimport appPhotosManager from './appPhotosManager';\r\nimport appProfileManager from './appProfileManager';\r\nimport appStickersManager from './appStickersManager';\r\nimport appWebPagesManager from './appWebPagesManager';\r\nimport PopupNewMedia from '../../components/popups/newMedia';\r\nimport MarkupTooltip from '../../components/chat/markupTooltip';\r\nimport { isTouchSupported } from '../../helpers/touchSupport';\r\nimport appPollsManager from './appPollsManager';\r\nimport SetTransition from '../../components/singleTransition';\r\nimport ChatDragAndDrop from '../../components/chat/dragAndDrop';\r\nimport { debounce, pause, doubleRaf } from '../../helpers/schedulers';\r\nimport lottieLoader from '../lottieLoader';\r\nimport useHeavyAnimationCheck, { dispatchHeavyAnimationEvent } from '../../hooks/useHeavyAnimationCheck';\r\nimport appDraftsManager from './appDraftsManager';\r\nimport serverTimeManager from '../mtproto/serverTimeManager';\r\nimport stateStorage from '../stateStorage';\r\nimport appDownloadManager from './appDownloadManager';\r\nimport { AppStateManager } from './appStateManager';\r\nimport { MOUNT_CLASS_TO } from '../../config/debug';\r\nimport appNavigationController from '../../components/appNavigationController';\r\nimport appNotificationsManager from './appNotificationsManager';\r\nimport AppPrivateSearchTab from '../../components/sidebarRight/tabs/search';\r\nimport { i18n, LangPackKey } from '../langPack';\r\nimport { ChatInvite, SendMessageAction } from '../../layer';\r\nimport { hslaStringToHex } from '../../helpers/color';\r\nimport { copy, getObjectKeysAndSort } from '../../helpers/object';\r\nimport { getFilesFromEvent } from '../../helpers/files';\r\nimport PeerTitle from '../../components/peerTitle';\r\nimport PopupPeer from '../../components/popups/peer';\r\nimport { SliceEnd } from '../../helpers/slicedArray';\r\nimport blurActiveElement from '../../helpers/dom/blurActiveElement';\r\nimport { cancelEvent } from '../../helpers/dom/cancelEvent';\r\nimport disableTransition from '../../helpers/dom/disableTransition';\r\nimport placeCaretAtEnd from '../../helpers/dom/placeCaretAtEnd';\r\nimport replaceContent from '../../helpers/dom/replaceContent';\r\nimport whichChild from '../../helpers/dom/whichChild';\r\nimport appEmojiManager from './appEmojiManager';\r\nimport PopupElement from '../../components/popups';\r\nimport singleInstance from '../mtproto/singleInstance';\r\nimport PopupStickers from '../../components/popups/stickers';\r\nimport PopupJoinChatInvite from '../../components/popups/joinChatInvite';\r\nimport { toast } from '../../components/toast';\r\n\r\n//console.log('appImManager included33!');\r\n\r\nappSidebarLeft; // just to include\r\n\r\nexport const CHAT_ANIMATION_GROUP = 'chat';\r\nconst FOCUS_EVENT_NAME = isTouchSupported ? 'touchstart' : 'mousemove';\r\n\r\nexport type ChatSavedPosition = {\r\n mids: number[], \r\n top: number\r\n};\r\n\r\nexport class AppImManager {\r\n public columnEl = document.getElementById('column-center') as HTMLDivElement;\r\n public chatsContainer: HTMLElement;\r\n\r\n public offline = false;\r\n public updateStatusInterval = 0;\r\n\r\n public log: ReturnType<typeof logger>;\r\n\r\n public setPeerPromise: Promise<void> = null;\r\n\r\n public tabId = -1;\r\n \r\n public chats: Chat[] = [];\r\n private prevTab: HTMLElement;\r\n private chatsSelectTabDebounced: () => void;\r\n \r\n public markupTooltip: MarkupTooltip;\r\n private themeColorElem: Element;\r\n private backgroundPromises: {[slug: string]: Promise<string>} = {};\r\n\r\n get myId() {\r\n return rootScope.myId;\r\n }\r\n\r\n get chat(): Chat {\r\n return this.chats[this.chats.length - 1];\r\n }\r\n\r\n constructor() {\r\n apiUpdatesManager.attach();\r\n appNotificationsManager.start();\r\n\r\n this.log = logger('IM', LogTypes.Log | LogTypes.Warn | LogTypes.Debug | LogTypes.Error);\r\n\r\n this.selectTab(0);\r\n \r\n window.addEventListener('blur', () => {\r\n animationIntersector.checkAnimations(true);\r\n \r\n this.offline = rootScope.idle.isIDLE = true;\r\n this.updateStatus();\r\n clearInterval(this.updateStatusInterval);\r\n rootScope.dispatchEvent('idle', rootScope.idle.isIDLE);\r\n \r\n window.addEventListener('focus', () => {\r\n this.offline = rootScope.idle.isIDLE = false;\r\n this.updateStatus();\r\n this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);\r\n \r\n // в обратном порядке\r\n animationIntersector.checkAnimations(false);\r\n\r\n rootScope.dispatchEvent('idle', rootScope.idle.isIDLE);\r\n }, {once: true});\r\n });\r\n\r\n // * Prevent setting online after reloading page\r\n window.addEventListener(FOCUS_EVENT_NAME, () => {\r\n this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);\r\n this.updateStatus();\r\n\r\n this.offline = rootScope.idle.isIDLE = false;\r\n rootScope.dispatchEvent('idle', rootScope.idle.isIDLE);\r\n }, {once: true, passive: true});\r\n\r\n this.chatsContainer = document.createElement('div');\r\n this.chatsContainer.classList.add('chats-container', 'tabs-container');\r\n this.chatsContainer.dataset.animation = 'navigation';\r\n\r\n this.columnEl.append(this.chatsContainer);\r\n \r\n this.createNewChat();\r\n this.chatsSelectTab(this.chat.container);\r\n\r\n appNavigationController.onHashChange = this.onHashChange;\r\n //window.addEventListener('hashchange', this.onHashChange);\r\n\r\n this.setSettings();\r\n rootScope.addEventListener('settings_updated', this.setSettings);\r\n\r\n useHeavyAnimationCheck(() => {\r\n animationIntersector.setOnlyOnePlayableGroup('lock');\r\n animationIntersector.checkAnimations(true);\r\n }, () => {\r\n animationIntersector.setOnlyOnePlayableGroup('');\r\n animationIntersector.checkAnimations(false);\r\n });\r\n\r\n this.applyCurrentTheme();\r\n\r\n // * fix simultaneous opened both sidebars, can happen when floating sidebar is opened with left sidebar\r\n mediaSizes.addEventListener('changeScreen', (from, to) => {\r\n if(document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME) \r\n && document.body.classList.contains(RIGHT_COLUMN_ACTIVE_CLASSNAME)) {\r\n appSidebarRight.toggleSidebar(false);\r\n }\r\n });\r\n\r\n rootScope.addEventListener('history_focus', (e) => {\r\n let {peerId, mid} = e;\r\n if(mid) {\r\n mid = appMessagesManager.generateMessageId(mid); // because mid can come from notification, i.e. server message id\r\n }\r\n \r\n this.setInnerPeer(peerId, mid);\r\n });\r\n\r\n rootScope.addEventListener('peer_changing', (chat) => {\r\n this.saveChatPosition(chat);\r\n });\r\n\r\n rootScope.addEventListener('theme_change', () => {\r\n this.applyCurrentTheme();\r\n });\r\n\r\n rootScope.addEventListener('instance_deactivated', () => {\r\n const popup = new PopupElement('popup-instance-deactivated', undefined, {overlayClosable: true});\r\n const c = document.createElement('div');\r\n c.classList.add('instance-deactivated-container');\r\n (popup as any).container.replaceWith(c);\r\n\r\n const header = document.createElement('div');\r\n header.classList.add('header');\r\n header.append(i18n('Deactivated.Title'));\r\n\r\n const subtitle = document.createElement('div');\r\n subtitle.classList.add('subtitle');\r\n subtitle.append(i18n('Deactivated.Subtitle'));\r\n\r\n c.append(header, subtitle);\r\n\r\n document.body.classList.add('deactivated');\r\n\r\n (popup as any).onClose = () => {\r\n document.body.classList.add('deactivated-backwards');\r\n\r\n singleInstance.activateInstance();\r\n\r\n setTimeout(() => {\r\n document.body.classList.remove('deactivated', 'deactivated-backwards');\r\n }, 333);\r\n };\r\n\r\n popup.show();\r\n });\r\n\r\n stateStorage.get('chatPositions').then((c) => {\r\n stateStorage.setToCache('chatPositions', c || {});\r\n });\r\n\r\n this.addAnchorListener<void>({\r\n name: 'showMaskedAlert', \r\n callback: (params, element) => {\r\n const href = element.href;\r\n\r\n const a = element.cloneNode(true) as HTMLAnchorElement;\r\n a.className = 'anchor-url';\r\n a.innerText = href;\r\n a.removeAttribute('onclick');\r\n\r\n new PopupPeer('popup-masked-url', {\r\n titleLangKey: 'OpenUrlTitle',\r\n descriptionLangKey: 'OpenUrlAlert2',\r\n descriptionLangArgs: [a],\r\n buttons: [{\r\n langKey: 'Open',\r\n callback: () => {\r\n a.click();\r\n },\r\n }]\r\n }).show();\r\n }, \r\n noParams: true\r\n });\r\n\r\n this.addAnchorListener<{command: string, bot: string}>({\r\n name: 'execBotCommand', \r\n callback: (params) => {\r\n const {command, bot} = params;\r\n\r\n /* const promise = bot ? this.openUsername(bot).then(() => this.chat.peerId) : Promise.resolve(this.chat.peerId);\r\n promise.then(peerId => {\r\n appMessagesManager.sendText(peerId, '/' + command);\r\n }); */\r\n\r\n appMessagesManager.sendText(this.chat.peerId, '/' + command + (bot ? '@' + bot : ''));\r\n\r\n //console.log(command, bot);\r\n }\r\n });\r\n\r\n this.addAnchorListener<{hashtag: string}>({\r\n name: 'searchByHashtag', \r\n callback: (params) => {\r\n if(!params) {\r\n return;\r\n }\r\n\r\n const {hashtag} = params;\r\n this.chat.initSearch('#' + hashtag + ' ');\r\n }\r\n });\r\n\r\n this.addAnchorListener<['addstickers', string]>({\r\n name: 'addstickers', \r\n callback: (params) => {\r\n new PopupStickers({id: params[1]}).show();\r\n }, \r\n parsePathname: true\r\n });\r\n\r\n this.addAnchorListener<['joinchat', string]>({\r\n name: 'joinchat', \r\n callback: (params) => {\r\n apiManager.invokeApi('messages.checkChatInvite', {\r\n hash: params[1]\r\n }).then(chatInvite => {\r\n if((chatInvite as ChatInvite.chatInvitePeek).chat) {\r\n appChatsManager.saveApiChat((chatInvite as ChatInvite.chatInvitePeek).chat, true);\r\n }\r\n\r\n // console.log(chatInvite);\r\n\r\n if(chatInvite._ === 'chatInviteAlready' ||\r\n chatInvite._ === 'chatInvitePeek'/* && chatInvite.expires > tsNow(true) */) {\r\n this.setInnerPeer(-chatInvite.chat.id);\r\n return;\r\n }\r\n\r\n new PopupJoinChatInvite(params[1], chatInvite).show();\r\n }, (err) => {\r\n if(err.type === 'INVITE_HASH_EXPIRED') {\r\n toast(i18n('InviteExpired'));\r\n }\r\n });\r\n },\r\n parsePathname: true\r\n });\r\n }\r\n\r\n private addAnchorListener<Params extends any>(options: {\r\n name: 'showMaskedAlert' | 'execBotCommand' | 'searchByHashtag' | 'addstickers' | 'joinchat', \r\n callback: (params: Params, element: HTMLAnchorElement) => boolean | void, \r\n noParams?: boolean, \r\n parsePathname?: boolean\r\n }) {\r\n (window as any)[options.name] = (element: HTMLAnchorElement/* , e: Event */) => {\r\n cancelEvent(null);\r\n\r\n const href = element.href;\r\n let params: any;\r\n if(!options.noParams) {\r\n params = options.parsePathname ? new URL(element.href).pathname.split('/').slice(1) : this.parseUriParams(href);\r\n }\r\n\r\n const res = options.callback(params, element);\r\n return res === undefined ? res : false;\r\n };\r\n }\r\n\r\n private parseUriParams(uri: string, splitted = uri.split('?')) {\r\n if(!splitted[1]) {\r\n return;\r\n }\r\n\r\n const params: any = {};\r\n splitted[1].split('&').forEach(item => {\r\n params[item.split('=')[0]] = decodeURIComponent(item.split('=')[1]);\r\n });\r\n\r\n return params;\r\n }\r\n\r\n private onHashChange = () => {\r\n const hash = location.hash;\r\n const splitted = hash.split('?');\r\n\r\n const params = this.parseUriParams(hash, splitted);\r\n\r\n this.log('hashchange', hash, splitted[0], params);\r\n\r\n switch(splitted[0]) {\r\n case '#/im': {\r\n const p = params.p;\r\n let postId = params.post !== undefined ? appMessagesManager.generateMessageId(+params.post) : undefined;\r\n\r\n switch(p[0]) {\r\n case '@': {\r\n this.openUsername(p, postId);\r\n break;\r\n }\r\n\r\n default: { // peerId\r\n this.setInnerPeer(postId ? -+p : +p, postId);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n\r\n //appNavigationController.replaceState();\r\n //location.hash = '';\r\n };\r\n\r\n public openUsername(username: string, msgId?: number) {\r\n return appUsersManager.resolveUsername(username).then(peer => {\r\n const isUser = peer._ === 'user';\r\n const peerId = isUser ? peer.id : -peer.id;\r\n\r\n return this.setInnerPeer(peerId, msgId);\r\n }, (err) => {\r\n if(err.type === 'USERNAME_NOT_OCCUPIED') {\r\n toast(i18n('NoUsernameFound'));\r\n }\r\n });\r\n }\r\n\r\n public setCurrentBackground(broadcastEvent = false) {\r\n const theme = rootScope.getTheme();\r\n\r\n if(theme.background.type === 'image' || (theme.background.type === 'default' && theme.background.slug)) {\r\n const defaultTheme = AppStateManager.STATE_INIT.settings.themes.find(t => t.name === theme.name);\r\n const isDefaultBackground = theme.background.blur === defaultTheme.background.blur && \r\n theme.background.slug === defaultTheme.background.slug;\r\n\r\n if(!isDefaultBackground) {\r\n return this.getBackground(theme.background.slug).then((url) => {\r\n return this.setBackground(url, broadcastEvent);\r\n }, () => { // * if NO_ENTRY_FOUND\r\n theme.background = copy(defaultTheme.background); // * reset background\r\n return this.setBackground('', true);\r\n });\r\n }\r\n }\r\n \r\n return this.setBackground('', broadcastEvent);\r\n }\r\n\r\n private getBackground(slug: string) {\r\n if(this.backgroundPromises[slug]) return this.backgroundPromises[slug];\r\n return this.backgroundPromises[slug] = appDownloadManager.cacheStorage.getFile('backgrounds/' + slug).then(blob => {\r\n return URL.createObjectURL(blob);\r\n });\r\n }\r\n\r\n public setBackground(url: string, broadcastEvent = true): Promise<void> {\r\n const promises = this.chats.map(chat => chat.setBackground(url));\r\n return promises[promises.length - 1].then(() => {\r\n if(broadcastEvent) {\r\n rootScope.dispatchEvent('background_change');\r\n }\r\n });\r\n }\r\n\r\n public saveChatPosition(chat: Chat) {\r\n if(!(['chat', 'discussion'] as ChatType[]).includes(chat.type) || !chat.peerId) {\r\n return;\r\n }\r\n\r\n //const bubble = chat.bubbles.getBubbleByPoint('top');\r\n //if(bubble) {\r\n //const top = bubble.getBoundingClientRect().top;\r\n const chatBubbles = chat.bubbles;\r\n const top = chatBubbles.scrollable.scrollTop;\r\n\r\n const key = chat.peerId + (chat.threadId ? '_' + chat.threadId : '');\r\n\r\n const chatPositions = stateStorage.getFromCache('chatPositions');\r\n if(!(chatBubbles.scrollable.getDistanceToEnd() <= 16 && chatBubbles.scrollable.loadedAll.bottom) && Object.keys(chatBubbles.bubbles).length) {\r\n const position = {\r\n mids: getObjectKeysAndSort(chatBubbles.bubbles, 'desc'),\r\n top\r\n };\r\n\r\n chatPositions[key] = position;\r\n\r\n this.log('saved chat position:', position);\r\n } else {\r\n delete chatPositions[key];\r\n\r\n this.log('deleted chat position');\r\n }\r\n\r\n stateStorage.set({chatPositions}, true);\r\n //}\r\n }\r\n\r\n public getChatSavedPosition(chat: Chat): ChatSavedPosition {\r\n if(!(['chat', 'discussion'] as ChatType[]).includes(chat.type) || !chat.peerId) {\r\n return;\r\n }\r\n \r\n const key = chat.peerId + (chat.threadId ? '_' + chat.threadId : '');\r\n const cache = stateStorage.getFromCache('chatPositions');\r\n return cache && cache[key];\r\n }\r\n\r\n public applyHighlightningColor() {\r\n let hsla: string;\r\n const theme = rootScope.getTheme();\r\n if(theme.background.highlightningColor) {\r\n hsla = theme.background.highlightningColor;\r\n document.documentElement.style.setProperty('--message-highlightning-color', hsla);\r\n } else {\r\n document.documentElement.style.removeProperty('--message-highlightning-color');\r\n }\r\n\r\n let themeColor = '#ffffff';\r\n if(hsla) {\r\n themeColor = hslaStringToHex(hsla);\r\n }\r\n\r\n if(this.themeColorElem === undefined) {\r\n this.themeColorElem = document.head.querySelector('[name=\"theme-color\"]') as Element || null;\r\n }\r\n\r\n if(this.themeColorElem) {\r\n this.themeColorElem.setAttribute('content', themeColor);\r\n }\r\n }\r\n\r\n public applyCurrentTheme(slug?: string, backgroundUrl?: string, broadcastEvent?: boolean) {\r\n this.applyHighlightningColor();\r\n\r\n rootScope.setTheme();\r\n\r\n if(backgroundUrl) {\r\n this.backgroundPromises[slug] = Promise.resolve(backgroundUrl);\r\n }\r\n \r\n return this.setCurrentBackground(broadcastEvent === undefined ? !!slug : broadcastEvent);\r\n }\r\n\r\n private setSettings = () => {\r\n document.documentElement.style.setProperty('--messages-text-size', rootScope.settings.messagesTextSize + 'px');\r\n \r\n document.body.classList.toggle('animation-level-0', !rootScope.settings.animationsEnabled);\r\n document.body.classList.toggle('animation-level-1', false);\r\n document.body.classList.toggle('animation-level-2', rootScope.settings.animationsEnabled);\r\n\r\n this.chatsSelectTabDebounced = debounce(() => {\r\n const topbar = this.chat.topbar;\r\n if(topbar.pinnedMessage) { // * буду молиться богам, чтобы это ничего не сломало, но это исправляет получение пиннеда после анимации\r\n topbar.pinnedMessage.setCorrectIndex(0);\r\n }\r\n\r\n apiManager.setQueueId(this.chat.bubbles.lazyLoadQueue.queueId);\r\n }, rootScope.settings.animationsEnabled ? 250 : 0, false, true);\r\n\r\n lottieLoader.setLoop(rootScope.settings.stickers.loop);\r\n animationIntersector.checkAnimations(false);\r\n \r\n for(const chat of this.chats) {\r\n chat.setAutoDownloadMedia();\r\n }\r\n };\r\n\r\n // * не могу использовать тут TransitionSlider, так как мне нужен отрисованный блок рядом \r\n // * (или под текущим чатом) чтобы правильно отрендерить чат (напр. scrollTop)\r\n private chatsSelectTab(tab: HTMLElement, animate?: boolean) {\r\n if(this.prevTab === tab) {\r\n return;\r\n }\r\n\r\n if(animate === false && this.prevTab) { // * will be used for Safari iOS history swipe\r\n disableTransition([tab, this.prevTab].filter(Boolean));\r\n }\r\n\r\n if(this.prevTab) {\r\n this.prevTab.classList.remove('active');\r\n this.chatsSelectTabDebounced();\r\n\r\n // ! нужно переделать на animation, так как при лаге анимация будет длиться не 250мс\r\n if(rootScope.settings.animationsEnabled && animate !== false) { \r\n dispatchHeavyAnimationEvent(pause(250 + 150), 250 + 150);\r\n }\r\n\r\n const prevIdx = whichChild(this.prevTab);\r\n const idx = whichChild(tab);\r\n if(idx > prevIdx) {\r\n appNavigationController.pushItem({\r\n type: 'chat', \r\n onPop: (canAnimate) => {\r\n this.setPeer(0, undefined, canAnimate);\r\n blurActiveElement();\r\n }\r\n });\r\n }\r\n }\r\n\r\n tab.classList.add('active');\r\n this.prevTab = tab;\r\n }\r\n\r\n private init() {\r\n document.addEventListener('paste', this.onDocumentPaste, true);\r\n \r\n const IGNORE_KEYS = new Set(['PageUp', 'PageDown', 'Meta', 'Control']);\r\n const onKeyDown = (e: KeyboardEvent) => {\r\n if(rootScope.overlayIsActive || IGNORE_KEYS.has(e.key)) return;\r\n \r\n const target = e.target as HTMLElement;\r\n \r\n //if(target.tagName === 'INPUT') return;\r\n \r\n //this.log('onkeydown', e, document.activeElement);\r\n\r\n const chat = this.chat;\r\n\r\n if(e.code === 'KeyC' && (e.ctrlKey || e.metaKey) && target.tagName !== 'INPUT') {\r\n return;\r\n } else if(e.code === 'ArrowUp') {\r\n if(!chat.input.editMsgId && chat.input.isInputEmpty()) {\r\n const historyStorage = appMessagesManager.getHistoryStorage(chat.peerId, chat.threadId);\r\n const slice = historyStorage.history.slice;\r\n if(slice.isEnd(SliceEnd.Bottom) && slice.length) {\r\n let goodMid: number;\r\n for(const mid of slice) {\r\n const message = chat.getMessage(mid);\r\n const good = this.myId === chat.peerId ? message.fromId === this.myId : message.pFlags.out;\r\n\r\n if(good) {\r\n if(appMessagesManager.canEditMessage(chat.getMessage(mid), 'text')) {\r\n goodMid = mid;\r\n break;\r\n }\r\n\r\n // * this check will allow editing only last message\r\n //break;\r\n }\r\n }\r\n \r\n if(goodMid) {\r\n chat.input.initMessageEditing(goodMid);\r\n cancelEvent(e); // * prevent from scrolling\r\n }\r\n }\r\n } else {\r\n return;\r\n }\r\n } else if(e.code === 'ArrowDown') {\r\n return;\r\n }\r\n \r\n if(chat.input.messageInput && \r\n e.target !== chat.input.messageInput && \r\n target.tagName !== 'INPUT' && \r\n !target.hasAttribute('contenteditable') && \r\n !isTouchSupported && \r\n (!mediaSizes.isMobile || this.tabId === 1) && \r\n !this.chat.selection.isSelecting && \r\n !this.chat.input.recording) {\r\n chat.input.messageInput.focus();\r\n placeCaretAtEnd(chat.input.messageInput);\r\n }\r\n };\r\n \r\n document.body.addEventListener('keydown', onKeyDown);\r\n\r\n rootScope.addEventListener('history_multiappend', (e) => {\r\n const msgIdsByPeer = e;\r\n\r\n for(const peerId in msgIdsByPeer) {\r\n appSidebarRight.sharedMediaTab.renderNewMessages(+peerId, Array.from(msgIdsByPeer[peerId]));\r\n }\r\n });\r\n \r\n rootScope.addEventListener('history_delete', (e) => {\r\n const {peerId, msgs} = e;\r\n\r\n const mids = Object.keys(msgs).map(s => +s);\r\n appSidebarRight.sharedMediaTab.deleteDeletedMessages(peerId, mids);\r\n });\r\n\r\n // Calls when message successfully sent and we have an id\r\n rootScope.addEventListener('message_sent', (e) => {\r\n const {storage, tempId, mid} = e;\r\n const message = appMessagesManager.getMessageFromStorage(storage, mid);\r\n appSidebarRight.sharedMediaTab.renderNewMessages(message.peerId, [mid]);\r\n });\r\n\r\n if(!isTouchSupported) {\r\n this.attachDragAndDropListeners();\r\n }\r\n\r\n //if(!isTouchSupported) {\r\n this.markupTooltip = new MarkupTooltip(this);\r\n this.markupTooltip.handleSelection();\r\n //}\r\n }\r\n\r\n private attachDragAndDropListeners() {\r\n const drops: ChatDragAndDrop[] = [];\r\n let mounted = false;\r\n const toggle = async(e: DragEvent, mount: boolean) => {\r\n if(mount === mounted) return;\r\n\r\n const _types = e.dataTransfer.types;\r\n // @ts-ignore\r\n const isFiles = _types.contains ? _types.contains('Files') : _types.indexOf('Files') >= 0;\r\n\r\n if(!isFiles || !this.canDrag()) { // * skip dragging text case\r\n counter = 0;\r\n return;\r\n }\r\n\r\n if(mount && !drops.length) {\r\n const types: string[] = await getFilesFromEvent(e, true)\r\n const force = isFiles && !types.length; // * can't get file items not from 'drop' on Safari\r\n \r\n const foundMedia = types.filter(t => ['image', 'video'].includes(t.split('/')[0])).length;\r\n const foundDocuments = types.length - foundMedia;\r\n \r\n this.log('drag files', types);\r\n \r\n if(types.length || force) {\r\n drops.push(new ChatDragAndDrop(dropsContainer, {\r\n icon: 'dragfiles',\r\n header: 'Chat.DropTitle',\r\n subtitle: 'Chat.DropAsFilesDesc',\r\n onDrop: (e: DragEvent) => {\r\n toggle(e, false);\r\n appImManager.log('drop', e);\r\n appImManager.onDocumentPaste(e, 'document');\r\n }\r\n }));\r\n }\r\n \r\n if((foundMedia && !foundDocuments) || force) {\r\n drops.push(new ChatDragAndDrop(dropsContainer, {\r\n icon: 'dragmedia',\r\n header: 'Chat.DropTitle',\r\n subtitle: 'Chat.DropQuickDesc',\r\n onDrop: (e: DragEvent) => {\r\n toggle(e, false);\r\n appImManager.log('drop', e);\r\n appImManager.onDocumentPaste(e, 'media');\r\n }\r\n }));\r\n }\r\n \r\n this.chat.container.append(dropsContainer);\r\n }\r\n\r\n //if(!mount) return;\r\n\r\n SetTransition(dropsContainer, 'is-visible', mount, 200, () => {\r\n if(!mount) {\r\n drops.forEach(drop => {\r\n drop.destroy();\r\n });\r\n\r\n drops.length = 0;\r\n }\r\n });\r\n\r\n if(mount) {\r\n drops.forEach(drop => {\r\n drop.setPath();\r\n });\r\n } else {\r\n counter = 0;\r\n }\r\n\r\n document.body.classList.toggle('is-dragging', mount);\r\n mounted = mount;\r\n };\r\n\r\n /* document.body.addEventListener('dragover', (e) => {\r\n cancelEvent(e);\r\n }); */\r\n\r\n let counter = 0;\r\n document.body.addEventListener('dragenter', (e) => {\r\n counter++;\r\n });\r\n\r\n document.body.addEventListener('dragover', (e) => {\r\n //this.log('dragover', e/* , e.dataTransfer.types[0] */);\r\n toggle(e, true);\r\n cancelEvent(e);\r\n });\r\n\r\n document.body.addEventListener('dragleave', (e) => {\r\n //this.log('dragleave', e, counter);\r\n //if((e.pageX <= 0 || e.pageX >= appPhotosManager.windowW) || (e.pageY <= 0 || e.pageY >= appPhotosManager.windowH)) {\r\n counter--;\r\n if(counter === 0) { \r\n //if(!findUpClassName(e.target, 'drops-container')) {\r\n toggle(e, false);\r\n }\r\n });\r\n\r\n const dropsContainer = document.createElement('div');\r\n dropsContainer.classList.add('drops-container');\r\n }\r\n\r\n private canDrag() {\r\n const peerId = this.chat?.peerId;\r\n return !(!peerId || rootScope.overlayIsActive || (peerId < 0 && !appChatsManager.hasRights(peerId, 'send_media')));\r\n }\r\n\r\n private onDocumentPaste = (e: ClipboardEvent | DragEvent, attachType?: 'media' | 'document') => {\r\n if(!this.canDrag()) return;\r\n\r\n //console.log('document paste');\r\n //console.log('item', event.clipboardData.getData());\r\n\r\n if(e instanceof DragEvent) {\r\n const _types = e.dataTransfer.types;\r\n // @ts-ignore\r\n const isFiles = _types.contains ? _types.contains('Files') : _types.indexOf('Files') >= 0;\r\n if(isFiles) {\r\n cancelEvent(e);\r\n }\r\n }\r\n \r\n getFilesFromEvent(e).then((files: File[]) => {\r\n if(files.length) {\r\n if(attachType === 'media' && files.find(file => !['image', 'video'].includes(file.type.split('/')[0]))) {\r\n attachType = 'document';\r\n }\r\n \r\n const chatInput = this.chat.input;\r\n chatInput.willAttachType = attachType || (files[0].type.indexOf('image/') === 0 ? 'media' : \"document\");\r\n new PopupNewMedia(this.chat, files, chatInput.willAttachType);\r\n }\r\n });\r\n };\r\n\r\n public selectTab(id: number, animate?: boolean) {\r\n if(animate === false) { // * will be used for Safari iOS history swipe\r\n disableTransition([appSidebarLeft.sidebarEl, this.columnEl, appSidebarRight.sidebarEl]);\r\n }\r\n\r\n document.body.classList.toggle(LEFT_COLUMN_ACTIVE_CLASSNAME, id === 0);\r\n\r\n const prevTabId = this.tabId;\r\n\r\n this.log('selectTab', id, prevTabId);\r\n\r\n let animationPromise: Promise<any> = doubleRaf();\r\n if(prevTabId !== -1 && prevTabId !== id && rootScope.settings.animationsEnabled && animate !== false) {\r\n const transitionTime = (mediaSizes.isMobile ? 250 : 200) + 100; // * cause transition time could be > 250ms\r\n animationPromise = pause(transitionTime);\r\n dispatchHeavyAnimationEvent(animationPromise, transitionTime);\r\n\r\n this.columnEl.classList.add('disable-hover');\r\n animationPromise.finally(() => {\r\n this.columnEl.classList.remove('disable-hover');\r\n });\r\n }\r\n\r\n this.tabId = id;\r\n blurActiveElement();\r\n if(mediaSizes.isMobile && prevTabId === 2 && id < 2) {\r\n document.body.classList.remove(RIGHT_COLUMN_ACTIVE_CLASSNAME);\r\n }\r\n\r\n if(prevTabId !== -1 && id > prevTabId) {\r\n if(id < 2 || !appNavigationController.findItemByType('im')) {\r\n appNavigationController.pushItem({\r\n type: 'im', \r\n onPop: (canAnimate) => {\r\n //this.selectTab(prevTabId, !isSafari);\r\n this.setPeer(0, undefined, canAnimate);\r\n }\r\n });\r\n }\r\n }\r\n\r\n rootScope.dispatchEvent('im_tab_change', id);\r\n\r\n //this._selectTab(id, mediaSizes.isMobile);\r\n //document.body.classList.toggle(RIGHT_COLUMN_ACTIVE_CLASSNAME, id === 2);\r\n\r\n return animationPromise;\r\n }\r\n \r\n public updateStatus() {\r\n if(!this.myId) return Promise.resolve();\r\n \r\n appUsersManager.setUserStatus(this.myId, this.offline);\r\n return apiManager.invokeApiSingle('account.updateStatus', {offline: this.offline});\r\n }\r\n\r\n private createNewChat() {\r\n const chat = new Chat(this, \r\n appChatsManager, \r\n appDocsManager, \r\n appInlineBotsManager, \r\n appMessagesManager, \r\n appPeersManager, \r\n appPhotosManager, \r\n appProfileManager, \r\n appStickersManager, \r\n appUsersManager, \r\n appWebPagesManager, \r\n appPollsManager, \r\n apiManager, \r\n appDraftsManager, \r\n serverTimeManager, \r\n stateStorage, \r\n appNotificationsManager, \r\n appEmojiManager\r\n );\r\n\r\n if(this.chats.length) {\r\n chat.backgroundEl.append(this.chat.backgroundEl.lastElementChild.cloneNode(true));\r\n }\r\n\r\n this.chats.push(chat);\r\n }\r\n\r\n private spliceChats(fromIndex: number, justReturn = true, animate?: boolean, spliced?: Chat[]) {\r\n if(fromIndex >= this.chats.length) return;\r\n\r\n if(this.chats.length > 1 && justReturn) {\r\n rootScope.dispatchEvent('peer_changing', this.chat);\r\n }\r\n\r\n if(!spliced) {\r\n spliced = this.chats.splice(fromIndex, this.chats.length - fromIndex);\r\n }\r\n\r\n // * -1 because one item is being sliced when closing the chat by calling .removeByType\r\n for(let i = 0; i < spliced.length - 1; ++i) {\r\n appNavigationController.removeByType('chat', true);\r\n }\r\n\r\n // * fix middle chat z-index on animation\r\n if(spliced.length > 1) {\r\n spliced.slice(0, -1).forEach(chat => {\r\n chat.container.remove();\r\n });\r\n }\r\n\r\n this.chatsSelectTab(this.chat.container, animate);\r\n\r\n if(justReturn) {\r\n rootScope.dispatchEvent('peer_changed', this.chat.peerId);\r\n\r\n const searchTab = appSidebarRight.getTab(AppPrivateSearchTab);\r\n if(searchTab) {\r\n searchTab.close();\r\n }\r\n \r\n const isSet = appSidebarRight.sharedMediaTab.setPeer(this.chat.peerId, this.chat.threadId);\r\n if(isSet) {\r\n appSidebarRight.sharedMediaTab.loadSidebarMedia(true);\r\n appSidebarRight.sharedMediaTab.fillProfileElements();\r\n }\r\n \r\n /* setTimeout(() => {\r\n appSidebarRight.sharedMediaTab.loadSidebarMedia(false);\r\n }); */\r\n }\r\n\r\n spliced.forEach(chat => {\r\n chat.beforeDestroy();\r\n });\r\n \r\n setTimeout(() => {\r\n //chat.setPeer(0);\r\n spliced.forEach(chat => {\r\n chat.destroy();\r\n });\r\n }, 250 + 100);\r\n }\r\n\r\n public setPeer(peerId: number, lastMsgId?: number, animate?: boolean): boolean {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n const chat = this.chat;\r\n const chatIndex = this.chats.indexOf(chat);\r\n\r\n if(!peerId) {\r\n if(chatIndex > 0) {\r\n this.spliceChats(chatIndex, undefined, animate);\r\n return;\r\n } else if(mediaSizes.activeScreen === ScreenSize.medium) { // * floating sidebar case\r\n this.selectTab(+!this.tabId, animate);\r\n return;\r\n }\r\n } else if(chatIndex > 0 && chat.peerId && chat.peerId !== peerId) {\r\n // const firstChat = this.chats[0];\r\n // if(firstChat.peerId !== chat.peerId) {\r\n /* // * slice idx > 0, set background and slice first, so new one will be the first\r\n const spliced = this.chats.splice(1, this.chats.length - 1);\r\n this.createNewChat();\r\n this.chats.splice(0, 1); */\r\n const spliced = this.chats.splice(1, this.chats.length - 1);\r\n if(this.chat.peerId === peerId) {\r\n this.spliceChats(0, true, true, spliced);\r\n return;\r\n } else {\r\n const ret = this.setPeer(peerId, lastMsgId);\r\n this.spliceChats(0, false, false, spliced);\r\n return ret;\r\n }\r\n // } else {\r\n // this.spliceChats(1, false, animate);\r\n // }\r\n\r\n //return ret;\r\n }\r\n\r\n // * don't reset peer if returning\r\n if(peerId === chat.peerId && mediaSizes.activeScreen <= ScreenSize.medium && document.body.classList.contains(LEFT_COLUMN_ACTIVE_CLASSNAME)) {\r\n this.selectTab(1, animate);\r\n return false;\r\n }\r\n\r\n if(peerId || mediaSizes.activeScreen !== ScreenSize.mobile) {\r\n const result = chat.setPeer(peerId, lastMsgId);\r\n\r\n // * wait for cached render\r\n const promise = result?.cached ? result.promise : Promise.resolve();\r\n if(peerId) {\r\n promise.then(() => {\r\n //window.requestAnimationFrame(() => {\r\n setTimeout(() => { // * setTimeout is better here\r\n setTimeout(() => {\r\n this.chatsSelectTab(this.chat.container);\r\n }, 0);\r\n this.selectTab(1, animate);\r\n }, 0);\r\n });\r\n }\r\n }\r\n\r\n if(!peerId) {\r\n this.selectTab(0, animate);\r\n return false;\r\n }\r\n }\r\n\r\n public setInnerPeer(peerId: number, lastMsgId?: number, type: ChatType = 'chat', threadId?: number) {\r\n // * prevent opening already opened peer\r\n const existingIndex = this.chats.findIndex(chat => chat.peerId === peerId && chat.type === type);\r\n if(existingIndex !== -1) {\r\n this.spliceChats(existingIndex + 1);\r\n return this.setPeer(peerId, lastMsgId);\r\n }\r\n\r\n const chat = this.chat;\r\n if(chat.inited) { // * use first not inited chat\r\n this.createNewChat();\r\n }\r\n\r\n if(type) {\r\n this.chat.setType(type);\r\n\r\n if(threadId) {\r\n this.chat.threadId = threadId;\r\n }\r\n }\r\n\r\n //this.chatsSelectTab(this.chat.container);\r\n\r\n return this.setPeer(peerId, lastMsgId);\r\n }\r\n\r\n public openScheduled(peerId: number) {\r\n this.setInnerPeer(peerId, undefined, 'scheduled');\r\n }\r\n\r\n private getTypingElement(action: SendMessageAction) {\r\n const el = document.createElement('span');\r\n el.classList.add('peer-typing');\r\n el.dataset.action = action._;\r\n switch(action._) {\r\n case 'sendMessageTypingAction': {\r\n //default: {\r\n const c = 'peer-typing-text';\r\n el.classList.add(c);\r\n for(let i = 0; i < 3; ++i) {\r\n const dot = document.createElement('span');\r\n dot.className = c + '-dot';\r\n el.append(dot);\r\n }\r\n break;\r\n }\r\n\r\n case 'sendMessageUploadAudioAction':\r\n case 'sendMessageUploadDocumentAction':\r\n case 'sendMessageUploadRoundAction':\r\n case 'sendMessageUploadVideoAction':\r\n case 'sendMessageUploadPhotoAction': {\r\n const c = 'peer-typing-upload';\r\n el.classList.add(c);\r\n /* const trail = document.createElement('span');\r\n trail.className = c + '-trail';\r\n el.append(trail); */\r\n break;\r\n }\r\n\r\n case 'sendMessageRecordAudioAction':\r\n case 'sendMessageRecordRoundAction':\r\n case 'sendMessageRecordVideoAction': {\r\n const c = 'peer-typing-record';\r\n el.classList.add(c);\r\n break;\r\n }\r\n }\r\n\r\n return el;\r\n }\r\n\r\n public getPeerTyping(peerId: number, container?: HTMLElement) {\r\n if(!appUsersManager.isBot(peerId)) {\r\n const typings = appProfileManager.getPeerTypings(peerId);\r\n if(!typings || !typings.length) {\r\n return;\r\n }\r\n\r\n const typing = typings[0];\r\n\r\n const langPackKeys: {\r\n [peerType in 'private' | 'chat' | 'multi']?: Partial<{[action in SendMessageAction['_']]: LangPackKey}>\r\n } = {\r\n private: {\r\n 'sendMessageTypingAction': 'Peer.Activity.User.TypingText',\r\n 'sendMessageUploadAudioAction': 'Peer.Activity.User.SendingFile',\r\n 'sendMessageUploadDocumentAction': 'Peer.Activity.User.SendingFile',\r\n 'sendMessageUploadPhotoAction': 'Peer.Activity.User.SendingPhoto',\r\n 'sendMessageUploadVideoAction': 'Peer.Activity.User.SendingVideo',\r\n 'sendMessageUploadRoundAction': 'Peer.Activity.User.SendingVideo',\r\n 'sendMessageRecordVideoAction': 'Peer.Activity.User.RecordingVideo',\r\n 'sendMessageRecordAudioAction': 'Peer.Activity.User.RecordingAudio',\r\n 'sendMessageRecordRoundAction': 'Peer.Activity.User.RecordingVideo',\r\n 'sendMessageGamePlayAction': 'Peer.Activity.User.PlayingGame'\r\n },\r\n chat: {\r\n 'sendMessageTypingAction': 'Peer.Activity.Chat.TypingText',\r\n 'sendMessageUploadAudioAction': 'Peer.Activity.Chat.SendingFile',\r\n 'sendMessageUploadDocumentAction': 'Peer.Activity.Chat.SendingFile',\r\n 'sendMessageUploadPhotoAction': 'Peer.Activity.Chat.SendingPhoto',\r\n 'sendMessageUploadVideoAction': 'Peer.Activity.Chat.SendingVideo',\r\n 'sendMessageUploadRoundAction': 'Peer.Activity.Chat.SendingVideo',\r\n 'sendMessageRecordVideoAction': 'Peer.Activity.Chat.RecordingVideo',\r\n 'sendMessageRecordAudioAction': 'Peer.Activity.Chat.RecordingAudio',\r\n 'sendMessageRecordRoundAction': 'Peer.Activity.Chat.RecordingVideo',\r\n 'sendMessageGamePlayAction': 'Peer.Activity.Chat.PlayingGame'\r\n },\r\n multi: {\r\n 'sendMessageTypingAction': 'Peer.Activity.Chat.Multi.TypingText1',\r\n 'sendMessageUploadAudioAction': 'Peer.Activity.Chat.Multi.SendingFile1',\r\n 'sendMessageUploadDocumentAction': 'Peer.Activity.Chat.Multi.SendingFile1',\r\n 'sendMessageUploadPhotoAction': 'Peer.Activity.Chat.Multi.SendingPhoto1',\r\n 'sendMessageUploadVideoAction': 'Peer.Activity.Chat.Multi.SendingVideo1',\r\n 'sendMessageUploadRoundAction': 'Peer.Activity.Chat.Multi.SendingVideo1',\r\n 'sendMessageRecordVideoAction': 'Peer.Activity.Chat.Multi.RecordingVideo1',\r\n 'sendMessageRecordAudioAction': 'Peer.Activity.Chat.Multi.RecordingAudio1',\r\n 'sendMessageRecordRoundAction': 'Peer.Activity.Chat.Multi.RecordingVideo1',\r\n 'sendMessageGamePlayAction': 'Peer.Activity.Chat.Multi.PlayingGame1'\r\n }\r\n };\r\n\r\n const mapa = peerId > 0 ? langPackKeys.private : (typings.length > 1 ? langPackKeys.multi : langPackKeys.chat);\r\n let action = typing.action;\r\n\r\n if(typings.length > 1) {\r\n const s: any = {};\r\n typings.forEach(typing => {\r\n const type = typing.action._;\r\n if(s[type] === undefined) s[type] = 0;\r\n ++s[type];\r\n });\r\n\r\n if(Object.keys(s).length > 1) {\r\n action = {\r\n _: 'sendMessageTypingAction'\r\n };\r\n }\r\n }\r\n\r\n const langPackKey = mapa[action._];\r\n if(!langPackKey) {\r\n return;\r\n }\r\n\r\n if(!container) {\r\n container = document.createElement('span');\r\n container.classList.add('online', 'peer-typing-container');\r\n }\r\n\r\n let typingElement = container.firstElementChild as HTMLElement;\r\n if(!typingElement) {\r\n typingElement = this.getTypingElement(action);\r\n container.prepend(typingElement);\r\n } else {\r\n if(typingElement.dataset.action !== action._) {\r\n typingElement.replaceWith(this.getTypingElement(action));\r\n }\r\n }\r\n\r\n let args: any[];\r\n if(peerId < 0) {\r\n args = [\r\n new PeerTitle({peerId: typing.userId, onlyFirstName: true}).element,\r\n typings.length - 1\r\n ];\r\n }\r\n const descriptionElement = i18n(langPackKey, args);\r\n descriptionElement.classList.add('peer-typing-description');\r\n\r\n if(container.childElementCount > 1) container.lastElementChild.replaceWith(descriptionElement);\r\n else container.append(descriptionElement);\r\n return container;\r\n }\r\n }\r\n\r\n public async getPeerStatus(peerId: number) {\r\n let subtitle: HTMLElement;\r\n if(!peerId) return '';\r\n\r\n if(peerId < 0) { // not human\r\n let span = this.getPeerTyping(peerId);\r\n if(span) {\r\n return span;\r\n }\r\n\r\n const chatInfo = await appProfileManager.getChatFull(-peerId) as any;\r\n this.chat.log('chatInfo res:', chatInfo);\r\n\r\n const participants_count = chatInfo.participants_count || (chatInfo.participants && chatInfo.participants.participants && chatInfo.participants.participants.length) || 1;\r\n //if(participants_count) {\r\n subtitle = appProfileManager.getChatMembersString(-peerId);\r\n\r\n if(participants_count < 2) return subtitle;\r\n /* const onlines = await appChatsManager.getOnlines(chat.id);\r\n if(onlines > 1) {\r\n subtitle += ', ' + numberThousandSplitter(onlines) + ' online';\r\n } */\r\n \r\n return subtitle;\r\n //}\r\n } else { // user\r\n const user = appUsersManager.getUser(peerId);\r\n \r\n if(rootScope.myId === peerId) {\r\n return '';\r\n } else if(user) {\r\n subtitle = appUsersManager.getUserStatusString(user.id);\r\n\r\n if(!appUsersManager.isBot(peerId)) {\r\n let span = this.getPeerTyping(peerId);\r\n if(!span && user.status?._ === 'userStatusOnline') {\r\n span = document.createElement('span');\r\n span.classList.add('online');\r\n span.append(subtitle);\r\n }\r\n\r\n if(span) {\r\n return span;\r\n }\r\n }\r\n \r\n return subtitle;\r\n }\r\n }\r\n }\r\n\r\n public setPeerStatus(peerId: number, element: HTMLElement, needClear: boolean, useWhitespace: boolean, middleware: () => boolean) {\r\n if(needClear) {\r\n element.innerHTML = useWhitespace ? '' : ''; // ! HERE U CAN FIND WHITESPACE\r\n }\r\n\r\n // * good good good\r\n const typingContainer = element.querySelector('.peer-typing-container') as HTMLElement;\r\n if(typingContainer && this.getPeerTyping(peerId, typingContainer)) {\r\n return;\r\n }\r\n\r\n this.getPeerStatus(peerId).then((subtitle) => {\r\n if(!middleware()) {\r\n return;\r\n }\r\n\r\n replaceContent(element, subtitle || (useWhitespace ? '' : ''));\r\n });\r\n }\r\n}\r\n\r\nconst appImManager = new AppImManager();\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appImManager = appImManager);\r\nexport default appImManager;\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 { deferredPromise } from \"../helpers/cancellablePromise\";\r\nimport mediaSizes from \"../helpers/mediaSizes\";\r\nimport { isTouchSupported } from \"../helpers/touchSupport\";\r\nimport { isMobileSafari, isSafari } from \"../helpers/userAgent\";\r\nimport appDocsManager, { MyDocument } from \"../lib/appManagers/appDocsManager\";\r\nimport appImManager from \"../lib/appManagers/appImManager\";\r\nimport appMessagesManager from \"../lib/appManagers/appMessagesManager\";\r\nimport appPhotosManager from \"../lib/appManagers/appPhotosManager\";\r\nimport { logger } from \"../lib/logger\";\r\nimport VideoPlayer from \"../lib/mediaPlayer\";\r\nimport { RichTextProcessor } from \"../lib/richtextprocessor\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport animationIntersector from \"./animationIntersector\";\r\nimport appMediaPlaybackController from \"./appMediaPlaybackController\";\r\nimport AvatarElement from \"./avatar\";\r\nimport ButtonIcon from \"./buttonIcon\";\r\nimport { ButtonMenuItemOptions } from \"./buttonMenu\";\r\nimport ButtonMenuToggle from \"./buttonMenuToggle\";\r\nimport { LazyLoadQueueBase } from \"./lazyLoadQueue\";\r\nimport PopupForward from \"./popups/forward\";\r\nimport ProgressivePreloader from \"./preloader\";\r\nimport Scrollable from \"./scrollable\";\r\nimport appSidebarRight, { AppSidebarRight } from \"./sidebarRight\";\r\nimport SwipeHandler from \"./swipeHandler\";\r\nimport { months, ONE_DAY } from \"../helpers/date\";\r\nimport { SearchSuperContext } from \"./appSearchSuper.\";\r\nimport DEBUG from \"../config/debug\";\r\nimport appNavigationController from \"./appNavigationController\";\r\nimport { Message } from \"../layer\";\r\nimport { forEachReverse } from \"../helpers/array\";\r\nimport AppSharedMediaTab from \"./sidebarRight/tabs/sharedMedia\";\r\nimport findUpClassName from \"../helpers/dom/findUpClassName\";\r\nimport renderImageFromUrl from \"../helpers/dom/renderImageFromUrl\";\r\nimport findUpAsChild from \"../helpers/dom/findUpAsChild\";\r\nimport getVisibleRect from \"../helpers/dom/getVisibleRect\";\r\nimport appDownloadManager from \"../lib/appManagers/appDownloadManager\";\r\nimport { cancelEvent } from \"../helpers/dom/cancelEvent\";\r\nimport fillPropertyValue from \"../helpers/fillPropertyValue\";\r\nimport generatePathData from \"../helpers/generatePathData\";\r\nimport replaceContent from \"../helpers/dom/replaceContent\";\r\nimport PeerTitle from \"./peerTitle\";\r\n\r\n// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию\r\n// TODO: картинки \"обрезаются\" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)\r\n// TODO: видео в мобильной вёрстке, если показываются элементы управления: если свайпнуть в сторону, то элементы вернутся на место, т.е. прыгнут - это не ок, надо бы замаскировать\r\n\r\nconst MEDIA_VIEWER_CLASSNAME = 'media-viewer';\r\n\r\nclass AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType extends string, TargetType extends object> {\r\n public wholeDiv: HTMLElement;\r\n protected overlaysDiv: HTMLElement;\r\n protected author: {[k in 'container' | 'avatarEl' | 'nameEl' | 'date']: HTMLElement} = {} as any;\r\n protected content: {[k in 'main' | 'container' | 'media' | 'mover' | ContentAdditionType]: HTMLElement} = {} as any;\r\n public buttons: {[k in 'download' | 'close' | 'prev' | 'next' | 'mobile-close' | ButtonsAdditionType]: HTMLElement} = {} as any;\r\n \r\n protected tempId = 0;\r\n protected preloader: ProgressivePreloader = null;\r\n protected preloaderStreamable: ProgressivePreloader = null;\r\n\r\n protected lastTarget: HTMLElement = null;\r\n protected prevTargets: TargetType[] = [];\r\n protected nextTargets: TargetType[] = [];\r\n //protected targetContainer: HTMLElement = null;\r\n //protected loadMore: () => void = null;\r\n\r\n public log: ReturnType<typeof logger>; \r\n\r\n protected isFirstOpen = true;\r\n protected loadMediaPromiseUp: Promise<void> = null;\r\n protected loadMediaPromiseDown: Promise<void> = null;\r\n protected loadedAllMediaUp = false;\r\n protected loadedAllMediaDown = false;\r\n\r\n protected reverse = false; // reverse means next = higher msgid\r\n protected needLoadMore = true;\r\n\r\n protected pageEl = document.getElementById('page-chats') as HTMLDivElement;\r\n\r\n protected setMoverPromise: Promise<void>;\r\n protected setMoverAnimationPromise: Promise<void>;\r\n\r\n protected lazyLoadQueue: LazyLoadQueueBase;\r\n\r\n protected highlightSwitchersTimeout: number;\r\n\r\n protected onDownloadClick: (e: MouseEvent) => void;\r\n protected onPrevClick: (target: TargetType) => void;\r\n protected onNextClick: (target: TargetType) => void;\r\n protected loadMoreMedia: (older: boolean) => Promise<void>;\r\n\r\n protected videoPlayer: VideoPlayer;\r\n \r\n constructor(topButtons: Array<keyof AppMediaViewerBase<ContentAdditionType, ButtonsAdditionType, TargetType>['buttons']>) {\r\n this.log = logger('AMV');\r\n this.preloader = new ProgressivePreloader();\r\n this.preloaderStreamable = new ProgressivePreloader({\r\n cancelable: false,\r\n streamable: true\r\n });\r\n this.preloader.construct();\r\n this.preloaderStreamable.construct();\r\n this.lazyLoadQueue = new LazyLoadQueueBase();\r\n\r\n this.wholeDiv = document.createElement('div');\r\n this.wholeDiv.classList.add(MEDIA_VIEWER_CLASSNAME + '-whole');\r\n\r\n this.overlaysDiv = document.createElement('div');\r\n this.overlaysDiv.classList.add('overlays');\r\n\r\n const mainDiv = document.createElement('div');\r\n mainDiv.classList.add(MEDIA_VIEWER_CLASSNAME);\r\n\r\n // * author\r\n this.author.container = document.createElement('div');\r\n this.author.container.classList.add(MEDIA_VIEWER_CLASSNAME + '-author', 'no-select');\r\n\r\n this.author.avatarEl = new AvatarElement();\r\n this.author.avatarEl.classList.add(MEDIA_VIEWER_CLASSNAME + '-userpic', 'avatar-44');\r\n\r\n this.author.nameEl = document.createElement('div');\r\n this.author.nameEl.classList.add(MEDIA_VIEWER_CLASSNAME + '-name');\r\n\r\n this.author.date = document.createElement('div');\r\n this.author.date.classList.add(MEDIA_VIEWER_CLASSNAME + '-date');\r\n\r\n this.author.container.append(this.author.avatarEl, this.author.nameEl, this.author.date);\r\n\r\n // * buttons\r\n const buttonsDiv = document.createElement('div');\r\n buttonsDiv.classList.add(MEDIA_VIEWER_CLASSNAME + '-buttons');\r\n\r\n topButtons.concat(['download', 'close']).forEach(name => {\r\n const button = ButtonIcon(name, {noRipple: name === 'close' || undefined});\r\n this.buttons[name] = button;\r\n buttonsDiv.append(button);\r\n });\r\n\r\n // * content\r\n this.content.main = document.createElement('div');\r\n this.content.main.classList.add(MEDIA_VIEWER_CLASSNAME + '-content');\r\n\r\n this.content.container = document.createElement('div');\r\n this.content.container.classList.add(MEDIA_VIEWER_CLASSNAME + '-container');\r\n\r\n this.content.media = document.createElement('div');\r\n this.content.media.classList.add(MEDIA_VIEWER_CLASSNAME + '-media');\r\n\r\n this.content.container.append(this.content.media);\r\n\r\n this.content.main.append(this.content.container);\r\n mainDiv.append(this.author.container, buttonsDiv, this.content.main);\r\n this.overlaysDiv.append(mainDiv);\r\n // * overlays end\r\n\r\n this.buttons[\"mobile-close\"] = ButtonIcon('close', {onlyMobile: true});\r\n\r\n this.buttons.prev = document.createElement('div');\r\n this.buttons.prev.className = `${MEDIA_VIEWER_CLASSNAME}-switcher ${MEDIA_VIEWER_CLASSNAME}-switcher-left`;\r\n this.buttons.prev.innerHTML = `<span class=\"tgico-down ${MEDIA_VIEWER_CLASSNAME}-prev-button\"></span>`;\r\n\r\n this.buttons.next = document.createElement('div');\r\n this.buttons.next.className = `${MEDIA_VIEWER_CLASSNAME}-switcher ${MEDIA_VIEWER_CLASSNAME}-switcher-right`;\r\n this.buttons.next.innerHTML = `<span class=\"tgico-down ${MEDIA_VIEWER_CLASSNAME}-next-button\"></span>`;\r\n\r\n this.wholeDiv.append(this.overlaysDiv, this.buttons['mobile-close'], this.buttons.prev, this.buttons.next);\r\n\r\n // * constructing html end\r\n \r\n this.setNewMover();\r\n }\r\n\r\n protected setListeners() {\r\n this.buttons.download.addEventListener('click', this.onDownloadClick);\r\n [this.buttons.close, this.buttons[\"mobile-close\"], this.preloaderStreamable.preloader].forEach(el => {\r\n el.addEventListener('click', this.close.bind(this));\r\n });\r\n\r\n this.buttons.prev.addEventListener('click', (e) => {\r\n cancelEvent(e);\r\n if(this.setMoverPromise) return;\r\n\r\n const target = this.prevTargets.pop();\r\n if(target) {\r\n this.onPrevClick(target);\r\n } else {\r\n this.buttons.prev.style.display = 'none';\r\n }\r\n });\r\n \r\n this.buttons.next.addEventListener('click', (e) => {\r\n cancelEvent(e);\r\n if(this.setMoverPromise) return;\r\n\r\n let target = this.nextTargets.shift();\r\n if(target) {\r\n this.onNextClick(target);\r\n } else {\r\n this.buttons.next.style.display = 'none';\r\n }\r\n });\r\n\r\n this.wholeDiv.addEventListener('click', this.onClick);\r\n\r\n if(isTouchSupported) {\r\n const swipeHandler = new SwipeHandler({\r\n element: this.wholeDiv, \r\n onSwipe: (xDiff, yDiff) => {\r\n if(VideoPlayer.isFullScreen()) {\r\n return;\r\n }\r\n //console.log(xDiff, yDiff);\r\n\r\n const percents = Math.abs(xDiff) / appPhotosManager.windowW;\r\n if(percents > .2 || xDiff > 125) {\r\n //console.log('will swipe', xDiff);\r\n\r\n if(xDiff < 0) {\r\n this.buttons.prev.click();\r\n } else {\r\n this.buttons.next.click();\r\n }\r\n\r\n return true;\r\n }\r\n\r\n const percentsY = Math.abs(yDiff) / appPhotosManager.windowH;\r\n if(percentsY > .2 || yDiff > 125) {\r\n this.buttons.close.click();\r\n return true;\r\n }\r\n\r\n return false;\r\n }, \r\n verifyTouchTarget: (evt) => {\r\n // * Fix for seek input\r\n if((evt.target as HTMLElement).tagName === 'INPUT' || findUpClassName(evt.target, 'media-viewer-caption')) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n }\r\n }\r\n\r\n protected setBtnMenuToggle(buttons: ButtonMenuItemOptions[]) {\r\n const btnMenuToggle = ButtonMenuToggle({onlyMobile: true}, 'bottom-left', buttons);\r\n this.wholeDiv.append(btnMenuToggle);\r\n }\r\n\r\n public close(e?: MouseEvent) {\r\n if(e) {\r\n cancelEvent(e);\r\n }\r\n\r\n if(this.setMoverAnimationPromise) return;\r\n\r\n appNavigationController.removeByType('media');\r\n\r\n this.lazyLoadQueue.clear();\r\n\r\n const promise = this.setMoverToTarget(this.lastTarget, true).then(({onAnimationEnd}) => onAnimationEnd);\r\n\r\n this.lastTarget = null;\r\n this.prevTargets = [];\r\n this.nextTargets = [];\r\n this.loadedAllMediaUp = this.loadedAllMediaDown = false;\r\n this.loadMediaPromiseUp = this.loadMediaPromiseDown = null;\r\n this.setMoverPromise = null;\r\n this.tempId = -1;\r\n\r\n /* if(appSidebarRight.historyTabIDs.slice(-1)[0] === AppSidebarRight.SLIDERITEMSIDS.forward) {\r\n promise.then(() => {\r\n appSidebarRight.forwardTab.closeBtn.click();\r\n });\r\n } */\r\n\r\n window.removeEventListener('keydown', this.onKeyDown);\r\n\r\n promise.finally(() => {\r\n this.wholeDiv.remove();\r\n rootScope.overlayIsActive = false;\r\n animationIntersector.checkAnimations(false);\r\n });\r\n\r\n return promise;\r\n }\r\n\r\n onClick = (e: MouseEvent) => {\r\n if(this.setMoverAnimationPromise) return;\r\n\r\n const target = e.target as HTMLElement;\r\n if(target.tagName === 'A') return;\r\n cancelEvent(e);\r\n\r\n if(isTouchSupported) {\r\n if(this.highlightSwitchersTimeout) {\r\n clearTimeout(this.highlightSwitchersTimeout);\r\n } else {\r\n this.wholeDiv.classList.add('highlight-switchers');\r\n }\r\n\r\n this.highlightSwitchersTimeout = window.setTimeout(() => {\r\n this.wholeDiv.classList.remove('highlight-switchers');\r\n this.highlightSwitchersTimeout = 0;\r\n }, 3e3);\r\n \r\n return;\r\n }\r\n\r\n let mover: HTMLElement = null;\r\n ['media-viewer-mover', 'media-viewer-buttons', 'media-viewer-author', 'media-viewer-caption'].find(s => {\r\n try {\r\n mover = findUpClassName(target, s);\r\n if(mover) return true;\r\n } catch(err) {return false;}\r\n });\r\n\r\n if(/* target === this.mediaViewerDiv */!mover || target.tagName === 'IMG' || target.tagName === 'image') {\r\n this.buttons.close.click();\r\n }\r\n };\r\n\r\n private onKeyDown = (e: KeyboardEvent) => {\r\n //this.log('onKeyDown', e);\r\n \r\n if(e.key === 'ArrowRight') {\r\n this.buttons.next.click();\r\n } else if(e.key === 'ArrowLeft') {\r\n this.buttons.prev.click();\r\n }\r\n };\r\n\r\n protected async setMoverToTarget(target: HTMLElement, closing = false, fromRight = 0) {\r\n if(this.videoPlayer) { // there could be a better place for it\r\n this.videoPlayer.removeListeners();\r\n this.videoPlayer = undefined;\r\n }\r\n\r\n const mover = this.content.mover;\r\n\r\n if(!closing) {\r\n mover.innerHTML = '';\r\n //mover.append(this.buttons.prev, this.buttons.next);\r\n }\r\n \r\n this.removeCenterFromMover(mover);\r\n\r\n const wasActive = fromRight !== 0;\r\n\r\n const delay = rootScope.settings.animationsEnabled ? (wasActive ? 350 : 200) : 0;\r\n //let delay = wasActive ? 350 : 10000;\r\n\r\n /* if(wasActive) {\r\n this.moveTheMover(mover);\r\n mover = this.setNewMover();\r\n } */\r\n\r\n /* if(DEBUG) {\r\n this.log('setMoverToTarget', target, closing, wasActive, fromRight);\r\n } */\r\n\r\n let realParent: HTMLElement;\r\n\r\n let rect: DOMRect;\r\n if(target) {\r\n if(target instanceof AvatarElement || target.classList.contains('grid-item')) {\r\n realParent = target;\r\n rect = target.getBoundingClientRect();\r\n } else if(target instanceof SVGImageElement || target.parentElement instanceof SVGForeignObjectElement) {\r\n realParent = findUpClassName(target, 'attachment');\r\n rect = realParent.getBoundingClientRect();\r\n } else if(target.classList.contains('profile-avatars-avatar')) {\r\n realParent = findUpClassName(target, 'profile-avatars-container');\r\n rect = realParent.getBoundingClientRect();\r\n\r\n // * if not active avatar\r\n if(closing && target.getBoundingClientRect().left !== rect.left) {\r\n target = realParent = rect = undefined;\r\n }\r\n }\r\n }\r\n\r\n if(!target) {\r\n target = this.content.media;\r\n }\r\n\r\n if(!rect) {\r\n realParent = target.parentElement as HTMLElement;\r\n rect = target.getBoundingClientRect();\r\n }\r\n\r\n let needOpacity = false;\r\n if(target !== this.content.media && !target.classList.contains('profile-avatars-avatar')) {\r\n const overflowElement = findUpClassName(realParent, 'scrollable');\r\n const visibleRect = getVisibleRect(realParent, overflowElement);\r\n\r\n if(closing && (!visibleRect || visibleRect.overflow.vertical === 2 || visibleRect.overflow.horizontal === 2)) {\r\n target = this.content.media;\r\n realParent = target.parentElement as HTMLElement;\r\n rect = target.getBoundingClientRect();\r\n } else if(visibleRect && (visibleRect.overflow.vertical === 1 || visibleRect.overflow.horizontal === 1)) {\r\n needOpacity = true;\r\n }\r\n }\r\n\r\n const containerRect = this.content.media.getBoundingClientRect();\r\n \r\n let transform = '';\r\n let left: number;\r\n let top: number;\r\n\r\n if(wasActive) {\r\n left = fromRight === 1 ? appPhotosManager.windowW : -containerRect.width;\r\n top = containerRect.top;\r\n } else {\r\n left = rect.left;\r\n top = rect.top;\r\n }\r\n\r\n transform += `translate3d(${left}px,${top}px,0) `;\r\n\r\n /* if(wasActive) {\r\n left = fromRight === 1 ? appPhotosManager.windowW / 2 : -(containerRect.width + appPhotosManager.windowW / 2);\r\n transform += `translate(${left}px,-50%) `;\r\n } else {\r\n left = rect.left - (appPhotosManager.windowW / 2);\r\n top = rect.top - (appPhotosManager.windowH / 2);\r\n transform += `translate(${left}px,${top}px) `;\r\n } */\r\n\r\n let aspecter: HTMLDivElement;\r\n if(target instanceof HTMLImageElement || target instanceof HTMLVideoElement || target.tagName === 'DIV') {\r\n if(mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter')) {\r\n aspecter = mover.firstElementChild as HTMLDivElement;\r\n\r\n const player = aspecter.querySelector('.ckin__player');\r\n if(player) {\r\n const video = player.firstElementChild as HTMLVideoElement;\r\n aspecter.append(video);\r\n player.remove();\r\n }\r\n\r\n if(!aspecter.style.cssText) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать\r\n mover.classList.remove('active');\r\n this.setFullAspect(aspecter, containerRect, rect);\r\n void mover.offsetLeft; // reflow\r\n mover.classList.add('active');\r\n }\r\n } else {\r\n aspecter = document.createElement('div');\r\n aspecter.classList.add('media-viewer-aspecter'/* , 'disable-hover' */);\r\n mover.prepend(aspecter);\r\n }\r\n \r\n aspecter.style.cssText = `width: ${rect.width}px; height: ${rect.height}px; transform: scale3d(${containerRect.width / rect.width}, ${containerRect.height / rect.height}, 1);`;\r\n }\r\n\r\n mover.style.width = containerRect.width + 'px';\r\n mover.style.height = containerRect.height + 'px';\r\n\r\n const scaleX = rect.width / containerRect.width;\r\n const scaleY = rect.height / containerRect.height;\r\n if(!wasActive) {\r\n transform += `scale3d(${scaleX},${scaleY},1) `;\r\n }\r\n\r\n let borderRadius = window.getComputedStyle(realParent).getPropertyValue('border-radius');\r\n const brSplitted = fillPropertyValue(borderRadius) as string[];\r\n borderRadius = brSplitted.map(r => (parseInt(r) / scaleX) + 'px').join(' ');\r\n if(!wasActive) {\r\n mover.style.borderRadius = borderRadius;\r\n }\r\n //let borderRadius = '0px 0px 0px 0px';\r\n\r\n mover.style.transform = transform;\r\n\r\n needOpacity && (mover.style.opacity = '0'/* !closing ? '0' : '' */);\r\n\r\n /* if(wasActive) {\r\n this.log('setMoverToTarget', mover.style.transform);\r\n } */\r\n\r\n let path: SVGPathElement;\r\n const isOut = target.classList.contains('is-out');\r\n\r\n const deferred = this.setMoverAnimationPromise = deferredPromise<void>();\r\n const ret = {onAnimationEnd: deferred};\r\n\r\n this.setMoverAnimationPromise.then(() => {\r\n this.setMoverAnimationPromise = null;\r\n });\r\n\r\n if(!closing) {\r\n let mediaElement: HTMLImageElement | HTMLVideoElement;\r\n let src: string;\r\n\r\n if(target.tagName === 'DIV' || target.tagName === 'AVATAR-ELEMENT') { // useContainerAsTarget\r\n if(target.firstElementChild) {\r\n mediaElement = new Image();\r\n src = (target.firstElementChild as HTMLImageElement).src;\r\n mover.append(mediaElement);\r\n }\r\n /* mediaElement = new Image();\r\n src = target.style.backgroundImage.slice(5, -2); */\r\n \r\n } else if(target instanceof HTMLImageElement) {\r\n mediaElement = new Image();\r\n src = target.src;\r\n } else if(target instanceof HTMLVideoElement) {\r\n const video = mediaElement = document.createElement('video');\r\n video.src = target?.src;\r\n } else if(target instanceof SVGSVGElement) {\r\n const clipId = target.dataset.clipId;\r\n const newClipId = clipId + '-mv';\r\n\r\n const {width, height} = containerRect;\r\n\r\n const newSvg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n newSvg.setAttributeNS(null, 'width', '' + width);\r\n newSvg.setAttributeNS(null, 'height', '' + height);\r\n\r\n // нижние два свойства для масштабирования\r\n newSvg.setAttributeNS(null, 'viewBox', `0 0 ${width} ${height}`);\r\n newSvg.setAttributeNS(null, 'preserveAspectRatio', 'xMidYMid meet');\r\n\r\n newSvg.insertAdjacentHTML('beforeend', target.firstElementChild.outerHTML.replace(clipId, newClipId));\r\n newSvg.insertAdjacentHTML('beforeend', target.lastElementChild.outerHTML.replace(clipId, newClipId));\r\n\r\n // теперь надо выставить новую позицию для хвостика\r\n const defs = newSvg.firstElementChild;\r\n const use = defs.firstElementChild.firstElementChild as SVGUseElement;\r\n if(use instanceof SVGUseElement) {\r\n let transform = use.getAttributeNS(null, 'transform');\r\n transform = transform.replace(/translate\\((.+?), (.+?)\\) scale\\((.+?), (.+?)\\)/, (match, x, y, sX, sY) => {\r\n x = +x;\r\n if(x !== 2) {\r\n x = width - (2 / scaleX);\r\n } else {\r\n x = 2 / scaleX;\r\n }\r\n \r\n y = height;\r\n \r\n return `translate(${x}, ${y}) scale(${+sX / scaleX}, ${+sY / scaleY})`;\r\n });\r\n use.setAttributeNS(null, 'transform', transform);\r\n \r\n // и новый RECT\r\n path = defs.firstElementChild.lastElementChild as SVGPathElement;\r\n\r\n // код ниже нужен только чтобы скрыть моргание до момента как сработает таймаут\r\n let d: string;\r\n const br: [number, number, number, number] = borderRadius.split(' ').map(v => parseInt(v)) as any;\r\n if(isOut) d = generatePathData(0, 0, width - 9 / scaleX, height, ...br);\r\n else d = generatePathData(9 / scaleX, 0, width - 9 / scaleX, height, ...br);\r\n path.setAttributeNS(null, 'd', d);\r\n }\r\n\r\n const foreignObject = newSvg.lastElementChild;\r\n foreignObject.setAttributeNS(null, 'width', '' + containerRect.width);\r\n foreignObject.setAttributeNS(null, 'height', '' + containerRect.height);\r\n \r\n mover.prepend(newSvg);\r\n }\r\n\r\n if(aspecter) {\r\n aspecter.style.borderRadius = borderRadius;\r\n\r\n if(mediaElement) {\r\n aspecter.append(mediaElement);\r\n }\r\n }\r\n\r\n mediaElement = mover.querySelector('video, img');\r\n if(mediaElement instanceof HTMLImageElement) {\r\n mediaElement.classList.add('thumbnail');\r\n if(!aspecter) {\r\n mediaElement.style.width = containerRect.width + 'px';\r\n mediaElement.style.height = containerRect.height + 'px';\r\n }\r\n\r\n if(src) {\r\n await new Promise((resolve, reject) => {\r\n mediaElement.addEventListener('load', resolve);\r\n \r\n if(src) {\r\n mediaElement.src = src;\r\n }\r\n });\r\n }\r\n }/* else if(mediaElement instanceof HTMLVideoElement && mediaElement.firstElementChild && ((mediaElement.firstElementChild as HTMLSourceElement).src || src)) {\r\n await new Promise((resolve, reject) => {\r\n mediaElement.addEventListener('loadeddata', resolve);\r\n\r\n if(src) {\r\n (mediaElement.firstElementChild as HTMLSourceElement).src = src;\r\n }\r\n });\r\n } */\r\n \r\n mover.style.display = '';\r\n\r\n window.requestAnimationFrame(() => {\r\n mover.classList.add(wasActive ? 'moving' : 'active');\r\n });\r\n } else {\r\n /* if(mover.classList.contains('center')) {\r\n mover.classList.remove('center');\r\n void mover.offsetLeft; // reflow\r\n } */\r\n \r\n if(target instanceof SVGSVGElement) {\r\n path = mover.querySelector('path');\r\n\r\n if(path) {\r\n this.sizeTailPath(path, containerRect, scaleX, delay, false, isOut, borderRadius);\r\n }\r\n }\r\n\r\n if(target.classList.contains('media-viewer-media')) {\r\n mover.classList.add('hiding');\r\n }\r\n\r\n setTimeout(() => {\r\n this.wholeDiv.classList.remove('active');\r\n }, 0);\r\n\r\n setTimeout(() => {\r\n mover.style.borderRadius = borderRadius;\r\n\r\n if(mover.firstElementChild) {\r\n (mover.firstElementChild as HTMLElement).style.borderRadius = borderRadius;\r\n }\r\n }, delay / 2);\r\n\r\n setTimeout(() => {\r\n mover.innerHTML = '';\r\n mover.classList.remove('moving', 'active', 'hiding');\r\n mover.style.cssText = 'display: none;';\r\n\r\n deferred.resolve();\r\n }, delay);\r\n\r\n return ret;\r\n }\r\n\r\n mover.classList.toggle('opening', !closing);\r\n\r\n //await new Promise((resolve) => setTimeout(resolve, 0));\r\n //await new Promise((resolve) => window.requestAnimationFrame(resolve));\r\n // * одного RAF'а недостаточно, иногда анимация с одним не срабатывает (преимущественно на мобильных)\r\n await new Promise((resolve) => window.requestAnimationFrame(() => window.requestAnimationFrame(resolve)));\r\n\r\n // чтобы проверить установленную позицию - раскомментировать\r\n // throw '';\r\n\r\n //await new Promise((resolve) => setTimeout(resolve, 5e3));\r\n\r\n mover.style.transform = `translate3d(${containerRect.left}px,${containerRect.top}px,0) scale3d(1,1,1)`;\r\n //mover.style.transform = `translate(-50%,-50%) scale(1,1)`;\r\n needOpacity && (mover.style.opacity = ''/* closing ? '0' : '' */);\r\n\r\n if(aspecter) {\r\n this.setFullAspect(aspecter, containerRect, rect);\r\n }\r\n\r\n //throw '';\r\n\r\n setTimeout(() => {\r\n mover.style.borderRadius = '';\r\n\r\n if(mover.firstElementChild) {\r\n (mover.firstElementChild as HTMLElement).style.borderRadius = '';\r\n }\r\n }, 0/* delay / 2 */);\r\n\r\n mover.dataset.timeout = '' + setTimeout(() => {\r\n mover.classList.remove('moving');\r\n\r\n if(aspecter) { // всё из-за видео, элементы управления скейлятся, так бы можно было этого не делать\r\n if(mover.querySelector('video') || true) {\r\n mover.classList.remove('active');\r\n aspecter.style.cssText = '';\r\n void mover.offsetLeft; // reflow\r\n }\r\n \r\n //aspecter.classList.remove('disable-hover');\r\n }\r\n\r\n // эти строки нужны для установки центральной позиции, в случае ресайза это будет нужно\r\n mover.classList.add('center', 'no-transition');\r\n /* mover.style.left = mover.style.top = '50%';\r\n mover.style.transform = 'translate(-50%, -50%)';\r\n void mover.offsetLeft; // reflow */\r\n\r\n // это уже нужно для будущих анимаций\r\n mover.classList.add('active');\r\n delete mover.dataset.timeout;\r\n\r\n deferred.resolve();\r\n }, delay);\r\n\r\n if(path) {\r\n this.sizeTailPath(path, containerRect, scaleX, delay, true, isOut, borderRadius);\r\n }\r\n\r\n return ret;\r\n }\r\n\r\n protected setFullAspect(aspecter: HTMLDivElement, containerRect: DOMRect, rect: DOMRect) {\r\n /* let media = aspecter.firstElementChild;\r\n let proportion: number;\r\n if(media instanceof HTMLImageElement) {\r\n proportion = media.naturalWidth / media.naturalHeight;\r\n } else if(media instanceof HTMLVideoElement) {\r\n proportion = media.videoWidth / media.videoHeight;\r\n } */\r\n const proportion = containerRect.width / containerRect.height;\r\n\r\n let {width, height} = rect;\r\n /* if(proportion === 1) {\r\n aspecter.style.cssText = '';\r\n } else { */\r\n if(proportion > 0) {\r\n width = height * proportion;\r\n } else {\r\n height = width * proportion;\r\n }\r\n\r\n //this.log('will set style aspecter:', `width: ${width}px; height: ${height}px; transform: scale(${containerRect.width / width}, ${containerRect.height / height});`);\r\n\r\n aspecter.style.cssText = `width: ${width}px; height: ${height}px; transform: scale3d(${containerRect.width / width}, ${containerRect.height / height}, 1);`;\r\n //}\r\n }\r\n\r\n protected sizeTailPath(path: SVGPathElement, rect: DOMRect, scaleX: number, delay: number, upscale: boolean, isOut: boolean, borderRadius: string) {\r\n const start = Date.now();\r\n const {width, height} = rect;\r\n delay = delay / 2;\r\n\r\n const br = borderRadius.split(' ').map(v => parseInt(v));\r\n\r\n const step = () => {\r\n const diff = Date.now() - start;\r\n\r\n let progress = delay ? diff / delay : 1;\r\n if(progress > 1) progress = 1;\r\n if(upscale) progress = 1 - progress;\r\n\r\n const _br: [number, number, number, number] = br.map(v => v * progress) as any;\r\n\r\n let d: string;\r\n if(isOut) d = generatePathData(0, 0, width - (9 / scaleX * progress), height, ..._br);\r\n else d = generatePathData(9 / scaleX * progress, 0, width/* width - (9 / scaleX * progress) */, height, ..._br);\r\n path.setAttributeNS(null, 'd', d);\r\n\r\n if(diff < delay) window.requestAnimationFrame(step);\r\n };\r\n \r\n //window.requestAnimationFrame(step);\r\n step();\r\n }\r\n\r\n protected removeCenterFromMover(mover: HTMLElement) {\r\n if(mover.classList.contains('center')) {\r\n //const rect = mover.getBoundingClientRect();\r\n const rect = this.content.media.getBoundingClientRect();\r\n mover.style.transform = `translate3d(${rect.left}px,${rect.top}px,0)`;\r\n mover.classList.remove('center');\r\n void mover.offsetLeft; // reflow\r\n mover.classList.remove('no-transition');\r\n }\r\n }\r\n\r\n protected moveTheMover(mover: HTMLElement, toLeft = true) {\r\n const windowW = appPhotosManager.windowW;\r\n\r\n this.removeCenterFromMover(mover);\r\n\r\n //mover.classList.remove('active');\r\n mover.classList.add('moving');\r\n\r\n if(mover.dataset.timeout) { // и это тоже всё из-за скейла видео, так бы это не нужно было\r\n clearTimeout(+mover.dataset.timeout);\r\n }\r\n\r\n const rect = mover.getBoundingClientRect();\r\n\r\n const newTransform = mover.style.transform.replace(/translate3d\\((.+?),/, (match, p1) => {\r\n const x = toLeft ? -rect.width : windowW;\r\n //const x = toLeft ? -(rect.right + (rect.width / 2)) : windowW / 2;\r\n\r\n return match.replace(p1, x + 'px');\r\n });\r\n\r\n ////////this.log('set newTransform:', newTransform, mover.style.transform, toLeft);\r\n mover.style.transform = newTransform;\r\n\r\n setTimeout(() => {\r\n mover.remove();\r\n }, 350);\r\n }\r\n\r\n protected setNewMover() {\r\n const newMover = document.createElement('div');\r\n newMover.classList.add('media-viewer-mover');\r\n\r\n if(this.content.mover) {\r\n const oldMover = this.content.mover;\r\n oldMover.parentElement.append(newMover);\r\n } else {\r\n this.wholeDiv.append(newMover);\r\n }\r\n\r\n return this.content.mover = newMover;\r\n }\r\n\r\n /* public isElementVisible(container: HTMLElement, target: HTMLElement) {\r\n const rect = container.getBoundingClientRect();\r\n const targetRect = target.getBoundingClientRect();\r\n\r\n return targetRect.bottom > rect.top && targetRect.top < rect.bottom;\r\n } */\r\n\r\n protected updateMediaSource(target: HTMLElement, url: string, tagName: 'video' | 'img') {\r\n //if(target instanceof SVGSVGElement) {\r\n const el = target.tagName.toLowerCase() === tagName ? target : target.querySelector(tagName) as HTMLElement;\r\n if(el) {\r\n renderImageFromUrl(el, url);\r\n }\r\n /* } else {\r\n\r\n } */\r\n }\r\n\r\n protected setAuthorInfo(fromId: number, timestamp: number) {\r\n const date = new Date();\r\n const time = new Date(timestamp * 1000);\r\n const now = date.getTime() / 1000;\r\n\r\n const timeStr = time.getHours() + ':' + ('0' + time.getMinutes()).slice(-2);\r\n let dateStr: string;\r\n if((now - timestamp) < ONE_DAY && date.getDate() === time.getDate()) { // if the same day\r\n dateStr = 'Today';\r\n } else if((now - timestamp) < (ONE_DAY * 2) && (date.getDate() - 1) === time.getDate()) { // yesterday\r\n dateStr = 'Yesterday';\r\n } else if(date.getFullYear() !== time.getFullYear()) { // different year\r\n dateStr = months[time.getMonth()].slice(0, 3) + ' ' + time.getDate() + ', ' + time.getFullYear();\r\n } else {\r\n dateStr = months[time.getMonth()].slice(0, 3) + ' ' + time.getDate();\r\n }\r\n\r\n this.author.date.innerText = dateStr + ' at ' + timeStr;\r\n\r\n replaceContent(this.author.nameEl, new PeerTitle({\r\n peerId: fromId,\r\n dialog: false,\r\n onlyFirstName: false,\r\n plainText: false\r\n }).element);\r\n\r\n let oldAvatar = this.author.avatarEl;\r\n this.author.avatarEl = (this.author.avatarEl.cloneNode() as AvatarElement);\r\n this.author.avatarEl.setAttribute('peer', '' + fromId);\r\n oldAvatar.parentElement.replaceChild(this.author.avatarEl, oldAvatar);\r\n }\r\n \r\n protected async _openMedia(media: any, timestamp: number, fromId: number, fromRight: number, target?: HTMLElement, reverse = false, \r\n prevTargets: TargetType[] = [], nextTargets: TargetType[] = [], needLoadMore = true) {\r\n if(this.setMoverPromise) return this.setMoverPromise;\r\n\r\n /* if(DEBUG) {\r\n this.log('openMedia:', media, fromId, prevTargets, nextTargets);\r\n } */\r\n\r\n this.setAuthorInfo(fromId, timestamp);\r\n \r\n const isVideo = (media as MyDocument).type === 'video' || (media as MyDocument).type === 'gif';\r\n\r\n if(this.isFirstOpen) {\r\n //this.targetContainer = targetContainer;\r\n this.prevTargets = prevTargets;\r\n this.nextTargets = nextTargets;\r\n this.reverse = reverse;\r\n this.needLoadMore = needLoadMore;\r\n this.isFirstOpen = false;\r\n //this.loadMore = loadMore;\r\n\r\n /* if(appSidebarRight.historyTabIDs.slice(-1)[0] === AppSidebarRight.SLIDERITEMSIDS.forward) {\r\n appSidebarRight.forwardTab.closeBtn.click();\r\n await new Promise((resolve) => setTimeout(resolve, 200));\r\n } */\r\n }\r\n\r\n /* if(this.nextTargets.length < 10 && this.loadMore) {\r\n this.loadMore();\r\n } */\r\n\r\n //if(prevTarget && (!prevTarget.parentElement || !this.isElementVisible(this.targetContainer, prevTarget))) prevTarget = null;\r\n //if(nextTarget && (!nextTarget.parentElement || !this.isElementVisible(this.targetContainer, nextTarget))) nextTarget = null;\r\n\r\n this.buttons.prev.classList.toggle('hide', !this.prevTargets.length);\r\n this.buttons.next.classList.toggle('hide', !this.nextTargets.length);\r\n \r\n const container = this.content.media;\r\n const useContainerAsTarget = !target || target === container;\r\n if(useContainerAsTarget) target = container;\r\n\r\n this.lastTarget = target;\r\n const tempId = ++this.tempId;\r\n\r\n if(this.needLoadMore) {\r\n if(this.nextTargets.length < 20) {\r\n this.loadMoreMedia(!this.reverse);\r\n }\r\n \r\n if(this.prevTargets.length < 20) {\r\n this.loadMoreMedia(this.reverse);\r\n }\r\n }\r\n \r\n if(container.firstElementChild) {\r\n container.innerHTML = '';\r\n }\r\n \r\n // ok set\r\n\r\n const wasActive = fromRight !== 0;\r\n if(wasActive) {\r\n this.moveTheMover(this.content.mover, fromRight === 1);\r\n this.setNewMover();\r\n } else {\r\n window.addEventListener('keydown', this.onKeyDown);\r\n const mainColumns = this.pageEl.querySelector('#main-columns');\r\n this.pageEl.insertBefore(this.wholeDiv, mainColumns);\r\n void this.wholeDiv.offsetLeft; // reflow\r\n this.wholeDiv.classList.add('active');\r\n rootScope.overlayIsActive = true;\r\n animationIntersector.checkAnimations(true);\r\n\r\n if(!isMobileSafari) {\r\n appNavigationController.pushItem({\r\n type: 'media',\r\n onPop: (canAnimate) => {\r\n if(this.setMoverAnimationPromise) {\r\n return false;\r\n }\r\n \r\n this.close();\r\n }\r\n });\r\n }\r\n }\r\n\r\n ////////this.log('wasActive:', wasActive);\r\n\r\n const mover = this.content.mover;\r\n\r\n //const maxWidth = appPhotosManager.windowW - 16;\r\n const maxWidth = mediaSizes.isMobile ? this.pageEl.scrollWidth : this.pageEl.scrollWidth - 16;\r\n // TODO: const maxHeight = mediaSizes.isMobile ? appPhotosManager.windowH : appPhotosManager.windowH - 100;\r\n const maxHeight = appPhotosManager.windowH - 100;\r\n let thumbPromise: Promise<any> = Promise.resolve();\r\n const size = appPhotosManager.setAttachmentSize(media, container, maxWidth, maxHeight, mediaSizes.isMobile ? false : true).photoSize;\r\n if(useContainerAsTarget) {\r\n const cacheContext = appDownloadManager.getCacheContext(media, size.type);\r\n let img: HTMLImageElement;\r\n if(cacheContext.downloaded) {\r\n img = new Image();\r\n img.src = cacheContext.url;\r\n } else {\r\n const gotThumb = appPhotosManager.getStrippedThumbIfNeeded(media, cacheContext, true);\r\n if(gotThumb) {\r\n thumbPromise = gotThumb.loadPromise;\r\n img = gotThumb.image;\r\n }\r\n }\r\n\r\n if(img) {\r\n img.classList.add('thumbnail');\r\n container.append(img);\r\n }\r\n }\r\n\r\n // need after setAttachmentSize\r\n /* if(useContainerAsTarget) {\r\n target = target.querySelector('img, video') || target;\r\n } */\r\n\r\n const preloader = media.supportsStreaming ? this.preloaderStreamable : this.preloader;\r\n\r\n let setMoverPromise: Promise<void>;\r\n if(isVideo) {\r\n ////////this.log('will wrap video', media, size);\r\n\r\n // потому что для safari нужно создать элемент из event'а\r\n const video = document.createElement('video');\r\n\r\n const set = () => this.setMoverToTarget(target, false, fromRight).then(({onAnimationEnd}) => {\r\n //return; // set and don't move\r\n //if(wasActive) return;\r\n //return;\r\n \r\n const div = mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter') ? mover.firstElementChild : mover;\r\n //const video = mover.querySelector('video') || document.createElement('video');\r\n \r\n const moverVideo = mover.querySelector('video');\r\n if(moverVideo) {\r\n moverVideo.remove();\r\n }\r\n \r\n //video.src = '';\r\n \r\n video.setAttribute('playsinline', 'true');\r\n \r\n // * fix for playing video if viewer is closed (https://contest.com/javascript-web-bonus/entry1425#issue11629)\r\n video.addEventListener('timeupdate', () => {\r\n if(this.tempId !== tempId) {\r\n video.pause();\r\n }\r\n });\r\n \r\n if(isSafari) {\r\n // test stream\r\n // video.controls = true;\r\n video.autoplay = true;\r\n }\r\n \r\n if(media.type === 'gif') {\r\n video.muted = true;\r\n video.autoplay = true;\r\n video.loop = true;\r\n }\r\n \r\n if(!video.parentElement) {\r\n div.append(video);\r\n }\r\n \r\n const canPlayThrough = new Promise((resolve) => {\r\n video.addEventListener('canplay', resolve, {once: true});\r\n });\r\n \r\n const createPlayer = () => {\r\n if(media.type !== 'gif') {\r\n video.dataset.ckin = 'default';\r\n video.dataset.overlay = '1';\r\n \r\n // fix for simultaneous play\r\n appMediaPlaybackController.pause();\r\n appMediaPlaybackController.willBePlayedMedia = null;\r\n \r\n Promise.all([canPlayThrough, onAnimationEnd]).then(() => {\r\n if(this.tempId !== tempId) {\r\n return;\r\n }\r\n \r\n const player = new VideoPlayer(video, true, media.supportsStreaming);\r\n this.videoPlayer = player;\r\n /* div.append(video);\r\n mover.append(player.wrapper); */\r\n });\r\n }\r\n };\r\n \r\n if(media.supportsStreaming) {\r\n onAnimationEnd.then(() => {\r\n if(video.readyState < video.HAVE_FUTURE_DATA) {\r\n preloader.attach(mover, true);\r\n }\r\n \r\n /* canPlayThrough.then(() => {\r\n preloader.detach();\r\n }); */\r\n });\r\n \r\n const attachCanPlay = () => {\r\n video.addEventListener('canplay', () => {\r\n //this.log('video waited and progress loaded');\r\n preloader.detach();\r\n video.parentElement.classList.remove('is-buffering');\r\n }, {once: true});\r\n };\r\n \r\n video.addEventListener('waiting', (e) => {\r\n const loading = video.networkState === video.NETWORK_LOADING;\r\n const isntEnoughData = video.readyState < video.HAVE_FUTURE_DATA;\r\n \r\n //this.log('video waiting for progress', loading, isntEnoughData);\r\n if(loading && isntEnoughData) {\r\n attachCanPlay();\r\n \r\n preloader.attach(mover, true);\r\n \r\n // поставлю класс для плеера, чтобы убрать большую иконку пока прелоадер на месте\r\n video.parentElement.classList.add('is-buffering');\r\n }\r\n });\r\n \r\n attachCanPlay();\r\n }\r\n \r\n //if(!video.src || media.url !== video.src) {\r\n const load = () => {\r\n const cacheContext = appDownloadManager.getCacheContext(media);\r\n const promise = media.supportsStreaming ? Promise.resolve() : appDocsManager.downloadDoc(media);\r\n \r\n if(!media.supportsStreaming) {\r\n onAnimationEnd.then(() => {\r\n if(!cacheContext.url) {\r\n preloader.attach(mover, true, promise);\r\n }\r\n });\r\n }\r\n \r\n (promise as Promise<any>).then(async() => {\r\n if(this.tempId !== tempId) {\r\n this.log.warn('media viewer changed video');\r\n return;\r\n }\r\n \r\n const url = cacheContext.url;\r\n if(target instanceof SVGSVGElement/* && (video.parentElement || !isSafari) */) { // if video exists\r\n //if(!video.parentElement) {\r\n div.firstElementChild.lastElementChild.append(video);\r\n //}\r\n \r\n this.updateMediaSource(mover, url, 'video');\r\n } else {\r\n renderImageFromUrl(video, url);\r\n }\r\n \r\n createPlayer();\r\n });\r\n \r\n return promise;\r\n };\r\n \r\n this.lazyLoadQueue.unshift({load});\r\n //} else createPlayer();\r\n });\r\n\r\n setMoverPromise = thumbPromise.then(set);\r\n } else {\r\n const set = () => this.setMoverToTarget(target, false, fromRight).then(({onAnimationEnd}) => {\r\n //return; // set and don't move\r\n //if(wasActive) return;\r\n //return;\r\n \r\n const load = () => {\r\n const cacheContext = appDownloadManager.getCacheContext(media, size.type);\r\n const cancellablePromise = appPhotosManager.preloadPhoto(media.id, size);\r\n \r\n onAnimationEnd.then(() => {\r\n if(!cacheContext.url) {\r\n this.preloader.attachPromise(cancellablePromise);\r\n //this.preloader.attach(mover, true, cancellablePromise);\r\n }\r\n });\r\n \r\n Promise.all([onAnimationEnd, cancellablePromise]).then(() => {\r\n if(this.tempId !== tempId) {\r\n this.log.warn('media viewer changed photo');\r\n return;\r\n }\r\n \r\n ///////this.log('indochina', blob);\r\n \r\n const url = cacheContext.url;\r\n if(target instanceof SVGSVGElement) {\r\n this.updateMediaSource(target, url, 'img');\r\n this.updateMediaSource(mover, url, 'img');\r\n \r\n if(mediaSizes.isMobile) {\r\n const imgs = mover.querySelectorAll('img');\r\n if(imgs && imgs.length) {\r\n imgs.forEach(img => {\r\n img.classList.remove('thumbnail'); // может здесь это вообще не нужно\r\n });\r\n }\r\n }\r\n } else {\r\n const div = mover.firstElementChild && mover.firstElementChild.classList.contains('media-viewer-aspecter') ? mover.firstElementChild : mover;\r\n const haveImage = div.firstElementChild?.tagName === 'IMG' ? div.firstElementChild as HTMLImageElement : null;\r\n if(!haveImage || haveImage.src !== url) {\r\n let image = new Image();\r\n image.classList.add('thumbnail');\r\n \r\n //this.log('will renderImageFromUrl:', image, div, target);\r\n \r\n renderImageFromUrl(image, url, () => {\r\n this.updateMediaSource(target, url, 'img');\r\n \r\n if(haveImage) {\r\n window.requestAnimationFrame(() => {\r\n haveImage.remove();\r\n });\r\n }\r\n \r\n div.append(image);\r\n });\r\n }\r\n }\r\n \r\n //this.preloader.detach();\r\n }).catch(err => {\r\n this.log.error(err);\r\n this.preloader.attach(mover);\r\n this.preloader.setManual();\r\n });\r\n \r\n return cancellablePromise;\r\n };\r\n \r\n this.lazyLoadQueue.unshift({load});\r\n });\r\n\r\n setMoverPromise = thumbPromise.then(set);\r\n }\r\n\r\n return this.setMoverPromise = setMoverPromise.catch(() => {\r\n this.setMoverAnimationPromise = null;\r\n }).finally(() => {\r\n this.setMoverPromise = null;\r\n });\r\n }\r\n}\r\n\r\ntype AppMediaViewerTargetType = {\r\n element: HTMLElement,\r\n mid: number,\r\n peerId: number\r\n};\r\nexport default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delete' | 'forward', AppMediaViewerTargetType> {\r\n public currentMessageId = 0;\r\n public currentPeerId = 0;\r\n public searchContext: SearchSuperContext;\r\n\r\n constructor() {\r\n super([/* 'delete', */'forward']);\r\n\r\n /* const stub = document.createElement('div');\r\n stub.classList.add(MEDIA_VIEWER_CLASSNAME + '-stub');\r\n this.content.main.prepend(stub); */\r\n\r\n this.content.caption = document.createElement('div');\r\n this.content.caption.classList.add(MEDIA_VIEWER_CLASSNAME + '-caption'/* , 'media-viewer-stub' */);\r\n\r\n new Scrollable(this.content.caption);\r\n\r\n //this.content.main.append(this.content.caption);\r\n this.wholeDiv.append(this.content.caption);\r\n\r\n this.setBtnMenuToggle([{\r\n icon: 'forward',\r\n text: 'Forward',\r\n onClick: this.onForwardClick\r\n }, {\r\n icon: 'download',\r\n text: 'MediaViewer.Context.Download',\r\n onClick: this.onDownloadClick\r\n }/* , {\r\n icon: 'delete danger btn-disabled',\r\n text: 'Delete',\r\n onClick: () => {}\r\n } */]);\r\n\r\n // * constructing html end\r\n \r\n this.setListeners();\r\n }\r\n\r\n protected setListeners() {\r\n super.setListeners();\r\n this.buttons.forward.addEventListener('click', this.onForwardClick);\r\n this.author.container.addEventListener('click', this.onAuthorClick);\r\n }\r\n\r\n /* public close(e?: MouseEvent) {\r\n const good = !this.setMoverAnimationPromise;\r\n const promise = super.close(e);\r\n\r\n if(good) { // clear\r\n this.currentMessageId = 0;\r\n this.peerId = 0;\r\n }\r\n\r\n return promise;\r\n } */\r\n\r\n onPrevClick = (target: AppMediaViewerTargetType) => {\r\n this.nextTargets.unshift({element: this.lastTarget, mid: this.currentMessageId, peerId: this.currentPeerId});\r\n this.openMedia(appMessagesManager.getMessageByPeer(target.peerId, target.mid), target.element, -1);\r\n };\r\n\r\n onNextClick = (target: AppMediaViewerTargetType) => {\r\n this.prevTargets.push({element: this.lastTarget, mid: this.currentMessageId, peerId: this.currentPeerId});\r\n this.openMedia(appMessagesManager.getMessageByPeer(target.peerId, target.mid), target.element, 1);\r\n };\r\n\r\n onForwardClick = () => {\r\n if(this.currentMessageId) {\r\n //appSidebarRight.forwardTab.open([this.currentMessageId]);\r\n new PopupForward(this.currentPeerId, [this.currentMessageId], () => {\r\n return this.close();\r\n });\r\n }\r\n };\r\n\r\n onAuthorClick = (e: MouseEvent) => {\r\n if(this.currentMessageId && this.currentMessageId !== Number.MAX_SAFE_INTEGER) {\r\n const mid = this.currentMessageId;\r\n const peerId = this.currentPeerId;\r\n const threadId = this.searchContext.threadId;\r\n this.close(e)\r\n //.then(() => mediaSizes.isMobile ? appSidebarRight.sharedMediaTab.closeBtn.click() : Promise.resolve())\r\n .then(() => {\r\n if(mediaSizes.isMobile) {\r\n const tab = appSidebarRight.getTab(AppSharedMediaTab);\r\n if(tab) {\r\n tab.close();\r\n }\r\n }\r\n\r\n const message = appMessagesManager.getMessageByPeer(peerId, mid);\r\n appImManager.setInnerPeer(message.peerId, mid, threadId ? 'discussion' : undefined, threadId);\r\n });\r\n }\r\n };\r\n\r\n onDownloadClick = () => {\r\n const message = appMessagesManager.getMessageByPeer(this.currentPeerId, this.currentMessageId);\r\n if(message.media.photo) {\r\n appPhotosManager.savePhotoFile(message.media.photo, appImManager.chat.bubbles.lazyLoadQueue.queueId);\r\n } else {\r\n let document: MyDocument = null;\r\n\r\n if(message.media.webpage) document = message.media.webpage.document;\r\n else document = message.media.document;\r\n\r\n if(document) {\r\n //console.log('will save document:', document);\r\n appDocsManager.saveDocFile(document, appImManager.chat.bubbles.lazyLoadQueue.queueId);\r\n }\r\n }\r\n };\r\n\r\n // нет смысла делать проверку для reverse и loadMediaPromise\r\n protected loadMoreMedia = (older = true) => {\r\n //if(!older && this.reverse) return;\r\n\r\n if(older && this.loadedAllMediaDown) return Promise.resolve();\r\n else if(!older && this.loadedAllMediaUp) return Promise.resolve();\r\n\r\n if(older && this.loadMediaPromiseDown) return this.loadMediaPromiseDown;\r\n else if(!older && this.loadMediaPromiseUp) return this.loadMediaPromiseUp;\r\n\r\n const loadCount = 50;\r\n const backLimit = older ? 0 : loadCount;\r\n let maxId = this.currentMessageId;\r\n \r\n let anchor: AppMediaViewerTargetType;\r\n if(older) {\r\n anchor = this.reverse ? this.prevTargets[0] : this.nextTargets[this.nextTargets.length - 1];\r\n } else {\r\n anchor = this.reverse ? this.nextTargets[this.nextTargets.length - 1] : this.prevTargets[0];\r\n }\r\n\r\n if(anchor) maxId = anchor.mid;\r\n if(!older) maxId = appMessagesManager.incrementMessageId(maxId, 1);\r\n\r\n const promise = appMessagesManager.getSearch({\r\n peerId: this.searchContext.peerId,\r\n query: this.searchContext.query,\r\n inputFilter: {\r\n _: this.searchContext.inputFilter\r\n },\r\n maxId,\r\n limit: backLimit ? 0 : loadCount,\r\n backLimit,\r\n threadId: this.searchContext.threadId,\r\n folderId: this.searchContext.folderId,\r\n nextRate: this.searchContext.nextRate,\r\n minDate: this.searchContext.minDate,\r\n maxDate: this.searchContext.maxDate\r\n }).then(value => {\r\n if(DEBUG) {\r\n this.log('loaded more media by maxId:', maxId, value, older, this.reverse);\r\n }\r\n\r\n if(value.next_rate) {\r\n this.searchContext.nextRate = value.next_rate;\r\n }\r\n\r\n if(value.history.length < loadCount) {\r\n /* if(this.reverse) {\r\n if(older) this.loadedAllMediaUp = true;\r\n else this.loadedAllMediaDown = true;\r\n } else { */\r\n if(older) this.loadedAllMediaDown = true;\r\n else this.loadedAllMediaUp = true;\r\n //}\r\n }\r\n\r\n const method: any = older ? value.history.forEach.bind(value.history) : forEachReverse.bind(null, value.history);\r\n method((message: Message.message) => {\r\n const {mid, peerId} = message;\r\n const media = this.getMediaFromMessage(message);\r\n\r\n if(!media) return;\r\n //if(media._ === 'document' && media.type !== 'video') return;\r\n\r\n const t = {element: null as HTMLElement, mid, peerId};\r\n if(older) {\r\n if(this.reverse) this.prevTargets.unshift(t);\r\n else this.nextTargets.push(t);\r\n } else {\r\n if(this.reverse) this.nextTargets.push(t);\r\n else this.prevTargets.unshift(t);\r\n }\r\n });\r\n\r\n this.buttons.prev.classList.toggle('hide', !this.prevTargets.length);\r\n this.buttons.next.classList.toggle('hide', !this.nextTargets.length);\r\n }, () => {}).then(() => {\r\n if(older) this.loadMediaPromiseDown = null;\r\n else this.loadMediaPromiseUp = null;\r\n });\r\n\r\n if(older) this.loadMediaPromiseDown = promise;\r\n else this.loadMediaPromiseUp = promise;\r\n\r\n return promise;\r\n };\r\n\r\n private getMediaFromMessage(message: any) {\r\n return message.action ? message.action.photo : message.media.photo \r\n || message.media.document \r\n || (message.media.webpage && (message.media.webpage.document || message.media.webpage.photo));\r\n }\r\n\r\n private setCaption(message: any) {\r\n const caption = message.message;\r\n this.content.caption.classList.toggle('hide', !caption);\r\n if(caption) {\r\n this.content.caption.firstElementChild.innerHTML = RichTextProcessor.wrapRichText(caption, {\r\n entities: message.totalEntities\r\n });\r\n } else {\r\n this.content.caption.firstElementChild.innerHTML = '';\r\n }\r\n }\r\n\r\n public setSearchContext(context: SearchSuperContext) {\r\n this.searchContext = context;\r\n\r\n if(this.searchContext.folderId !== undefined) {\r\n this.loadedAllMediaUp = true;\r\n\r\n if(this.searchContext.nextRate === undefined) {\r\n this.loadedAllMediaDown = true;\r\n }\r\n }\r\n\r\n return this;\r\n }\r\n\r\n public async openMedia(message: any, target?: HTMLElement, fromRight = 0, reverse = false, \r\n prevTargets: AppMediaViewer['prevTargets'] = [], nextTargets: AppMediaViewer['prevTargets'] = [], needLoadMore = true) {\r\n if(this.setMoverPromise) return this.setMoverPromise;\r\n\r\n const mid = message.mid;\r\n const fromId = message.fromId;\r\n const media = this.getMediaFromMessage(message);\r\n\r\n this.currentMessageId = mid;\r\n this.currentPeerId = message.peerId;\r\n const promise = super._openMedia(media, message.date, fromId, fromRight, target, reverse, prevTargets, nextTargets, needLoadMore);\r\n this.setCaption(message);\r\n\r\n return promise;\r\n }\r\n}\r\n\r\ntype AppMediaViewerAvatarTargetType = {element: HTMLElement, photoId: string};\r\nexport class AppMediaViewerAvatar extends AppMediaViewerBase<'', 'delete', AppMediaViewerAvatarTargetType> {\r\n public currentPhotoId: string;\r\n public peerId: number;\r\n\r\n constructor(peerId: number) {\r\n super([/* 'delete' */]);\r\n\r\n this.peerId = peerId;\r\n\r\n this.setBtnMenuToggle([{\r\n icon: 'download',\r\n text: 'MediaViewer.Context.Download',\r\n onClick: this.onDownloadClick\r\n }/* , {\r\n icon: 'delete danger btn-disabled',\r\n text: 'Delete',\r\n onClick: () => {}\r\n } */]);\r\n\r\n // * constructing html end\r\n \r\n this.setListeners();\r\n }\r\n\r\n onPrevClick = (target: AppMediaViewerAvatarTargetType) => {\r\n this.nextTargets.unshift({element: this.lastTarget, photoId: this.currentPhotoId});\r\n this.openMedia(target.photoId, target.element, -1);\r\n };\r\n\r\n onNextClick = (target: AppMediaViewerAvatarTargetType) => {\r\n this.prevTargets.push({element: this.lastTarget, photoId: this.currentPhotoId});\r\n this.openMedia(target.photoId, target.element, 1);\r\n };\r\n\r\n onDownloadClick = () => {\r\n appPhotosManager.savePhotoFile(appPhotosManager.getPhoto(this.currentPhotoId), appImManager.chat.bubbles.lazyLoadQueue.queueId);\r\n };\r\n\r\n protected loadMoreMedia = (older = true) => {\r\n if(this.peerId < 0) return Promise.resolve(); // ! это значит, что открыло аватар чата, но следующих фотографий нет.\r\n if(this.loadedAllMediaDown) return Promise.resolve();\r\n if(this.loadMediaPromiseDown) return this.loadMediaPromiseDown;\r\n\r\n const peerId = this.peerId;\r\n const loadCount = 50;\r\n\r\n const maxId = this.nextTargets.length ? this.nextTargets[this.nextTargets.length - 1].photoId : this.currentPhotoId;\r\n\r\n const promise = appPhotosManager.getUserPhotos(peerId, maxId, loadCount).then(value => {\r\n if(this.peerId !== peerId) {\r\n this.log.warn('peer changed');\r\n return;\r\n }\r\n\r\n // if(DEBUG) {\r\n // this.log('loaded more media by maxId:', /* maxId, */value, older, this.reverse);\r\n // }\r\n\r\n if(value.photos.length < loadCount) {\r\n this.loadedAllMediaDown = true;\r\n }\r\n\r\n value.photos.forEach(photoId => {\r\n if(this.currentPhotoId === photoId) return;\r\n this.nextTargets.push({element: null as HTMLElement, photoId: photoId});\r\n });\r\n\r\n this.buttons.prev.classList.toggle('hide', !this.prevTargets.length);\r\n this.buttons.next.classList.toggle('hide', !this.nextTargets.length);\r\n }, () => {}).then(() => {\r\n this.loadMediaPromiseDown = null;\r\n });\r\n\r\n return this.loadMediaPromiseDown = promise;\r\n };\r\n\r\n public async openMedia(photoId: string, target?: HTMLElement, fromRight = 0, prevTargets?: AppMediaViewerAvatarTargetType[], nextTargets?: AppMediaViewerAvatarTargetType[]) {\r\n if(this.setMoverPromise) return this.setMoverPromise;\r\n\r\n const photo = appPhotosManager.getPhoto(photoId);\r\n\r\n this.currentPhotoId = photo.id;\r\n \r\n return super._openMedia(photo, photo.date, this.peerId, fromRight, target, false, prevTargets, nextTargets);\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 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","/*\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 AppMediaViewer, { AppMediaViewerAvatar } from \"./appMediaViewer\";\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\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', onAvatarUpdate);\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,\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","/*\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 appMessagesManager, {Dialog} from \"../lib/appManagers/appMessagesManager\";\r\nimport appPeersManager from \"../lib/appManagers/appPeersManager\";\r\nimport rootScope from \"../lib/rootScope\";\r\nimport { positionMenu, openBtnMenu } from \"./misc\";\r\nimport ButtonMenu, { ButtonMenuItemOptions } from \"./buttonMenu\";\r\nimport PopupDeleteDialog from \"./popups/deleteDialog\";\r\nimport { i18n } from \"../lib/langPack\";\r\nimport findUpTag from \"../helpers/dom/findUpTag\";\r\nimport appNotificationsManager from \"../lib/appManagers/appNotificationsManager\";\r\nimport PopupPeer from \"./popups/peer\";\r\nimport AppChatFoldersTab from \"./sidebarLeft/tabs/chatFolders\";\r\nimport appSidebarLeft from \"./sidebarLeft\";\r\nimport { toastNew } from \"./toast\";\r\n\r\nexport default class DialogsContextMenu {\r\n private element: HTMLElement;\r\n private buttons: (ButtonMenuItemOptions & {verify: () => boolean})[];\r\n\r\n private selectedId: number;\r\n private filterId: number;\r\n private dialog: Dialog;\r\n\r\n private init() {\r\n this.buttons = [{\r\n icon: 'unread',\r\n text: 'MarkAsUnread',\r\n onClick: this.onUnreadClick,\r\n verify: () => {\r\n const isUnread = !!(this.dialog.pFlags?.unread_mark || this.dialog.unread_count);\r\n return !isUnread;\r\n }\r\n }, {\r\n icon: 'readchats',\r\n text: 'MarkAsRead',\r\n onClick: this.onUnreadClick,\r\n verify: () => { \r\n const isUnread = !!(this.dialog.pFlags?.unread_mark || this.dialog.unread_count);\r\n return isUnread;\r\n }\r\n }, {\r\n icon: 'pin',\r\n text: 'ChatList.Context.Pin',\r\n onClick: this.onPinClick,\r\n verify: () => {\r\n const isPinned = this.filterId > 1 ? appMessagesManager.filtersStorage.filters[this.filterId].pinned_peers.includes(this.dialog.peerId) : !!this.dialog.pFlags?.pinned;\r\n return !isPinned;\r\n }\r\n }, {\r\n icon: 'unpin',\r\n text: 'ChatList.Context.Unpin',\r\n onClick: this.onPinClick,\r\n verify: () => {\r\n const isPinned = this.filterId > 1 ? appMessagesManager.filtersStorage.filters[this.filterId].pinned_peers.includes(this.dialog.peerId) : !!this.dialog.pFlags?.pinned;\r\n return isPinned;\r\n }\r\n }, {\r\n icon: 'mute',\r\n text: 'ChatList.Context.Mute',\r\n onClick: this.onMuteClick,\r\n verify: () => {\r\n return this.selectedId !== rootScope.myId && !appNotificationsManager.isPeerLocalMuted(this.dialog.peerId); \r\n }\r\n }, {\r\n icon: 'unmute',\r\n text: 'ChatList.Context.Unmute',\r\n onClick: this.onUnmuteClick,\r\n verify: () => {\r\n return this.selectedId !== rootScope.myId && appNotificationsManager.isPeerLocalMuted(this.dialog.peerId); \r\n }\r\n }, {\r\n icon: 'archive',\r\n text: 'Archive',\r\n onClick: this.onArchiveClick,\r\n verify: () => this.filterId === 0 && this.selectedId !== rootScope.myId\r\n }, {\r\n icon: 'unarchive',\r\n text: 'Unarchive',\r\n onClick: this.onArchiveClick,\r\n verify: () => this.filterId === 1 && this.selectedId !== rootScope.myId\r\n }, {\r\n icon: 'delete danger',\r\n text: 'Delete',\r\n onClick: this.onDeleteClick,\r\n verify: () => true\r\n }];\r\n\r\n this.element = ButtonMenu(this.buttons);\r\n this.element.id = 'dialogs-contextmenu';\r\n this.element.classList.add('contextmenu');\r\n document.getElementById('page-chats').append(this.element);\r\n }\r\n\r\n private onArchiveClick = () => {\r\n let dialog = appMessagesManager.getDialogOnly(this.selectedId);\r\n if(dialog) {\r\n appMessagesManager.editPeerFolders([dialog.peerId], +!dialog.folder_id);\r\n }\r\n };\r\n\r\n private onPinClick = () => {\r\n appMessagesManager.toggleDialogPin(this.selectedId, this.filterId).catch(err => {\r\n if(err.type === 'PINNED_DIALOGS_TOO_MUCH') {\r\n if(this.filterId >= 1) {\r\n toastNew({langPackKey: 'PinFolderLimitReached'});\r\n } else {\r\n new PopupPeer('pinned-dialogs-too-much', {\r\n buttons: [{\r\n langKey: 'OK',\r\n isCancel: true\r\n }, {\r\n langKey: 'FiltersSetupPinAlert',\r\n callback: () => {\r\n new AppChatFoldersTab(appSidebarLeft).open();\r\n }\r\n }],\r\n descriptionLangKey: 'PinToTopLimitReached2',\r\n descriptionLangArgs: [i18n('Chats', [rootScope.config.pinned_dialogs_count_max])]\r\n }).show();\r\n }\r\n }\r\n });\r\n };\r\n\r\n private onUnmuteClick = () => {\r\n appMessagesManager.mutePeer(this.selectedId, false);\r\n };\r\n \r\n private onMuteClick = () => {\r\n appMessagesManager.mutePeer(this.selectedId, true);\r\n };\r\n\r\n private onUnreadClick = () => {\r\n const dialog = appMessagesManager.getDialogOnly(this.selectedId);\r\n if(!dialog) return;\r\n\r\n if(dialog.unread_count) {\r\n appMessagesManager.readHistory(this.selectedId, dialog.top_message);\r\n appMessagesManager.markDialogUnread(this.selectedId, true);\r\n } else {\r\n appMessagesManager.markDialogUnread(this.selectedId);\r\n }\r\n };\r\n\r\n private onDeleteClick = () => {\r\n new PopupDeleteDialog(this.selectedId);\r\n };\r\n\r\n onContextMenu = (e: MouseEvent | Touch) => {\r\n if(this.init) {\r\n this.init();\r\n this.init = null;\r\n }\r\n\r\n let li: HTMLElement = null;\r\n \r\n try {\r\n li = findUpTag(e.target, 'LI');\r\n } catch(e) {}\r\n \r\n if(!li) return;\r\n\r\n if(e instanceof MouseEvent) e.preventDefault();\r\n if(this.element.classList.contains('active')) {\r\n return false;\r\n }\r\n if(e instanceof MouseEvent) e.cancelBubble = true;\r\n\r\n this.filterId = appDialogsManager.filterId;\r\n\r\n this.selectedId = +li.dataset.peerId;\r\n this.dialog = appMessagesManager.getDialogOnly(this.selectedId);\r\n\r\n this.buttons.forEach(button => {\r\n const good = button.verify();\r\n\r\n button.element.classList.toggle('hide', !good);\r\n });\r\n\r\n // delete button\r\n this.buttons[this.buttons.length - 1].element.lastChild.replaceWith(i18n(appPeersManager.getDeleteButtonText(this.selectedId)));\r\n\r\n li.classList.add('menu-open');\r\n positionMenu(e, this.element);\r\n openBtnMenu(this.element, () => {\r\n li.classList.remove('menu-open');\r\n this.selectedId = this.dialog = this.filterId = undefined;\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 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","/*\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","/*\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 AvatarElement from \"../../components/avatar\";\r\nimport DialogsContextMenu from \"../../components/dialogsContextMenu\";\r\nimport { horizontalMenu } from \"../../components/horizontalMenu\";\r\nimport { attachContextMenuListener, putPreloader } from \"../../components/misc\";\r\nimport { ripple } from \"../../components/ripple\";\r\n//import Scrollable from \"../../components/scrollable\";\r\nimport Scrollable, { ScrollableX, SliceSides } from \"../../components/scrollable\";\r\nimport { formatDateAccordingToTodayNew } from \"../../helpers/date\";\r\nimport { isSafari } from \"../../helpers/userAgent\";\r\nimport { logger, LogTypes } from \"../logger\";\r\nimport { RichTextProcessor } from \"../richtextprocessor\";\r\nimport rootScope from \"../rootScope\";\r\nimport apiUpdatesManager from \"./apiUpdatesManager\";\r\nimport appPeersManager from './appPeersManager';\r\nimport appImManager from \"./appImManager\";\r\nimport appMessagesManager, { Dialog } from \"./appMessagesManager\";\r\nimport {MyDialogFilter as DialogFilter} from \"../storages/filters\";\r\nimport appStateManager, { State } from \"./appStateManager\";\r\nimport appUsersManager from \"./appUsersManager\";\r\nimport Button from \"../../components/button\";\r\nimport SetTransition from \"../../components/singleTransition\";\r\nimport appDraftsManager, { MyDraftMessage } from \"./appDraftsManager\";\r\nimport DEBUG, { MOUNT_CLASS_TO } from \"../../config/debug\";\r\nimport appNotificationsManager from \"./appNotificationsManager\";\r\nimport PeerTitle from \"../../components/peerTitle\";\r\nimport I18n, { FormatterArguments, i18n, LangPackKey, _i18n } from \"../langPack\";\r\nimport findUpTag from \"../../helpers/dom/findUpTag\";\r\nimport { LazyLoadQueueIntersector } from \"../../components/lazyLoadQueue\";\r\nimport lottieLoader from \"../lottieLoader\";\r\nimport { wrapLocalSticker } from \"../../components/wrappers\";\r\nimport AppEditFolderTab from \"../../components/sidebarLeft/tabs/editFolder\";\r\nimport appSidebarLeft from \"../../components/sidebarLeft\";\r\nimport { attachClickEvent } from \"../../helpers/dom/clickEvent\";\r\nimport positionElementByIndex from \"../../helpers/dom/positionElementByIndex\";\r\nimport replaceContent from \"../../helpers/dom/replaceContent\";\r\nimport ConnectionStatusComponent from \"../../components/connectionStatus\";\r\nimport appChatsManager from \"./appChatsManager\";\r\nimport { renderImageFromUrlPromise } from \"../../helpers/dom/renderImageFromUrl\";\r\nimport { fastRafPromise } from \"../../helpers/schedulers\";\r\n\r\nexport type DialogDom = {\r\n avatarEl: AvatarElement,\r\n captionDiv: HTMLDivElement,\r\n titleSpan: HTMLSpanElement,\r\n titleSpanContainer: HTMLSpanElement,\r\n statusSpan: HTMLSpanElement,\r\n lastTimeSpan: HTMLSpanElement,\r\n unreadMessagesSpan: HTMLSpanElement,\r\n lastMessageSpan: HTMLSpanElement,\r\n containerEl: HTMLElement,\r\n listEl: HTMLLIElement,\r\n muteAnimationTimeout?: number\r\n};\r\n\r\n//const testScroll = false;\r\n//let testTopSlice = 1;\r\n\r\nexport class AppDialogsManager {\r\n private chatList: HTMLUListElement;\r\n\r\n private doms: {[peerId: number]: DialogDom} = {};\r\n\r\n private chatsContainer = document.getElementById('chatlist-container') as HTMLDivElement;\r\n private chatsPreloader: HTMLElement;\r\n\r\n private loadDialogsPromise: Promise<any>;\r\n\r\n private scroll: Scrollable = null;\r\n \r\n private log = logger('DIALOGS', LogTypes.Log | LogTypes.Error | LogTypes.Warn | LogTypes.Debug);\r\n\r\n private contextMenu = new DialogsContextMenu();\r\n\r\n public chatLists: {[filterId: number]: HTMLUListElement} = {};\r\n public scrollables: {[filterId: number]: Scrollable} = {};\r\n public filterId: number;\r\n private folders: {[k in 'menu' | 'container' | 'menuScrollContainer']: HTMLElement} = {\r\n menu: document.getElementById('folders-tabs'),\r\n menuScrollContainer: null,\r\n container: document.getElementById('folders-container')\r\n };\r\n private filtersRendered: {\r\n [filterId: string]: {\r\n menu: HTMLElement, \r\n container: HTMLElement,\r\n unread: HTMLElement,\r\n title: HTMLElement\r\n }\r\n } = {};\r\n private showFiltersPromise: Promise<void>;\r\n private allUnreadCount: HTMLElement;\r\n\r\n private accumulateArchivedTimeout: number;\r\n\r\n //private topOffsetIndex = 0;\r\n\r\n private sliceTimeout: number;\r\n private reorderDialogsTimeout: number;\r\n\r\n private lastActiveElements: Set<HTMLElement> = new Set();\r\n\r\n private offsets: {top: number, bottom: number} = {top: 0, bottom: 0};\r\n\r\n constructor() {\r\n this.chatsPreloader = putPreloader(null, true);\r\n\r\n this.allUnreadCount = this.folders.menu.querySelector('.badge');\r\n \r\n this.folders.menuScrollContainer = this.folders.menu.parentElement;\r\n\r\n const bottomPart = document.createElement('div');\r\n bottomPart.classList.add('connection-status-bottom');\r\n bottomPart.append(this.folders.container);\r\n\r\n /* if(isTouchSupported && isSafari) {\r\n let allowUp: boolean, allowDown: boolean, slideBeginY: number;\r\n const container = this.scroll.container;\r\n container.addEventListener('touchstart', (event) => {\r\n allowUp = container.scrollTop > 0;\r\n allowDown = (container.scrollTop < container.scrollHeight - container.clientHeight);\r\n // @ts-ignore\r\n slideBeginY = event.pageY;\r\n });\r\n \r\n container.addEventListener('touchmove', (event: any) => {\r\n var up = (event.pageY > slideBeginY);\r\n var down = (event.pageY < slideBeginY);\r\n slideBeginY = event.pageY;\r\n if((up && allowUp) || (down && allowDown)) {\r\n event.stopPropagation();\r\n } else if(up || down) {\r\n event.preventDefault();\r\n }\r\n });\r\n } */\r\n\r\n this.filterId = 0;\r\n this.addFilter({\r\n id: this.filterId,\r\n title: '',\r\n titleEl: i18n('ChatList.Filter.AllChats'),\r\n orderIndex: 0\r\n });\r\n\r\n this.chatList = this.chatLists[this.filterId];\r\n this.scroll = this.scrollables[this.filterId];\r\n\r\n /* if(testScroll) {\r\n let i = 0;\r\n let add = () => {\r\n let li = document.createElement('li');\r\n li.dataset.id = '' + i;\r\n li.id = '' + i;\r\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>`;\r\n i++;\r\n this.scroll.append(li);\r\n };\r\n for(let i = 0; i < 500; ++i) {\r\n add();\r\n }\r\n (window as any).addElement = add;\r\n } */\r\n\r\n rootScope.addEventListener('user_update', (userId) => {\r\n //console.log('updating user:', user, dialog);\r\n \r\n const dom = this.getDialogDom(userId);\r\n if(dom && !appUsersManager.isBot(userId) && userId !== rootScope.myId) {\r\n const user = appUsersManager.getUser(userId);\r\n const online = user.status?._ === 'userStatusOnline';\r\n dom.avatarEl.classList.toggle('is-online', online);\r\n }\r\n });\r\n\r\n /* rootScope.$on('dialog_top', (e) => {\r\n const dialog = e;\r\n\r\n this.setLastMessage(dialog);\r\n this.setDialogPosition(dialog);\r\n\r\n this.setFiltersUnreadCount();\r\n }); */\r\n\r\n rootScope.addEventListener('dialog_flush', (e) => {\r\n const peerId: number = e.peerId;\r\n const dialog = appMessagesManager.getDialogOnly(peerId);\r\n if(dialog) {\r\n this.setLastMessage(dialog);\r\n this.validateForFilter();\r\n this.setFiltersUnreadCount();\r\n }\r\n });\r\n\r\n rootScope.addEventListener('dialogs_multiupdate', (e) => {\r\n const dialogs = e;\r\n\r\n for(const id in dialogs) {\r\n const dialog = dialogs[id];\r\n this.updateDialog(dialog);\r\n }\r\n\r\n this.validateForFilter();\r\n this.setFiltersUnreadCount();\r\n });\r\n\r\n rootScope.addEventListener('dialog_drop', (e) => {\r\n const {peerId} = e;\r\n\r\n this.deleteDialog(peerId);\r\n this.setFiltersUnreadCount();\r\n });\r\n\r\n rootScope.addEventListener('dialog_unread', (e) => {\r\n const info = e;\r\n\r\n const dialog = appMessagesManager.getDialogOnly(info.peerId);\r\n if(dialog) {\r\n this.setUnreadMessages(dialog);\r\n this.validateForFilter();\r\n this.setFiltersUnreadCount();\r\n }\r\n });\r\n\r\n rootScope.addEventListener('dialog_notify_settings', (dialog) => {\r\n this.setUnreadMessages(dialog); // возможно это не нужно, но нужно менять is-muted\r\n });\r\n\r\n rootScope.addEventListener('dialog_draft', (e) => {\r\n const dialog = appMessagesManager.getDialogOnly(e.peerId);\r\n if(dialog) {\r\n this.updateDialog(dialog);\r\n }\r\n });\r\n\r\n rootScope.addEventListener('peer_changed', (e) => {\r\n const peerId = e;\r\n\r\n //const perf = performance.now();\r\n for(const element of this.lastActiveElements) {\r\n if(+element.dataset.peerId !== peerId) {\r\n element.classList.remove('active');\r\n this.lastActiveElements.delete(element);\r\n }\r\n }\r\n\r\n const elements = Array.from(document.querySelectorAll(`[data-autonomous=\"0\"] li[data-peer-id=\"${peerId}\"]`)) as HTMLElement[];\r\n elements.forEach(element => {\r\n element.classList.add('active');\r\n this.lastActiveElements.add(element);\r\n });\r\n //this.log('peer_changed total time:', performance.now() - perf);\r\n });\r\n\r\n rootScope.addEventListener('filter_update', (e) => {\r\n const filter: DialogFilter = e;\r\n if(!this.filtersRendered[filter.id]) {\r\n this.addFilter(filter);\r\n return;\r\n } else if(filter.id === this.filterId) { // это нет тут смысла вызывать, так как будет dialogs_multiupdate\r\n //this.validateForFilter();\r\n const folder = appMessagesManager.dialogsStorage.getFolder(filter.id);\r\n this.validateForFilter();\r\n for(let i = 0, length = folder.length; i < length; ++i) {\r\n const dialog = folder[i];\r\n this.updateDialog(dialog);\r\n }\r\n this.setFiltersUnreadCount();\r\n }\r\n\r\n const elements = this.filtersRendered[filter.id];\r\n elements.title.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);\r\n });\r\n\r\n rootScope.addEventListener('filter_delete', (e) => {\r\n const filter: DialogFilter = e;\r\n const elements = this.filtersRendered[filter.id];\r\n if(!elements) return;\r\n\r\n // set tab\r\n //(this.folders.menu.firstElementChild.children[Math.max(0, filter.id - 2)] as HTMLElement).click();\r\n (this.folders.menu.firstElementChild as HTMLElement).click();\r\n\r\n elements.container.remove();\r\n elements.menu.remove();\r\n \r\n delete this.chatLists[filter.id];\r\n delete this.scrollables[filter.id];\r\n delete this.filtersRendered[filter.id];\r\n\r\n if(Object.keys(this.filtersRendered).length <= 1) {\r\n this.folders.menuScrollContainer.classList.add('hide');\r\n }\r\n });\r\n\r\n rootScope.addEventListener('filter_order', (e) => {\r\n const order = e;\r\n \r\n const containerToAppend = this.folders.menu as HTMLElement;\r\n order.forEach((filterId) => {\r\n const filter = appMessagesManager.filtersStorage.filters[filterId];\r\n const renderedFilter = this.filtersRendered[filterId];\r\n\r\n positionElementByIndex(renderedFilter.menu, containerToAppend, filter.orderIndex);\r\n positionElementByIndex(renderedFilter.container, this.folders.container, filter.orderIndex);\r\n });\r\n\r\n /* if(this.filterId) {\r\n const tabIndex = order.indexOf(this.filterId) + 1;\r\n selectTab.prevId = tabIndex;\r\n } */\r\n });\r\n\r\n rootScope.addEventListener('peer_typings', (e) => {\r\n const {peerId, typings} = e;\r\n\r\n const dialog = appMessagesManager.getDialogOnly(peerId);\r\n if(!dialog) return;\r\n\r\n if(typings.length) {\r\n this.setTyping(dialog);\r\n } else {\r\n this.unsetTyping(dialog);\r\n }\r\n });\r\n\r\n rootScope.addEventListener('state_cleared', () => {\r\n //setTimeout(() => \r\n appStateManager.getState().then((state) => {\r\n appUsersManager.clear();\r\n appChatsManager.clear();\r\n \r\n const filtersStorage = appMessagesManager.filtersStorage;\r\n const filters = filtersStorage.filters;\r\n for(const filterId in filters) { // delete filters\r\n rootScope.dispatchEvent('updateDialogFilter', {\r\n _: 'updateDialogFilter',\r\n id: +filterId,\r\n });\r\n }\r\n\r\n appMessagesManager.clear();\r\n\r\n /* const clearPromises: Promise<any>[] = [];\r\n for(const name in appStateManager.storagesResults) {\r\n const results = appStateManager.storagesResults[name as keyof AppStateManager['storages']];\r\n const storage = appStateManager.storages[name as keyof AppStateManager['storages']];\r\n results.length = 0;\r\n clearPromises.push(storage.clear());\r\n } */\r\n\r\n this.validateForFilter();\r\n\r\n this.onStateLoaded(state);\r\n })//, 5000);\r\n });\r\n\r\n const foldersScrollable = new ScrollableX(this.folders.menuScrollContainer);\r\n bottomPart.prepend(this.folders.menuScrollContainer);\r\n const selectTab = horizontalMenu(this.folders.menu, this.folders.container, (id, tabContent) => {\r\n /* if(id !== 0) {\r\n id += 1;\r\n } */\r\n\r\n id = +tabContent.dataset.filterId || 0;\r\n\r\n if(this.filterId === id) return;\r\n\r\n this.chatLists[id].innerHTML = '';\r\n this.filterId = id;\r\n this.onTabChange();\r\n }, () => {\r\n for(const folderId in this.chatLists) {\r\n if(+folderId !== this.filterId) {\r\n this.chatLists[folderId].innerHTML = '';\r\n }\r\n }\r\n }, undefined, foldersScrollable);\r\n\r\n //selectTab(0);\r\n (this.folders.menu.firstElementChild as HTMLElement).click();\r\n appMessagesManager.construct();\r\n appStateManager.getState().then((state) => {\r\n return this.onStateLoaded(state);\r\n }).then(() => {\r\n //return;\r\n \r\n const isLoadedMain = appMessagesManager.dialogsStorage.isDialogsLoaded(0);\r\n const isLoadedArchive = appMessagesManager.dialogsStorage.isDialogsLoaded(1);\r\n const wasLoaded = isLoadedMain || isLoadedArchive;\r\n const a: Promise<any> = isLoadedMain ? Promise.resolve() : appMessagesManager.getConversationsAll('', 0);\r\n const b: Promise<any> = isLoadedArchive ? Promise.resolve() : appMessagesManager.getConversationsAll('', 1);\r\n a.finally(() => {\r\n b.then(() => {\r\n this.accumulateArchivedUnread();\r\n\r\n if(wasLoaded) {\r\n (apiUpdatesManager.updatesState.syncLoading || Promise.resolve()).then(() => {\r\n appMessagesManager.refreshConversations();\r\n });\r\n }\r\n });\r\n });\r\n });\r\n\r\n new ConnectionStatusComponent(this.chatsContainer);\r\n this.chatsContainer.append(bottomPart);\r\n\r\n setTimeout(() => {\r\n lottieLoader.loadLottieWorkers();\r\n }, 200);\r\n }\r\n\r\n private async onStateLoaded(state: State) {\r\n appNotificationsManager.getNotifyPeerTypeSettings();\r\n \r\n const renderFiltersPromise = appMessagesManager.filtersStorage.getDialogFilters().then((filters) => {\r\n for(const filter of filters) {\r\n this.addFilter(filter);\r\n }\r\n });\r\n\r\n if(state.filters && Object.keys(state.filters).length) {\r\n await renderFiltersPromise;\r\n if(this.showFiltersPromise) {\r\n await this.showFiltersPromise;\r\n }\r\n }\r\n\r\n if(appStateManager.storagesResults.dialogs.length) {\r\n appDraftsManager.addMissedDialogs();\r\n }\r\n\r\n return this.loadDialogs();\r\n }\r\n\r\n /* private getOffset(side: 'top' | 'bottom'): {index: number, pos: number} {\r\n if(!this.scroll.loadedAll[side]) {\r\n const element = (side === 'top' ? this.chatList.firstElementChild : this.chatList.lastElementChild) as HTMLElement;\r\n if(element) {\r\n const peerId = +element.dataset.peerId;\r\n const dialog = appMessagesManager.getDialogByPeerId(peerId);\r\n return {index: dialog[0].index, pos: dialog[1]};\r\n }\r\n }\r\n\r\n return {index: 0, pos: -1};\r\n } */\r\n private getOffsetIndex(side: 'top' | 'bottom') {\r\n return {index: this.scroll.loadedAll[side] ? 0 : this.offsets[side]};\r\n }\r\n\r\n private isDialogMustBeInViewport(dialog: Dialog) {\r\n if(dialog.migratedTo !== undefined) return false;\r\n //return true;\r\n const topOffset = this.getOffsetIndex('top');\r\n const bottomOffset = this.getOffsetIndex('bottom');\r\n \r\n if(!topOffset.index && !bottomOffset.index) {\r\n return true;\r\n }\r\n \r\n const index = dialog.index;\r\n return (!topOffset.index || index <= topOffset.index) && (!bottomOffset.index || index >= bottomOffset.index);\r\n }\r\n\r\n private deleteDialog(peerId: number) {\r\n const dom = this.getDialogDom(peerId);\r\n if(dom) {\r\n dom.listEl.remove();\r\n delete this.doms[peerId];\r\n\r\n this.onListLengthChange();\r\n\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n private updateDialog(dialog: Dialog) {\r\n if(!dialog) {\r\n return;\r\n }\r\n\r\n if(this.isDialogMustBeInViewport(dialog)) {\r\n if(!this.doms.hasOwnProperty(dialog.peerId)) {\r\n const ret = this.addDialogNew({dialog});\r\n if(ret) {\r\n const idx = appMessagesManager.getDialogByPeerId(dialog.peerId)[1];\r\n positionElementByIndex(ret.dom.listEl, this.chatList, idx);\r\n this.onListLengthChange();\r\n } else {\r\n return;\r\n }\r\n }\r\n } else {\r\n this.deleteDialog(dialog.peerId);\r\n return;\r\n }\r\n\r\n /* const topOffset = this.getOffset('top');\r\n if(topOffset.index && dialog.index > topOffset.index) {\r\n const dom = this.getDialogDom(dialog.peerId);\r\n if(dom) {\r\n dom.listEl.remove();\r\n delete this.doms[dialog.peerId];\r\n }\r\n\r\n return;\r\n }\r\n\r\n if(!this.doms.hasOwnProperty(dialog.peerId)) {\r\n this.addDialogNew({dialog});\r\n } */\r\n\r\n if(this.getDialogDom(dialog.peerId)) {\r\n this.setLastMessage(dialog);\r\n this.reorderDialogs();\r\n }\r\n }\r\n\r\n public onTabChange = () => {\r\n this.doms = {};\r\n this.scroll = this.scrollables[this.filterId];\r\n this.scroll.loadedAll.top = true;\r\n this.scroll.loadedAll.bottom = false;\r\n this.offsets.top = this.offsets.bottom = 0;\r\n this.loadDialogsPromise = undefined;\r\n this.chatList = this.chatLists[this.filterId];\r\n this.loadDialogs();\r\n };\r\n\r\n private setFilterUnreadCount(filterId: number, folder?: Dialog[]) {\r\n const unreadSpan = filterId === 0 ? this.allUnreadCount : this.filtersRendered[filterId]?.unread;\r\n if(!unreadSpan) {\r\n return;\r\n }\r\n\r\n folder = folder || appMessagesManager.dialogsStorage.getFolder(filterId);\r\n let mutedCount = 0;\r\n let notMutedCount = 0;\r\n folder.forEach(dialog => {\r\n const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);\r\n\r\n if(isMuted && filterId === 0) {\r\n return;\r\n }\r\n\r\n const value = +!!dialog.unread_count || +dialog.pFlags.unread_mark || 0; // * unread_mark can be undefined\r\n if(isMuted) mutedCount += value;\r\n else notMutedCount += value;\r\n });\r\n \r\n unreadSpan.classList.toggle('badge-gray', mutedCount && !notMutedCount);\r\n \r\n const sum = mutedCount + notMutedCount;\r\n unreadSpan.innerText = sum ? '' + sum : '';\r\n }\r\n\r\n private setFiltersUnreadCount() {\r\n for(const filterId in this.filtersRendered) {\r\n this.setFilterUnreadCount(+filterId);\r\n }\r\n\r\n this.setFilterUnreadCount(0);\r\n }\r\n\r\n /**\r\n * Удалит неподходящие чаты из списка, но не добавит их(!)\r\n */\r\n private validateForFilter() {\r\n // !WARNING, возможно это было зачем-то, но комментарий исправил архивирование\r\n //if(this.filterId === 0) return;\r\n\r\n const folder = appMessagesManager.dialogsStorage.getFolder(this.filterId);\r\n for(const _peerId in this.doms) {\r\n const peerId = +_peerId;\r\n\r\n // если больше не подходит по фильтру, удаляем\r\n if(folder.findIndex((dialog) => dialog.peerId === peerId) === -1) {\r\n this.deleteDialog(peerId);\r\n }\r\n }\r\n }\r\n\r\n public generateScrollable(list: HTMLUListElement, filterId: number) {\r\n const scrollable = new Scrollable(null, 'CL', 500);\r\n scrollable.container.addEventListener('scroll', this.onChatsRegularScroll);\r\n scrollable.container.dataset.filterId = '' + filterId;\r\n scrollable.container.append(list);\r\n scrollable.onScrolledTop = this.onChatsScrollTop;\r\n scrollable.onScrolledBottom = this.onChatsScroll;\r\n scrollable.setVirtualContainer(list);\r\n\r\n this.chatLists[filterId] = list;\r\n this.scrollables[filterId] = scrollable;\r\n\r\n return scrollable;\r\n }\r\n\r\n private addFilter(filter: Pick<DialogFilter, 'title' | 'id' | 'orderIndex'> & Partial<{titleEl: HTMLElement}>) {\r\n if(this.filtersRendered[filter.id]) return;\r\n\r\n const menuTab = document.createElement('div');\r\n menuTab.classList.add('menu-horizontal-div-item');\r\n const span = document.createElement('span');\r\n const titleSpan = document.createElement('span');\r\n titleSpan.classList.add('text-super');\r\n if(filter.titleEl) titleSpan.append(filter.titleEl);\r\n else titleSpan.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);\r\n const unreadSpan = document.createElement('div');\r\n unreadSpan.classList.add('badge', 'badge-20', 'badge-primary');\r\n const i = document.createElement('i');\r\n span.append(titleSpan, unreadSpan, i);\r\n menuTab.append(span);\r\n ripple(menuTab);\r\n\r\n const containerToAppend = this.folders.menu as HTMLElement;\r\n positionElementByIndex(menuTab, containerToAppend, filter.orderIndex);\r\n //containerToAppend.append(li);\r\n\r\n const ul = this.createChatList();\r\n const scrollable = this.generateScrollable(ul, filter.id);\r\n const div = scrollable.container;\r\n //this.folders.container.append(div);\r\n positionElementByIndex(scrollable.container, this.folders.container, filter.orderIndex);\r\n\r\n this.setListClickListener(ul, null, true);\r\n\r\n this.filtersRendered[filter.id] = {\r\n menu: menuTab,\r\n container: div,\r\n unread: unreadSpan,\r\n title: titleSpan\r\n };\r\n\r\n if(!this.showFiltersPromise && Object.keys(this.filtersRendered).length > 1) {\r\n this.showFiltersPromise = new Promise<void>((resolve) => {\r\n window.setTimeout(() => {\r\n this.showFiltersPromise = undefined;\r\n if(Object.keys(this.filtersRendered).length > 1) {\r\n this.folders.menuScrollContainer.classList.remove('hide');\r\n this.setFiltersUnreadCount();\r\n }\r\n resolve();\r\n }, 0);\r\n });\r\n }\r\n }\r\n\r\n private loadDialogs(side: SliceSides = 'bottom') {\r\n /* if(testScroll) {\r\n return;\r\n } */\r\n \r\n if(this.loadDialogsPromise/* || 1 === 1 */) return this.loadDialogsPromise;\r\n\r\n const promise = new Promise<void>(async(resolve) => {\r\n if(!this.chatList.childElementCount) {\r\n const container = this.chatList.parentElement;\r\n container.append(this.chatsPreloader);\r\n }\r\n \r\n //return;\r\n \r\n const filterId = this.filterId;\r\n let loadCount = 30/*this.chatsLoadCount */;\r\n let offsetIndex = 0;\r\n \r\n const {index: currentOffsetIndex} = this.getOffsetIndex(side);\r\n if(currentOffsetIndex) {\r\n if(side === 'top') {\r\n const storage = appMessagesManager.dialogsStorage.getFolder(filterId);\r\n const index = storage.findIndex(dialog => dialog.index <= currentOffsetIndex);\r\n const needIndex = Math.max(0, index - loadCount);\r\n loadCount = index - needIndex;\r\n offsetIndex = storage[needIndex].index + 1;\r\n } else {\r\n offsetIndex = currentOffsetIndex;\r\n }\r\n }\r\n \r\n //let offset = storage[storage.length - 1]?.index || 0;\r\n \r\n try {\r\n //console.time('getDialogs time');\r\n \r\n const getConversationPromise = (this.filterId > 1 ? appUsersManager.getContacts() as Promise<any> : Promise.resolve()).then(() => {\r\n return appMessagesManager.getConversations('', offsetIndex, loadCount, filterId);\r\n });\r\n \r\n const result = await getConversationPromise;\r\n \r\n if(this.loadDialogsPromise !== promise) {\r\n return;\r\n }\r\n \r\n //console.timeEnd('getDialogs time');\r\n \r\n // * loaded all\r\n //if(!result.dialogs.length || this.chatList.childElementCount === result.count) {\r\n // !result.dialogs.length не подходит, так как при супердревном диалоге getConversations его не выдаст.\r\n //if(this.chatList.childElementCount === result.count) {\r\n if(side === 'bottom') {\r\n if(result.isEnd) {\r\n this.scroll.loadedAll[side] = true;\r\n }\r\n } else {\r\n const storage = appMessagesManager.dialogsStorage.getFolder(filterId);\r\n if(!result.dialogs.length || (storage.length && storage[0].index < offsetIndex)) {\r\n this.scroll.loadedAll[side] = true;\r\n }\r\n }\r\n \r\n if(result.dialogs.length) {\r\n const dialogs = side === 'top' ? result.dialogs.slice().reverse() : result.dialogs;\r\n \r\n dialogs.forEach((dialog) => {\r\n this.addDialogNew({\r\n dialog,\r\n append: side === 'bottom'\r\n });\r\n });\r\n }\r\n\r\n const offsetDialog = result.dialogs[side === 'top' ? 0 : result.dialogs.length - 1];\r\n if(offsetDialog) {\r\n this.offsets[side] = offsetDialog.index;\r\n }\r\n\r\n this.onListLengthChange();\r\n \r\n this.log.debug('getDialogs ' + loadCount + ' dialogs by offset:', offsetIndex, result, this.chatList.childElementCount);\r\n \r\n setTimeout(() => {\r\n this.scroll.onScroll();\r\n }, 0);\r\n } catch(err) {\r\n this.log.error(err);\r\n }\r\n \r\n this.chatsPreloader.remove();\r\n resolve();\r\n }).finally(() => {\r\n this.loadDialogsPromise = undefined;\r\n });\r\n\r\n return this.loadDialogsPromise = promise;\r\n }\r\n\r\n private generateEmptyPlaceholder(options: {\r\n title: LangPackKey,\r\n subtitle?: LangPackKey,\r\n subtitleArgs?: FormatterArguments,\r\n classNameType: string\r\n }) {\r\n const BASE_CLASS = 'empty-placeholder';\r\n const container = document.createElement('div');\r\n container.classList.add(BASE_CLASS, BASE_CLASS + '-' + options.classNameType);\r\n \r\n const header = document.createElement('div');\r\n header.classList.add(BASE_CLASS + '-header');\r\n _i18n(header, options.title);\r\n\r\n const subtitle = document.createElement('div');\r\n subtitle.classList.add(BASE_CLASS + '-subtitle');\r\n if(options.subtitle) {\r\n _i18n(subtitle, options.subtitle, options.subtitleArgs);\r\n }\r\n\r\n container.append(header, subtitle);\r\n\r\n return {container, header, subtitle};\r\n }\r\n\r\n private onListLengthChange = () => {\r\n //return;\r\n if(this.filterId === 1) {\r\n return;\r\n }\r\n\r\n let placeholderContainer = (Array.from(this.chatList.parentElement.children) as HTMLElement[]).find(el => el.matches('.empty-placeholder'));\r\n const needPlaceholder = this.scroll.loadedAll.bottom && !this.chatList.childElementCount/* || true */;\r\n // this.chatList.style.display = 'none';\r\n\r\n if(needPlaceholder && placeholderContainer) {\r\n return;\r\n } else if(!needPlaceholder) {\r\n if(placeholderContainer) {\r\n placeholderContainer.remove();\r\n }\r\n\r\n return;\r\n }\r\n\r\n let placeholder: ReturnType<AppDialogsManager['generateEmptyPlaceholder']>;\r\n if(!this.filterId) {\r\n placeholder = this.generateEmptyPlaceholder({\r\n title: 'ChatList.Main.EmptyPlaceholder.Title',\r\n classNameType: 'dialogs'\r\n });\r\n \r\n placeholderContainer = placeholder.container;\r\n \r\n const img = document.createElement('img');\r\n img.classList.add('empty-placeholder-dialogs-icon');\r\n \r\n Promise.all([\r\n appUsersManager.getContacts().then(users => {\r\n let key: LangPackKey, args: FormatterArguments;\r\n\r\n if(users.length) {\r\n key = 'ChatList.Main.EmptyPlaceholder.Subtitle';\r\n args = [i18n('Contacts.Count', [users.length])];\r\n } else {\r\n key = 'ChatList.Main.EmptyPlaceholder.SubtitleNoContacts';\r\n args = [];\r\n }\r\n\r\n const subtitleEl = new I18n.IntlElement({\r\n key,\r\n args,\r\n element: placeholder.subtitle\r\n });\r\n }),\r\n renderImageFromUrlPromise(img, 'assets/img/EmptyChats.svg'),\r\n fastRafPromise()\r\n ]).then(() => {\r\n placeholderContainer.classList.add('visible');\r\n });\r\n\r\n placeholderContainer.prepend(img);\r\n } else {\r\n placeholder = this.generateEmptyPlaceholder({\r\n title: 'FilterNoChatsToDisplay',\r\n subtitle: 'FilterNoChatsToDisplayInfo',\r\n classNameType: 'folder'\r\n });\r\n\r\n placeholderContainer = placeholder.container;\r\n\r\n placeholderContainer.prepend(wrapLocalSticker({\r\n emoji: '📂',\r\n width: 128,\r\n height: 128\r\n }).container)\r\n\r\n const button = Button('btn-primary btn-color-primary btn-control tgico', {\r\n text: 'FilterHeaderEdit',\r\n icon: 'settings'\r\n });\r\n\r\n attachClickEvent(button, () => {\r\n new AppEditFolderTab(appSidebarLeft).open(appMessagesManager.filtersStorage.filters[this.filterId]);\r\n });\r\n\r\n placeholderContainer.append(button);\r\n }\r\n\r\n this.chatList.parentElement.append(placeholderContainer);\r\n };\r\n\r\n public onChatsRegularScroll = () => {\r\n if(this.sliceTimeout) clearTimeout(this.sliceTimeout);\r\n this.sliceTimeout = window.setTimeout(() => {\r\n this.sliceTimeout = undefined;\r\n \r\n if(this.reorderDialogsTimeout) {\r\n this.onChatsRegularScroll();\r\n return;\r\n }\r\n\r\n if(!this.chatList.childElementCount) {\r\n return;\r\n }\r\n\r\n /* const observer = new IntersectionObserver((entries) => {\r\n const \r\n });\r\n\r\n Array.from(this.chatList.children).forEach(el => {\r\n observer.observe(el);\r\n }); */\r\n\r\n const scrollTopWas = this.scroll.scrollTop;\r\n\r\n const firstElementChild = this.chatList.firstElementChild;\r\n const rectContainer = this.scroll.container.getBoundingClientRect();\r\n const rectTarget = firstElementChild.getBoundingClientRect();\r\n const children = Array.from(this.scroll.splitUp.children) as HTMLElement[];\r\n\r\n // const padding = 8;\r\n // const offsetTop = this.folders.container.offsetTop;\r\n let offsetTop = this.scroll.splitUp.offsetTop;\r\n if(offsetTop && scrollTopWas < offsetTop) offsetTop -= scrollTopWas;\r\n // const offsetTop = scrollTopWas < padding ? padding - scrollTopWas : 0;\r\n const firstY = rectContainer.y + offsetTop;\r\n const lastY = rectContainer.y/* - 8 */; // 8px - .chatlist padding-bottom\r\n \r\n const firstElement = findUpTag(document.elementFromPoint(Math.ceil(rectTarget.x), Math.ceil(firstY + 1)), firstElementChild.tagName) as HTMLElement;\r\n const lastElement = findUpTag(document.elementFromPoint(Math.ceil(rectTarget.x), Math.floor(lastY + rectContainer.height - 1)), firstElementChild.tagName) as HTMLElement;\r\n\r\n //alert('got element:' + rect.y);\r\n\r\n if(!firstElement || !lastElement) {\r\n return;\r\n }\r\n\r\n //alert('got element:' + !!firstElement);\r\n\r\n const firstElementRect = firstElement.getBoundingClientRect();\r\n const elementOverflow = firstElementRect.y - firstY;\r\n\r\n const sliced: HTMLElement[] = [];\r\n const firstIndex = children.indexOf(firstElement);\r\n const lastIndex = children.indexOf(lastElement);\r\n\r\n const saveLength = 10;\r\n\r\n const sliceFromStart = isSafari ? [] : children.slice(0, Math.max(0, firstIndex - saveLength));\r\n const sliceFromEnd = children.slice(lastIndex + saveLength);\r\n\r\n /* if(sliceFromStart.length !== sliceFromEnd.length) {\r\n console.log('not equal', sliceFromStart.length, sliceFromEnd.length);\r\n }\r\n\r\n if(sliceFromStart.length > sliceFromEnd.length) {\r\n const diff = sliceFromStart.length - sliceFromEnd.length;\r\n sliceFromStart.splice(0, diff);\r\n } else if(sliceFromEnd.length > sliceFromStart.length) {\r\n const diff = sliceFromEnd.length - sliceFromStart.length;\r\n sliceFromEnd.splice(sliceFromEnd.length - diff, diff);\r\n } */\r\n\r\n if(sliceFromStart.length) {\r\n this.scroll.loadedAll.top = false;\r\n }\r\n\r\n if(sliceFromEnd.length) {\r\n this.scroll.loadedAll.bottom = false;\r\n }\r\n\r\n sliced.push(...sliceFromStart);\r\n sliced.push(...sliceFromEnd);\r\n\r\n sliced.forEach(el => {\r\n const peerId = +el.dataset.peerId;\r\n this.deleteDialog(peerId);\r\n });\r\n\r\n this.setOffsets();\r\n\r\n //this.log('[slicer] elements', firstElement, lastElement, rect, sliced, sliceFromStart.length, sliceFromEnd.length);\r\n\r\n //this.log('[slicer] reset scrollTop', this.scroll.scrollTop, firstElement.offsetTop, firstElementRect.y, rect.y, elementOverflow);\r\n\r\n //alert('left length:' + children.length);\r\n\r\n this.scroll.scrollTop = firstElement.offsetTop - elementOverflow;\r\n /* const firstElementRect = firstElement.getBoundingClientRect();\r\n const scrollTop = */\r\n\r\n //this.scroll.scrollIntoView(firstElement, false);\r\n }, 200);\r\n };\r\n\r\n private setOffsets() {\r\n const firstDialog = this.getDialogFromElement(this.chatList.firstElementChild as HTMLElement);\r\n const lastDialog = this.getDialogFromElement(this.chatList.lastElementChild as HTMLElement);\r\n\r\n this.offsets.top = firstDialog.index;\r\n this.offsets.bottom = lastDialog.index;\r\n }\r\n\r\n private getDialogFromElement(element: HTMLElement) {\r\n return appMessagesManager.getDialogOnly(+element.dataset.peerId);\r\n }\r\n\r\n public onChatsScrollTop = () => {\r\n this.onChatsScroll('top');\r\n };\r\n \r\n public onChatsScroll = (side: SliceSides = 'bottom') => {\r\n if(this.scroll.loadedAll[side] || this.loadDialogsPromise) return;\r\n this.log('onChatsScroll', side);\r\n this.loadDialogs(side);\r\n };\r\n\r\n public setListClickListener(list: HTMLUListElement, onFound?: () => void, withContext = false, autonomous = false, openInner = false) {\r\n let lastActiveListElement: HTMLElement;\r\n\r\n const setPeerFunc = (openInner ? appImManager.setInnerPeer : appImManager.setPeer).bind(appImManager);\r\n\r\n list.dataset.autonomous = '' + +autonomous;\r\n list.addEventListener('mousedown', (e) => {\r\n if(e.button !== 0) return;\r\n //cancelEvent(e);\r\n\r\n this.log('dialogs click list');\r\n const target = e.target as HTMLElement;\r\n const elem = findUpTag(target, 'LI');\r\n\r\n if(!elem) {\r\n return;\r\n }\r\n\r\n if(autonomous) {\r\n const sameElement = lastActiveListElement === elem;\r\n if(lastActiveListElement && !sameElement) {\r\n lastActiveListElement.classList.remove('active');\r\n }\r\n\r\n if(elem) {\r\n elem.classList.add('active');\r\n lastActiveListElement = elem;\r\n this.lastActiveElements.add(elem);\r\n }\r\n }\r\n\r\n if(elem) {\r\n if(onFound) onFound();\r\n\r\n const peerId = +elem.dataset.peerId;\r\n const lastMsgId = +elem.dataset.mid || undefined;\r\n\r\n setPeerFunc(peerId, lastMsgId);\r\n } else {\r\n setPeerFunc(0);\r\n }\r\n }, {capture: true});\r\n\r\n if(DEBUG) {\r\n list.addEventListener('dblclick', (e) => {\r\n const li = findUpTag(e.target, 'LI');\r\n if(li) {\r\n const peerId = +li.dataset.peerId;\r\n this.log('debug dialog:', appMessagesManager.getDialogByPeerId(peerId));\r\n }\r\n });\r\n }\r\n\r\n if(withContext) {\r\n attachContextMenuListener(list, this.contextMenu.onContextMenu);\r\n }\r\n }\r\n\r\n public createChatList(/* options: {\r\n avatarSize?: number,\r\n handheldsSize?: number,\r\n //size?: number,\r\n } = {} */) {\r\n const list = document.createElement('ul');\r\n list.classList.add('chatlist'/* , \r\n 'chatlist-avatar-' + (options.avatarSize || 54) *//* , 'chatlist-' + (options.size || 72) */);\r\n\r\n /* if(options.handheldsSize) {\r\n list.classList.add('chatlist-handhelds-' + options.handheldsSize);\r\n } */\r\n\r\n return list;\r\n }\r\n\r\n private reorderDialogs() {\r\n //const perf = performance.now();\r\n if(this.reorderDialogsTimeout) {\r\n window.cancelAnimationFrame(this.reorderDialogsTimeout);\r\n }\r\n \r\n this.reorderDialogsTimeout = window.requestAnimationFrame(() => {\r\n this.reorderDialogsTimeout = 0;\r\n const dialogs = appMessagesManager.dialogsStorage.getFolder(this.filterId);\r\n\r\n const currentOrder = (Array.from(this.chatList.children) as HTMLElement[]).map(el => +el.dataset.peerId);\r\n\r\n const {index} = this.getOffsetIndex('top');\r\n const pos = dialogs.findIndex(dialog => dialog.index <= index);\r\n\r\n const offset = Math.max(0, pos);\r\n dialogs.forEach((dialog, index) => {\r\n const dom = this.getDialogDom(dialog.peerId);\r\n if(!dom) {\r\n return;\r\n }\r\n \r\n const needIndex = index - offset;\r\n if(needIndex > currentOrder.length) {\r\n this.deleteDialog(dialog.peerId);\r\n return;\r\n }\r\n\r\n const peerIdByIndex = currentOrder[needIndex];\r\n \r\n if(peerIdByIndex !== dialog.peerId) {\r\n if(positionElementByIndex(dom.listEl, this.chatList, needIndex)) {\r\n this.log.debug('setDialogPosition:', dialog, dom, peerIdByIndex, needIndex);\r\n }\r\n }\r\n });\r\n \r\n //this.log('Reorder time:', performance.now() - perf);\r\n });\r\n }\r\n\r\n public setLastMessage(dialog: Dialog, lastMessage?: any, dom?: DialogDom, highlightWord?: string) {\r\n ///////console.log('setlastMessage:', lastMessage);\r\n if(!dom) {\r\n dom = this.getDialogDom(dialog.peerId);\r\n\r\n if(!dom) {\r\n //this.log.error('no dom for dialog:', dialog, lastMessage, dom, highlightWord);\r\n return;\r\n }\r\n }\r\n\r\n let draftMessage: MyDraftMessage;\r\n if(!lastMessage) {\r\n if(dialog.draft && dialog.draft._ === 'draftMessage') {\r\n draftMessage = dialog.draft;\r\n }\r\n \r\n lastMessage = appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);\r\n }\r\n\r\n if(lastMessage._ === 'messageEmpty'/* || (lastMessage._ === 'messageService' && !lastMessage.rReply) */) {\r\n dom.lastMessageSpan.innerHTML = '';\r\n dom.lastTimeSpan.innerHTML = '';\r\n delete dom.listEl.dataset.mid;\r\n return;\r\n }\r\n\r\n let peer = dialog.peer;\r\n let peerId = dialog.peerId;\r\n //let peerId = appMessagesManager.getMessagePeer(lastMessage);\r\n\r\n //console.log('setting last message:', lastMessage);\r\n\r\n /* if(!dom.lastMessageSpan.classList.contains('user-typing')) */ {\r\n\r\n dom.lastMessageSpan.textContent = '';\r\n if(highlightWord && lastMessage.message) {\r\n dom.lastMessageSpan.append(appMessagesManager.wrapMessageForReply(lastMessage, undefined, undefined, false, highlightWord));\r\n } else if(draftMessage) {\r\n dom.lastMessageSpan.append(appMessagesManager.wrapMessageForReply(draftMessage));\r\n } else if(!lastMessage.deleted) {\r\n dom.lastMessageSpan.append(appMessagesManager.wrapMessageForReply(lastMessage));\r\n }\r\n \r\n /* if(lastMessage.from_id === auth.id) { // You: */\r\n if(draftMessage) {\r\n const bold = document.createElement('b');\r\n bold.classList.add('danger');\r\n bold.append(i18n('Draft'));\r\n bold.append(': ');\r\n dom.lastMessageSpan.prepend(bold);\r\n } else if(peer._ !== 'peerUser' && peerId !== lastMessage.fromId && !lastMessage.action) {\r\n const sender = appPeersManager.getPeer(lastMessage.fromId);\r\n if(sender && sender.id) {\r\n const senderBold = document.createElement('b');\r\n\r\n if(sender.id === rootScope.myId) {\r\n senderBold.append(i18n('FromYou'));\r\n } else {\r\n //str = sender.first_name || sender.last_name || sender.username;\r\n senderBold.append(new PeerTitle({\r\n peerId: lastMessage.fromId,\r\n onlyFirstName: true,\r\n }).element);\r\n }\r\n\r\n senderBold.append(': ');\r\n //console.log(sender, senderBold.innerText);\r\n dom.lastMessageSpan.prepend(senderBold);\r\n } //////// else console.log('no sender', lastMessage, peerId);\r\n }\r\n }\r\n\r\n if(!lastMessage.deleted || draftMessage/* && lastMessage._ !== 'draftMessage' */) {\r\n const date = draftMessage ? Math.max(draftMessage.date, lastMessage.date || 0) : lastMessage.date;\r\n dom.lastTimeSpan.textContent = '';\r\n dom.lastTimeSpan.append(formatDateAccordingToTodayNew(new Date(date * 1000)));\r\n } else dom.lastTimeSpan.textContent = '';\r\n\r\n if(this.doms[peerId] === dom) {\r\n this.setUnreadMessages(dialog);\r\n } else { // means search\r\n dom.listEl.dataset.mid = lastMessage.mid;\r\n }\r\n }\r\n\r\n private setUnreadMessages(dialog: Dialog) {\r\n const dom = this.getDialogDom(dialog.peerId);\r\n\r\n if(dialog.folder_id === 1) {\r\n this.accumulateArchivedUnread();\r\n }\r\n\r\n if(!dom) {\r\n //this.log.error('setUnreadMessages no dom!', dialog);\r\n return;\r\n }\r\n\r\n const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);\r\n const wasMuted = dom.listEl.classList.contains('is-muted');\r\n if(isMuted !== wasMuted) {\r\n SetTransition(dom.listEl, 'is-muted', isMuted, 200);\r\n }\r\n\r\n const lastMessage = dialog.draft && dialog.draft._ === 'draftMessage' ? \r\n dialog.draft : \r\n appMessagesManager.getMessageByPeer(dialog.peerId, dialog.top_message);\r\n if(lastMessage._ !== 'messageEmpty' && !lastMessage.deleted && \r\n lastMessage.pFlags.out && lastMessage.peerId !== rootScope.myId/* && \r\n dialog.read_outbox_max_id */) { // maybe comment, 06.20.2020\r\n const outgoing = (lastMessage.pFlags && lastMessage.pFlags.unread)\r\n /* && dialog.read_outbox_max_id !== 0 */; // maybe uncomment, 31.01.2020\r\n \r\n //console.log('outgoing', outgoing, lastMessage);\r\n \r\n if(outgoing) {\r\n dom.statusSpan.classList.remove('tgico-checks');\r\n dom.statusSpan.classList.add('tgico-check');\r\n } else {\r\n dom.statusSpan.classList.remove('tgico-check');\r\n dom.statusSpan.classList.add('tgico-checks');\r\n }\r\n } else dom.statusSpan.classList.remove('tgico-check', 'tgico-checks');\r\n\r\n dom.unreadMessagesSpan.innerText = '';\r\n\r\n const filter = appMessagesManager.filtersStorage.filters[this.filterId];\r\n let isPinned: boolean;\r\n if(filter) {\r\n isPinned = filter.pinned_peers.findIndex(peerId => peerId === dialog.peerId) !== -1;\r\n } else {\r\n isPinned = !!dialog.pFlags.pinned;\r\n }\r\n\r\n if(isPinned) {\r\n dom.unreadMessagesSpan.classList.add('tgico-chatspinned', 'tgico');\r\n } else {\r\n dom.unreadMessagesSpan.classList.remove('tgico-chatspinned', 'tgico');\r\n }\r\n\r\n if(dialog.unread_count || dialog.pFlags.unread_mark) {\r\n //dom.unreadMessagesSpan.innerText = '' + (dialog.unread_count ? formatNumber(dialog.unread_count, 1) : ' ');\r\n dom.unreadMessagesSpan.innerText = '' + (dialog.unread_count || ' ');\r\n dom.unreadMessagesSpan.classList.add('unread');\r\n } else {\r\n dom.unreadMessagesSpan.classList.remove('unread');\r\n }\r\n }\r\n\r\n private accumulateArchivedUnread() {\r\n if(this.accumulateArchivedTimeout) return;\r\n this.accumulateArchivedTimeout = window.setTimeout(() => {\r\n this.accumulateArchivedTimeout = 0;\r\n const dialogs = appMessagesManager.dialogsStorage.getFolder(1);\r\n const sum = dialogs.reduce((acc, dialog) => acc + dialog.unread_count, 0);\r\n rootScope.dispatchEvent('dialogs_archived_unread', {count: sum});\r\n }, 0);\r\n }\r\n\r\n private getDialogDom(peerId: number) {\r\n return this.doms[peerId];\r\n }\r\n\r\n public addDialogNew(options: {\r\n dialog: Dialog | number,\r\n container?: HTMLUListElement | Scrollable | false,\r\n drawStatus?: boolean,\r\n rippleEnabled?: boolean,\r\n onlyFirstName?: boolean,\r\n meAsSaved?: boolean,\r\n append?: boolean,\r\n avatarSize?: number,\r\n autonomous?: boolean,\r\n lazyLoadQueue?: LazyLoadQueueIntersector,\r\n }) {\r\n return this.addDialog(options.dialog, options.container, options.drawStatus, options.rippleEnabled, options.onlyFirstName, options.meAsSaved, options.append, options.avatarSize, options.autonomous, options.lazyLoadQueue);\r\n }\r\n\r\n public addDialog(_dialog: Dialog | number, container?: HTMLUListElement | Scrollable | false, drawStatus = true, rippleEnabled = true, onlyFirstName = false, meAsSaved = true, append = true, avatarSize = 54, autonomous = !!container, lazyLoadQueue?: LazyLoadQueueIntersector) {\r\n let dialog: Dialog;\r\n \r\n if(typeof(_dialog) === 'number') {\r\n let originalDialog = appMessagesManager.getDialogOnly(_dialog);\r\n if(!originalDialog) {\r\n originalDialog = {\r\n peerId: _dialog,\r\n peer: appPeersManager.getOutputPeer(_dialog),\r\n pFlags: {}\r\n } as any;\r\n }\r\n\r\n dialog = originalDialog;\r\n } else {\r\n dialog = _dialog;\r\n }\r\n\r\n const peerId: number = dialog.peerId;\r\n\r\n if(container === undefined) {\r\n if(this.doms[peerId] || dialog.migratedTo !== undefined) return;\r\n\r\n const filter = appMessagesManager.filtersStorage.filters[this.filterId];\r\n if((filter && !appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) || (!filter && this.filterId !== dialog.folder_id)) {\r\n return;\r\n }\r\n }\r\n\r\n const avatarEl = new AvatarElement();\r\n avatarEl.lazyLoadQueue = lazyLoadQueue;\r\n avatarEl.setAttribute('dialog', meAsSaved ? '1' : '0');\r\n avatarEl.setAttribute('peer', '' + peerId);\r\n avatarEl.classList.add('dialog-avatar', 'avatar-' + avatarSize);\r\n\r\n if(drawStatus && peerId !== rootScope.myId && dialog.peer) {\r\n const peer = dialog.peer;\r\n \r\n switch(peer._) {\r\n case 'peerUser':\r\n const user = appUsersManager.getUser(peerId);\r\n //console.log('found user', user);\r\n \r\n if(user.status && user.status._ === 'userStatusOnline') {\r\n avatarEl.classList.add('is-online');\r\n }\r\n \r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n\r\n const captionDiv = document.createElement('div');\r\n captionDiv.classList.add('user-caption');\r\n\r\n const titleSpanContainer = document.createElement('span');\r\n titleSpanContainer.classList.add('user-title');\r\n\r\n const peerTitle = new PeerTitle({\r\n peerId,\r\n dialog: meAsSaved,\r\n onlyFirstName,\r\n plainText: false\r\n });\r\n\r\n titleSpanContainer.append(peerTitle.element);\r\n //p.classList.add('')\r\n\r\n // в других случаях иконка верификации не нужна (а первый - это главные чатлисты)\r\n //if(!container) {\r\n const peer = appPeersManager.getPeer(peerId);\r\n\r\n // for muted icon\r\n titleSpanContainer.classList.add('tgico'); // * эта строка будет актуальна только для !container, но ладно\r\n\r\n if(peer?.pFlags?.verified) {\r\n titleSpanContainer.classList.add('is-verified');\r\n titleSpanContainer.append(generateVerifiedIcon());\r\n }\r\n //}\r\n \r\n const span = document.createElement('span');\r\n span.classList.add('user-last-message');\r\n span.setAttribute('dir', 'auto');\r\n\r\n //captionDiv.append(titleSpan);\r\n //captionDiv.append(span);\r\n\r\n const li = document.createElement('li');\r\n if(rippleEnabled) {\r\n ripple(li);\r\n }\r\n\r\n li.append(avatarEl, captionDiv);\r\n li.dataset.peerId = '' + peerId;\r\n\r\n const statusSpan = document.createElement('span');\r\n statusSpan.classList.add('message-status');\r\n\r\n const lastTimeSpan = document.createElement('span');\r\n lastTimeSpan.classList.add('message-time');\r\n\r\n const unreadMessagesSpan = document.createElement('div');\r\n unreadMessagesSpan.className = 'dialog-subtitle-badge badge badge-24';\r\n\r\n const titleP = document.createElement('p');\r\n titleP.classList.add('dialog-title');\r\n\r\n const rightSpan = document.createElement('span');\r\n rightSpan.classList.add('dialog-title-details');\r\n rightSpan.append(statusSpan, lastTimeSpan);\r\n titleP.append(titleSpanContainer, rightSpan);\r\n\r\n const messageP = document.createElement('p');\r\n messageP.classList.add('dialog-subtitle');\r\n messageP.append(span, unreadMessagesSpan);\r\n\r\n captionDiv.append(titleP, messageP);\r\n\r\n const dom: DialogDom = {\r\n avatarEl,\r\n captionDiv,\r\n titleSpan: peerTitle.element,\r\n titleSpanContainer,\r\n statusSpan,\r\n lastTimeSpan,\r\n unreadMessagesSpan,\r\n lastMessageSpan: span,\r\n containerEl: li,\r\n listEl: li\r\n };\r\n\r\n /* let good = false;\r\n for(const folderId in this.chatLists) {\r\n if(this.chatLists[folderId] === container) {\r\n good = true;\r\n }\r\n } */\r\n const method: 'append' | 'prepend' = append ? 'append' : 'prepend';\r\n if(container === undefined/* || good */) {\r\n this.scroll[method](li);\r\n\r\n this.doms[dialog.peerId] = dom;\r\n\r\n /* if(container) {\r\n container.append(li);\r\n } */\r\n\r\n const isMuted = appNotificationsManager.isPeerLocalMuted(dialog.peerId, true);\r\n if(isMuted) {\r\n li.classList.add('is-muted');\r\n }\r\n\r\n this.setLastMessage(dialog);\r\n } else if(container) {\r\n container[method](li);\r\n }\r\n\r\n if(!autonomous && appImManager.chat?.peerId === peerId) {\r\n li.classList.add('active');\r\n this.lastActiveElements.add(li);\r\n } \r\n \r\n return {dom, dialog};\r\n }\r\n\r\n public setTyping(dialog: Dialog) {\r\n const dom = this.getDialogDom(dialog.peerId);\r\n if(!dom) {\r\n return;\r\n }\r\n\r\n let typingElement = dom.lastMessageSpan.querySelector('.peer-typing-container') as HTMLElement;\r\n if(typingElement) {\r\n appImManager.getPeerTyping(dialog.peerId, typingElement);\r\n } else {\r\n typingElement = appImManager.getPeerTyping(dialog.peerId);\r\n replaceContent(dom.lastMessageSpan, typingElement);\r\n dom.lastMessageSpan.classList.add('user-typing');\r\n }\r\n }\r\n\r\n public unsetTyping(dialog: Dialog) {\r\n const dom = this.getDialogDom(dialog.peerId);\r\n if(!dom) {\r\n return;\r\n }\r\n\r\n dom.lastMessageSpan.classList.remove('user-typing');\r\n this.setLastMessage(dialog, null, dom);\r\n }\r\n}\r\n\r\nexport function generateVerifiedIcon() {\r\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\r\n svg.setAttributeNS(null, 'viewBox', '0 0 24 24');\r\n svg.setAttributeNS(null, 'width', '24');\r\n svg.setAttributeNS(null, 'height', '24');\r\n svg.classList.add('verified-icon');\r\n\r\n const use = document.createElementNS('http://www.w3.org/2000/svg', 'use');\r\n use.setAttributeNS(null, 'href', '#verified-background');\r\n use.classList.add('verified-background');\r\n\r\n const use2 = document.createElementNS('http://www.w3.org/2000/svg', 'use');\r\n use2.setAttributeNS(null, 'href', '#verified-check');\r\n use2.classList.add('verified-check');\r\n\r\n svg.append(use, use2);\r\n\r\n return svg;\r\n}\r\n\r\nconst appDialogsManager = new AppDialogsManager();\r\nMOUNT_CLASS_TO.appDialogsManager = appDialogsManager;\r\nexport default appDialogsManager;\r\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 type { DownloadOptions } from \"../mtproto/apiFileManager\";\r\nimport type { ApiError } from \"../mtproto/apiManager\";\r\nimport type { MyDocument } from \"./appDocsManager\";\r\nimport type { MyPhoto } from \"./appPhotosManager\";\r\nimport rootScope from \"../rootScope\";\r\nimport apiManager from \"../mtproto/mtprotoworker\";\r\nimport { deferredPromise, CancellablePromise } from \"../../helpers/cancellablePromise\";\r\nimport { InputFile } from \"../../layer\";\r\nimport referenceDatabase, {ReferenceBytes} from \"../mtproto/referenceDatabase\";\r\nimport { getFileNameByLocation } from \"../../helpers/fileName\";\r\nimport CacheStorageController from \"../cacheStorage\";\r\nimport { MOUNT_CLASS_TO } from \"../../config/debug\";\r\n\r\nexport type ResponseMethodBlob = 'blob';\r\nexport type ResponseMethodJson = 'json';\r\nexport type ResponseMethod = ResponseMethodBlob | ResponseMethodJson;\r\n\r\n/* export type DownloadBlob = {promise: Promise<Blob>, controller: AbortController};\r\nexport type DownloadJson = {promise: Promise<any>, controller: AbortController}; */\r\nexport type DownloadBlob = CancellablePromise<Blob>;\r\nexport type DownloadJson = CancellablePromise<any>;\r\n//export type Download = DownloadBlob/* | DownloadJson */;\r\nexport type Download = DownloadBlob/* | DownloadJson */;\r\n\r\nexport type Progress = {done: number, fileName: string, total: number, offset: number};\r\nexport type ProgressCallback = (details: Progress) => void;\r\n\r\nexport type ThumbCache = {\r\n downloaded: number, \r\n url: string\r\n};\r\n\r\nexport type ThumbsCache = {\r\n [id: string]: {\r\n [size: string]: ThumbCache\r\n }\r\n};\r\n\r\nexport class AppDownloadManager {\r\n public cacheStorage = new CacheStorageController('cachedFiles');\r\n private downloads: {[fileName: string]: Download} = {};\r\n private progress: {[fileName: string]: Progress} = {};\r\n private progressCallbacks: {[fileName: string]: Array<ProgressCallback>} = {};\r\n\r\n private uploadId = 0;\r\n\r\n private thumbsCache: {\r\n photo: ThumbsCache,\r\n document: ThumbsCache\r\n } = {\r\n photo: {},\r\n document: {}\r\n };\r\n\r\n constructor() {\r\n rootScope.addEventListener('download_progress', (e) => {\r\n const details = e as {done: number, fileName: string, total: number, offset: number};\r\n this.progress[details.fileName] = details;\r\n\r\n const callbacks = this.progressCallbacks[details.fileName];\r\n if(callbacks) {\r\n callbacks.forEach(callback => callback(details));\r\n }\r\n\r\n const download = this.downloads[details.fileName];\r\n if(download) {\r\n download.notifyAll(details);\r\n }\r\n });\r\n }\r\n\r\n private getNewDeferred<T>(fileName: string) {\r\n const deferred = deferredPromise<T>();\r\n\r\n deferred.cancel = () => {\r\n //try {\r\n const error = new Error('Download canceled');\r\n error.name = 'AbortError';\r\n \r\n apiManager.cancelDownload(fileName);\r\n \r\n deferred.reject(error);\r\n deferred.cancel = () => {};\r\n /* } catch(err) {\r\n\r\n } */\r\n };\r\n\r\n deferred.finally(() => {\r\n delete this.progress[fileName];\r\n delete this.progressCallbacks[fileName];\r\n });\r\n\r\n deferred.catch(() => {\r\n this.clearDownload(fileName);\r\n });\r\n\r\n return this.downloads[fileName] = deferred as any;\r\n }\r\n\r\n private clearDownload(fileName: string) {\r\n delete this.downloads[fileName];\r\n }\r\n\r\n public fakeDownload(fileName: string, value: Blob | string) {\r\n const deferred = this.getNewDeferred<Blob>(fileName);\r\n if(typeof(value) === 'string') {\r\n fetch(value)\r\n .then(response => response.blob())\r\n .then(blob => deferred.resolve(blob));\r\n } else {\r\n deferred.resolve(value);\r\n }\r\n\r\n return deferred;\r\n }\r\n\r\n public download(options: DownloadOptions): DownloadBlob {\r\n const fileName = getFileNameByLocation(options.location, {fileName: options.fileName});\r\n if(this.downloads.hasOwnProperty(fileName)) return this.downloads[fileName];\r\n\r\n const deferred = this.getNewDeferred<Blob>(fileName);\r\n\r\n const onError = (err: ApiError) => {\r\n deferred.reject(err);\r\n };\r\n\r\n const tryDownload = (): Promise<unknown> => {\r\n //return Promise.resolve();\r\n\r\n if(!apiManager.worker || options.onlyCache) {\r\n const promise = this.cacheStorage.getFile(fileName).then((blob) => {\r\n if(blob.size < options.size) throw 'wrong size';\r\n else deferred.resolve(blob);\r\n });\r\n \r\n if(options.onlyCache) return promise.catch(onError);\r\n return promise.catch(() => {\r\n return apiManager.downloadFile(options).then(deferred.resolve, onError);\r\n });\r\n } else {\r\n /* return apiManager.downloadFile(options).then(res => {\r\n setTimeout(() => deferred.resolve(res), 5e3);\r\n }, onError); */\r\n\r\n return apiManager.downloadFile(options).then(deferred.resolve, onError);\r\n }\r\n };\r\n\r\n tryDownload();\r\n\r\n //console.log('Will download file:', fileName, url);\r\n return deferred;\r\n }\r\n\r\n public upload(file: File | Blob, fileName?: string) {\r\n if(!fileName) {\r\n const mimeType = file?.type;\r\n if(mimeType) { // the same like apiFileName in appMessagesManager for upload!\r\n const ext = this.uploadId++ + '.' + mimeType.split('/')[1];\r\n \r\n if(['image/jpeg', 'image/png', 'image/bmp'].indexOf(mimeType) >= 0) {\r\n fileName = 'photo' + ext;\r\n } else if(mimeType.indexOf('audio/') === 0 || ['video/ogg'].indexOf(mimeType) >= 0) {\r\n fileName = 'audio' + ext;\r\n } else if(mimeType.indexOf('video/') === 0) {\r\n fileName = 'video' + ext;\r\n } else {\r\n fileName = 'document' + ext;\r\n }\r\n \r\n } else {\r\n fileName = 'upload-' + this.uploadId++;\r\n }\r\n }\r\n\r\n const deferred = this.getNewDeferred<InputFile>(fileName);\r\n apiManager.uploadFile({file, fileName}).then(deferred.resolve, deferred.reject);\r\n\r\n deferred.finally(() => {\r\n this.clearDownload(fileName);\r\n });\r\n\r\n return deferred as any as CancellablePromise<InputFile>;\r\n }\r\n\r\n public getDownload(fileName: string) {\r\n return this.downloads[fileName];\r\n }\r\n\r\n public addProgressCallback(fileName: string, callback: ProgressCallback) {\r\n const progress = this.progress[fileName];\r\n (this.progressCallbacks[fileName] ?? (this.progressCallbacks[fileName] = [])).push(callback);\r\n\r\n if(progress) {\r\n callback(progress);\r\n }\r\n }\r\n\r\n public createDownloadAnchor(url: string, fileName: string, onRemove?: () => void) {\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = fileName;\r\n a.target = '_blank';\r\n \r\n a.style.position = 'absolute';\r\n a.style.top = '1px';\r\n a.style.left = '1px';\r\n \r\n document.body.append(a);\r\n \r\n try {\r\n var clickEvent = document.createEvent('MouseEvents');\r\n clickEvent.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);\r\n a.dispatchEvent(clickEvent);\r\n } catch (e) {\r\n console.error('Download click error', e);\r\n try {\r\n a.click();\r\n } catch (e) {\r\n window.open(url as string, '_blank');\r\n }\r\n }\r\n \r\n setTimeout(() => {\r\n a.remove();\r\n onRemove && onRemove();\r\n }, 100);\r\n }\r\n\r\n /* public downloadToDisc(fileName: string, url: string) {\r\n this.createDownloadAnchor(url);\r\n \r\n return this.download(fileName, url);\r\n } */\r\n\r\n public downloadToDisc(options: DownloadOptions, discFileName: string) {\r\n const download = this.download(options);\r\n download/* .promise */.then(blob => {\r\n const objectURL = URL.createObjectURL(blob);\r\n this.createDownloadAnchor(objectURL, discFileName, () => {\r\n URL.revokeObjectURL(objectURL);\r\n });\r\n });\r\n \r\n return download;\r\n }\r\n\r\n public getCacheContext(media: MyPhoto | MyDocument, thumbSize: string = 'full'): ThumbCache {\r\n /* if(media._ === 'photo' && thumbSize !== 'i') {\r\n thumbSize = 'full';\r\n } */\r\n\r\n const cache = this.thumbsCache[media._][media.id] ?? (this.thumbsCache[media._][media.id] = {});\r\n return cache[thumbSize] ?? (cache[thumbSize] = {downloaded: 0, url: ''});\r\n }\r\n}\r\n\r\nconst appDownloadManager = new AppDownloadManager();\r\nMOUNT_CLASS_TO && (MOUNT_CLASS_TO.appDownloadManager = appDownloadManager);\r\nexport default appDownloadManager;\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 { ripple } from \"../ripple\";\r\nimport animationIntersector from \"../animationIntersector\";\r\nimport appNavigationController, { NavigationItem } from \"../appNavigationController\";\r\nimport { i18n, LangPackKey } from \"../../lib/langPack\";\r\nimport findUpClassName from \"../../helpers/dom/findUpClassName\";\r\nimport blurActiveElement from \"../../helpers/dom/blurActiveElement\";\r\n\r\nexport type PopupButton = {\r\n text?: string,\r\n callback?: () => void,\r\n langKey?: LangPackKey,\r\n langArgs?: any[],\r\n isDanger?: true,\r\n isCancel?: true\r\n};\r\n\r\nexport type PopupOptions = Partial<{\r\n closable: true, \r\n overlayClosable: true, \r\n withConfirm: LangPackKey | true, \r\n body: true\r\n}>;\r\n\r\nexport default class PopupElement {\r\n protected element = document.createElement('div');\r\n protected container = document.createElement('div');\r\n protected header = document.createElement('div');\r\n protected title = document.createElement('div');\r\n protected btnClose: HTMLElement;\r\n protected btnConfirm: HTMLElement;\r\n protected body: HTMLElement;\r\n\r\n protected onClose: () => void;\r\n protected onCloseAfterTimeout: () => void;\r\n protected onEscape: () => boolean = () => true;\r\n\r\n protected navigationItem: NavigationItem;\r\n\r\n constructor(className: string, buttons?: Array<PopupButton>, options: PopupOptions = {}) {\r\n this.element.classList.add('popup');\r\n this.element.className = 'popup' + (className ? ' ' + className : '');\r\n this.container.classList.add('popup-container', 'z-depth-1');\r\n\r\n this.header.classList.add('popup-header');\r\n this.title.classList.add('popup-title');\r\n\r\n this.header.append(this.title);\r\n\r\n if(options.closable) {\r\n this.btnClose = document.createElement('span');\r\n this.btnClose.classList.add('btn-icon', 'popup-close', 'tgico-close');\r\n //ripple(this.closeBtn);\r\n this.header.prepend(this.btnClose);\r\n\r\n this.btnClose.addEventListener('click', this.hide, {once: true});\r\n }\r\n\r\n if(options.overlayClosable) {\r\n const onOverlayClick = (e: MouseEvent) => {\r\n if(!findUpClassName(e.target, 'popup-container')) {\r\n this.hide();\r\n this.element.removeEventListener('click', onOverlayClick);\r\n }\r\n };\r\n \r\n this.element.addEventListener('click', onOverlayClick);\r\n }\r\n\r\n if(options.withConfirm) {\r\n this.btnConfirm = document.createElement('button');\r\n this.btnConfirm.classList.add('btn-primary', 'btn-color-primary');\r\n if(options.withConfirm !== true) {\r\n this.btnConfirm.append(i18n(options.withConfirm));\r\n }\r\n this.header.append(this.btnConfirm);\r\n ripple(this.btnConfirm);\r\n }\r\n\r\n this.container.append(this.header);\r\n if(options.body) {\r\n this.body = document.createElement('div');\r\n this.body.classList.add('popup-body');\r\n this.container.append(this.body);\r\n }\r\n\r\n if(buttons && buttons.length) {\r\n const buttonsDiv = document.createElement('div');\r\n buttonsDiv.classList.add('popup-buttons');\r\n\r\n if(buttons.length === 2) {\r\n buttonsDiv.classList.add('popup-buttons-row');\r\n }\r\n \r\n const buttonsElements = buttons.map(b => {\r\n const button = document.createElement('button');\r\n button.className = 'btn' + (b.isDanger ? ' danger' : ' primary');\r\n\r\n ripple(button);\r\n \r\n if(b.text) {\r\n button.innerHTML = b.text;\r\n } else {\r\n button.append(i18n(b.langKey, b.langArgs));\r\n }\r\n \r\n if(b.callback) {\r\n button.addEventListener('click', () => {\r\n b.callback();\r\n this.destroy();\r\n }, {once: true});\r\n } else if(b.isCancel) {\r\n button.addEventListener('click', () => {\r\n this.destroy();\r\n }, {once: true});\r\n }\r\n \r\n return button;\r\n });\r\n \r\n buttonsDiv.append(...buttonsElements);\r\n this.container.append(buttonsDiv);\r\n }\r\n\r\n this.element.append(this.container);\r\n }\r\n\r\n public show() {\r\n this.navigationItem = {\r\n type: 'popup',\r\n onPop: this.destroy,\r\n onEscape: this.onEscape\r\n };\r\n\r\n appNavigationController.pushItem(this.navigationItem);\r\n\r\n blurActiveElement(); // * hide mobile keyboard\r\n document.body.append(this.element);\r\n void this.element.offsetWidth; // reflow\r\n this.element.classList.add('active');\r\n rootScope.overlayIsActive = true;\r\n animationIntersector.checkAnimations(true);\r\n }\r\n\r\n public hide = () => {\r\n appNavigationController.back('popup');\r\n };\r\n\r\n private destroy = () => {\r\n this.onClose && this.onClose();\r\n this.element.classList.add('hiding');\r\n this.element.classList.remove('active');\r\n\r\n if(this.btnClose) this.btnClose.removeEventListener('click', this.hide);\r\n rootScope.overlayIsActive = false;\r\n\r\n appNavigationController.removeItem(this.navigationItem);\r\n this.navigationItem = undefined;\r\n\r\n setTimeout(() => {\r\n this.element.remove();\r\n this.onCloseAfterTimeout && this.onCloseAfterTimeout();\r\n animationIntersector.checkAnimations(false);\r\n }, 150);\r\n };\r\n}\r\n\r\nexport const addCancelButton = (buttons: PopupButton[]) => {\r\n const button = buttons.find(b => b.isCancel);\r\n if(!button) {\r\n buttons.push({\r\n langKey: 'Cancel',\r\n isCancel: true\r\n });\r\n }\r\n\r\n return buttons;\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 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 type { InputFileLocation, InputStickerSet } from \"../layer\";\r\nimport type { DownloadOptions } from \"../lib/mtproto/apiFileManager\";\r\n\r\nconst FILENAME_JOINER = '_';\r\n\r\nexport function getFileNameByLocation(location: InputFileLocation, options?: Partial<{\r\n fileName: string\r\n}>) {\r\n const fileName = '';//(options?.fileName || '').split('.');\r\n const ext = fileName[fileName.length - 1] || '';\r\n\r\n let str: string;\r\n switch(location._) {\r\n case 'inputPhotoFileLocation': {\r\n str = ['photo', fileName[0], location.id, location.thumb_size].filter(Boolean).join(FILENAME_JOINER);\r\n break;\r\n }\r\n\r\n case 'inputDocumentFileLocation': {\r\n str = ['document', fileName[0], location.id, location.thumb_size].filter(Boolean).join(FILENAME_JOINER);\r\n break;\r\n }\r\n\r\n case 'inputPeerPhotoFileLocation':\r\n str = ['peerPhoto', location.photo_id, location.pFlags.big ? 'big' : 'small'].join(FILENAME_JOINER);\r\n break;\r\n \r\n case 'inputStickerSetThumb': {\r\n const id = (location.stickerset as InputStickerSet.inputStickerSetID).id || \r\n (location.stickerset as InputStickerSet.inputStickerSetShortName).short_name || \r\n (location.stickerset as InputStickerSet.inputStickerSetDice).emoticon || \r\n location.stickerset._;\r\n str = ['stickerSetThumb', id, location.thumb_version].join(FILENAME_JOINER);\r\n break;\r\n }\r\n\r\n case 'inputFileLocation': {\r\n str = location.volume_id + '_' + location.local_id;\r\n break;\r\n }\r\n\r\n default: {\r\n console.error('Unrecognized location:', location);\r\n str = '';\r\n break;\r\n }\r\n }\r\n\r\n return str + (ext ? '.' + ext : ext);\r\n}\r\n\r\nexport type FileURLType = 'photo' | 'thumb' | 'document' | 'stream' | 'download';\r\nexport function getFileURL(type: FileURLType, options: DownloadOptions) {\r\n //console.log('getFileURL', location);\r\n //const perf = performance.now();\r\n const encoded = encodeURIComponent(JSON.stringify(options));\r\n //console.log('getFileURL encode:', performance.now() - perf, encoded);\r\n\r\n return '/' + type + '/' + encoded;\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","/*\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","/*\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\nfunction resizeableImage(originalImage: HTMLImageElement, canvas?: HTMLCanvasElement) {\r\n let cropComponent: HTMLDivElement, \r\n container: HTMLDivElement, \r\n cropImage: HTMLImageElement, \r\n event_state: Partial<{ \r\n mouse_x: number, \r\n mouse_y: number, \r\n container_width: number, \r\n container_height: number, \r\n container_left: number, \r\n container_top: number\r\n }> = {}, \r\n keyZoomValue = 4.0, \r\n MINWIDTH = 50, \r\n MINHEIGHT = 50, \r\n CROPWIDTH = 200, \r\n CROPHEIGHT = 200, \r\n cropLeft = 0, \r\n cropTop = 0, \r\n cropWidth = 0, \r\n cropHeight = 0,\r\n scaledRatio = 0;\r\n \r\n if(originalImage.complete) init();\r\n else originalImage.onload = init;\r\n \r\n function removeHandlers() {\r\n container.removeEventListener('mousedown', startMoving);\r\n container.removeEventListener('touchstart', startMoving);\r\n container.removeEventListener('wheel', resizing);\r\n \r\n document.removeEventListener('mouseup', endMoving);\r\n document.removeEventListener('touchend', endMoving);\r\n document.removeEventListener('mousemove', moving);\r\n document.removeEventListener('touchmove', moving);\r\n document.removeEventListener('keypress', keyHandler);\r\n\r\n cropComponent.remove();\r\n container.remove();\r\n cropImage.remove();\r\n }\r\n \r\n function addHandlers() {\r\n container.addEventListener('mousedown', startMoving, false);\r\n container.addEventListener('touchstart', startMoving, false);\r\n container.addEventListener('wheel', resizing, false);\r\n \r\n document.addEventListener('keypress', keyHandler, false);\r\n //document.querySelector('.btn-crop').addEventListener('click', openCropCanvasImg);\r\n }\r\n \r\n function init() {\r\n originalImage.classList.add('crop-blur');\r\n originalImage.draggable = false;\r\n \r\n cropImage = new Image();\r\n cropImage.src = originalImage.src;\r\n cropImage.draggable = false;\r\n cropImage.classList.add('crop-overlay-image');\r\n \r\n if(!canvas) {\r\n canvas = document.createElement('canvas');\r\n }\r\n \r\n cropComponent = document.createElement('div');\r\n cropComponent.classList.add('crop-component');\r\n \r\n container = document.createElement('div');\r\n container.classList.add('crop-overlay');\r\n \r\n const overlayColor = document.createElement('div');\r\n overlayColor.classList.add('crop-overlay-color');\r\n \r\n cropComponent.appendChild(container);\r\n const wrapper = originalImage.parentNode as HTMLElement;\r\n wrapper.appendChild(cropComponent);\r\n cropComponent.appendChild(cropImage);\r\n cropComponent.appendChild(originalImage);\r\n cropComponent.appendChild(overlayColor);\r\n container.appendChild(cropImage);\r\n\r\n cropImage.style.maxWidth = originalImage.width + 'px';\r\n\r\n scaledRatio = originalImage.naturalWidth / originalImage.offsetWidth;\r\n \r\n const left = originalImage.offsetWidth / 2 - CROPWIDTH / 2;\r\n const top = originalImage.offsetHeight / 2 - CROPHEIGHT / 2;\r\n \r\n updateCropSize(CROPWIDTH, CROPHEIGHT);\r\n updateCropImage(left, top);\r\n updateContainer(left, top);\r\n addHandlers();\r\n //crop();\r\n }\r\n \r\n function updateCropSize(width: number, height: number) {\r\n cropWidth = width * scaledRatio;\r\n cropHeight = height * scaledRatio;\r\n\r\n container.style.width = width + 'px';\r\n container.style.height = height + 'px';\r\n }\r\n \r\n function updateCropImage(left: number, top: number) {\r\n cropTop = top * scaledRatio;\r\n cropLeft = left * scaledRatio;\r\n\r\n cropImage.style.top = -top + 'px';\r\n cropImage.style.left = -left + 'px';\r\n }\r\n \r\n function updateContainer(left: number, top: number) {\r\n container.style.top = top + 'px';\r\n container.style.left = left + 'px';\r\n }\r\n \r\n // Save the initial event details and container state\r\n function saveEventState(e: any) {\r\n event_state.container_width = container.offsetWidth;\r\n event_state.container_height = container.offsetHeight;\r\n \r\n event_state.container_left = container.offsetLeft;\r\n event_state.container_top = container.offsetTop;\r\n \r\n event_state.mouse_x = (e.clientX || e.pageX || e.touches && e.touches[0].clientX) + window.scrollX;\r\n event_state.mouse_y = (e.clientY || e.pageY || e.touches && e.touches[0].clientY) + window.scrollY;\r\n }\r\n \r\n function imgZoom(zoom: number) {\r\n zoom = zoom * Math.PI * 2\r\n let newWidth = Math.floor(container.clientWidth + zoom), \r\n newHeight = Math.floor(container.clientHeight + zoom), \r\n w = cropImage.clientWidth, \r\n h = cropImage.clientHeight, \r\n left: number, \r\n top: number, \r\n right: number, \r\n bottom: number;\r\n \r\n if(newWidth < MINWIDTH) {\r\n return;\r\n } else if(newWidth > w) {\r\n return;\r\n }\r\n \r\n left = container.offsetLeft - (zoom / 2);\r\n top = container.offsetTop - (zoom / 2);\r\n right = left + newWidth;\r\n bottom = top + newHeight;\r\n \r\n if(left < 0) left = 0;\r\n if(top < 0) top = 0;\r\n\r\n if(right > w) return;\r\n if(bottom > h) return;\r\n\r\n updateCropSize(newWidth, newWidth);\r\n updateCropImage(left, top);\r\n updateContainer(left, top);\r\n //crop();\r\n }\r\n \r\n function keyHandler(e: KeyboardEvent) {\r\n e.preventDefault();\r\n \r\n switch (String.fromCharCode(e.charCode)) {\r\n case '+' :\r\n imgZoom(keyZoomValue);\r\n break;\r\n case '-' :\r\n imgZoom(-keyZoomValue);\r\n break;\r\n }\r\n }\r\n \r\n function resizing(e: any) {\r\n e.preventDefault();\r\n imgZoom(e.deltaY > 0 ? 1 : -1);\r\n }\r\n \r\n function startMoving(e: MouseEvent | TouchEvent) {\r\n e.preventDefault();\r\n e.stopPropagation();\r\n \r\n saveEventState(e);\r\n \r\n document.addEventListener('mousemove', moving);\r\n document.addEventListener('touchmove', moving);\r\n document.addEventListener('mouseup', endMoving);\r\n document.addEventListener('touchend', endMoving);\r\n }\r\n \r\n function endMoving(e: MouseEvent | TouchEvent) {\r\n e.preventDefault();\r\n \r\n document.removeEventListener('mouseup', endMoving);\r\n document.removeEventListener('touchend', endMoving);\r\n document.removeEventListener('mousemove', moving);\r\n document.removeEventListener('touchmove', moving);\r\n }\r\n \r\n function moving(e: any) {\r\n let currentTouch = {x: 0, y: 0}, \r\n left: number, \r\n top: number, \r\n w: number, \r\n h: number;\r\n \r\n e.preventDefault();\r\n e.stopPropagation();\r\n \r\n currentTouch.x = e.pageX || e.touches && e.touches[0].pageX;\r\n currentTouch.y = e.pageY || e.touches && e.touches[0].pageY;\r\n \r\n left = currentTouch.x - (event_state.mouse_x - event_state.container_left);\r\n top = currentTouch.y - (event_state.mouse_y - event_state.container_top);\r\n w = container.offsetWidth;\r\n h = container.offsetHeight;\r\n \r\n if(left < 0) left = 0;\r\n else if(left > cropImage.offsetWidth - w) left = cropImage.offsetWidth - w;\r\n\r\n if(top < 0) top = 0;\r\n else if(top > cropImage.offsetHeight - h) top = cropImage.offsetHeight - h;\r\n \r\n updateCropImage(left, top);\r\n updateContainer(left, top);\r\n //crop();\r\n }\r\n\r\n function crop() {\r\n canvas.width = cropWidth;\r\n canvas.height = cropHeight;\r\n \r\n const ctx = canvas.getContext('2d');\r\n ctx.drawImage(originalImage,\r\n cropLeft, cropTop,\r\n cropWidth, cropHeight,\r\n 0, 0,\r\n cropWidth, cropHeight\r\n );\r\n }\r\n \r\n return {crop, removeHandlers};\r\n}\r\n\r\nexport default resizeableImage;\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 appDownloadManager from \"../../lib/appManagers/appDownloadManager\";\r\nimport resizeableImage from \"../../lib/cropper\";\r\nimport PopupElement from \".\";\r\nimport { ripple } from \"../ripple\";\r\nimport { _i18n } from \"../../lib/langPack\";\r\nimport { readBlobAsDataURL } from \"../../helpers/blob\";\r\n\r\nexport default class PopupAvatar extends PopupElement {\r\n private cropContainer: HTMLElement;\r\n private input: HTMLInputElement;\r\n private btnSubmit: HTMLElement;\r\n private h6: HTMLElement;\r\n\r\n private image = new Image();\r\n\r\n private canvas: HTMLCanvasElement;\r\n private blob: Blob;\r\n private cropper = {\r\n crop: () => {},\r\n removeHandlers: () => {}\r\n };\r\n\r\n private onCrop: (upload: () => ReturnType<typeof appDownloadManager.upload>) => void;\r\n\r\n constructor() {\r\n super('popup-avatar', null, {closable: true});\r\n\r\n this.h6 = document.createElement('h6');\r\n _i18n(this.h6, 'Popup.Avatar.Title');\r\n\r\n this.btnClose.classList.remove('btn-icon');\r\n\r\n this.header.append(this.h6);\r\n\r\n this.cropContainer = document.createElement('div');\r\n this.cropContainer.classList.add('crop');\r\n this.cropContainer.append(this.image);\r\n\r\n this.input = document.createElement('input');\r\n this.input.type = 'file';\r\n this.input.style.display = 'none';\r\n this.input.addEventListener('change', (e: any) => {\r\n const file = e.target.files[0];\r\n if(!file) {\r\n return;\r\n }\r\n\r\n readBlobAsDataURL(file).then(contents => {\r\n this.image = new Image();\r\n this.cropContainer.append(this.image);\r\n this.image.src = contents;\r\n \r\n this.image.onload = () => {\r\n /* let {w, h} = calcImageInBox(this.image.naturalWidth, this.image.naturalHeight, 460, 554);\r\n cropContainer.style.width = w + 'px';\r\n cropContainer.style.height = h + 'px'; */\r\n this.show();\r\n \r\n this.cropper = resizeableImage(this.image, this.canvas);\r\n this.input.value = '';\r\n };\r\n });\r\n }, false);\r\n\r\n this.btnSubmit = document.createElement('button');\r\n this.btnSubmit.className = 'btn-primary btn-color-primary btn-circle btn-crop btn-icon tgico-check z-depth-1';\r\n ripple(this.btnSubmit);\r\n this.btnSubmit.addEventListener('click', () => {\r\n this.cropper.crop();\r\n this.btnClose.click();\r\n\r\n this.canvas.toBlob(blob => {\r\n this.blob = blob; // save blob to send after reg\r\n this.darkenCanvas();\r\n this.resolve();\r\n }, 'image/jpeg', 1);\r\n });\r\n\r\n this.container.append(this.cropContainer, this.btnSubmit, this.input);\r\n\r\n this.onCloseAfterTimeout = () => {\r\n this.cropper.removeHandlers();\r\n if(this.image) {\r\n this.image.remove();\r\n }\r\n };\r\n }\r\n\r\n private resolve() {\r\n this.onCrop(() => {\r\n return appDownloadManager.upload(this.blob);\r\n });\r\n }\r\n\r\n public open(postCanvas: HTMLCanvasElement, onCrop: PopupAvatar['onCrop']) {\r\n this.canvas = postCanvas;\r\n this.onCrop = onCrop;\r\n\r\n this.input.click();\r\n }\r\n\r\n public darkenCanvas() {\r\n let ctx = this.canvas.getContext('2d');\r\n ctx.fillStyle = \"rgba(0, 0, 0, 0.3)\";\r\n ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);\r\n }\r\n}\r\n"],"sourceRoot":""}