PageSourceSearch

https://www.census.gov/apps/census/components/common/shared/modules.min.96b3c6f6cdc608d9f5f513d42a6b6f8d.js

js census.gov collected 2026-09-24 06:23:31 UTC 12,691 bytes, 320 lines download raw bytes

1var ResultPagination = ( function () {
2    'use strict';
3
4    function keydownPaginate( event, page, listID, nodePath, selector ) {
5        if ( event.key === 'Enter' ) {
6            paginate( page, listID, nodePath, selector );
7        }
8    }
9
10    function paginate( page, listID, nodePath, selector ) {
11        var params = ListUtil.updateQueryString( { 'page': page }, listID );
12        ListUtil.applyParameters( params, listID, nodePath, selector );
13    }
14
15    return {
16        keydownPaginate: keydownPaginate,
17        paginate: paginate
18    }
19})();
20var ListFiltering = ( function () {
21    'use strict';
22
23    // TODO: Connect to value in ListUtil
24    var filterDelimiter = '$';
25
26    function keydownSearch( event, el, listID, nodePath, selector, searchURL ) {
27        if ( event.key === 'Enter' ) {
28            search( el, listID, nodePath, selector, searchURL );
29        }
30    }
31
32    function search( el, listID, nodePath, selector, searchURL ) {
33        const searchParams = searchURL ? { q: el.value, page: 1 } : { query: el.value, page: 1};
34        var params = /** @type {URLSearchParams} */ ListUtil.updateQueryString( searchParams, searchURL ? '' : listID, searchURL );
35        if (!searchURL) {
36            ListUtil.applyParameters( params, listID, nodePath, selector );
37        } else {
38            const q = params.get("q") || params.get("query");
39            window.location = searchURL + '.html?' +  (q && `q=${q}`);
40        } 
41    }
42
43    function keydownFilter( event, el, listID, nodePath, selector ) {
44        if ( event.key === 'Enter' || event.key == 'Space' ) {
45            filter( el, listID, nodePath, selector );
46        }
47    }
48    
49    function filter( el, listID, nodePath, selector ) {
50        switch ( el.tagName.toLowerCase() ) {
51            case 'input':
52                  // Key input on dropdown checkbox
53                var value = el.value;
54                break;
55            case 'i':
56                  // Key input on pill X
57                var value = el.dataset.value;
58                break;
59            default:
60                  // Clicks
61                var value = $( el ).find( 'input[type="checkbox"]' ).val();
62        }
63
64        var params = ListUtil.updateQueryString( { 'filters': value, 'page': 1 }, listID );
65        ListUtil.applyParameters( params, listID, nodePath, selector );
66    }
67
68    function prepopulateFilters( listID ) {
69        var filters = new URLSearchParams( window.location.search ).get( listID + ':filters' );
70
71        if ( filters ) {
72            var $filterPanel = $( '#' + listID + ' .uscb-list__filters' );
73            filters.split( filterDelimiter ).forEach( tag => {
74                // Easiest to just use CSS selectors to find elements with the correct value. Otherwise, several nested loops would be necessary
75                // and would duplicate checks against multiple filters if they shared items
76                var $matchingItems = $filterPanel.find( 'input[type="checkbox"][value="' + tag + '"]' );
77                if ( $matchingItems ) {
78                    $matchingItems.prop( 'checked', true );
79                    $matchingItems.attr( 'aria-checked', true );
80                }
81            });
82        }
83    }
84
85    function prepopulateSearch( listID ) {
86        var query = new URLSearchParams( window.location.search ).get( listID + ':query' );
87        $( '#' + listID + ' .uscb-form-text__search-container input' ).val( query );
88    }
89
90    function keydownClearFilters( event, listID, nodePath, selector ) {
91        if ( event.key === 'Enter' ) {
92            clearFilters( listID, nodePath, selector );
93        }
94    }
95
96    function clearFilters( listID, nodePath, selector ) {
97        var params = ListUtil.updateQueryString( { 'filters': undefined, 'page': undefined, 'query': undefined }, listID );
98        ListUtil.applyParameters( params, listID, nodePath, selector );
99
100        togglePanel( listID + '_panel', false, false );
101    }
102
103    function keydownTogglePanel( event, panelID, open, submitSearch ) {
104        if ( event.key === 'Enter' ) {
105            togglePanel( panelID, open, submitSearch );
106        }
107    }
108
109    function togglePanel( panelID, open, submitSearch ) {
110        var $panel = $( '#' + panelID );
111
112        if ( open ) {
113            $panel.removeClass( 'uscb-hide' );
114        } else {
115            if( submitSearch ) {
116                // Closing the panel, apply the search term if provided
117                const searchInputEle = $panel.find('.uscb-form-text__search-container input').get(0);
118                if( searchInputEle.value?.trim().length ) {
119                    // Faking an "Enter" on the input, to leverage existing attribute listeners
120                    const enterEvent = new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, which: 13, bubbles: true });
121                    searchInputEle.dispatchEvent(enterEvent);
122                }
123            }
124            
125            // Close the panel
126            $panel.addClass( 'uscb-hide' );
127        }
128    }
129
130    function toggleToUpdateProps(ele, panelID) {
131        var $dropDownButton = $( ele );
132        var $panel = $( '#' + panelID );
133
134        if ( $panel[0] ) {
135        	if ( $panel[0].className.includes('uscb-hide')) {
136                $dropDownButton.attr('aria-expanded', 'false');
137        	} else {
138                $dropDownButton.attr('aria-expanded', 'true');
139        	}
140        }
141    }
142
143    return {
144        keydownSearch: keydownSearch,
145        search: search,
146        prepopulateSearch: prepopulateSearch,
147
148        keydownFilter: keydownFilter,
149        filter: filter,
150        prepopulateFilters: prepopulateFilters,
151
152        clearFilters: clearFilters,
153        keydownClearFilters: keydownClearFilters,
154
155        togglePanel: togglePanel,
156        keydownTogglePanel: keydownTogglePanel,
157        toggleToUpdateProps: toggleToUpdateProps
158    }
159})();
160var ResultTabs = ( function() {
161    'use strict';
162
163    function keydownChangeTab( event, tab, listID, nodePath, selector ) {
164        if ( event.key === 'Enter' ) {
165            changeTab( tab, listID, nodePath, selector );
166        }
167    }
168
169    function changeTab( tab, listID, nodePath, selector ) {
170        var params = ListUtil.updateQueryString( { 'tab': tab, 'page': undefined }, listID );
171        ListUtil.applyParameters( params, listID, nodePath, selector );
172    }
173
174    return {
175        changeTab: changeTab,
176        keydownChangeTab: keydownChangeTab
177    }
178})();
179var ListUtil = ( function() {
180    'use strict';
181
182    var filterDelimiter = '$';
183
184    function updateQueryString( updates, listID, noRedirect ) {
185        var params = new URLSearchParams( window.location.search );
186
187        var updateKeys = Object.keys( updates );
188        for ( var i = 0; i < Object.keys( updates ).length; i++ ) {
189            var key = updateKeys[ i ];
190            var namespacedKey = !listID ? key : listID + ':' + key;
191
192              // If the incoming value is undefined, clear the key
193            if ( updates[ key ] == undefined ) {
194                params.delete( namespacedKey );
195                continue;
196            }
197
198              // Tags are a special case. If they already exist as a parameter, they will be removed. If they don't exist, they will be appended, not replaced.
199            if ( key === 'filters' && params.get( namespacedKey ) ) {
200                var tagParam = params.get( namespacedKey );
201
202                if ( tagParam.includes( updates[ key ] ) ) {
203                      // Remove the existing tag
204                        // If it's the only tag, remove the whole parameter
205                    if ( tagParam === updates[ key ] ) {
206                        params.delete( namespacedKey );
207                    } else {
208                          // Determine where the delimiter is relative to the incoming tag
209                        var pattern = tagParam.startsWith( updates[ key ] ) ? updates[ key ] + filterDelimiter : filterDelimiter + updates[ key ];
210                        params.set( namespacedKey, tagParam.replace( pattern, '' ).trim() );
211                    }
212                } else {
213                      // Add new tag
214                    params.set( namespacedKey, tagParam + filterDelimiter + updates[ key ] );
215                }
216            } else {
217                params.set( namespacedKey, updates[ key ] );
218            }
219        }
220        if (noRedirect) return params;
221        var url = window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + params.toString();
222        window.history.pushState( { path: url }, '', url );
223
224        return params;
225    }
226
227    function applyParameters( params, listID, nodePath, selector ) {
228        var url = nodePath + '.' + selector + '.html?' + params.toString();
229
230          // Add loading indicator on 500ms delay. If added immediately, some variants of lists are fast enough to return almost immediately
231            // so content appears to flash. Adding the delay means that quick-responding lists won't do this but slower ones will still give user feedback
232        var timer = setTimeout( () => {
233            replaceHTML( '<div id="' + listID + '" class="uscb-loading-circular-indeterminate" style="margin: 0 auto" aria-label="Loading"></div>', listID );
234            document.dispatchEvent( new Event( 'activate-loading-indicators' ) );
235        }, 500 );
236
237        $.get( url ).then( response => {
238            clearTimeout( timer );
239            replaceHTML( response, listID );
240
241              // Updates
242            ListFiltering.prepopulateSearch( listID );
243            ListFiltering.prepopulateFilters( listID );
244
245            document.dispatchEvent( new Event( 'adjust-lists' ) );
246            window.location.hash = listID;
247        });
248    }
249
250    function replaceHTML( html, listID ) {
251        var $root = $( '#' + listID );
252        if ( $root.length > 0 ) {
253              // Create contextual fragment so that scripts in resulting HTML are executed properly
254            var htmlFragment = document.createRange().createContextualFragment( html );
255            $root[0].replaceWith( htmlFragment );
256        }
257    }
258
259    return {
260        updateQueryString: updateQueryString,
261        applyParameters: applyParameters
262    };
263})();
264
265  // TODO: Genericize this entire utility and move to other clientlib
266  var DropdownUtil = ( function() {
267
268        function keydownToggle( event, dropdownID ) {
269            if ( event.key === 'ArrowDown' ) {
270                toggle( dropdownID );
271                event.preventDefault();
272            }
273        }
274
275        function clickOutside( dropdownID ) {
276            let dropdownMenu = $('#' + dropdownID );
277            let dropdownContainer = dropdownMenu.siblings('.uscb-dropdown-container, .uscb-result__tabs-tab-more');
278
279            if( dropdownMenu.length === 0 || dropdownContainer.length === 0 || dropdownMenu.hasClass('uscb-hide') ) {
280                return;
281            }
282
283            let namespace = 'click.dropdownUtil.' + dropdownID.replace(/[^a-zA-Z0-9_-]/g, '');
284            $('body').off(namespace);
285            $('body').on(namespace, function(event) {
286                const hasClickedContainer = $(event.target).closest(dropdownContainer).length > 0;
287                const hasClickedMenu = $(event.target).closest(dropdownMenu).length > 0;
288
289                if( hasClickedContainer === false && hasClickedMenu === false ) {
290                    if( !dropdownMenu.hasClass('uscb-hide') ) {
291                        toggle(dropdownID);
292                    }
293
294                    $('body').off(namespace);
295                }
296
297                if( hasClickedMenu === true && hasClickedContainer === false ) {
298                    $('body').off(namespace);
299                    toggle(dropdownID);
300                }
301            });
302            
303        } //outerfunction
304
305        function toggle( dropdownID ) {
306            var dropdownMenu = $( '.' + dropdownID );
307            dropdownMenu.toggleClass( 'uscb-hide' );
308
309            var isOpen = dropdownMenu.length > 0 && !dropdownMenu.first().hasClass( 'uscb-hide' );
310            dropdownMenu.each(function() {
311                $(this).siblings('.uscb-dropdown-container, .uscb-result__tabs-tab-more').attr('aria-expanded', isOpen ? 'true' : 'false');
312            });
313        }
314
315        return {
316            keydownToggle: keydownToggle,
317            toggle: toggle,
318            clickOutside : clickOutside  
319        }
320})();

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.