@@ -2,7 +2,15 @@ import { Controller } from "@hotwired/stimulus";
22import { getAyahModalPrefs , setAyahModalPrefs } from "../lib/ayah_modal_store" ;
33
44export default class extends Controller {
5- static targets = [ "panel" , "backdrop" , "form" ] ;
5+ static targets = [
6+ "panel" ,
7+ "backdrop" ,
8+ "form" ,
9+ "search" ,
10+ "translationList" ,
11+ "chevron" ,
12+ "groupContent" ,
13+ ] ;
614
715 connect ( ) {
816 const prefs = getAyahModalPrefs ( ) ;
@@ -14,7 +22,9 @@ export default class extends Controller {
1422 }
1523 if ( prefs . translationIds && prefs . translationIds . length ) {
1624 const current = this . currentTranslationIds ( ) ;
17- const desired = prefs . translationIds . map ( ( x ) => parseInt ( x , 10 ) ) . filter ( ( x ) => Number . isInteger ( x ) ) ;
25+ const desired = prefs . translationIds
26+ . map ( ( x ) => parseInt ( x , 10 ) )
27+ . filter ( ( x ) => Number . isInteger ( x ) ) ;
1828 if ( ! this . sameIds ( current , desired ) ) {
1929 this . setTranslationIds ( desired ) ;
2030 if ( this . formTarget ) this . formTarget . requestSubmit ( ) ;
@@ -38,24 +48,32 @@ export default class extends Controller {
3848 this . panelTarget . classList . remove ( "tw-flex" ) ;
3949 this . backdropTarget . classList . add ( "tw-hidden" ) ;
4050 this . backdropTarget . classList . remove ( "tw-block" ) ;
51+ // Submit form when closing to save translation selections
52+ if ( this . formTarget ) this . formTarget . requestSubmit ( ) ;
4153 }
4254
4355 change ( ) {
4456 const ids = this . currentTranslationIds ( ) ;
4557 setAyahModalPrefs ( { translationIds : ids } ) ;
46- if ( this . formTarget ) this . formTarget . requestSubmit ( ) ;
58+ // Removed form submission to prevent dropdown collapse during selection
4759 }
4860
4961 currentTranslationIds ( ) {
5062 if ( ! this . formTarget ) return [ ] ;
51- const inputs = this . formTarget . querySelectorAll ( 'input[name="translation_ids[]"]:checked' ) ;
52- return Array . from ( inputs ) . map ( ( i ) => parseInt ( i . value , 10 ) ) . filter ( ( x ) => Number . isInteger ( x ) ) ;
63+ const inputs = this . formTarget . querySelectorAll (
64+ 'input[name="translation_ids[]"]:checked' ,
65+ ) ;
66+ return Array . from ( inputs )
67+ . map ( ( i ) => parseInt ( i . value , 10 ) )
68+ . filter ( ( x ) => Number . isInteger ( x ) ) ;
5369 }
5470
5571 setTranslationIds ( ids ) {
5672 if ( ! this . formTarget ) return ;
5773 const set = new Set ( ids . map ( ( x ) => x . toString ( ) ) ) ;
58- const inputs = this . formTarget . querySelectorAll ( 'input[name="translation_ids[]"]' ) ;
74+ const inputs = this . formTarget . querySelectorAll (
75+ 'input[name="translation_ids[]"]' ,
76+ ) ;
5977 inputs . forEach ( ( i ) => {
6078 i . checked = set . has ( i . value ) ;
6179 } ) ;
@@ -71,6 +89,105 @@ export default class extends Controller {
7189 }
7290 return true ;
7391 }
74- }
7592
93+ search ( ) {
94+ const query = this . searchTarget . value . toLowerCase ( ) ;
95+ const items =
96+ this . translationListTarget . querySelectorAll ( ".translation-item" ) ;
97+ const groups =
98+ this . translationListTarget . querySelectorAll ( ".translation-group" ) ;
99+
100+ if ( query === "" ) {
101+ // Show all items and groups when search is empty
102+ items . forEach ( ( item ) => ( item . style . display = "" ) ) ;
103+ groups . forEach ( ( group ) => ( group . style . display = "" ) ) ;
104+ return ;
105+ }
106+
107+ // Find groups that match the search query (language names)
108+ const matchingGroups = [ ] ;
109+ groups . forEach ( ( group ) => {
110+ const language = group . dataset . language ;
111+ if ( language && language . includes ( query ) ) {
112+ matchingGroups . push ( group ) ;
113+ }
114+ } ) ;
115+
116+ // If any groups match the query (language search), show all items in those groups
117+ if ( matchingGroups . length > 0 ) {
118+ items . forEach ( ( item ) => {
119+ const parentGroup = item . closest ( ".translation-group" ) ;
120+ const isInMatchingGroup = matchingGroups . includes ( parentGroup ) ;
121+ item . style . display = isInMatchingGroup ? "" : "none" ;
122+ } ) ;
123+
124+ groups . forEach ( ( group ) => {
125+ const isMatching = matchingGroups . includes ( group ) ;
126+ group . style . display = isMatching ? "" : "none" ;
127+
128+ // Expand matching groups
129+ if ( isMatching ) {
130+ const groupContent = group . querySelector (
131+ '[data-ayah-translation-selector-target="groupContent"]' ,
132+ ) ;
133+ if ( groupContent ) {
134+ groupContent . classList . remove ( "tw-hidden" ) ;
135+ const chevron = group . querySelector (
136+ '[data-ayah-translation-selector-target="chevron"]' ,
137+ ) ;
138+ if ( chevron ) chevron . style . transform = "rotate(180deg)" ;
139+ }
140+ }
141+ } ) ;
142+ } else {
143+ // No groups match, filter individual items by name
144+ items . forEach ( ( item ) => {
145+ const name = item . dataset . name ;
146+ const matches = name . includes ( query ) ;
147+ item . style . display = matches ? "" : "none" ;
148+ } ) ;
76149
150+ // Hide groups that have no visible items
151+ groups . forEach ( ( group ) => {
152+ const visibleItems = group . querySelectorAll (
153+ '.translation-item[style=""], .translation-item:not([style*="none"])' ,
154+ ) ;
155+ group . style . display = visibleItems . length > 0 ? "" : "none" ;
156+
157+ // If group is visible and has matching items, expand it
158+ if ( visibleItems . length > 0 ) {
159+ const groupContent = group . querySelector (
160+ '[data-ayah-translation-selector-target="groupContent"]' ,
161+ ) ;
162+ if ( groupContent ) {
163+ groupContent . classList . remove ( "tw-hidden" ) ;
164+ const chevron = group . querySelector (
165+ '[data-ayah-translation-selector-target="chevron"]' ,
166+ ) ;
167+ if ( chevron ) chevron . style . transform = "rotate(180deg)" ;
168+ }
169+ }
170+ } ) ;
171+ }
172+ }
173+
174+ toggleGroup ( event ) {
175+ const button = event . currentTarget ;
176+ const group = button . dataset . group ;
177+ const content = this . groupContentTargets . find (
178+ ( target ) => target . dataset . group === group ,
179+ ) ;
180+ const chevron = this . chevronTargets . find (
181+ ( target ) => target . dataset . group === group ,
182+ ) ;
183+
184+ if ( content ) {
185+ content . classList . toggle ( "tw-hidden" ) ;
186+ }
187+
188+ if ( chevron ) {
189+ const isExpanded = ! content . classList . contains ( "tw-hidden" ) ;
190+ chevron . style . transform = isExpanded ? "rotate(180deg)" : "rotate(0deg)" ;
191+ }
192+ }
193+ }
0 commit comments