@@ -11,7 +11,7 @@ import rootScope from '../lib/rootScope';
1111import Scrollable from './scrollable' ;
1212import { FocusDirection } from '../helpers/fastSmoothScroll' ;
1313import CheckboxField from './checkboxField' ;
14- import { i18n , LangPackKey , _i18n } from '../lib/langPack' ;
14+ import { _i18n , i18n , LangPackKey } from '../lib/langPack' ;
1515import findUpAttribute from '../helpers/dom/findUpAttribute' ;
1616import findUpClassName from '../helpers/dom/findUpClassName' ;
1717import PeerTitle from './peerTitle' ;
@@ -38,12 +38,112 @@ import getDialogIndex from '../lib/appManagers/utils/dialogs/getDialogIndex';
3838import { generateDelimiter } from './generateDelimiter' ;
3939import SettingSection from './settingSection' ;
4040import liteMode from '../helpers/liteMode' ;
41+ import { ButtonMenuItemOptions , ButtonMenuSync } from "./buttonMenu" ;
42+ import ListenerSetter from "../helpers/listenerSetter" ;
43+ import { attachContextMenuListener } from "../helpers/dom/attachContextMenuListener" ;
44+ import positionMenu from "../helpers/positionMenu" ;
45+ import contextMenuController from "../helpers/contextMenuController" ;
46+ import { addFullScreenListener , isFullScreen } from "../helpers/dom/fullScreen" ;
4147
4248type SelectSearchPeerType = 'contacts' | 'dialogs' | 'channelParticipants' ;
4349
4450// TODO: правильная сортировка для addMembers, т.е. для peerType: 'contacts', потому что там идут сначала контакты - потом неконтакты, а должно всё сортироваться по имени
51+ export class AppSelectPeersContextMenu {
52+ private buttons : ( ButtonMenuItemOptions & { verify : ( peerId : PeerId ) => boolean | Promise < boolean > } ) [ ] ;
53+ private element : HTMLElement ;
54+ private targetPeerId : PeerId ;
55+ private managers : AppManagers ;
56+
57+
58+ constructor ( options : {
59+ listenerSetter : ListenerSetter ,
60+ onContextElement : HTMLElement ,
61+ toggleMultiSelectState : ( ) => void ,
62+ selectContact : ( key : PeerId | string ) => void
63+ } ) {
64+ const { listenerSetter} = options ;
65+ this . buttons = [ {
66+ icon : 'select' ,
67+ text : 'Message.Context.Select' ,
68+ verify : ( ) => true ,
69+ onClick : ( e ) => {
70+ cancelEvent ( e ) ;
71+ options . toggleMultiSelectState ( ) ;
72+ options . selectContact ( this . targetPeerId ) ;
73+ console . log ( this . targetPeerId )
74+ }
75+ } ] ;
76+ this . element = ButtonMenuSync ( { buttons : this . buttons , listenerSetter} ) ;
77+ this . element . classList . add ( 'select-peers-menu' , 'night' ) ;
78+
79+ attachContextMenuListener ( {
80+ element : options . onContextElement ,
81+ callback : async ( e ) => {
82+
83+ const li = findUpClassName ( e . target , 'chatlist-chat' ) ;
84+ if ( ! li ) {
85+ return ;
86+ }
87+
88+ if ( this . element . parentElement !== appendTo ) {
89+ appendTo . append ( this . element ) ;
90+ }
91+
92+ cancelEvent ( e ) ;
93+
94+ const peerId = this . targetPeerId = li . dataset . peerId . toPeerId ( ) ;
95+
96+ await filterAsync ( this . buttons , async ( button ) => {
97+ const good = await button . verify ( peerId ) ;
98+ button . element . classList . toggle ( 'hide' , ! good ) ;
99+ return good ;
100+ } ) ;
101+
102+ positionMenu ( ( e as TouchEvent ) . touches ? ( e as TouchEvent ) . touches [ 0 ] : e as MouseEvent , this . element , 'right' ) ;
103+ contextMenuController . openBtnMenu ( this . element ) ;
104+ } ,
105+ listenerSetter
106+ } ) ;
107+
108+ let appendTo : HTMLElement = document . body ;
109+ addFullScreenListener ( document . body , ( ) => {
110+ const isFull = isFullScreen ( ) ;
111+ appendTo = document . body ;
112+
113+ if ( ! isFull ) {
114+ contextMenuController . close ( ) ;
115+ }
116+ } , listenerSetter ) ;
117+ }
118+
119+ }
120+
121+ export interface ISelectPeers {
122+ appendTo : AppSelectPeers [ 'appendTo' ] ,
123+ onChange ?: AppSelectPeers [ 'onChange' ] ,
124+ peerType ?: AppSelectPeers [ 'peerType' ] ,
125+ peerId ?: AppSelectPeers [ 'peerId' ] ,
126+ onFirstRender ?: ( ) => void ,
127+ renderResultsFunc ?: AppSelectPeers [ 'renderResultsFunc' ] ,
128+ chatRightsActions ?: AppSelectPeers [ 'chatRightsActions' ] ,
129+ multiSelect ?: AppSelectPeers [ 'multiSelect' ] ,
130+ rippleEnabled ?: AppSelectPeers [ 'rippleEnabled' ] ,
131+ avatarSize ?: AppSelectPeers [ 'avatarSize' ] ,
132+ placeholder ?: AppSelectPeers [ 'placeholder' ] ,
133+ selfPresence ?: AppSelectPeers [ 'selfPresence' ] ,
134+ exceptSelf ?: AppSelectPeers [ 'exceptSelf' ] ,
135+ filterPeerTypeBy ?: AppSelectPeers [ 'filterPeerTypeBy' ] ,
136+ sectionNameLangPackKey ?: AppSelectPeers [ 'sectionNameLangPackKey' ] ,
137+ managers : AppSelectPeers [ 'managers' ] ,
138+ design ?: AppSelectPeers [ 'design' ] ,
139+ listenerSetter ?: ListenerSetter ,
140+ toggleableMultiSelect ?: boolean ,
141+ }
142+
45143
46144export default class AppSelectPeers {
145+ private contextMenu : AppSelectPeersContextMenu ;
146+ private listenerSetter : ListenerSetter ;
47147 public container = document . createElement ( 'div' ) ;
48148 public list = appDialogsManager . createChatList ( /* {
49149 handheldsSize: 66,
@@ -52,8 +152,7 @@ export default class AppSelectPeers {
52152 private chatsContainer = document . createElement ( 'div' ) ;
53153 public scrollable : Scrollable ;
54154 private selectedScrollable : Scrollable ;
55-
56- private selectedContainer : HTMLElement ;
155+ public selectedContainer : HTMLElement ;
57156 public input : HTMLInputElement ;
58157
59158 // public selected: {[peerId: PeerId]: HTMLElement} = {};
@@ -68,7 +167,7 @@ export default class AppSelectPeers {
68167 private query = '' ;
69168 private cachedContacts : PeerId [ ] ;
70169
71- private loadedWhat : Partial < { [ k in 'dialogs' | 'archived' | 'contacts' | 'channelParticipants' ] : true } > = { } ;
170+ private loadedWhat : Partial < { [ k in 'dialogs' | 'archived' | 'contacts' | 'channelParticipants' ] : true } > = { } ;
72171
73172 private renderedPeerIds : Set < PeerId > = new Set ( ) ;
74173
@@ -83,7 +182,7 @@ export default class AppSelectPeers {
83182 private exceptSelf = false ;
84183 private filterPeerTypeBy : IsPeerType [ ] ;
85184
86- private tempIds : { [ k in keyof AppSelectPeers [ 'loadedWhat' ] ] : number } = { } ;
185+ private tempIds : { [ k in keyof AppSelectPeers [ 'loadedWhat' ] ] : number } = { } ;
87186 private peerId : PeerId ;
88187
89188 private placeholder : LangPackKey ;
@@ -98,25 +197,11 @@ export default class AppSelectPeers {
98197
99198 private design : 'round' | 'square' = 'round' ;
100199
101- constructor ( options : {
102- appendTo : AppSelectPeers [ 'appendTo' ] ,
103- onChange ?: AppSelectPeers [ 'onChange' ] ,
104- peerType ?: AppSelectPeers [ 'peerType' ] ,
105- peerId ?: AppSelectPeers [ 'peerId' ] ,
106- onFirstRender ?: ( ) => void ,
107- renderResultsFunc ?: AppSelectPeers [ 'renderResultsFunc' ] ,
108- chatRightsActions ?: AppSelectPeers [ 'chatRightsActions' ] ,
109- multiSelect ?: AppSelectPeers [ 'multiSelect' ] ,
110- rippleEnabled ?: AppSelectPeers [ 'rippleEnabled' ] ,
111- avatarSize ?: AppSelectPeers [ 'avatarSize' ] ,
112- placeholder ?: AppSelectPeers [ 'placeholder' ] ,
113- selfPresence ?: AppSelectPeers [ 'selfPresence' ] ,
114- exceptSelf ?: AppSelectPeers [ 'exceptSelf' ] ,
115- filterPeerTypeBy ?: AppSelectPeers [ 'filterPeerTypeBy' ] ,
116- sectionNameLangPackKey ?: AppSelectPeers [ 'sectionNameLangPackKey' ] ,
117- managers : AppSelectPeers [ 'managers' ] ,
118- design ?: AppSelectPeers [ 'design' ]
119- } ) {
200+ public toggleableMultiSelect : boolean = false ;
201+ public toggleableMultiSelectState : boolean = false ;
202+
203+
204+ constructor ( options : ISelectPeers ) {
120205 safeAssign ( this , options ) ;
121206
122207 this . container . classList . add ( 'selector' , 'selector-' + this . design ) ;
@@ -195,7 +280,6 @@ export default class AppSelectPeers {
195280 simulateClickEvent ( li ) ;
196281 }
197282 } ) ;
198-
199283 section . content . append ( topContainer ) ;
200284 this . container . append ( section . container /* , delimiter */ ) ;
201285 }
@@ -221,7 +305,7 @@ export default class AppSelectPeers {
221305 let key : PeerId | string = target . dataset . peerId ;
222306 key = key . isPeerId ( ) ? key . toPeerId ( ) : key ;
223307
224- if ( ! this . multiSelect ) {
308+ if ( ! this . multiSelect || ( this . multiSelect && this . toggleableMultiSelect && ! this . toggleableMultiSelectState ) ) {
225309 this . add ( key ) ;
226310 return ;
227311 }
@@ -260,6 +344,10 @@ export default class AppSelectPeers {
260344 } , 0 ) ;
261345 }
262346
347+ private toggleMultiSelectState = ( ) => {
348+ this . toggleableMultiSelectState = true ;
349+ this . container . querySelectorAll ( '.checkbox-field' ) . forEach ( node => node . classList . remove ( 'hide' ) ) ;
350+ }
263351 private onInput = ( ) => {
264352 const value = this . input . value ;
265353 if ( this . query !== value ) {
@@ -553,7 +641,7 @@ export default class AppSelectPeers {
553641 }
554642
555643 private getMoreSomething ( peerType : SelectSearchPeerType ) {
556- const map : { [ type in SelectSearchPeerType ] : ( ) => Promise < any > } = {
644+ const map : { [ type in SelectSearchPeerType ] : ( ) => Promise < any > } = {
557645 dialogs : this . getMoreDialogs ,
558646 contacts : this . getMoreContacts ,
559647 channelParticipants : this . getMoreChannelParticipants
@@ -565,7 +653,22 @@ export default class AppSelectPeers {
565653
566654 private async renderResults ( peerIds : PeerId [ ] ) {
567655 // console.log('will renderResults:', peerIds);
568-
656+ if ( this . toggleableMultiSelect ) {
657+ const { listenerSetter} = this ;
658+ this . contextMenu = new AppSelectPeersContextMenu ( {
659+ onContextElement : this . list ,
660+ listenerSetter,
661+ toggleMultiSelectState : ( ) => {
662+ this . toggleMultiSelectState ( ) ;
663+ } ,
664+ selectContact : ( peerId ) => {
665+ window . requestAnimationFrame ( ( ) => {
666+ const li = this . chatsContainer . querySelector ( '[data-peer-id="' + peerId + '"]' ) as HTMLElement ;
667+ simulateClickEvent ( li ) ;
668+ } )
669+ }
670+ } ) ;
671+ }
569672 // оставим только неконтакты с диалогов
570673 if ( ! this . peerType . includes ( 'dialogs' ) && this . loadedWhat . contacts ) {
571674 peerIds = await filterAsync ( peerIds , ( peerId ) => {
@@ -582,8 +685,12 @@ export default class AppSelectPeers {
582685 } ) ;
583686
584687 if ( this . multiSelect ) {
688+
585689 const selected = this . selected . has ( peerId ) ;
586- const checkboxField = new CheckboxField ( ) ;
690+ const checkboxField = new CheckboxField ( { round : true } ) ;
691+ if ( ! this . toggleableMultiSelectState ) {
692+ checkboxField . hide ( ) ;
693+ }
587694
588695 if ( selected ) {
589696 // dom.listEl.classList.add('active');
@@ -610,7 +717,7 @@ export default class AppSelectPeers {
610717 // console.trace('add');
611718 this . selected . add ( key ) ;
612719
613- if ( ! this . multiSelect ) {
720+ if ( ! this . multiSelect || ( this . multiSelect && this . toggleableMultiSelect && ! this . toggleableMultiSelectState ) ) {
614721 this . onChange ( this . selected . size ) ;
615722 return ;
616723 }
@@ -641,7 +748,7 @@ export default class AppSelectPeers {
641748 }
642749
643750 if ( title ) {
644- if ( typeof ( title ) === 'string' ) {
751+ if ( typeof ( title ) === 'string' ) {
645752 div . innerHTML = title ;
646753 } else {
647754 replaceContent ( div , title ) ;
@@ -650,8 +757,12 @@ export default class AppSelectPeers {
650757 }
651758
652759 div . insertAdjacentElement ( 'afterbegin' , avatarEl ) ;
760+ try {
761+ this . selectedContainer . insertBefore ( div , this . input ) ;
762+ } catch ( e ) {
763+ this . selectedContainer . append ( div ) ;
764+ }
653765
654- this . selectedContainer . insertBefore ( div , this . input ) ;
655766 // this.selectedScrollable.scrollTop = this.selectedScrollable.scrollHeight;
656767 this . onChange ?.( this . selected . size ) ;
657768
0 commit comments