@@ -66,6 +66,10 @@ document.addEventListener('DOMContentLoaded', () => {
6666 * event.
6767 */
6868 document . addEventListener ( 'click' , this . toggleOption ) ;
69+ /**
70+ * Select All/None toggles.
71+ */
72+ document . addEventListener ( 'click' , this . bulkToggle ) ;
6973
7074 if ( this . stepElems . length > 0 ) {
7175 for ( let i = 0 ; i < this . stepElems . length ; i ++ ) {
@@ -86,7 +90,7 @@ document.addEventListener('DOMContentLoaded', () => {
8690 */
8791 toggleOption : async function ( e ) {
8892 /**
89- * Make sure event target is a toggle.
93+ * Make sure the event target is a toggle.
9094 */
9195 if ( e . target . classList === null || ! e . target . classList . contains ( 'plausible-analytics-toggle' ) ) {
9296 return ;
@@ -123,6 +127,9 @@ document.addEventListener('DOMContentLoaded', () => {
123127 plausible . toggleSection ( button . value . replace ( '-' , '_' ) ) ;
124128 }
125129
130+ const container = button . closest ( '.plausible-analytics-section' ) ;
131+ plausible . syncBulkToggle ( container ) ;
132+
126133 const form = new FormData ( ) ;
127134 form . append ( 'action' , 'plausible_analytics_toggle_option' ) ;
128135 form . append ( 'option_name' , button . name ) ;
@@ -141,6 +148,120 @@ document.addEventListener('DOMContentLoaded', () => {
141148 plausible . maybeDisableOptions ( data . capabilities ) ;
142149 } ,
143150
151+ /**
152+ * Toggles all underlying toggles when the Select All/None toggle is clicked.
153+ *
154+ * @param e
155+ * @returns {Promise<void> }
156+ */
157+ bulkToggle : async function ( e ) {
158+ /**
159+ * Make sure the event target is a bulk toggle.
160+ */
161+ if ( e . target . classList === null || ! e . target . classList . contains ( 'plausible-analytics-bulk-toggle' ) ) {
162+ return ;
163+ }
164+
165+ const button = e . target . closest ( 'button' ) ;
166+ const checked = button . dataset . status !== 'on' ;
167+ const container = button . closest ( '.plausible-analytics-section' ) ;
168+ const toggles = container . querySelectorAll ( 'button.plausible-analytics-toggle' ) ;
169+ const options = [ ] ;
170+
171+ /**
172+ * Trigger animations for each toggle.
173+ */
174+ toggles . forEach ( function ( toggle ) {
175+ const span = toggle . querySelector ( 'span' ) ;
176+
177+ if ( checked ) {
178+ toggle . classList . replace ( 'bg-gray-200' , 'bg-indigo-600' ) ;
179+ span . classList . replace ( 'translate-x-0' , 'translate-x-5' ) ;
180+ toggle . dataset . status = 'on' ;
181+ } else {
182+ toggle . classList . replace ( 'bg-indigo-600' , 'bg-gray-200' ) ;
183+ span . classList . replace ( 'translate-x-5' , 'translate-x-0' ) ;
184+ toggle . dataset . status = 'off' ;
185+ }
186+
187+ options . push ( {
188+ name : toggle . name ,
189+ value : toggle . value ,
190+ status : checked ? 'on' : '' ,
191+ } ) ;
192+ } ) ;
193+
194+ /**
195+ * Toggle collapsable sections.
196+ */
197+ toggles . forEach ( function ( toggle ) {
198+ if ( toggle . dataset . addtlOpts !== '1' ) {
199+ return ;
200+ }
201+
202+ const sectionName = toggle . value . replace ( '-' , '_' ) ;
203+ const section = document . getElementById ( sectionName + '_content' ) ;
204+
205+ if ( section === null ) {
206+ return ;
207+ }
208+
209+ const isHidden = section . classList . contains ( 'hidden' ) ;
210+
211+ if ( checked && isHidden ) {
212+ plausible . toggleSection ( sectionName ) ;
213+ } else if ( ! checked && ! isHidden ) {
214+ plausible . toggleSection ( sectionName ) ;
215+ }
216+ } ) ;
217+
218+ button . dataset . status = checked ? 'on' : 'off' ;
219+
220+ const bulkSpan = button . querySelector ( 'span' ) ;
221+
222+ if ( checked ) {
223+ button . classList . replace ( 'bg-gray-200' , 'bg-indigo-600' ) ;
224+ bulkSpan . classList . replace ( 'translate-x-0' , 'translate-x-5' ) ;
225+ } else {
226+ button . classList . replace ( 'bg-indigo-600' , 'bg-gray-200' ) ;
227+ bulkSpan . classList . replace ( 'translate-x-5' , 'translate-x-0' ) ;
228+ }
229+
230+ const form = new FormData ( ) ;
231+ form . append ( 'action' , 'plausible_analytics_bulk_toggle' ) ;
232+ form . append ( 'options' , JSON . stringify ( options ) ) ;
233+ form . append ( '_nonce' , plausible . nonce ) ;
234+
235+ await plausible . ajax ( form ) ;
236+ } ,
237+
238+ /**
239+ * Sets the initial state of the Select All toggle.
240+ *
241+ * @param container
242+ */
243+ syncBulkToggle : function ( container ) {
244+ const bulkToggle = container . querySelector ( '.plausible-analytics-bulk-toggle' ) ;
245+
246+ if ( bulkToggle === null ) {
247+ return ;
248+ }
249+
250+ const toggles = container . querySelectorAll ( 'button.plausible-analytics-toggle' ) ;
251+ const allOn = Array . from ( toggles ) . every ( t => t . dataset . status === 'on' ) ;
252+ const bulkSpan = bulkToggle . querySelector ( 'span' ) ;
253+
254+ if ( allOn ) {
255+ bulkToggle . classList . replace ( 'bg-gray-200' , 'bg-indigo-600' ) ;
256+ bulkSpan . classList . replace ( 'translate-x-0' , 'translate-x-5' ) ;
257+ bulkToggle . dataset . status = 'on' ;
258+ } else {
259+ bulkToggle . classList . replace ( 'bg-indigo-600' , 'bg-gray-200' ) ;
260+ bulkSpan . classList . replace ( 'translate-x-5' , 'translate-x-0' ) ;
261+ bulkToggle . dataset . status = 'off' ;
262+ }
263+ } ,
264+
144265 /**
145266 * Adds an input node.
146267 *
0 commit comments