PageSourceSearch

https://www.subaru.co.za/wp-content/plugins/wp-store-locator/assets/src/frontend/js/modules/wpsl-buttons.js

js subaru.co.za collected 2026-10-02 21:25:20 UTC 12,030 bytes, 334 lines download raw bytes

1import { slData, config } from './wpsl-shared.js';
2import { helpers } from './wpsl-helpers.js';
3import { search } from './wpsl-search.js';
4import { geolocation } from './wpsl-geolocation.js';
5import { accessibility } from './wpsl-accessibility.js';
6
7/**
8 * Button handlers for WPSL frontend
9 * 
10 * @since 3.0.0
11 */
12export const buttons = {
13    args: {
14        autoLoad: false,
15        wasEmpty: true
16    },
17
18    /**
19     * Execute search based on current state.
20     * 
21     * @since 3.0.0
22     * @param {object} args Search arguments
23     * @param {string} typeField Type field value
24     */
25    executeSearch: function( args, typeField ) {
26        if ( ( typeField.length && typeField != 'location' ) || ( ! typeField && typeof wpslSettings.search !== 'undefined' && wpslSettings.search.namesEnabled ) ) {
27            config.search.namesEnabled = 1;
28            config.search.skipGeocode = true;
29
30            jQuery( '.wpsl-icon-direction' ).hide();
31
32            search.reset();
33            search.run( args );
34        } else {
35            config.search.namesEnabled = 0;
36            delete config.search.skipGeocode;
37
38            jQuery( '.wpsl-icon-direction' ).show();
39            search.reset();
40
41            // Coordinates are known when a suggestion was picked from the
42            // autocomplete, or when the search widget passed the location
43            // of a geolocation request along with the searched text.
44            if ( slData.autoCompleteLatLng ) {
45                args.latLng = slData.autoCompleteLatLng;
46
47                // Border enforcement needs the country code and the statistics
48                // add-on needs the address components, both of which only come
49                // from the reverse geocode response. Skipping it when either is
50                // active leaves restrictions[borders] as 'undefined,undefined'.
51                if ( ! config.search.restrictions.borders && typeof config.collectStatistics === 'undefined' ) {
52                    slData.skipReverseGeocode = true;
53                } else {
54                    slData.skipReverseGeocode = false;
55                }
56
57                search.prepare( args );
58            } else {
59                search.submitActions( buttons.args );
60            }
61        }
62    },
63
64    /**
65     * Bind search button and input field events.
66     *
67     * @since   3.0.0
68     * @returns {void}
69     */
70    bindSearch: function() {
71        const $input = helpers.input.getSearchField();
72
73        let typeField = '', 
74            args = {};
75
76        // Make sure the 'enter' input triggers the
77        // search instead of opening the next dropdown.
78        $input.on( 'keypress', function( e ) {
79            if ( e.which == 13 ) {
80                jQuery( '#wpsl-search-btn' ).trigger( 'click' );
81
82                return false;
83            }
84        });
85
86        // v3 templates: show / hide the 'clear' button and remove the error state.
87        if ( helpers.flexboxAvailable() ) {
88            $input.on( 'input', function() {
89                const isEmpty = jQuery( this ).val().length === 0;
90
91                buttons.updateClearSearchVisibility( isEmpty );
92                
93                // Remove error state when user starts typing
94                if ( ! isEmpty ) {
95                    jQuery( '.wpsl-search-wrap' ).removeClass( 'wpsl-error' );
96                }
97
98                // Force a fresh geocode instead of reusing stale coordinates.
99                slData.autoCompleteLatLng = '';
100            });
101        } else {
102            // For v2 templates, remove error class from input field when user starts typing
103            $input.on( 'input', function() {
104                if ( jQuery( this ).val().length > 0 ) {
105                    jQuery( this ).removeClass( 'wpsl-error' );
106                }
107
108                // Force a fresh geocode instead of reusing stale coordinates.
109                slData.autoCompleteLatLng = '';
110            });
111        }
112
113        jQuery( '#wpsl-search-btn' ).off( 'click keydown' ).on( 'click keydown', function( e ) {
114            // Allow both click and keyboard activation (Enter or Space)
115            if ( e.type === 'keydown' && e.which !== 13 && e.which !== 32 ) {
116                return;
117            }
118            
119            if ( e.type === 'keydown' ) {
120                e.preventDefault();
121            }
122
123            jQuery( '#wpsl-search-btn' ).attr( 'disabled', true );
124            $input.removeClass();
125
126            // Make sure the previous results and
127            // filter are hidden for v3.x+ templates.
128            if ( helpers.flexboxAvailable() ) {
129                jQuery( '#wpsl-result-list' ).hide();
130                jQuery( '.wpsl-search-wrap' ).removeClass( 'wpsl-error' );
131
132                helpers.panel.maybeCloseFilters();
133            }
134
135            slData.useBasicMode            = false;
136            slData.firstLoadInProgress     = false;
137
138            if ( jQuery( '#wpsl-search-wrap input[name=types]' ).length ) {
139                typeField = jQuery( '#wpsl-search-wrap input[name=types]' ).val().trim();
140            }
141
142            if ( $input.val() ) {
143                buttons.executeSearch( args, typeField );
144            } else if ( helpers.flexboxAvailable() && jQuery( '.wpsl-filter input[type="checkbox"]:checked, .wpsl-custom-c
144heckboxes input[type="checkbox"]:checked' ).length > 0 ) {
145                // Filter-only search ( category and / or custom panels like country, no user input required, v3.x+ templates )
146                config.search.skipGeocode = true;
147
148                // Clear the existing markers / results before running, like the geocoded search path does.
149                search.reset();
150                search.run( args );
151            } else if ( jQuery( '#wpsl-wrap' ).hasClass( 'wpsl-cat-filter-only' ) ) {
152                config.search.skipGeocode = true;
153
154                search.reset();
155                search.run( args );
156            } else {
157                jQuery( '#wpsl-search-btn' ).attr( 'disabled', false );
158                $input.removeClass();
159
160                if ( helpers.flexboxAvailable() ) {
161                    jQuery( '.wpsl-search-wrap' ).addClass( 'wpsl-error' );
162                } else {
163                    $input.addClass( 'wpsl-error' );
164                }
165
166                $input.trigger( 'focus' );
167            }
168
169            return false;
170        });
171    },
172
173    /**
174     * Update the visibility of the clear search input button.
175     * 
176     * @since   3.0.0
177     * @param   {boolean} isEmpty Whether the search input is empty
178     * @returns {void}
179     */
180    updateClearSearchVisibility: function( isEmpty ) {
181        const $clearBtn = jQuery( '#wpsl-clear-search-input' );
182
183        if ( ! isEmpty ) {
184            $clearBtn.show();
185            
186            if ( ! $clearBtn.data( 'bound' ) ) {
187                this.bindEmptySearchInput();
188                $clearBtn.data( 'bound', true );
189            }
190        } else {
191            $clearBtn.hide();
192            search.reset();
193        }
194    },
195
196    /**
197     * Bind map control icons (reset and direction buttons).
198     *
199     * @since   3.0.0
200     * @returns {void}
201     */
202    bindMapControlIcons: function() {
203        if ( jQuery( '.wpsl-icon-reset, #wpsl-reset-map' ).length > 0 ) {
204
205            this.bindResetMapBtn();
206
207            // Hide it to prevent users from clicking it
208            // before the store location are placed on the map.
209            if ( jQuery.isEmptyObject( slData.viewport ) ) {
210                jQuery( '.wpsl-icon-reset' ).hide();
211            } else {
212                // Google Maps only adds the controls once its tiles are in, by
213                // which time the autoload search has already stored the
214                // viewport and tried to show a button that wasn't there yet.
215                helpers.map.revealResetBtn();
216            }
217        }
218
219        // Bind the direction button to trigger a new geolocation request.
220        jQuery( '.wpsl-icon-direction' ).on( 'click keydown', function( e ) {
221            // For keyboard events, only respond to Enter or Space
222            if ( e.type === 'keydown' && ! accessibility.keyboard.isActivationKey( e ) ) {
223                return;
224            }
225
226            if ( e.type === 'keydown' ) {
227                e.preventDefault();
228            }
229
230            jQuery( this ).addClass( 'wpsl-user-activated' );
231            jQuery( '#wpsl-search-btn' ).attr( 'disabled', true );
232
233            slData.directions.active = false;
234
235            // If the direction details are showing, then hide them.
236            if ( jQuery( '#wpsl-direction-details' ).is( ':visible' ) ) {
237                jQuery( '.wpsl-back' ).trigger( 'click' );
238            }
239
240            geolocation.run( true );
241        });
242    },
243
244    /**
245     * Bind the clear search input button.
246     *
247     * @since   3.0.0
248     * @returns {void}
249     */
250    bindEmptySearchInput: function() {
251        jQuery( '#wpsl-clear-search-input' ).off( 'click keydown' ).on( 'click keydown', function( e ) {
252
253            // Allow both click and keyboard activation (Enter or Space)
254            if ( e.type === 'keydown' && e.which !== 13 && e.which !== 32 ) {
255                return;
256            }
257            
258            if ( e.type === 'keydown' ) {
259                e.preventDefault();
260            }
261
262            helpers.input.getSearchField().val( '' );
263            jQuery( '#wpsl-clear-search-input' ).hide();
264
265            jQuery( '.wpsl-autocomplete-search-results' ).hide();
266            
267            // Close filters if they're open (same as search button behavior)
268            if ( helpers.flexboxAvailable() ) {
269                helpers.panel.maybeCloseFilters();
270            }
271            
272            search.reset();
273
274            return false;
275        });
276    },
277
278    /**
279     * Make sure that when the reset button ( bottom corner of the map ) is
280     * clicked the map is restored to how it was on pageload.
281     *
282     * @since   3.0.0
283     * @returns {void}
284     */
285    bindResetMapBtn: function() {
286        jQuery( '.wpsl-icon-reset , #wpsl-reset-map' ).on( 'click keydown', function( e ) {
287            // For keyboard events, only respond to Enter or Space
288            if ( e.type === 'keydown' && ! accessibility.keyboard.isActivationKey( e ) ) {
289                return;
290            }
291
292            if ( e.type === 'keydown' ) {
293                e.preventDefault();
294            }
295
296            helpers.results.restoreInitialState();
297        });
298    },
299
300    /**
301     * Bind the back button that returns from the directions to the results.
302     *
303     * @since  3.0.0
304     * @returns {void}
305     */
306    bindRemoveDirections: function() {
307        jQuery( '#wpsl-result-list' ).on( 'click', '.wpsl-back', function() {
308            slData.provider.api.directions.restoreResults();
309
310            // Move focus to the first store result so the user can keep cycling
311            // the list. setTimeout(0) defers until restoreResults() has finished
312            // showing #wpsl-stores.
313            setTimeout( function() {
314                const firstResult = document.querySelector(
315                    '#wpsl-stores ul li .wpsl-location-name a, #wpsl-stores ul li a[href]'
316                );
317
318                if ( firstResult ) {
319                    firstResult.focus();
320                } else {
321                    // Fallback: focus the result list container itself
322                    const resultList = document.querySelector( '#wpsl-stores' );
323
324                    if ( resultList ) {
325                        resultList.setAttribute( 'tabindex', '-1' );
326                        resultList.focus();
327                    }
328                }
329            }, 0 );
330
331            return false;
332        });
333    },
334};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.