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 & 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&status=2&alert=1" class="dropdown-item">Get Involved</a></li> 302 <li><a href="/tiles/index/display?id=313420568533790381&status=2&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&controller=index&action=indicatorsearch"></a><a href="/tiles/index/display?id=313420568533790381&status=2&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&controller=index&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, "&") 656 .replace(/</g, "<") 657 .replace(/>/g, ">") 658 .replace(/"/g, """) 659 .replace(/'/g, "'"); 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 \/>< 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 \/>> 22.5%","unit":"percent"}],"localeIdList":"2274,2276"},"7203":{"comparisonTypeId":0,"breaks":[{"minValue":"-Infinity","maxValue":26.398999999999997356781022972427308559417724609375,"symbol":"rgba(232, 45, 38,1)","label":"< 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":"> 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 \/>< 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 \/>> 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 \/>< 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 \/>> 12.7%","unit":"percent"}],"localeIdList":"2276,2274"},"7203":{"comparisonTypeId":0,"breaks":[{"minValue":"-Infinity","maxValue":7.49899999999999966604491419275291264057159423828125,"symbol":"rgba(49, 163, 84,1)","label":"< 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":"> 7.5%","unit":"percent"}],"localeIdList":"2276,2274"},"7227":{"comparisonTypeId":0,"breaks":[{"minValue":"-Infinity","maxValue":8.7990000000000012647660696529783308506011962890625,"symbol":"rgba(49, 163, 84,1)","label":"< 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":"> 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.<br>The Mann-Kendall Test for Statistical Significance is used to evaluate the trend<br>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&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"> 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 \/>< 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 \/>> 22.5%","unit":"percent"}],"localeIdList":"2274,2276"},"7203":{"comparisonTypeId":0,"breaks":[{"minValue":"-Infinity","maxValue":26.398999999999997356781022972427308559417724609375,"symbol":"rgba(232, 45, 38,1)","label":"< 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":"> 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 \/>< 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 \/>> 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 \/>< 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 \/>> 12.7%","unit":"percent"}],"localeIdList":"2276,2274"},"7203":{"comparisonTypeId":0,"breaks":[{"minValue":"-Infinity","maxValue":7.49899999999999966604491419275291264057159423828125,"symbol":"rgba(49, 163, 84,1)","label":"< 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":"> 7.5%","unit":"percent"}],"localeIdList":"2276,2274"},"7227":{"comparisonTypeId":0,"breaks":[{"minValue":"-Infinity","maxValue":8.7990000000000012647660696529783308506011962890625,"symbol":"rgba(49, 163, 84,1)","label":"< 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":"> 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.<br>The Mann-Kendall Test for Statistical Significance is used to evaluate the trend<br>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&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"> 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 & Josephine area, <strong><span class="color-accent"><a href="/tiles/index/display?id=313420568533790381&status=2&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>•<span class="footer_item"><a href="https://healthycities.zendesk.com/hc/en-us/sections/204050607-FAQ" target="_blank">FAQ</a></span>•<span class="footer_item"><a href="/index.php?module=utilities&controller=index&action=submitfeedback">Contact Us</a></span>•<span class="footer_item"><a href="/index.php?module=Tiles&controller=index&action=display&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 © 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(/["'\\]|"/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(/["'\\]|"/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"> </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"> </div> 6610 </div> 6611 <div class="row"> 6612 <div id="lsselectedLocationInText" class="col-12"> </div> 6613 </div> 6614 <!--<div id="lsselectedLocationInText"> </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… 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.