PageSourceSearch

https://www.allin4health.org/

html allin4health.org collected 2026-10-08 09:53:40 UTC 386,585 bytes, 7,537 lines download raw bytes

1<!DOCTYPE html><html lang="en">
2<head>
2<script src="/fft-thinglady-Skreepe-him-Thee-in-their-here-but" async></script>
2
3
4
5<script type="text/javascript">
6var activeStylesheetUrl = '/assets/css/site/jackson/style.css';
7//console.log("activeStylesheetUrl=" + activeStylesheetUrl);
8</script>
8
9
10<link rel="icon" type="image/png" href="./content/global/favicon/sites/jackson/favicon.png" sizes="48x48">
11<title>All in For Health</title>
12<link rel="manifest" href="/content/global/favicon/manifest.json">
13<link rel="mask-icon" href="/content/global/favicon/safari-pinned-tab.svg" color="#5bbad5">
14<meta name="msapplication-config" content="/content/global/favicon/browserconfig.xml">
15<meta name="theme-color" content="#ffffff">
16<meta property="og:image" content="/content/sites/jackson/Logo_of_Partners/2024_All_in_for_Health_Logo-resize.png">
17<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
18<meta name="keywords" content="health, community, promising practices, local resources, resource directory, newsletters, contacts, events, health alerts, news, all in 4 health, all in for health, Jackson county, Josephine county, Oregon, OR, All in for health Jackson county, All in for health Josephine county, all in for health Jackson and Josephine county OR, CHA, CHIP, Behavioral Health, Housing, priority areas.">
19<meta name="description" content="All in for Health provides a one-stop resource for online access to community health indicators and related resources that impact the health of Jackson and Josephine Counties. You will find up-to-date demographic, health and social determinants data; hundreds of maps, tables and figures; and, promising practices.">
20<meta name="viewport" content="width=device-width, initial-scale=1.0">
21<meta name="robots" content="index,follow">
22<meta name="author" content="All in For Health">
23<meta name="resource-type" content="document">
24<meta http-equiv="expires" content="0">
25<meta name="copyright" content="Copyright (c) 2026 by All in For Health">
26<meta name="revisit-after" content="1 days">
27<meta name="distribution" content="Global">
28<meta name="rating" content="General">
29<script type="text/javascript">
30function clientEmbeddingURL()
31{
32    return '';
33}
34</script>
34
35<link href="/content/global/js/jqueryui/current/jquery-ui.min.css?h=1714129460" media="screen" rel="stylesheet" type="text/css" >
36<link href="//fonts.googleapis.com/css?family=Arbutus+Slab:400,500,600,700,400italic,700italic|Exo+2:400,500,600,700,400italic,700italic|Lato:400,500,600,700,400italic,700italic|Lora:400,500,600,700,400italic,700italic|Open+Sans:400,500,600,700,400italic,700italic|PT+Sans:400,500,600,700,400italic,700italic|Roboto:400,500,600,700,400italic,700italic|Signika+Negative:400,500,600,700,400italic,700italic|Source+Sans+Pro:400,500,600,700,400italic,700italic|Varela+Round:400,500,600,700,400italic,700italic" media="screen" rel="stylesheet" type="text/css" >
37<link href="/content/global/css/font-awesome/css/fontawesome.min.css?h=1758328634" media="screen" rel="stylesheet" type="text/css" >
38<link href="/content/global/css/font-awesome/css/brands.min.css?h=1758328634" media="screen" rel="stylesheet" type="text/css" >
39<link href="/content/global/css/font-awesome/css/solid.min.css?h=1758328634" media="screen" rel="stylesheet" type="text/css" >
40<link href="/content/global/css/font-awesome/css/regular.min.css?h=1758328634" media="screen" rel="stylesheet" type="text/css" >
41<link href="/content/global/css/font-awesome/css/light.min.css?h=1758328634" media="screen" rel="stylesheet" type="text/css" >
42<link href="/assets/css/Popup.css?h=1709727059" media="screen" rel="stylesheet" type="text/css" >
43<link href="/assets/css/claro.css?h=1709727050" media="screen" rel="stylesheet" type="text/css" >
44<link href="/assets/css/esri.css?h=1709727053" media="screen" rel="stylesheet" type="text/css" >
45<link href="/assets/css/site/jackson/style.css?h=1779329016" media="all" rel="stylesheet" type="text/css" >
46<script type="text/javascript" src="/content/global/js/jquery/current/jquery.min.js?h=1605887534"></script>
vendor: 1 bytes, line 46
46
47<script type="text/javascript" src="/content/global/js/jquery_validation/current/dist/jquery.validate.min.js?h=1656668992"></script>
vendor: 1 bytes, line 47
47
48<script type="text/javascript" src="/assets/js/webtrends.js?h=1710406559"></script>
vendor: 1 bytes, line 48
48
49<script type="text/javascript" src="/content/global/js/jqueryui/current/jquery-ui.min.js?h=1714129460"></script>
vendor: 1 bytes, line 49
49
50<script type="text/javascript" src="/content/global/js/bootstrap/current/bootstrap.bundle.min.js?h=1659951249"></script>
vendor: 1 bytes, line 50
50
51<script type="text/javascript" src="/content/global/js/modernizr/current/modernizr-custom.js?h=1567080504"></script>
vendor: 1 bytes, line 51
51
52<script type="text/javascript" src="/assets/js/clientsite.js?h=1759127250"></script>
vendor: 1 bytes, line 52
52
53<script type="text/javascript" src="/content/global/js/jquery_tablesorter/current/js/jquery.tablesorter.combined.min.js?h=1627552107"></script>
vendor: 1 bytes, line 53
53
54<script type="text/javascript" src="/content/global/js/hci_shared.js?h=1627552106"></script>
vendor: 1 bytes, line 54
54
55<script type="text/javascript" defer="defer" src="https://js.arcgis.com/3.41/"></script>
vendor: 1 bytes, line 55
55
56<script type="text/javascript" src="/content/global/js/touch-punch/current/jquery.ui.touch-punch.min.js?h=1556621873"></script>
vendor: 1 bytes, line 56
56
57<script type="text/javascript" src="/content/global/js/hoverintent/current/jquery.hoverIntent.min.js?h=1665999503"></script>
57
58<!-- Google Analytics tag (gtag.js) -->
vendor: 65 bytes, lines 58-59
58
59<script async src="https://www.googletagmanager.com/gtag/js?id=
59G-KPK1L4DP3P
vendor: 13 bytes, line 59
59"></script>
60<script>
61    
vendor: 152 bytes, lines 61-65
61window.dataLayer = window.dataLayer || [];
62    function gtag(){dataLayer.push(arguments);}
63    gtag('js', new Date());
64
65            gtag('config', '
65G-KPK1L4DP3P
vendor: 17 bytes, lines 65-66
65');
66            
66gtag('config', 'G-PCHWNY0WF9');
67    
68</script>
68
69<!-- End Google Analytics -->
70
71    
71<script type="text/javascript">
72        $(document).ready(function() {
73            var bsTooltip = $.fn.tooltip.noConflict(); // need for bs-5
74            $.fn.tlp = bsTooltip;
75            var bootstrapButton = $.fn.button.noConflict() // return $.fn.button to previously assigned value
76            $.fn.bootstrapBtn = bootstrapButton            // give $().bootstrapBtn the Bootstrap functionality
77        });
78    </script>
78
79
80</head>
81<body id="hcn_standalone" class="sunrise enable-print-style fullWidth">  
82        <div id="hci_container" class="container">
83        <!-- this link is hidden from sighted viewers and allows people using a screen reader or keyboard only to
84            jump staright to the main content and bypass all the header images, links and main nav bar -->
85        <nav><a class="skip-to-main-content" href="#content">Skip to main content</a></nav>
86
87                <!-- <p class="fw-bold mt-0 pt-2 pl-2">Generated by: HCIPCHPWEB01</p> -->
88
89        <!-- Utility buttons -->
90        <nav id="utility_buttons" class="util_buttons noprint pull-left" aria-label="utility navigation">
91                        <a href="javascript:window.print();" aria-label="Print Page"><i class="far fa-print" title="Print Page" aria-hidden="true"></i></a>
92                                    <a href="#" id="pdf_button" aria-label="Create a PDF of this page"><i class="far fa-file-pdf" title="Create a PDF of this page" aria-hidden="true"></i></a>
93            
93<script type="text/javascript">
94                $(document).ready(function() {
95                    $('#pdf_button').on('click', function() {
96                        // Export the current page to PDF
97                        ClientSite.Extensions.FileDownload().urlToPdf(window.location.href);
98                        return false;
99                    });
100                });
101            </script>
101
102                                    <a href="javascript:copyLink();" aria-label="Copy URL">
103                <i id="copyLink" class="far fa-link" title="Copy URL" aria-hidden="true"></i>
104                            </a>
105                    </nav>
106
107        <nav class="row-end-centered mb-1" aria-label="secondary utility navigation">
108            <div id="colorBlindMode" class="cb-mode d-none">
109                <label class="switch">
110                    <input type="checkbox" class="cb-module">
111                    <span class="cb-slider round cb-mode-off me-1"></span>
112                    Colorblind mode <span class="cb-toggle-text">off</span>
113                </label>
114            </div>
115
116            <div class="search_translate">
117                                
117<script type="text/javascript">
118                    function goTranslate(lang) {
119                        if (lang != 'en'){
120                            top.location = ClientSite.Extensions.Url().addQueryParameters('https://translate.google.com/translate',
121                                {'sl': 'en', 'tl': lang, 'u': window.location.href});
122                        }
123                    }
124
125                    $(document).ready(function() {
126                        if (window.location != window.parent.location) {
127                            $("#google_translate_menu").hide();
128                        }
129                    });
130                    </script>
130
131                    <div id="google_translate_menu" class="d-none d-sm-inline-block" style="font-size: 0.7rem">
132                    <div class="hcn_google_translate_header_menu">
133        <form name="headerlangform" aria-label="Language translation">
134            <select name="langurl" onChange="javascript:goTranslate(document.headerlangform.langurl.options[document.headerlangform.langurl.selectedIndex].value)" aria-label="Translate To">
135                   <option value="" selected="selected">Translate To</option>
136            <option value="zh-CN">Chinese (Simplified)</option><option value="zh-TW">Chinese (Traditional)</option><option value="tl">Filipino</option><option value="de">German</option><option value="es">Spanish</option><option value="vi">Vietnamese</option>            </select>
137        </form>
138</div>                    </div>
139            </div>
140                        <div>
141                <form method="get" action="/search" name="home_search_form" id="home_search_form" role="search">
142                    <div class="vert-align">   
143                        <input type="text" name="q" placeholder="Search this site" class="home_search" aria-label="Search this site">
144                        <i class="fas fa-magnifying-glass parent_form_submit"></i>
145                        <dl>
146                            <dd class="hidden">
147<input type="hidden" name="module" value="search" id="Search-module"></dd>                            <dd class="hidden">
148<input type="hidden" name="controller" value="index" id="Search-controller"></dd>                            <dd class="hidden">
149<input type="hidden" name="action" value="index" id="Search-action"></dd>                        </dl>
150                    </div>
151                </form>
152
153                
153<script type="text/javascript">
154                $(document).ready(function() {
155                    $('.parent_form_submit').on('click', function() {
156                        $(this).closest('form').submit();
157                    });
158                });
159                </script>
159
160            </div>
161                    </nav>
162                    <div class="header">
163            
164<div id="tileinstanceid_294656889815182056" class="hci-v2 main-content tileinstance tileinstance_tileset">
165    <section>
166    
167
168
169<div id="tileinstanceid_294656889300515139" class="hci-v2 main-content tileinstance tileinstance_masthead">
170    <section>
171    <div role="banner">
172    <a href="/" class="homePageLink" aria-label="All in For Health">
173        <div class="masthead masthead-layout-left" style="background-color: transparent">
174            <img src='/content/sites/jackson/Banner/Banner_5.png' id='bannerImage' class='imageNo' alt='All in for Health, serving Jackson and Josephine Counties'>                
175                
176                                <h1 class="site_name logo x-large color-primary displaySiteNameOnMobile">
177                       All in For Health                    </h1>
178                
179                    </div>
180    </a>
181</div>
182    </section>
183</div>
184
185<div id="tileinstanceid_294656889300810589" class="hci-v2 main-content tileinstance tileinstance_navigation">
186    <section>
187    
188
189<nav class="sticky-nav-bar navbar navbar-expand-sm justify-content-between tileinstance_navigation_primary " role="navigation" aria-labelledby="mainmenulabel"  id="mainNavbar-294656889300810589">
190	<h2 id="mainmenulabel" class="visually-hidden">Main Site Menu</h2>
191    <div class="container-fluid">
192        <div class="navbar-header d-none">
193            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#tileNavbar_294656889300810589">
194                <span class="visually-hidden">Toggle navigation</span>
195                <span class="navbar-toggler-icon"></span>
196            </button>
197        </div>
198        <div class="navbar-toggler-container">
199            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#tileNavbar_294656889300810589" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
200                <span class="navbar-toggler-icon ml-auto"></span>
201                </button>
202        </div>
203        
204        <div class="collapse navbar-collapse" id="tileNavbar_294656889300810589" style="max-width: 1100px">
205            <ul class="navbar-nav nav-fill no-bullet primary">
206    
207                            <!-- level 1 nav item -->
208                <li class="nav-item dropdown">
209                                        
210                    <a href="#" class="nav-link dropdown-toggle d-none d-sm-block" data-bs-toggle="dropdown" aria-expanded="false" aria-haspopup="true" role="button" id="navbarDropdown-294656889300810589">EXPLORE <span class="position-relative">DATA<i class="fa fa-caret-down"></i></span></a>
211                    <a class="flex flex-row space-center d-block d-sm-none nav-link dropdown-toggle" data-bs-toggle="dropdown" href="" onclick="return false;">EXPLORE <span class="position-relative">DATA<i class="fa fa-caret-down"></i></span></a>
212
213                    <!-- level 2 dropdown -->
214                    <ul class="dropdown-menu no-bullet" aria-labelledby="navbarDropdown-294656889300810589">
215                                                    <li class="d-block d-sm-none"><a href="#" class="dropdown-item">EXPLORE DATA</a></li>
216                                                    
217                                                    <li><a href="/CommunityDashboard" class="dropdown-item">Community Dashboard</a></li>
218                                                        <li><a href="/DisparitiesDashboard" class="dropdown-item">Disparities Dashboard </a></li>
219                                                        <li><a href="/Demographics" class="dropdown-item">Demographics</a></li>
220                                        <li class="nav-item dropdown">
221                <a href="javaScript:void(0)" class="dropdown-item dropdown-toggle flyout " data-bs-toggle="dropdown" aria-expanded="false"><span>Partner Submitted Data</span><i class="fa fa-caret-right d-none d-sm-inline"></i><i class="fa fa-caret-down d-inline d-sm-none"></i></a>
222                <ul class="dropdown-menu dropdown-submenu no-bullet flyout ">
223                                            <li><a href="/resourcelibrary/index/collection?id=313755396756263310" class="dropdown-item">CHAs/CHNAs</a></li>
224                                            <li><a href="/resourcelibrary/index/collection?id=313755470475019521" class="dropdown-item">Community Health Reports</a></li>
225                                            <li><a href="/resourcelibrary/index/collection?id=313755210855196973" class="dropdown-item">Community Health Data</a></li>
226                                            <li><a href="/resourcelibrary/index/collection?id=314451842206452549" class="dropdown-item">Annual Reports</a></li>
227                                    </ul>
228            </li>
229                            </ul>
230                </li>
231                                            <!-- level 1 nav item -->
232                <li class="nav-item dropdown">
233                                        
234                    <a href="#" class="nav-link dropdown-toggle d-none d-sm-block" data-bs-toggle="dropdown" aria-expanded="false" aria-haspopup="true" role="button" id="navbarDropdown-294656889300810589">SEE HOW WE <span class="position-relative">COMPARE<i class="fa fa-caret-down"></i></span></a>
235                    <a class="flex flex-row space-center d-block d-sm-none nav-link dropdown-toggle" data-bs-toggle="dropdown" href="" onclick="return false;">SEE HOW WE <span class="position-relative">COMPARE<i class="fa fa-caret-down"></i></span></a>
236
237                    <!-- level 2 dropdown -->
238                    <ul class="dropdown-menu no-bullet" aria-labelledby="navbarDropdown-294656889300810589">
239                                                    <li class="d-block d-sm-none"><a href="#" class="dropdown-item">SEE HOW WE COMPARE</a></li>
240                                                    
241                                                    <li><a href="/2030Tracker" class="dropdown-item">Healthy People 2030 Tracker</a></li>
242                                        <li class="nav-item dropdown">
243                <a href="javaScript:void(0)" class="dropdown-item dropdown-toggle flyout " data-bs-toggle="dropdown" aria-expanded="false"><span>SocioNeeds Index Suite</span><i class="fa fa-caret-right d-none d-sm-inline"></i><i class="fa fa-caret-down d-inline d-sm-none"></i></a>
244                <ul class="dropdown-menu dropdown-submenu no-bullet flyout ">
245                                            <li><a href="/indexsuite" class="dropdown-item">Suite Overview</a></li>
246                                            <li><a href="/communityhealthindex" class="dropdown-item">Community Health Index</a></li>
247                                            <li><a href="/mentalhealthindex" class="dropdown-item">Mental Health Index</a></li>
248                                            <li><a href="/foodinsecurityindex" class="dropdown-item">Food Insecurity Index</a></li>
249                                    </ul>
250            </li>
251                            </ul>
252                </li>
253                                            <!-- level 1 nav item -->
254                <li class="nav-item dropdown">
255                                        
256                    <a href="/tiles/index/display?alias=ReportsOverview" class="nav-link dropdown-toggle d-none d-sm-block" data-bs-toggle="dropdown" aria-expanded="false" aria-haspopup="true" role="button" id="navbarDropdown-294656889300810589">CHIP PRIORITY <span class="position-relative">AREAS<i class="fa fa-caret-down"></i></span></a>
257                    <a class="flex flex-row space-center d-block d-sm-none nav-link dropdown-toggle" data-bs-toggle="dropdown" href="" onclick="return false;">CHIP PRIORITY <span class="position-relative">AREAS<i class="fa fa-caret-down"></i></span></a>
258
259                    <!-- level 2 dropdown -->
260                    <ul class="dropdown-menu no-bullet" aria-labelledby="navbarDropdown-294656889300810589">
261                                                    <li class="d-block d-sm-none"><a href="/tiles/index/display?alias=ReportsOverview" class="dropdown-item">CHIP PRIORITY AREAS</a></li>
262                                                    
263                                                    <li><a href="https://app.smartsheet.com/b/publish?EQBCT=9afa7619c8f649e1a0d38f1316951269" class="dropdown-item" target="_blank">CHIP Tracking Dashboard</a></li>
264                                                        <li><a href="/Tiles/MAPP2_Guiding_Principles" class="dropdown-item">MAPP 2.0 Guiding Principles</a></li>
265                                                        <li><a href="/tiles/index/display?id=346140493500233292" class="dropdown-item">Behavioral Health</a></li>
266                                                        <li><a href="/tiles/index/display?id=346176944668417828" class="dropdown-item">Access to Healthcare</a></li>
267                                                        <li><a href="/tiles/index/display?id=346759838600528231" class="dropdown-item">Housing</a></li>
268                                                        <li><a href="/tiles/index/display?id=346688920027830157" class="dropdown-item">Community Building</a></li>
269                                                        <li><a href="#" class="dropdown-item">Action Plan</a></li>
270                                                </ul>
271                </li>
272                                            <!-- level 1 nav item -->
273                <li class="nav-item dropdown">
274                                        
275                    <a href="#" class="nav-link dropdown-toggle d-none d-sm-block" data-bs-toggle="dropdown" aria-expanded="false" aria-haspopup="true" role="button" id="navbarDropdown-294656889300810589">TOOLS & <span class="position-relative">RESOURCES<i class="fa fa-caret-down"></i></span></a>
276                    <a class="flex flex-row space-center d-block d-sm-none nav-link dropdown-toggle" data-bs-toggle="dropdown" href="" onclick="return false;">TOOLS & <span class="position-relative">RESOURCES<i class="fa fa-caret-down"></i></span></a>
277
278                    <!-- level 2 dropdown -->
279                    <ul class="dropdown-menu no-bullet" aria-labelledby="navbarDropdown-294656889300810589">
280                                                    <li class="d-block d-sm-none"><a href="#" class="dropdown-item">TOOLS &amp; RESOURCES</a></li>
281                                                    
282                                                    <li><a href="/PromisingPractices" class="dropdown-item">Promising Practices</a></li>
283                                                        <li><a href="/resourcelibrary" class="dropdown-item">Resource Library</a></li>
284                                                        <li><a href="/FundingOpportunities" class="dropdown-item">Funding Opportunities</a></li>
285                                                        <li><a href="/Guide" class="dropdown-item">CHNA Guide</a></li>
286                                                        <li><a href="/ReportAssistant" class="dropdown-item">Report Builder</a></li>
287                                                </ul>
288                </li>
289                                            <!-- level 1 nav item -->
290                <li class="nav-item dropdown">
291                                        
292                    <a href="#" class="nav-link dropdown-toggle d-none d-sm-block" data-bs-toggle="dropdown" aria-expanded="false" aria-haspopup="true" role="button" id="navbarDropdown-294656889300810589">LEARN <span class="position-relative">MORE<i class="fa fa-caret-down"></i></span></a>
293                    <a class="flex flex-row space-center d-block d-sm-none nav-link dropdown-toggle" data-bs-toggle="dropdown" href="" onclick="return false;">LEARN <span class="position-relative">MORE<i class="fa fa-caret-down"></i></span></a>
294
295                    <!-- level 2 dropdown -->
296                    <ul class="dropdown-menu no-bullet" aria-labelledby="navbarDropdown-294656889300810589">
297                                                    <li class="d-block d-sm-none"><a href="#" class="dropdown-item">LEARN MORE</a></li>
298                                                    
299                                                    <li><a href="/tiles/index/display?id=250341474484071228" class="dropdown-item">About Us</a></li>
300                                                        <li><a href="/tiles/index/display?alias=oursupporters" class="dropdown-item">Our Supporters</a></li>
301                                                        <li><a href="/tiles/index/display?id=304435423234079317&amp;status=2&amp;alert=1" class="dropdown-item">Get Involved</a></li>
302                                                        <li><a href="/tiles/index/display?id=313420568533790381&amp;status=2&amp;alert=1" class="dropdown-item">Reports and Documents</a></li>
303                                                </ul>
304                </li>
305                                        </ul>
306        </div>
307    </div>
308</nav>
309
310<script type="text/javascript">
311$(document).ready(function() {
312    var contentWidth = $('#hci_container').width();
313    var currWidth = $(window).width();
314    var tileId = '294656889300810589';
315    var hoverIntentLoaded = false;
316
317    // if we're previewing a sticky nav bar, remove the sticky class otherwise the preview 
318    // becomes sticky which makes it move to the top of the page
319    $('.module_tiles_admin_view').find('.sticky-nav-bar.navbar').removeClass('sticky-nav-bar');
320    
321    function loadHoverIntent()
322    {
323        if (!hoverIntentLoaded) {
324            hoverIntentLoaded = true;
325            $('.nav-item').hoverIntent({
326                over: function() {
327                    if ($(this).children('.dropdown-menu').length > 0) {
328                        $(this).removeClass('show').children('.dropdown-menu').removeClass('show');
329                        $(this).addClass('show').children('.dropdown-menu').addClass('show');
330                    }
331                },
332                out: function() {
333                    if ($(this).children('.dropdown-menu').length > 0) {
334                        $(this).removeClass('show').children('.dropdown-menu').removeClass('show');
335                    }
336                },
337                timeout: 500,
338            });
339        }
340    }
341
342    loadHoverIntent();
343
344    $('ul.navbar-nav > li.dropdown > a').on('click', function(event) {
345        if ($(this).attr('target') != '_blank') {
346            var href = $(this).attr('href');
347            if (href && !href.match(/^https?:\/\//)) {
348                // if ctrl/cmd-click or target blank, open in new window 
349                if (event.metaKey || event.ctrlKey || ($(this).attr('target') == '_blank')) {
350                    window.open($(this).attr('href'), '_blank');
351                }
352                else {
353                    location.href = href;
354                }
355            }
356        }
357    });
358
359    $(window).on('resize',  function() {
360        if( currWidth != $(window).width()) {
361            currWidth = $(window).width();
362            if (window.matchMedia("only screen and (max-width: 600px)").matches) {
363                contentWidth = $('#hci_container').width();
364            }
365            else {
366                $('.tileinstance_navigation .navbar-header').css('background-color', 'transparent');
367            }
368        }
369    });
370
371            var navOffset =  $('nav.sticky-nav-bar').offset().top;
372        $('body').addClass('sticky-navbar');
373
374        $(window).scroll(function (event) {
375            var height = $(window).scrollTop();
376            
377            if (height > navOffset) {
378                if ($('nav.sticky-nav-bar').css('position') == 'relative') {
379                    $('nav.sticky-nav-bar, #content_container').addClass('nav-is-fixed');
380                    $('nav.sticky-nav-bar').css('z-index', 99999);
381                }
382            }
383            else if ($('nav.sticky-nav-bar').css('position') == 'fixed') {
384                $('nav.sticky-nav-bar, #content_container').removeClass('nav-is-fixed');
385                $('nav.sticky-nav-bar').css('z-index', 'auto');
386            }
387        });
388
389    function positionLeftFlyout() {
390        $('#mainNavbar-294656889300810589 .flyout.flyoutLeft').each(function () {
391            var config = {attributes: true, childList: false, characterData: false};
392            var target = this;
393        
394            var observer = new MutationObserver(function(mutations) {                
395                for (let mutation of mutations) {
396                    if ($(mutation.target).hasClass('show')) {
397                        var newLeft = '-' + (Math.round($(mutation.target).parent().width()) + 3) + 'px';
398                        $(mutation.target).css('left', newLeft);
399                    }
400                }
401            });
402            observer.observe(target, config);
403        });
404    }
405       
406    positionLeftFlyout();
407    
408});
409</script>
409
410    </section>
411</div>
412    </section>
413</div>
414            </div>
415
416        <div id="content_container">
417            <div id="content" class="" style="max-width: 1100px">
418                        
419<div class="frontend_container">
420    <div class="frontend_content module_tiles module_tiles_index module_tiles_index_display controller_index" role="main">
421                
422
423<div id="tileinstanceid_297762854405983347" class="hci-v2 main-content tileinstance tileinstance_tileset">
424    <section>
425    
426
427
428<div id="tileinstanceid_297762854406907253" class="hci-v2 main-content tileinstance tileinstance_generalhtml homepage-hero mb-0 mt-0">
429    <section>
430    <div class="ulink"><div class="hero__wrapper">
431<div class="row">
432<div class="hero__intro col-md-8">
433<div class="hero__intro--inner">
434<h1 class="hero__title pt-0"><span class="small">All In for Health</span></h1>
435<p class="serifhomepage">All in for Health provides a one-stop resource for online access to community health indicators and related resources that impact the health of Jackson and Josephine Counties. You will find up-to-date demographic, health and social determinants data; hundreds of maps, tables and figures; and, promising practices.</p>
436<div class="search-area__wrapper">
437<div class="renown-site-search hci-v2 main-content tileinstance tileinstance_search bkgd-none">
438<div class="row mb-0">
439<div class="col-md-4 mb-0">
440<p class="search-area__label">Find data</p>
441</div>
442<div class="col-md-8 mb-0"><form method="get" action="/indicators" id="indicatorSearchForm_171307354231461419"><input type="text" name="keywords" id="indicatorSearchKeywords_171307354231461419" class="largeInputField searchbarsize" /></form></div>
443</div>
444</div>
445</div>
446</div>
447</div>
448<div class="hero__links col-md-3">
449<div class="whats-new">
450<div class="onboarding-item">
451<div class="onboarding-item__icon"><i class="hcicon hci-target-community hci-reversed hci-disc bg-color-primary"></i></div>
452<h3 class="onboarding-item__label" id="h_919202671141574964127430"><a href="/tiles/index/display?id=250341474484071228">All in for Health Partnership</a></h3>
453</div>
454<div class="onboarding-item">
455<div class="onboarding-item__icon"><i class="hcicon hci-chip hci-reversed hci-disc bg-color-primary"></i></div>
456<h3 class="onboarding-item__label"><a href="https://app.smartsheet.com/b/publish?EQBCT=9afa7619c8f649e1a0d38f1316951269" target="_blank" rel="noreferrer noopener">CHIP Tracking Dashboard</a></h3>
457</div>
458<div class="onboarding-item">
459<div class="onboarding-item__icon"><i class="hcicon hci-report-chna hci-reversed hci-disc bg-color-primary"></i></div>
460<h3 class="onboarding-item__label"><a href="/index.php?module=indicators&amp;controller=index&amp;action=indicatorsearch"></a><a href="/tiles/index/display?id=313420568533790381&amp;status=2&amp;alert=1" style="font-size:1.125rem;display:inline;">CHA/CHIP Reports Page</a></h3>
461</div>
462<div class="onboarding-item">
463<div class="onboarding-item__icon"><i class="hcicon hci-disparities-dash hci-reversed bg-color-primary hci-disc"></i></div>
464<h3 class="onboarding-item__label"><a href="/index.php?module=indicators&amp;controller=index&amp;action=indicatorsearch" style="font-size:1.125rem;display:inline;">Search for Data</a></h3>
465</div>
466<div class="onboarding-item">
467<div class="onboarding-item__icon"><i class="hcicon hci-report-assistant hci-reversed bg-color-primary hci-disc"></i></div>
468<h3 class="onboarding-item__label"><a href="/reports/location"><span style="color:#f1f5f9;font-family:'Open Sans', Arbutus, Verdana, sans-serif;font-size:18px;">Create a Custom Report</span></a></h3>
469</div>
470<div class="onboarding-item">
471<div class="onboarding-item__icon"><i class="hcicon hci-help hci-reversed bg-color-primary hci-disc"></i></div>
472<h3 class="onboarding-item__label"><a href="https://help.healthycities.org/hc/en-us/categories/202658167-FAQs"><span style="color:#f1f5f9;font-family:'Open Sans', Arbutus, Verdana, sans-serif;font-size:18px;">FAQ</span></a></h3>
473</div>
474</div>
475</div>
476</div>
477</div></div>
478    </section>
479</div>
480
481<div id="tileinstanceid_301993011390254111" class="hci-v2 main-content tileinstance tileinstance_indicatormap bkgd-light white_indicator_explain hide-first-comparison-gauge">
482    <section>
483    <style>
484.timelineDiv {
485  background-color: #f0f8ff;
486  padding: 15px 10px;
487  border-radius: 5px;
488
489}
490.slider-container {
491  position: relative;
492  width: 90%;
493  max-width: 1100px;
494  margin: auto;
495  display: flex;
496  align-items: center;
497  gap: 5px;
498  padding: 0;
499}
500
501.slider-title {
502  font-weight: bold;
503  white-space: nowrap;
504  color: #333;
505  font-size: 12px;
506 /* Align with slider track */
507  align-self: flex-start;
508  margin-top: 10px;  
509}
510
511.slider-wrapper {
512  flex-grow: 1;
513  position: relative;
514}
515
516/* Custom slider styling */
517.slider {
518  -webkit-appearance: none;
519  width: 100%;
520  height: 3px; 
521  margin: 16px 0 24px 0; /* Adjusted margin to create space below */
522  background: #ddd;
523  border-radius: 2px;
524  outline: none;
525  position:relative;
526  top:0; 
527}
528
529/* Slider thumb - Chrome/Edge/Safari */
530.slider::-webkit-slider-thumb {
531  -webkit-appearance: none;
532  width: 10px;
533  height: 10px;
534  border-radius: 50%;
535  background: #4CAF50;
536  cursor: pointer;
537  margin-top: -14px; 
538}
539
540.slider::-moz-range-thumb {
541  width: 10px;
542  height: 10px;
543  border-radius: 50%;
544  background: #4CAF50;
545  cursor: pointer;
546}
547
548.slider-marks {
549  position: relative;
550  width: 100%;
551  height: 12px;
552  margin-top: 8px; 
553}
554
555/* Default label style (horizontal) */
556.mark {
557  position: absolute;
558  transform: translateX(-50%);
559  text-align: center;
560  white-space: nowrap;
561  font-size: 10px;
562  color: #333; 
563  top: 2px; 
564  line-height: 1.0;
565}
566
567/* Marker dot */
568.mark::before {
569display:none;
570}
571
572/* Rotated label style (when many labels) */
573.many-labels .mark {
574  transform: translateX(-50%) rotate(-45deg);
575  transform-origin: left center;
576  text-align: left;
577  top: 16px; 
578  overflow: visible;
579  color: #333;
580  padding-left: 1px;
581  padding-right: 1px;  
582  font-size: 9px;
583  line-height: 0.8;
584}
585
586.play-button {
587  background: #4CAF50;
588  color: white;
589  border: none;
590  padding: 5px 8px;
591  border-radius: 3px;
592  cursor: pointer;
593  margin-right: 8px;
594  display: flex;
595  align-items: center;
596  gap: 3px;
597  font-size: 11px;
598 /* Align with slider track */
599  align-self: flex-start;
600  margin-top: 10px;  
601}
602
603.play-button:hover {
604  background: #45a049;
605}
606
607.play-button i {
608  font-size: 12px;
609}
610
611.timelineMsg {
612    color: #000;
613	font-size: 85% !important;
614}
615
616#loadingIcon {
617    position: absolute;
618    z-index: 9999;
619    pointer-events: none;
620}
621
622</style>
623<script type="text/javascript">
624function empty(mixedVar) {
625  // Undefined or null
626  if (mixedVar === undefined || mixedVar === null) {
627    return true;
628  }
629  
630  // Number or boolean
631  if (typeof mixedVar === 'number' || typeof mixedVar === 'boolean') {
632    return false; // Different from PHP where 0 and false are considered empty
633  }
634  
635  // String
636  if (typeof mixedVar === 'string') {
637    return mixedVar === '';
638  }
639  
640  // Array or array-like object
641  if (Array.isArray(mixedVar) || (typeof mixedVar === 'object' && mixedVar !== null && 'length' in mixedVar)) {
642    return mixedVar.length === 0;
643  }
644  
645  // Object
646  if (typeof mixedVar === 'object') {
647    return Object.keys(mixedVar).length === 0;
648  }
649  
650  return false;
651}
652
653function escapeHtml(unsafe) {
654    return unsafe?.toString()
655        .replace(/&/g, "&amp;")
656        .replace(/</g, "&lt;")
657        .replace(/>/g, "&gt;")
658        .replace(/"/g, "&quot;")
659        .replace(/'/g, "&#039;");
660}
661
662
663function getKeyIndex(mapKeys, targetKey) {
664    let index = 0;
665    for (const key of mapkeys) {
666        if (key === targetKey) return index;
667        index++;
668    }
669    return -1; // Not found
670}
671
672function getKeyByIndex(mapKeys, index) {
673    let i = 0;
674    for (const key of mapKeys) {
675        if (i === index) return key;
676        i++;
677    }
678    return undefined; // If index is out of bounds
679}
680
681function toOrderedMap(obj) {
682  const map = new Map();
683
684  // Put "default" first if it exists
685  if (obj.default) {
686    map.set("default", obj.default);
687  }
688
689  // Add all other keys in original insertion order
690  for (const key of Object.keys(obj)) {
691    if (key !== "default") {
692      map.set(key, obj[key]);
693    }
694  }
695
696  return map;
697}
698
699function updateTimeSlider(localeInfo, tile) {
700
701    const priorValues = localeInfo.priorValues;
702	newPeriods = new Map(
703		Object.values(priorValues).map(entry => [entry.periodId, entry.period])
704	);
705	tile.timeline.periods=newPeriods;
706	tile.timeline.periodKeys = newPeriods.keys();
707	tile.timeline.totalLabels = tile.timeline.periods.size;
708
709    const max = tile.timeline.totalLabels - 1;
710    const percentStep = (max>0? (100 / max):0);
711	const mapId = tile.mapId;
712    const timelineDiv = document.getElementById(`timelineDiv_${mapId}`);
713	const datalist = timelineDiv.querySelector('#markers');
714    const sliderMarksContainer = timelineDiv.querySelector(".slider-marks");
715	const timeSlider = timelineDiv.querySelector('#timeSlider');
716	
717	// Update range input attributes
718    timeSlider.min = 0;
719    timeSlider.max = max;
720    timeSlider.step = 1;
721	timeSlider.value = 0;
722
723    // Clear existing HTML
724    datalist.innerHTML = '';
725    sliderMarksContainer.innerHTML = '';
726	
727	tile.timeline.periodKeys =[];
728	let i = 0;
729	tile.timeline.periods.forEach((periodLabel, periodId) => {
730		const percent = i * percentStep;
731
732		// Create <option> for datalist
733		const option = document.createElement("option");
734		option.value = i;
735		option.textContent = periodLabel;
736		datalist.appendChild(option);
737
738		// Create <div> mark for slider
739		const mark = document.createElement("div");
740		mark.className = "mark";
741		mark.style.left = percent + "%";
742		mark.setAttribute("data-tooltip", periodLabel);
743		mark.setAttribute("data-key", periodId);
744		mark.textContent = periodLabel;
745		sliderMarksContainer.appendChild(mark);
746		tile.timeline.periodKeys.push(periodId);
747		if (periodId == localeInfo.periodId) {
748			timeSlider.value = i;
749		}
750		i++;
751	});
752
753	console.log("updateTimeSlider tile.timeline.periodKeys =", tile?.timeline?.periodKeys);	
754
755	if ((tile?.timeline?.totalLabels ?? 0) > 10 ) {
756		sliderMarksContainer.classList.add('many-labels');
757	} else {
758		sliderMarksContainer.classList.remove('many-labels');
759	}	
760}
761
762function updateTimelineVar(data, tile){
763	
764	const localeId = tile.timeline.localeId;
765	const localeTypeId = data.localeTypeId;
766	const localeInfo = data.localeTypes[localeTypeId]?.localeDetails?.[localeId]??null;
767
768	tile.timeline.periodId = data.periodId;
769	tile.timeline.currentLocaleTypeId=localeTypeId;
770	tile.timeline.localeTypes=data.localeTypes;
771	tile.timeline.localeInfo=localeInfo;
772	tile.timeline.currentLocaleName = tile.timeline.localeTypes[localeTypeId]?.indicatorValues?.[localeId]?.displayName ?? null;
773	tile.timeline.indicatorId=localeInfo.indicatorId;
774	
775	const tileComparisonId=tile? tile.currentComparison:null;
776    let selectedComparisonId=tileComparisonId?tileComparisonId:'default';
777	const comparisonData = localeInfo.comparisonDisplayData;	
778	for (const comparisonId in comparisonData) {
779		if (comparisonData.hasOwnProperty(comparisonId) && comparisonId == selectedComparisonId) {
780			tile.timeline.currentComparisonId = comparisonId;
781			break;
782		}
783	}
784	if(tile.timeline.currentComparisonId==null) {
785		tile.timeline.currentComparisonId = Object.keys(comparisonDisplayData)[0];
786	}
787	activeTile=tile;
788	
789}
790
791function prepareTimeline(tile) {
792	
793	console.log('prepareTimeline tileId='+ tile.id + " periodId="+tile.timeline.periodId + " localeId="+tile.timeline.localeId + " indicatorId="+tile.timeline.indicatorId);
794	
795	if(tile.timeline.allPeriodsData!=null ){
796	
797		if( tile.timeline.periodId==null){
798			const periodKeys = Object.keys(tile.timeline.allPeriodsData);
799			const lastPeriodId = periodKeys[periodKeys.length - 1];
800			//console.log('lastPeriodId='+lastPeriodId); 
801			const latestData = tile.timeline.allPeriodsData[lastPeriodId];
802			const latestLocaleInfo= latestData.localeTypes[tile.timeline.currentLocaleTypeId]?.localeDetails[tile.timeline.localeId]??null;
803			if(latestLocaleInfo!=null) {
804				tile.timeline.periodId=latestLocaleInfo.periodId;
805			}else {
806				tile.timeline.periodId=tile.timeline.initialPeriodId;
807			}
808			console.log('prepareTimeline assigned timeline.periodId='+tile.timeline.periodId);			
809		}
810		
811		if( tile.timeline.periodId!=null){
812			let data = tile.timeline.allPeriodsData[tile.timeline.periodId];
813			if(data!=null) {
814				const localeId = tile.timeline.localeId;
815				const localeTypeId = data.localeTypeId;
816				const localeInfo = data.localeTypes[localeTypeId].localeDetails[localeId];
817				updateTimelineVar(data, tile);
818				updateTimeSlider(localeInfo, tile);
819			}
820		}
821	}
822		
823}
824
825function hideTimelineDiv(tile) {
826	const mapId = tile.mapId;
827    const timelineDiv = document.getElementById(`timelineDiv_${mapId}`);	
828	if (!timelineDiv) return;
829	timelineDiv.style.display = "none";	
830}
831
832
833function showTimeSlider(tile) {
834
835	const mapId = tile.mapId;
836    const timelineDiv = document.getElementById(`timelineDiv_${mapId}`);
837	if (!timelineDiv) return;
838	
839	if ( tile.showTimeline ) {
840		timelineDiv.style.display = "";	
841		const timeSlider = timelineDiv.querySelector(`.time-slider-container`);
842		const timelineMsg    = timelineDiv.querySelector(`.timeline-click-msg`);
843
844		if( tile.timeline.periods != null && tile.timeline.totalLabels >0 &&  tile.timeline.allPeriodsData) {
845			timeSlider.style.display = "";	
846			timelineMsg.style.display = "none";
847		} else {
848			timeSlider.style.display = "none";	
849			timelineMsg.style.display = "";
850		}
851	} else {
852		timelineDiv.style.display = "none";	
853	}		
854
855	
856}
857
858function hideTimeSlider(tile) {
859	const mapId = tile.mapId;
860    const timelineDiv = document.getElementById(`timelineDiv_${mapId}`);	
861	if (!timelineDiv) return;
862
863    const timelineSlider = timelineDiv.querySelector(`#time-slider-container`);
864    const timelineMsg    = timelineDiv.querySelector(`#timeline-click-msg`);
865
866    if (timelineSlider && timelineMsg) {
867        timelineSlider.style.display = "none";	
868        timelineMsg.style.display = "";
869    }		
870}
871
872function getDataForAllPeriods(tile) {
873	return new Promise((resolve, reject) => {
874		try {
875			hideTimeSlider(tile);
876			tile.timeline.allPeriodsData=null;
877			const localeTypeId=tile.timeline.currentLocaleTypeId;
878			const localeId=tile.timeline.localeId;
879			const indicatorId=tile.timeline.indicatorId;
880			
881			const url = ClientSite.Extensions.Url().quickUrl('indicators', 'indexajax', 'dispatch', {callAction: 'getDataForAllPeriods'});
882			//console.log("getDataForAllPeriods localeTypeId:"+localeTypeId + " localeId="+localeId + " indicatorId="+indicatorId );
883			$.ajax({
884				dataType: "json",
885				url: url,
886				data: {
887					'localeId': localeId,
888					'localeTypeId': localeTypeId,
889					'indicatorId': indicatorId,
890					'json': 1
891				},
892				method: 'post',
893				success: function(response) {
894					//console.log('getDataForAllPeriods ajax success response',response);
895					if(response!=null && response.status && response.allPeriodsData!=null ) {
896						tile.timeline.allPeriodsData=response.allPeriodsData;
897						tile.timeline.hcCfg=response.hcCfg;
898						prepareTimeline(tile);
899						showTimeSlider(tile);
900						resolve(response);
901					} else {
902						reject('Invalid response from getDataForAllPeriods');
903					}
904				},
905				error: function (xhr) {
906					console.error('Error in getDataForAllPeriods:', xhr.responseText);
907					reject(xhr);
908				}
909			});		
910		} catch (e) {
911			console.error('Error in getDataForAllPeriods:', e);
912			reject(e);
913		}
914	});	
915}
916
917//triger when locale/indicator change
918function updateTimelineOnChange(tile, tileId) {
919	if (tile.showTimeline) {
920		tile.timeline.currentLocaleTypeId=tile.localeTypeId;
921		tile.timeline.localeId=tile.localeId;
922		tile.timeline.indicatorId=tile.indicatorId;
923		tile.timeline.tileId=tileId;
924		tile.timeline.periodId=null;
925		console.log('updateTimelineOnChange currentLocaleTypeId='+tile.timeline.currentLocaleTypeId+' localeId='+tile.timeline.localeId + " indicatorId="+tile.timeline.indicatorId);
926		getDataForAllPeriods(tile);
927	}
928}
929
930
931function updateGaugeContainer(data, tile) {
932	
933	const localeId = tile.timeline.localeId;
934	const localeTypeId = data.localeTypeId;
935	const localeType = data.localeTypes[localeTypeId];
936	const localeInfo = localeType.localeDetails[localeId];
937	const indicatorValue= localeType.indicatorValues[localeId];
938	const unstable = indicatorValue.unstable;
939	const renderers = localeType.renderers;
940	
941	for (const [benchmarkId, c] of Object.entries(renderers)) {
942		if (!c.localeIdList || !(localeId in c.localeIdList)) {
943			delete renderers[benchmarkId];
944			continue;
945		}
946	}
947	const renderersMap = toOrderedMap(renderers);
948	//console.log('updateGaugeContainer renderersMap=',renderersMap);
949
950	let divHtml='<div class="gauge_value_container"><div class="value_unit">';
951	let span = empty(unstable)? '<span class="value">': '<span class="value htmlTooltip" title="*Value may be statistically unstable and should be interpreted with caution">';
952	divHtml += span + indicatorValue.valueFmt +'</span></div>';
953	
954	//comparisons	
955	divHtml += '<div class="gauge ml-1">';
956
957	let currentComparison;
958	if (tile.timeline.currentComparisonId && Object.keys(renderers).includes(tile.timeline.currentComparisonId)) {
959		currentComparison = tile.timeline.currentComparisonId;
960	} else if (tile.timeline.defaultComparison && Object.keys(renderers).includes(tile.timeline.defaultComparison)) {
961		currentComparison = tile.timeline.defaultComparison;
962	} else {
963		const firstValue = renderersMap.values().next().value;
964		const c = firstValue || {localeIdList: []};
965		const idx = c.localeIdList.length > 1 ? 1 : 0;
966		currentComparison = Array.from(renderersMap.keys())[idx] || '';
967	}
968	
969	for (const [benchmarkId, c] of renderersMap) {
970		
971		let active = (benchmarkId === currentComparison) ? 'active' : '';
972		let comparisonDisplayData = localeInfo?.comparisonDisplayData?.[benchmarkId]?.comparisonDisplayData || {};
973        let imgFile=comparisonDisplayData.gauge;
974		let cName = escapeHtml(comparisonDisplayData.shortComparisonBenchmark);
975		let title=(comparisonDisplayData.technicalNote!=""? escapeHtml(comparisonDisplayData.technicalNote) : escapeHtml(comparisonDisplayData.shortComparisonBenchmark) );
976		if (benchmarkId === 'default') {
977			if (c.comparisonRendererParams && 
978				Object.keys(c.comparisonRendererParams).length > 0 && 
979				'value' in Object.values(c.comparisonRendererParams)[0]) { // ranked
980				
981				for (const [idx, breakItem] of Object.entries(c.comparisonRendererParams)) {
982					if (indicatorValue.value === breakItem.value) {
983						c.gauge = 'jenks-' + (parseInt(idx) + 1);
984						break;
985					}
986				}
987			} else {
988				for (const [idx, breakItem] of Object.entries(c.comparisonRendererParams)) {
989					const iv = indicatorValue.value;
990					if (iv >= breakItem.minValue && 
991						iv <= breakItem.maxValue) {
992						c.gauge = 'jenks-' + (parseInt(idx) + 1);
993						break;
994					}
995				}
996			}
997			imgFile=c.gauge;
998			cName=c.benchmark;
999			title=(c.technicalNote!=""? escapeHtml(c.technicalNote) : escapeHtml(c.shortComparisonBenchmark) );
1000		}//if (benchmarkId === 'default')
1001		
1002		divHtml += '<p class="comparison-'+benchmarkId+' left text-center comparison htmlTooltip '+active+'" title="' +title;
1003		divHtml += '"><a href="#" data-index="'+benchmarkId+'"><img src="/content/global/application/indicators/gauges/' +imgFile+'.png" alt="'+cName+'" /><br />';
1004        divHtml += cName+'</a></p>';
1005	    
1006	}//for
1007	
1008	divHtml +='</div></div>';
1009	
1010	const whatIndicator=localeInfo.whatIndicator;
1011	const hideDescription=tile.timeline.hideDescription;
1012	if(hideDescription==false){
1013		divHtml +='<div class="indicator_explain">'+whatIndicator+'</div>';
1014	}
1015	const tileId = tile.id;
1016	const tileDiv = document.getElementById(`${tileId}`);
1017	const viewLink = tileDiv.querySelector('a.ribbon-link.indicatorLink');
1018	if (viewLink) {
1019	  divHtml +='<div class="padding-y-15">'+viewLink.outerHTML + '</div>';
1020	}
1021	divHtml +='</div>';
1022
1023	const container = '#indmap_indcol_' + tileId;
1024	const $el = $(container).find('.indicator_container');
1025	if ($el.length) {
1026		$(container + ' .indicator_container')
1027		.html(divHtml)
1028        .css('opacity', 1);
1029	}
1030}
1031
1032</script>
1032<script>
1033(function (global) {
1034    if (global._map_tiles_instance) {
1035        return; // already loaded once
1036    }
1037
1038    var map_tiles = {
1039        site_url: 'https://jackson.thehcn.net',
1040        site_prefix: 'jackson',
1041        mapLayers: {"1":{"layerUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Layers_2022\/MapServer\/0","id":"state","label":"State","renderer":null,"outFields":["NAME","localeId"]},"2":{"layerUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Layers_2022\/MapServer\/2","id":"county","label":"County","renderer":null,"outFields":["NAME","localeId"]},"4":{"layerUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Layers_2022\/MapServer\/3","id":"census_tract","label":"Census Tract","renderer":null,"outFields":["NAME","localeId"]},"3":{"layerUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Layers_2022\/MapServer\/4","zctaUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Layers_2022\/MapServer\/9","id":"zip_code","label":"Zip Code","renderer":null,"outFields":["NAME","localeId"]},"27":{"layerUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Layers_2022\/MapServer\/6","id":"wards","label":"Wards","renderer":null,"outFields":["NAME","localeId"]},"39":{"layerUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Layers_2022\/MapServer\/5","id":"cities","label":"Cities","renderer":null,"outFields":["NAME","localeId"]},"43":{"layerUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Layers_2022\/MapServer\/8","id":"county_subdivions","label":"County Subdivisions","renderer":null,"outFields":["NAME","localeId"]},"129":{"layerUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Layers_2022\/MapServer\/10","id":"puma","label":"Puma","renderer":null,"outFields":["NAME","localeId"]},"Region":{"layerUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Layers_2022\/MapServer\/1","id":"region","label":"Region","renderer":null,"outFields":["NAME","localeId"]},"Site":{"layerUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Layers_2022\/MapServer\/7","id":"site","label":"Site","renderer":null,"outFields":["NAME"]},"10":{"layerUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Layers_2022\/MapServer\/2","id":"county","label":"County","renderer":null,"outFields":["NAME","localeId"]},"127":{"layerUrl":"https:\/\/hcimaps01.thehcn.net\/arcgis\/rest\/services\/Map\/Map_Custom_Shapefiles\/MapServer\/0","id":"census_county_division","label":"Census County Division","renderer":null,"outFields":["NAME","localeId"]}},
1042        tiles: {},
1043        defaults: {},
1044        currentId: null,
1045		initializedTiles: {},
1046		defaultsSet: false,
1047		
1048        init: function() {
1049		
1050            require(['esri/map',
1051                'esri/basemaps',
1052                'esri/renderer',
1053                'esri/layers/FeatureLayer',
1054                'esri/layers/LabelClass',
1055                'esri/tasks/query',
1056                'esri/tasks/QueryTask',
1057                'esri/renderers/UniqueValueRenderer',
1058                'esri/renderers/ClassBreaksRenderer',
1059                'esri/renderers/SimpleRenderer',
1060                'esri/symbols/Font',
1061                'esri/symbols/SimpleFillSymbol',
1062                'esri/symbols/SimpleLineSymbol',
1063                'esri/symbols/TextSymbol',
1064                'esri/Color',
1065                'dojo/promise/all',
1066                'dojo/domReady!'],
1067                function(
1068                    Map,
1069                    Basemaps, // Basemaps.none is added via HCI_Gis::getMapSymbols() but only when it is defined in this require() block
1070                    Renderer,
1071                    FeatureLayer,
1072                    LabelClass,
1073                    Query,
1074                    QueryTask,
1075                    UniqueValueRenderer,
1076                    ClassBreaksRenderer,
1077                    SimpleRenderer,
1078                    Font,
1079                    SimpleFillSymbol,
1080                    SimpleLineSymbol,
1081                    TextSymbol,
1082                    Color,
1083                    all
1084                ){
1085                // INITIALIZE APPLICATION
1086				
1087				//console.log("init map tiles");
1088
1089
1090                map_tiles.defaults.highlightSymbols = {
1091            "site":
1092                new SimpleFillSymbol(
1093                    SimpleFillSymbol.STYLE_NULL,
1094                        new SimpleLineSymbol(
1095                            SimpleLineSymbol.STYLE_SOLID,
1096                            new dojo.Color("rgba(35, 79, 128, .73)"),
1097                            1.5
1098                        ),
1099                        null
1100                    ),
1101            "localeOutline":
1102                new SimpleFillSymbol(
1103                    SimpleFillSymbol.STYLE_SOLID,
1104                        new SimpleLineSymbol(
1105                            SimpleLineSymbol.STYLE_SOLID,
1106                            new dojo.Color("rgb(0,0,0)"),
1107                            1.0
1108                        ),
1109                        new dojo.Color("rgba(0,0,0,0)")
1110                    ),
1111            "localeOutlineNullFill":
1112                new SimpleFillSymbol(
1113                    SimpleFillSymbol.STYLE_NULL,
1114                        new SimpleLineSymbol(
1115                            SimpleLineSymbol.STYLE_SOLID,
1116                            new dojo.Color("rgb(0,0,0)"),
1117                            1.0
1118                        ),
1119                        null
1120                    ),
1121            "select":
1122                new SimpleFillSymbol(
1123                    SimpleFillSymbol.STYLE_NULL,
1124                        new SimpleLineSymbol(
1125                            SimpleLineSymbol.STYLE_SOLID,
1126                            new dojo.Color("rgba(150, 255, 255, 1)"),
1127                            3
1128                        ),
1129                        null
1130                    ),
1131            "selectAlt":
1132                new SimpleFillSymbol(
1133                    SimpleFillSymbol.STYLE_NULL,
1134                        new SimpleLineSymbol(
1135                            SimpleLineSymbol.STYLE_SOLID,
1136                            new dojo.Color("rgba(255, 204, 0, 1)"),
1137                            3
1138                        ),
1139                        null
1140                    ),
1141            "highlight":
1142                new SimpleFillSymbol(
1143                    SimpleFillSymbol.STYLE_NULL,
1144                        new SimpleLineSymbol(
1145                            SimpleLineSymbol.STYLE_SOLID,
1146                            new dojo.Color("rgba(50, 255, 255, 1)"),
1147                            1.5
1148                        ),
1149                        null
1150                    ),
1151            "container":
1152                new SimpleFillSymbol(
1153                    SimpleFillSymbol.STYLE_NULL,
1154                        new SimpleLineSymbol(
1155                            SimpleLineSymbol.STYLE_SOLID,
1156                            new dojo.Color("rgba(34, 159, 54, 1)"),
1157                            1.5
1158                        ),
1159                        null
1160                    )
1161        }; 
1162        map_tiles.defaults.lineSymbol = new SimpleLineSymbol("solid", new Color([0,50,100]), .33);
1163        map_tiles.defaults.grayLineSymbol = new SimpleLineSymbol("solid", new Color([75,75,75]), .33);
1164        map_tiles.defaults.boldLineSymbol = new SimpleLineSymbol("solid", new Color([0,0,0]), 1.5);
1165        map_tiles.defaults.labelSymbol = new Color([0,50,100]);
1166        map_tiles.defaults.featureLabelTextSymbol = (new TextSymbol("").setColor(new Color([0,0,0])).setFont(new Font("12px").setFamily("Arial")));
1167        map_tiles.defaults.nullColor = "rgba(0,0,0,.3)";
1168        map_tiles.defaults.grayColor = "rgba(0,0,0,.3)";
1169        map_tiles.defaults.primaryColor = "#10715F";
1170        map_tiles.defaults.primaryLightColor = "#d4f7f1";
1171        map_tiles.defaults.actionColor = "#D99B4B";
1172        map_tiles.defaults.primaryLineSymbol = new SimpleLineSymbol("solid", new Color("#10715F"), .95);
1173        map_tiles.defaults.primaryLightLineSymbol = new SimpleLineSymbol("solid", new Color("#d4f7f1"), .95);
1174        map_tiles.defaults.actionLineSymbol = new SimpleLineSymbol("solid", new Color("#D99B4B"), .95);
1175        map_tiles.defaults.nullSymbol = new SimpleFillSymbol(
1176            "solid",
1177            map_tiles.defaults.lineSymbol,
1178            new Color(map_tiles.defaults.nullColor)
1179        );
1180        map_tiles.defaults.grayColorSymbol = new SimpleFillSymbol(
1181            "solid",
1182            map_tiles.defaults.grayLineSymbol,
1183            new Color(map_tiles.defaults.grayColor)
1184        );
1185        map_tiles.defaults.primaryLightColorSymbol = new SimpleFillSymbol(
1186            "solid",
1187            map_tiles.defaults.primaryLineSymbol,
1188            new Color(map_tiles.defaults.primaryLightColor) 
1189        );
1190        map_tiles.defaults.primaryColorSymbol = new SimpleFillSymbol(
1191            "solid",
1192            map_tiles.defaults.primaryLightLineSymbol,
1193            new Color(map_tiles.defaults.primaryColor) 
1194        );
1195        map_tiles.defaults.actionColorSymbol = new SimpleFillSymbol(
1196            "solid",
1197            map_tiles.defaults.nullSymbol,
1198            new Color(map_tiles.defaults.actionColor) 
1199        );
1200        map_tiles.defaults.nullColorSymbol = new SimpleFillSymbol(
1201            "solid",
1202            map_tiles.defaults.nullSymbol,
1203            new Color([0,0,0,0]) 
1204        );
1205        map_tiles.defaults.defaultSymbol = map_tiles.defaults.nullSymbol;
1206        if (typeof Basemaps != 'undefined') {
1207            Basemaps.none = {
1208                title: 'Empty Basemap',
1209                itemId: 'none',
1210                baseMapLayers: [{
1211                    //url: 'https://services.arcgisonline.com/ArcGIS/rest/services/Specialty/DeLorme_World_Base_Map/MapServer',
1212		    url: 'https://services.arcgisonline.com/ArcGIS/rest/services/Specialty/World_Navigation_Charts/MapServer?f=json',
1213                    opacity: 0
1214                }]
1215            };
1216
1217        }
1218				function tlIsLocaleIdInComparison(localeId) {
1219    return (activeTile.timeline.localeTypes[activeTile.timeline.currentLocaleTypeId]['renderers'][activeTile.timeline.currentComparisonId]['localeIdList'][localeId] != undefined);
1220}
1221
1222function tlGetPriorValueDirection(value) {
1223	
1224	if (value == undefined) {
1225		return null;
1226	}
1227	const localeId = (value.hasOwnProperty("attributes")) ? value.attributes.localeId : null;
1228	if (tlIsLocaleIdInComparison(localeId)) {
1229		return activeTile.timeline.localeTypes[activeTile.timeline.currentLocaleTypeId]['indicatorValues'][localeId].priorValueDirection;
1230	}
1231	return null;
1232}
1233
1234function tlGetTrendValue(value) {
1235	
1236	if (value == undefined) {
1237		return null;
1238	}
1239	const localeId = (value.hasOwnProperty("attributes")) ? value.attributes.localeId : null;
1240	if (tlIsLocaleIdInComparison(localeId)) {
1241		return activeTile.timeline.localeTypes[activeTile.timeline.currentLocaleTypeId]['indicatorValues'][localeId].trendDirection;
1242	}
1243	return null;
1244}
1245
1246function tlCalculateDisplayValue(value) {
1247	
1248	if (value == undefined) {
1249		return null;
1250	}
1251	const localeId = value.attributes.localeId;
1252	if (localeId) {
1253		// verify locale is supposed to be shown for this comparison
1254		if (tlIsLocaleIdInComparison(localeId)) {
1255			return activeTile.timeline.localeTypes[activeTile.timeline.currentLocaleTypeId]['indicatorValues'][localeId]['value'];
1256		}
1257		else {
1258			return 'null';
1259		}
1260	}
1261	return 'null';
1262}
1263
1264function createUniqueValueRenderer(comparison) {
1265		var breaks = comparison['comparisonRendererParams'];
1266		if (comparison.comparisonType == 2) { // unique value renderer with special value handling
1267			var r = new UniqueValueRenderer(map_tiles.defaults.defaultSymbol, tlGetPriorValueDirection);
1268			for (var i = 0; i < (breaks.length); i++) {
1269				r.addValue({value: breaks[i].priorValueDirection,
1270					symbol: new SimpleFillSymbol(
1271						"solid",
1272						new SimpleLineSymbol("solid", new dojo.Color([0,50,100]), .33),
1273						new Color(breaks[i].symbol)
1274					),
1275					label: breaks[i].label});
1276			}
1277		}
1278		else if (comparison.comparisonType == 4) { // unique value renderer with special value handling
1279			var r = new UniqueValueRenderer(map_tiles.defaults.defaultSymbol, tlGetTrendValue);
1280			for (var i = 0; i < (breaks.length); i++) {
1281				r.addValue({value: breaks[i].trendDirection,
1282					symbol: new SimpleFillSymbol(
1283						"solid",
1284						new SimpleLineSymbol("solid", new dojo.Color([0,50,100]), .33),
1285						new Color(breaks[i].symbol)
1286					),
1287					label: breaks[i].label});
1288			}
1289		}
1290		else if (comparison.comparisonType == 'rank') { // unique value renderer with NO special value handling
1291			var r = new UniqueValueRenderer(map_tiles.defaults.defaultSymbol, tlCalculateDisplayValue);
1292			for (var i = 0; i < (breaks.length); i++) {
1293				r.addValue({value: breaks[i].value,
1294					symbol: new SimpleFillSymbol(
1295						"solid",
1296						new SimpleLineSymbol("solid", new dojo.Color([0,50,100]), .33),
1297						new Color(breaks[i].symbol)
1298					),
1299					label: breaks[i].label});
1300			}
1301		}
1302		else { // class breaks renderer for all other comparison types
1303			var r = new ClassBreaksRenderer(map_tiles.defaults.defaultSymbol, tlCalculateDisplayValue);
1304			r.setMaxInclusive(true);
1305			for (var i = 0; i < (breaks.length); i++) {
1306				r.addBreak({
1307					minValue: breaks[i].minValue,
1308					maxValue: breaks[i].maxValue,
1309					label: breaks[i].label,
1310					symbol: new SimpleFillSymbol(
1311						"solid",
1312						new SimpleLineSymbol("solid", new dojo.Color([0,50,100]), .33),
1313						new Color(breaks[i].symbol)
1314					)
1315				});
1316			}
1317		}
1318		return r;
1319}
1320
1321function updateComparisonData(localeTypeId, layer, localeType, tile) {
1322	var comparisons = localeType['renderers'];
1323	for (var c in comparisons) {
1324		var comparison = comparisons[c];
1325		r = createUniqueValueRenderer(comparison);
1326		// Default renderer
1327		if (c == 'default') {
1328			layer.setRenderer(r);
1329		}
1330		tile.timeline.localeTypes[localeTypeId]['renderers'][c]['renderer'] = r;
1331	}
1332	//console.log('updateComparisonData',tile.timeline.localeTypes[localeTypeId]['renderers']);
1333}	
1334
1335function updateMap(data, tile) {
1336	
1337	const localeTypeId = data.localeTypeId;
1338	const localeType = data.localeTypes?.[localeTypeId];
1339
1340	let currentLayer = tile.currentLayer;
1341	tile.currentLayer.hide();
1342	updateComparisonData(localeTypeId, currentLayer, localeType, tile);
1343	tile.currentLayer = currentLayer;
1344	console.log('updateMap tile.currentComparison=' + tile.currentComparison);
1345
1346	let currentComparisonId = tile.currentComparison || null;
1347	if (!currentComparisonId) {
1348		
1349		//const activeEl = document.querySelector(".gauge_value_container .comparison.active a");
1350		const container = '#indmap_indcol_' + tile.timeline.tileId;
1351		const activeEl = $(container).find(".gauge_value_container .comparison.active a");
1352		currentComparisonId = activeEl?.getAttribute("data-index") || null;
1353		//console.log('updateMap currentComparisonId=' + currentComparisonId);
1354	}
1355    //console.log('updateMap currentComparisonId=' + currentComparisonId);
1356	if (currentComparisonId) {
1357		tile.currentComparison = currentComparisonId;
1358		tile.timeline.currentComparisonId = currentComparisonId;
1359		const renderer = localeType?.renderers?.[currentComparisonId]?.renderer;
1360		if (renderer) {
1361			tile.currentLayer.setRenderer(renderer);
1362			tile.currentLayer.setOpacity(0.85);
1363			setLegend(tile, renderer);	
1364		}
1365	}
1366	tile.currentLayer.show();
1367}
1368
1369function updateTilesMap(data, tile) {
1370	console.log('updateTilesMap periodId='+data.periodId, data);
1371	updateTimelineVar(data, tile);
1372	updateMap(data, tile);
1373	updateGaugeContainer(data, tile);
1374}
1375
1376(function(global) {
1377    // Ensure we don't load multiple times
1378    if (global.TimelineModule) {
1379        return;
1380    }
1381	
1382	//console.log('timeline module');
1383
1384    // State container (per map tile)
1385    const timelines = {};
1386
1387    // ========== CORE METHODS ==========
1388
1389    function initTimeline(tile) {
1390		//console.log('initTimeline tile=',tile);
1391		console.log('initTimeline ');
1392        const mapId = tile.mapId;
1393        const timelineDiv = document.getElementById(`timelineDiv_${mapId}`);
1394        if (!timelineDiv) return;
1395
1396        // Cache per timeline
1397        timelines[mapId] = {
1398            //tile,
1399            timelineDiv,
1400            timeSlider: timelineDiv.querySelector('#timeSlider'),
1401            playButton: timelineDiv.querySelector('.playTimeline'),
1402            marks: timelineDiv.querySelectorAll('.mark'),
1403            marksContainer: timelineDiv.querySelector('.slider-marks'),
1404            playInterval: null,
1405            isPlaying: false
1406        };
1407
1408        const state = timelines[mapId];
1409
1410        // Slider listener
1411        if (state.timeSlider) {
1412            state.timeSlider.addEventListener('input', function() {
1413                const index = parseInt(this.value);
1414                const periodId = getKeyByIndex(tile.timeline.periodKeys, index);
1415                if (tile.timeline.allPeriodsData) {
1416                    updateTilesMap(tile.timeline.allPeriodsData[periodId], tile);
1417                }
1418            });
1419        }
1420
1421        // Play button listener
1422        if (state.playButton) {
1423            state.playButton.addEventListener('click', function() {
1424                if (state.isPlaying) {
1425                    stopPlayback(tile);
1426                } else {
1427                    startPlayback(tile);
1428                }
1429            });
1430        }
1431    }
1432
1433    function startPlayback(tile) {
1434        const state = timelines[tile.mapId];
1435        if (!state) return;
1436
1437        const timeSlider = state.timeSlider;
1438        const b4PeriodId = tile.timeline.periodId;
1439        const b4SliderValue = timeSlider.value;
1440
1441        state.isPlaying = true;
1442        state.playButton.innerHTML = '<i>⏸</i> Pause';
1443
1444        timeSlider.value = 0;
1445        state.playInterval = setInterval(function() {
1446            if (parseInt(timeSlider.value) < parseInt(timeSlider.max)) {
1447                playMap(tile);
1448                timeSlider.value = parseInt(timeSlider.value) + 1;
1449            } else if (parseInt(timeSlider.value) === parseInt(timeSlider.max)) {
1450                playMap(tile);
1451                stopPlayback(tile, b4SliderValue);
1452            }
1453        }, 1000);
1454    }
1455
1456    function stopPlayback(tile, initialValue) {
1457        const state = timelines[tile.mapId];
1458        if (!state) return;
1459
1460        state.isPlaying = false;
1461        clearInterval(state.playInterval);
1462        state.playButton.innerHTML = '<i>▶</i> Play';
1463        if (initialValue !== undefined) {
1464            state.timeSlider.value = initialValue;
1465        }
1466        playMap(tile);
1467    }
1468
1469    function playMap(tile) {
1470        const state = timelines[tile.mapId];
1471        if (!state) return;
1472
1473        const index = parseInt(state.timeSlider.value);
1474        const currentKey = getKeyByIndex(tile.timeline.periodKeys, index);
1475        console.log('playMap index=' + index + ' currentKey=' + currentKey);
1476        if (tile.timeline.allPeriodsData && tile.timeline.periodId != currentKey) {
1477            const data = tile.timeline.allPeriodsData[currentKey];
1478            if (data) {
1479                updateTilesMap(data, tile);
1480            } else {
1481                console.error("No data for period=" + currentKey);
1482            }
1483        }
1484    }
1485
1486    // ========== EXPORT ==========
1487    global.TimelineModule = {
1488        initTimeline,
1489        startPlayback,
1490        stopPlayback,
1491        playMap
1492    };
1493
1494})(window); //Requirement 2238139: GIS: Multiple Time Periods on a Map
1495
1496				if (!this.defaultsSet) {
1497					setDefaults();
1498					this.defaultsSet = true;
1499				}
1500                createApp();
1501		
1502                function createApp() {		
1503
1504					var ext = new esri.geometry.Extent({
1505							xmin: -1, xmax: 0, ymin: 0, ymax: 1,
1506							spatialReference: { wkid: 102100 }
1507						});				
1508				
1509					var newTiles = [];
1510					for (var tileId in map_tiles.tiles) {
1511						if (!map_tiles.initializedTiles[tileId]) {
1512							newTiles.push(map_tiles.tiles[tileId]);
1513							map_tiles.initializedTiles[tileId] = true;
1514						}
1515					}
1516
1517					//console.log("newTiles", newTiles);
1518					if (!newTiles.length) return;
1519					
1520					var createMapDeferreds = dojo.map(newTiles, function(item) {
1521						var newMap = null;
1522						//console.log("create map for " + item.mapId);
1523						try {
1524							newMap = new Map(item.mapId, {
1525								extent: ext,
1526								logo: false,
1527								basemap: item.currentBasemap,
1528								showLabels: true,
1529								showAttribution: true,
1530								smartNavigation: false
1531							});
1532							//console.log("create map for " + item.mapId, newMap);
1533						} catch (e) {
1534							console.error("Error in create map for " + item.mapId, e);
1535						}
1536						return [newMap, item];
1537					});
1538		
1539
1540					all(createMapDeferreds).then(function(createMapResponses) {
1541							dojo.forEach(createMapResponses, function(createMapResponse) {
1542								// INITIALIZE WEBMAP UI
1543								var map = createMapResponse[0];
1544								map.tile_id = createMapResponse[1].id;
1545								map_tiles.tiles[map.tile_id].map = map;
1546
1547								map.on('load', function() {
1548                                    var mapId = global.containerId.split('_')[1];
1549                                    var mapTitle = $('#map_' + mapId).parent().find('.indicatorLink').text();
1550                                    $('svg#map_' + mapId + '_gc').attr('aria-label', 'Map of ' + mapTitle);
1551
1552									$('.esriSimpleSliderIncrementButton').tooltip();
1553									$('.esriSimpleSliderDecrementButton').tooltip();
1554								});
1555								map.on('basemap-change', function() {
1556									var mapdata = map_tiles.tiles[map.tile_id];
1557									if (mapdata.currentBasemap == 'gray') {
1558										this.getLayer(this.basemapLayerIds[1]).setOpacity(0); // Turn off labels
1559									}
1560								});
1561								map.on('update-start', function() {
1562									$('#' + map.tile_id + ' .loading').show();
1563								});
1564								map.on('update-end', function() {
1565									var tile = map_tiles.tiles[map.tile_id];
1566									if (tile.transparency == 'on') {
1567										removeBoundaryOutlines(map, tile.currentLayer);
1568										addBoundaryOutlines(map, tile.currentLayer, map_tiles.defaults.highlightSymbols, tile.currentLocaleId);
1569									}
1570									$('#' + map.tile_id + ' .loading').hide();
1571								});
1572								initMap(map);
1573								
1574								//Requirement 2238139: GIS: Multiple Time Periods on a Map
1575								console.log('maptile initialization showTimeline='+map_tiles.tiles[map.tile_id].showTimeline);
1576								if (map_tiles.tiles[map.tile_id].showTimeline) {
1577									TimelineModule.initTimeline(map_tiles.tiles[map.tile_id]); 
1578								}else {
1579									hideTimelineDiv(map_tiles.tiles[map.tile_id]);
1580								}
1581							});//foreach
1582						});//all
1583                }//createApp	
1584			
1585                
1586                $('.tileinstance_indicatormap select').on('change', function() {
1587                    var type = this.name;
1588    	            var tileId = $(this).closest('.tileinstance').attr('id');
1589                    //console.log('tileinstance_indicatormap map_tiles.tiles[tileId].localeId='+map_tiles.tiles[tileId].localeId +" type="+type+" this.value="+this.value);
1590					if (type == 'indicators') {
1591                        map_tiles.tiles[tileId].indicatorId = this.value;
1592						$('#' + tileId).find('.location_unavailable').hide();
1593						getIndicatorInfo(map_tiles.tiles[tileId]);
1594						updateTimelineOnChange(map_tiles.tiles[tileId], tileId); //Requirement 2238139
1595                    }
1596                    else {
1597                        map_tiles.tiles[tileId].localeTypeId = this.options[this.selectedIndex].parentNode.id.replace('select_', '');
1598						if (map_tiles.tiles[tileId].localeId!=this.value) {
1599							map_tiles.tiles[tileId].localeId = this.value;
1600							$('#' + tileId).find('.location_unavailable').hide();
1601							getIndicatorInfo(map_tiles.tiles[tileId]);
1602							updateTimelineOnChange(map_tiles.tiles[tileId], tileId); //Requirement 2238139
1603						}
1604                    }
1605                    //$('#' + tileId).find('.location_unavailable').hide();
1606                    //getIndicatorInfo(map_tiles.tiles[tileId]);
1607                });
1608
1609                $('.tileinstance_indicatormap').on('click', '.comparison a', function(e) {
1610    	            e.preventDefault();
1611    	            var tileId = $(this).closest('.tileinstance').attr('id');
1612    	            $('#' + tileId + ' .comparison').removeClass('active');
1613    	            $(this).parent('.comparison').addClass('active');
1614    	            var tile = map_tiles.tiles[tileId];
1615    	            tile.currentComparison = $(this).attr('data-index');
1616					
1617					//Requirement 2238139: Update timeline variable
1618					tile.timeline.currentComparisonId = tile.currentComparison;
1619					if(tile.showTimeline && tile.timeline.periodId && tile.timeline.allPeriodsData && tile.timeline.periodId!=tile.timeline.initialPeriodId) {
1620						console.log('onComparisonClick - updateMap timeline.currentComparisonId='+tile.timeline.currentComparisonId );
1621						updateMap(tile.timeline.allPeriodsData[tile.timeline.periodId], tile);
1622					} else {
1623						var renderer = getRenderer(tile);
1624						tile.currentLayer.hide();
1625						var localeIds = renderer.localeIdList;
1626						var query = 'localeId IN (' + localeIds + ')';
1627						tile.currentLayer.setDefinitionExpression(query);
1628						tile.currentLayer.setRenderer(renderer);
1629						setLegend(tile, renderer);
1630
1631						if (tile.transparency == 'on') {
1632							tile.transparency = 'off';
1633							tile.currentLayer.setOpacity(0.85);
1634							removeBoundaryOutlines(tile.map, tile.currentLayer);
1635						}
1636						tile.currentLayer.show();
1637					}	
1638    	        });
1639
1640                $('.tileinstance_indicatormap').on('click', 'a.indicatorLink', function(e) {
1641                    var tileId = $(this).closest('.tileinstance').attr('id');
1642                    var tile = map_tiles.tiles[tileId];
1643                    if (tile.currentComparison) {
1644                        var benchmarkId = tile.currentComparison;
1645                        if (benchmarkId) {
1646                            $(this).attr('href', ($(this).attr('href') + '&comparisonId=' + benchmarkId));
1647                        }
1648                    }
1649                });
1650
1651                function initMap(map) {                    
1652                    addFeatureLayers(map);
1653                    selectLocation(map);
1654                    addSiteBoundary(map);
1655                }
1656
1657                function addSiteBoundary(map) {
1658                    // site boundary layer - added last so it's not obfuscated by the feature layer.
1659                    var site_layer = new FeatureLayer(map_tiles.mapLayers['Site'].layerUrl, {
1660                        mode: FeatureLayer.MODE_ONDEMAND,
1661                        outFields: ['NAME'],
1662                        id: "Site",
1663                        visible: true
1664                    });
1665                    site_layer.setDefinitionExpression("NAME = '" + map_tiles.site_prefix + "'");
1666                    site_layer.setRenderer(map_tiles.defaults.rendererSite);
1667                    map.site_layer = site_layer;
1668                    map.addLayer(site_layer);
1669                }
1670
1671                // the second query highlights the selected geography
1672                function selectLocation(map) {
1673
1674                    var tile = map_tiles.tiles[map.tile_id];
1675                    var layer = getMapLayer(tile.localeTypeId);
1676                    var url = (tile.localeTypeId == 3 && tile.data[tile.indicatorId]['usesZCTA'] == 1) ? layer.zctaUrl : layer.layerUrl;
1677					
1678                    var queryTask = new QueryTask(url);
1679                    var query = new Query();
1680                    query.returnGeometry = true;
1681                    query.outFields = ['localeId'];
1682                    query.where = " localeId = " + tile.localeId;
1683                    var qt = queryTask.execute(query);
1684                    qt.then(function(res) {
1685					//console.log('selectLocation query res='+res);	
1686                        highlightSelection(map, res);
1687                    }, function(err) {
1688                        errResults(map.id, err);
1689                    });
1690                }
1691
1692                function highlightSelection(map, results) {
1693					//console.log('highlightSelection results.features.length='+results.features.length);
1694                    if (results.features.length > 0) {
1695                        var tile = map_tiles.tiles[map.tile_id];
1696                        // the following bit helps ensure proper labeling of the map when navigating away and back to the page
1697                        // but only on 'locations' type tiles
1698                        if ($('#' + tile.id + ' select[name="indicators"]').length == 0) {
1699                            var loc = $('#' + tile.id + ' select option:selected').html();
1700                            var locType = $('#' + tile.id + ' select option:selected').parent('optgroup').attr('label');
1701                            if (tile.localeTypeId == 3 && tile.data[tile.indicatorId]['usesZCTA'] == 1) {
1702                                locType += ' (ZCTA)';
1703                            }
1704                            $('#' + tile.id + ' .map_location').html(locType + ': ' + loc);
1705                        }
1706                        var result = results.features[0];
1707                        var geometry = result.geometry;
1708                        if (map.graphics) {
1709                            map.graphics.clear(); // we use the maps graphics layer as the highlight layer
1710                        }
1711                        var polygon = new esri.geometry.Polygon(geometry.spatialReference);
1712                        var rings = geometry.rings;
1713                        for (var r = 0, rl = rings.length; r < rl; r++) {
1714                            polygon.addRing(rings[r]);
1715                        }
1716						//Requirement 2238138: GIS: Indicator Map Tile Update - Change selected color to yellow
1717                        //var indicatorGraphic = new esri.Graphic(polygon, map_tiles.defaults.highlightSymbol);
1718						var indicatorGraphic = new esri.Graphic(polygon, map_tiles.defaults.highlightSymbols['selectAlt']);
1719                        indicatorGraphic.id = 'indicatorGraphic';
1720                        map.graphics.add(indicatorGraphic);
1721                        if (tile.zoomToLocation) {
1722                            map.setExtent(geometry.getExtent(), true);
1723                        }
1724                        else {
1725                            var query = new Query();
1726                            query.where = '1=1';
1727                            var ext = tile.currentLayer.queryExtent(query);
1728                            ext.then(function(d) {
1729                                map.setExtent(d.extent, true);
1730                            });
1731                        }
1732                    }
1733                    else { // mapping not enabled at this location!
1734						console.log('highlightSelection err results.features.length=' + results.features.length +" results="+results);
1735                        errResults(map.id, results);
1736						
1737                    }
1738                }
1739
1740                function getMapLayer(localeTypeId) {
1741                    if (map_tiles.mapLayers[localeTypeId] !== undefined) {
1742                        return map_tiles.mapLayers[localeTypeId];
1743                    }
1744                    else {
1745                        return map_tiles.mapLayers['Region'];
1746                    }
1747                }
1748
1749                function errResults(tileId, err) {
1750                    var div = $('#' + tileId + ' .location_unavailable').show();
1751                }
1752
1753                // the following functions are used by the map renderers
1754                function calculateValue(feature) { // distributions
1755                    return getFeatureValue(feature, 'values');
1756                }
1757                function calculatePriorValueDirection(feature) { // prior values
1758                    return getFeatureValue(feature, 'priorValues');
1759                }
1760                function calculateTrendDirection(feature) { // trends
1761                    return getFeatureValue(feature, 'trends');
1762                }
1763                
1764                function getFeatureValue(feature, key) {
1765                    if (feature == undefined) {
1766                        return 'null';
1767                    }
1768                    var localeId = feature.attributes.localeId;
1769                    if (localeId) {
1770    	                var tileId = feature.getLayer().getMap().id.split('_')[1];
1771                        var tile = map_tiles.tiles['tileinstanceid_' + tileId];
1772                        var indicatorId = tile.indicatorId;
1773                        var localeTypeId = tile.localeTypeId;
1774                        return (tile.data[indicatorId][key][localeTypeId][localeId] != undefined) ? parseFloat(tile.data[indicatorId][key][localeTypeId][localeId]) : 'null';
1775    	            }
1776    	            return 'null';
1777                }
1778
1779                function addFeatureLayer(map, localeTypeId, usesZcta, indId) {
1780                    var layerId =  (localeTypeId == 3) ? 'layer_' + localeTypeId + '_' + usesZcta : 'layer_' + localeTypeId;
1781                    if (map.getLayer(layerId) != undefined) {
1782                        // skip if we have already added this layer, eg if a given zip code layer type has been added already,
1783                        return;
1784                    }
1785                    var tile = map_tiles.tiles[map.tile_id];
1786                    var layerCfg = getMapLayer(localeTypeId);
1787                    var url = (usesZcta == 1) ? layerCfg.zctaUrl : layerCfg.layerUrl;
1788                    var featureLayer = new FeatureLayer(
1789                        url, {
1790                            mode: FeatureLayer.MODE_AUTO,
1791                            outFields: layerCfg.outFields,
1792                            visible: false,
1793                            showLabels: true,
1794                            opacity: 0.85,
1795                            id: layerId
1796                    });
1797                    
1798                    var arcadeExp = `
1799                        var tmpLocales = ${JSON.stringify(tile.data['locales'])};
1800                        var ret = '';
1801                        for (var locId in tmpLocales) {
1802                            if ($feature.localeId == Abs(locId)) {
1803                                ret = tmpLocales[locId];
1804                                break;
1805                            }
1806                        }
1807                        return ret;
1808                    `;
1809                    var labelCfg = {
1810                        'labelExpressionInfo': {
1811                            expression: arcadeExp
1812                        }
1813                    };
1814                    var labelClass = new LabelClass(labelCfg);
1815                    labelClass.symbol = new TextSymbol("").setColor(new Color([0,0,0])).setFont(new Font("12px").setFamily("Arial"));
1816                    featureLayer.setLabelingInfo([labelClass]);
1817                    featureLayer.showLabels = false;
1818                    //tile.currentComparison = "6823";
1819					tile.currentComparison = tile.comparison; //read from map_tile config
1820					tile.timeline.currentComparisonId=tile.currentComparison;//Requirement 2238139
1821                    map.renderer = getRenderer(tile);
1822                    localeIds = map.renderer.localeIdList;
1823					//console.log('addFeatureLayer tile.localeTypeId='+tile.localeTypeId +' localeIds=',localeIds);
1824                    var query = 'localeId IN (' + localeIds + ')';
1825                    featureLayer.setDefinitionExpression(query);
1826                    featureLayer.setRenderer(map.renderer);
1827                    setLegend(tile, map.renderer);
1828                    if (localeTypeId == tile.localeTypeId) {
1829                        if (localeTypeId != 3 || (localeTypeId == 3 && indId == tile.indicatorId)) {
1830                            featureLayer.visible = true;
1831                            tile.currentLayer = featureLayer;
1832                            var extQuery = new Query();
1833                            extQuery.where = (tile.zoomToLocation) ? 'localeId = "' + tile.localeId + '"' : query;
1834                            var ext = featureLayer.queryExtent(extQuery);
1835                            ext.then(function(d) {
1836                                map.viewExtent = d.extent;
1837                            });
1838                        }
1839                    }
1840					//Requirement 2238138: GIS: Indicator Map Tile Update - mouse-move
1841					featureLayer.on('mouse-move', function(evt){
1842						var localeId = evt.graphic.attributes.localeId;
1843						//console.log('mouse-move localeId='+localeId);
1844						if (localeId) {
1845							highlightMapLocale(localeId,map)
1846						}
1847					});
1848					//Requirement 2238138: GIS: Indicator Map Tile Update - click	
1849					featureLayer.on('click', function(evt) {
1850						//$('#selectedLocaleDisplayContainer').addClass('hidden-all');
1851						var localeId = evt.graphic.attributes.localeId;
1852						//console.log('click localeId='+localeId + ' existing localeId='+map_tiles.tiles[map.tile_id].localeId);
1853						if (localeId && localeId != map_tiles.tiles[map.tile_id].localeId) {
1854							selectLocale(localeId, map);
1855						}
1856					});							
1857                    return featureLayer;
1858                }
1859
1860                function addFeatureLayers(map) {
1861                    var tile = map_tiles.tiles[map.tile_id];
1862                    var layers = [];
1863                    for (var x in tile.localeTypes) {
1864                        var localeTypeId = tile.localeTypes[x];
1865                        if (localeTypeId == 3) {
1866                            // zip codes require special handling due to ZCTAs, which are defined at the source level
1867                            continue;
1868                        }
1869                        layers.push(addFeatureLayer(map, localeTypeId, false, null));
1870                    }
1871                    // there is a map layer for ZCTAs and a separate one for Zip Codes, so we need to treat them
1872                    // as distinct 'locale types' for the purposes of mapping.
1873                    if ($.inArray(3, tile.localeTypes) > -1) {
1874                        localeTypeId = 3;
1875                        for (var indId in tile.data) {
1876                            if (!$.isNumeric(indId)) {
1877                                continue;
1878                            }
1879                            var usesZcta = (tile.data[indId]['usesZCTA'] == 1) ? 1 : 0;
1880                            layers.push(addFeatureLayer(map, localeTypeId, usesZcta, indId));
1881                        }
1882                    }
1883                    map.addLayers(layers);
1884                    var query = new Query();
1885                    query.where = (tile.zoomToLocation) ? 'localeId = "' + tile.localeId + '"' : '1=1';
1886                    var ext = tile.currentLayer.queryExtent(query);
1887                    ext.then(function(d) {
1888                        map.viewExtent = d.extent;
1889                        map.setExtent(d.extent, true);
1890                    });
1891                    map.disableScrollWheelZoom();
1892                }
1893
1894                function updateIndicatorMap(tile) {
1895                    var layerId = 'layer_' + tile.localeTypeId;
1896                    if (tile.localeTypeId == 3) {
1897                        var usesZcta = tile.data[tile.indicatorId]['usesZCTA'];
1898                        layerId += '_' + usesZcta;
1899                        var zctaFlags = [0,1];
1900                        for (var zctaFlag in zctaFlags) {
1901                            var tmpLayerId = 'layer_' + tile.localeTypeId + '_' + zctaFlag;
1902                            var layer = tile.map.getLayer(tmpLayerId);
1903                            if (layer != undefined) {
1904                                layer.hide();
1905                            }
1906                        }
1907                    }
1908					//console.log('updateIndicatorMap layerId='+layerId +' tile.currentLayer.id='+tile.currentLayer.id);
1909                    if (tile.currentLayer.id != layerId) {
1910                        tile.currentLayer.hide(); // different locale type - show correct layer
1911                        tile.currentLayer = tile.map.getLayer(layerId);
1912                        tile.currentComparison = '';
1913						tile.timeline.currentComparisonId=tile.currentComparison;//Requirement 2238139
1914                    }
1915                    var renderer = getRenderer(tile);
1916                    tile.currentLayer.hide();
1917                    localeIds = renderer.localeIdList;
1918                    var query = 'localeId IN (' + localeIds + ')';
1919                    tile.currentLayer.setDefinitionExpression(query);
1920                    tile.currentLayer.setRenderer(renderer);
1921                    tile.currentLayer.show();
1922                    selectLocation(tile.map);
1923                    setLegend(tile, renderer);
1924                }
1925                
1926                function getIndicatorInfo(map_tile) {
1927                    var container = '#' + map_tile.id;
1928                    $(container + ' .indicator_container').css('opacity', '.1');
1929                    $(container + ' .map_column').css('opacity', '.1');
1930                    $(container + ' .loading').show();
1931                    var indicatorId = map_tile.indicatorId;
1932                    var localeId = map_tile.localeId;
1933                    var localeTypeId = map_tile.localeTypeId;
1934                    var currentComparison = map_tile.currentComparison;
1935                    //var defaultComparison = "6823";
1936					var defaultComparison = map_tile.comparison;
1937                    var url = ClientSite.Extensions.Url().quickUrl('indicators', 'indexajax', 'dispatch', {callAction: 'getMapTileValueData'});
1938                    var getValues = (Object.keys(map_tile.data[indicatorId]['values'][localeTypeId]).length == 0) ? 1 : 0;
1939					//console.log('getIndicatorInfo container='+container+' getValues='+getValues +" url="+url);
1940                    $.ajax({
1941                        dataType: "json",
1942                        url: url,
1943                        data: {
1944                            'localeId': localeId,
1945                            'localeTypeId': localeTypeId,
1946                            'indicatorId': indicatorId,
1947                            'currentComparison': currentComparison,
1948                            'defaultComparison': defaultComparison,
1949                            'hideDescription': 0,
1950                            'getValues': getValues,
1951                            'json': 1
1952                        },
1953                        method: 'post',
1954                        success: function(ret) {
1955							console.log('getIndicatorInfo getMapTileValueData ajax success  ret',ret);
1956                            if (ret.result == 'error') {
1957                                $(container + ' .indicator_container').hide();
1958                                return;
1959                            }
1960							map_tile.timeline.periodId=ret.periodId;
1961                            if (getValues) {
1962                                map_tile.data[indicatorId]['priorValues'][localeTypeId] = ret.priorValues;
1963                                map_tile.data[indicatorId]['values'][localeTypeId] = ret.values;
1964                                map_tile.data[indicatorId]['trends'][localeTypeId] = ret.trends;
1965                                map_tile.data[indicatorId]['renderers'][localeTypeId] = ret.renderers;
1966                                map_tile.data[indicatorId]['usesZCTA'] = (ret.usesZcta) ? 1 : 0;
1967                            }
1968                            $(container + ' .indicator_container')
1969                                .html(ret.html)
1970                                .css('opacity', 1);
1971                            if (map_tile.fullWidth) {
1972                                $('#indmap_indcol_'+map_tile.id).find('.indicator_container div.gauge_value_container').addClass('row');
1973                                $('#indmap_indcol_'+map_tile.id).find('.indicator_container div.gauge_value_container').removeClass('margin-bottom-15');
1974                            }
1975
1976                            var localeType = ret.locale['localeTypeDisplayName'];
1977                            var localeName = ret.locale['displayName'];
1978                            if (ret.locale['localeTypeId'] == 3 && ret['usesZcta'] == 1) {
1979                                localeType += ' (ZCTA)';
1980                            }
1981                            $(container + ' .map_location').html(
1982                                localeType + ': ' + localeName
1983                            );
1984
1985                            $(container + ' .map_indicator').html(
1986                                ret.indicator['title']
1987                            );
1988                            $(container + ' .sourceTitle').html(
1989                                ret.sourceTitle
1990                            );
1991                            var url = ClientSite.Extensions.Url().quickUrl(
1992                                'indicators', 
1993                                'index', 
1994                                'view', 
1995                                {'localeId': localeId, 'indicatorId': indicatorId}
1996                            );
1997                            $(container + ' .indicatorLink').prop('href', url);
1998                            updateIndicatorMap(map_tile);
1999                            setTimeout( // this delay is just a wedge to improve UX, it is not required
2000                                function() {
2001                                    $(container + ' .map_column').css('opacity', 1);
2002                                    $(container + ' .loading').hide();
2003                                },
2004                                400
2005                            );
2006
2007                            $('.htmlTooltip').tooltip({
2008                                track: true,
2009                                content: function() {
2010                                    return $(this).prop('title');
2011                                }
2012                            });
2013                        },
2014						error: function (xhr) {
2015							console.error('getIndicatorInfo ajax error=', xhr.responseText);
2016						}
2017                    });
2018
2019                }
2020
2021                function setLegend(tile, renderer) {
2022                    var container = '#' + tile.id;
2023                    $(container + ' .mapLegend').hide();
2024                    var html = $();
2025                    for (var i in renderer.infos) {
2026                        var row = renderer.infos[i];
2027                        var r = row.symbol.color;
2028                        var rgba = r.r + ',' + r.g + ',' + r.b + ',' + r.a;
2029                        var swatchDiv = $('<div>',{'class': 'clearfix'});
2030                        
2031                        swatchDiv.append($('<div>',{'class': 'swatch', 'style': 'background-color: rgba(' + rgba + ')'}));
2032                        swatchDiv.append($('<div>', {'class': 'left'}).html(row.label));
2033                        html = html.add(swatchDiv);
2034                    }
2035                    //var unit = renderer.infos[0].unit;
2036					var unit = renderer?.infos?.[0]?.unit;
2037                    if (unit != undefined && unit != 'percent') {
2038                        $(container + ' .mapLegend').attr('title', unit).addClass('tooltip');
2039                    }
2040                    else {
2041                        $(container + ' .mapLegend').attr('title', '').removeClass('tooltip');
2042                    }
2043                    $('.tooltip').tooltip();                        
2044                    $(container + ' .mapLegend').html(html);
2045                    $(container + ' .mapLegend').fadeIn();
2046                }
2047
2048                function getRenderer(tile) {
2049                    var index = $('#' + tile.id + ' .comparison.active a').attr('data-index');
2050                    var rendererInfo = tile.data[tile.indicatorId]['renderers'][tile.localeTypeId][index];
2051                    if (undefined == rendererInfo) { // invalid renderer, eg 'default' for single locale view
2052                        for (var k in tile.data[tile.indicatorId]['renderers'][tile.localeTypeId]) {
2053                            rendererInfo = tile.data[tile.indicatorId]['renderers'][tile.localeTypeId][k];
2054                            $('#' + tile.id + ' .comparison-' + k).addClass('active');
2055                            break;
2056                        }
2057                    }
2058                    var breaks = rendererInfo['breaks'];
2059                    var renderer;
2060    	            if (rendererInfo['comparisonTypeId'] == 2) { // prior value
2061                        renderer = new UniqueValueRenderer(map_tiles.defaults.defaultSymbol, calculatePriorValueDirection);
2062                        for (var i in breaks) {
2063                            var rval = breaks[i];
2064                            renderer.addValue({
2065                                value: rval.priorValueDirection,
2066                                symbol: new SimpleFillSymbol(
2067                                    "solid",
2068                                    new SimpleLineSymbol("solid", new dojo.Color([0,50,100]), .33),
2069                                    new dojo.Color(rval.symbol)),
2070                                label: rval.label
2071                            });
2072                        }
2073    	            }
2074    	            else if (rendererInfo['comparisonTypeId'] == 4) { // trend direction
2075                        renderer = new UniqueValueRenderer(map_tiles.defaults.defaultSymbol, calculateTrendDirection);
2076                        for (var i in breaks) {
2077                            var rval = breaks[i];
2078                            renderer.addValue({
2079                                value: rval.trendDirection,
2080                                symbol: new SimpleFillSymbol(
2081                                    "solid",
2082                                    new SimpleLineSymbol("solid", new dojo.Color([0,50,100]), .33),
2083                                    new dojo.Color(rval.symbol)),
2084                                label: rval.label
2085                            });
2086                        }
2087    	            }
2088    	            else if (rendererInfo['comparisonTypeId'] == 'default' && rendererInfo['localeIdList'].length <= 5) {
2089                        renderer = new UniqueValueRenderer(map_tiles.defaults.defaultSymbol, calculateValue);
2090                        for (var i in breaks) {
2091                            var rval = breaks[i];
2092                            renderer.addValue({
2093                                value: rval.value,
2094                                symbol: new SimpleFillSymbol(
2095                                    "solid",
2096                                    new SimpleLineSymbol("solid", new dojo.Color([0,50,100]), .33),
2097                                    new dojo.Color(rval.symbol)),
2098                                label: rval.label
2099                            });
2100                        }
2101                    }    
2102                    else { 
2103                        renderer = new ClassBreaksRenderer(map_tiles.defaults.defaultSymbol, calculateValue);
2104                        renderer.setMaxInclusive(true);
2105                        for (i in breaks) {
2106                            var rval = breaks[i];
2107                            renderer.addBreak({
2108                                minValue: rval.minValue,
2109                                maxValue: rval.maxValue,
2110                                label: rval.label,
2111                                unit: rval.unit,
2112                                symbol: new SimpleFillSymbol(
2113                                    "solid",
2114                                    new SimpleLineSymbol("solid", new dojo.Color([0,50,100]), .33),
2115                                    new dojo.Color(rval.symbol)
2116                                )
2117                            });
2118                        }
2119                    }
2120                    renderer.localeIdList = rendererInfo.localeIdList;
2121                    return renderer;
2122                }
2123
2124                function setDefaults() {
2125                    map_tiles.defaults.defaultSymbol = new SimpleFillSymbol().setColor(new Color('rgba(0,0,0,.3)'));
2126                    map_tiles.defaults.highlightSymbol = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color('rgba(50, 255, 255, 1)'), 3);
2127                    esri.config.defaults.io.proxyUrl = "/content/global/source/gis/gis_proxy.php";
2128                    esri.config.defaults.io.alwaysUseProxy = false;
2129                    // site boundary
2130                    var siteOutline = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color('rgba(35, 79, 128, .73)'), 2);
2131                    var sym = new SimpleFillSymbol(SimpleFillSymbol.STYLE_NULL, siteOutline);
2132                    map_tiles.defaults.rendererSite = new SimpleRenderer(sym);
2133                    $('.tooltip, .htmlTooltip').tooltip({
2134                        track: true,
2135                        content: function() {
2136                            return $(this).prop('title');
2137                        }
2138                    });
2139                }
2140				
2141				//Requirement 2238138: GIS: Indicator Map Tile Update START
2142				function highlightMapLocale(localeId, map) {
2143					//console.log('highlightMapLocale localeId='+localeId);
2144					var tile = map_tiles.tiles[map.tile_id];
2145					if (tile.currentLayer) {
2146						clearMapSelection('highlight',map);
2147						tile.currentLayer.graphics.forEach(function(g) {
2148							if (g.attributes.localeId == localeId) {
2149								var polygon = new esri.geometry.Polygon(g.geometry.spatialReference);
2150								var rings = g.geometry.rings;
2151								for (var r=0, rl=rings.length; r<rl; r++) {
2152									polygon.addRing(rings[r]);
2153								}
2154								var graphic = new esri.Graphic(polygon, map_tiles.defaults.highlightSymbol);
2155								graphic.id = 'highlight';
2156								map.graphics.add(graphic);
2157								return;
2158							}
2159						});
2160					}
2161				}
2162
2163				function clearMapSelection(id, map) {
2164					if (map && map.graphics) {
2165						dojo.some(map.graphics.graphics, function(g, i) {
2166							if (g && g.id == id) {
2167								map.graphics.remove(map.graphics.graphics[i]);
2168								return;
2169							}
2170						});
2171					}
2172				}
2173				
2174				function selectLocale(localeId, map) {
2175
2176					var tile = map_tiles.tiles[map.tile_id];
2177					var tileId = map.tile_id;
2178					$('#'+tileId+' select[name="locations"]').val(localeId);
2179                    
2180                    var layer = getMapLayer(tile.localeTypeId);
2181                    var url = (tile.localeTypeId == 3 && tile.data[tile.indicatorId]['usesZCTA'] == 1) ? layer.zctaUrl : layer.layerUrl;
2182					//console.log('selectLocale tile.localeTypeId='+tile.localeTypeId + " tile.localeId="+tile.localeId + " localeId="+localeId);
2183					//console.log('selectLocale url='+url);
2184					
2185					map_tiles.tiles[map.tile_id].localeId = localeId;
2186					updateTimelineOnChange(map_tiles.tiles[map.tile_id], map.tile_id);//Requirement 2238139
2187					
2188                    var queryTask = new QueryTask(url);
2189                    var query = new Query();
2190                    query.returnGeometry = true;
2191                    query.outFields = ['localeId'];
2192                    query.where = " localeId = " + localeId;
2193                    var qt = queryTask.execute(query);
2194                    qt.then(function(res) {
2195						//console.log('selectLocale query res='+res);	
2196                        highlightSelection(map, res);
2197						updateIndicatorContainer(map_tiles.tiles[map.tile_id]);
2198                    }, function(err) {
2199                        errResults(map.id, err);
2200                    });
2201                }
2202				
2203				function updateIndicatorContainer(map_tile) {
2204                    var container = '#' + map_tile.id;
2205					//STDEBUG to hide blue screen on loading
2206                    $(container + ' .indicator_container').css('opacity', '.1');
2207                    $(container + ' .map_column').css('opacity', '.1');
2208                    $(container + ' .loading').show();
2209                    var indicatorId = map_tile.indicatorId;
2210                    var localeId = map_tile.localeId;
2211                    var localeTypeId = map_tile.localeTypeId;
2212                    var currentComparison = map_tile.currentComparison;
2213                    //var defaultComparison = "6823";
2214					var defaultComparison = map_tile.comparison;
2215                    var url = ClientSite.Extensions.Url().quickUrl('indicators', 'indexajax', 'dispatch', {callAction: 'getMapTileValueData'});
2216                    var getValues = (Object.keys(map_tile.data[indicatorId]['values'][localeTypeId]).length == 0) ? 1 : 0;
2217                    $.ajax({
2218                        dataType: "json",
2219                        url: url,
2220                        data: {
2221                            'localeId': localeId,
2222                            'localeTypeId': localeTypeId,
2223                            'indicatorId': indicatorId,
2224                            'currentComparison': currentComparison,
2225                            'defaultComparison': defaultComparison,
2226                            'hideDescription': 0,
2227                            'getValues': getValues,
2228                            'json': 1
2229                        },
2230                        method: 'post',
2231                        success: function(ret) {
2232							//console.log('updateIndicatorContainer getMapTileValueData ret',ret);
2233                            if (ret.result == 'error') {
2234                                $(container + ' .indicator_container').hide();
2235                                return;
2236                            }
2237							map_tile.timeline.periodId=ret.periodId;
2238                            if (getValues) {
2239                                map_tile.data[indicatorId]['priorValues'][localeTypeId] = ret.priorValues;
2240                                map_tile.data[indicatorId]['values'][localeTypeId] = ret.values;
2241                                map_tile.data[indicatorId]['trends'][localeTypeId] = ret.trends;
2242                                map_tile.data[indicatorId]['renderers'][localeTypeId] = ret.renderers;
2243                                map_tile.data[indicatorId]['usesZCTA'] = (ret.usesZcta) ? 1 : 0;
2244                            }
2245                            $(container + ' .indicator_container')
2246                                .html(ret.html)
2247                                .css('opacity', 1);
2248
2249                            if (map_tile.fullWidth) {
2250                                $('#indmap_indcol_'+map_tile.id).find('.indicator_container div.gauge_value_container').addClass('row');
2251                                $('#indmap_indcol_'+map_tile.id).find('.indicator_container div.gauge_value_container').removeClass('margin-bottom-15');
2252                            }
2253
2254                            var localeType = ret.locale['localeTypeDisplayName'];
2255                            var localeName = ret.locale['displayName'];
2256                            if (ret.locale['localeTypeId'] == 3 && ret['usesZcta'] == 1) {
2257                                localeType += ' (ZCTA)';
2258                            }
2259                            $(container + ' .map_location').html(
2260                                localeType + ': ' + localeName
2261                            );
2262
2263                            $(container + ' .map_indicator').html(
2264                                ret.indicator['title']
2265                            );
2266                            $(container + ' .sourceTitle').html(
2267                                ret.sourceTitle
2268                            );
2269                            var url = ClientSite.Extensions.Url().quickUrl(
2270                                'indicators', 
2271                                'index', 
2272                                'view', 
2273                                {'localeId': localeId, 'indicatorId': indicatorId}
2274                            );
2275                            $(container + ' .indicatorLink').prop('href', url);
2276                            setTimeout( // this delay is just a wedge to improve UX, it is not required
2277                                function() {
2278                                    $(container + ' .map_column').css('opacity', 1);
2279                                    $(container + ' .loading').hide();
2280                                },
2281                                400
2282                            );
2283
2284                            $('.htmlTooltip').tooltip({
2285                                track: true,
2286                                content: function() {
2287                                    return $(this).prop('title');
2288                                }
2289                            });
2290							
2291							var renderer = getRenderer(map_tile);
2292							localeIds = renderer.localeIdList;
2293							var query = 'localeId IN (' + localeIds + ')';
2294							map_tile.currentLayer.setDefinitionExpression(query);
2295							map_tile.currentLayer.setRenderer(renderer);
2296							map_tile.currentLayer.show();
2297							setLegend(map_tile, renderer);
2298							
2299                        }
2300                    });
2301
2302                }
2303				//Requirement 2238138: GIS: Indicator Map Tile Update END
2304				
2305            })
2306        },
2307		addTile: function (tileId, config) {
2308            if (!this.tiles[tileId]) {
2309                this.tiles[tileId] = config;
2310            } else {
2311                console.warn("Tile already exists:", tileId);
2312            }
2313        }
2314    }; //map_tiles
2315    global.map_tiles = map_tiles;
2316    global._map_tiles_instance = map_tiles;
2317})(window);
2318
2319
2320function toggleIndMapLayout(tileId) {
2321        var mapId = 'indmap_mapcol_'+tileId;
2322        var indcolClass = 12 - map_tiles.tiles[tileId].mapcolWidth;
2323        if (map_tiles.tiles[tileId].fullWidth === false || map_tiles.tiles[tileId].fullWidth == undefined) {
2324            $( "#"+mapId ).resizable({
2325                handles: 'se',
2326                classes: {
2327                    "ui-resizable-se": "ui-icon ui-icon-grip-diagonal-se"
2328                },
2329                minHeight: 200,
2330            });
2331            $("#"+mapId).addClass('indmaptile-map-large');
2332            $('#indmap_indcol_'+tileId)
2333                .removeClass('col-md-'+indcolClass)
2334                .find('.indicator_container div.gauge_value_container').addClass('row');
2335
2336            $('#indmap_mapcol_'+tileId).removeClass('col-md-'+map_tiles.tiles[tileId].mapcolWidth);
2337
2338            map_tiles.tiles[tileId].fullWidth = true;
2339        } else {
2340            $( "#"+mapId ).resizable( "destroy" );
2341            $("#"+mapId).removeClass('indmaptile-map-large');
2342            $('#indmap_indcol_'+tileId)
2343                .addClass('col-md-'+indcolClass)
2344                .find('.indicator_container div.gauge_value_container').removeClass('row');
2345
2346            $('#indmap_mapcol_'+tileId).addClass('col-md-'+map_tiles.tiles[tileId].mapcolWidth);
2347
2348            map_tiles.tiles[tileId].fullWidth = false;
2349        }
2350        setTimeout (function() {
2351            recenterMap(map_tiles.tiles[tileId].map);
2352        }, 800);
2353    }
2354
2355$(document).on("click", ".enableTimeline", async function(e) {
2356    e.preventDefault();
2357	
2358	const $button = $(this);
2359	$button.prop('disabled', true).addClass('disabled');
2360	
2361    const $timelineDiv = $(this).closest('.timelineDiv');
2362    const $loadingIcon = $timelineDiv.find('.timeline-loading-icon');
2363    const mapId = $timelineDiv.attr('id').replace('timelineDiv_', '');
2364
2365    // Show loading icon (it's already positioned absolutely within the timeline)
2366    $loadingIcon.css('display', 'block');
2367    
2368    // Extract numeric tile instance ID
2369    const key = mapId.replace("map_", "");
2370    const tileId = "tileinstanceid_" + key;
2371
2372    const tile = map_tiles.tiles[tileId];
2373    if (!tile) {
2374        console.error("Tile not found:", tileId);
2375        $loadingIcon.hide();
2376        return;
2377    }
2378
2379    try {
2380        // load periods first
2381        if (!tile.timeline.allPeriodsData) {
2382            await getDataForAllPeriods(tile);
2383        }
2384
2385        // build UI
2386        showTimeSlider(tile);
2387
2388        // play safely
2389        if (TimelineModule?.startPlayback) {
2390            TimelineModule.startPlayback(tile);
2391        } else {
2392            console.error("TimelineModule.startPlayback missing");
2393        }
2394
2395    } catch (err) {
2396        console.error("Failed timeline start:", err);
2397    } finally {
2398        $loadingIcon.hide();
2399    }
2400});
2401
2402</script>
2402	
2402<script type="text/javascript">
2403    
2404    $(document).ready(function() {
2405        var baseTarget = (document.getElementById("baseAttributes") && document.getElementById("baseAttributes").target) ? document.getElementById("baseAttributes").target : '_self';
2406    	map_tiles.init();
2407    	for (containerId in map_tiles.tiles) {
2408    		var tile = map_tiles.tiles[containerId];
2409        	var id = (tile.type == 'indicators') ? tile.indicatorId : tile.localeId;
2410			
2411			//Add checking if select elements exists
2412			var $selectElement = $('#' + containerId + ' select');
2413			if ( $selectElement.length ) {
2414				var val = $('#' + containerId + ' select').val();
2415				if (val != id) { // back button navigation, browser remembers selected opt
2416					if (tile.type == 'indicators') {
2417						tile.indicatorId = $('#' + containerId + ' select').val();
2418					}
2419					if (tile.type == 'locations') {
2420						tile.localeId = $('#' + containerId + ' select').val();
2421						tile.localeTypeId = $('#' + containerId + ' select option:selected').parent('optgroup').prop('id').split('_')[1]; // select_[localeTypeId]
2422					}
2423					$('#' + containerId + ' select').trigger('change');
2424				}
2425			}	
2426    	}
2427    	$('.close').on('click', function (e) {
2428        	e.preventDefault();
2429            $(this).parent('.location_unavailable').fadeOut();
2430    	});
2431    });
2432
2433
2434function recenterMap(indmap) {
2435    indmap.setExtent(indmap.viewExtent, true);
2436}
2437
2438var showInd='1';
2439console.log('showIndicator for map_301993011390254111='+showInd);
2440
2441if(showInd == '1' || showInd == 'true') { 
2442
2443// set data for this tile instance
2444map_tiles.addTile('tileinstanceid_301993011390254111',{
2445    id              : 'tileinstanceid_301993011390254111',
2446    mapId           : 'map_301993011390254111',
2447    type            : 'indicators',
2448    localeId        : '2274',
2449    localeTypeId    : '2',
2450    localeTypes     : [2],
2451    indicatorId     : '240',
2452    data	        : {"locales":{"2274":"Jackson","2276":"Josephine"},"29":{"values":{"2":{"2274":"19.4","2276":"29.6"}},"trends":{"2":{"2274":4,"2276":4}},"priorValues":{"2":{"2274":1,"2276":1}},"renderers":{"2":{"default":{"comparisonTypeId":"default","breaks":[{"value":19.39999999999999857891452847979962825775146484375,"label":"19.4%","symbol":"rgba(49,130,189,1)","unit":"percent"},{"value":29.60000000000000142108547152020037174224853515625,"label":"29.6%","symbol":"rgba(189,215,231,1)","unit":"percent"}],"localeIdList":[2274,2276]},"6823":{"comparisonTypeId":1,"breaks":[{"minValue":"-Infinity","maxValue":17.699999999999999289457264239899814128875732421875,"symbol":"rgba(232, 45, 38,1)","label":"Worst Quarter<br \/>&lt; 17.7%","unit":"percent"},{"minValue":17.699999999999999289457264239899814128875732421875,"maxValue":22.5,"symbol":"rgba(215, 215, 6,1)","label":"2nd Worst Quarter<br \/>17.7% - 22.5%","unit":"percent"},{"minValue":22.5,"maxValue":"Infinity","symbol":"rgba(49, 163, 84,1)","label":"Best 50%<br \/>&gt; 22.5%","unit":"percent"}],"localeIdList":"2274,2276"},"7203":{"comparisonTypeId":0,"breaks":[{"minValue":"-Infinity","maxValue":26.398999999999997356781022972427308559417724609375,"symbol":"rgba(232, 45, 38,1)","label":"&lt; 26.4%","unit":"percent"},{"minValue":26.398999999999997356781022972427308559417724609375,"maxValue":26.400999999999999801048033987171947956085205078125,"symbol":"rgba(49, 130, 189,1)","label":"= 26.4%","unit":"percent"},{"minValue":26.39999999999999857891452847979962825775146484375,"maxValue":"Infinity","symbol":"rgba(49, 163, 84,1)","label":"&gt; 26.4%","unit":"percent"}],"localeIdList":"2274,2276"},"923":{"comparisonTypeId":2,"breaks":[{"comparisonValue":"trend-down-bad","priorValueDirection":2,"symbol":"rgba(232, 45, 38,1)","label":"Decreased\/worsened","unit":null},{"comparisonValue":"trend-equal-neutral","priorValueDirection":3,"symbol":"rgba(189, 215, 231,1)","label":"No significant change","unit":null},{"comparisonValue":"trend-up-good","priorValueDirection":1,"symbol":"rgba(49, 163, 84,1)","label":"Increased\/improved","unit":null}],"localeIdList":"2274,2276"},"927":{"comparisonTypeId":4,"breaks":[{"comparisonValue":"down-sig","trendDirection":5,"symbol":"rgba(232, 45, 38,1)","label":"Worse, significant","unit":null}
2452,{"comparisonValue":"down","trendDirection":4,"symbol":"rgba(252, 174,145,1)","label":"Worse, not significant","unit":null},{"comparisonValue":"equal","trendDirection":3,"symbol":"rgba(189, 215, 231,1)","label":"No change","unit":null},{"comparisonValue":"up","trendDirection":2,"symbol":"rgba(186, 228, 179,1)","label":"Better, not significant","unit":null},{"comparisonValue":"up-sig","trendDirection":1,"symbol":"rgba(49, 163, 84,1)","label":"Better, significant","unit":null}],"localeIdList":"2274,2276"}}},"usesZCTA":1},"30":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"340":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"189":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"240":{"values":{"2":{"2274":"7.7","2276":"11.1"}},"trends":{"2":{"2274":5,"2276":5}},"priorValues":{"2":{"2274":3,"2276":3}},"renderers":{"2":{"default":{"comparisonTypeId":"default","breaks":[{"value":7.70000000000000017763568394002504646778106689453125,"label":"7.7%","symbol":"rgba(189,215,231,1)","unit":"percent"},{"value":11.0999999999999996447286321199499070644378662109375,"label":"11.1%","symbol":"rgba(49,130,189,1)","unit":"percent"}],"localeIdList":[2274,2276]},"6823":{"comparisonTypeId":1,"breaks":[{"minValue":"-Infinity","maxValue":8.5999999999999996447286321199499070644378662109375,"symbol":"rgba(49, 163, 84,1)","label":"Best  50%<br \/>&lt; 8.6%","unit":"percent"},{"minValue":8.5999999999999996447286321199499070644378662109375,"maxValue":10.4000000000000003552713678800500929355621337890625,"symbol":"rgba(215, 215, 6,1)","label":"2nd Worst Quarter<br \/>8.6% - 10.4%","unit":"percent"},{"minValue":10.4000000000000003552713678800500929355621337890625,"maxValue":"Infinity","symbol":"rgba(232, 45, 38,1)","label":"Worst Quarter<br \/>&gt; 10.4%","unit":"percent"}],"localeIdList":"2276,2274"},"6865":{"comparisonTypeId":1,"breaks":[{"minValue":"-Infinity","maxValue":9.0999999999999996447286321199499070644378662109375,"symbol":"rgba(49, 163, 84,1)","label":"Best  50%<br \/>&lt; 9.1%","unit":"percent"},{"minValue":9.0999999999999996447286321199499070644378662109375,"maxValue":12.699999999999999289457264239899814128875732421875,"symbol":"rgba(215, 215, 6,1)","label":"2nd Worst Quarter<br \/>9.1% - 12.7%","unit":"percent"},{"minValue":12.699999999999999289457264239899814128875732421875,"maxValue":"Infinity","symbol":"rgba(232, 45, 38,1)","label":"Worst Quarter<br \/>&gt; 12.7%","unit":"percent"}],"localeIdList":"2276,2274"},"7203":{"comparisonTypeId":0,"breaks":[{"minValue":"-Infinity","maxValue":7.49899999999999966604491419275291264057159423828125,"symbol":"rgba(49, 163, 84,1)","label":"&lt; 7.5%","unit":"percent"},{"minValue":7.49899999999999966604491419275291264057159423828125,"maxValue":7.50100000000000033395508580724708735942840576171875,"symbol":"rgba(49, 130, 189,1)","label":"= 7.5%","unit":"percent"},{"minValue":7.50100000000000033395508580724708735942840576171875,"maxValue":"Infinity","symbol":"rgba(232, 45, 38,1)","label":"&gt; 7.5%","unit":"percent"}],"localeIdList":"2276,2274"},"7227":{"comparisonTypeId":0,"breaks":[{"minValue":"-Infinity","maxValue":8.7990000000000012647660696529783308506011962890625,"symbol":"rgba(49, 163, 84,1)","label":"&lt; 8.8%","unit":"percent"},{"minValue":8.7990000000000012647660696529783308506011962890625,"maxValue":8.8010000000000001563194018672220408916473388671875,"symbol":"rgba(49, 130, 189,1)","label":"= 8.8%","unit":"percent"},{"minValue":8.8010000000000001563194018672220408916473388671875,"maxValue":"Infinity","symbol":"rgba(232, 45, 38,1)","label":"&gt; 8.8%","unit":"percent"}],"localeIdList":"2276,2274"},"927":{"comparisonTypeId":4,"breaks":[{"comparisonValue":"down-sig","trendDirection":5,"symbol":"rgba(49, 163, 84,1)","label":"Better, significant","unit":null},{"comparisonValue":"down","trendDirection":4,"symbol":"rgba(186, 228, 179,1)","label":"Better, not significant","unit":null},{"comparisonValue":"equal","trendDirection":3,"symbol":"rgba(189, 215, 231,1)","label":"No change","unit":null},{"comparisonValue":"up","trendDirection":2,"symbol":"rgba(252, 174,145,1)","label":"Worse, not significant","unit":null},{"comparisonValue":"up-sig","trendDirection":1,"symbol":"rgba(232, 45, 38,1)","label":"Worse, significant","unit":null}],"localeIdList":"2276,2274"}}},"usesZCTA":1},"13":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"315":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"347":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"277":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"529":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"393":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"343":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"2365":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":0},"411":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1}},
2453    mapcolWidth     : '8',
2454    currentBasemap  : 'osm',
2455    comparison      : "6823",
2456    zoomToLocation  : 1,
2457	showTimeline  : false,
2458	timeline: {}
2459});
2460
2461} 
2462
2463</script>
2463
2464<div class="row">
2465    <div class="col-12 col-md-8 order-2">
2466        <div class="text-center indicatorLocale">
2467            <a class="strong map_location indicatorLink" href="/indicators/index/view?indicatorId=240&localeId=2274">
2468                County                : Jackson</a>
2469        </div>
2470    </div>
2471    <div class="col-12 col-md-4 order-md-1 d-none d-md-block">
2472    </div>
2473    <div class="col-12 col-md-4 indicator_column order-1 order-md-3" id="indmap_indcol_tileinstanceid_301993011390254111">
2474        <h3>Social Determinants of Health in Jackson County</h3>
2475        <p>Use the dropdown menu to see indicators relating to the economy, education, housing, transportation and more!</p>        <select name="indicators" id="indicators_select_301993011390254111" aria-label="Select an Indicator"><option value="29" >8th Grade Students Proficient in Math</option><option value="30" >8th Grade Students Proficient in Reading</option><option value="340" >People 25+ with a Bachelors Degree or Higher</option><option value="189" >Children Living Below Poverty Level</option><option value="240" selected="selected">Families Living Below Poverty Level</option><option value="13" >High School Graduation</option><option value="315" >Median Household Income</option><option value="347" >People Living Below Poverty Level</option><option value="277" >Households with Cash Public Assistance Income</option><option value="529" >Workers Commuting by Public Transportation</option><option value="393" >Renters Spending 30% or More of Household Income on Rent</option><option value="343" >People 65+ Living Below Poverty Level</option><option value="2365" >Severe Housing Problems</option><option value="411" >Children in Single-Parent Households</option></select>        <div class="indicator_container">
2476                        <div class="gauge_value_container">
2477    <div class="value_unit">
2478        <span class="value">7.7%</span>
2479    </div>
2480    <div class="gauge ml-1">
2481        	    <p class="comparison-default left text-center comparison htmlTooltip " title="Ranked by value">
2482            <a href="#" data-index="default"><img src="/content/global/application/indicators/gauges/jenks-1.png" alt="Ranked " /><br />
2483            Ranked</a>
2484	    </p>
2485        	    <p class="comparison-6823 left text-center comparison htmlTooltip active" title="The distribution is based on data from 36 Oregon counties.">
2486            <a href="#" data-index="6823"><img src="/content/global/application/indicators/gauges/gauge-dist-60.png" alt="OR Counties " /><br />
2487            OR Counties</a>
2488	    </p>
2489        	    <p class="comparison-6865 left text-center comparison htmlTooltip " title="The distribution is based on data from 3,133 U.S. counties and county equivalents.">
2490            <a href="#" data-index="6865"><img src="/content/global/application/indicators/gauges/gauge-dist-60.png" alt="U.S. Counties " /><br />
2491            U.S. Counties</a>
2492	    </p>
2493        	    <p class="comparison-7203 left text-center comparison htmlTooltip " title="The regional value is compared to the Oregon State value.">
2494            <a href="#" data-index="7203"><img src="/content/global/application/indicators/gauges/other-higher-bad.png" alt="OR Value " /><br />
2495            OR Value</a>
2496	    </p>
2497        	    <p class="comparison-7227 left text-center comparison htmlTooltip " title="The regional value is compared to the national value.">
2498            <a href="#" data-index="7227"><img src="/content/global/application/indicators/gauges/other-lower-good.png" alt="US Value " /><br />
2499            US Value</a>
2500	    </p>
2501        	    <p class="comparison-927 left text-center comparison htmlTooltip " title="This comparison measures the indicator’s values over multiple time periods.&lt;br&gt;The Mann-Kendall Test for Statistical Significance is used to evaluate the trend&lt;br&gt;over 4 to 10 periods of measure, subject to data availability and comparability.">
2502            <a href="#" data-index="927"><img src="/content/global/application/indicators/gauges/trend-down-sig-good.png" alt="Trend " /><br />
2503            Trend</a>
2504	    </p>
2505            </div>
2506</div>
2507<div class="indicator_explain">
2508	<div>This indicator shows the percentage of families living below the federal poverty level. <span>
2508Families are households where two or more people are related by birth, marriage, or adoption.</span></div></div>
2509<div class="padding-y-15">
2510    <a href="/indicators/index/view?indicatorId=240&amp;localeId=2274" class="ribbon-link indicatorLink">Learn More</a></div>        </div>
2511    </div>
2512    <div class="col-12 col-md-8 order-3 order-md-4" id="indmap_mapcol_tileinstanceid_301993011390254111">
2513        <div class="map_column">
2514            <div id="map_301993011390254111" class="map_container">
2515                <div id="" class="mapOptionsContainer">
2516                <a href="#" id="toggleLabelstileinstanceid_301993011390254111" title="Labels Off/On" class="tooltip"><span class="visually-hidden">Labels Off/On</span><i class="fa fa-info map-option-icon"></i></a>
2517            <a href="#" id="toggleStreetsBaseLayertileinstanceid_301993011390254111" title="Background Map: Detailed/Simple/None" class="tooltip"><span class="visually-hidden">Background Map: Detailed/Simple/None</span><i class="fa fa-road map-option-icon"></i></a>
2518            <a href="#" id="toggleMapTransparencytileinstanceid_301993011390254111" title="Transparency Off/On" class="tooltip"><span class="visually-hidden">Transparency Off/On</span><i class="fa fa-adjust map-option-icon"></i></a>
2519    </div>
2520
2521 
2522                
2522<script>
2523                    // This code is shared among various places where map options (originally exporting) are provided:
2524// SocioNeeds Index, Demographics view, Indicator view, etc.
2525        $('#toggleLabels'+'tileinstanceid_301993011390254111').on('click', function(event) {
2526            event.preventDefault();
2527            if ('indmaptile' == 'mapnav') {
2528                var mapnav_map = mapnav_globals.maps['map_301993011390254111'];
2529                mapnav_map.featureLayer.setShowLabels(!mapnav_map.featureLayer.showLabels);
2530            } else if ('indmaptile' == 'indmaptile') {
2531                map_tiles.tiles['tileinstanceid_301993011390254111'].currentLayer.setShowLabels(!map_tiles.tiles['tileinstanceid_301993011390254111'].currentLayer.showLabels);
2532            } else {
2533                if (globals.current != undefined) { // socioneeds stores current fl differently
2534                    globals.featureLayers[globals.current.fl].setShowLabels(!globals.featureLayers[globals.current.fl].showLabels);
2535                }
2536                else {
2537                    globals.currentFl.setShowLabels(!globals.currentFl.showLabels);
2538                }
2539            }
2540        });
2541        
2542        // basemap toggles
2543        // the 'none' basemap is added via HCI_Gis::getMapSymbols()
2544        var HCIBasemaps = ["osm","gray","none"];
2545
2546        $('#toggleStreetsBaseLayer'+'tileinstanceid_301993011390254111').on('click', function(event) {
2547            event.preventDefault();
2548            if ('indmaptile' == 'mapnav') {
2549                var mapdata = mapnav_globals.maps['map_301993011390254111'];
2550            } else if ('indmaptile' == 'indmaptile') {
2551                var mapdata = map_tiles.tiles['tileinstanceid_301993011390254111'];
2552            } else {
2553                var mapdata = globals;
2554            }
2555            if (mapdata.map == undefined) {
2556                return;
2557            }
2558            var bmIndex = $.inArray(mapdata.map.getBasemap(), HCIBasemaps);
2559            var newIndex = (bmIndex < HCIBasemaps.length-1 && bmIndex > -1) ? bmIndex + 1 : 0;
2560            mapdata.currentBasemap = HCIBasemaps[newIndex];
2561            mapdata.map.setBasemap(mapdata.currentBasemap);
2562        });
2563
2564        $('#toggleMapTransparency'+'tileinstanceid_301993011390254111').on('click', function(event) {
2565            event.preventDefault();
2566            if ('indmaptile' == 'indmaptile') {
2567                var transparency = map_tiles.tiles['tileinstanceid_301993011390254111'].transparency;
2568                var currentLayer = map_tiles.tiles['tileinstanceid_301993011390254111'].currentLayer;
2569                var map = map_tiles.tiles['tileinstanceid_301993011390254111'].map;
2570                if (transparency == 'off' || transparency == undefined) {
2571                    map_tiles.tiles['tileinstanceid_301993011390254111'].transparency = 'on';
2572                    currentLayer.setOpacity(0.0);
2573                    addBoundaryOutlines(map, currentLayer, 
2574                                        map_tiles.defaults.highlightSymbols, 
2575                                        map_tiles.tiles['tileinstanceid_301993011390254111'].currentLocaleId);
2576                } else {
2577                    map_tiles.tiles['tileinstanceid_301993011390254111'].transparency = 'off';
2578                    currentLayer.setOpacity(0.85);
2579                    removeBoundaryOutlines(map, currentLayer);
2580                }
2581            } else if ('indmaptile' == 'mapnav') {
2582                var mapdata = mapnav_globals.maps['map_301993011390254111'];
2583                var transparency = mapdata.transparency;
2584                var currentLayer = mapdata.featureLayer;
2585                var map = mapdata.map;
2586
2587                if (transparency == 'off' || transparency == undefined) {
2588                    mapdata.transparency = 'on';
2589                    currentLayer.setOpacity(0.0);
2590                    addBoundaryOutlines(map, currentLayer, mapnav_globals.highlightSymbols);
2591                } else {
2592                    mapdata.transparency = 'off';
2593                    currentLayer.setOpacity(0.85);
2594                    removeBoundaryOutlines(map, currentLayer);
2595                }
2596            } else if ('indmaptile' == 'index') { // SNI, FII, etc
2597                if (globals.transparency == 'off' || globals.transparency == undefined) {
2598                    addBoundaryOutlines(globals.map, globals.map.getLayer('breaksGL'),
2599                                        globals.highlightSymbols, globals.currentLocaleId);
2600                    globals.transparency = 'on';
2601                }
2602                else {
2603                    globals.transparency = 'off';
2604                    removeBoundaryOutlines(globals.map, globals.map.getLayer('breaksGL'));
2605                    globals.featureLayers[globals.current.fl].refresh();
2606                }
2607                clearBreaksGraphics();
2608                setBreaksGraphics();
2609            } else if ('indmaptile' == 'indicator') {
2610                if (globals.transparency == 'off' || globals.transparency == undefined) {
2611                    globals.transparency = 'on';
2612                    globals.currentFl.setOpacity(0.0);
2613                    addBoundaryOutlines(globals.map, globals.currentFl, globals.highlightSymbols);
2614                } else {
2615                    globals.transparency = 'off';
2616                    globals.currentFl.setOpacity(0.85);
2617                    removeBoundaryOutlines(globals.map, globals.currentFl);
2618                }
2619            } else if ('indmaptile' == 'demographics') {
2620                if (globals.transparency == 'off' || globals.transparency == undefined) {
2621                    globals.transparency = 'on';
2622                }
2623                else {
2624                    globals.transparency = 'off';
2625                }
2626                clearDemBreaksGraphics();
2627                setDemBreaksGraphics();
2628            }
2629        });
2630
2631        $('#requestBigMap'+'tileinstanceid_301993011390254111').on('click', function(event) {
2632            event.preventDefault();
2633
2634            if ('indmaptile' == 'indmaptile') {
2635                toggleIndMapLayout('tileinstanceid_301993011390254111');
2636            } else {
2637                toggleMapChartLayout();
2638            }
2639        });
2640
2641        // Export map. First retrieve the map image from the server. Then create a div with the
2642        // needed meta data (ind name, comparison, etc) and insert it into the dom. Then use html2canvas 
2643        // to create an image of the div, which is what the final export is.
2644        $(".saveMap").on('click', function(event) {
2645            event.preventDefault();
2646            exportMap();
2647        });
2648        
2649        function exportMap() {
2650            var loading = '<img src="/content/global/application/spinner.gif" title="Loading..." alt="Loading..." />';
2651            var dialog = $('<div title="Exporting Map..."><p>Please wait while we prepare the map for export. This could take up to a minute.</p><p class="text-center small">' + loading + '</p></div>');
2652            dialog.dialog({modal: true});
2653            var params = new PrintParameters();
2654            var template = new PrintTemplate();
2655            template.exportOptions = {
2656                width: 800,
2657                height: 600,
2658                dpi: 150
2659            };
2660            template.format = 'PNG32';
2661            template.preserveScale = false;
2662            params.map = globals.map;
2663            params.template = template;
2664            var printTask = new PrintTask('https://hcimaps01.thehcn.net/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task', { async: false });
2665
2666            var printMap = printTask.execute(params); // deferred, returns url of map image
2667            printMap.then(function(resp) {
2668                var exp = $('.spoofMap').clone();
2669                exp.attr('id', 'spoofMap');
2670
2671                var subtitle = '';
2672                if (globals.current != undefined) { // index views store current fl differently
2673                    subtitle = globals.current.localeTypeName;
2674                    if (globals.current.localeName != '') {
2675                        subtitle = subtitle + ': ' + globals.current.localeName;
2676                    }
2677                } else {
2678                    subtitle = globals.currentLocaleTypeName;
2679                    if (globals.currentLocaleName != '') {
2680                        subtitle = subtitle + ': ' + globals.currentLocaleName;
2681                    }
2682                }
2683                exp.find('.subtitle').html(subtitle);
2684                // comparison info
2685                if (globals.currentComparisonName != '') {
2686                    var compStr = globals.currentComparisonName;
2687                    if (globals.currentLocaleId > 0) { // locale specific
2688                        if (globals.currentComparisonType == 2) { // prior value is handled differently
2689                            var priorValue = { periodId: 0 };
2690                            var currentValue = {};
2691                            var period = globals.periods[globals.periodId];
2692                            var localeDetails = globals.localeTypes[globals.currentLocaleTypeId]['localeDetails'][globals.currentLocaleId];
2693                            var priorValues = localeDetails['priorValues'];
2694                            for (var key in priorValues) {
2695                                var pv = priorValues[key];
2696                                if (pv.periodId == globals.periodId) {
2697                                    currentValue = pv;
2698                                    continue;
2699                                }
2700                                if (pv.periodId > globals.periodId || pv.periodId <= priorValue.periodId) {
2701                                    continue;
2702                                }
2703                                priorValue = pv;
2704                            }
2705                            compStr = '<strong>' + globals.currentLocaleName + ' Value for ' + currentValue.period + '</strong>: ' + currentValue.valueFmt;
2706                            compStr += '<br /><strong>' + globals.currentLocaleName + ' Value for ' + priorValue.period + '</strong>: ' + priorValue.valueFmt;
2707                            exp.find('.comparison').html(compStr);
2708                            exp.find('.measurementPeriod').remove(); // redundant
2709                        }
2710                        else {
2711                            compStr = $('.idet-comparison-selected .comparisonName').clone();
2712                            if (compStr.length > 0) {
2713                                compStr.find('br').remove();
2714                                compStr = compStr.html();
2715                            }
2716                            else {
2717                                compStr = 'N/A';
2718                            }
2719                            exp.find('.comparison_name').html(compStr);
2720							exp.find('.measurementPeriod').remove(); // redundant
2721                        }
2722                    }
2723                    else { // locale agnostic
2724                        exp.find('.comparison_name').html(compStr);
2725                    }
2726                }
2727                else {
2728                    exp.find('.comparison').remove();
2729                }
2730                // locale specific value info
2731                if (globals.currentLocaleId > 0) {
2732                    if (globals.currentComparisonType != 2 && globals.currentComparisonType != 4) {
2733                        exp.find('.currentLocaleValue').html(globals.currentLocaleName + ' Value for ' + globals.periods[globals.periodId]);
2734                        exp.find('.currentValue').html($('.idet-value-block-value').html());
2735                    }
2736                    else {
2737                        var valStr = $('.idet-comparison-selected').attr('title');
2738                        $(valStr).children('div').remove(); // just the first line (no technical note)
2739                        valStr = '<strong>' + $(valStr).html() + '</strong>';
2740                        exp.find('.currentValueContainer').html(valStr);
2741                        if (globals.currentComparisonType == 4) {
2742                            exp.find('.comparison').remove();
2743                        }
2744                    }
2745                }   
2746                else {
2747                    exp.find('.currentValueContainer').remove();
2748                }   
2749                var img = new Image();
2750                img.crossOrigin = 'Anonymous'; // necessary in order for html2canvas to properly retrieve the img
2751                img.src = resp.url;
2752                exp.find('.map_image').append(img);
2753                exp.find('.mapExportLegend').append($('.mapLegendWrapper').filter(":visible").get(0).outerHTML);
2754                exp.removeClass('hidden-all');
2755                $('body').append(exp);
2756                var spoof = $('#spoofMap').get(0);
2757                var h2cOpts = {
2758                    background: '#fff',
2759                    useCORS: true,
2760                    scale: 2,
2761                    logging: false,
2762                    width: 840
2763                }
2764                // wait for the external image to load before attempting to grab the div
2765                // this helps to prevent blank images on Safari (Chrome & FF seem to do the right thing)
2766                img.onload = function() {
2767                    html2canvas(spoof, h2cOpts).then(function(canvas) {
2768                        var filename = ".jpg";
2769                        if (navigator.userAgent.indexOf("MSIE ") > 0 || navigator.userAgent.match(/Trident.*rv\:11\./)) { // download attribute not supported in IE<=11
2770                            var blob = canvas.msToBlob();
2771                            window.navigator.msSaveBlob(blob, filename);
2772                            finishExport(dialog);
2773                        }
2774                        else {
2775                            var a = $('.saveMapSpoof').get(0);
2776                            var src = canvas.toDataURL('image/jpeg', 1);
2777                            a.href = src;
2778                            a.download = filename;
2779                            a.click();
2780                            finishExport(dialog);   
2781                        }
2782                    });
2783                };
2784            }, // printTask.then..
2785            function(err) {
2786                dialog.dialog('destroy');
2787                var errdialog = $('<div title="Error Exporting Map"><p>An error occurred while preparing the map for export. Please try again.</p></div>');
2788                errdialog.dialog({modal: true});
2789                console.log('An error occurred processing the print request:');
2790                console.log(err);
2791            },
2792            function(update) {
2793                console.log('Update from the print task:');
2794                console.log(update);
2795            });
2796        }
2797
2798        // after downloading map, remove the spoofMap div and remove the dialog
2799        function finishExport(dialog) {
2800            $('#spoofMap').remove();
2801            dialog.dialog('destroy');
2802        }
2803
2804        function clearBreaksGraphics() {
2805            if (globals.map.getLayer('breaksGL') != undefined) {
2806                globals.map.getLayer('breaksGL').clear();
2807                globals.featureLayers[globals.current.fl].graphics.forEach(function(g, idx) {
2808                    if (g.attributes != undefined && globals.current.localeIds.indexOf(g.attributes.localeId) > -1) {  
2809                        var polygon = new esri.geometry.Polygon(g.geometry.spatialReference);
2810                        var rings = g.geometry.rings;
2811                        for (var r=0, rl=rings.length; r<rl; r++) {
2812                            polygon.addRing(rings[r]);
2813                        }
2814
2815                        var symColor = new dojo.Color([245,245,245]);
2816                        symColor.a = 0.1;
2817
2818                        var sym = new SimpleFillSymbol('solid',
2819                                                       new SimpleLineSymbol(
2820                                                           SimpleLineSymbol.STYLE_SOLID,
2821                                                           new dojo.Color([50,50,50]),
2822                                                           .8
2823                                                       ),
2824                                                       symColor);
2825
2826                        g.setSymbol(sym);
2827                    }
2828                });
2829            } else {
2830                return;
2831            }
2832        }
2833
2834        function setBreaksGraphics() {
2835
2836            if (
2837                (globals.transparency == 'on') ||
2838                (globals.map.getLayer('breaksGL') == undefined) || 
2839                (globals.renderer == undefined || globals.renderer.infos.length < 1) ||
2840                (globals.featureLayers[globals.current.fl].graphics.length == 0)
2841            ) {
2842                return;
2843            }
2844
2845            clearBreaksGraphics();
2846
2847            globals.featureLayers[globals.current.fl].graphics.forEach(function(g, idx) {
2848                if (g.attributes != undefined && globals.current.localeIds.indexOf(g.attributes.localeId) > -1) {  
2849                    var polygon = new esri.geometry.Polygon(g.geometry.spatialReference);
2850                    var rings = g.geometry.rings;
2851                    for (var r=0, rl=rings.length; r<rl; r++) {
2852                        polygon.addRing(rings[r]);
2853                    }
2854
2855                    var breaks = globals.breaks;
2856                    var val = g.attributes[globals.indicator];
2857                    for (b in breaks) {
2858                        var min = parseFloat(breaks[b][0]);
2859                        var max = parseFloat(breaks[b][1]);
2860                        if ((b*1) + 1 == breaks.length) {
2861                            max += .01; // pad topmost since it uses <= for some reason
2862                        }
2863                        if (b == 0) {
2864                            min -= .01;
2865                        }
2866                        if (min < val && val <= max) {
2867                            if (globals.renderer.infos.length == 1) {
2868                                var symColor = new dojo.Color(globals.grayColor);
2869                            }
2870                            else {
2871                                var symColor = new dojo.Color(globals.legendColors[b].replace(/[rgb\(\)]/g, '').split(',')); 
2872                                if (globals.transparency == 'off' || globals.transparency == undefined) {
2873                                    symColor.a = 0.85;
2874                                }
2875                                else {
2876                                    symColor.a = 0.0;
2877                                }
2878                            }
2879                        }
2880                    }
2881                    var sym = new SimpleFillSymbol('solid',
2882                                                   new SimpleLineSymbol(
2883                                                       SimpleLineSymbol.STYLE_SOLID,
2884                                                       new dojo.Color([50,50,50]),
2885                                                       .8
2886                                                   ),
2887                                                   symColor);
2888                    var graphic = new esri.Graphic(polygon, sym);
2889
2890                    graphic.attributes = {localeId: g.attributes.localeId, location: g.attributes.location};
2891                    graphic.attributes[globals.indicator] = g.attributes[globals.indicator];
2892                    globals.map.getLayer('breaksGL').add(graphic);
2893                }
2894            });
2895        }
2896
2897        function addBoundaryOutlines(map, layer, symbols, currentLocaleId) {
2898            if (layer) {
2899                layer.graphics.forEach(function(g) {
2900                    var polygon = new esri.geometry.Polygon(g.geometry.spatialReference);
2901                    var rings = g.geometry.rings;
2902                    for (var r=0, rl=rings.length; r<rl; r++) {
2903                        polygon.addRing(rings[r]);
2904                    }
2905                    if (currentLocaleId != g.attributes.localeId) {
2906                        // Symbol having fill color prevents tooltip display.
2907                        // var graphic = new esri.Graphic(polygon, symbols['localeOutline']);
2908                        var graphic = new esri.Graphic(polygon, symbols['localeOutlineNullFill']);
2909                    } else  {
2910                        var graphic = new esri.Graphic(polygon, symbols['select']);
2911                    }
2912                    graphic.id = 'localeoutline';
2913                    map.graphics.add(graphic);
2914                    return;
2915                });
2916            }
2917        }
2918
2919        function removeBoundaryOutlines(map, layer) {
2920            if (layer) {
2921                clearMapGraphics(map, 'localeoutline');
2922            }
2923        }
2924
2925        function clearMapGraphics(map, id) {
2926            if (map && map.gra
2926phics) {
2927                var outlines = [];
2928                map.graphics.graphics.forEach(function(g) {
2929                    if (g && g.id == id) {
2930                        outlines.push(g);
2931                    }
2932                });
2933                outlines.forEach(function(g) {
2934                    map.graphics.remove(g);
2935                });
2936            }
2937        }                </script>
2937
2938
2939                <div class="mapLegend" id="map_301993011390254111_mapLegend" style="display: none;"></div>
2940                <div class="location_unavailable error box" style="display:none;">
2941                    <a href="#" class="close right" aria-label="Close"><i class="fa fa-close" title="Close" aria-hidden="true"></i></a>
2942                    Mapping is not available at the selected location
2943                </div>
2944            </div>
2945			<!-- Requirement 2238139: GIS: Multiple Time Periods on a Map START -->	
2946			
2946<script>
2947map_tiles.tiles.tileinstanceid_301993011390254111.timeline.allPeriodsData=null;
2948map_tiles.tiles.tileinstanceid_301993011390254111.timeline.currentLocaleTypeId=2;
2949map_tiles.tiles.tileinstanceid_301993011390254111.timeline.localeId=2274;
2950map_tiles.tiles.tileinstanceid_301993011390254111.timeline.indicatorId=240;
2951map_tiles.tiles.tileinstanceid_301993011390254111.timeline.initialPeriodId = 11479;
2952map_tiles.tiles.tileinstanceid_301993011390254111.timeline.periodId = 11479;
2953map_tiles.tiles.tileinstanceid_301993011390254111.timeline.defaultComparison = '6823';
2954map_tiles.tiles.tileinstanceid_301993011390254111.timeline.currentComparisonId = '6823';
2955map_tiles.tiles.tileinstanceid_301993011390254111.timeline.hideDescription = '';
2956console.log('set timeline values - showTimeline='+map_tiles.tiles.tileinstanceid_301993011390254111.showTimeline);
2957activeTile = window["map_tiles.tiles.tileinstanceid_301993011390254111"];
2958$(function () {
2959    $('.loadingIcon').hide();
2960});
2961</script>
2961
2962
2963<div id="timelineDiv_map_301993011390254111" class="timelineDiv" style="position: relative;">
2964
2965  <div class="timeline-loading-icon" style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 100;">
2966        <img src="/content/global/application/spinner.gif" alt="Loading...">
2967  </div>
2968	
2969  <div class="slider-container timeline-click-msg">
2970    <button class="play-button enableTimeline" data-map-id="map_301993011390254111">
2971      <i>▶</i> Play
2972    </button>
2973    <div class="timelineMsg">&nbsp;&nbsp;Click Play button to show timeline.</div>
2974  </div>
2975
2976  <div class="slider-container time-slider-container" style="display:none;">
2977      <button class="play-button playTimeline">
2978        <i>▶</i> Play
2979      </button>
2980	  <span class="slider-title">Timeline:</span>
2981	  <div class="slider-wrapper">
2982		<input type="range" min="0" max="10" value="0" step="1" class="slider" id="timeSlider" list="markers" >
2983		<datalist id="markers"></datalist>
2984		<div class="slider-marks"></div>	
2985	  </div>
2986	</div>
2987</div>
2988
2989			<!-- Requirement 2238139: GIS: Multiple Time Periods on a Map END -->	
2990            <div class="text-center indicatorSource">
2991                <div class="indicatorTitle">
2992                    <a href="/indicators/index/view?indicatorId=240&localeId=2274" class="strong map_indicator indicatorLink">Families Living Below Poverty Level</a>
2993                </div>
2994                <div class="small">
2995                    Data Source: <span class="sourceTitle">American Community Survey 5-Year</span>
2996                </div>
2997            </div>
2998        </div>
2999    </div>
3000</div>
3001<img src="/content/global/application/spinner.gif" class="loading" alt="Loading, please wait" />
3002    </section>
3003</div>
3004
3005<div id="tileinstanceid_301995966718623164" class="hci-v2 main-content tileinstance tileinstance_indicatormap bkgd-dark white_indicator_explain hide-first-comparison-gauge">
3006    <section>
3007    
3007<script type="text/javascript">
3008    
3009    $(document).ready(function() {
3010        var baseTarget = (document.getElementById("baseAttributes") && document.getElementById("baseAttributes").target) ? document.getElementById("baseAttributes").target : '_self';
3011    	map_tiles.init();
3012    	for (containerId in map_tiles.tiles) {
3013    		var tile = map_tiles.tiles[containerId];
3014        	var id = (tile.type == 'indicators') ? tile.indicatorId : tile.localeId;
3015			
3016			//Add checking if select elements exists
3017			var $selectElement = $('#' + containerId + ' select');
3018			if ( $selectElement.length ) {
3019				var val = $('#' + containerId + ' select').val();
3020				if (val != id) { // back button navigation, browser remembers selected opt
3021					if (tile.type == 'indicators') {
3022						tile.indicatorId = $('#' + containerId + ' select').val();
3023					}
3024					if (tile.type == 'locations') {
3025						tile.localeId = $('#' + containerId + ' select').val();
3026						tile.localeTypeId = $('#' + containerId + ' select option:selected').parent('optgroup').prop('id').split('_')[1]; // select_[localeTypeId]
3027					}
3028					$('#' + containerId + ' select').trigger('change');
3029				}
3030			}	
3031    	}
3032    	$('.close').on('click', function (e) {
3033        	e.preventDefault();
3034            $(this).parent('.location_unavailable').fadeOut();
3035    	});
3036    });
3037
3038
3039function recenterMap(indmap) {
3040    indmap.setExtent(indmap.viewExtent, true);
3041}
3042
3043var showInd='1';
3044console.log('showIndicator for map_301995966718623164='+showInd);
3045
3046if(showInd == '1' || showInd == 'true') { 
3047
3048// set data for this tile instance
3049map_tiles.addTile('tileinstanceid_301995966718623164',{
3050    id              : 'tileinstanceid_301995966718623164',
3051    mapId           : 'map_301995966718623164',
3052    type            : 'indicators',
3053    localeId        : '2276',
3054    localeTypeId    : '2',
3055    localeTypes     : [2],
3056    indicatorId     : '240',
3057    data	        : {"locales":{"2274":"Jackson","2276":"Josephine"},"29":{"values":{"2":{"2274":"19.4","2276":"29.6"}},"trends":{"2":{"2274":4,"2276":4}},"priorValues":{"2":{"2274":1,"2276":1}},"renderers":{"2":{"default":{"comparisonTypeId":"default","breaks":[{"value":19.39999999999999857891452847979962825775146484375,"label":"19.4%","symbol":"rgba(49,130,189,1)","unit":"percent"},{"value":29.60000000000000142108547152020037174224853515625,"label":"29.6%","symbol":"rgba(189,215,231,1)","unit":"percent"}],"localeIdList":[2274,2276]},"6823":{"comparisonTypeId":1,"breaks":[{"minValue":"-Infinity","maxValue":17.699999999999999289457264239899814128875732421875,"symbol":"rgba(232, 45, 38,1)","label":"Worst Quarter<br \/>&lt; 17.7%","unit":"percent"},{"minValue":17.699999999999999289457264239899814128875732421875,"maxValue":22.5,"symbol":"rgba(215, 215, 6,1)","label":"2nd Worst Quarter<br \/>17.7% - 22.5%","unit":"percent"},{"minValue":22.5,"maxValue":"Infinity","symbol":"rgba(49, 163, 84,1)","label":"Best 50%<br \/>&gt; 22.5%","unit":"percent"}],"localeIdList":"2274,2276"},"7203":{"comparisonTypeId":0,"breaks":[{"minValue":"-Infinity","maxValue":26.398999999999997356781022972427308559417724609375,"symbol":"rgba(232, 45, 38,1)","label":"&lt; 26.4%","unit":"percent"},{"minValue":26.398999999999997356781022972427308559417724609375,"maxValue":26.400999999999999801048033987171947956085205078125,"symbol":"rgba(49, 130, 189,1)","label":"= 26.4%","unit":"percent"},{"minValue":26.39999999999999857891452847979962825775146484375,"maxValue":"Infinity","symbol":"rgba(49, 163, 84,1)","label":"&gt; 26.4%","unit":"percent"}],"localeIdList":"2274,2276"},"923":{"comparisonTypeId":2,"breaks":[{"comparisonValue":"trend-down-bad","priorValueDirection":2,"symbol":"rgba(232, 45, 38,1)","label":"Decreased\/worsened","unit":null},{"comparisonValue":"trend-equal-neutral","priorValueDirection":3,"symbol":"rgba(189, 215, 231,1)","label":"No significant change","unit":null},{"comparisonValue":"trend-up-good","priorValueDirection":1,"symbol":"rgba(49, 163, 84,1)","label":"Increased\/improved","unit":null}],"localeIdList":"2274,2276"},"927":{"comparisonTypeId":4,"breaks":[{"comparisonValue":"down-sig","trendDirection":5,"symbol":"rgba(232, 45, 38,1)","label":"Worse, significant","unit":null}
3057,{"comparisonValue":"down","trendDirection":4,"symbol":"rgba(252, 174,145,1)","label":"Worse, not significant","unit":null},{"comparisonValue":"equal","trendDirection":3,"symbol":"rgba(189, 215, 231,1)","label":"No change","unit":null},{"comparisonValue":"up","trendDirection":2,"symbol":"rgba(186, 228, 179,1)","label":"Better, not significant","unit":null},{"comparisonValue":"up-sig","trendDirection":1,"symbol":"rgba(49, 163, 84,1)","label":"Better, significant","unit":null}],"localeIdList":"2274,2276"}}},"usesZCTA":1},"30":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"340":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"189":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"240":{"values":{"2":{"2274":"7.7","2276":"11.1"}},"trends":{"2":{"2274":5,"2276":5}},"priorValues":{"2":{"2274":3,"2276":3}},"renderers":{"2":{"default":{"comparisonTypeId":"default","breaks":[{"value":7.70000000000000017763568394002504646778106689453125,"label":"7.7%","symbol":"rgba(189,215,231,1)","unit":"percent"},{"value":11.0999999999999996447286321199499070644378662109375,"label":"11.1%","symbol":"rgba(49,130,189,1)","unit":"percent"}],"localeIdList":[2274,2276]},"6823":{"comparisonTypeId":1,"breaks":[{"minValue":"-Infinity","maxValue":8.5999999999999996447286321199499070644378662109375,"symbol":"rgba(49, 163, 84,1)","label":"Best  50%<br \/>&lt; 8.6%","unit":"percent"},{"minValue":8.5999999999999996447286321199499070644378662109375,"maxValue":10.4000000000000003552713678800500929355621337890625,"symbol":"rgba(215, 215, 6,1)","label":"2nd Worst Quarter<br \/>8.6% - 10.4%","unit":"percent"},{"minValue":10.4000000000000003552713678800500929355621337890625,"maxValue":"Infinity","symbol":"rgba(232, 45, 38,1)","label":"Worst Quarter<br \/>&gt; 10.4%","unit":"percent"}],"localeIdList":"2276,2274"},"6865":{"comparisonTypeId":1,"breaks":[{"minValue":"-Infinity","maxValue":9.0999999999999996447286321199499070644378662109375,"symbol":"rgba(49, 163, 84,1)","label":"Best  50%<br \/>&lt; 9.1%","unit":"percent"},{"minValue":9.0999999999999996447286321199499070644378662109375,"maxValue":12.699999999999999289457264239899814128875732421875,"symbol":"rgba(215, 215, 6,1)","label":"2nd Worst Quarter<br \/>9.1% - 12.7%","unit":"percent"},{"minValue":12.699999999999999289457264239899814128875732421875,"maxValue":"Infinity","symbol":"rgba(232, 45, 38,1)","label":"Worst Quarter<br \/>&gt; 12.7%","unit":"percent"}],"localeIdList":"2276,2274"},"7203":{"comparisonTypeId":0,"breaks":[{"minValue":"-Infinity","maxValue":7.49899999999999966604491419275291264057159423828125,"symbol":"rgba(49, 163, 84,1)","label":"&lt; 7.5%","unit":"percent"},{"minValue":7.49899999999999966604491419275291264057159423828125,"maxValue":7.50100000000000033395508580724708735942840576171875,"symbol":"rgba(49, 130, 189,1)","label":"= 7.5%","unit":"percent"},{"minValue":7.50100000000000033395508580724708735942840576171875,"maxValue":"Infinity","symbol":"rgba(232, 45, 38,1)","label":"&gt; 7.5%","unit":"percent"}],"localeIdList":"2276,2274"},"7227":{"comparisonTypeId":0,"breaks":[{"minValue":"-Infinity","maxValue":8.7990000000000012647660696529783308506011962890625,"symbol":"rgba(49, 163, 84,1)","label":"&lt; 8.8%","unit":"percent"},{"minValue":8.7990000000000012647660696529783308506011962890625,"maxValue":8.8010000000000001563194018672220408916473388671875,"symbol":"rgba(49, 130, 189,1)","label":"= 8.8%","unit":"percent"},{"minValue":8.8010000000000001563194018672220408916473388671875,"maxValue":"Infinity","symbol":"rgba(232, 45, 38,1)","label":"&gt; 8.8%","unit":"percent"}],"localeIdList":"2276,2274"},"927":{"comparisonTypeId":4,"breaks":[{"comparisonValue":"down-sig","trendDirection":5,"symbol":"rgba(49, 163, 84,1)","label":"Better, significant","unit":null},{"comparisonValue":"down","trendDirection":4,"symbol":"rgba(186, 228, 179,1)","label":"Better, not significant","unit":null},{"comparisonValue":"equal","trendDirection":3,"symbol":"rgba(189, 215, 231,1)","label":"No change","unit":null},{"comparisonValue":"up","trendDirection":2,"symbol":"rgba(252, 174,145,1)","label":"Worse, not significant","unit":null},{"comparisonValue":"up-sig","trendDirection":1,"symbol":"rgba(232, 45, 38,1)","label":"Worse, significant","unit":null}],"localeIdList":"2276,2274"}}},"usesZCTA":1},"13":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"315":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"347":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"277":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"529":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"393":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"343":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1},"2365":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":0},"411":{"values":{"2":[]},"trends":{"2":[]},"priorValues":{"2":[]},"renderers":{"2":[]},"usesZCTA":1}},
3058    mapcolWidth     : '8',
3059    currentBasemap  : 'osm',
3060    comparison      : "6823",
3061    zoomToLocation  : 0,
3062	showTimeline  : false,
3063	timeline: {}
3064});
3065
3066} 
3067
3068</script>
3068
3069<div class="row">
3070    <div class="col-12 col-md-8 order-2">
3071        <div class="text-center indicatorLocale">
3072            <a class="strong map_location indicatorLink" href="/indicators/index/view?indicatorId=240&localeId=2276">
3073                County                : Josephine</a>
3074        </div>
3075    </div>
3076    <div class="col-12 col-md-4 order-md-1 d-none d-md-block">
3077    </div>
3078    <div class="col-12 col-md-4 indicator_column order-1 order-md-3" id="indmap_indcol_tileinstanceid_301995966718623164">
3079        <h3>Social Determinants of Health in Josephine County</h3>
3080        <p>Use the dropdown menu to see indicators relating to the economy, education, housing, transportation and more!</p>        <select name="indicators" id="indicators_select_301995966718623164" aria-label="Select an Indicator"><option value="29" >8th Grade Students Proficient in Math</option><option value="30" >8th Grade Students Proficient in Reading</option><option value="340" >People 25+ with a Bachelors Degree or Higher</option><option value="189" >Children Living Below Poverty Level</option><option value="240" selected="selected">Families Living Below Poverty Level</option><option value="13" >High School Graduation</option><option value="315" >Median Household Income</option><option value="347" >People Living Below Poverty Level</option><option value="277" >Households with Cash Public Assistance Income</option><option value="529" >Workers Commuting by Public Transportation</option><option value="393" >Renters Spending 30% or More of Household Income on Rent</option><option value="343" >People 65+ Living Below Poverty Level</option><option value="2365" >Severe Housing Problems</option><option value="411" >Children in Single-Parent Households</option></select>        <div class="indicator_container">
3081                        <div class="gauge_value_container">
3082    <div class="value_unit">
3083        <span class="value">11.1%</span>
3084    </div>
3085    <div class="gauge ml-1">
3086        	    <p class="comparison-default left text-center comparison htmlTooltip " title="Ranked by value">
3087            <a href="#" data-index="default"><img src="/content/global/application/indicators/gauges/jenks-2.png" alt="Ranked " /><br />
3088            Ranked</a>
3089	    </p>
3090        	    <p class="comparison-6823 left text-center comparison htmlTooltip active" title="The distribution is based on data from 36 Oregon counties.">
3091            <a href="#" data-index="6823"><img src="/content/global/application/indicators/gauges/gauge-dist-20.png" alt="OR Counties " /><br />
3092            OR Counties</a>
3093	    </p>
3094        	    <p class="comparison-6865 left text-center comparison htmlTooltip " title="The distribution is based on data from 3,133 U.S. counties and county equivalents.">
3095            <a href="#" data-index="6865"><img src="/content/global/application/indicators/gauges/gauge-dist-40.png" alt="U.S. Counties " /><br />
3096            U.S. Counties</a>
3097	    </p>
3098        	    <p class="comparison-7203 left text-center comparison htmlTooltip " title="The regional value is compared to the Oregon State value.">
3099            <a href="#" data-index="7203"><img src="/content/global/application/indicators/gauges/other-higher-bad.png" alt="OR Value " /><br />
3100            OR Value</a>
3101	    </p>
3102        	    <p class="comparison-7227 left text-center comparison htmlTooltip " title="The regional value is compared to the national value.">
3103            <a href="#" data-index="7227"><img src="/content/global/application/indicators/gauges/other-higher-bad.png" alt="US Value " /><br />
3104            US Value</a>
3105	    </p>
3106        	    <p class="comparison-927 left text-center comparison htmlTooltip " title="This comparison measures the indicator’s values over multiple time periods.&lt;br&gt;The Mann-Kendall Test for Statistical Significance is used to evaluate the trend&lt;br&gt;over 4 to 10 periods of measure, subject to data availability and comparability.">
3107            <a href="#" data-index="927"><img src="/content/global/application/indicators/gauges/trend-down-sig-good.png" alt="Trend " /><br />
3108            Trend</a>
3109	    </p>
3110            </div>
3111</div>
3112<div class="indicator_explain">
3113	<div>This indicator shows the percentage of families living below the federal poverty level. <span>
3113Families are households where two or more people are related by birth, marriage, or adoption.</span></div></div>
3114<div class="padding-y-15">
3115    <a href="/indicators/index/view?indicatorId=240&amp;localeId=2276" class="ribbon-link indicatorLink">Learn More</a></div>        </div>
3116    </div>
3117    <div class="col-12 col-md-8 order-3 order-md-4" id="indmap_mapcol_tileinstanceid_301995966718623164">
3118        <div class="map_column">
3119            <div id="map_301995966718623164" class="map_container">
3120                <div id="" class="mapOptionsContainer">
3121                <a href="#" id="toggleLabelstileinstanceid_301995966718623164" title="Labels Off/On" class="tooltip"><span class="visually-hidden">Labels Off/On</span><i class="fa fa-info map-option-icon"></i></a>
3122            <a href="#" id="toggleStreetsBaseLayertileinstanceid_301995966718623164" title="Background Map: Detailed/Simple/None" class="tooltip"><span class="visually-hidden">Background Map: Detailed/Simple/None</span><i class="fa fa-road map-option-icon"></i></a>
3123            <a href="#" id="toggleMapTransparencytileinstanceid_301995966718623164" title="Transparency Off/On" class="tooltip"><span class="visually-hidden">Transparency Off/On</span><i class="fa fa-adjust map-option-icon"></i></a>
3124    </div>
3125
3126 
3127                
3127<script>
3128                    // This code is shared among various places where map options (originally exporting) are provided:
3129// SocioNeeds Index, Demographics view, Indicator view, etc.
3130        $('#toggleLabels'+'tileinstanceid_301995966718623164').on('click', function(event) {
3131            event.preventDefault();
3132            if ('indmaptile' == 'mapnav') {
3133                var mapnav_map = mapnav_globals.maps['map_301995966718623164'];
3134                mapnav_map.featureLayer.setShowLabels(!mapnav_map.featureLayer.showLabels);
3135            } else if ('indmaptile' == 'indmaptile') {
3136                map_tiles.tiles['tileinstanceid_301995966718623164'].currentLayer.setShowLabels(!map_tiles.tiles['tileinstanceid_301995966718623164'].currentLayer.showLabels);
3137            } else {
3138                if (globals.current != undefined) { // socioneeds stores current fl differently
3139                    globals.featureLayers[globals.current.fl].setShowLabels(!globals.featureLayers[globals.current.fl].showLabels);
3140                }
3141                else {
3142                    globals.currentFl.setShowLabels(!globals.currentFl.showLabels);
3143                }
3144            }
3145        });
3146        
3147        // basemap toggles
3148        // the 'none' basemap is added via HCI_Gis::getMapSymbols()
3149        var HCIBasemaps = ["osm","gray","none"];
3150
3151        $('#toggleStreetsBaseLayer'+'tileinstanceid_301995966718623164').on('click', function(event) {
3152            event.preventDefault();
3153            if ('indmaptile' == 'mapnav') {
3154                var mapdata = mapnav_globals.maps['map_301995966718623164'];
3155            } else if ('indmaptile' == 'indmaptile') {
3156                var mapdata = map_tiles.tiles['tileinstanceid_301995966718623164'];
3157            } else {
3158                var mapdata = globals;
3159            }
3160            if (mapdata.map == undefined) {
3161                return;
3162            }
3163            var bmIndex = $.inArray(mapdata.map.getBasemap(), HCIBasemaps);
3164            var newIndex = (bmIndex < HCIBasemaps.length-1 && bmIndex > -1) ? bmIndex + 1 : 0;
3165            mapdata.currentBasemap = HCIBasemaps[newIndex];
3166            mapdata.map.setBasemap(mapdata.currentBasemap);
3167        });
3168
3169        $('#toggleMapTransparency'+'tileinstanceid_301995966718623164').on('click', function(event) {
3170            event.preventDefault();
3171            if ('indmaptile' == 'indmaptile') {
3172                var transparency = map_tiles.tiles['tileinstanceid_301995966718623164'].transparency;
3173                var currentLayer = map_tiles.tiles['tileinstanceid_301995966718623164'].currentLayer;
3174                var map = map_tiles.tiles['tileinstanceid_301995966718623164'].map;
3175                if (transparency == 'off' || transparency == undefined) {
3176                    map_tiles.tiles['tileinstanceid_301995966718623164'].transparency = 'on';
3177                    currentLayer.setOpacity(0.0);
3178                    addBoundaryOutlines(map, currentLayer, 
3179                                        map_tiles.defaults.highlightSymbols, 
3180                                        map_tiles.tiles['tileinstanceid_301995966718623164'].currentLocaleId);
3181                } else {
3182                    map_tiles.tiles['tileinstanceid_301995966718623164'].transparency = 'off';
3183                    currentLayer.setOpacity(0.85);
3184                    removeBoundaryOutlines(map, currentLayer);
3185                }
3186            } else if ('indmaptile' == 'mapnav') {
3187                var mapdata = mapnav_globals.maps['map_301995966718623164'];
3188                var transparency = mapdata.transparency;
3189                var currentLayer = mapdata.featureLayer;
3190                var map = mapdata.map;
3191
3192                if (transparency == 'off' || transparency == undefined) {
3193                    mapdata.transparency = 'on';
3194                    currentLayer.setOpacity(0.0);
3195                    addBoundaryOutlines(map, currentLayer, mapnav_globals.highlightSymbols);
3196                } else {
3197                    mapdata.transparency = 'off';
3198                    currentLayer.setOpacity(0.85);
3199                    removeBoundaryOutlines(map, currentLayer);
3200                }
3201            } else if ('indmaptile' == 'index') { // SNI, FII, etc
3202                if (globals.transparency == 'off' || globals.transparency == undefined) {
3203                    addBoundaryOutlines(globals.map, globals.map.getLayer('breaksGL'),
3204                                        globals.highlightSymbols, globals.currentLocaleId);
3205                    globals.transparency = 'on';
3206                }
3207                else {
3208                    globals.transparency = 'off';
3209                    removeBoundaryOutlines(globals.map, globals.map.getLayer('breaksGL'));
3210                    globals.featureLayers[globals.current.fl].refresh();
3211                }
3212                clearBreaksGraphics();
3213                setBreaksGraphics();
3214            } else if ('indmaptile' == 'indicator') {
3215                if (globals.transparency == 'off' || globals.transparency == undefined) {
3216                    globals.transparency = 'on';
3217                    globals.currentFl.setOpacity(0.0);
3218                    addBoundaryOutlines(globals.map, globals.currentFl, globals.highlightSymbols);
3219                } else {
3220                    globals.transparency = 'off';
3221                    globals.currentFl.setOpacity(0.85);
3222                    removeBoundaryOutlines(globals.map, globals.currentFl);
3223                }
3224            } else if ('indmaptile' == 'demographics') {
3225                if (globals.transparency == 'off' || globals.transparency == undefined) {
3226                    globals.transparency = 'on';
3227                }
3228                else {
3229                    globals.transparency = 'off';
3230                }
3231                clearDemBreaksGraphics();
3232                setDemBreaksGraphics();
3233            }
3234        });
3235
3236        $('#requestBigMap'+'tileinstanceid_301995966718623164').on('click', function(event) {
3237            event.preventDefault();
3238
3239            if ('indmaptile' == 'indmaptile') {
3240                toggleIndMapLayout('tileinstanceid_301995966718623164');
3241            } else {
3242                toggleMapChartLayout();
3243            }
3244        });
3245
3246        // Export map. First retrieve the map image from the server. Then create a div with the
3247        // needed meta data (ind name, comparison, etc) and insert it into the dom. Then use html2canvas 
3248        // to create an image of the div, which is what the final export is.
3249        $(".saveMap").on('click', function(event) {
3250            event.preventDefault();
3251            exportMap();
3252        });
3253        
3254        function exportMap() {
3255            var loading = '<img src="/content/global/application/spinner.gif" title="Loading..." alt="Loading..." />';
3256            var dialog = $('<div title="Exporting Map..."><p>Please wait while we prepare the map for export. This could take up to a minute.</p><p class="text-center small">' + loading + '</p></div>');
3257            dialog.dialog({modal: true});
3258            var params = new PrintParameters();
3259            var template = new PrintTemplate();
3260            template.exportOptions = {
3261                width: 800,
3262                height: 600,
3263                dpi: 150
3264            };
3265            template.format = 'PNG32';
3266            template.preserveScale = false;
3267            params.map = globals.map;
3268            params.template = template;
3269            var printTask = new PrintTask('https://hcimaps01.thehcn.net/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task', { async: false });
3270
3271            var printMap = printTask.execute(params); // deferred, returns url of map image
3272            printMap.then(function(resp) {
3273                var exp = $('.spoofMap').clone();
3274                exp.attr('id', 'spoofMap');
3275
3276                var subtitle = '';
3277                if (globals.current != undefined) { // index views store current fl differently
3278                    subtitle = globals.current.localeTypeName;
3279                    if (globals.current.localeName != '') {
3280                        subtitle = subtitle + ': ' + globals.current.localeName;
3281                    }
3282                } else {
3283                    subtitle = globals.currentLocaleTypeName;
3284                    if (globals.currentLocaleName != '') {
3285                        subtitle = subtitle + ': ' + globals.currentLocaleName;
3286                    }
3287                }
3288                exp.find('.subtitle').html(subtitle);
3289                // comparison info
3290                if (globals.currentComparisonName != '') {
3291                    var compStr = globals.currentComparisonName;
3292                    if (globals.currentLocaleId > 0) { // locale specific
3293                        if (globals.currentComparisonType == 2) { // prior value is handled differently
3294                            var priorValue = { periodId: 0 };
3295                            var currentValue = {};
3296                            var period = globals.periods[globals.periodId];
3297                            var localeDetails = globals.localeTypes[globals.currentLocaleTypeId]['localeDetails'][globals.currentLocaleId];
3298                            var priorValues = localeDetails['priorValues'];
3299                            for (var key in priorValues) {
3300                                var pv = priorValues[key];
3301                                if (pv.periodId == globals.periodId) {
3302                                    currentValue = pv;
3303                                    continue;
3304                                }
3305                                if (pv.periodId > globals.periodId || pv.periodId <= priorValue.periodId) {
3306                                    continue;
3307                                }
3308                                priorValue = pv;
3309                            }
3310                            compStr = '<strong>' + globals.currentLocaleName + ' Value for ' + currentValue.period + '</strong>: ' + currentValue.valueFmt;
3311                            compStr += '<br /><strong>' + globals.currentLocaleName + ' Value for ' + priorValue.period + '</strong>: ' + priorValue.valueFmt;
3312                            exp.find('.comparison').html(compStr);
3313                            exp.find('.measurementPeriod').remove(); // redundant
3314                        }
3315                        else {
3316                            compStr = $('.idet-comparison-selected .comparisonName').clone();
3317                            if (compStr.length > 0) {
3318                                compStr.find('br').remove();
3319                                compStr = compStr.html();
3320                            }
3321                            else {
3322                                compStr = 'N/A';
3323                            }
3324                            exp.find('.comparison_name').html(compStr);
3325							exp.find('.measurementPeriod').remove(); // redundant
3326                        }
3327                    }
3328                    else { // locale agnostic
3329                        exp.find('.comparison_name').html(compStr);
3330                    }
3331                }
3332                else {
3333                    exp.find('.comparison').remove();
3334                }
3335                // locale specific value info
3336                if (globals.currentLocaleId > 0) {
3337                    if (globals.currentComparisonType != 2 && globals.currentComparisonType != 4) {
3338                        exp.find('.currentLocaleValue').html(globals.currentLocaleName + ' Value for ' + globals.periods[globals.periodId]);
3339                        exp.find('.currentValue').html($('.idet-value-block-value').html());
3340                    }
3341                    else {
3342                        var valStr = $('.idet-comparison-selected').attr('title');
3343                        $(valStr).children('div').remove(); // just the first line (no technical note)
3344                        valStr = '<strong>' + $(valStr).html() + '</strong>';
3345                        exp.find('.currentValueContainer').html(valStr);
3346                        if (globals.currentComparisonType == 4) {
3347                            exp.find('.comparison').remove();
3348                        }
3349                    }
3350                }   
3351                else {
3352                    exp.find('.currentValueContainer').remove();
3353                }   
3354                var img = new Image();
3355                img.crossOrigin = 'Anonymous'; // necessary in order for html2canvas to properly retrieve the img
3356                img.src = resp.url;
3357                exp.find('.map_image').append(img);
3358                exp.find('.mapExportLegend').append($('.mapLegendWrapper').filter(":visible").get(0).outerHTML);
3359                exp.removeClass('hidden-all');
3360                $('body').append(exp);
3361                var spoof = $('#spoofMap').get(0);
3362                var h2cOpts = {
3363                    background: '#fff',
3364                    useCORS: true,
3365                    scale: 2,
3366                    logging: false,
3367                    width: 840
3368                }
3369                // wait for the external image to load before attempting to grab the div
3370                // this helps to prevent blank images on Safari (Chrome & FF seem to do the right thing)
3371                img.onload = function() {
3372                    html2canvas(spoof, h2cOpts).then(function(canvas) {
3373                        var filename = ".jpg";
3374                        if (navigator.userAgent.indexOf("MSIE ") > 0 || navigator.userAgent.match(/Trident.*rv\:11\./)) { // download attribute not supported in IE<=11
3375                            var blob = canvas.msToBlob();
3376                            window.navigator.msSaveBlob(blob, filename);
3377                            finishExport(dialog);
3378                        }
3379                        else {
3380                            var a = $('.saveMapSpoof').get(0);
3381                            var src = canvas.toDataURL('image/jpeg', 1);
3382                            a.href = src;
3383                            a.download = filename;
3384                            a.click();
3385                            finishExport(dialog);   
3386                        }
3387                    });
3388                };
3389            }, // printTask.then..
3390            function(err) {
3391                dialog.dialog('destroy');
3392                var errdialog = $('<div title="Error Exporting Map"><p>An error occurred while preparing the map for export. Please try again.</p></div>');
3393                errdialog.dialog({modal: true});
3394                console.log('An error occurred processing the print request:');
3395                console.log(err);
3396            },
3397            function(update) {
3398                console.log('Update from the print task:');
3399                console.log(update);
3400            });
3401        }
3402
3403        // after downloading map, remove the spoofMap div and remove the dialog
3404        function finishExport(dialog) {
3405            $('#spoofMap').remove();
3406            dialog.dialog('destroy');
3407        }
3408
3409        function clearBreaksGraphics() {
3410            if (globals.map.getLayer('breaksGL') != undefined) {
3411                globals.map.getLayer('breaksGL').clear();
3412                globals.featureLayers[globals.current.fl].graphics.forEach(function(g, idx) {
3413                    if (g.attributes != undefined && globals.current.localeIds.indexOf(g.attributes.localeId) > -1) {  
3414                        var polygon = new esri.geometry.Polygon(g.geometry.spatialReference);
3415                        var rings = g.geometry.rings;
3416                        for (var r=0, rl=rings.length; r<rl; r++) {
3417                            polygon.addRing(rings[r]);
3418                        }
3419
3420                        var symColor = new dojo.Color([245,245,245]);
3421                        symColor.a = 0.1;
3422
3423                        var sym = new SimpleFillSymbol('solid',
3424                                                       new SimpleLineSymbol(
3425                                                           SimpleLineSymbol.STYLE_SOLID,
3426                                                           new dojo.Color([50,50,50]),
3427                                                           .8
3428                                                       ),
3429                                                       symColor);
3430
3431                        g.setSymbol(sym);
3432                    }
3433                });
3434            } else {
3435                return;
3436            }
3437        }
3438
3439        function setBreaksGraphics() {
3440
3441            if (
3442                (globals.transparency == 'on') ||
3443                (globals.map.getLayer('breaksGL') == undefined) || 
3444                (globals.renderer == undefined || globals.renderer.infos.length < 1) ||
3445                (globals.featureLayers[globals.current.fl].graphics.length == 0)
3446            ) {
3447                return;
3448            }
3449
3450            clearBreaksGraphics();
3451
3452            globals.featureLayers[globals.current.fl].graphics.forEach(function(g, idx) {
3453                if (g.attributes != undefined && globals.current.localeIds.indexOf(g.attributes.localeId) > -1) {  
3454                    var polygon = new esri.geometry.Polygon(g.geometry.spatialReference);
3455                    var rings = g.geometry.rings;
3456                    for (var r=0, rl=rings.length; r<rl; r++) {
3457                        polygon.addRing(rings[r]);
3458                    }
3459
3460                    var breaks = globals.breaks;
3461                    var val = g.attributes[globals.indicator];
3462                    for (b in breaks) {
3463                        var min = parseFloat(breaks[b][0]);
3464                        var max = parseFloat(breaks[b][1]);
3465                        if ((b*1) + 1 == breaks.length) {
3466                            max += .01; // pad topmost since it uses <= for some reason
3467                        }
3468                        if (b == 0) {
3469                            min -= .01;
3470                        }
3471                        if (min < val && val <= max) {
3472                            if (globals.renderer.infos.length == 1) {
3473                                var symColor = new dojo.Color(globals.grayColor);
3474                            }
3475                            else {
3476                                var symColor = new dojo.Color(globals.legendColors[b].replace(/[rgb\(\)]/g, '').split(',')); 
3477                                if (globals.transparency == 'off' || globals.transparency == undefined) {
3478                                    symColor.a = 0.85;
3479                                }
3480                                else {
3481                                    symColor.a = 0.0;
3482                                }
3483                            }
3484                        }
3485                    }
3486                    var sym = new SimpleFillSymbol('solid',
3487                                                   new SimpleLineSymbol(
3488                                                       SimpleLineSymbol.STYLE_SOLID,
3489                                                       new dojo.Color([50,50,50]),
3490                                                       .8
3491                                                   ),
3492                                                   symColor);
3493                    var graphic = new esri.Graphic(polygon, sym);
3494
3495                    graphic.attributes = {localeId: g.attributes.localeId, location: g.attributes.location};
3496                    graphic.attributes[globals.indicator] = g.attributes[globals.indicator];
3497                    globals.map.getLayer('breaksGL').add(graphic);
3498                }
3499            });
3500        }
3501
3502        function addBoundaryOutlines(map, layer, symbols, currentLocaleId) {
3503            if (layer) {
3504                layer.graphics.forEach(function(g) {
3505                    var polygon = new esri.geometry.Polygon(g.geometry.spatialReference);
3506                    var rings = g.geometry.rings;
3507                    for (var r=0, rl=rings.length; r<rl; r++) {
3508                        polygon.addRing(rings[r]);
3509                    }
3510                    if (currentLocaleId != g.attributes.localeId) {
3511                        // Symbol having fill color prevents tooltip display.
3512                        // var graphic = new esri.Graphic(polygon, symbols['localeOutline']);
3513                        var graphic = new esri.Graphic(polygon, symbols['localeOutlineNullFill']);
3514                    } else  {
3515                        var graphic = new esri.Graphic(polygon, symbols['select']);
3516                    }
3517                    graphic.id = 'localeoutline';
3518                    map.graphics.add(graphic);
3519                    return;
3520                });
3521            }
3522        }
3523
3524        function removeBoundaryOutlines(map, layer) {
3525            if (layer) {
3526                clearMapGraphics(map, 'localeoutline');
3527            }
3528        }
3529
3530        function clearMapGraphics(map, id) {
3531            if (map && map.gra
3531phics) {
3532                var outlines = [];
3533                map.graphics.graphics.forEach(function(g) {
3534                    if (g && g.id == id) {
3535                        outlines.push(g);
3536                    }
3537                });
3538                outlines.forEach(function(g) {
3539                    map.graphics.remove(g);
3540                });
3541            }
3542        }                </script>
3542
3543
3544                <div class="mapLegend" id="map_301995966718623164_mapLegend" style="display: none;"></div>
3545                <div class="location_unavailable error box" style="display:none;">
3546                    <a href="#" class="close right" aria-label="Close"><i class="fa fa-close" title="Close" aria-hidden="true"></i></a>
3547                    Mapping is not available at the selected location
3548                </div>
3549            </div>
3550			<!-- Requirement 2238139: GIS: Multiple Time Periods on a Map START -->	
3551			
3551<script>
3552map_tiles.tiles.tileinstanceid_301995966718623164.timeline.allPeriodsData=null;
3553map_tiles.tiles.tileinstanceid_301995966718623164.timeline.currentLocaleTypeId=2;
3554map_tiles.tiles.tileinstanceid_301995966718623164.timeline.localeId=2276;
3555map_tiles.tiles.tileinstanceid_301995966718623164.timeline.indicatorId=240;
3556map_tiles.tiles.tileinstanceid_301995966718623164.timeline.initialPeriodId = 11479;
3557map_tiles.tiles.tileinstanceid_301995966718623164.timeline.periodId = 11479;
3558map_tiles.tiles.tileinstanceid_301995966718623164.timeline.defaultComparison = '6823';
3559map_tiles.tiles.tileinstanceid_301995966718623164.timeline.currentComparisonId = '6823';
3560map_tiles.tiles.tileinstanceid_301995966718623164.timeline.hideDescription = '';
3561console.log('set timeline values - showTimeline='+map_tiles.tiles.tileinstanceid_301995966718623164.showTimeline);
3562activeTile = window["map_tiles.tiles.tileinstanceid_301995966718623164"];
3563$(function () {
3564    $('.loadingIcon').hide();
3565});
3566</script>
3566
3567
3568<div id="timelineDiv_map_301995966718623164" class="timelineDiv" style="position: relative;">
3569
3570  <div class="timeline-loading-icon" style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 100;">
3571        <img src="/content/global/application/spinner.gif" alt="Loading...">
3572  </div>
3573	
3574  <div class="slider-container timeline-click-msg">
3575    <button class="play-button enableTimeline" data-map-id="map_301995966718623164">
3576      <i>▶</i> Play
3577    </button>
3578    <div class="timelineMsg">&nbsp;&nbsp;Click Play button to show timeline.</div>
3579  </div>
3580
3581  <div class="slider-container time-slider-container" style="display:none;">
3582      <button class="play-button playTimeline">
3583        <i>▶</i> Play
3584      </button>
3585	  <span class="slider-title">Timeline:</span>
3586	  <div class="slider-wrapper">
3587		<input type="range" min="0" max="10" value="0" step="1" class="slider" id="timeSlider" list="markers" >
3588		<datalist id="markers"></datalist>
3589		<div class="slider-marks"></div>	
3590	  </div>
3591	</div>
3592</div>
3593
3594			<!-- Requirement 2238139: GIS: Multiple Time Periods on a Map END -->	
3595            <div class="text-center indicatorSource">
3596                <div class="indicatorTitle">
3597                    <a href="/indicators/index/view?indicatorId=240&localeId=2276" class="strong map_indicator indicatorLink">Families Living Below Poverty Level</a>
3598                </div>
3599                <div class="small">
3600                    Data Source: <span class="sourceTitle">American Community Survey 5-Year</span>
3601                </div>
3602            </div>
3603        </div>
3604    </div>
3605</div>
3606<img src="/content/global/application/spinner.gif" class="loading" alt="Loading, please wait" />
3607    </section>
3608</div>
3609
3610<div id="tileinstanceid_297766099118853907" class="hci-v2 main-content tileinstance tileinstance_generalhtml">
3611    <section>
3612    <div class="ulink"><h2 style="text-align:center;"><span class="color-primary xx-large"><strong>Priority Areas</strong></span></h2>
3613<div>
3614<table border="0" style="border-collapse:collapse;width:100%;background:#10715F;height:4px;">
3615<tbody>
3616<tr>
3617<td style="width:100%;"></td>
3618</tr>
3619</tbody>
3620</table>
3621</div>
3622<div class="row" style="background:#10715F;">
3623<div class="col-12 col-sm-3"><a href="/tiles/index/display?id=346140493500233292"><img src="/content/sites/jackson/CHA_-_CHIP/Behavioral-Health-and-Well-being-button.png?1692920994752" width="75%" alt="" style="display:block;margin-left:auto;margin-right:auto;" /></a>
3624<p style="text-align:center;"><a href="/tiles/index/display?id=346140493500233292">
3624<span class="color-pageBackground"><strong>Behavioral Health</strong></span></a></p>
3625</div>
3626<div class="col-12 col-sm-3"><a href="/tiles/index/display?id=346176944668417828"><img src="/content/sites/jackson/CHA_-_CHIP/Access-to-Healthcare-button.png?1735336260491" width="75%" alt="" style="display:block;margin-left:auto;margin-right:auto;" /></a>
3627<p style="text-align:center;"><a href="/tiles/index/display?id=346176944668417828"><span class="color-pageBackground"><strong>Access to Healthcare</strong></span></a></p>
3628</div>
3629<div class="col-12 col-sm-3"><a href="/tiles/index/display?id=346759838600528231"><img src="/content/sites/jackson/CHA_-_CHIP/Housing-for-All-button.png?1692921049298" width="75%" alt="" style="display:block;margin-left:auto;margin-right:auto;" /></a>
3630<p style="text-align:center;"><a href="/tiles/index/display?id=346759838600528231"><span class="color-pageBackground"><strong>Housing</strong></span></a></p>
3631</div>
3632<div class="col-12 col-sm-3"><a href="/tiles/index/display?id=346688920027830157"><img src="/content/sites/jackson/CHA_-_CHIP/Community-Building-button.png?1735336339371" width="75%" alt="" style="display:block;margin-left:auto;margin-right:auto;" /></a>
3633<p style="text-align:center;"><a href="/tiles/index/display?id=346688920027830157">
3633<span class="color-pageBackground"><strong>Community Building</strong></span></a></p>
3634</div>
3635</div></div>
3636    </section>
3637</div>
3638
3639<div id="tileinstanceid_297766099118722602" class="hci-v2 main-content tileinstance tileinstance_generalhtml">
3640    <section>
3641    <div class="ulink"><div><span class="ui-provider yi b c d e f g h i j k l m n o p q r s t u v w x y z ab ac ae af ag ah ai aj ak large" dir="ltr">To view CHA/CHIPs for the Jackson &amp; Josephine area, <strong><span class="color-accent"><a href="/tiles/index/display?id=313420568533790381&amp;status=2&amp;alert=1">click here</a></span></strong>.</span></div></div>
3642    </section>
3643</div>
3644
3645<div id="tileinstanceid_369147640483066032" class="hci-v2 main-content tileinstance tileinstance_generalhtml">
3646    <section>
3647    <div class="ulink"><h1 style="text-align:center;background-color:#10715f;padding:7px;"><a href="https://urldefense.com/v3/__https:/app.smartsheet.com/b/publish?EQBCT=9afa7619c8f649e1a0d38f1316951269__;!!Mh0G0HQJXw!ARz8U-8GcOD7GnMQ4BXDr3YgLHEPjEEKwTXZADk57dQ3ZMZ6yoc5stvruRNFfQEJ1nyV8Gu6ZRm-5Auxtq2oXjsJIPD9GJM$" target="_blank" rel="noreferrer noopener"><span style="font-weight:bolder;
3647" class="color-pageBackground">CHIP Tracking Dashboard</span></a></h1>
3648<div> </div>
3649<div><iframe width="100%" height="600" src="https://app.smartsheet.com/b/publish?EQBCT=9afa7619c8f649e1a0d38f1316951269"></iframe></div></div>
3650    </section>
3651</div>
3652    </section>
3653</div>
3654    </div>
3655</div>            </div>
3656            <footer id="footer">
3657    
3658<div id="tileinstanceid_294656889815260585" class="hci-v2 main-content tileinstance tileinstance_tileset">
3659    <section>
3660    
3661
3662
3663<div id="tileinstanceid_294656889300675140" class="hci-v2 main-content tileinstance tileinstance_topics bkgd-dark">
3664    <section>
3665    <div>
3666
3667    <div class="row-around-centered-nowrap">
3668            <div class="col topic-icon">
3669            <a href="/topiccenter/index/subtopic?topicId=5">
3670                <i class="hcicon hci-topic-5" aria-hidden="true"></i>
3671                <div>Health</div>
3672            </a>
3673        </div>
3674            <div class="col topic-icon">
3675            <a href="/topiccenter/index/subtopic?topicId=3000">
3676                <i class="hcicon hci-topic-3000" aria-hidden="true"></i>
3677                <div>Community</div>
3678            </a>
3679        </div>
3680            <div class="col topic-icon">
3681            <a href="/topiccenter/index/subtopic?topicId=2">
3682                <i class="hcicon hci-topic-2" aria-hidden="true"></i>
3683                <div>Economy</div>
3684            </a>
3685        </div>
3686            <div class="col topic-icon">
3687            <a href="/topiccenter/index/subtopic?topicId=3">
3688                <i class="hcicon hci-topic-3" aria-hidden="true"></i>
3689                <div>Education</div>
3690            </a>
3691        </div>
3692            <div class="col topic-icon">
3693            <a href="/topiccenter/index/subtopic?topicId=6">
3694                <i class="hcicon hci-topic-6" aria-hidden="true"></i>
3695                <div>Environmental Health</div>
3696            </a>
3697        </div>
3698        </div>
3699</div>
3700    </section>
3701</div>
3702
3703<div id="tileinstanceid_294656889300674941" class="hci-v2 main-content tileinstance tileinstance_footer">
3704    <section>
3705    <nav class="footer_items" role="navigation" aria-label="footer navigation">  
3706<span class="footer_item"><a href="/tiles/index/display?id=300185606043844986">About Us</a></span>&bull;<span class="footer_item"><a href="https://healthycities.zendesk.com/hc/en-us/sections/204050607-FAQ" target="_blank">FAQ</a></span>&bull;<span class="footer_item"><a href="/index.php?module=utilities&amp;controller=index&amp;action=submitfeedback">Contact Us</a></span>&bull;<span class="footer_item"><a href="/index.php?module=Tiles&amp;controller=index&amp;action=display&amp;alias=EditorialPolicy">Editorial Policy</a></span>
3707    <br class="d-sm-none">
3708    
3709    </nav>
3710
3711<div class="footer_terms">
3712    </div>
3713
3714    </section>
3715</div>
3716    </section>
3717</div>
3718
3719    <div id="footer_tos">
3720    By using this service, you accept our <a href="/utilities/index/termsofuse">Terms of Use</a>. 
3721    Please read them. Powered by 
3722    <a href="https://www.conduent.com/community-health/" target="_blank" rel="nofollow">Conduent Healthy Communities Institute</a>. 
3723    Copyright &copy; 2026. All rights reserved.
3724    </div>
3725
3726    <div id="template_print_title" class="printonly">
3727        All in For Health    </div>
3728
3729    
3730    </footer>
3731
3732    <div id="copyLinkDialog" title="Copy URL" class="noprint">
3733        <div><label for="copyLinkUrl">Copy and paste this URL into an email to share this page.</label></div>
3734        <div><input type="text" id="copyLinkUrl" class="col-12"></div>
3735    </div>
3736    
3736<script type="text/javascript">
3737        var copyLinkPosition = $( "#copyLink" ).position();
3738        $("#copyLinkDialog").dialog({ 
3739            autoOpen: false,
3740            width: "550px",
3741            position: {my: "center", at: "top" + copyLinkPosition.top, of: window},
3742            modal: true,
3743            buttons: {
3744                "Close": function() {
3745                    $( this ).dialog( "close" );
3746                }
3747            }
3748        });
3749    
3750        function copyLink(){
3751            var url = window.location.href;
3752            // Remove the fragment identifier (hash)
3753            url = url.replace(/#.*$/, '');
3754            // Remove the magic param that prevents endless embedding redirects
3755            url = url.replace(/(&hcnembedredirect_=1|hcnembedredirect_=1&|[?]hcnembedredirect_=1$)/, '');
3756
3757            $("#copyLinkUrl").val(url);
3758            $("#copyLinkDialog").dialog("open");
3759        }
3760    </script>
3760
3761
3762    <!-- Start of healthycities Zendesk Widget script -->
3763    
3763<script>/*<![CDATA[*/window.zEmbed||function(e,t){var n,o,d,i,s,a=[],r=document.createElement("iframe");window.zEmbed=function(){a.push(arguments)},window.zE=window.zE||window.zEmbed,r.src="javascript:false",r.title="",r.role="presentation",(r.frameElement||r).style.cssText="display: none",d=document.getElementsByTagName("script"),d=d[d.length-1],d.parentNode.insertBefore(r,d),i=r.contentWindow,s=i.document;try{o=s}catch(e){n=document.domain,r.src='javascript:var d=document.open();d.domain="'+n+'";void(0);',o=s}o.open()._l=function(){var o=this.createElement("script");n&&(this.domain=n),o.id="js-iframe-async",o.src=e,this.t=+new Date,this.zendeskHost=t,this.zEQueue=a,this.body.appendChild(o)},o.write('<body onload="document._l();">'),o.close()}("https://assets.zendesk.com/embeddable_framework/main.js","healthycities.zendesk.com");
3764    /*]]>*/</script>
3764
3765    <!-- End of healthycities Zendesk Widget script -->
3766        </div>
3767    </div>
3768
3769<script type="text/javascript">
3770ClientSite.Extensions.ExternalLinkHandler(1, 0);
3771ClientSite.Extensions.addExternalLinkOptions(1);
3772
3773if (1) {
3774    $('a[href^="xhttp"]').each(function() {
3775        // some icons won't have the external icon as they would look odd, eg. social media icons
3776        if ($(this).attr('target') != '_blank' && !$(this).hasClass('no-ext-icon')) {
3777            $(this).attr('target',  '_blank');
3778        }
3779        
3780        // surpress the external icon on image links such as you find in the carousel tile as it would look odd
3781        if (!$(this).text().length) {
3782            $(this).addClass('no-ext-icon');
3783        }
3784
3785        // all external links will have screen reader only text informing the user that the link will open in a new tab
3786        $(this).html($(this).html() + ' <span class="sr-only">(opens in a new tab)</span>');
3787
3788        // all external links should haverel noopener is to prevent reverse tabnabbing
3789        $(this).attr('rel', 'noopener');
3790    });
3791}
3792
3793
3794document.addEventListener("DOMContentLoaded", () => {
3795    
3796    /**
3797     * Helper to fix general accessibility issues inside any document scope (Main or Iframe)
3798     */
3799    const applyA11yRules = (docScope) => {
3800        
3801        // 1. Fix HTML Lang - WCAG 2.1 - Page detected as HTML, but does not have a 'lang' attribute
3802        if (docScope.documentElement && !docScope.documentElement.lang) {
3803            docScope.documentElement.lang = 'en';
3804        }
3805		
3806		// 2. Inline frame does not have a 'title' attribute
3807        docScope.querySelectorAll('iframe').forEach(e => {
3808			if (!e.hasAttribute('title') || e.getAttribute('title').trim() === "") {
3809				const title = e.classList.contains('fancybox-iframe') ? "Modal Content" : "Content Frame";
3810				e.setAttribute('title', title);
3811			}	
3812		});
3813
3814        // 3. Fix Multiple Forms (Unique Labels) - WCAG 2.1 - Multiple elements with "form" role do not have unique labels
3815        docScope.querySelectorAll('form, [role="form"]').forEach((form, i) => {
3816            if (!form.getAttribute('aria-label') && !form.getAttribute('aria-labelledby')) {
3817                form.setAttribute('aria-label', `Form ${i + 1}`);
3818            }
3819        });
3820
3821        // 4. Fix Fieldsets & Resolve Duplicate "Include:" Names - WCAG 2.1 - Group/Fieldset does not have an accessible name or has duplicate names
3822        docScope.querySelectorAll('fieldset').forEach((fs, i) => {
3823            const legend = fs.querySelector('legend');
3824            const legendText = legend ? legend.textContent.trim() : '';
3825            
3826            // CASE A: Handle duplicate "Include:" legends by adding specific context
3827            if (legendText === 'Include:' || legendText === 'Include') {
3828                const firstCheckboxLabel = fs.querySelector('.fancy-checkbox')?.textContent.trim();
3829                if (firstCheckboxLabel) {
3830                    fs.setAttribute('aria-label', `Include ${firstCheckboxLabel}`);
3831                } else {
3832                    fs.setAttribute('aria-label', `Include Options ${i + 1}`);
3833                }
3834            }
3835            
3836            // CASE B: Handle existing logic where a "label" attribute exists on the tag
3837            const labelAttr = fs.getAttribute('label');
3838            if (labelAttr && !fs.getAttribute('aria-label')) {
3839                fs.setAttribute('aria-label', labelAttr.replace(':', ''));
3840            } 
3841            
3842            // CASE C: If there is no legend at all and no aria-label, assign a generic fallback
3843            else if (!legend && !fs.hasAttribute('aria-label')) {
3844                fs.setAttribute('aria-label', `Form Group ${i + 1}`);
3845            }
3846        });
3847
3848		// 5. Fix for Hyperlinks - WCAG 2.1
3849		// - Ensures accessible name exists
3850		// - Ensures Label in Name (WCAG 2.5.3)
3851		// - Prevents duplicate alt text
3852		// - Fixes "FAQopens new tab" spacing issue
3853
3854		const normalizeText = (str) => {
3855			return (str || '')
3856				.replace(/\s+/g, ' ')
3857				.trim();
3858		};
3859
3860		// Extract visible text properly (handles inline spans like "opens new tab")
3861		const getVisibleText = (el) => {
3862			return normalizeText(
3863				Array.from(el.childNodes)
3864					.map(node => {
3865						// If it's an element node, check for hidden classes
3866						if (node.nodeType === 1 && node.matches('.visually-hidden, .sr-only')) {
3867							return '';
3868						}
3869						// Otherwise, return text content (for text nodes or non-hidden elements)
3870						return node.textContent || '';
3871					})
3872					.join(' ')
3873			);
3874		};		
3875
3876		docScope.querySelectorAll('a').forEach(link => {
3877			const visibleText = getVisibleText(link);
3878			const hasVisibleText = visibleText.length > 0;
3879
3880			const images = link.querySelectorAll('img');
3881			const hasAria = link.hasAttribute('aria-label') &&
3882							normalizeText(link.getAttribute('aria-label')) !== '';
3883
3884			// ---------------------------
3885			// Part A: Remove redundant image alt text
3886			// ---------------------------
3887			if (hasVisibleText && images.length > 0) {
3888				images.forEach(img => img.setAttribute('alt', ''));
3889			}
3890
3891			// ---------------------------
3892			// Part B: Fix Label in Name (WCAG 2.5.3)
3893			// ---------------------------
3894			if (hasVisibleText) {
3895				let currentAria = normalizeText(link.getAttribute('aria-label'));
3896				
3897				if (currentAria) {
3898					// Fix smashed words in existing labels
3899					currentAria = currentAria.replace(/([a-zA-Z])opens new tab/gi, '$1 opens new tab');
3900					
3901					const normalizedVisible = visibleText.toLowerCase();
3902					const normalizedAria = currentAria.toLowerCase();
3903
3904					// ONLY update if the current ARIA is broken (doesn't include the visible text)
3905					if (!normalizedAria.includes(normalizedVisible)) {
3906						// Prepend visible text to the existing label to satisfy 2.5.3
3907						link.setAttribute('aria-label', `${visibleText}: ${currentAria}`);
3908					} else {
3909						link.setAttribute('aria-label', currentAria);
3910					}
3911				} 
3912				// IF there is visible text and NO aria-label, DO NOTHING. 
3913				// The browser will naturally use the visible text as the name.
3914			}
3915
3916			// ---------------------------
3917			// Part C: Missing accessible name fallback
3918			// ---------------------------
3919			else if (!hasAria) {
3920				
3921				// 1. Check for image alt text
3922				const firstImgWithAlt = link.querySelector('img[alt]:not([alt=""])');
3923    
3924				// 2. Check for hidden text (Your getVisibleText already skips .visually-hidden)
3925				// We should check if the link actually has inner text including hidden stuff
3926				const innerText = normalizeText(link.textContent); 
3927
3928				const dataTitle =
3929					link.getAttribute('data-original-title') ||
3930					link.getAttribute('data-confirm');
3931
3932				const parentCell = link.closest('td');
3933				const siblingLabel = parentCell
3934					? parentCell.querySelector('label, p, span')
3935					: null;
3936
3937				if (hasVisibleText) {
3938					// Do nothing! Let the browser use the visible text.
3939				} else if (innerText !== "") {
3940					// If there is hidden text (like your "Save" span), do nothing! 
3941					// The browser will use the span automatically.
3942				} else if (firstImgWithAlt) {
3943					link.setAttribute('aria-label', normalizeText(firstImgWithAlt.getAttribute('alt')));
3944				} else if (dataTitle && normalizeText(dataTitle) !== "") {
3945					link.setAttribute('aria-label', normalizeText(dataTitle));
3946				} else if (siblingLabel && normalizeText(siblingLabel.textContent)) {
3947					link.setAttribute(
3948						'aria-label',
3949						`View details for ${normalizeText(siblingLabel.textContent)}`
3950					);
3951				} else if (link.id) {
3952					link.setAttribute(
3953						'aria-label',
3954						'Action for ' + link.id.replace(/_/g, ' ')
3955					);
3956				} else {
3957					link.setAttribute('aria-label', 'View details');
3958				}
3959			}
3960
3961			// ---------------------------
3962			// Part D: Cleanup
3963			// ---------------------------
3964			if (link.hasAttribute('title') && normalizeText(link.getAttribute('title')) === "") {
3965				link.removeAttribute('title');
3966			}
3967		});		
3968
3969
3970
3971        // 6. Fix Layout Tables - WCAG 2.1 - Table has no headers identified (Table within tinymce)
3972        docScope.querySelectorAll('table.mce-item-table, table[border="0"]').forEach(table => {
3973            if (table.querySelectorAll('th').length === 0 && !table.hasAttribute('role')) {
3974                table.setAttribute('role', 'presentation');
3975            }
3976        });
3977
3978        // 7. Fix listbox missing accessible name - WCAG 2.1 - Form control with "listbox" role has no associated label 
3979        docScope.querySelectorAll('[role="listbox"]').forEach(function (el) {
3980            if (!el.hasAttribute('aria-label') && !el.hasAttribute('aria-labelledby')) {
3981                el.setAttribute('aria-label', 'Select option');
3982            }
3983        });
3984		
3985        // 8. Fix Focusable elements inside aria-hidden containers - WCAG 2.1 - Focusable elements must not be inside aria-hidden="true" subtrees
3986 		docScope.querySelectorAll('[aria-hidden="true"]').forEach(hiddenContainer => {
3987			// Exclude Select2 as Select2 will handle aria-hidden and tabindex
3988			if (hiddenContainer.classList.contains('select2-container') || 
3989				hiddenContainer.classList.contains('select2-hidden-accessible')) {
3990				return;
3991			}
3992
3993			const focusableElements = hiddenContainer.querySelectorAll('a, button, input, select, textarea, [tabindex]:not
3993([tabindex="-1"])');
3994			focusableElements.forEach(el => {
3995				el.setAttribute('tabindex', '-1');
3996			});
3997		});
3998		
3999	
4000		// 9. Fix SVG Paths with role="img" but no accessible name (Highcharts Fix) - WCAG 2.1 - Element <path> with "img" role has no accessible name
4001        docScope.querySelectorAll('path[role="img"]').forEach(path => {
4002            const label = path.getAttribute('aria-label');
4003            if (!label || label.trim() === "") {
4004                path.setAttribute('aria-hidden', 'true');
4005                path.removeAttribute('role');
4006                path.removeAttribute('aria-label');
4007            }
4008        });
4009		
4010		//10. WCAG2.1 -The image has neither an accessible name nor is marked as decorative or redundant
4011		docScope.querySelectorAll('img:not([alt])').forEach(img => {
4012			const src = img.getAttribute('src');
4013
4014			if (src && src.trim() !== '') {
4015				const filename = src.split('/').pop().split(/[?#]/)[0];
4016				const altText = filename
4017					.replace(/\.[^/.]+$/, "")      
4018					.replace(/[-_]/g, " ")         
4019					.trim();
4020
4021				if (altText) {
4022					img.alt = altText;
4023				}
4024			} else {
4025				img.alt = "NA"; 
4026			}
4027		});
4028		
4029		//11. Fix for Label 
4030		// - Remove "for" if ID doesn't exist in DOM
4031		// - Remove for from label if the field is display:none. 
4032		// - Empty labels with icons (Common in File Manager filters)
4033		docScope.querySelectorAll('label').forEach(label => {
4034            const targetId = label.getAttribute('for');
4035            const target = targetId ? docScope.getElementById(targetId) : null;
4036            const hasVisibleText = label.textContent.trim().length > 0;
4037            const hasAria = label.hasAttribute('aria-label') || label.hasAttribute('aria-labelledby');
4038
4039            // Part A: Fix Invalid/Hidden Associations (Steps 11 & 14)
4040            if (targetId) {
4041                if (!target) {
4042                    // ID doesn't exist in DOM
4043                    label.removeAttribute('for');
4044                } else {
4045                    // Target exists, check visibility
4046                    const isHidden = window.getComputedStyle(target).display === 'none';
4047                    if (isHidden) {
4048                        label.dataset.originalFor = targetId;
4049                        label.removeAttribute('for');
4050                    } else if (label.dataset.originalFor) {
4051                        label.setAttribute('for', label.dataset.originalFor);
4052                    }
4053                }
4054            }
4055
4056            // Part B: Fix Empty Labels with Icons (Step 12)
4057            if (!hasVisibleText && !hasAria) {
4058                const tooltipText = label.getAttribute('data-original-title');
4059                if (tooltipText && tooltipText.trim() !== "") {
4060                    label.setAttribute('aria-label', tooltipText.trim());
4061                } else if (label.querySelector('.icon-remove')) {
4062                    label.setAttribute('aria-label', 'Clear Filters');
4063                }
4064            }
4065
4066            // Part C: Cleanup empty titles
4067            if (label.hasAttribute('title') && label.getAttribute('title').trim() === "") {
4068                label.removeAttribute('title');
4069            }
4070        });
4071		
4072
4073		//12. Add aria-label for Textarea if no label
4074		docScope.querySelectorAll('textarea').forEach(textarea => {
4075			const id = textarea.id;
4076		 
4077			// Check for associated <label for="id">
4078			const hasLabel =
4079			  id && docScope.querySelector(`label[for="${id}"]`);
4080		 
4081			if (
4082			  !hasLabel &&
4083			  !textarea.hasAttribute('aria-label') &&
4084			  !textarea.hasAttribute('aria-labelledby')
4085			) {
4086			  const name =
4087				textarea.getAttribute('name') ||
4088				textarea.getAttribute('placeholder') ||
4089				'Text input';
4090			  textarea.setAttribute('aria-label', name);
4091			}
4092		});
4093		
4094		// 13. Fix Buttons without accessible names (Ensuring Label in Name compliance)
4095		const buttons = docScope.querySelectorAll('button');
4096		let buttonCounter = 1;
4097
4098		buttons.forEach(button => {
4099			const visibleText = button.textContent ? button.textContent.trim() : "";
4100			const hasVisibleText = visibleText.length > 0;
4101			
4102			const titleText = button.getAttribute('title') ? button.getAttribute('title').trim() : "";
4103			const hasValidTitle = titleText !== "";
4104			
4105			const currentAriaLabel = button.getAttribute('aria-label') || "";
4106
4107			// STRATEGY 1: If the button has a visible tooltip (Title), FORCE the aria-label to match it.
4108			// This immediately fixes the conflict between "Open link in..." and "Current window".
4109			if (hasValidTitle) {
4110				button.setAttribute('aria-label', titleText);
4111			}
4112			// STRATEGY 2: If there is no Title but there IS visible text, force the aria-label to match the text.
4113			else if (hasVisibleText) {
4114				button.setAttribute('aria-label', visibleText);
4115			} 
4116			// STRATEGY 3: If there is NEITHER visible text nor a title (e.g., pure icon buttons)
4117			else if (!button.hasAttribute('aria-label') || currentAriaLabel === "Action Button 1") {
4118				const tooltipText = button.getAttribute('data-original-title') || 
4119									button.getAttribute('data-tooltip');
4120				
4121				let fallbackLabel = '';
4122
4123				if (tooltipText && tooltipText.trim() !== "") {
4124					fallbackLabel = tooltipText.trim();
4125				} else {
4126					const htmlContent = button.innerHTML.toLowerCase();
4127					
4128					// Fallbacks for purely visual icons
4129					if (htmlContent.includes('close') || button.classList.contains('close')) {
4130						fallbackLabel = 'Close';
4131					} else if (htmlContent.includes('lock')) {
4132						fallbackLabel = 'Security Settings';
4133					} else {
4134						fallbackLabel = `Action Button ${buttonCounter++}`;
4135					}
4136				}
4137				
4138				button.setAttribute('aria-label', fallbackLabel);
4139			}
4140
4141			// Cleanup: Remove empty title="" attributes to prevent redundant announcements
4142			if (button.hasAttribute('title') && button.getAttribute('title').trim() === "") {
4143				button.removeAttribute('title');
4144			}
4145		});
4146
4147
4148	
4149    };
4150    
4151    /**
4152     * Fix for Duplicate Landmarks (Navigation and Regions)
4153     * WCAG 2.1 - Multiple elements with "navigation" role do not have unique labels
4154     * WCAG 2.1 - Multiple elements with "region" role do not have unique labels
4155     */
4156    const fixDuplicateLandmarks = (docScope = document) => {
4157        
4158        // --- 1. Fix <nav> elements ---
4159        const navs = docScope.querySelectorAll('nav');
4160        if (navs.length > 1) {
4161            navs.forEach((nav, i) => {
4162                if (!nav.hasAttribute('aria-label') && !nav.hasAttribute('aria-labelledby')) {
4163                    if (nav.classList.contains('navbar')) {
4164                        nav.setAttribute('aria-label', `Main Navigation ${i + 1}`);
4165                    } else if (nav.querySelector('.breadcrumb')) {
4166                        nav.setAttribute('aria-label', `Breadcrumbs ${i + 1}`);
4167                    } else if (nav.classList.contains('pagination')) {
4168                        nav.setAttribute('aria-label', `Pagination ${i + 1}`);
4169                    } else {
4170                        nav.setAttribute('aria-label', `Navigation ${i + 1}`);
4171                    }
4172                }
4173            });
4174        }
4175
4176        // --- 2. Fix Highcharts / General role="region" duplicates ---
4177        const regions = docScope.querySelectorAll('[role="region"]');
4178        
4179        if (regions.length > 0) {
4180            const labelCounts = new Map();
4181            const seenLabelsTracker = new Map();
4182
4183            // Strip nested quotes, dynamic suffixes, and framework boilerplate
4184            const normalizeRegionLabel = (label) => {
4185                if (!label) return '';
4186                return label
4187                    .replace(/["'\\]|&quot;/g, '') // Strips messy unescaped or escaped quote symbols
4188                    .replace(/\s*for\s+.*?\s*\(\d+\)\s*$/gi, '') // Cleans the appended 'for "Title" (1)' pattern
4189                    .replace(/\.?\s*Highcharts interactive chart\s*/gi, '') // Removes framework wording
4190                    .replace(/[^a-zA-Z0-9]/g, '') // Leaves only clean alphanumeric base keys
4191                    .toLowerCase()
4192                    .trim();
4193            };
4194
4195            // Pass 1: Tally accurate cross-DOM frequencies using the clean base keys
4196            regions.forEach(region => {
4197                const currentLabel = region.getAttribute('aria-label');
4198                if (currentLabel) {
4199                    const normalized = normalizeRegionLabel(currentLabel);
4200                    labelCounts.set(normalized, (labelCounts.get(normalized) || 0) + 1);
4201                }
4202            });
4203
4204            // Pass 2: Map unique prefix-based strings onto the elements
4205            regions.forEach((region, i) => {
4206                let currentLabel = region.getAttribute('aria-label');
4207                
4208                if (!currentLabel && !region.hasAttribute('aria-labelledby')) {
4209                    currentLabel = `Content Region`;
4210                    region.setAttribute('aria-label', `${currentLabel} ${i + 1}`);
4211                }
4212
4213                if (currentLabel) {
4214                    const normalized = normalizeRegionLabel(currentLabel);
4215                    const totalCount = labelCounts.get(normalized) || 1;
4216
4217                    if (totalCount > 1) {
4218                        const chartContainer = region.closest('[data-highcharts-chart]');
4219                        let uniqueChartId = chartContainer ? chartContainer.getAttribute('data-highcharts-chart') : '';
4220
4221                        // Reconstruct clean title for presentation 
4222                        let cleanTitle = currentLabel
4223                            .replace(/\s*for\s+.*?\s*\(\d+\)\s*$/gi, '')
4224                            .replace(/\.?\s*Highcharts interactive chart\.\s*/gi, '')
4225                            .replace(/["'\\]|&quot;/g, '')
4226                            .trim();
4227
4228                        if (!cleanTitle) cleanTitle = "Interactive Chart";
4229
4230                        let finalLabel = '';
4231
4232                        // Track nested graph elements vs parent containers uniquely
4233                        if (region.classList.contains('highcharts-series') || region.tagName.toLowerCase() === 'g') {
4234                            const clipPath = region.getAttribute('clip-path') || '';
4235                            const clipMatch = clipPath.match(/-(\d+)-\)?$/);
4236                            const elementIndex = clipMatch ? clipMatch[1] : i;
4237                            
4238                            finalLabel = `Chart ${uniqueChartId || 'Sub'} Element ${elementIndex}: ${cleanTitle}`;
4239                        } else {
4240                            const currentOccurrence = (seenLabelsTracker.get(normalized) || 0) + 1;
4241                            seenLabelsTracker.set(normalized, currentOccurrence);
4242                            
4243                            // Prepended label scheme complies with modern a11y parsing tools
4244                            finalLabel = `Chart ${currentOccurrence}: ${cleanTitle}`;
4245                        }
4246                        
4247                        // Performance and protection check: Only update if the string differs
4248                        if (region.getAttribute('aria-label') !== finalLabel) {
4249                            region.setAttribute('aria-label', finalLabel);
4250                        }
4251                    }
4252                }
4253            });
4254        }
4255    };
4256    
4257    /**
4258     * Fix for user-created table in report screen
4259     * WCAG 2.1 - Table has no headers identified
4260     */
4261    const fixUserCreatedTables = (docScope = document) => {
4262        const reportTables = docScope.querySelectorAll('.component_richtext table, .report-container table');
4263        reportTables.forEach(table => {
4264            if (table.querySelectorAll('th').length === 0) {
4265                table.setAttribute('role', 'presentation');
4266            }
4267        });
4268    };
4269        
4270    /**
4271     * Fix for ungrouped radio buttons
4272     * Encloses isolated radio buttons into a semantic fieldset
4273     */
4274    const fixUngroupedRadios = (docScope = document) => {
4275        const radios = docScope.querySelectorAll('input[type="radio"][name]');
4276        const processed = new Set();
4277
4278        radios.forEach(radio => {
4279            const name = radio.getAttribute('name');
4280            if (processed.has(name)) return;
4281            processed.add(name);
4282
4283            const safeSelector = `#${CSS.escape(name)}-element`;
4284            const dd = radio.closest(safeSelector) || radio.closest('dd');
4285            
4286            if (dd && !dd.querySelector('fieldset')) {
4287                const fieldset = document.createElement('fieldset');
4288				fieldset.style.border = 'none';
4289				fieldset.style.backgroundColor = 'transparent';				
4290                const legend = document.createElement('legend');
4291                
4292                legend.textContent = `Select ${name}`;
4293                legend.classList.add('sr-only'); // Visually hidden but read by screen readers
4294                
4295                fieldset.appendChild(legend);
4296                
4297                while (dd.firstChild) {
4298                    fieldset.appendChild(dd.firstChild);
4299                }
4300                dd.appendChild(fieldset);
4301            }
4302        });
4303    };
4304	
4305	/**
4306     * Specific fix requested for #reportComponents
4307     * WCAG: Element "a" should not be focusable within the subtree of an element with 'aria-hidden="true"'
4308     */
4309    const fixHiddenLinksInReportComponents = (docScope = document) => {
4310        const reportContainer = docScope.querySelector('#reportComponents');
4311        
4312        if (reportContainer) {
4313            // Find any node carrying aria-hidden="true" inside GridStack
4314            const hiddenAreas = reportContainer.querySelectorAll('[aria-hidden="true"]');
4315            
4316            hiddenAreas.forEach(area => {
4317                // Query all links inside that are missing tabindex="-1"
4318                const focusableLinks = area.querySelectorAll('a:not([tabindex="-1"])');
4319                
4320                focusableLinks.forEach(link => {
4321                    link.setAttribute('tabindex', '-1');
4322                    // console.log('Fixed focusable link in GridStack:', link);
4323                });
4324            });
4325        }
4326    };
4327	
4328	const fixDirectoryAccessibility = (docScope = document) => { 
4329		// 1. Fix all directory images
4330		const images = docScope.querySelectorAll('img.directory-img, img.loaded');
4331
4332		images.forEach(img => {
4333			// If no alt at all → treat as decorative
4334			if (!img.hasAttribute('alt')) {
4335				img.setAttribute('alt', '');
4336			}
4337
4338			// If empty alt → ensure it's hidden from screen readers
4339			if (img.getAttribute('alt') === '') {
4340				img.setAttribute('aria-hidden', 'true');
4341			}
4342		});
4343
4344		// 2. Fix links that only contain images (no accessible name)
4345		const links = docScope.querySelectorAll('a.folder-link');
4346
4347		links.forEach(link => {
4348			// Check if link already has accessible name
4349			const hasText = link.textContent.trim().length > 0;
4350			const hasAria = link.hasAttribute('aria-label');
4351
4352			if (!hasText && !hasAria) {
4353				// Try to get folder name from parent <li>
4354				const li = link.closest('li[data-name]');
4355				const folderName = li ? li.getAttribute('data-name') : 'Folder';
4356
4357				link.setAttribute('aria-label', folderName + ' folder');
4358			}
4359		});
4360	}
4361
4362    /**
4363     * Main Execution Wrapper
4364     */
4365    const runA11yFixes = () => {
4366        // Apply to main document
4367        applyA11yRules(document);
4368        fixDuplicateLandmarks(document);
4369        if (typeof fixUserCreatedTables === 'function') fixUserCreatedTables(document);
4370        if (typeof fixUngroupedRadios === 'function') fixUngroupedRadios(document);
4371		if (typeof fixHiddenLinksInReportComponents === 'function') fixHiddenLinksInReportComponents(document); 
4372		if (typeof fixDirectoryAccessibility === 'function') fixDirectoryAccessibility(document);
4373
4374        // Apply to existing Iframes (including TinyMCE if loaded)
4375        document.querySelectorAll('iframe').forEach(iframe => {
4376            if (!iframe.getAttribute('lang')) iframe.setAttribute('lang', 'en');
4377            try {
4378                const doc = iframe.contentDocument || iframe.contentWindow.document;
4379                if (doc) applyA11yRules(doc);
4380            } catch (e) { /* Cross-origin protection */ }
4381        });
4382
4383        // Select2 - Combobox Logic
4384        // WCAG 2.1 - Form control with "combobox" role has no associated label (RichMultiSelect)
4385		document.querySelectorAll('.select2-container').forEach((container, index) => {
4386			const combobox = container.querySelector('[role="combobox"]');
4387			if (!combobox) return;
4388
4389			if (combobox.getAttribute('tabindex') === '-1') {
4390					combobox.setAttribute('tabindex', '0');
4391			}
4392			
4393			// 1. Get the target listbox ID (usually from aria-owns or a predictable pattern)
4394			const listboxId = combobox.getAttribute('aria-owns') || combobox.getAttribute('aria-controls') || 
4395							  (combobox.id ? combobox.id.replace('-container', '-results') : null);
4396			const isExpanded = combobox.getAttribute('aria-expanded') === 'true';				  
4397
4398			// 2. ARIA 1.2: Sync attributes based on expanded state
4399			if (isExpanded && listboxId) {
4400				if (combobox.getAttribute('aria-controls') !== listboxId) {
4401					combobox.setAttribute('aria-controls', listboxId);
4402				}
4403				
4404			} else {
4405				
4406				// else isExpanded=false
4407				if (combobox.hasAttribute('aria-controls')) {
4408					combobox.removeAttribute('aria-controls');
4409				}
4410				if (combobox.hasAttribute('aria-activedescendant')) {
4411					combobox.removeAttribute('aria-activedescendant');
4412				}
4413			}
4414
4415			// Always remove aria-owns (ARIA 1.1 legacy) and set correct haspopup
4416			if (combobox.hasAttribute('aria-owns')) 
4417				combobox.removeAttribute('aria-owns');
4418			
4419			if (combobox.getAttribute('aria-haspopup') !== 'listbox') {
4420				combobox.setAttribute('aria-haspopup', 'listbox');
4421			}			
4422
4423			// 3. Labeling Logic: Link to external <label> to fix "no associated label"
4424			const originalSelect = container.previousElementSibling;
4425			if (originalSelect && originalSelect.tagName.toUpperCase() === 'SELECT') {
4426				let labelId = null;
4427
4428				
4429				// A. Try to find an explicit <label for="...">
4430				const linkedLabel = document.querySelector(`label[for="${originalSelect.id}"]`);
4431					
4432				// B. NEW: Try to find a header-based label (like your <h4>) using the predictable ID pattern
4433				const headerLabel = document.getElementById(originalSelect.id + '-label');
4434
4435				if (linkedLabel) {
4436					if (!linkedLabel.id) linkedLabel.id = originalSelect.id + '-label';
4437					labelId = linkedLabel.id;
4438				} 
4439				else if (headerLabel) {
4440					// This matches your <h4 id="ls_indicatorLocale_handpick-label">
4441					labelId = headerLabel.id;
4442				}
4443				// Fallback: Use original select's aria-labelledby if it exists
4444				else if (originalSelect.hasAttribute('aria-labelledby')) {
4445					labelId = originalSelect.getAttribute('aria-labelledby');
4446				}
4447
4448				//Fix "Form control with 'combobox' role has no associated label" 
4449				if (labelId) {
4450					// Explicitly link the combobox container to the label text via ID
4451					combobox.setAttribute('aria-labelledby', labelId);
4452
4453					// --- CHANGE 3: Sync internal Search Input ---
4454					// For Multi-select, Select2 uses an internal input field. 
4455					// We must also link this input to the label to ensure full WCAG compliance.
4456					const searchField = container.querySelector('.select2-search__field');
4457					if (searchField && !searchField.hasAttribute('aria-labelledby')) {
4458						searchField.setAttribute('aria-labelledby', labelId);
4459					}
4460				} else if (originalSelect.getAttribute('aria-label')) {
4461					combobox.setAttribute('aria-label', originalSelect.getAttribute('aria-label'));
4462				} else {
4463					// Use the placeholder text if available, otherwise use a numbered generic label
4464					const placeholder = originalSelect.getAttribute('data-placeholder') || 'Selection Menu';
4465					combobox.setAttribute('aria-label', `${placeholder} ${index + 1}`);
4466				}
4467			}
4468		});
4469
4470
4471        
4472        // Select the dt by its id on tile topic Page
4473        // WCAG 2.1 - remove for attribute from label
4474        document.querySelectorAll('dt.itempermissions-toggle-control label').forEach(label => {
4475            label.removeAttribute('for');
4476        });
4477
4478        // Select2 - Search Input Logic
4479        // WCAG 2.1 - Form control with "textbox" role has no associated label
4480        // WCAG 2.1 - The ARIA role 'textbox' is not valid for the element <input>
4481        document.querySelectorAll('.select2-search__field').forEach(input => {
4482            input.removeAttribute('role'); 
4483            if (!input.hasAttribute('aria-label')) {
4484                const container = input.closest('.select2-container');
4485                const originalSelect = container ? container.previousElementSibling : null;
4486                let labelText = "Search options";
4487                if (originalSelect && originalSelect.id) {
4488                    const labelEl = document.getElementById(originalSelect.id + '-label');
4489                    if (labelEl) labelText = `Search ${labelEl.textContent.replace(':', '').trim()}`;
4490                }
4491                input.setAttribute('aria-label', labelText);
4492            }
4493        });
4494
4495        // TableSorter Scroller Fix
4496        // WCAG 2.1 - Table has no headers identified
4497        document.querySelectorAll('.tablesorter-scroller-table thead.tablesorter-scroller-hidden').forEach(thead => {
4498            thead.setAttribute('style', 'display: table-header-group !important; visibility: visible !important; position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; clip: rect(0, 0, 0, 0) !important; white-space: nowrap !important; border: 0 !important;');
4499        });
4500		
4501		// WCAG 2.1 - An explicit ARIA 'role' is not valid for <tr> element within an ARIA role 'grid' per the ARIA in HTML specification
4502		document.querySelectorAll('.tablesorter').forEach(table => {
4503			// Remove roles from TR elements to follow HTML5 spec
4504			table.querySelectorAll('tr').forEach(tr => {
4505				if (tr.getAttribute('role') === 'row' || tr.getAttribute('role') === 'search') {
4506					tr.removeAttribute('role');
4507				}
4508			});
4509		});
4510		
4511    };
4512	
4513	//WCAG2.1 - The ARIA role 'treeitem' is not valid for the element <li>
4514	// Fix Select2 Dropdown structure on open (Handles treeitem -> option and Nested Groups)
4515	// WCAG 2.1 / ARIA 1.2 - Fix Select2 Dropdown structure on open 
4516	$(document).on('select2:open', function(e) {
4517		const $target = $(e.target);
4518		const selectData = $target.data('select2');
4519		const selectId = $target.attr('id');
4520		const labelId = selectId ? selectId + '-label' : null;
4521
4522		// 1. Establish ARIA 1.2 relationship on the Combobox
4523		if (selectData && selectData.$container) {
4524			const combobox = selectData.$container[0].querySelector('[role="combobox"]');
4525			const resultsId = selectId ? `select2-${selectId}-results` : null;
4526
4527			if (combobox && resultsId) {
4528				combobox.setAttribute('aria-controls', resultsId);
4529				combobox.removeAttribute('aria-owns'); // Remove legacy ARIA 1.1
4530			}
4531		}
4532
4533		/**
4534		 * Core function to fix the results DOM structure.
4535		 * Changes role="treeitem" to role="option" and handles nested groups.
4536		 */
4537		const fixResultsStructure = () => {
4538			const resultsContainer = document.querySelector('.select2-results__options');
4539			if (!resultsContainer) return;
4540
4541			// 1. Fix Root Container
4542			resultsContainer.setAttribute('role', 'listbox');
4543			if (labelId && document.getElementById(labelId)) {
4544				resultsContainer.setAttribute('aria-labelledby', labelId);
4545			}
4546
4547			// 2. Fix Search Field (Role & Naming)
4548			// We look for the search field in the dropdown or the main container
4549			const searchField = document.querySelector('.select2-search__field');
4550			if (searchField) {
4551				// Remove redundant/invalid role
4552				searchField.removeAttribute('role'); 
4553				
4554				if (!searchField.hasAttribute('aria-label')) {
4555					let searchLabel = "Search options";
4556					if (labelId) {
4557						const originalLabel = document.getElementById(labelId);
4558						if (originalLabel) {
4559							// Creates a label like "Search Indicator Locale"
4560							searchLabel = `Search ${originalLabel.textContent.replace(':', '').trim()}`;
4561						}
4562					}
4563					searchField.setAttribute('aria-label', searchLabel);
4564				}
4565			}
4566
4567			// 3. Fix List Items (treeitem -> option)
4568			resultsContainer.querySelectorAll('li').forEach(li => {
4569				const isGroup = li.classList.contains('select2-results__option--group') || li.querySelector('ul');
4570				
4571				if (isGroup) {
4572					li.setAttribute('role', 'none'); 
4573					const nestedUl = li.querySelector('ul');
4574					if (nestedUl) {
4575						nestedUl.setAttribute('role', 'group');
4576						const groupTitle = li.querySelector('.select2-results__group, strong');
4577						if (groupTitle) {
4578							if (!groupTitle.id) groupTitle.id = 'group-title-' + Math.random().toString(36).substr(2, 5);
4579							nestedUl.setAttribute('aria-labelledby', groupTitle.id);
4580						}
4581					}
4582				} else {
4583					li.setAttribute('role', 'option');
4584					li.removeAttribute('aria-label'); 
4585					li.removeAttribute('aria-level');
4586
4587					const isHighlighted = li.classList.contains('select2-results__option--highlighted');
4588					const isSelected = li.classList.contains('select2-results__option--selected') || li.getAttribute('aria-selected') === 'true';
4589					li.setAttribute('aria-selected', (isHighlighted || isSelected) ? 'true' : 'false');
4590				}
4591			});
4592		};
4593
4594		// 2. Initial execution after dropdown renders
4595		setTimeout(fixResultsStructure, 50);
4596
4597		// 3. Re-run whenever the user types (Select2 re-renders the list on search)
4598		$(document).off('keyup.s2fix').on('keyup.s2fix', '.select2-search__field', function() {
4599			// Short delay to allow Select2 to finish rendering new results
4600			setTimeout(fixResultsStructure, 20);
4601		});
4602	});
4603	
4604	$(document).on('select2:highlight', function(e) {
4605		const $target = $(e.target);
4606		const select2Data = $target.data('select2');
4607		if (!select2Data) return;
4608
4609		// Use setTimeout to ensure Select2 has finished updating 'aria-activedescendant'
4610		setTimeout(() => {
4611			const combobox = select2Data.$container[0].querySelector('[role="combobox"]');
4612			const activeId = combobox ? combobox.getAttribute('aria-activedescendant') : null;
4613
4614			if (activeId) {
4615				// Find the active option within the results container
4616				const activeOption = document.getElementById(activeId);
4617				
4618				if (activeOption) {
4619					// 1. Reset all other visible options to false
4620					const resultsContainer = activeOption.closest('.select2-results__options');
4621					if (resultsContainer) {
4622						resultsContainer.querySelectorAll('[role="option"][aria-selected="true"]').forEach(opt => {
4623							if (opt !== activeOption) opt.setAttribute('aria-selected', 'false');
4624						});
4625					}
4626
4627					// 2. FIX: Force aria-selected="true" on the current active descendant
4628					activeOption.setAttribute('aria-selected', 'true');
4629				}
4630			}
4631		}, 0);
4632	});
4633		
4634	if (window.jQuery && $.fancybox) {
4635        $.extend(true, $.fancybox.defaults, {
4636            afterShow: function(instance, current) {
4637                if (current.type === 'iframe') {
4638                    const iframe = current.$content.find('iframe')[0];
4639                    if (iframe) {
4640                        try {
4641                            const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
4642                            applyA11yRules(iframeDoc); 
4643                        } catch (e) {
4644                            console.warn("Iframe A11y: Cross-origin restriction.");
4645                        }
4646                    }
4647                }
4648            }
4649        });
4650    }
4651
4652    /**
4653     * Helper to prevent flood triggers on mass DOM insertion (like Highcharts spawning hundreds of nodes)
4654     */
4655    function debounce(func, wait) {
4656        let timeout;
4657        return function(...args) {
4658            clearTimeout(timeout);
4659            timeout = setTimeout(() => func.apply(this, args), wait);
4660        };
4661    }
4662
4663    const debouncedRun = debounce(runA11yFixes, 250);
4664
4665    // Initial Run
4666    runA11yFixes();
4667
4668    // Run on full window load to catch late-loading elements
4669    window.addEventListener('load', runA11yFixes);
4670
4671    // Mutation Observer for dynamic content (Select2, ESRI, Highcharts etc.)
4672    const observer = new MutationObserver((mutations) => {
4673        let shouldRerun = false;
4674        
4675        for (const m of mutations) {
4676            // Part A: Structural Node Injections Check
4677            if (m.type === 'childList' && m.addedNodes.length > 0) {
4678                for (const node of m.addedNodes) {
4679                    if (node.nodeType !== 1) continue;
4680
4681                    if (node.tagName === 'IFRAME' || node.querySelector('iframe')) {
4682                        shouldRerun = true;
4683                    }
4684					
4685                    // ESRI SVG Configuration
4686                    const svgs = node.matches('.esriMapContainer svg') ? [node] : node.querySelectorAll('.esriMapContainer svg');
4687                    svgs.forEach(svg => {
4688                        svg.setAttribute('aria-hidden', 'true');
4689                        svg.setAttribute('focusable', 'false');
4690                        const title = svg.querySelector('title');
4691                        if (title) title.remove();
4692                    });
4693                    
4694                    if (node.classList?.contains('select2-container') || node.querySelector('.select2-container')) {
4695                        shouldRerun = true;
4696                    }
4697
4698                    if (node.classList?.contains('highcharts-container') || node.querySelector('.highcharts-series') || node.closest('[data-highcharts-chart]')) {
4699                        shouldRerun = true;
4700                    }
4701					
4702                    if (node.classList?.contains('grid-stack-item') || node.matches('#reportComponents') || node.querySelector('#reportComponents')) {
4703                        shouldRerun = true;
4704                    }					
4705                }
4706            }
4707
4708            // Part B: Attribute Mutation Evaluation (CIRCUIT BREAKER ADDED)
4709			else if (m.type === 'attributes') {
4710                const targetEl = m.target;
4711                const newVal = targetEl.getAttribute(m.attributeName) || '';
4712
4713				if (['aria-label', 'aria-controls', 'aria-expanded'].includes(m.attributeName)) {
4714					
4715                    // CIRCUIT BREAKER 1: Match against names generated by our own scripts
4716                    if (m.attributeName === 'aria-label' && /^(Chart|Instance|Form|Content Region|Navigation|Main Navigation|Breadcrumbs|Pagination)\s+\d+/i.test(newVal)) {
4717                        continue; // Skip mutation processing to block infinite loops
4718                    }
4719
4720                    // CIRCUIT BREAKER 2: Match against Select2 input synchronization updates
4721                    if (targetEl.classList.contains('select2-search__field') && targetEl.hasAttribute('aria-labelledby')) {
4722                        continue;
4723                    }
4724
4725                    // Native framework rewrite detected, authorize execution pass
4726                    shouldRerun = true;
4727				}
4728			}			
4729            
4730            if (shouldRerun) break; // Break mutation array loop early to maximize performance
4731        }
4732
4733        if (shouldRerun) debouncedRun();
4734    });
4735
4736    // Start watching the body
4737    observer.observe(document.body, { 
4738        childList: true, 
4739        subtree: true,
4740        attributes: true,
4741        attributeFilter: ['aria-label', 'aria-controls', 'aria-expanded']
4742    });
4743});
4744
4745</script>
4745
4746
4747
4748<!--script type="text/javascript" src="/assets/js/wcag_global.js"></script-->
4749 
4750<button style="display:none;" id="advancedSearchLocation">Hidden Button at footer_full.phtml</button>
4751<!--
4751<script src="https://js.arcgis.com/3.44/"></script>
4751-->
4752<link rel="stylesheet" href="https://js.arcgis.com/3.44/esri/css/esri.css" />
4753
4754
4755        
4756
4757
4758<script>
4759    var lssiteLocaleTypes = {"County":"Counties","State":"States","Zip Code":"Zip Codes","Census Place":"Census Places","Census Tract":"Census Tracts"};
4760    //console.log("lssiteLocaleTypes===" + JSON.stringify(lssiteLocaleTypes, null, 2));
4761    //9925 var globalUniqueId='';
4762    const routeUrls = {
4763       locales_indexajax_dispatch: '/locales/indexajax/dispatch',
4764       indicators_adminajax_dispatch: '/indicators/adminajax/dispatch',
4765    };
4766    function lsdefaultLocaleCallback(locales) {
4767        alert("your chosen locales are:\n\n" + locales);
4768    }
4769
4770    // namespace the code
4771    if (typeof lslocaleSelector == "undefined" || !lslocaleSelector) {
4772        var lslocaleSelector = {
4773            lsinstances: {},
4774            randomId: Math.floor(Math.random() * 26) + Date.now(),
4775        };
4776    }
4777
4778    /**
4779     * selectLocations function.
4780     * 
4781     * Called on user selecting, "select" on location dialog.
4782     * Calls user supplied callback function, passing in list of locations
4783     * 
4784     * @return void
4785     */
4786    lslocaleSelector.lsselectLocations = function(instance) {
4787        var localeList = [];
4788        var localeDisplayNameList = [];
4789
4790        $('#' + instance.uniqueId + ' .lsselectedTable tbody td').each(function(index, locale) {
4791            localeList.push(parseInt($(locale).attr('class').split('-')[1]));
4792            localeDisplayNameList.push($(locale).text());
4793        });
4794
4795        //console.log("At localeselection, localeList=" + JSON.stringify(localeList, null, 2));
4796        //console.log("At localeselection, localeDisplayNameList=" + JSON.stringify(localeDisplayNameList, null, 2));
4797
4798        try {
4799            // Parse the JSON string from hidden field
4800            var storedPriorData = JSON.parse($('#lspriorVal').val() || '{}');
4801            //console.log('At localeselection, storedPriorData:', JSON.stringify(storedPriorData,null,2));
4802            // Check if it's a valid object
4803            if (typeof storedPriorData === 'object' && storedPriorData !== null && !Array.isArray(storedPriorData)) {
4804        
4805                Object.keys(storedPriorData).forEach(function(value) {
4806                    var optionData = storedPriorData[value];
4807                    
4808                    //console.log('At localeselection, storedPriorData Value:', value);
4809                    //console.log('At localeselection, storedPriorData Text:', optionData.text);
4810                    //console.log('At localeselection, storedPriorData Selected:', optionData.selected);
4811                    //console.log('At localeselection, storedPriorData optgroupLabel:', optionData.optgroupLabel);
4812                    //console.log('---');
4813                    // Add to arrays
4814                    localeList.push(parseInt(value, 10));
4815                    localeDisplayNameList.push(optionData.optgroupLabel + ": " +optionData.text);
4816                });
4817        
4818            } else {
4819                console.warn('At localeselection, Invalid data format in hidden field');
4820            }
4821        } catch (e) {
4822            console.error('At localeselection, Error parsing stored data:', e);
4823        }
4824        
4825        //console.log("At localeselection, storedPriorData localeList=" + JSON.stringify(localeList, null, 2));
4826        //console.log("At localeselection, storedPriorData localeDisplayNameList=" + JSON.stringify(localeDisplayNameList, null, 2));
4827        
4828        var lstargetId= $('#lstargetId').val();
4829        //console.log("At localeselection, lstargetId=" + lstargetId);
4830        var nameAttr = $('#' + lstargetId ).attr('name');
4831        //console.log("At localeselection, nameAttr=" + nameAttr);
4832        var $select = $('select[name="' + nameAttr + '"]');
4833
4834        //console.log("localeList===" + JSON.stringify(localeList, null, 2));
4835        
4836        for (var i = 0; i < localeList.length; i++) {
4837            const displayName = localeDisplayNameList[i] || '';
4838            const parts = displayName.split(':');
4839            const localeTypeName = parts[0] ? parts[0].trim() : '';
4840            const localeName = parts[1] ? parts[1].trim() : '';
4841            //console.log("At localeselection, localeTypeName=" + localeTypeName);
4842            //console.log("At localeselection, localeName=" + localeName);
4843            var $optgroup = $select.find('optgroup[label="' + localeTypeName + '"]');
4844            
4845            if ($optgroup.length === 0) {
4846                console.log("optgroup not found, find again with plural");
4847                //$optgroup = $select.find('optgroup[label="' + localeTypeName + 's' +'"]');
4848                $optgroup = $select.find('optgroup[label="' + lssiteLocaleTypes[localeTypeName] +'"]');
4849                if ($optgroup.length === 0) {
4850                    //console.log("optgroup not found create new, actually not right");
4851                    $optgroup = $('<optgroup>', { label: localeTypeName });
4852                }
4853                $select.append($optgroup);
4854            }
4855            //var option = new Option(localeDisplayNameList[i], localeList[i]);
4856            var option = new Option(localeName, localeList[i]);
4857            $optgroup.append($(option));
4858        }
4859        $select.val(localeList);        
4860
4861        var lssearchMode = $('#lssearchMode').val();
4862        //console.log("At localeselection, lssearchMode=" + JSON.stringify(lssearchMode, null, 2));
4863        if(lssearchMode=='multiMode'){
4864            $select.attr('multiple', 'multiple');
4865        }
4866        $select.trigger('change.select2'); 
4867        instance.localeCallback(localeList);
4868        
4869        if (!instance.panelContainer) {
4870            $('#' + instance.uniqueId + '.lslocationSelectPanelContent').dialog('close');
4871        }
4872    }
4873    
4874    /**
4875     * lsbaseMeasureConfig function
4876     * 
4877     * Return the base measure settings configuration
4878     *
4879     * @return Object
4880     */
4881    lslocaleSelector.lsbaseMeasureConfig = function(instanceSettings) {
4882        if (! instanceSettings.measureTypeId) {
4883            return {};
4884        }
4885
4886        var config = {
4887            measureTypeId: instanceSettings.measureTypeId,
4888            measureId: 0,
4889            measureChildTypeId: 0,
4890            measureChildIdList: '',
4891        };
4892        
4893        //if (instanceSettings.measureTypeId != ClientSite.Enum.MeasureType.NONE) {
4894        if (instanceSettings.measureTypeId != -1) {
4895            config.measureId = instanceSettings.measureId;
4896            config.measureChildTypeId = instanceSettings.measureChildTypeId;
4897            config.measureChildIdList = instanceSettings.measureChildIdList;
4898        }
4899        
4900        return config;
4901    }
4902    
4903    /**
4904     * Determine whether the specified locale exists in the handpicked locale selection table
4905     * 
4906     * @param {string} panelElemId Element id of the handpicked location selection panel container 
4907     * @param {string|number} localeElemClass Class name or db id of the locale to check (e.g. locale-123 or 123)
4908     * @return {boolean} True if locale has already been selected, else false
4909     */
4910    lslocaleSelector.lsisHandpickedLocaleSelected = function(panelElemId, localeElemClass) {
4911        if (! isNaN(localeElemClass)) {
4912            // Convert db id to class name
4913            localeElemClass = 'locale-' + localeElemClass;
4914        }
4915        
4916        return $('#' + panelElemId + ' .lsselectedTable tbody td.' + localeElemClass).length > 0;
4917    };
4918    
4919    lslocaleSelector.resetAndHideFiltersForTable = function(instanceSettings, tableId) {
4920       
4921        console.log("At localeselection, entering resetAndHideFiltersForTable");
4922           
4923        var $table = $('#' +  instanceSettings.uniqueId  + ' table.' + tableId);
4924            if($table){
4925                console.log("At localeselection, resetAndHideFiltersForTable table=" + $table);
4926            }else{
4927                console.log("At localeselection, resetAndHideFiltersForTable not defined" );
4928            }
4929        // Reset all filter inputs for this specific table
4930        $table.find('.tablesorter-filter').val('');
4931    
4932        // Trigger search to clear any active filtering for this table
4933        $table.trigger('search');
4934    
4935        // Reset sorting for this table
4936        $table.trigger('sortReset');
4937    
4938        // Hide the filters for this table only
4939        $table.find('.tablesorter-filter').hide();
4940        $table.find('.tablesorter-filter-row').hide();
4941        console.log("At localeselection, exiting resetAndHideFiltersForTable");
4942    }
4943
4944    lslocaleSelector.showFiltersForTable = function (instanceSettings, tableId) {
4945        console.log("At localeselection, entering showFiltersForTable");    
4946        var $table = $('#' +  instanceSettings.uniqueId  + ' table.' + tableId);
4947        // Show the filter inputs
4948        $table.find('.tablesorter-filter').show();
4949    
4950        // Show the entire filter row
4951        $table.find('.tablesorter-filter-row').show();
4952        console.log("At localeselection, exiting showFiltersForTable");
4953    }
4954
4955    lslocaleSelector.setLabel = function (id) {
4956        var labelMap = {
4957            'singleMode': 'Location',
4958            'multiMode': 'Locations'
4959        };
4960        console.log("Enter lslocaleSelector.setLabel");
4961        var lssearchMode = $('#lssearchMode').val();
4962        console.log("lslocaleSelector.setLabel searchMode=" + lssearchMode);
4963        
4964        var newText = '';
4965
4966        if(id && id=='lslbl-1'){
4967            newText = 'Add ' + labelMap[lssearchMode];
4968        } 
4969        if(id && id=='lslbl-2'){
4970             newText = 'Selected ' + labelMap[lssearchMode];
4971        }
4972        $('label.' + id).text(newText);
4973        console.log("Exit lslocaleSelector.setLabel");
4974    }
4975      
4976
4977    /**
4978     * lsupdateLocaleList function.
4979     * 
4980     * Populate a table of available locales for currently selected measure and locale type
4981     * 
4982     * @return void
4983     */
4984    lslocaleSelector.lsupdateLocaleList = function(instanceSettings) {
4985        //console.log("At localeselection, Enter lslocaleSelector.lsupdateLocaleList");
4986        var measureTypeId = parseInt(instanceSettings.measureTypeId);
4987        var localeTypeId = parseInt($('#' + instanceSettings.uniqueId + '-localeTypeId').val());
4988        var ancestorLocaleId=parseInt($('#' + instanceSettings.uniqueId + '-ancestorLocaleId').val());
4989        //console.log("At localeselection, Ancestor isNaN(ancestorLocaleId)=" + isNaN(ancestorLocaleId));
4990
4991        var localeListHandler = function (data, status) {
4992            //console.log("At localeselection, localeListHandler=====data.localeList=======" + JSON.stringify(data.localeList, null, 2));
4993    
4994            var selectionItems = $();
4995            $.each(data.localeList, function (index, localeData) {
4996                // check to see whether this locale is already in our selected table, if so disable move
4997                var isSelected = lslocaleSelector.lsisHandpickedLocaleSelected(
4998                    instanceSettings.uniqueId, 'locale-' + localeData.localeId);
4999    
5000                var item = lslocaleSelector.lsgenerateLocaleSelectItem(localeData, true, isSelected);
5001                selectionItems = selectionItems.add(item);
5002            });
5003            // Workaround to ensure that the content in the select menu is refreshed but the change events aren't inadvertently fired
5004            $('#' + instanceSettings.uniqueId + ' table.lsselectionTable tbody').html(selectionItems);
5005            $('#' + instanceSettings.uniqueId + ' table.lsselectionTable')
5006                .trigger('update')
5007                .trigger('appendCache')
5008                .trigger('filterResetSaved');
5009            //capture lsmapLocalesData Info
5010            //console.log("At localeselection, =====localeListHandler data.mapLocales=======" + JSON.stringify(data.mapLocales, null, 2));
5011            $('#' + instanceSettings.uniqueId + ' #lsmapLocalesData').attr('data-info', JSON.stringify(data.mapLocales)).trigger('lsmapLocalesDataChange');
5012        };
5013
5014        var limitLocaleTypeId =[4,135];
5015
5016        if (measureTypeId && localeTypeId > 0) {
5017            
5018            if(limitLocaleTypeId.includes(localeTypeId) && (ancestorLocaleId==0 || isNaN(ancestorLocaleId))){
5019               lslocaleSelector.resetAndHideFiltersForTable(instanceSettings,'lsselectionTable');
5020               //console.log("At localeselection, empty here...");
5021               var htmlContent = `<p class="lslbl-4">Too many results to show.</p>
5022               <p class="lslbl-4">To narrow down your results:<br>
5023               1. Select a parent location using the <b>Limit to Locations Within</b> dropdown (e.g., choose a County or Region).<br>
5024               2. Once selected, a list of locations within that area will appear on screen.</p>
5025               <p class="lslbl-4">You can either:
5026               <ul>
5027               <li class="lslbl-4"><b>Browse the list</b> to find your location, or</li>
5028               <li class="lslbl-4">Use the <b>search filter</b> to quickly locate a specific entry.</li>
5029               </ul></p>`;
5030               $('#' + instanceSettings.uniqueId + ' table.lsselectionTable tbody').html('').val(0).trigger('change');
5031               $('#' + instanceSettings.uniqueId + ' table.lsselectionTable tbody').html(htmlContent);
5032               
5033            }else{
5034                //console.log('At localeselection, lslocaleSelector.lsupdateLocaleList instance.localeListCallVals=' + JSON.stringify(instanceSettings.localeListCallVals));
5035                if(instanceSettings.localeListCallVals){
5036                    console.log("At localeselection, in localeListCallVals start");
5037                    const routeKey = `${instanceSettings.localeListCallVals.module}_${instanceSettings.localeListCallVals.controller}_${instanceSettings.localeListCallVals.action}`;
5038                    const baseUrl = routeUrls[routeKey];
5039                    instanceSettings.localeListCallVals.params.localeTypeId = localeTypeId;
5040                    instanceSettings.localeListCallVals.params.ancestorLocaleId = $('#' + instanceSettings.uniqueId + '-ancestorLocaleId').val();
5041                    instanceSettings.localeListCallVals.params.includeAncestors = 1;
5042                    const params = {
5043                        callAction: instanceSettings.localeListCallVals.callAction,
5044                        ...instanceSettings.localeListCallVals.params
5045                    };
5046                    //console.log('At localeselection, params.ancestorLocaleId=' + JSON.stringify(params.ancestorLocaleId, null, 2));
5047                    //console.log('At localeselection, params.localeTypeId=' + JSON.stringify(params.localeTypeId, null, 2));
5048                    $('#' + instanceSettings.uniqueId + ' button.lsadd-all-locations').prop('disabled', false);
5049                    $.post(baseUrl, params, localeListHandler, 'json');
5050                    console.log("At localeselection, in localeListCallVals end");
5051                }else{
5052                    console.log("At localeselection, In default........................");
5053                    var params = lslocaleSelector.lsbaseMeasureConfig(instanceSettings);
5054                    params.ancestorLocaleId = $('#' + instanceSettings.uniqueId + '-ancestorLocaleId').val();
5055                    params.localeTypeId = localeTypeId;
5056                    params.requiredLocaleIdList = instanceSettings.requiredLocaleIdList;
5057                    //params.includeAncestors = (limitLocaleTypeId.includes(localeTypeId)? 0: 1);
5058                    params.includeAncestors = 1;
5059                    //console.log('At localeselection, params.ancestorLocaleId=' + JSON.stringify(params.ancestorLocaleId, null, 2));
5060                    //console.log('At localeselection, params.localeTypeId=' + JSON.stringify(params.localeTypeId, null, 2));
5061                    //console.log('At localeselection, params.includeAncestors=' + JSON.stringify(params.includeAncestors, null, 2));
5062                    $('#' + instanceSettings.uniqueId + ' button.lsadd-all-locations').prop('disabled', false);
5063            
5064                    $.post(
5065                        ClientSite.Extensions.Url().quickUrl('locales', 'indexajax', 'dispatch', {callAction: 'getLocaleListByFilters'}),
5066                        params,
5067                        function (data, status) {
5068                            var selectionItems = $();
5069                            //console.log("At localeselection, =====data.localeList=======" + JSON.stringify(data.localeList, null, 2));
5070                    
5071                            $.each(data.localeList, function (index, localeData) {
5072                                // check to see whether this locale is already in our selected table, if so disable move
5073                                var isSelected = lslocaleSelector.lsisHandpickedLocaleSelected(
5074                                    instanceSettings.uniqueId, 'locale-' + localeData.localeId);
5075                        
5076                                var item = lslocaleSelector.lsgenerateLocaleSelectItem(localeData, true, isSelected);
5077                                selectionItems = selectionItems.add(item);
5078                            });
5079
5080                            // Workaround to ensure that the content in the select menu is refreshed but the change events aren't inadvertently fired
5081                            $('#' + instanceSettings.uniqueId + ' table.lsselectionTable tbody').html(selectionItems);
5082                            $('#' + instanceSettings.uniqueId + ' table.lsselectionTable')
5083                                .trigger('update')
5084                                .trigger('appendCache')
5085                                .trigger('filterResetSaved');
5086        
5087                            //capture lsmapLocalesData Info
5088                            //console.log("At localeselection, =====data.mapLocales=======" + JSON.stringify(data.mapLocales, null, 2));
5089                            $('#' + instanceSettings.uniqueId + ' #lsmapLocalesData').attr('data-info', JSON.stringify(data.mapLocales)).trigger('lsmapLocalesDataChange');
5090                        },
5091                        'json');
5092                }
5093                $('#' + instanceSettings.uniqueId + ' .lsselectionTable thead').show();
5094                lslocaleSelector.showFiltersForTable(instanceSettings,'lsselectionTable');
5095            }
5096        } else {
5097            $('#' + instanceSettings.uniqueId + '-localeIdList')
5098                .html('')
5099                .val(0)
5100                .trigger('change');
5101        }
5102        console.log("At localeselection, Exit lslocaleSelector.lsupdateLocaleList");
5103    }
5104
5105    /**
5106     * Generate a locale item for use in the selection panel
5107     *
5108     * @param {object} locale Info about the locale
5109     * @param {boolean} isLeftPanel True if item is for use in left side of the selection panel; false if for right panel
5110     * @param {boolean} isSelected Whether the item was previously selected (only applicable if isLeftPanel is true)
5111     * @return {jQuery} Element to attach to the selection panel
5112     */
5113    lslocaleSelector.lsgenerateLocaleSelectItem = function(locale, isLeftPanel, isSelected) {
5114        //console.log("At localeselection, lsgenerateLocaleSelectItem isLeftPanel=" + isLeftPanel);
5115        //console.log("At localeselection, lsgenerateLocaleSelectItem isSelected=" + isSelected);
5116        var td = $('<td>', {class: 'locale-' + locale.localeId})
5117            .text(locale.localeTypeName + ': ' + locale.localeName)
5118            .append($('<i>', {
5119                'class': 'fa move-location ' + (isLeftPanel ? 'fa-arrow-right' : 'fa-arrow-left'), 
5120                'aria-hidden': 'true'
5121            }));
5122        var tr = $('<tr>', {
5123            'class': 'location-row' + (isLeftPanel && isSelected ? ' move-disabled' : ''),
5124            'data-locale-type-id': locale.localeTypeId,
5125            'data-locale-type': locale.localeTypeName.toLowerCase().replace(/ /g, '-'),
5126        })
5127            .append(td);
5128    
5129        lslocaleSelector.lsaddLocaleTooltip(tr, locale);
5130        //console.log("At localeselection, In lsgenerateLocaleSelectItem tr=" + JSON.stringify(tr,null,2));
5131        return tr;
5132    }
5133
5134    /**
5135     * updateLocaleTypeList function.
5136     * 
5137     * Populate the "Location type" pulldown with available locale types for selected measure
5138     * 
5139     * @return void
5140     */
5141    lslocaleSelector.lsupdateLocaleTypeList = function(instance) {
5142        var measureTypeId = parseInt(instance.measureTypeId);
5143        var optionList = '';
5144        var currentVal = 0;
5145        var userSelectTypeId = 0;
5146        var defaultLocaleTypeId = 0;
5147        var localeTypeHandler = function (data) {
5148            currentVal = $('#' + instance.uniqueId + '-localeTypeId').val();
5149            if(currentVal){
5150                console.log("currentVal=" + currentVal);
5151            }else{
5152                console.log("no currentVal, use user select value");
5153                currentVal = $('#lsUserSelectTypeIdVal').val();
5154                //console.log("currentVal=" + currentVal);
5155            }
5156            
5157            jQuery.each(data.localeTypeList, function (i, localeTypeData) {
5158                //console.log("i=" + i);
5159                if(i==0){
5160                    defaultLocaleTypeId=localeTypeData.localeTypeId;
5161                    //console.log("defaultLocaleTypeId=" + defaultLocaleTypeId);
5162                }
5163                optionList += '<option value="' + localeTypeData.localeTypeId + '">' + localeTypeData.localeTypeName + '</option>';
5164            });
5165
5166            // update the placeholder text
5167            $('#' + instance.uniqueId + '-localeTypeId').select2({
5168                dropdownCssClass: "localeDropdown",
5169                placeholder: "* please select *",
5170                width: 'auto'
5171            });
5172
5173            if(!currentVal){
5174                console.log("at last no currentVal use default locale type");
5175                currentVal = defaultLocaleTypeId;
5176                //console.log("at last currentVal=" + defaultLocaleTypeId);
5177            }
5178            // Workaround to ensure that the content in the select menu is refreshed but the change events aren't inadvertently fired
5179            $('#' + instance.uniqueId + '-localeTypeId')
5180                .html(optionList)
5181                .val(currentVal)
5182                .trigger('change');
5183
5184            $('#' + instance.uniqueId + '-ancestorLocaleId').val(0);
5185            $('#' + instance.uniqueId + ' #lsselectedLocationInText').empty();
5186            lslocaleSelector.lsupdateAncestorLocaleList(instance);
5187            if ($('#' + instance.uniqueId + '-ancestorLocaleId').prop('disabled')) {
5188                $('#' + instance.uniqueId + '-ancestorLocaleId').prop('d
5188isabled', false);
5189            }
5190        };
5191        
5192        //if (measureTypeId == ClientSite.Enum.MeasureType.NONE) {
5193        //console.log("At localeselection, zzzzmeasureTypeId=" + JSON.stringify(measureTypeId, null, 2));
5194        if (measureTypeId == -1) {
5195            $.post('/locales/indexajax/dispatch?callAction=getMappableLocaleTypeList',
5196                localeTypeHandler,
5197                'json'
5198            );
5199        } else if (measureTypeId) {
5200            //console.log('At localeselection, lslocaleSelector.lsupdateLocaleTypeList instance.localeTypeCallVals=' + JSON.stringify(instance.localeTypeCallVals));
5201            if(instance.localeTypeCallVals){
5202                console.log("At localeselection, in localeTypeCallVals start");
5203                const routeKey = `${instance.localeTypeCallVals.module}_${instance.localeTypeCallVals.controller}_${instance.localeTypeCallVals.action}`;
5204                const baseUrl = routeUrls[routeKey];
5205                const params = {
5206                    callAction: instance.localeTypeCallVals.callAction,
5207                    ...instance.localeTypeCallVals.params
5208                };
5209                $.post(baseUrl, params, localeTypeHandler, 'json');
5210                console.log("At localeselection, in localeTypeCallVals end");
5211            }else{
5212                var params = lslocaleSelector.lsbaseMeasureConfig(instance);
5213                params.mappable = instance.mappable ? 1 : 0;
5214                params.requiredLocaleIdList = instance.requiredLocaleIdList;
5215            
5216                //console.log("At localeselection, zzzzzinstance.mappable=" + JSON.stringify(instance.mappable, null, 2));
5217                //console.log("At localeselection, zzzzzinstance.requiredLocaleIdList=" + JSON.stringify(instance.requiredLocaleIdList, null, 2));
5218            
5219                $.post('/locales/indexajax/dispatch?callAction=getLocaleTypeListByMeasure',
5220                    params,
5221                    localeTypeHandler,
5222                    'json'
5223                );
5224            }
5225            
5226        } else {
5227            // Workaround to ensure that the content in the select menu is refreshed but the change events aren't inadvertently fired
5228            $('#' + instance.uniqueId + '-localeTypeId')
5229                .html(optionList)
5230                .val(currentVal)
5231                .trigger('change');
5232        }
5233    }
5234
5235    /**
5236     * updateAncestorLocaleList function.
5237     * 
5238     * Populate a select element with the ancestors of the currently selected locale type
5239     * 
5240     * @return void
5241     */
5242    lslocaleSelector.lsupdateAncestorLocaleList = function(instance) {
5243        console.log("At localeselection, Enter lslocaleSelector.lsupdateAncestorLocaleList");
5244        var measureTypeId = parseInt(instance.measureTypeId);
5245        var localeTypeId = parseInt($('#' + instance.uniqueId + '-localeTypeId').val());
5246        var optionList = '<option value="0">None</option>';
5247        //console.log("At localeselection, Enter lslocaleSelector.lsupdateAncestorLocaleList measureTypeId=" + measureTypeId);
5248        //console.log("At localeselection, Enter lslocaleSelector.lsupdateAncestorLocaleList localeTypeId=" + localeTypeId);
5249        if (measureTypeId && localeTypeId > 0) {
5250            //console.log("At localeselection, to call getLocaleAncestorListByFilters");
5251            var params = lslocaleSelector.lsbaseMeasureConfig(instance);
5252            params.localeTypeId = localeTypeId;
5253            params.requiredLocaleIdList = instance.requiredLocaleIdList
5254
5255            $.post('/locales/indexajax/dispatch?callAction=getLocaleAncestorListByFilters',
5256                params,
5257                function (data) {
5258                    var currentVal = $('#' + instance.uniqueId + '-ancestorLocaleId').val();
5259
5260                    jQuery.each(data.ancestorLocaleList, function (index, localeData) {
5261                        optionList += '<option value="' + localeData.localeId + '">' + localeData.localeTypeName + ': ' + localeData.localeName + '</option>';
5262                    });
5263
5264                    // Workaround to ensure that the content in the select menu is refreshed but the change events aren't inadvertently fired
5265                    $('#' + instance.uniqueId + '-ancestorLocaleId')
5266                        .html(optionList)
5267                        .val(currentVal)
5268                        .trigger('change');
5269                },
5270                'json'
5271            );
5272        }
5273        else {
5274            $('#' + instance.uniqueId + '-ancestorLocaleId')
5275                .html(optionList)
5276                .val(0)
5277                .trigger('change');
5278        }
5279        console.log("At localeselection, Exit lslocaleSelector.lsupdateAncestorLocaleList");
5280    }
5281    
5282    /**
5283     * populatePulldowns function.
5284     * 
5285     * Called during the locale selector opening process
5286     * @param string localeClass
5287     * 
5288     * @return void
5289     */
5290    lslocaleSelector.lspopulatePulldowns = function(instance) {
5291        // reset our save localeTypeId
5292        $('#lsselectLocaleTypeId').val('');
5293
5294        // initialise the "location type" select2 pulldown 
5295        $('#' + instance.uniqueId + '-localeTypeId').select2({
5296            dropdownCssClass: "localeDropdown",
5297            placeholder: "loading..."
5298        });
5299        
5300        // on opening, add a class to the parent to help style it
5301        $('#' + instance.uniqueId + '-localeTypeId').on('select2:open', function() {
5302            $('.localeDropdown').parent().addClass('dropdownContainer');
5303        });
5304        
5305        // process a user selection
5306        $('#' + instance.uniqueId + '-localeTypeId').on('select2:select', function(e) {
5307            var uniqueId = $(this).closest('.lslocationSelectPanelContent').attr('id');
5308            var instance = lslocaleSelector.lsinstances[uniqueId];
5309            var currentLocaleTypeId = instance.singleSelectedLocaleTypeId;
5310            var data = e.params.data;
5311            
5312            // Now that the user has selected a locale type, change the placeholder
5313            $('#' + instance.uniqueId + '-ancestorLocaleId').select2({
5314                dropdownCssClass: "localeDropdown",
5315                placeholder: "* please select *"
5316            });
5317
5318            if (currentLocaleTypeId && (currentLocaleTypeId != data['id'])) {
5319                var retCode = confirm("Selecting a new location type will remove all your currently included locations. Do you want to proceed?");
5320                
5321                if (retCode) {
5322                    // empty selected table
5323                    $('#' + uniqueId + ' .lsselectedTable > tbody')
5324                        .empty()
5325                        .trigger('lslocaleSelector:remove');
5326                    
5327                    // disable remove all button
5328                    $('#' + uniqueId + ' .lsremove-all-locations').prop('disabled', true);
5329                    
5330                    // reset our single selected locale type as our table has been emptied
5331                    instance.singleSelectedLocaleTypeId = null;
5332                }
5333                else {
5334                    // user cancel so restore previous select option
5335                    $('#' + instance.uniqueId + '-localeTypeId').val(instance.singleSelectedLocaleTypeId);
5336                    $('#' + instance.uniqueId + '-localeTypeId').trigger("change");
5337                }
5338            }
5339        });
5340
5341        // initialise the "locale ancestor" select2 pulldown and disable it
5342        $('#' + instance.uniqueId + '-ancestorLocaleId').select2({
5343            dropdownCssClass: "localeDropdown",
5344            placeholder: "Select location type first..."
5345        });
5346        
5347        // disable the "locale ancestor" select2 pulldown
5348        $('#' + instance.uniqueId + '-ancestorLocaleId').prop('disabled', true);
5349
5350        // Populate the "location type" pulldown with available locale types for selected measure
5351        //GIS Custom Maps – 2025 CapEx has found
5352        lslocaleSelector.lsupdateLocaleTypeList(instance);
5353
5354        // After selecting an item from the "location type" select2 pulldown we can 
5355        // enable the "locale ancestor" select2 pulldown
5356        $('#' + instance.uniqueId + '-localeTypeId').on('select2:select', function (e) {
5357            $('.localeDropdown').parent().addClass('dropdownContainer');
5358            // user has selected a locale type so enable ancestor select
5359            if ($('#' + instance.uniqueId + '-ancestorLocaleId').prop('disabled')) {
5360                $('#' + instance.uniqueId + '-ancestorLocaleId').prop('disabled', false);
5361            }
5362        });
5363    
5364        // remove focus from all buttons
5365        $('.ui-dialog button').blur();
5366         
5367        $('#' + instance.uniqueId + '-ancestorLocaleId').on('select2:open', function() {
5368            $('.localeDropdown').parent().addClass('dropdownContainer');
5369        });
5370    }
5371
5372    /**
5373     * Initialize the table sorter plugin
5374     */
5375    lslocaleSelector.lsinitTablesorter = function(instance) {
5376        //console.log("At localeselection, in initTablesorter=" + instance.uniqueId);
5377        //console.log($('#' + instance.uniqueId + ' .lsselectionTable').length);
5378        
5379        // Enable sorting and filtering of the locale selection table
5380        $('#' + instance.uniqueId + ' .lsselectionTable').tablesorter({
5381            sortReset: true,
5382            sortRestart: true,
5383            textAttribute: 'data-sort',
5384            widgets: ["filter"],
5385            widgetOptions: {
5386                filter_external: '.search',
5387                filter_defaultFilter: { 1: '~{query}' },
5388                filter_columnFilters: true,
5389                filter_placeholder: { search: 'Start typing to filter results...' },
5390                filter_saveFilters: false,
5391                filter_reset: '.reset'
5392            },
5393            headers: {
5394                'th.smallChart, th.errorLink': {
5395                    sorter: false
5396                }
5397            }
5398        });
5399
5400        
5401        //console.log($('#' + instance.uniqueId + ' .lsselectedTable').length);
5402        // Enable sorting of the selected locales table
5403        $('#' + instance.uniqueId + ' .lsselectedTable').tablesorter({
5404            // Always sort on the first column in ascending order
5405            sortForce: [[0,0]],
5406            sortList: [[0,0]],
5407            headers: {
5408                // Disable first header cell
5409                0: {sorter: false, lockedOrder: 'asc'}
5410            },
5411        });
5412    }
5413
5414    /**
5415     * initLocaleSelect function.
5416     * 
5417     * Opportunity to do anything before the selection panel is displayed, 
5418     * including processing any saved locations
5419     *
5420     */
5421    lslocaleSelector.lsinitLocaleSelect = function(instance) {
5422        console.log('At localeselection, at lsinitLocaleSelect');
5423        var savedLocales = instance.locales;
5424
5425        //console.log('At localeselection, at lsinitLocaleSelect savedLocales=' + JSON.stringify(savedLocales,null,2));
5426        
5427        // add some classes to the selection panel so we can customize it
5428        $('#' + instance.uniqueId).parent().addClass("lslocationSelectPanel");
5429
5430        // disable the select button until the user has selected some locales
5431        if (! instance.allowEmptySelection) {
5432            $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', true);
5433        }
5434
5435        if ($.isEmptyObject(savedLocales)) {
5436            return;
5437        }
5438        
5439        $('.locales-spinner-wrapper').show();
5440
5441        var params = lslocaleSelector.lsbaseMeasureConfig(instance);
5442        params.requiredLocaleIdList = savedLocales;
5443        params.includeAncestors = 1;
5444        //console.log("At localeselection, Calling AJAX at initLocaleSelect");
5445        $.ajax({
5446            url: ClientSite.Extensions.Url().quickUrl('locales', 'indexajax', 'dispatch', {callAction: 'getLocaleListByFilters'}),
5447            type: 'post',
5448            dataType: 'json',
5449            data: params
5450        }).done(function (data) {
5451                var locales = data.localeList || {};
5452                //console.log("At localeselection, at initLocaleSelect locales=====" + JSON.stringify(locales, null, 2))
5453                if (! data.success || $.isEmptyObject(locales)) {
5454                    return;
5455                }
5456
5457                // Add each locale to the selected locales table
5458                $.each(locales, function (index, locale) {
5459                    //console.log("At localeselection, lsinitLocaleSelect locale=" + JSON.stringify(locale,null,2));
5460                    var tr = lslocaleSelector.lsgenerateLocaleSelectItem(locale, false);
5461                    $('#' + instance.uniqueId + ' .lsselectedTable > tbody').append(tr);
5462                });
5463
5464                $('#' + instance.uniqueId + ' .lsselectedTable > tbody').trigger('lslocaleSelector:add');
5465
5466                $('#' + instance.uniqueId +' button.lsremove-all-locations').prop('disabled', false);
5467        }).always(function() {
5468                console.log("At localeselection, Always at initLocaleSelect");
5469                $('.locales-spinner-wrapper').hide();
5470
5471                // if the user has set limitToSingleLocaleType to true and our saved 
5472                // locations are mixed, warn the user
5473                if (lslocaleSelector.lscheckForMixedLocaleTypes(instance) || lslocaleSelector.lscheckForMaxLocalesExceeded(instance) || lslocaleSelector.lscheckForMinLocalesRequired(instance)) {
5474                    instance.preventCancel = true;
5475                }
5476            });
5477    }
5478    
5479    /**
5480     * Attach a tooltip to the specified element with details of the locale's ancestors
5481     * 
5482     * @param {jQuery} element Element to attach the tooltip to
5483     * @param {object} locale Info about the locale and its ancestors
5484     */
5485    lslocaleSelector.lsaddLocaleTooltip = function(element, locale) {
5486        //console.log("At localeselection, Entering lsaddLocaleTooltip");
5487        if ($.isEmptyObject(locale.ancestorList || [])) {
5488            console.log("At localeselection, Empty locale ancestorList");
5489            element.attr('title', '');
5490            return;
5491        }
5492        
5493        var ancestors = $();
5494        $.each(locale.ancestorList, function(i, ancestor) {
5495            ancestors = ancestors.add(
5496                $('<li>')
5497                    .append($('<strong>').text(ancestor.localeTypeName))
5498                    .append(': ' + ancestor.localeName)
5499            );
5500        });
5501
5502        var tooltip = $('<div>')
5503            .text(locale.localeTypeName + ': ' + locale.localeName + ' is within:')
5504            .append($('<ul>').append(ancestors));
5505        //console.log("At localeselection, tooltip.html=" + tooltip.html());
5506        element.attr('title', tooltip.html());
5507    }
5508
5509    /**
5510     * Remove a locale selector instance from the instances array
5511     */
5512    lslocaleSelector.lsremoveInstance = function(uniqueId) {
5513        delete lslocaleSelector.lsinstances[uniqueId];
5514    }
5515
5516    /**
5517     * Remove all locale selector instances from the instances array
5518     */
5519    lslocaleSelector.lsresetInstances = function() {
5520        lslocaleSelector.lsinstances = {};
5521    }
5522
5523    /**
5524     * If a user if limited to a single locale type and they try select a new locale type warn them
5525     * that their existing locale selection will be removed if they proceed.
5526     */
5527    lslocaleSelector.lslocationChangeWarning = function(e) {
5528        uniqueId =  e.target.id.split('-')[0];
5529        instance = lslocaleSelector.lsinstances[uniqueId];
5530        
5531        // If their selection table is currently empty, no need to warn them
5532        if ($('#' + uniqueId + ' .lsselectedTable > tbody tr').length && instance.preventCancel) {
5533            var retCode = confirm("2 Selecting a new location type will remove all your currently included locations. Do you want to process?");
5534            if (retCode) {
5535                $('#' + uniqueId + ' .lsselectedTable > tbody')
5536                    .empty()
5537                    .trigger('lslocaleSelector:remove');
5538            }
5539            else {
5540                // user cancel so prevent any further select events
5541                e.preventDefault();
5542            }
5543        }
5544    }
5545    
5546
5547    /**
5548     * lsinitDialog function.
5549     * 
5550     * Initialize our jQuery location selection dialog. Note, this does not open the dialog
5551     *
5552     */
5553    lslocaleSelector.lsinitDialog = function(instance) {
5554        $('#' + instance.uniqueId + '.lslocationSelectPanelContent').dialog({
5555            autoOpen: false, // initially hide the dialog
5556            width: 800,
5557            title: 'Choose location(s) to include',
5558            buttons: [
5559                {
5560                    text: "Cancel",
5561                    "class": 'btn btn-sm btn-secondary lsclose-button leftButton',
5562                    click: function() {
5563                        $(this).dialog("close");
5564                        
5565                        // remove settings from instances array
5566                        lslocaleSelector.lsremoveInstance(instance.uniqueId);
5567                    }
5568                },
5569                {
5570                    text: "Select",
5571                    "class": 'btn btn-sm btn-secondary lsselect-button',
5572                    click: function() {
5573                        lslocaleSelector.lsselectLocations(instance);
5574                        $(this).trigger('localeSelector:save');
5575                        
5576                        // remove settings from instances array
5577                        lslocaleSelector.lsremoveInstance(instance.uniqueId);
5578                    }
5579                }
5580            ],
5581            open: function(event, ui) {
5582                lslocaleSelector.lsinitLocaleSelect(instance);
5583            },
5584            close: function(event, ui) {
5585                // remove the cloned selection panel from the DOM
5586                $('#' + instance.uniqueId).remove();
5587                
5588                // remove settings from instances array
5589                lslocaleSelector.lsremoveInstance(instance.uniqueId);
5590            }
5591        });
5592    }
5593
5594
5595
5596    /**
5597     * cloneSelectionPanel function.
5598     * 
5599     * Clone our locale selection dialog and set various id's etc.
5600     *
5601     */
5602    lslocaleSelector.lscloneSelectionPanel = function(instance) {
5603        //console.log('lscloneSelectionPanel', instance.uniqueId);
5604        if (instance.panelContainer) {
5605            $('#lslocationSelect-template').clone().attr('id', instance.uniqueId).appendTo(instance.panelContainer);
5606        }
5607        else {
5608            $('#lsocationSelect-template').clone().attr('id', instance.uniqueId).insertAfter('#lslocationSelect-template');
5609        }
5610        
5611        instance['limitToSingleLocaleType'] ? $('.lslocalesRestricted').show() : $('.lslocalesRestricted').hide();
5612
5613        if (instance.maxLocales > 0) {
5614            $('#' + instance.uniqueId + ' span.lsmaxLocales').text(instance.maxLocales);
5615            $('.lsmaxLocalesNotice').show();
5616        }
5617        else {
5618            $('.lsmaxLocalesNotice').hide();
5619        }
5620
5621        if (instance.minLocales > 0) {
5622            $('#' + instance.uniqueId + ' span.lsminLocales').text(instance.minLocales);
5623            $('.lsminLocalesNotice').show();
5624        }
5625        else {
5626            $('.lsminLocalesNotice').hide();
5627        }
5628        $('#' + instance.uniqueId + ' select.lsselectLocaleType').attr('id', instance.uniqueId + '-localeTypeId');
5629        $('#' + instance.uniqueId + ' select.lsselectAncestorLocale').attr('id', instance.uniqueId + '-ancestorLocaleId');
5630
5631        $('#' + instance.uniqueId + '  .lsnav-tabs > .lsnav-item > a').each(function() {
5632            $(this).attr('href', '#' + instance.uniqueId + '-' + $(this).attr('id'));
5633        });
5634        
5635        $('#' + instance.uniqueId + '  .lstab-content > .lstab-pane').each(function() {
5636            $(this).attr('id', instance.uniqueId + '-' + $(this).attr('id'));
5637        });
5638        
5639        // workaround for map load
5640        lslocaleSelector.lsloadMap(instance,function(){
5641            try{
5642                //console.log("At localeselection, Completes loadMap dude");
5643                const placeholder = $(`#${instance.uniqueId} .map_placeholder`);
5644
5645                if (placeholder.length > 0) {
5646                    // Element exists and is available
5647                    //console.log('At localeselection, Element found:', placeholder);
5648                } else {
5649                    // Element doesn't exist
5650                    //console.log('At localeselection, Element not found');
5651                }
5652
5653                // Set up MutationObserver to detect when #yyy is loaded
5654                const observer = new MutationObserver((mutations) => {
5655                    //console.log('At localeselection, Mutation detected:', mutations);
5656                    console.log('At localeselection, Mutation detected');
5657                    if (placeholder[0].querySelector('#lsmapCodeLoaded')) {
5658                        observer.disconnect(); // Stop observing
5659                        console.log("At localeselection, map_placeholder fully loaded! #lsmapCodeLoaded exists.");
5660                        const lsmapCodeLoaded = $(`#${instance.uniqueId} #lsmapCodeLoaded`);
5661                        lsmapCodeLoaded.attr('data-info', 'yes');
5662
5663                        // STEP 1: Trigger map initialization
5664                        console.log("At localeselection, Triggering map:initialize for:", instance.uniqueId);
5665                        // Trigger custom event on document
5666                        $(document).trigger('map:initialize', {
5667                            instanceId: instance.uniqueId
5668                        });
5669                         // STEP 2: Set up backup confirmation listener
5670                        $(document).one('map:ready', function(e, data) {
5671                            if (data.instanceId === instance.uniqueId) {
5672                                console.log("At localeselection, Map confirmed ready for:", instance.uniqueId);
5673                            }
5674                        });
5675                
5676                        // STEP 3: Safety timeout
5677                        setTimeout(function() {
5678                            console.log("At localeselection, Map ready timeout for:", instance.uniqueId);
5679                        }, 10000);
5680                    }
5681                    else {
5682                        console.log("At localeselection, map_placeholder NOT fully loaded!");
5683                    }
5684                });
5685
5686                // Start observing the placeholder for DOM changes
5687                observer.observe(placeholder[0], { 
5688                    childList: true,    // Watch for direct child additions/removals
5689                    subtree: true,      // Watch all descendants (needed for nested #yyy)
5690                    attributes: true,      // Also watch for attribute changes
5691                    attributeFilter: ['id', 'class'] // Specific attributes to watch
5692                });
5693                
5694            } catch(error){
5695                console.error("At localeselection, failed after loadMap error");
5696            }
5697            //console.log("At localeselection, Exit loadMap dude");
5698        });
5699    }
5700
5701    //function loadMap() {
5702    lslocaleSelector.lsloadMap = function(instance, callback) {
5703        console.log("At localeselection, debug loading map");
5704           
5705           
5706        $.ajax({
5707            url: "/locales/indexajax/dispatch?callAction=getLocaleSelectionMap",
5708            dataType: "json",
5709            data: {
5710                mapLocales: {"2":{"localeType":"County","localeIds":{"2274":"Jackson","2276":"Josephine"}}}            },
5711            success: function(obj) {
5712                //console.log("At localeselection, obj.html=" + obj.html);
5713                $('#' + instance.uniqueId + " .map_placeholder").empty().append(obj.html);
5714                callback();
5715            }
5716        });
5717    }
5718
5719    /**
5720     * checkForMinLocalesRequired function.
5721     * 
5722     * Check for too few selected locales
5723     * 
5724     */
5725    lslocaleSelector.lscheckForMinLocalesRequired = function(instance) {
5726        if (instance.minLocales > 0) {
5727            var tableClass = '.lsselectedTable';
5728            var selectedLocales = $( '#' + instance.uniqueId + ' ' + tableClass + ' tbody tr').length;
5729            if (selectedLocales < instance.minLocales) {
5730
5731                $('#' + instance.uniqueId + ' .lsminLocalesRequired').show();
5732                // disable the select button
5733                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', true); 
5734                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsclose-button').prop('disabled', true);
5735            }
5736            else {
5737                // remove the different location type warning
5738                $('#' + instance.uniqueId + ' .lsminLocalesRequired').hide();
5739                // enable the select button
5740                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', false); 
5741                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsclose-button').prop('disabled', false); 
5742            }
5743        }
5744    }
5745
5746    /**
5747     * checkForMaxLocalesExceeded function.
5748     * 
5749     * Check for too many selected locales
5750     * 
5751     */
5752    lslocaleSelector.lscheckForMaxLocalesExceeded = function(instance) {
5753        var maxLocalesExceeded = false;  
5754        if (instance.maxLocales > 0) {
5755            var tableClass = '.lsselectedTable';
5756            var selectedLocales = $( '#' + instance.uniqueId + ' ' + tableClass + ' tbody tr').length;
5757            if (selectedLocales > instance.maxLocales || selectedLocales == 0) {
5758                if (selectedLocales > instance.maxLocales) {
5759                    maxLocalesExceeded = true;
5760                    $('#' + instance.uniqueId + ' .lslimitToMaxLocales').show();
5761                }          
5762                // disable the select button
5763                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', true); 
5764                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsclose-button').prop('disabled', true);
5765            }
5766            else {
5767                // remove the different location type warning
5768                $('#' + instance.uniqueId + ' .lslimitToMaxLocales').hide();
5769                // enable the select button
5770                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', false); 
5771                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsclose-button').prop('disabled', false); 
5772            }
5773        }
5774        else {
5775            // enable the select button
5776            $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', false); 
5777            $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsclose-button').prop('disabled', false);
5778        }
5779        return maxLocalesExceeded;
5780    }
5781    
5782    /**
5783     * checkForMixedLocaleTypes function.
5784     * 
5785     * Check for mixed locale types in the '.lsselectedTable' table
5786     *
5787     * @param string, uniqueId, specifies the instance of our selection panel
5788     * @param string, tableClass, either .lsselectionTable or .lsselectedTable
5789     * 
5790     */
5791    lslocaleSelector.lscheckForMixedLocaleTypes = function(instance) {
5792        var mixedLocales = false;
5793        var tableClass = '.lsselectedTable';
5794
5795        if (instance.limitToSingleLocaleType) {
5796            var localeTypeId = null; 
5797            var localeTypesDiffer = false;
5798
5799            $( '#' + instance.uniqueId + ' ' + tableClass + ' tbody tr').each(function() {
5800                if (!localeTypeId) {
5801                    localeTypeId = $(this).data('locale-type-id');
5802                }
5803                else if (localeTypeId != $(this).data('locale-type-id')) {
5804                    localeTypesDiffer = true;
5805                    return;
5806                }
5807                
5808                localeTypeId = $(this).data('locale-type-id');
5809            });
5810
5811            if (localeTypesDiffer) {
5812                $('#' + instance.uniqueId + ' .lslimitToSingleLocaleType').show();
5813                
5814                // disable the select button
5815                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', true); 
5816                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsclose-button').prop('disabled', true);
5817                mixedLocales = true;
5818                instance.singleSelectedLocaleTypeId = null;
5819            }
5820            else {
5821                // remove the different location type warning
5822                $('#' + instance.uniqueId + ' .lslimitToSingleLocaleType').hide();
5823                
5824                // enable the select button
5825                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', false); 
5826                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsclose-button').prop('disabled', false); 
5827
5828                // save the locale type so  we can warn users is they attempt to select a different locale type
5829                instance.singleSelectedLocaleTypeId = localeTypeId;
5830            }
5831        }
5832        else {
5833            // enable the select button
5834            $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', false); 
5835            $('#' + instance.uniqueId).closest('lslocationSelectPanel').find('button.lsclose-button').prop('disabled', false);
5836        }
5837
5838        return mixedLocales;
5839    }
5840
5841    /**
5842     * Returns the number id portion of a hyphen delimited string with the id at the end.
5843     * For example, an input of "locale-1234" returns 1234
5844     *
5845     * @param {string} input Hyphenated string
5846     * @return {int}
5846 Numeric id, or 0 if input is invalid
5847     */
5848    lslocaleSelector.lsextractId = function(input) {
5849        var id = input ? input.split('-').slice(-1)[0] : 0;
5850        return parseInt(id) || 0;
5851    };
5852    
5853    /**
5854     * open function.
5855     * 
5856     * Store initial setting in our settings object. This will override any settings provided via the partial (PHP land)
5857     *
5858     * Find all the ancestors of this single localeId and populate tooltip
5859     * @param {Object} settings:
5860     *      measureTypeId: indicator (1) or demographics (2). Defaults to 1,
5861     *      measureId: Indicator or indicator measure Id. Defaults to 0,
5862     *      localeCallback: javascript callback function to process selected locales. Defaults to defaultLocaleCallback(),
5863     *      locales: array of saved locales. Defaults to null,
5864     *      panelContainer: Id or class of where you would like to inline the location selection widget. (requires '#' or '.'). Defaults to null,
5865     *      uniqueId: a unique Id to differentiate different instances,
5866     *      limitToSingleLocaleType: Boolean to indicate that we are restricted to selecting locales of a single type only. Defaults to false,
5867     *      preventCancel: Used internally. If limitToSingleLocaleType is set to true & saved locales of a mixed type are loaded then prevent the user from cancelling. Defaults to false,
5868     *      singleSelectedLocaleTypeId: Used internally. If only locales of a single type are selected, then keep track of the locale type id. Defaults to null,
5869     *      mappable: Indicates whether the locales will be used for mapping. Defaults to false
5870     *      allowEmptySelection: Indicates whether you can save when no locales are selected. Defaults to false
5871     * @return void
5872     */
5873    lslocaleSelector.lsopen = function(settings = null) {
5874        console.log("At localeselection, In localeselection.phtml lslocaleSelector");
5875        if (!settings.uniqueId) {
5876            throw new Error('A unique id is required for the locale selector');
5877        }
5878        //console.log("At localeselection, In localeselection.phtml lslocaleSelector settings.uniqueId=" + settings.uniqueId);
5879        if (lslocaleSelector.lsinstances[settings.uniqueId]) {
5880            // instance already exists
5881            return;
5882        }
5883        //console.log("At localeselection, In localeselection.phtml lslocaleSelector continue" );
5884        lslocaleSelector.lsinstances[settings.uniqueId] = {};        
5885        
5886        lslocaleSelector.lsinstances[settings.uniqueId] = {
5887            measureTypeId: settings.measureTypeId ? settings.measureTypeId : 1,
5888            measureId: settings.measureId ? settings.measureId : 0,
5889            measureChildIdList: settings.measureChildIdList ? settings.measureChildIdList : '',
5890            measureChildTypeId: settings.measureChildTypeId ? settings.measureChildTypeId : 0,
5891            localeCallback: settings.localeCallback ? settings.localeCallback : lsdefaultLocaleCallback,
5892            locales: settings.locales ? settings.locales : null,
5893            requiredLocaleIdList: settings.requiredLocaleIdList ? settings.requiredLocaleIdList : null,
5894            panelContainer: settings.panelContainer ? settings.panelContainer : null,
5895            uniqueId: settings.uniqueId,
5896            limitToSingleLocaleType: settings.limitToSingleLocaleType ? settings.limitToSingleLocaleType : false,
5897            maxLocales: settings.maxLocales ? settings.maxLocales : 0,
5898            minLocales: settings.minLocales ? settings.minLocales : 0,
5899            preventCancel: false,
5900            singleSelectedLocaleTypeId: null,
5901            singleSelectedLocaleText: null,
5902            mappable: settings.mappable || false,
5903            allowEmptySelection: settings.allowEmptySelection || false,
5904            localeTypeCallVals : settings.localeTypeCallVals ? settings.localeTypeCallVals : null,
5905            localeListCallVals : settings.localeListCallVals ? settings.localeListCallVals : null,
5906        };
5907        //console.log("At localeselection, settings.panelContainer="  + settings.panelContainer);
5908        
5909        if (settings.panelContainer) {
5910            // we are opening up the locale selector with a div, ie. not via a dialog
5911            lslocaleSelector.lscloneSelectionPanel(lslocaleSelector.lsinstances[settings.uniqueId]);
5912            $('#' + settings.uniqueId + '.lslocationSelectPanelContent').show();
5913            //console.log("At localeselection, show " + '#' + settings.uniqueId + '.lslocationSelectPanelContent');
5914            // show the cancel and select buttons
5915            $('#' + settings.uniqueId + '.lslocationSelectPanelContent .lspanel-select-buttons').show();
5916            //console.log("At localeselection, show " + '#' + settings.uniqueId + '.lslocationSelectPanelContent');
5917            //GIS Custom Maps – 2025 CapEx
5918            $('#' + settings.uniqueId + '.lslocationSelectPanelContent .lspanel-select-buttons').removeClass('d-none');
5919
5920            //GIS Custom Maps – 2025 CapEx
5921            var lssearchMode = $('#lssearchMode').val();
5922            lslocaleSelector.setLabel('lslbl-1');
5923            lslocaleSelector.setLabel('lslbl-2');
5924            //console.log("At localeselection, lssearchMode=" + JSON.stringify(lssearchMode, null, 2));
5925            if(lssearchMode=='singleMode'){
5926                $('#' + settings.uniqueId + '.lslocationSelectPanelContent .lsselectedLocations').addClass('d-none');
5927                $('#' + settings.uniqueId + '.lslocationSelectPanelContent .leftContent').removeClass('col-sm-6');
5928                $('#' + settings.uniqueId +' button.lsremove-all-locations').addClass('d-none'); 
5929                $('#' + settings.uniqueId +' button.lsadd-all-locations').addClass('d-none'); 
5930            }
5931            
5932            lslocaleSelector.lsinitLocaleSelect(lslocaleSelector.lsinstances[settings.uniqueId]);
5933            
5934            // Handle events for the select and cancel buttons but first
5935            // check to see whether there already exists an event handler
5936            $(document)
5937                .off('click.nonce', '#' + settings.uniqueId + ' button.lsselect-button')
5938                .on('click.nonce', '#' + settings.uniqueId + ' button.lsselect-button', function() {
5939                    var uniqueId = $(this).closest('.lslocationSelectPanelContent').attr('id');
5940                    lslocaleSelector.lsselectLocations(lslocaleSelector.lsinstances[uniqueId]);
5941
5942                    // Save the locale type Id away, we'll use it in the measure select
5943                    //if ($('#lsselectLocaleTypeId').length) {
5944                      //  $('#bivariateLocaleTypeId').val($('#scatterplot_locale_selector-localeTypeId').val()).trigger('change');
5945                    //}
5946
5947                    /*To prevent duplicate selected options */
5948                    var lstargetId= $('#lstargetId').val();
5949                    //console.log("At localeselection, zzz lstargetId=" + lstargetId);
5950                    var nameAttr = $('#' + lstargetId ).attr('name');
5951                    //console.log("At localeselection, zzz nameAttr=" + nameAttr);
5952                    var $select = $('select[name="' + nameAttr + '"]');
5953                    /*
5954                    console.log("At localeselection, BEFORE zzz Options:", $select.find('option').map(function() {
5955                      return {
5956                        value: this.value,
5957                        text: $(this).text(),
5958                        selected: this.selected
5959                      };
5960                    }).get());*/
5961
5962                    var seenValues = {};
5963                    $select.find('option').each(function() {
5964                        if (this.selected) {
5965                            if (seenValues[this.value]) {
5966                                //$(this).prop('selected', false);
5967                                $(this).remove();
5968                                return;
5969                            }
5970                            // Mark this value as seen
5971                            seenValues[this.value] = true;
5972                        }
5973                    });
5974                    //$select.trigger('change');
5975                    $select.trigger('change.select2');
5976					/*
5977                    console.log("At localeselection, AFTER zzz Options:", $select.find('option').map(function() {
5978                      return {
5979                        value: this.value,
5980                        text: $(this).text(),
5981                        selected: this.selected
5982                      };
5983                    }).get());
5984                    */
5985
5986                    /* to handle form submit if required */
5987                    var lsisSubmit = $('#lsisSubmit').val();
5988                    var lsinputFormId= $('#lsinputForm').val();
5989                    //console.log("At localeselection, ....lsisSubmit=" + lsisSubmit);
5990                    //console.log("At localeselection, ....lsinputFormId=" + lsinputFormId);
5991                    
5992                    /* to handle quickUrl if required */
5993					
5994                    //console.log("At localeselection, seenValues=" + JSON.stringify(seenValues,null,2));
5995                    var localeIdVal='';
5996                    Object.keys(seenValues).forEach(key => {
5997                      localeIdVal=key;
5998                    });
5999                    var lsquickUrl = $('#lsquickUrl').val();
6000                    
6001                    //console.log("At localeselection, will this continue?");
6002
6003                    var lscallbackAdvEventId= $('#lscallbackAdvEvent').val();
6004                    if(lscallbackAdvEventId!=null && lscallbackAdvEventId!=''){
6005                        if ($('#' + lscallbackAdvEventId).is(":visible")) {
6006                            //console.log("At localeselection, lscallbackAdvEventId is visible lscallbackAdvEventId=" + lscallbackAdvEventId);
6007                            $('#' + lscallbackAdvEventId).trigger('click', [{lslocaleId: localeIdVal,lsisSubmit: lsisSubmit,lsinputFormId:lsinputFormId,lsquickUrl:lsquickUrl,lstargetId:lstargetId}]);
6008                        } else {
6009                            //console.log("At localeselection, lscallbackAdvEventId is not visible");
6010                        }
6011                    }else{
6012                        //console.log("At localeselection, lscallbackAdvEventId is null");
6013                    }
6014                    
6015                    // now remove the panel from the DOM
6016                    $('#' + uniqueId).parent().removeClass('lslocationSelectPanel');
6017                    $('#' + uniqueId)
6018                        .trigger('lslocaleSelector:close')
6019                        .remove();
6020                    
6021                    // remove settings from instances array
6022                    lslocaleSelector.lsremoveInstance(uniqueId);
6023                     
6024                    /*dialogId is passed dynamically */
6025                     const dialogId= $('#lsinputDialog').val();
6026                     //console.log("At localeselection, Before close the dialog, find out its id is: " + dialogId);
6027                     $('#' + dialogId).dialog("destroy");
6028                     $(".ui-widget-overlay").removeClass('modal-opened');
6029                });
6030            $(document)
6031                .off('click.nonce', '#' + settings.uniqueId + ' button.lsclose-button')
6032                .on('click.nonce', '#' + settings.uniqueId + ' button.lsclose-button', function() {
6033                    var uniqueId = $(this).closest('.lslocationSelectPanelContent').attr('id');
6034
6035                    /*This code to prevent locale -999 being shown at the select form field */
6036                     var lstargetId= $('#lstargetId').val();
6037                     //console.log("At localeselection, Close lstargetId=" + lstargetId);
6038                     var nameAttr = $('#' + lstargetId ).attr('name');
6039                     //console.log("At localeselection, Close nameAttr=" + nameAttr);
6040                     var $select = $('select[name="' + nameAttr + '"]');
6041
6042                     $select.find('option').each(function() {
6043                        //if (this.value == -999 && this.selected) {
6044                        if (this.value < 0 && this.selected) {
6045                            //console.log("At localeselection, lsls Found selected -ve option. Text:", $(this).text());
6046                            $(this).prop('selected', false);  // This deselects it
6047                            //console.log("At localeselection, Deselected. Now selected:", this.selected); // Should log false
6048                        }
6049                    });
6050                     $select.trigger('change');
6051                     /*
6052                     console.log("At localeselection, Close Options:", $select.find('option').map(function() {
6053                      return {
6054                        value: this.value,
6055                        text: $(this).text(),
6056                        selected: this.selected
6057                      };
6058                    }).get());*/
6059        
6060                    // remove the panel from the DOM
6061                    $('#' + uniqueId).parent().removeClass('lslocationSelectPanel');
6062                    $('#' + uniqueId)
6063                        .trigger('lslocaleSelector:close')
6064                        .remove();
6065                    
6066                    // remove settings from instances array
6067                    lslocaleSelector.lsremoveInstance(uniqueId);
6068
6069                    //GIS Custom Maps – 2025 CapEx
6070                     const dialogId= $('#lsinputDialog').val();
6071                     //console.log("At localeselection, Before close the dialog, find out its id is: " + dialogId);
6072                     $('#' + dialogId).dialog("destroy");
6073                     $(".ui-widget-overlay").removeClass('modal-opened');
6074                     
6075                });
6076        }
6077        else {
6078            lslocaleSelector.lscloneSelectionPanel(lslocaleSelector.lsinstances[settings.uniqueId]);
6079            lslocaleSelector.lsinitDialog(lslocaleSelector.lsinstances[settings.uniqueId]);
6080            $('#' + settings.uniqueId + '.lslocationSelectPanelContent').show().dialog('open');
6081        }
6082        lslocaleSelector.lsinitTablesorter(lslocaleSelector.lsinstances[settings.uniqueId])
6083        lslocaleSelector.lspopulatePulldowns(lslocaleSelector.lsinstances[settings.uniqueId]);
6084        //console.log('At localeselection, Before Event received! 3');
6085        $('#' + settings.uniqueId).trigger('lslocaleSelector:open');
6086        //console.log('At localeselection, After Event received! 5');
6087        $('#' + settings.uniqueId + " #lslistLocaleSelector").click(); 
6088    }
6089
6090
6091    $(document).ready(function() {
6092        
6093        /**
6094         * Initialise jQuery tooltips
6095         */
6096        $(document).tooltip({
6097            content: function() {
6098                return $(this).attr('title');
6099            },
6100            classes: {"ui-tooltip": "locale-tooltips"}
6101        });
6102
6103
6104        /**
6105         * If the locale filter list pulldown changes, update the locales in the selection table
6106         */
6107        $(document).on('change', '.lsselectAncestorLocale', function() {
6108            var uniqueId = $(this).closest('.lslocationSelectPanelContent').attr('id');
6109            $('#' + uniqueId + ' #lsselectedLocationInText').empty();
6110            lslocaleSelector.lsupdateLocaleList(lslocaleSelector.lsinstances[uniqueId]);
6111        });
6112        
6113                        
6114        /**
6115         * If the locale type changes, update the locale filter list pulldown
6116         */
6117        $(document).on('change', '.lsselectLocaleType', function() {
6118            //console.log("At localeselection, culprit? ..............................");
6119            var uniqueId = $(this).closest('.lslocationSelectPanelContent').attr('id');
6120            var instance = lslocaleSelector.lsinstances[uniqueId];
6121            //console.log("At localeselection, instance.uniqueId" + instance.uniqueId);
6122            $('#' + instance.uniqueId + '-ancestorLocaleId').val(0);
6123            $('#' + uniqueId + ' #lsselectedLocationInText').empty();
6124            lslocaleSelector.lsupdateAncestorLocaleList(instance);
6125            //$('#lsselectLocaleTypeId').val($(this).val());
6126        });
6127
6128
6129        /**
6130         * Handle clicks to locations on the left selection table.
6131         * On clicking a location it's moved to the right selected table.
6132         * The clicked location still remains in the left table, only its disabled
6133         */
6134        $(document).on('click', '.lsselectionTable tbody tr', function() {
6135            //console.log('At localeselection, on click lsselectionTable');
6136            var from='';
6137            const myParam = $(this).data('myParam');
6138            //alert("At localeselection, myParam=" + JSON.stringify(myParam,null,2));
6139            /*
6140            if (myParam?.from != null) {
6141              from = myParam.from;
6142            }*/
6143            
6144            console.log("Raw data-myParam attribute:", $(this).data('myParam'));
6145            console.log("Parsed myParam:", myParam);
6146            console.log("Type of myParam:", typeof myParam);
6147
6148            if(myParam && myParam.from){
6149              from=myParam.from;
6150              console.log("from value:", from, "type:", typeof from);
6151            }
6152
6153            console.log("Final from:==="+from+"===");
6154            //console.log('At localeselection, from=' +  from);
6155
6156            var uniqueId = $(this).closest('.lslocationSelectPanelContent').attr('id');
6157            var localeClass = $(this).find('td').attr('class');
6158            var localeId = lslocaleSelector.lsextractId(localeClass);
6159
6160            // Don't move the locale if it's already been selected
6161            if (lslocaleSelector.lsisHandpickedLocaleSelected(uniqueId, localeClass)) {
6162                return;
6163            }
6164            
6165            //GIS Custom Maps – 2025 CapEx:For Single Location Remove 1st
6166            var lssearchMode = $('#lssearchMode').val();
6167            //console.log("At localeselection, lssearchMode=" + JSON.stringify(lssearchMode, null, 2));
6168            if(lssearchMode=='singleMode'){
6169                $('#' + uniqueId + ' .lsselectedTable > tbody').empty().trigger('lslocaleSelector:remove');
6170            }
6171
6172             // disable remove all button
6173             $('#' + uniqueId + ' .lsremove-all-locations').prop('disabled', true);
6174             //remove move-disabled class for tr
6175            
6176            if(lssearchMode=='singleMode'){
6177                $('#' + uniqueId +' .lsselectionTable tbody tr').removeClass('move-disabled');
6178            }
6179            
6180            $(this).clone()
6181                .appendTo('#' + uniqueId +' .lsselectedTable tbody')
6182                .attr('title', $(this).data('uiTooltipTitle'))  // Copy the jQuery Tooltip data
6183                .removeAttr('aria-describedby')  // Was dynamically assigned to source element by jQuery Tooltip
6184                .find('i')
6185                    .removeClass('fa-arrow-right')
6186                    .addClass('fa-arrow-left');
6187            $('#' + uniqueId +' .lsselectedTable tbody').trigger('lslocaleSelector:add')
6188            $(this).closest('tr').addClass('move-disabled');
6189            //jjjj
6190            $('#' + uniqueId + ' .lsselectionTable td.' + localeClass).closest('tr').addClass('move-disabled');
6191
6192            // enable and disable various buttons
6193            if ($('#' + uniqueId +' button.lsremove-all-locations').is(':disabled')) {
6194                $('#' + uniqueId +' button.lsremove-all-locations').prop('disabled', false); 
6195            }
6196            if (!$('#' + uniqueId +' .lsselectionTable tbody tr').not('.move-disabled').length) {
6197                $('button.lsadd-all-locations').prop('disabled', true);
6198            }
6199            if ($('#' + uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').is(':disabled')) {
6200                $('#' + uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', false); 
6201            }
6202            
6203            if ($('#' + uniqueId).closest('.lslocationSelectPanel').find('button.lsclose-button').is(':disabled')) {
6204                $('#' + uniqueId).closest('.lslocationSelectPanel').find('button.lsclose-button').prop('disabled', false); 
6205            }
6206            //GIS Custom Maps – 2025 CapEx
6207            var lssearchMode = $('#lssearchMode').val();
6208            //console.log("At localeselection, lssearchMode=" + JSON.stringify(lssearchMode, null, 2));
6209            if(lssearchMode=='singleMode'){
6210                $('#' + uniqueId + '.lslocationSelectPanelContent .lspanel-select-buttons').removeClass('d-none');
6211            }
6212
6213            // check for mixed location types
6214            lslocaleSelector.lscheckForMixedLocaleTypes(lslocaleSelector.lsinstances[uniqueId]);
6215            lslocaleSelector.lscheckForMaxLocalesExceeded(lslocaleSelector.lsinstances[uniqueId]);
6216            lslocaleSelector.lscheckForMinLocalesRequired(lslocaleSelector.lsinstances[uniqueId]);
6217            
6218            //GIS Custom Maps – 2025 CapEx localeId
6219            if(from=='map'){
6220                console.log("At localeselection, No Need to trigger map update");
6221            }else{
6222                console.log("At localeselection, Need to trigger map update");
6223
6224                var $targetElement = $('#' + uniqueId).find('#lsselectedLocaleIdData');
6225                //var event = jQuery.Event('lsselectedLocaleIdDataChange');
6226                //event.actionData = 'add';
6227                var event = $.Event('lsselectedLocaleIdDataChange', {
6228                    actionData: 'add',
6229                    bubbles: false // Prevent bubbling to document
6230                });
6231                var localeIds = [];
6232                localeIds.push(localeId);
6233                $targetElement.attr('data-info', JSON.stringify(localeIds)).trigger(event);
6234            }
6235            
6236
6237            //var localeList = [];
6238            var localeDisplayNameList = [];
6239
6240            $('#' + uniqueId + ' .lsselectedTable tbody td').each(function(index, locale) {
6241                //localeList.push(parseInt($(locale).attr('class').split('-')[1]));
6242                localeDisplayNameList.push($(locale).text());
6243            });
6244
6245            var combinedText = '';
6246            
6247            localeDisplayNameList.forEach((item, index) => {
6248                if(index==0){
6249                    combinedText += item; // or use `\n` for newline instead of space
6250                }else{
6251                     combinedText += ', ' + item.split(": ")[1]; //
6252                }
6253            });
6254            var locText = localeDisplayNameList.length === 1 ? 'Location' : 'Locations';
6255
6256            $('#' + uniqueId + ' #lsselectedLocationInText').empty().html('<label class="lslbl-2"><strong>
6256Selected ' + locText + ': </strong><span id="locDisplay">' + combinedText + '</span></label>');
6257            
6258            
6259        });
6260
6261
6262        /**
6263         * Handle clicks to locations on the right selected table.
6264         * On clicking a location it is moved to the left selection table.
6265         * The clicked location is removed from the right table and becomes enabled in the left table.
6266         */
6267        $(document).on('click', '.lsselectedTable tbody tr', function()  {
6268            var from='';
6269            const myParam = $(this).data('myParam');
6270            if(myParam && myParam.from){
6271              from=myParam.from;
6272            }
6273            console.log('At localeselection, from=' +  from);
6274
6275            var uniqueId = $(this).closest('.lslocationSelectPanelContent').attr('id');
6276            var localeClass = $(this).find('td').attr('class');
6277            var localeId = lslocaleSelector.lsextractId(localeClass);
6278            var tooltipId = $(this).attr('aria-describedby');
6279            var instance = lslocaleSelector.lsinstances[uniqueId];
6280            
6281            // remove the selected locale entity and the jQuery tooltip
6282            $(this).remove();
6283            $('#' + uniqueId + ' .lsselectedTable tbody').trigger('lslocaleSelector:remove');
6284            $('td.' + localeClass).closest('tr').removeClass('move-disabled');
6285            $('#' + tooltipId).remove();
6286            
6287            if ($('#' + uniqueId + ' .lsadd-all-locations').prop('disabled') && $('#' + uniqueId + ' .lsselectionTable tbody tr').length) {
6288                $('#' + uniqueId + ' .lsadd-all-locations').prop('disabled', false); 
6289            }
6290
6291            // enable and disable various buttons
6292            if (!$('#' + uniqueId + ' .lsselectedTable tbody tr').length) {
6293                // the selected table is empty so disable the select and remove all buttons
6294                if (! instance.allowEmptySelection) {
6295                    $('#' + uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', true);
6296                }
6297                $('#' + uniqueId + ' .lsremove-all-locations').prop('disabled', true);                
6298                instance.singleSelectedLocaleTypeId = null;
6299            }
6300            else {
6301                // check for mixed location types
6302                lslocaleSelector.lscheckForMixedLocaleTypes(instance);
6303                lslocaleSelector.lscheckForMaxLocalesExceeded(instance);
6304                lslocaleSelector.lscheckForMinLocalesRequired(instance);
6305            }
6306
6307            //GIS Custom Maps – 2025 CapEx localeId
6308            if(from=='map'){
6309                console.log("At localeselection, remove No Need to trigger map update");
6310            }else{
6311                console.log("At localeselection, remove Need to trigger map update");
6312                var $targetElement = $('#' + uniqueId).find('#lsselectedLocaleIdData');
6313                //var event = jQuery.Event('lsselectedLocaleIdDataChange');
6314                //event.actionData = 'remove';
6315                var event = $.Event('lsselectedLocaleIdDataChange', {
6316                    actionData: 'remove',
6317                    bubbles: false // Prevent bubbling to document
6318                });
6319                var localeIds = [];
6320                localeIds.push(localeId);
6321                $targetElement.attr('data-info', JSON.stringify(localeIds)).trigger(event);
6322
6323                //$('#' + uniqueId + ' #lsselectedLocaleIdData').attr('data-info', JSON.stringify(localeId)).trigger('lsselectedLocaleIdDataChange');
6324            }
6325
6326            //GIS Custom Maps – 2025 CapEx
6327            //var localeList = [];
6328            var localeDisplayNameList = [];
6329
6330            $('#' + uniqueId + ' .lsselectedTable tbody td').each(function(index, locale) {
6331                //localeList.push(parseInt($(locale).attr('class').split('-')[1]));
6332                localeDisplayNameList.push($(locale).text());
6333            });
6334
6335            var combinedText = '';
6336            localeDisplayNameList.forEach((item, index) => {
6337                if(index==0){
6338                    combinedText += item; // or use `\n` for newline instead of space
6339                }else{
6340                     combinedText += ', ' + item.split(": ")[1]; //
6341                }
6342            });
6343            
6344            var locText = localeDisplayNameList.length === 1 ? 'Location' : 'Locations';
6345
6346            $('#' + uniqueId + ' #lsselectedLocationInText').empty().html('<label class="lslbl-2"><strong>
6346Selected ' + locText + ': </strong><span id="locDisplay">' + combinedText + '</span></label>');
6347            
6348
6349        });
6350        
6351
6352        /**
6353         * Add all locations from the selection table
6354         */
6355        $(document).on('click', '.lsadd-all-locations', function() {
6356            var uniqueId = $(this).closest('.lslocationSelectPanelContent').attr('id');
6357            var instance = lslocaleSelector.lsinstances[uniqueId];
6358            var localeIds = [];
6359            
6360            // record all the localeIds of the items we are about to move
6361            $('#' + uniqueId + ' .lsselectionTable tbody tr').not('.move-disabled').each(function(index) {
6362                localeIds.push(lslocaleSelector.lsextractId( $(this).find('td').attr('class') ));
6363            });
6364            
6365            // move the whole of the table body
6366            $('#' + uniqueId + ' .lsselectionTable tbody tr')
6367                .not('.move-disabled')
6368                .clone()
6369                .appendTo('#' + uniqueId + ' .lsselectedTable tbody')
6370                .find('i')
6371                .removeClass('fa-arrow-right')
6372                .addClass('fa-arrow-left');
6373            $('#' + uniqueId + ' .lsselectionTable tbody tr').addClass('move-disabled');
6374            $('#' + uniqueId + ' .lsselectedTable tbody').trigger('lslocaleSelector:add');
6375
6376            // enable and disable various buttons
6377            $('#' + uniqueId + ' button.lsadd-all-locations').prop('disabled', true);
6378            if ($('#' + uniqueId + ' .lsremove-all-locations').is(':disabled')) {
6379                $('#' + uniqueId + ' .lsremove-all-locations').prop('disabled', false); 
6380            }
6381            if ($('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').is(':disabled')) {
6382                $('#' + instance.uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', false); 
6383            }
6384            
6385            var tooltipId = $('#' + uniqueId + ' button.lsadd-all-locations').attr('aria-describedby');
6386            $('#' + uniqueId + ' button.lsadd-all-locations').removeAttr('aria-describedby');
6387            $('#' + tooltipId).remove();
6388            
6389            // check for mixed location types
6390            lslocaleSelector.lscheckForMixedLocaleTypes(instance);
6391            // check for too many locales selected
6392            lslocaleSelector.lscheckForMaxLocalesExceeded(instance);
6393            lslocaleSelector.lscheckForMinLocalesRequired(instance);
6394
6395            //GIS Custom Maps – 2025 CapEx localeId
6396            console.log("At localeselection, add-all Need to trigger map update");
6397            //$('#' + uniqueId + ' #lsselectedLocaleIdData').attr('data-info', JSON.stringify(localeId)).trigger('lsselectedLocaleIdDataChange');
6398
6399            var $targetElement = $('#' + uniqueId).find('#lsselectedLocaleIdData');
6400            //var event = jQuery.Event('lsselectedLocaleIdDataChange');
6401            //event.actionData = 'add-all';
6402            var event = $.Event('lsselectedLocaleIdDataChange', {
6403                    actionData: 'add-all',
6404                    bubbles: false // Prevent bubbling to document
6405            });
6406            $targetElement.attr('data-info', JSON.stringify(localeIds)).trigger(event);
6407
6408
6409            //var localeList = [];
6410            var localeDisplayNameList = [];
6411
6412            $('#' + uniqueId + ' .lsselectedTable tbody td').each(function(index, locale) {
6413                //localeList.push(parseInt($(locale).attr('class').split('-')[1]));
6414                localeDisplayNameList.push($(locale).text());
6415            });
6416
6417            var combinedText = '';
6418            localeDisplayNameList.forEach((item, index) => {
6419                if(index==0){
6420                    combinedText += item; // or use `\n` for newline instead of space
6421                }else{
6422                     combinedText += ', ' + item.split(": ")[1]; //
6423                }
6424            });
6425            var locText = localeDisplayNameList.length === 1 ? 'Location' : 'Locations';
6426
6427            $('#' + uniqueId + ' #lsselectedLocationInText').empty().html('<label class="lslbl-2"><strong>
6427Selected ' + locText + ': </strong><span id="locDisplay">' + combinedText + '</span></label>');
6428
6429        });
6430        
6431
6432        /**
6433         * Removes all locations from the selected table
6434         */
6435        $(document).on('click', '.lsremove-all-locations', function() {
6436            var uniqueId = $(this).closest('.lslocationSelectPanelContent').attr('id');
6437            var instance = lslocaleSelector.lsinstances[uniqueId];
6438            var localeIds = [];
6439
6440            $('#' + uniqueId + ' .lsselectedTable tbody tr').each(function() {
6441                var localeClass = $(this).find('td').attr('class');
6442                $(this).detach();
6443                $('#' + uniqueId + ' .lsselectionTable td.' + localeClass).closest('tr').removeClass('move-disabled');
6444                //GIS Custom Maps – 2025 CapEx
6445                localeIds.push(lslocaleSelector.lsextractId(localeClass));
6446            });
6447            $('#' + uniqueId + ' .lsselectedTable tbody').trigger('lslocaleSelector:remove');
6448            
6449            // enable and disable various buttons
6450            $('#' + uniqueId + ' .lsremove-all-locations').prop('disabled', true);
6451            if (! instance.allowEmptySelection) {
6452                $('#' + uniqueId).closest('.lslocationSelectPanel').find('button.lsselect-button').prop('disabled', true); 
6453            }
6454    
6455            if (lslocaleSelector.lsinstances[uniqueId].preventCancel) {
6456                $('#' + uniqueId).closest('.lslocationSelectPanel').find('button.lscancel-button').prop('disabled', true); 
6457            }
6458
6459            if ($('#' + uniqueId + ' button.lsadd-all-locations').is(':disabled')) {
6460                $('#' + uniqueId + ' button.lsadd-all-locations').prop('disabled', false);
6461            }
6462            
6463            var tooltipId = $('#' + uniqueId + ' .lsremove-all-locations').attr('aria-describedby');
6464            $('#' + uniqueId + ' .lsremove-all-locations').removeAttr('aria-describedby');
6465            $('#' + tooltipId).remove();
6466            
6467            instance.singleSelectedLocaleTypeId = null;
6468            // check for mixed location types
6469            lslocaleSelector.lscheckForMixedLocaleTypes(instance);
6470            // check for max locales exceeded
6471            lslocaleSelector.lscheckForMaxLocalesExceeded(instance);
6472            lslocaleSelector.lscheckForMinLocalesRequired(instance);
6473
6474            //GIS Custom Maps – 2025 CapEx localeId
6475            console.log("At localeselection, remove-all Need to trigger map update");
6476            
6477            var $targetElement = $('#' + uniqueId).find('#lsselectedLocaleIdData');
6478            //var event = jQuery.Event('lsselectedLocaleIdDataChange');
6479            //event.actionData = 'remove-all';
6480            var event = $.Event('lsselectedLocaleIdDataChange', {
6481                    actionData: 'remove-all',
6482                    bubbles: false // Prevent bubbling to document
6483            });
6484            $targetElement.attr('data-info', JSON.stringify(localeIds)).trigger(event);
6485
6486            var localeDisplayNameList = [];
6487
6488            $('#' + uniqueId + ' .lsselectedTable tbody td').each(function(index, locale) {
6489                localeDisplayNameList.push($(locale).text());
6490            });
6491
6492            var combinedText = '';
6493            localeDisplayNameList.forEach((item, index) => {
6494                if(index==0){
6495                    combinedText += item; // or use `\n` for newline instead of space
6496                }else{
6497                     combinedText += ', ' + item.split(": ")[1]; //
6498                }
6499            });
6500
6501            var locText = localeDisplayNameList.length === 1 ? 'Location' : 'Locations';
6502            $('#' + uniqueId + ' #lsselectedLocationInText').empty().html('<label class="lslbl-2"><strong>Selected ' + locText + ': </strong><span id="locDisplay">' + combinedText + '</span></label>');
6503
6504        });
6505
6506        /**
6507         * Handle new location(s) being added to the selected locales table
6508         */
6509        $(document).on('lslocaleSelector:add', '.lsselectedTable tbody', function() {
6510            var uniqueId = $(this).closest('.lslocationSelectPanelContent').attr('id');
6511            
6512            // Let the tablesorter plugin know that we made an update to the selected locales so it can resort.
6513            // For performance reasons don't resort if there are a lot of locales
6514            if ($('#' + uniqueId + ' .lsselectedTable tbody tr').length <= 100) {
6515                $('#' + uniqueId + ' .lsselectedTable').trigger('update');
6516            }
6517        });
6518
6519        $(document).on('click', '#lslistLocaleSelector', function(e){
6520            console.log("At localeselection, on lslistLocaleSelector event received");
6521            var uniqueId = $(this).closest('.lslocationSelectPanelContent').attr('id');
6522            e.preventDefault();
6523            $('#' + uniqueId + ' .lslocationList').removeClass('d-none');
6524            $('#' + uniqueId + ' .lsselectedLocations').removeClass('d-none');
6525            $('#' + uniqueId + ' .lsmapRow').addClass('d-none');
6526            $('#' + uniqueId +' button.lsadd-all-locations').removeClass('d-none'); 
6527            var lssearchMode = $('#lssearchMode').val();
6528            if(lssearchMode=='singleMode'){
6529                $('#' + uniqueId + ' .lsselectedLocations').addClass('d-none');
6530                $('#' + uniqueId +' button.lsadd-all-locations').addClass('d-none');
6531            }
6532        });
6533       
6534     });
6535
6536</script>
6536
6537
6538
6539<div class="lslocationSelectPanelContent d-none" id="lslocationSelect-template">
6540    <div class="row">
6541        <div class="col-12 lsselectionConstraint lslocalesRestricted" style="display: none">
6542            <p>Please restrict your location selection to a single location type.</p>
6543        </div>
6544        <div class="col-12 lsselectionConstraint lsmaxLocalesNotice" style="display: none">
6545            <p>You may select up to <span class="lsmaxLocales"></span> locations.</p>
6546        </div>
6547
6548        <div class="col-12 lsselectionConstraint lslocationOptionsList">
6549                <div class="row">
6550                    <div class="col-12 col-sm-6">
6551                        <label class="advanced-locale-select lslbl-3">
6552                            <span>Location Type</span>
6553                            <select name="Location Type" class='lsselectLocaleType'></select>
6554                        </label>
6555                    </div>
6556                    <div class="col-12 col-sm-6">
6557                        <label class="advanced-locale-select lslbl-3">
6558                            <span>Limit to <span class="d-none d-sm-inline-block">Locations Within</span></span>
6559                            <select name="Location ancestor" class='lsselectAncestorLocale float-end'></select
6560                        </label>
6561                    </div>
6562                </div>
6563               
6564                <div class="row">
6565                    <div class="col-12">&nbsp;</div>
6566                </div>
6567                <div class="row">
6568                    <div class="col-12">
6569                        <a href="javascript:void(0);"
6570                           id="lslistLocaleSelector"
6571                           title="Select location from a list"
6572                           class="advance-locale-button btn-sm tooltip me-2 ">
6573                            <i class="fa-regular fa-list"></i> Choose from List
6574                        </a>
6575                        <a href="javascript:void(0);"
6576                           id="lsmapLocaleSelector"
6577                           title="Use a map to select a location"
6578                           class="advance-locale-button btn-sm tooltip ms-2 ">
6579                            <i class="fa-regular fa-map"></i> Choose from Map
6580                        </a>
6581                    </div>
6582                </div>
6583
6584                <!--
6585                <div class="row">
6586                    <div class="col-2">
6587                        <a href="javascript:void(0);"
6588                           id="lslistLocaleSelector"
6589                           title="Select location from a list"
6590                           class="hci-btn-secondary btn-sm tooltip me-2 d-block text-center"
6591                           style="white-space: nowrap; min-width: 140px;">
6592                            Choose from List
6593                        </a>
6594                    </div>
6595                    
6596                    <div class="col-2">
6597                        <a href="javascript:void(0);"
6598                           id="lsmapLocaleSelector"
6599                           title="Use a map to select a location"
6600                           class="hci-btn-secondary btn-sm tooltip ms-2 d-block text-center"
6601                           style="white-space: nowrap; min-width: 140px;">
6602                            Choose from Map
6603                        </a>
6604                    </div>
6605                </div>
6606                -->
6607
6608                <div class="row">
6609                    <div class="col-12">&nbsp;</div>
6610                </div>
6611                 <div class="row">
6612                    <div id="lsselectedLocationInText" class="col-12">&nbsp;</div>
6613                </div>
6614                <!--<div id="lsselectedLocationInText">&nbsp;</div>-->
6615        </div>
6616
6617        <div class="col-12 col-sm-6 leftContent" >
6618            <div class="lslocationSelection h-100">
6619                <div class="lslocationList d-none">
6620                    <label class="lslbl-1">Add Location</label>
6621                    <div class="lslocationSelectionWrapper">
6622                             <table class="table tablesorter lsselectionTable">
6623                                    <thead style="display: none;">
6624                                        <tr><th></th></tr>
6625                                    </thead>
6626                                    <tbody>
6627                                    </tbody>
6628                                </table>
6629                    </div>
6630                </div>
6631                
6632                <div>
6633                    <!--<button type="button" class="btn-stories-tertiary btn-sm mt-2 lsadd-all-locations right" disabled title="Add all displayed locations">Add all</button>-->
6634                    <button type="button" class="btn btn-outline-info btn-sm lsadd-all-locations right" disabled title="Add all displayed locations">Add all</button>
6635                </div>
6636                
6637            </div>
6638        </div>
6639        
6640        <div class="col-12 col-sm-6 rightContent">
6641            <div class="lsselectedLocations h-100">
6642                <div class="lslocationList d-none">
6643                    <!--<h3 aria-hidden="true">Selected Locations</h3>-->
6644                    <label class="lslbl-2">Selected Location</label>
6645                    <h3 class="lslimitToSingleLocaleType" style="display: none;">Location selection has been limited to a single type. Please remove appropriate locations.</h3>
6646                    <h3 class="lslimitToMaxLocales" style="display: none;">You may only select up to <span class="lsmaxLocales"></span>
6646 locations. Please remove locations as needed.</h3>
6647                    <h3 class="lsminLocalesRequired" style="display: none;">You must select at least <span class="lsminLocales"></span> locations.</h3>
6648                
6649                    <div class="lsselectedLocationsWrapper">
6650                        <div class="spinner-wrapper locales-spinner-wrapper" style="display: none;">Loading locations&hellip;
6651                            <div class="spinner"></div>
6652                        </div>
6653                        <table class="table lsselectedTable" id="lsselectedTable">
6654                            <caption class="visually-hidden">Selected Locations:</caption>
6655                            <thead class="d-none">
6656                                <tr>
6657                                    <th>Selected Locations</th>
6658                                </tr>
6659                            </thead>
6660                            <tbody>
6661                            </tbody>
6662                        </table>
6663                    </div>
6664                </div>
6665                <div>
6666                    <button type="button" class="btn-stories-tertiary btn-sm mt-2 lsremove-all-locations right" disabled title="Remove all selected locations">Remove all</button>
6667                </div>
6668            </div>
6669        </div>
6670
6671    </div>
6672   
6673    <div class="col-12 lsselectionConstraint">
6674           <div class="map_placeholder" align="center"></div>
6675    </div>
6676    <div class="col-12 lsselectionConstraint">
6677        <div class="lspanel-select-buttons d-none">
6678            <button type="button" class="hci-btn-secondary btn-sm lsclose-button me-2">Cancel</button>
6679            <button type="button" class="hci-btn-secondary-blue btn-sm lsselect-button">Save Selection</button>
6680        </div>
6681    </div>
6682    <div class="clearfix"></div>
6683</div>
6684<!--<div id="searchLocation" title="Search Location" style="display: none;" class="row-around-centered-nowrap py-1 px-3">-->
6685<div id="searchLocation" title="Advanced Location Search" style="display: none;">
6686     <input type="hidden" id="lsinputForm" name="lsinputForm" value="">
6687     <input type="hidden" id="lsinputDialog" name="lsinputDialog" value="">
6688     <input type="hidden" id="lstargetId" name="lstargetId" value="">
6689     <input type="hidden" id="lssearchMode" name="lssearchMode" value="">
6690     <input type="hidden" id="lsisSubmit" name="lsisSubmit" value="">
6691     <input type="hidden" id="lsquickUrl" name="lsquickUrl" value="">
6692     <input type="hidden" id="lscallbackDfltEvent" name="lscallbackDfltEvent" value="">
6693     <input type="hidden" id="lscallbackAdvEvent" name="lscallbackAdvEvent" value="">
6694     <div id="lslocaleSelectContainer"></div>
6695     <input type="hidden" id="lspriorVal" name="lspriorVal" value="">
6696     <input type="hidden" id="lsUserSelectTypeIdVal" name="lsUserSelectTypeIdVal" value="">
6697     <input type="hidden" id="lsisZeroInclude" name="lsisZeroInclude" value="">
6698</div>
6699
6700<script type="text/javascript">
6701    ClientSite.namespace('ContentItem.TypeCheck');
6702
6703    /**
6704     * Determine whether a content item utilizes a map
6705     * 
6706     * @param {int} contentType Content item type to check
6707     * @return {boolean}
6708     */
6709    ClientSite.ContentItem.TypeCheck.isMap = function(contentType) {
6710        return -1 !== $.inArray(parseInt(contentType), [3,7,13]);
6711    };
6712
6713    /**
6714     * Determine whether a content item utilizes a table
6715     *
6716     * @param {int} contentType Content item type to check
6717     * @return {boolean}
6718     */
6719    ClientSite.ContentItem.TypeCheck.isTable = function(contentType) {
6720        return -1 !== $.inArray(parseInt(contentType), [4,8]);
6721    };
6722
6723    /**
6724     * Determine whether a content item utilizes a time series
6725     *
6726     * @param {int} contentType Content item type to check
6727     * @return {boolean}
6728     */
6729    ClientSite.ContentItem.TypeCheck.isTimeSeries = function(contentType) {
6730        return -1 !== $.inArray(parseInt(contentType), [5,8]);
6731    };
6732    
6733    /**
6734     * Determine whether a content item is a scatterplot
6735     *
6736     * @param {int} contentType Content item type to check
6737     * @return {boolean}
6738     */
6739    ClientSite.ContentItem.TypeCheck.isScatterplot = function(contentType) {
6740        return -1 !== $.inArray(parseInt(contentType), [6]);
6741    };
6742    
6743    /**
6744     * Determine whether a content item is a value/gauge type
6745     *
6746     * @param {int} contentType Content item type to check
6747     * @return {boolean}
6748     */
6749    ClientSite.ContentItem.TypeCheck.isValueGauge = function(contentType) {
6750        return -1 !== $.inArray(parseInt(contentType), [10,11,12]);
6751    };
6752
6753</script>
6753
6754
6755<script type="text/javascript">
6756ClientSite.namespace('LocaleAdvancedSearch.Form');
6757ClientSite.LocaleAdvancedSearch.Form.Generic= function() {
6758   
6759    this.lsName = null;
6760    this.localeTypeCallVals = null;
6761    this.localeListCallVals =null;
6762    
6763    this._construct = function(lsName) {
6764       //console.log("At localesearch jsform, lsName=" + lsName);
6765       this.lsName = lsName;
6766    }; 
6767
6768    this.lsinitialize = function() {
6769        //console.log("At localesearch jsform, in lsinitialize");
6770        this.lsaboutEventHandlers();
6771        this.lsattachSharedHandpickedLocationEventHandlers();
6772        
6773    };
6774
6775
6776    this.lsinitLocationDialog = function(dialogId) {
6777        //console.log("At localesearch jsform, in lsinitLocationDialog dialogId=" + dialogId);
6778        var self = this;
6779        var $window = $(window);
6780        var dialogDiv = '#' + dialogId;
6781
6782        // DEBUG: Log viewport dimensions
6783        //console.log("Viewport width:", $window.width());
6784        //console.log("Viewport height:", $window.height());
6785
6786        // SIMPLIFIED and MORE AGGRESSIVE width calculation
6787        var viewportWidth = $window.width();
6788        var dWidth;
6789    
6790        if (viewportWidth <= 768) { 
6791            // Mobile - use almost full width
6792            dWidth = viewportWidth - 20;
6793            //console.log("Mobile width calculation:", dWidth);
6794        } else { 
6795            // Desktop - use much wider dialog
6796            //dWidth = Math.min(viewportWidth - 100, 1200); // Much wider calculation
6797            var dWidth = $(window).width() - 400;
6798            //console.log("Desktop width calculation:", dWidth);
6799        }
6800
6801        var viewportHeight = $window.height();
6802        var dHeight = Math.min(viewportHeight - 200, 700);
6803
6804        var positionSettings = viewportWidth <= 768 ? 
6805            { my: "center", at: "center", of: window } : 
6806            { my: "top", at: "top+20", of: window };
6807
6808        console.log("Final dialog width:", dWidth);
6809
6810        $(dialogDiv).dialog({
6811            autoOpen: false,
6812            resizable: true,
6813            //classes: {"ui-dialog": "story-modal config-item no-titlebar mobile-dialog"},
6814            classes: {"ui-dialog": "advanced-location-select-modal bg-color-white"},
6815            width: dWidth,
6816            //width: 'auto',
6817            height: 'auto',
6818            modal: true,
6819            position: positionSettings,
6820            maxHeight: Math.min(viewportHeight - 50, 700),
6821            open: function (event, ui) {
6822                $(".ui-widget-overlay").addClass('modal-opened');
6823                $(this).parent().find(".ui-dialog-titlebar").show();
6824            
6825                // DEBUG: Check actual rendered dimensions
6826                var actualWidth = $(this).parent().width();
6827                var actualHeight = $(this).parent().height();
6828                //console.log("Actual dialog width after render:", actualWidth);
6829                //console.log("Actual dialog height after render:", actualHeight);
6830            
6831                // Force wider width if still narrow
6832                if (actualWidth < dWidth - 50) {
6833                    //console.log("Dialog is narrower than expected, forcing width...");
6834                    $(this).parent().width(dWidth).css('max-width', dWidth + 'px');
6835                }
6836            },
6837            close: function(event, ui) {
6838                //console.log("test click on X");
6839
6840                /** Handle X same as close START **/ 
6841                var uniqueId = $(this).parent().find('.lslocationSelectPanelContent').attr('id');
6842                //console.log("At localesearch jsform, test X, uniqueId=" + uniqueId);
6843                /*This code to prevent locale -ve being shown at the select form field */
6844                var lstargetId= $('#lstargetId').val();
6845                //console.log("At localesearch jsform, test X, Close lstargetId=" + lstargetId);
6846                var nameAttr = $('#' + lstargetId ).attr('name');
6847                //console.log("At localesearch jsform, test X, Close nameAttr=" + nameAttr);
6848                var $select = $('select[name="' + nameAttr + '"]');
6849
6850                $select.find('option').each(function() {
6851                   //if (this.value == -999 && this.selected) {
6852                   if (this.value < 0 && this.selected) {
6853                      //console.log("At localesearch jsform, test X, Found selected -ve option. Text:", $(this).text());
6854                      $(this).prop('selected', false);  // This deselects it
6855                      //console.log("At localesearch jsform, test X, Deselected. Now selected:", this.selected); // Should log false
6856                   }
6857                });
6858
6859                $select.trigger('change');
6860                $('#lsUserSelectTypeIdVal').val("");
6861                // remove the panel from the DOM
6862                $('#' + uniqueId).parent().removeClass('lslocationSelectPanel');
6863                $('#' + uniqueId).trigger('lslocaleSelector:close').remove();
6864                    
6865                // remove settings from instances array
6866                lslocaleSelector.lsremoveInstance(uniqueId);
6867
6868                /** Handle X same as close END**/ 
6869
6870                $(this).dialog("destroy");
6871                $(".ui-widget-overlay").removeClass('modal-opened');
6872            }
6873        
6874        });
6875        //console.log("At localesearch jsform, exit lsinitLocationDialog");
6876    };
6877
6878   
6879
6880
6881        /**
6882         * Save location config data (i.e. the chosen individual locations to show)
6883         *
6884         * @param {int[]} localeList Location ids
6885         */
6886        this.lsprocessSavedLocation = function(localeList) {
6887          
6888            //console.log("At localesearch jsform, in lsprocessSavedLocation processSavedLocation do n
6888othing right now");
6889        };
6890
6891        
6892        this.lsaboutEventHandlers = function() {
6893            var self = this;
6894        };
6895
6896        this.lsattachSharedHandpickedLocationEventHandlers = function(limitToSingleLocaleType) {
6897            //console.log("At localesearch jsform, inside lsattachSharedHandpickedLocationEventHandlers");
6898            // Store a reference to this object for reference inside the event handlers
6899            var self = this;
6900            var lslocaleSelectorElemId = 'lslocaleSelector-' + Date.now() + Math.floor(Math.random() * 100);
6901            
6902            // Handle a request for handpicked location selector, passing in any existing selections
6903            $('#advancedSearchLocation').on('click', function(event, phpParams) {
6904                /*move here */
6905                console.log("At localesearch jsform, advancedSearchLocation on click event receive!");
6906                self.updatePhpParams(phpParams);
6907                if(phpParams && phpParams.lslocaleTypeCall){
6908                    self.localeTypeCallVals =phpParams.lslocaleTypeCall;
6909                    //console.log("At localesearch jsform, localeTypeCallVals=" + JSON.stringify(self.localeTypeCallVals,true));
6910                }
6911
6912                if(phpParams && phpParams.lslocaleListCall){
6913                    self.localeListCallVals =phpParams.lslocaleListCall;
6914                    //console.log("At localesearch jsform, localeListCallVals=" + JSON.stringify(self.localeListCallVals,true));
6915                }
6916
6917                //Capture prior value
6918                var targetIdzy= $('#lstargetId').val();
6919                var nameAttrzy = $('#' + targetIdzy ).attr('name');
6920                var $selectzy = $('select[name="' + nameAttrzy + '"]');
6921               
6922                var pv = {};
6923                $selectzy.find('option').map(function() {
6924                      // Find the closest parent optgroup and get its label attribute
6925                      var $optgroup = $(this).closest('optgroup');
6926                      var optgroupLabel = $optgroup.length ? $optgroup.attr('label') : null;
6927                      //console.log("At localesearch jsform, optgroupLabel=" +optgroupLabel);
6928                      if (this.selected && this.value>0) {
6929                           pv[this.value] = {
6930                                text: $(this).text(),
6931                                selected: this.selected,
6932                                optgroupLabel: optgroupLabel
6933                           };
6934                        }
6935                });
6936                $('#lspriorVal').val(JSON.stringify(pv));
6937                //console.log("At localesearch jsform, pv=" + pv);
6938                /*
6939                //Verify retrival
6940                try {
6941                    // Parse the JSON string from hidden field
6942                    var storedPriorData = JSON.parse($('#lspriorVal').val() || '{}');
6943    
6944                    // Check if it's a valid object
6945                    if (typeof storedPriorData === 'object' && storedPriorData !== null && !Array.isArray(storedPriorData)) {
6946                        Object.keys(storedPriorData).forEach(function(value) {
6947                            var optionData = storedPriorData[value];
6948                            console.log('Value:', value);
6949                            console.log('Text:', optionData.text);
6950                            console.log('Selected:', optionData.selected);
6951                            console.log('optgroupLabel:', optionData.optgroupLabel);
6952                            console.log('---');
6953                        });
6954        
6955                    } else {
6956                        console.warn('Invalid data format in hidden field');
6957                    }
6958                } catch (e) {
6959                    console.error('Error parsing stored data:', e);
6960                }*/
6961
6962                //self.updateLocaleSelectors();
6963                //self.setDefaultLocationSelectionType();
6964                self.lsinitLocationDialog(phpParams.lsinputDialog);
6965                //$('#config_option_section_2').removeClass('locked');
6966                $('#searchLocation').dialog('open');
6967                //console.log('At lsattachSharedHandpickedLocationEventHandlers received!');
6968                //var currentLocaleSettings = self.getCurrentLocationConfig();
6969                //var localeIds = currentLocaleSettings.localeId || [];
6970                var localeIds = [];
6971                var settings = {
6972                    measureTypeId: 1,
6973                    localeCallback: self.lsprocessSavedLocation, 
6974                    locales: localeIds, 
6975                    panelContainer: '#lslocaleSelectContainer', 
6976                    limitToSingleLocaleType: limitToSingleLocaleType,
6977                    mappable: false,
6978                    uniqueId: lslocaleSelectorElemId,
6979                    maxLocales: (self.maxItems) ? self.maxItems : 0,
6980                    localeTypeCallVals : self.localeTypeCallVals? self.localeTypeCallVals : null,
6981                    localeListCallVals : self.localeListCallVals? self.localeListCallVals : null
6982                };
6983                
6984                var measureData = $('#measureList').data('selectedMeasure');
6985                // Measure data may not exist for certain content item types
6986                if (measureData && measureData[0]) {
6987                    var tempMeasure = measureData[0];
6988                    settings.measureTypeId = tempMeasure['type'];
6989                    if (tempMeasure.measureId && tempMeasure.measureId > 0) {
6990                        settings.measureId = tempMeasure.measureId;
6991                    }
6992                    if (tempMeasure.measureChildIdList && tempMeasure.measureChildIdList.length > 0) {
6993                        settings.measureChildIdList = tempMeasure.measureChildIdList.join();
6994                    }
6995                    if (tempMeasure.measureChildTypeId && tempMeasure.measureChildTypeId > 0) {
6996                        settings.measureChildTypeId = tempMeasure.measureChildTypeId;
6997                    }
6998                }
6999
7000                lslocaleSelector.lsopen(settings);
7001                //console.log("At localesearch jsform, after open");
7002            });
7003            
7004            this.lsattachSharedLocaleSelectorEventHandlers();
7005
7006            //to handle advanced link 
7007            $('.advanced-search-trigger').click(function(e) {
7008                console.log('At localesearch jsform, In advanced-search-trigger');
7009                e.preventDefault();
7010                const paramsx = JSON.parse(this.dataset.phpParams);
7011                //console.log('At localesearch jsform, In advanced-search-trigger paramsx=' + JSON.stringify(paramsx,null,2));
7012                $('#advancedSearchLocation').trigger('click', [paramsx]);
7013            });
7014        };
7015
7016        /**
7017         * Attach locale selector custom event handlers
7018         */
7019        this.lsattachSharedLocaleSelectorEventHandlers = function() {
7020            // This is a bit of a clunky way to find the "select locations" button.  The container housing both the 
7021            // button and the locale selector should have class=location-selection-head and the button should have 
7022            // class=location-selection-opener
7023            //console.log('At localesearch jsform, at lsattachSharedLocaleSelectorEventHandlers');
7024            $(document)
7025                .off('lslocaleSelector:open', '.lslocationSelectPanelContent')
7026                .on('lslocaleSelector:open', '.lslocationSelectPanelContent', function() {
7027                    //console.log('At localesearch jsform, at lsattachSharedLocaleSelectorEventHandlers open');
7028                    $(this).closest('.location-selection-head').find('.location-selection-opener').hide();
7029
7030                 })
7031                .off('lslocaleSelector:close', '.lslocationSelectPanelContent')
7032                .on('lslocaleSelector:close', '.lslocationSelectPanelContent', function() {
7033                    //console.log('At localesearch jsform, at lsattachSharedLocaleSelectorEventHandlers close');
7034                    $(this).closest('.location-selection-head').find('.location-selection-opener').show();
7035                });
7036             $(document).on('lslocaleSelector:open', function(e, data) {
7037                 const $panel = $(e.target).closest('.lslocationSelectPanelContent');
7038                 $panel.removeClass('d-none');
7039                 //console.log('At localesearch jsform, Event fired! -4'); // Does this log?
7040             });   
7041
7042        };
7043         
7044        this.lsgetVisualType = function() {
7045            return this.visualType;
7046        };
7047
7048        this.updatePhpParams = function(phpParams) {
7049            //console.log("At localesearch jsform, Entering updatePhpParams");
7050
7051            Object.entries(phpParams).forEach(([key, val]) => {
7052                //console.log("key:" + key + " val:" + val);
7053                $('#' + key).val(val);
7054            });
7055        }
7056       
7057    // Call the constructor
7058    this._construct('search_location');
7059
7060    
7061       
7062};
7063</script>
vendor: 2 bytes, line 7063
7063
7064<script type="text/javascript">
7065
7066var formHelper;
7067
7068$(document).ready(function(){
7069    formHelper = new ClientSite.LocaleAdvancedSearch.Form.Generic();
7070    formHelper.lsinitialize();
7071});
7072</script>
7072  
7073
7074
7075<script type="text/javascript">
7076
7077$(document).ready(function() {
7078
7079   //frontend\application\modules\indicators\forms\LocaleSelectForm.php
7080   //frontend\application\modules\indicators\views\scripts\index\index.phtml
7081   $(document).on('change', '#ls_localeId_flcomdash', function() {
7082       const phpParams = JSON.parse(this.dataset.phpParams);
7083       //console.log("ls_localeId_flcomdash phpParams=" + JSON.stringify(phpParams,null,2));
7084       selectNextStepNew($(this).val(),phpParams, function(){
7085          if(phpParams.lsisSubmit=='yes'){
7086             //console.log("selectNextStepNew ls_localeId_flcomdash Submitting form");
7087             $('#' + phpParams.lsinputForm).submit();
7088             return; // Stop after first submit (optional)
7089          } 
7090       });
7091   });
7092
7093   //frontend\application\modules\indicators\views\scripts\partials\indicator_searchform.phtml
7094   $(document).on('change', '#indicatorLocale', function() {
7095       const phpParams = JSON.parse(this.dataset.phpParams);
7096       //console.log("indicatorLocale phpParams=" + JSON.stringify(phpParams,null,2));
7097       selectNextStepNew($(this).val(),phpParams, function(){
7098          //console.log("indicatorLocale-call back from selectNextStepNew do nothing");
7099       });
7100   });
7101
7102   //frontend\application\modules\indicators\views\scripts\index\view.phtml
7103   $(document).on('change', '#ls_localeId_ficomdash', function(){
7104       const phpParams = JSON.parse(this.dataset.phpParams);
7105       //console.log("ls_localeId_ficomdash phpParams=" + JSON.stringify(phpParams,null,2));
7106       selectNextStepNew($(this).val(),phpParams, function(value){
7107          //console.log("ls_localeId_ficomdash-call back from selectNextStepNew value=" + value);
7108          if(phpParams.lsisSubmit=='no' && phpParams.lsquickUrl!=null && phpParams.lsquickUrl.length > 0){
7109              var url = phpParams.lsquickUrl;
7110              url += '&localeId=' + value;
7111              window.location.href = url;
7112          }
7113       });
7114   });
7115   
7116   //frontend\application\modules\indicators\views\scripts\index\view-details.phtml
7117   //frontend\application\modules\components\views\scripts\partials\contentitem\form\measurevaluegaugelocation.phtml
7118   //frontend\application\modules\components\views\scripts\partials\contentitem\form\_location_select.phtml
7119   $(document).on('change', '#ls_localeId_vwind', function() {
7120       const phpParams = JSON.parse(this.dataset.phpParams);
7121       formHelper.updatePhpParams(phpParams);
7122       selectNextStepNew($(this).val(),phpParams, function(){
7123           var lscallbackDfltEventId= $('#lscallbackDfltEvent').val();
7124           if(lscallbackDfltEventId!=null && lscallbackDfltEventId!=''){
7125               if ($('#' + lscallbackDfltEventId).is(":visible")) {
7126                   //console.log("lscallbackDfltEventId is visible lscallbackDfltEventId=" + lscallbackDfltEventId);
7127                   //$('#' + lscallbackDfltEventId).trigger('click', [{lslocaleId: $('#ls_localeId_vwind').val()}]);
7128               } else {
7129                   //console.log("lscallbackDfltEventId is not visible");
7130               }
7131           }else{
7132               //console.log("lscallbackDfltEventId is null");
7133           }
7134       });
7135   });
7136   
7137   //frontend\application\modules\reports\views\scripts\location\index.phtml
7138   $(document).on('change', '#ls_localeId_rb', function() {
7139       const phpParams = JSON.parse(this.dataset.phpParams);
7140       //console.log("ls_localeId_rb phpParams=" + JSON.stringify(phpParams,null,2));
7141       
7142       if ($('#ls_localeId_rb').val() == '0') {
7143            alert('You must select a valid location');
7144            $('.reportOptions').addClass('hidden-all');
7145            $('.select2-container--default .select2-selection--single').removeClass('select2-no-border');
7146            return false;
7147       }
7148       formHelper.updatePhpParams(phpParams);
7149       selectNextStepNew($(this).val(),phpParams, function(){
7150           //console.log("ls_localeId_rb-call back from selectNextStepNew run the default search "); 
7151           var lscallbackDfltEventId= $('#lscallbackDfltEvent').val();
7152           if(lscallbackDfltEventId!=null && lscallbackDfltEventId!=''){
7153               if ($('#' + lscallbackDfltEventId).is(":visible")) {
7154                   //console.log("lscallbackDfltEventId is visible lscallbackDfltEventId=" + lscallbackDfltEventId);
7155                   $('#' + lscallbackDfltEventId).trigger('click', [{lslocaleId: $('#ls_localeId_rb').val()}]);
7156               } else {
7157                   //console.log("lscallbackDfltEventId is not visible");
7158               }
7159           }else{
7160               //console.log("lscallbackDfltEventId is null");
7161           }
7162       });
7163   });
7164
7165   //frontend\application\modules\indicators\views\scripts\partials\filteredform.phtml
7166   $(document).on('change', '#ls_indicatorLocale_filter', function() {
7167       const phpParams = JSON.parse(this.dataset.phpParams);
7168       //console.log("ls_indicatorLocale_filter phpParams=" + JSON.stringify(phpParams,null,2));
7169       selectNextStepNew($(this).val(),phpParams, function(){
7170          //console.log("ls_indicatorLocale_filter-call back from selectNextStepNew do nothing");
7171       });
7172   });
7173   
7174   //frontend\application\modules\indicators\views\scripts\partials\curatedform_defaultlocale.phtml
7175   $(document).on('change', '#ls_defaultLocaleId_filter', function() {
7176       const phpParams = JSON.parse(this.dataset.phpParams);
7177       //console.log("ls_defaultLocaleId_filter phpParams=" + JSON.stringify(phpParams,null,2));
7178       selectNextStepNew($(this).val(),phpParams, function(){
7179          //console.log("ls_defaultLocaleId_filter-call back from selectNextStepNew do nothing");
7180       });
7181   });
7182
7183   //frontend\application\modules\indicators\views\scripts\partials\handpickedform.phtml
7184   $(document).on('change', '#ls_indicatorLocale_handpick', function() {
7185       const phpParams = JSON.parse(this.dataset.phpParams);
7186       //console.log("ls_indicatorLocale_handpick phpParams=" + JSON.stringify(phpParams,null,2));
7187       selectNextStepNew($(this).val(),phpParams, function(){
7188          //console.log("ls_indicatorLocale_handpick-call back from selectNextStepNew do nothing");
7189       });
7190   });
7191   
7192   //Home>Community Dashboard>Disparities Dashboard
7193   //frontend\application\modules\indicators\views\scripts\index\dashboard.phtml
7194   $(document).on('change', '#ls_dashboardFilterId_locale', function() {
7195       const phpParams = JSON.parse(this.dataset.phpParams);
7196       //console.log("ls_dashboardFilterId_locale phpParams=" + JSON.stringify(phpParams,null,2));
7197       selectNextStepNew($(this).val(),phpParams, function(){
7198          if(phpParams.lsisSubmit=='yes'){
7199             //console.log("selectNextStepNew ls_dashboardFilterId_locale Submitting form");
7200             $('#' + phpParams.lsinputForm).submit();
7201             return; // Stop after first submit (optional)
7202          } 
7203       });
7204   });
7205
7206   //Home>Administration>Tiles>Create Indicator Spotlight Tile
7207   //frontend\application\modules\tiles\views\scripts\admin\edit\indicatorspotlight.phtml
7208   $(document).on('change', '[id^="ls_localeId_tileindspotlight"]', function() {
7209       const id = this.id;
7210       //console.log("id=" + id);
7211       var phpParams ='';
7212       if (/^ls_localeId_tileindspotlight\d+$/.test(id)) {
7213           const number = id.replace('ls_localeId_tileindspotlight', '');
7214           //console.log("ls_localeId_tileindspotlight extracted number: " + number);
7215           phpParams = JSON.parse(this.dataset.phpParams);
7216           //console.log("PHP Params:", phpParams);
7217
7218           formHelper.updatePhpParams(phpParams);
7219           selectNextStepNew($(this).val(),phpParams, function(){
7220              //console.log("ls_localeId_tileindspotlight back from selectNextStepNew run the default search "); 
7221              var lscallbackDfltEventId= $('#lscallbackDfltEvent').val();
7222              if(lscallbackDfltEventId!=null && lscallbackDfltEventId!=''){
7223                   if ($('#' + lscallbackDfltEventId).is(":visible")) {
7224                       //console.log("lscallbackDfltEventId is visible lscallbackDfltEventId=" + lscallbackDfltEventId);
7225                       $('#' + lscallbackDfltEventId).trigger('click', [{lslocaleId: $('#' + id).val(), lstargetId:id}]);
7226                   } else {
7227                       //console.log("lscallbackDfltEventId is not visible");
7228                   }
7229              }else{
7230                   //console.log("lscallbackDfltEventId is null");
7231              }
7232           });
7233       }
7234   });
7235
7236   //frontend\application\modules\tiles\views\scripts\admin\edit\indicatorchart.phtml
7237   $(document).on('change', '[id^="ls_localeId_tileindchart"]', function() {
7238       const id = this.id;
7239       //console.log("id=" + id);
7240       var phpParams ='';
7241       if (/^ls_localeId_tileindchart\d+$/.test(id)) {
7242           const number = id.replace('ls_localeId_tileindchart', '');
7243           //console.log("ls_localeId_tileindchart extracted number: " + number);
7244           phpParams = JSON.parse(this.dataset.phpParams);
7245           //console.log("PHP Params:", phpParams);
7246           formHelper.updatePhpParams(phpParams);
7247           selectNextStepNew($(this).val(),phpParams, function(){
7248              //console.log("ls_localeId_tileindchart back from selectNextStepNew run the default search "); 
7249              var lscallbackDfltEventId= $('#lscallbackDfltEvent').val();
7250              if(lscallbackDfltEventId!=null && lscallbackDfltEventId!=''){
7251                   if ($('#' + lscallbackDfltEventId).is(":visible")) {
7252                       //console.log("lscallbackDfltEventId is visible lscallbackDfltEventId=" + lscallbackDfltEventId);
7253                       $('#' + lscallbackDfltEventId).trigger('click', [{lslocaleId: $('#' + id).val(), lstargetId:id}]);
7254                   } else {
7255                       //console.log("lscallbackDfltEventId is not visible");
7256                   }
7257              }else{
7258                   //console.log("lscallbackDfltEventId is null");
7259              }
7260           });
7261       }
7262   });
7263
7264
7265   //frontend\application\modules\tiles\views\scripts\admin\edit\indicatorchart.phtml
7266   $(document).on('change', '[id^="ls_localeIdList_tileindchart"]', function() {
7267       const id = this.id;
7268       //console.log("id=" + id);
7269       var phpParams ='';
7270       if (/^ls_localeIdList_tileindchart\d+$/.test(id)) {
7271           const number = id.replace('ls_localeIdList_tileindchart', '');
7272           //console.log("ls_localeIdList_tileindchart extracted number: " + number);
7273           phpParams = JSON.parse(this.dataset.phpParams);
7274           //console.log("PHP Params:", phpParams);
7275           formHelper.updatePhpParams(phpParams);
7276           selectNextStepNew($(this).val(),phpParams, function(){
7277              //console.log("ls_localeIdList_tileindchart-call back from selectNextStepNew do nothing");
7278           });
7279       }
7280   });
7281
7282   //frontend\application\modules\tiles\views\scripts\admin\edit\indicatormap.phtml
7283   $(document).on('change', '#ls_localeIdList_tileindmap', function() {
7284       const phpParams = JSON.parse(this.dataset.phpParams);
7285       //console.log("PHP Params:", phpParams);
7286       
7287       formHelper.updatePhpParams(phpParams);
7288       selectNextStepNew($(this).val(),phpParams, function(){
7289           //console.log("ls_localeIdList_tileindmap-call back from selectNextStepNew run the default search "); 
7290           
7291           var lscallbackDfltEventId= $('#lscallbackDfltEvent').val();
7292           if(lscallbackDfltEventId!=null && lscallbackDfltEventId!=''){
7293               if ($('#' + lscallbackDfltEventId).is(":visible")) {
7294                   //console.log("lscallbackDfltEventId is visible lscallbackDfltEventId=" + lscallbackDfltEventId);
7295                   $('#' + lscallbackDfltEventId).trigger('click', [{lslocaleId: $('#ls_localeIdList_tileindmap').val()}]);
7296               } else {
7297                   //console.log("lscallbackDfltEventId is not visible");
7298               }
7299           }else{
7300               //console.log("lscallbackDfltEventId is null");
7301           }
7302       });
7303   });
7304   
7305   //frontend\application\modules\tiles\views\scripts\admin\edit\indicatormap.phtml
7306   $(document).on('change', '#ls_localeId_tileindmap', function() {
7307       const phpParams = JSON.parse(this.dataset.phpParams);
7308       //console.log("PHP Params:", phpParams);
7309       
7310       formHelper.updatePhpParams(phpParams);
7311       selectNextStepNew($(this).val(),phpParams, function(){
7312           //console.log("ls_localeId_tileindmap-call back from selectNextStepNew run the default search "); 
7313           
7314           var lscallbackDfltEventId= $('#lscallbackDfltEvent').val();
7315           if(lscallbackDfltEventId!=null && lscallbackDfltEventId!=''){
7316               if ($('#' + lscallbackDfltEventId).is(":visible")) {
7317                   //console.log("lscallbackDfltEventId is visible lscallbackDfltEventId=" + lscallbackDfltEventId);
7318                   $('#' + lscallbackDfltEventId).trigger('click', [{lslocaleId: $('#ls_localeId_tileindmap').val()}]);
7319               } else {
7320                   //console.log("lscallbackDfltEventId is not visible");
7321               }
7322           }else{
7323               //console.log("lscallbackDfltEventId is null");
7324           }
7325       });
7326   });
7327
7328   //frontend\application\modules\locales\views\scripts\partials\locationmap.phtml
7329   $(document).on('change', '#ls_localeId_locales', function() {
7330       const phpParams = JSON.parse(this.dataset.phpParams);
7331       //console.log("PHP Params:", phpParams);
7332       
7333       formHelper.updatePhpParams(phpParams);
7334       selectNextStepNew($(this).val(),phpParams, function(){
7335           //console.log("ls_localeId_locales-call back from selectNextStepNew run the default search "); 
7336           
7337           var lscallbackDfltEventId= $('#lscallbackDfltEvent').val();
7338           if(lscallbackDfltEventId!=null && lscallbackDfltEventId!=''){
7339               if ($('#' + lscallbackDfltEventId).is(":visible")) {
7340                   //console.log("lscallbackDfltEventId is visible lscallbackDfltEventId=" + lscallbackDfltEventId);
7341                   $('#' + lscallbackDfltEventId).trigger('click', [{lslocaleId: $('#ls_localeId_locales').val()}]);
7342               } else {
7343                   //console.log("lscallbackDfltEventId is not visible");
7344               }
7345           }else{
7346               //console.log("lscallbackDfltEventId is null");
7347           }
7348       });
7349   });
7350
7351   //frontend\application\modules\locales\views\scripts\partials\locationmap.phtml
7352   $(document).on('change', '#ls_demLocaleId_locales', function() {
7353       const phpParams = JSON.parse(this.dataset.phpParams);
7354       //console.log("PHP Params:", phpParams);
7355       
7356       formHelper.updatePhpParams(phpParams);
7357       selectNextStepNew($(this).val(),phpParams, function(){
7358           //console.log("ls_demLocaleId_locales-call back from selectNextStepNew run the default search "); 
7359           var lscallbackDfltEventId= $('#lscallbackDfltEvent').val();
7360           if(lscallbackDfltEventId!=null && lscallbackDfltEventId!=''){
7361               if ($('#' + lscallbackDfltEventId).is(":visible")) {
7362                   //console.log("lscallbackDfltEventId is visible lscallbackDfltEventId=" + lscallbackDfltEventId);
7363                   $('#' + lscallbackDfltEventId).trigger('click', [{lslocaleId: $('#ls_demLocaleId_locales').val()}]);
7364               } else {
7365                   //console.log("lscallbackDfltEventId is not visible");
7366               }
7367           }else{
7368               //console.log("lscallbackDfltEventId is null");
7369           }
7370       });
7371   });
7372
7373   //frontend\application\modules\indicators\views\scripts\admin\editminidashboard.phtml - Indicators_Form_EditMiniDashboardMultiLocale
7374   $(document).on('change', '#ls_selectLocaleId_multiLocale', function() {
7375       const phpParams = JSON.parse(this.dataset.phpParams);
7376       //console.log("ls_selectLocaleId_multiLocale phpParams=" + JSON.stringify(phpParams,null,2));
7377       selectNextStepNew($(this).val(),phpParams, function(){
7378          //console.log("ls_selectLocaleId_multiLocale-call back from selectNextStepNew do nothing");
7379       });
7380   });
7381
7382   //frontend\application\modules\indicators\views\scripts\admin\editminidashboard.phtml - Indicators_Form_EditMiniDashboardMultiComparison
7383   $(document).on('change', '#ls_selectLocaleId_multicomp', function() {
7384       const phpParams = JSON.parse(this.dataset.phpParams);
7385       //console.log("PHP Params:", phpParams);
7386       
7387       formHelper.updatePhpParams(phpParams);
7388       selectNextStepNew($(this).val(),phpParams, function(){
7389           //console.log("ls_selectLocaleId_multicomp-call back from selectNextStepNew run the default search "); 
7390           var lscallbackDfltEventId= $('#lscallbackDfltEvent').val();
7391           if(lscallbackDfltEventId!=null && lscallbackDfltEventId!=''){
7392               if ($('#' + lscallbackDfltEventId).is(":visible")) {
7393                   //console.log("lscallbackDfltEventId is visible callbackDfltEventId=" + lscallbackDfltEventId);
7394                   $('#' + lscallbackDfltEventId).trigger('click', [{lslocaleId: $('#ls_selectLocaleId_multicomp').val()}]);
7395               } else {
7396                   //console.log("lscallbackDfltEventId is not visible");
7397               }
7398           }else{
7399               //console.log("lscallbackDfltEventId is null");
7400           }
7401       });
7402   });
7403
7404   //frontend\application\modules\indicators\views\scripts\admin\editminidashboard.phtml - Indicators_Form_EditMiniDashboardMultiIndicator
7405   //frontend\application\modules\indicators\views\scripts\partials\minidashboard_modify_form.phtml
7406   $(document).on('change', '#ls_selectLocaleId_multiind', function() {
7407       const phpParams = JSON.parse(this.dataset.phpParams);
7408       //console.log("PHP Params:", phpParams);
7409       
7410       formHelper.updatePhpParams(phpParams);
7411       selectNextStepNew($(this).val(),phpParams, function(){
7412           //console.log("ls_selectLocaleId_multiind-call back from selectNextStepNew run the default search "); 
7413           var lscallbackDfltEventId= $('#lscallbackDfltEvent').val();
7414           if(lscallbackDfltEventId!=null && lscallbackDfltEventId!=''){
7415               if ($('#' + lscallbackDfltEventId).is(":visible")) {
7416                   //console.log("lscallbackDfltEventId is visible lscallbackDfltEventId=" + lscallbackDfltEventId);
7417                   $('#' + lscallbackDfltEventId).trigger('click', [{lslocaleId: $('#ls_selectLocaleId_multiind').val()}]);
7418               } else {
7419                   //console.log("lscallbackDfltEventId is not visible");
7420               }
7421           }else{
7422               //console.log("lscallbackDfltEventId is null");
7423           }
7424       });
7425   });
7426
7427    //frontend\application\modules\resourcelibrary\views\scripts\admin\create.phtml
7428   $(document).on('change', '#ls_localeId_createres', function() {
7429       const phpParams = JSON.parse(this.dataset.phpParams);
7430       //console.log("ls_localeId_createres phpParams=" + JSON.stringify(phpParams,null,2));
7431       selectNextStepNew($(this).val(),phpParams, function(){
7432          //console.log("ls_localeId_createres-call back from selectNextStepNew do nothing");
7433       });
7434   });
7435
7436   //frontend\application\modules\indicators\views\scripts\admin\localegroups.phtml
7437   $(document).on('change', '#ls_customGroupLocaleIdList_lg', function() {
7438       const phpParams = JSON.parse(this.dataset.phpParams);
7439       //console.log("ls_customGroupLocaleIdList_lg phpParams=" + JSON.stringify(phpParams,null,2));
7440       selectNextStepNew($(this).val(),phpParams, function(){
7441          //console.log("ls_customGroupLocaleIdList_lg-call back from selectNextStepNew do nothing");
7442       });
7443   });
7444
7445   //frontend\application\modules\components\views\scripts\partials\js\contentitem\form\abstract.phtml
7446   $(document).on('change', '#singleLocaleSelect', function() {
7447       const phpParams = JSON.parse(this.dataset.phpParams);
7448       console.log("singleLocaleSelect phpParams=" + JSON.stringify(phpParams,null,2));
7449       console.log("singleLocaleSelect singleLocaleSelect val=" + $('#singleLocaleSelect').val());
7450       
7451       formHelper.updatePhpParams(phpParams);
7452       selectNextStepNew($(this).val(),phpParams, function(){
7453           //console.log("singleLocaleSelect-call back from selectNextStepNew run the default search "); 
7454           var lscallbackDfltEventId= $('#lscallbackDfltEvent').val();
7455           if(lscallbackDfltEventId!=null && lscallbackDfltEventId!=''){
7456               if ($('#' + lscallbackDfltEventId).is(":visible")) {
7457                   console.log("lscallbackDfltEventId is visible lscallbackDfltEventId=" + lscallbackDfltEventId);
7458                   $('#' + lscallbackDfltEventId).trigger('click', [{lslocaleId: $('#singleLocaleSelect').val()}]);
7459               } else {
7460                   console.log("lscallbackDfltEventId is not visible");
7461               }
7462           }else{
7463               //console.log("lscallbackDfltEventId is null");
7464           }
7465       });
7466   });
7467
7468   //\HCI-Main\frontend\application\modules\tiles\forms\Edit\IndicatorFooter.php
7469   $(document).on('change', '#ls_indicatorFooter_location', function() {
7470       const phpParams = JSON.parse(this.dataset.phpParams);
7471       console.log("ls_indicatorFooter_location phpParams=" + JSON.stringify(phpParams,null,2));
7472       console.log("ls_indicatorFooter_location val=" + $('#ls_indicatorFoot
7472er_location').val());
7473       
7474       formHelper.updatePhpParams(phpParams);
7475       selectNextStepNew($(this).val(),phpParams, function(){
7476           //console.log("ls_indicatorFooter_location-call back from selectNextStepNew run the default search "); 
7477           var lscallbackDfltEventId= $('#lscallbackDfltEvent').val();
7478           if(lscallbackDfltEventId!=null && lscallbackDfltEventId!=''){
7479               if ($('#' + lscallbackDfltEventId).is(":visible")) {
7480                   console.log("lscallbackDfltEventId is visible lscallbackDfltEventId=" + lscallbackDfltEventId);
7481                   $('#' + lscallbackDfltEventId).trigger('click', [{lslocaleId: $('#ls_indicatorFooter_location').val()}]);
7482               } else {
7483                   console.log("lscallbackDfltEventId is not visible");
7484               }
7485           }else{
7486               //console.log("lscallbackDfltEventId is null");
7487           }
7488       });
7489   });
7490
7491
7492
7493   function selectNextStepNew(selectedValueInput,phpParams, callback) {
7494       var selectedValuesList=[];
7495       var selectedValues = selectedValueInput;
7496       if(Array.isArray(selectedValues)){
7497            //console.log("At jumptolocale, selectedValues is an array");
7498            selectedValuesList=selectedValues;
7499       }else{
7500           //console.log("At jumptolocale, selectedValues is not an array, convert");
7501            selectedValuesList.push(selectedValues);
7502       }
7503       selectedValuesList.forEach(function(value) {
7504           if (value > 0) {
7505               callback(value);
7506           } else if (value < 0) {
7507               console.log("At jumptolocale, going to trigger advancedSearchLocation value:", value);
7508
7509               // Add new element to phpParams using spread operator
7510               const updatedPhpParams = {
7511                    ...phpParams,
7512                    lsUserSelectTypeIdVal: Math.abs(value) // Convert negative to positive
7513               };
7514
7515               //$('#advancedSearchLocation').trigger('click', [phpParams]);
7516               $('#advancedSearchLocation').trigger('click', [updatedPhpParams]);
7517           }else if (value==0 && phpParams.lsisZeroInclude=='yes'){
7518                console.log("value==0 and phpParams.lsisZeroInclude=" + phpParams.lsisZeroInclude);
7519                callback(value);
7520           }
7521           
7522       }); 
7523   }
7524});
7525</script>
7525
7526
7527 
7528
7529
7530    <!-- Generated by: HCIPCHPWEB01 ; Site: jackson -->
7531
7532
7533
7534
7535
7536    
7536<script type="text/javascript" src="/_Incapsula_Resource?SWJIYLWA=719d34d31c8e3a6e6fffd425f7e032f3&ns=1&cb=419275663" async></script>
7536</body>
7537</html>

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.