1 2 3<!DOCTYPE html> 4<html id="ctl00_ctl00_mainhtml" xmlns="http://www.w3.org/1999/xhtml" lang="en"> 5<head id="ctl00_ctl00_Head1"> 6 7
7<script type="text/javascript"> 8 if (window.name == "refresh") 9 { 10 window.stop(); 11 window.location.replace(window.location.pathname + window.location.search + window.location.hash); 12 window.name = ""; 13 } 14 </script>
14 15 16 <link rel="preconnect" href="https://fonts.googleapis.com" /><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="" /><meta name="viewport" content="width=device-width, initial-scale=1" /> 17 18 <link rel="stylesheet" type="text/css" href="https://media-sixrivers.mynews360.com/css/smartBanner.css?v=1.14.5.35260" media="screen" /> 19 <link rel="stylesheet" type="text/css" href="https://media-sixrivers.mynews360.com/css/common.css?v=1.14.5.35260" /> 20 <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Roboto:400,400i,700,700i,900,900i&display=swap" /> 21 <link rel="stylesheet" type="text/css" href="https://media-sixrivers.mynews360.com/css/fontawesome/fontawesome.min.css?v=1.14.5.35260" /> 22 <link rel="stylesheet" type="text/css" href="https://media-sixrivers.mynews360.com/css/fontawesome/brands.min.css?v=1.14.5.35260" /> 23 24 25
25<script type="text/javascript" src="https://media-sixrivers.mynews360.com/js/jquery.js?v=1.14.5.35260"></script>
25 26 27
27<script type="text/javascript"> 28 var _fbClientId = "309214499646406", 29 _fbTarget = window.location.pathname, 30 _baseUri = "https://timesnews.mynews360.com/", 31 _webUri = "https://johnsoncitypress.com", 32 _mediaUrl = "https://media-sixrivers.mynews360.com/", 33 _logoTemplate = "https://media-sixrivers.mynews360.com/logo/%%TEAM_ID%%/213", 34 _schoolTemplate = "https://media-sixrivers.mynews360.com/logo/%%SCHOOL_ID%%/school/%%SPORT_ID%%/213", 35 _MTS_PHOTO_TEMPLATE = "https://media-sixrivers.mynews360.com/image/%%IMG_ID%%/%%SIZE%%/%%TEAM_ID%%/%%USER_ID%%/%%TYPE%%/213", 36 _portalId = 213, 37 _portalName = "Johnson City Press", 38 _portalUrl = "https://johnsoncitypress.com/", 39 _twitterName = "", 40 _facebookName = "", 41 _region = "Johnson City", 42 _MTS_widgetsReady = false, 43 _MTS_userId = -1, 44 _MTS_thirdPartyId = null, 45 _MTS_urlRegex = new RegExp("[|+<>\\*%&:\\?\\/\\\\\'.\"\\r\\n#]", "g"), 46 _isAdmin = false, 47 _warnAboutRejected = false, 48 _MTS_cssList = [], 49 _MTS_jsList = [], 50 _MTS_pageVP = "~/CustomPage.aspx", 51 _MTS_pageId = 0, 52 _MTS_histCount = 0, 53 _MTS_sportsEnabled = false, 54 _MTS_uploadLimit = 41943040, 55 56 _hasAlerts = false, 57 _registrationPop = false, 58 _targetList = "team,".split(','); 59 </script>
59 60 61 62 <!--[if lt IE 9]> 63 <link rel="stylesheet" type="text/css" href="../../%3C%25=SportsApp.Core.MediaUrl%20%25%3Ecss/?pid=<%=_portal.Id %>&ie=1&v=<%=SportsApp.Core.Version %>" /> 64 <![endif]--> 65
66<script type="text/javascript"> 67 var _pageName = "About Johnsonn City Press"; 68 var _ga_sport = ""; 69 var _ga_school = ""; 70 var _ga_guid = ""; 71 var _ga_author = ""; 72 var _ga_pagetype = "custompage"; 73 var _ga_tags = ""; 74</script>
vendor: 67 bytes, lines 74-76
74 75 76<script async src="https://www.googletagmanager.com/gtag/js?id=
76G-ZJ4C47N33G
vendor: 13 bytes, line 76
76"></script>
77<script type="text/javascript"> 78
vendor: 144 bytes, lines 78-82
78window.dataLayer = window.dataLayer || []; 79 function gtag() { dataLayer.push(arguments); } 80 gtag('js', new Date()); 81 82 gtag('config', '
82G-ZJ4C47N33G
vendor: 5 bytes, line 82
82');
83</script>
83 84 85 86<style> 87#silktide-wrapper { 88 --focus: 0 0 0 2px #ffffff, 0 0 0 4px #000000, 0 0 0 6px #ffffff; 89 --boxShadow: -5px 5px 10px 0px #00000012, 0px 0px 50px 0px #0000001a; 90 --fontFamily: Helvetica Neue, Segoe UI, Arial, sans-serif; 91 --primaryColor: white; 92 --backgroundColor: #050505; 93 --textColor: #F4F0DF; 94 --backdropBackgroundColor: #00000033; 95 --backdropBackgroundBlur: 0px; 96 --cookieIconColor: #050505; 97 --cookieIconBackgroundColor: white; 98} 99</style>
100<script> 101 // Initialize the dataLayer 102 window.dataLayer = window.dataLayer || []; 103 104 // Create the gtag function that pushes to the dataLayer 105 function gtag() { 106 dataLayer.push(arguments); 107 } 108 109 // Set consent defaults 110 gtag('consent', 'default', { 111 analytics_storage: localStorage.getItem('silktideCookieChoice_analytics') === 'true' ? 'granted' : 'denied', 112 ad_storage: localStorage.getItem('silktideCookieChoice_marketing') === 'true' ? 'granted' : 'denied', 113 ad_user_data: localStorage.getItem('silktideCookieChoice_marketing') === 'true' ? 'granted' : 'denied', 114 ad_personalization: localStorage.getItem('silktideCookieChoice_marketing') === 'true' ? 'granted' : 'denied', 115 functionality_storage: localStorage.getItem('silktideCookieChoice_necessary') === 'true' ? 'granted' : 'denied', 116 security_storage: localStorage.getItem('silktideCookieChoice_necessary') === 'true' ? 'granted' : 'denied' 117 }); 118</script>
118 119 120<!--Google Consent Default Config-->
121<script> 122 // Define dataLayer and the gtag function 123 window.dataLayer = window.dataLayer || []; 124 function gtag(){dataLayer.push(arguments);} 125 126 // Set default consent to 'granted' as a placeholder 127 if(localStorage.getItem('consentMode') === null){ 128 gtag('consent', 'default', { 129 'ad_storage': 'granted', 130 'ad_user_data': 'granted', 131 'ad_personalization': 'granted', 132 'analytics_storage': 'granted', 133 'personalization_storage': 'granted', 134 'security_storage': 'granted', 135 'functionality_storage': 'granted', 136 }); 137 // To further redact your ads data when ad_storage is denied, set ads_data_redaction to true 138 gtag('set', 'ads_data_redaction', true); 139 } else { 140 gtag('consent', 'default', JSON.parse(localStorage.getItem('consentMode'))); 141 } 142</script>
142 143 144<style> 145/* 146 Silktide Consent Manager - https://silktide.com/consent-manager/ 147*/ 148 149/* -------------------------------- 150 Global Styles - These elements exist in the main DOM and styling is limited to positioning and animation 151-------------------------------- */ 152/* Wrapper (Global) */ 153#silktide-wrapper { 154 position: fixed; 155 bottom: 0; 156 right: 0; 157 width: 100%; 158 height: 100%; 159 z-index: 99999; 160 pointer-events: none; 161 border: 0px; 162 display: flex; 163 justify-content: center; 164 align-items: center; 165 overscroll-behavior: contain; 166 overflow-y: auto; 167 } 168 169/* Backdrop (Global) */ 170#silktide-backdrop-global { 171 position: fixed; 172 top: 0; 173 left: 0; 174 width: 100%; 175 height: 100%; 176 pointer-events: auto; 177 border: 0px; 178 display: none; 179} 180 181/* -------------------------------- 182 Links 183-------------------------------- */ 184#silktide-wrapper a { 185 all: unset; 186 display: inline-block; 187 color: var(--primaryColor); 188 text-decoration: underline; 189} 190 191#silktide-wrapper a:hover { 192 cursor: pointer; 193 color: var(--textColor); 194} 195 196/* -------------------------------- 197 Focus Styles 198-------------------------------- */ 199#silktide-wrapper a:focus, 200#silktide-wrapper #silktide-banner button:focus, 201#silktide-wrapper #silktide-modal button:focus, 202#silktide-wrapper #silktide-cookie-icon:focus { 203 outline: none; 204 box-shadow: var(--focus); 205 border-radius: 5px; 206} 207 208#silktide-wrapper #silktide-cookie-icon:focus { 209 border-radius: 50%; 210} 211 212/* -------------------------------- 213 General Styles 214-------------------------------- */ 215 216#silktide-wrapper .st-button { 217 color: var(--backgroundColor); 218 background-color: var(--primaryColor); 219 border: 2px solid var(--primaryColor); 220 padding: 10px 20px; 221 text-decoration: none; 222 text-align: center; 223 display: inline-block; 224 font-size: 16px; 225 line-height: 24px; 226 cursor: pointer; 227 border-radius: 5px; 228} 229 230#silktide-wrapper .st-button--primary { 231} 232 233#silktide-wrapper .st-button--primary:hover { 234 background-color: var(--backgroundColor); 235 color: var(--primaryColor); 236} 237 238#silktide-wrapper .st-button--secondary { 239 background-color: var(--backgroundColor); 240 color: var(--primaryColor); 241} 242 243#silktide-wrapper .st-button--secondary:hover { 244 background-color: var(--primaryColor); 245 color: var(--backgroundColor); 246} 247 248/* -------------------------------- 249 Banner 250-------------------------------- */ 251#silktide-banner { 252 font-family: var(--fontFamily); 253 color: var(--textColor); 254 background-color: var(--backgroundColor); 255 box-sizing: border-box; 256 padding: 32px; 257 border-radius: 5px; 258 pointer-events: auto; 259 border: 0px; 260 position: fixed; 261 bottom: 16px; 262 right: 16px; 263 width: 600px; 264 overflow: auto; 265 max-width: calc(100% - 32px); 266 max-height: calc(100vh - 32px); 267 transform: translate(0, -20px); 268 opacity: 0; 269 animation: silktide-slideInDown 350ms ease-out forwards; 270 animation-delay: 0.3s; 271 box-shadow: -5px 5px 10px 0px #00000012, 0px 0px 50px 0px #0000001a; 272} 273 274#silktide-banner:focus { 275 border-radius: 50%; 276} 277 278#silktide-banner.center { 279 top: 50%; 280 left: 50%; 281 bottom: auto; 282 right: auto; 283 position: fixed; 284 transform: translate(-50%, calc(-50% - 20px)); 285 animation: silktide-slideInDown-center 350ms ease-out forwards; 286} 287 288#silktide-banner.bottomLeft { 289 bottom: 16px; 290 left: 16px; 291 position: fixed; 292} 293 294#silktide-banner.bottomCenter { 295 bottom: 16px; 296 left: 50%; 297 position: fixed; 298 transform: translate(-50%, -20px); 299 animation: silktide-slideInDown-bottomCenter 350ms ease-out forwards; 300} 301 302#silktide-banner .preferences { 303 display: flex; 304 gap: 5px; 305 border: none; 306 padding: 15px 0px; 307 background-color: transparent; 308 color: var(--primaryColor); 309 cursor: pointer; 310 font-size: 16px; 311} 312 313#silktide-banner .preferences span { 314 display: block; 315 white-space: nowrap; 316 text-decoration: underline; 317} 318 319#silktide-banner .preferences span:hover { 320 color: var(--textColor); 321} 322 323#silktide-banner .preferences:after { 324 display: block; 325 content: '>'; 326 text-decoration: none; 327} 328 329#silktide-banner p { 330 font-size: 16px; 331 line-height: 24px; 332 margin: 0px 0px 15px; 333} 334 335#silktide-banner a { 336 display: inline-block; 337 color: var(--primaryColor); 338 text-decoration: underline; 339 background-color: var(--backgroundColor); 340} 341 342#silktide-banner a:hover {
343 color: var(--textColor); 344} 345 346#silktide-banner a.silktide-logo { 347 display: flex; 348 align-items: center; 349 justify-content: center; 350 fill: var(--primaryColor); /* passed down to svg > path */ 351 margin-left: auto; 352 width: 48px; 353 height: 48px; 354} 355 356 357#silktide-banner .actions { 358 display: flex; 359 gap: 16px; 360 flex-direction: column; 361 margin-top: 24px; 362} 363 364@media (min-width: 600px) { 365 #silktide-banner .actions { 366 flex-direction: row; 367 align-items: center; 368 } 369} 370 371#silktide-banner .actions-row { 372 display: flex; 373 gap: 16px; 374 flex-direction: row; 375 align-items: center; 376 justify-content: space-between; 377 flex-grow: 1; 378} 379 380/* -------------------------------- 381 Modal 382-------------------------------- */ 383#silktide-modal { 384 display: none; 385 pointer-events: auto; 386 overflow: auto; 387 width: 800px; 388 max-width: 100%; 389 max-height: 100%; 390 border: 0px; 391 transform: translate(0px, -20px); 392 opacity: 0; 393 animation: silktide-slideInUp-center 350ms ease-out forwards; 394 box-shadow: -5px 5px 10px 0px #00000012, 0px 0px 50px 0px #0000001a; 395 font-family: var(--fontFamily); 396 color: var(--textColor); 397 flex-direction: column; 398 padding: 30px; 399 background-color: var(--backgroundColor); 400 border-radius: 5px; 401 box-sizing: border-box; 402} 403 404/* -------------------------------- 405 Modal - Header 406-------------------------------- */ 407#silktide-modal .silk-header { 408 display: flex; 409 justify-content: space-between; 410 align-items: center; 411 margin-bottom: 20px; 412 gap: 16px; 413} 414 415#silktide-modal h1 { 416 font-family: var(--fontFamily); 417 color: var(--textColor); 418 font-size: 24px; 419 font-weight: 500; 420 margin: 0px; 421} 422 423#silktide-modal .modal-close { 424 display: inline-flex; 425 border: none; 426 padding: 13px; 427 border: 0px; 428 cursor: pointer; 429 background: var(--backgroundColor); 430 color: var(--primaryColor); 431} 432 433#silktide-modal .modal-close svg { 434 fill: var(--primaryColor); 435} 436 437/* -------------------------------- 438 Modal - Content 439-------------------------------- */ 440 441#silktide-modal section { 442 flex: 1; 443 margin-top: 32px; 444} 445 446#silktide-modal section::-webkit-scrollbar {
447 display: block; /* Force scrollbars to show */ 448 width: 5px; /* Width of the scrollbar */ 449} 450 451#silktide-modal section::-webkit-scrollbar-thumb { 452 background-color: var(--textColor); /* Color of the scrollbar thumb */ 453 border-radius: 10px; /* Rounded corners for the thumb */ 454} 455 456#silktide-modal p { 457 font-size: 16px; 458 line-height: 24px; 459 color: var(--textColor); 460 margin: 0px 0px 15px; 461} 462 463#silktide-modal p:last-of-type { 464 margin: 0px; 465} 466 467#silktide-modal fieldset { 468 padding: 0px; 469 border: none; 470 margin: 0px 0px 32px; 471} 472 473#silktide-modal fieldset:last-of-type { 474 margin: 0px; 475} 476 477#silktide-modal legend { 478 padding: 0px; 479 margin: 0px 0px 10px; 480 font-weight: 700; 481 color: var(--textColor); 482 font-size: 16px; 483} 484 485#silktide-modal .cookie-type-content { 486 display: flex; 487 justify-content: space-between; 488 align-items: flex-start; 489 gap: 24px; 490} 491 492/* -------------------------------- 493 Modal - Switches 494-------------------------------- */ 495#silktide-modal .switch { 496 flex-shrink: 0; 497 position: relative; 498 display: inline-block; 499 height: 34px; 500 width: 74px; 501 cursor: pointer; 502} 503 504#silktide-modal .switch:focus-within { 505 outline: none; 506 box-shadow: var(--focus); 507 border-radius: 25px; 508} 509 510#silktide-modal .switch input { 511 opacity: 0; 512 position: absolute; 513} 514 515/* Unchecked Switch Styles */ 516#silktide-modal .switch__pill { 517 position: relative; 518 display: block; 519 height: 34px; 520 width: 74px; 521 background: var(--textColor); 522 border-radius: 25px; 523} 524 525#silktide-modal .switch__dot { 526 position: absolute; 527 top: 2px; 528 left: 2px; 529 display: block; 530 height: 30px; 531 width: 30px; 532 background: var(--backgroundColor); 533 border-radius: 50%; 534 transition: left 150ms ease-out; 535} 536 537#silktide-modal .switch__off, 538#silktide-modal .switch__on { 539 text-transform: uppercase; 540 font-size: 15px; 541 font-weight: 500; 542 color: var(--backgroundColor); 543 position: absolute; 544 top: 7px; 545 right: 8px; 546 transition: right 150ms ease-out, opacity 150ms ease-out; 547} 548 549#silktide-modal .switch__off { 550 opacity: 1; 551} 552 553#silktide-modal .switch__on { 554 opacity: 0; 555} 556 557/* Checked Switch Styles */ 558#silktide-modal .switch input:checked + .switch__pill { 559 background: var(--primaryColor); 560} 561 562#silktide-modal .switch input:checked ~ .switch__dot { 563 left: calc(100% - 32px); 564} 565 566#silktide-modal .switch input:checked ~ .switch__off { 567 right: calc(100% - 32px); 568 opacity: 0; 569} 570 571#silktide-modal .switch input:checked ~ .switch__on { 572 right: calc(100% - 34px); 573 opacity: 1; 574} 575 576/* Disabled Switch Styles */ 577#silktide-modal .switch input:disabled + .switch__pill { 578 opacity: 0.65; 579 cursor: not-allowed; 580} 581 582/* -------------------------------- 583 Modal - Footer 584-------------------------------- */ 585#silktide-modal .silk-footer { 586 display: flex; 587 flex-direction: column; 588 gap: 16px; 589 margin-top: 24px; 590} 591 592@media (min-width: 600px) { 593 #silktide-modal .silk-footer { 594 flex-direction: row; 595 align-items: center; 596 } 597} 598 599#silktide-modal .silk-footer a { 600 margin-left: auto; 601 padding: 14px 0px; 602} 603 604/* Cookie Icon */ 605#silktide-cookie-icon { 606 display: none !important; 607 position: fixed; 608 bottom: 10px; 609 left: 10px; 610 justify-content: center; 611 align-items: center; 612 width: 60px; 613 height: 60px; 614 border-radius: 50%; 615 padding: 0px; 616 border: none; 617 background-color: var(--cookieIconColor); 618 cursor: pointer; 619 box-shadow: 0px 0px 6px 0px #0000001a; 620 pointer-events: auto; 621 animation: silktide-fadeIn 0.3s ease-in-out forwards; 622} 623 624#silktide-cookie-icon.bottomRight { 625 left: auto; 626 right: 10px; 627} 628 629#silktide-cookie-icon svg { 630 fill: var(--cookieIconBackgroundColor); 631} 632 633/* -------------------------------- 634 Backdrop 635-------------------------------- */ 636#silktide-backdrop { 637 display: none; 638 position: absolute; 639 top: 0; 640 left: 0; 641 width: 100%; 642 height: 100%; 643 background-color: var(--backdropBackgroundColor); 644 backdrop-filter: blur(var(--backdropBackgroundBlur)); 645 pointer-events: all; 646} 647 648/* -------------------------------- 649 Animations 650-------------------------------- */ 651@keyframes silktide-fadeIn { 652 from { 653 opacity: 0; 654 } 655 to { 656 opacity: 1; 657 } 658} 659 660@keyframes silktide-slideInDown { 661 from { 662 opacity: 0; 663 transform: translateY(-20px); 664 } 665 to { 666 opacity: 1; 667 transform: translateY(0); 668 } 669} 670 671@keyframes silktide-slideInDown-center { 672 from { 673 opacity: 0; 674 transform: translate(-50%, calc(-50% - 20px)); 675 } 676 to { 677 opacity: 1; 678 transform: translate(-50%, -50%); 679 } 680} 681 682@keyframes silktide-slideInDown-bottomCenter { 683 from { 684 opacity: 0; 685 transform: translate(-50%, -20px); 686 } 687 to { 688 opacity: 1; 689 transform: translate(-50%, 0); 690 } 691} 692 693@keyframes silktide-slideInUp-center { 694 from { 695 opacity: 0; 696 transform: translate(0px, 20px); 697 } 698 to { 699 opacity: 1; 700 transform: translate(0px, 0px); 701 } 702} 703 704</style>
705<script> 706// Silktide Consent Manager - https://silktide.com/consent-manager/ 707 708class SilktideCookieBanner { 709 constructor(config) { 710 this.config = config; // Save config to the instance 711 712 this.wrapper = null; 713 this.banner = null; 714 this.modal = null; 715 this.cookieIcon = null; 716 this.backdrop = null; 717 718 this.createWrapper(); 719 720 if (this.shouldShowBackdrop()) { 721 this.createBackdrop(); 722 } 723 724 this.createCookieIcon(); 725 this.createModal(); 726 727 if (this.shouldShowBanner()) { 728 this.createBanner(); 729 this.showBackdrop(); 730 } else { 731 this.showCookieIcon(); 732 } 733 734 this.setupEventListeners(); 735 736 if (this.hasSetInitialCookieChoices()) { 737 this.loadRequiredCookies(); 738 this.runAcceptedCookieCallbacks(); 739 } 740 } 741 742 destroyCookieBanner() { 743 // Remove all cookie banner elements from the DOM 744 if (this.wrapper && this.wrapper.parentNode) { 745 this.wrapper.parentNode.removeChild(this.wrapper); 746 } 747 748 // Restore scrolling 749 this.allowBodyScroll(); 750 751 // Clear all references 752 this.wrapper = null; 753 this.banner = null; 754 this.modal = null; 755 this.cookieIcon = null; 756 this.backdrop = null; 757 } 758 759 // ---------------------------------------------------------------- 760 // Wrapper 761 // ---------------------------------------------------------------- 762 createWrapper() { 763 this.wrapper = document.createElement('div'); 764 this.wrapper.id = 'silktide-wrapper'; 765 document.body.insertBefore(this.wrapper, document.body.firstChild); 766 } 767 768 // ---------------------------------------------------------------- 769 // Wrapper Child Generator 770 // ---------------------------------------------------------------- 771 createWrapperChild(htmlContent, id) { 772 // Create child element 773 const child = document.createElement('div'); 774 child.id = id; 775 child.innerHTML = htmlContent; 776 777 // Ensure wrapper exists 778 if (!this.wrapper || !document.body.contains(this.wrapper)) { 779 this.createWrapper(); 780 } 781 782 // Append child to wrapper 783 this.wrapper.appendChild(child); 784 return child; 785 } 786 787 // ---------------------------------------------------------------- 788 // Backdrop 789 // ---------------------------------------------------------------- 790 createBackdrop() { 791 this.backdrop = this.createWrapperChild(null, 'silktide-backdrop'); 792 } 793 794 showBackdrop() { 795 if (this.backdrop) { 796 this.backdrop.style.display = 'block'; 797 }
798 // Trigger optional onBackdropOpen callback 799 if (typeof this.config.onBackdropOpen === 'function') { 800 this.config.onBackdropOpen(); 801 } 802 } 803 804 hideBackdrop() { 805 if (this.backdrop) { 806 this.backdrop.style.display = 'none'; 807 } 808 809 // Trigger optional onBackdropClose callback 810 if (typeof this.config.onBackdropClose === 'function') { 811 this.config.onBackdropClose(); 812 } 813 } 814 815 shouldShowBackdrop() { 816 return this.config?.background?.showBackground || false; 817 } 818 819 // update the checkboxes in the modal with the values from localStorage 820 updateCheckboxState(saveToStorage = false) { 821 const preferencesSection = this.modal.querySelector('#cookie-preferences'); 822 const checkboxes = preferencesSection.querySelectorAll('input[type="checkbox"]'); 823 824 checkboxes.forEach((checkbox) => { 825 const [, cookieId] = checkbox.id.split('cookies-'); 826 const cookieType = this.config.cookieTypes.find(type => type.id === cookieId); 827 828 if (!cookieType) return; 829 830 if (saveToStorage) { 831 // Save the current state to localStorage and run callbacks 832 const currentState = checkbox.checked; 833 834 if (cookieType.required) { 835 localStorage.setItem( 836 `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}`, 837 'true' 838 ); 839 } else { 840 localStorage.setItem( 841 `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}`, 842 currentState.toString() 843 ); 844 845 // Run appropriate callback 846 if (currentState && typeof cookieType.onAccept === 'function') { 847 cookieType.onAccept(); 848 } else if (!currentState && typeof cookieType.onReject === 'function') { 849 cookieType.onReject(); 850 } 851 } 852 } else { 853 // When reading values (opening modal) 854 if (cookieType.required) { 855 checkbox.checked = true; 856 checkbox.disabled = true; 857 } else { 858 const storedValue = localStorage.getItem( 859 `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}` 860 ); 861 862 if (storedValue !== null) { 863 checkbox.checked = storedValue === 'true'; 864 } else { 865 checkbox.checked = !!cookieType.defaultValue; 866 } 867 } 868 } 869 }); 870 } 871 872 setInitialCookieChoiceMade() { 873 window.localStorage.setItem(`silktideCookieBanner_InitialChoice${this.getBannerSuffix()}`, 1); 874 } 875 876 // ---------------------------------------------------------------- 877 // Consent Handling 878 // ---------------------------------------------------------------- 879 handleCookieChoice(accepted) { 880 // We set that an initial choice was made regardless of what it was so we don't show the banner again 881 this.setInitialCookieChoiceMade(); 882 883 this.removeBanner(); 884 this.hideBackdrop(); 885 this.toggleModal(false); 886 this.showCookieIcon(); 887 888 this.config.cookieTypes.forEach((type) => { 889 // Set localStorage and run accept/reject callbacks 890 if (type.required == true) { 891 localStorage.setItem(`silktideCookieChoice_${type.id}${this.getBannerSuffix()}`, 'true'); 892 if (typeof type.onAccept === 'function') { type.onAccept() } 893 } else { 894 localStorage.setItem( 895 `silktideCookieChoice_${type.id}${this.getBannerSuffix()}`, 896 accepted.toString(), 897 ); 898 899 if (accepted) { 900 if (typeof type.onAccept === 'function') { type.onAccept(); } 901 } else { 902 if (typeof type.onReject === 'function') { type.onReject(); } 903 } 904 } 905 }); 906 907 // Trigger optional onAcceptAll/onRejectAll callbacks 908 if (accepted && typeof this.config.onAcceptAll === 'function') { 909 if (typeof this.config.onAcceptAll === 'function') { this.config.onAcceptAll(); } 910 } else if (typeof this.config.onRejectAll === 'function') { 911 if (typeof this.config.onRejectAll === 'function') { this.config.onRejectAll(); } 912 } 913 914 // finally update the checkboxes in the modal with the values from localStorage 915 this.updateCheckboxState(); 916 } 917 918 getAcceptedCookies() { 919 return (this.config.cookieTypes || []).reduce((acc, cookieType) => { 920 acc[cookieType.id] = 921 localStorage.getItem(`silktideCookieChoice_${cookieType.id}${this.getBannerSuffix()}`) === 922 'true'; 923 return acc; 924 }, {}); 925 } 926 927 runAcceptedCookieCallbacks() { 928 if (!this.config.cookieTypes) return; 929 930 const acceptedCookies = this.getAcceptedCookies();
931 this.config.cookieTypes.forEach((type) => { 932 if (type.required) return; // we run required cookies separately in loadRequiredCookies 933 if (acceptedCookies[type.id] && typeof type.onAccept === 'function') { 934 if (typeof type.onAccept === 'function') { type.onAccept(); } 935 } 936 }); 937 } 938 939 runRejectedCookieCallbacks() { 940 if (!this.config.cookieTypes) return; 941 942 const rejectedCookies = this.getRejectedCookies(); 943 this.config.cookieTypes.forEach((type) => { 944 if (rejectedCookies[type.id] && typeof type.onReject === 'function') { 945 if (typeof type.onReject === 'function') { type.onReject(); } 946 } 947 }); 948 } 949 950 /** 951 * Run through all of the cookie callbacks based on the current localStorage values 952 */ 953 runStoredCookiePreferenceCallbacks() { 954 this.config.cookieTypes.forEach((type) => { 955 const accepted = 956 localStorage.getItem(`silktideCookieChoice_${type.id}${this.getBannerSuffix()}`) === 'true'; 957 // Set localStorage and run accept/reject callbacks 958 if (accepted) { 959 if (typeof type.onAccept === 'function') { type.onAccept(); } 960 } else { 961 if (typeof type.onReject === 'function') { type.onReject(); } 962 } 963 }); 964 } 965 966 loadRequiredCookies() { 967 if (!this.config.cookieTypes) return;
968 this.config.cookieTypes.forEach((cookie) => { 969 if (cookie.required && typeof cookie.onAccept === 'function') { 970 if (typeof cookie.onAccept === 'function') { cookie.onAccept(); } 971 } 972 }); 973 } 974 975 // ---------------------------------------------------------------- 976 // Banner 977 // ---------------------------------------------------------------- 978 getBannerContent() { 979 const bannerDescription = 980 this.config.text?.banner?.description || 981 "<p>We use cookies on our site to enhance your user experience, provide personalized content, and analyze our traffic.</p>"; 982 983 // Accept button 984 const acceptAllButtonText = this.config.text?.banner?.acceptAllButtonText || 'Accept all'; 985 const acceptAllButtonLabel = this.config.text?.banner?.acceptAllButtonAccessibleLabel; 986 const acceptAllButton = `<button class="accept-all st-button st-button--primary"${ 987 acceptAllButtonLabel && acceptAllButtonLabel !== acceptAllButtonText 988 ? ` aria-label="${acceptAllButtonLabel}"` 989 : '' 990 }>${acceptAllButtonText}</button>`; 991 992 // Reject button 993 const rejectNonEssentialButtonText = this.config.text?.banner?.rejectNonEssentialButtonText || 'Reject non-essential'; 994 const rejectNonEssentialButtonLabel = this.config.text?.banner?.rejectNonEssentialButtonAccessibleLabel; 995 const rejectNonEssentialButton = `<button class="reject-all st-button st-button--primary"${ 996 rejectNonEssentialButtonLabel && rejectNonEssentialButtonLabel !== rejectNonEssentialButtonText 997 ? ` aria-label="${rejectNonEssentialButtonLabel}"` 998 : '' 999 }>${rejectNonEssentialButtonText}</button>`; 1000 1001 // Preferences button 1002 const preferencesButtonText = this.config.text?.banner?.preferencesButtonText || 'Preferences'; 1003 const preferencesButtonLabel = this.config.text?.banner?.preferencesButtonAccessibleLabel; 1004 const preferencesButton = `<button class="preferences"${ 1005 preferencesButtonLabel && preferencesButtonLabel !== preferencesButtonText 1006 ? ` aria-label="${preferencesButtonLabel}"` 1007 : '' 1008 }><span>${preferencesButtonText}</span></button>`; 1009 1010 1011 // Silktide logo link 1012 const silktideLogo = ` 1013 <a class="silktide-logo" href="https://silktide.com/consent-manager" target="_blank" rel="noreferrer" aria-label="Visit the Silktide Consent Manager page"> 1014 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="25" viewBox="0 0 24 25" fill="inherit"> 1015 <path fill-rule="evenodd" clip-rule="evenodd" d="M14.1096 16.7745C13.8895 17.2055 13.3537 17.3805 12.9129 17.1653L8.28443 14.9055L2.73192 17.7651L11.1025 21.9814C11.909 22.3876 12.8725 22.3591 13.6524 21.9058L20.4345 17.9645C21.2845 17.4704 21.7797 16.5522 21.7164 15.5872L21.7088 15.4704C21.6487 14.5561 21.0962 13.7419 20.2579 13.3326L15.6793 11.0972L10.2283 13.9045L13.71 15.6043C14.1507 15.8195 14.3297 16.3434 14.1096 16.7745ZM8.2627 12.9448L13.7136 10.1375L10.2889 8.46543C9.84803 8.25021 9.66911 7.72629 9.88916 7.29524C10.1093 6.86417 10.6451 6.68921 11.0859 6.90442L15.6575 9.13647L21.2171 6.27325L12.8808 2.03496C12.0675 1.62147 11.0928 1.65154 10.3078 2.11432L3.54908 6.09869C2.70732 6.59492 2.21846 7.50845 2.28139 8.46761L2.29003 8.59923C2.35002 9.51362 2.9026 10.3278 3.7409 10.7371L8.2627 12.9448ZM6.31884 13.9458L2.94386 12.2981C1.53727 11.6113 0.610092 10.2451 0.509431 8.71094L0.500795 8.57933C0.3952 6.96993 1.21547 5.4371 2.62787 4.60447L9.38662 0.620092C10.7038 -0.156419 12.3392 -0.206861 13.7039 0.486938L23.3799 5.40639C23.4551 5.44459 23.5224 5.4918 23.5811 5.54596C23.7105 5.62499 23.8209 5.73754 23.897 5.87906C24.1266 6.30534 23.9594 6.83293 23.5234 7.05744L17.6231 10.0961L21.0549 11.7716C22.4615 12.4583 23.3887 13.8245 23.4893 15.3587L23.497 15.4755C23.6033 17.0947 22.7724 18.6354 21.346 19.4644L14.5639 23.4057C13.2554 24.1661 11.6386 24.214 10.2854 23.5324L0.621855 18.6649C0.477299 18.592 0.361696 18.4859 0.279794 18.361C0.210188 18.2968 0.150054 18.2204 0.10296 18.133C-0.126635 17.7067 0.0406445 17.1792 0.47659 16.9546L6.31884 13.9458Z" fill="inherit"/> 1016 </svg> 1017 </a> 1018 `; 1019 1020 const bannerContent = ` 1021 ${bannerDescription} 1022 <div class="actions"> 1023 ${acceptAllButton} 1024 ${rejectNonEssentialButton} 1025 <div class="actions-row"> 1026 ${preferencesButton} 1027 1028 </div> 1029 </div> 1030 `; 1031 1032 return bannerContent; 1033 } 1034 1035 hasSetInitialCookieChoices() { 1036 return !!localStorage.getItem(`silktideCookieBanner_InitialChoice${this.getBannerSuffix()}`); 1037 } 1038 1039 createBanner() { 1040 // Create banner element 1041 this.banner = this.createWrapperChild(this.getBannerContent(), 'silktide-banner'); 1042 1043 // Add positioning class from config 1044 if (this.banner && this.config.position?.banner) { 1045 this.banner.classList.add(this.config.position.banner); 1046 } 1047 1048 // Trigger optional onBannerOpen callback 1049 if (this.banner && typeof this.config.onBannerOpen === 'function') { 1050 this.config.onBannerOpen(); 1051 } 1052 } 1053 1054 removeBanner() { 1055 if (this.banner && this.banner.parentNode) { 1056 this.banner.parentNode.removeChild(this.banner); 1057 this.banner = null; 1058 1059 // Trigger optional onBannerClose callback 1060 if (typeof this.config.onBannerClose === 'function') { 1061 this.config.onBannerClose(); 1062 } 1063 } 1064 } 1065 1066 shouldShowBanner() { 1067 if (this.config.showBanner === false) { 1068 return false;
1069 } 1070 return ( 1071 localStorage.getItem(`silktideCookieBanner_InitialChoice${this.getBannerSuffix()}`) === null 1072 ); 1073 } 1074 1075 // ---------------------------------------------------------------- 1076 // Modal 1077 // ---------------------------------------------------------------- 1078 getModalContent() { 1079 const preferencesTitle = 1080 this.config.text?.preferences?.title || 'Customize your cookie preferences'; 1081 1082 const preferencesDescription = 1083 this.config.text?.preferences?.description || 1084 "<p>We respect your right to privacy. You can choose not to allow some types of cookies. Your cookie preferences will apply across our website.</p>"; 1085 1086 // Preferences button 1087 const preferencesButtonLabel = this.config.text?.banner?.preferencesButtonAccessibleLabel; 1088 1089 const closeModalButton = `<button class="modal-close"${preferencesButtonLabel ? ` aria-label="${preferencesButtonLabel}"` : ''}> 1090 <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"> 1091 <path d="M19.4081 3.41559C20.189 2.6347 20.189 1.36655 19.4081 0.585663C18.6272 -0.195221 17.3591 -0.195221 16.5782 0.585663L10 7.17008L3.41559 0.59191C2.6347 -0.188974 1.36655 -0.188974 0.585663 0.59191C-0.195221 1.37279 -0.195221 2.64095 0.585663 3.42183L7.17008 10L0.59191 16.5844C-0.188974 17.3653 -0.188974 18.6335 0.59191 19.4143C1.37279 20.1952 2.64095 20.1952 3.42183 19.4143L10 12.8299L16.5844 19.4081C17.3653 20.189 18.6335 20.189 19.4143 19.4081C20.1952 18.6272 20.1952 17.3591 19.4143 16.5782L12.8299 10L19.4081 3.41559Z"/> 1092 </svg> 1093 </button>`; 1094 1095 1096 const cookieTypes = this.config.cookieTypes || []; 1097 const acceptedCookieMap = this.getAcceptedCookies(); 1098 1099 // Accept button 1100 const acceptAllButtonText = this.config.text?.banner?.acceptAllButtonText || 'Accept all'; 1101 const acceptAllButtonLabel = this.config.text?.banner?.acceptAllButtonAccessibleLabel; 1102 const acceptAllButton = `<button class="preferences-accept-all st-button st-button--primary"${ 1103 acceptAllButtonLabel && acceptAllButtonLabel !== acceptAllButtonText 1104 ? ` aria-label="${acceptAllButtonLabel}"` 1105 : '' 1106 }>${acceptAllButtonText}</button>`; 1107 1108 // Reject button 1109 const rejectNonEssentialButtonText = this.config.text?.banner?.rejectNonEssentialButtonText || 'Reject non-essential'; 1110 const rejectNonEssentialButtonLabel = this.config.text?.banner?.rejectNonEssentialButtonAccessibleLabel; 1111 const rejectNonEssentialButton = `<button class="preferences-reject-all st-button st-button--primary"${ 1112 rejectNonEssentialButtonLabel && rejectNonEssentialButtonLabel !== rejectNonEssentialButtonText 1113 ? ` aria-label="${rejectNonEssentialButtonLabel}"` 1114 : '' 1115 }>${rejectNonEssentialButtonText}</button>`; 1116 1117 // Credit link 1118 const creditLinkText = this.config.text?.preferences?.creditLinkText || ''; 1119 const creditLinkAccessibleLabel = this.config.text?.preferences?.creditLinkAccessibleLabel; 1120 const creditLink = `<a href="https://silktide.com/consent-manager" target="_blank" rel="noreferrer"${ 1121 creditLinkAccessibleLabel && creditLinkAccessibleLabel !== creditLinkText 1122 ? ` aria-label="${creditLinkAccessibleLabel}"` 1123 : '' 1124 }>${creditLinkText}</a>`; 1125 1126 1127 1128 const modalContent = ` 1129 <div class="silk-header"> 1130 <h1>${preferencesTitle}</h1> 1131 ${closeModalButton} 1132 </div> 1133 ${preferencesDescription} 1134 <section id="cookie-preferences"> 1135 ${cookieTypes 1136 .map((type) => { 1137 const accepted = acceptedCookieMap[type.id]; 1138 let isChecked = false; 1139 1140 // if it's accepted then show as checked 1141 if (accepted) { 1142 isChecked = true; 1143 } 1144 1145 // if nothing has been accepted / rejected yet, then show as checked if the default value is true 1146 if (!accepted && !this.hasSetInitialCookieChoices()) { 1147 isChecked = type.defaultValue; 1148 } 1149 1150 return ` 1151 <fieldset> 1152 <legend>${type.name}</legend> 1153 <div class="cookie-type-content"> 1154 <div class="cookie-type-description">${type.description}</div> 1155 <label class="switch" for="cookies-${type.id}"> 1156 <input type="checkbox" id="cookies-${type.id}" ${ 1157 type.required ? 'checked disabled' : isChecked ? 'checked' : '' 1158 } />
1159 <span class="switch__pill" aria-hidden="true"></span> 1160 <span class="switch__dot" aria-hidden="true"></span> 1161 <span class="switch__off" aria-hidden="true">Off</span> 1162 <span class="switch__on" aria-hidden="true">On</span> 1163 </label> 1164 </div> 1165 </fieldset> 1166 `; 1167 }) 1168 .join('')} 1169 </section> 1170 <div class="silk-footer"> 1171 ${acceptAllButton} 1172 ${rejectNonEssentialButton} 1173 ${creditLink} 1174 </div> 1175 `; 1176 1177 return modalContent; 1178 } 1179 1180 createModal() { 1181 // Create banner element 1182 this.modal = this.createWrapperChild(this.getModalContent(), 'silktide-modal'); 1183 } 1184 1185 toggleModal(show) { 1186 if (!this.modal) return; 1187 1188 this.modal.style.display = show ? 'flex' : 'none'; 1189 1190 if (show) { 1191 this.showBackdrop(); 1192 this.hideCookieIcon(); 1193 this.removeBanner(); 1194 this.preventBodyScroll(); 1195 1196 // Focus the close button 1197 const modalCloseButton = this.modal.querySelector('.modal-close'); 1198 modalCloseButton.focus(); 1199 1200 // Trigger optional onPreferencesOpen callback 1201 if (typeof this.config.onPreferencesOpen === 'function') { 1202 this.config.onPreferencesOpen(); 1203 } 1204 1205 this.updateCheckboxState(false); // read from storage when opening 1206 } else { 1207 // Set that an initial choice was made when closing the modal 1208 this.setInitialCookieChoiceMade(); 1209 1210 // Save current checkbox states to storage 1211 this.updateCheckboxState(true); 1212 1213 this.hideBackdrop(); 1214 this.showCookieIcon(); 1215 this.allowBodyScroll(); 1216 1217 // Trigger optional onPreferencesClose callback 1218 if (typeof this.config.onPreferencesClose === 'function') { 1219 this.config.onPreferencesClose(); 1220 } 1221 } 1222 } 1223 1224 // ---------------------------------------------------------------- 1225 // Cookie Icon 1226 // ---------------------------------------------------------------- 1227 getCookieIconContent() { 1228 return ` 1229 <svg width="38" height="38" viewBox="0 0 38 38" fill="none" xmlns="http://www.w3.org/2000/svg"> 1230 <path d="M19.1172 1.15625C19.0547 0.734374 18.7344 0.390624 18.3125 0.328124C16.5859 0.0859365 14.8281 0.398437 13.2813 1.21875L7.5 4.30469C5.96094 5.125 4.71875 6.41406 3.95313 7.98437L1.08594 13.8906C0.320314 15.4609 0.0703136 17.2422 0.375001 18.9609L1.50781 25.4297C1.8125 27.1562 2.64844 28.7344 3.90625 29.9531L8.61719 34.5156C9.875 35.7344 11.4766 36.5156 13.2031 36.7578L19.6875 37.6719C21.4141 37.9141 23.1719 37.6016 24.7188 36.7812L30.5 33.6953C32.0391 32.875 33.2813 31.5859 34.0469 30.0078L36.9141 24.1094C37.6797 22.5391 37.9297 20.7578 37.625 19.0391C37.5547 18.625 37.2109 18.3125 36.7969 18.25C32.7734 17.6094 29.5469 14.5703 28.6328 10.6406C28.4922 10.0469 28.0078 9.59375 27.4063 9.5C23.1406 8.82031 19.7734 5.4375 19.1094 1.15625H19.1172ZM15.25 10.25C15.913 10.25 16.5489 10.5134 17.0178 10.9822C17.4866 11.4511 17.75 12.087 17.75 12.75C17.75 13.413 17.4866 14.0489 17.0178 14.5178C16.5489 14.9866 15.913 15.25 15.25 15.25C14.587 15.25 13.9511 14.9866 13.4822 14.5178C13.0134 14.0489 12.75 13.413 12.75 12.75C12.75 12.087 13.0134 11.4511 13.4822 10.9822C13.9511 10.5134 14.587 10.25 15.25 10.25ZM10.25 25.25C10.25 24.587 10.5134 23.9511 10.9822 23.4822C11.4511 23.0134 12.087 22.75 12.75 22.75C13.413 22.75 14.0489 23.0134 14.5178 23.4822C14.9866 23.9511 15.25 24.587 15.25 25.25C15.25 25.913 14.9866 26.5489 14.5178 27.0178C14.0489 27.4866 13.413 27.75 12.75 27.75C12.087 27.75 11.4511 27.4866 10.9822 27.0178C10.5134 26.5489 10.25 25.913 10.25 25.25ZM27.75 20.25C28.413 20.25 29.0489 20.5134 29.5178 20.9822C29.9866 21.4511 30.25 22.087 30.25 22.75C30.25 23.413 29.9866 24.0489 29.5178 24.5178C29.0489 24.9866 28.413 25.25 27.75 25.25C27.087 25.25 26.4511 24.9866 25.9822 24.5178C25.5134 24.0489 25.25 23.413 25.25 22.75C25.25 22.087 25.5134 21.4511 25.9822 20.9822C26.4511 20.5134 27.087 20.25 27.75 20.25Z" /> 1231 </svg> 1232 `; 1233 } 1234 1235 createCookieIcon() { 1236 this.cookieIcon = document.createElement('button'); 1237 this.cookieIcon.id = 'silktide-cookie-icon'; 1238 this.cookieIcon.title = 'Manage your cookie preferences for this site'; 1239 this.cookieIcon.innerHTML = this.getCookieIconContent(); 1240 1241 if (this.config.text?.banner?.preferencesButtonAccessibleLabel) { 1242 this.cookieIcon.ariaLabel = this.config.text?.banner?.preferencesButtonAccessibleLabel; 1243 } 1244 1245 // Ensure wrapper exists 1246 if (!this.wrapper || !document.body.contains(this.wrapper)) { 1247 this.createWrapper(); 1248 } 1249 1250 // Append child to wrapper 1251 this.wrapper.appendChild(this.cookieIcon); 1252 1253 // Add positioning class from config 1254 if (this.cookieIcon && this.config.cookieIcon?.position) { 1255 this.cookieIcon.classList.add(this.config.cookieIcon.position); 1256 } 1257 1258 // Add color scheme class from config 1259 if (this.cookieIcon && this.config.cookieIcon?.colorScheme) { 1260 this.cookieIcon.classList.add(this.config.cookieIcon.colorScheme); 1261 } 1262 } 1263 1264 showCookieIcon() { 1265 if (this.cookieIcon) { 1266 this.cookieIcon.style.display = 'flex'; 1267 } 1268 } 1269 1270 hideCookieIcon() { 1271 if (this.cookieIcon) { 1272 this.cookieIcon.style.display = 'none'; 1273 } 1274 } 1275 1276 /** 1277 * This runs if the user closes the modal without making a choice for the first time 1278 * We apply the default values and the necessary values as default 1279 */ 1280 handleClosedWithNoChoice() {
1281 this.config.cookieTypes.forEach((type) => { 1282 let accepted = true; 1283 // Set localStorage and run accept/reject callbacks 1284 if (type.required == true || type.defaultValue) { 1285 localStorage.setItem( 1286 `silktideCookieChoice_${type.id}${this.getBannerSuffix()}`, 1287 accepted.toString(), 1288 ); 1289 } else { 1290 accepted = false; 1291 localStorage.setItem( 1292 `silktideCookieChoice_${type.id}${this.getBannerSuffix()}`, 1293 accepted.toString(), 1294 ); 1295 } 1296 1297 if (accepted) { 1298 if (typeof type.onAccept === 'function') { type.onAccept(); } 1299 } else { 1300 if (typeof type.onReject === 'function') { type.onReject(); } 1301 } 1302 // set the flag to say that the cookie choice has been made 1303 this.setInitialCookieChoiceMade(); 1304 this.updateCheckboxState(); 1305 }); 1306 } 1307 1308 // ---------------------------------------------------------------- 1309 // Focusable Elements 1310 // ---------------------------------------------------------------- 1311 getFocusableElements(element) { 1312 return element.querySelectorAll( 1313 'button, a[href], input, select, textarea, [tabindex]:not([tabindex="-1"])', 1314 ); 1315 } 1316 1317 // ---------------------------------------------------------------- 1318 // Event Listeners 1319 // ---------------------------------------------------------------- 1320 setupEventListeners() { 1321 // Check Banner exists before trying to add event listeners 1322 if (this.banner) { 1323 // Get the buttons 1324 const acceptButton = this.banner.querySelector('.accept-all'); 1325 const rejectButton = this.banner.querySelector('.reject-all'); 1326 const preferencesButton = this.banner.querySelector('.preferences'); 1327 1328 // Add event listeners to the buttons 1329 acceptButton?.addEventListener('click', () => this.handleCookieChoice(true)); 1330 rejectButton?.addEventListener('click', () => this.handleCookieChoice(false)); 1331 preferencesButton?.addEventListener('click', () => { 1332 this.showBackdrop(); 1333 this.toggleModal(true); 1334 }); 1335 1336 // Focus Trap 1337 const focusableElements = this.getFocusableElements(this.banner); 1338 const firstFocusableEl = focusableElements[0]; 1339 const lastFocusableEl = focusableElements[focusableElements.length - 1]; 1340 1341 // Add keydown event listener to handle tab navigation 1342 this.banner.addEventListener('keydown', (e) => { 1343 if (e.key === 'Tab') { 1344 if (e.shiftKey) { 1345 if (document.activeElement === firstFocusableEl) {
1346 lastFocusableEl.focus(); 1347 e.preventDefault(); 1348 } 1349 } else { 1350 if (document.activeElement === lastFocusableEl) { 1351 firstFocusableEl.focus(); 1352 e.preventDefault(); 1353 } 1354 } 1355 } 1356 }); 1357 1358 // Set initial focus 1359 if (this.config.mode !== 'wizard') { 1360 acceptButton?.focus(); 1361 } 1362 } 1363 1364 // Check Modal exists before trying to add event listeners 1365 if (this.modal) { 1366 const closeButton = this.modal.querySelector('.modal-close'); 1367 const acceptAllButton = this.modal.querySelector('.preferences-accept-all'); 1368 const rejectAllButton = this.modal.querySelector('.preferences-reject-all'); 1369 1370 closeButton?.addEventListener('click', () => { 1371 this.toggleModal(false); 1372 1373 const hasMadeFirstChoice = this.hasSetInitialCookieChoices(); 1374 1375 if (hasMadeFirstChoice) { 1376 // run through the callbacks based on the current localStorage state 1377 this.runStoredCookiePreferenceCallbacks(); 1378 } else { 1379 // handle the case where the user closes without making a choice for the first time 1380 this.handleClosedWithNoChoice(); 1381 } 1382 }); 1383 acceptAllButton?.addEventListener('click', () => this.handleCookieChoice(true)); 1384 rejectAllButton?.addEventListener('click', () => this.handleCookieChoice(false)); 1385 1386 // Banner Focus Trap 1387 const focusableElements = this.getFocusableElements(this.modal); 1388 const firstFocusableEl = focusableElements[0]; 1389 const lastFocusableEl = focusableElements[focusableElements.length - 1]; 1390 1391 this.modal.addEventListener('keydown', (e) => { 1392 if (e.key === 'Tab') { 1393 if (e.shiftKey) { 1394 if (document.activeElement === firstFocusableEl) {
1395 lastFocusableEl.focus(); 1396 e.preventDefault(); 1397 } 1398 } else { 1399 if (document.activeElement === lastFocusableEl) { 1400 firstFocusableEl.focus(); 1401 e.preventDefault(); 1402 } 1403 } 1404 } 1405 if (e.key === 'Escape') { 1406 this.toggleModal(false); 1407 } 1408 }); 1409 1410 closeButton?.focus(); 1411 1412 // Update the checkbox event listeners 1413 const preferencesSection = this.modal.querySelector('#cookie-preferences'); 1414 const checkboxes = preferencesSection.querySelectorAll('input[type="checkbox"]'); 1415 1416 checkboxes.forEach(checkbox => { 1417 checkbox.addEventListener('change', (event) => { 1418 const [, cookieId] = event.target.id.split('cookies-'); 1419 const isAccepted = event.target.checked; 1420 const previousValue = localStorage.getItem( 1421 `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}` 1422 ) === 'true'; 1423 1424 // Only proceed if the value has actually changed 1425 if (isAccepted !== previousValue) { 1426 // Find the corresponding cookie type 1427 const cookieType = this.config.cookieTypes.find(type => type.id === cookieId); 1428 1429 if (cookieType) { 1430 // Update localStorage 1431 localStorage.setItem( 1432 `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}`, 1433 isAccepted.toString() 1434 ); 1435 1436 // Run the appropriate callback only if the value changed 1437 if (isAccepted && typeof cookieType.onAccept === 'function') { 1438 cookieType.onAccept(); 1439 } else if (!isAccepted && typeof cookieType.onReject === 'function') { 1440 cookieType.onReject(); 1441 } 1442 } 1443 } 1444 }); 1445 }); 1446 } 1447 1448 // Check Cookie Icon exists before trying to add event listeners 1449 if (this.cookieIcon) { 1450 1451 this.cookieIcon.addEventListener('click', () => { 1452 // If modal is not found, create it 1453 if (!this.modal) { 1454 this.createModal(); 1455 this.toggleModal(true); 1456 this.hideCookieIcon(); 1457 } 1458 // If modal is hidden, show it 1459 else if (this.modal.style.display === 'none' || this.modal.style.display === '') { 1460 this.toggleModal(true); 1461 this.hideCookieIcon(); 1462 } 1463 // If modal is visible, hide it 1464 else { 1465 this.toggleModal(false); 1466 } 1467 }); 1468 } 1469 } 1470 1471 getBannerSuffix() { 1472 if (this.config.bannerSuffix) { 1473 return '_' + this.config.bannerSuffix; 1474 } 1475 return ''; 1476 } 1477 1478 preventBodyScroll() { 1479 document.body.style.overflow = 'hidden'; 1480 // Prevent iOS Safari scrolling 1481 document.body.style.position = 'fixed'; 1482 document.body.style.width = '100%'; 1483 } 1484 1485 allowBodyScroll() { 1486 document.body.style.overflow = ''; 1487 document.body.style.position = ''; 1488 document.body.style.width = ''; 1489 } 1490} 1491 1492(function () { 1493 window.silktideCookieBannerManager = {}; 1494 1495 let config = {}; 1496 let cookieBanner; 1497 1498 function updateCookieBannerConfig(userConfig = {}) { 1499 config = {...config, ...userConfig}; 1500 1501 // If cookie banner exists, destroy and recreate it with new config 1502 if (cookieBanner) { 1503 cookieBanner.destroyCookieBanner(); // We'll need to add this method 1504 cookieBanner = null; 1505 } 1506 1507 // Only initialize if document.body exists 1508 if (document.body) { 1509 initCookieBanner(); 1510 } else { 1511 // Wait for DOM to be ready 1512 document.addEventListener('DOMContentLoaded', initCookieBanner, {once: true}); 1513 } 1514 } 1515 1516 function initCookieBanner() { 1517 if (!cookieBanner) { 1518 cookieBanner = new SilktideCookieBanner(config); // Pass config to the CookieBanner instance 1519 } 1520 } 1521 1522 function injectScript(url, loadOption) { 1523 // Check if script with this URL already exists 1524 const existingScript = document.querySelector(`script[src="${url}"]`); 1525 if (existingScript) { 1526 return; // Script already exists, don't add it again 1527 } 1528 1529 const script = document.createElement('script'); 1530 script.src = url; 1531 1532 // Apply the async or defer attribute based on the loadOption parameter 1533 if (loadOption === 'async') { 1534 script.async = true; 1535 } else if (loadOption === 'defer') { 1536 script.defer = true; 1537 } 1538 1539 document.head.appendChild(script); 1540 } 1541 1542 window.silktideCookieBannerManager.initCookieBanner = initCookieBanner; 1543 window.silktideCookieBannerManager.updateCookieBannerConfig = updateCookieBannerConfig; 1544 window.silktideCookieBannerManager.injectScript = injectScript; 1545 1546 if (document.readyState === 'loading') { 1547 document.addEventListener('DOMContentLoaded', initCookieBanner, {once: true}); 1548 } else {
1549 initCookieBanner(); 1550 } 1551})(); 1552</script>
vendor: 1 bytes, line 1552
1552
1553<script> 1554silktideCookieBannerManager.updateCookieBannerConfig({ 1555 showBanner: false, // <--- THIS HIDES THE POPUP ON LOAD 1556 background: { 1557 showBackground: true 1558 }, 1559 cookieIcon: { 1560 position: "bottomLeft" 1561 }, 1562 cookieTypes: [ 1563 { 1564 id: "necessary", 1565 name: "Necessary", 1566 description: "<p>These cookies are necessary for the website to function properly and cannot be switched off. They help with things like logging in and setting your privacy preferences.</p>", 1567 required: true, 1568 onAccept: function() { 1569 //console.log('Add logic for the required Necessary here'); 1570 //Remaining cookies 1571 } 1572 }, 1573 { 1574 id: "analytics", 1575 name: "Analytics", 1576 description: "<p>These cookies help us improve the site by tracking which pages are most popular and how visitors move around the site.</p>", 1577 defaultValue: true, 1578 onAccept: function() { 1579 gtag('consent', 'update', { 1580 analytics_storage: 'granted', 1581 }); 1582 // Dynamic Refresh: No IDs required 1583 if (window.google_tag_manager) { 1584 Object.keys(google_tag_manager).forEach(id => { 1585 if (id.startsWith('G-') || id.startsWith('GT-')) { 1586 gtag('config', id, { 'update_config': true }); 1587 } 1588 }); 1589 } 1590 dataLayer.push({ 1591 'event': 'consent_accepted_analytics', 1592 }); 1593 }, 1594 onReject: function() { 1595 gtag('consent', 'update', { 1596 analytics_storage: 'denied', 1597 }); 1598 } 1599 }, 1600 { 1601 id: "advertising", 1602 name: "Advertising", 1603 description: "<p>These cookies provide extra features and personalization to improve your experience. They may be set by us or by partners whose services we use.</p>", 1604 defaultValue: true, 1605 onAccept: function() { 1606 gtag('consent', 'update', { 1607 ad_storage: 'granted', 1608 ad_user_data: 'granted', 1609 ad_personalization: 'granted', 1610 }); 1611 // Dynamic Refresh: No IDs required 1612 if (window.google_tag_manager) { 1613 Object.keys(google_tag_manager).forEach(id => { 1614 if (id.startsWith('G-') || id.startsWith('GT-')) { 1615 gtag('config', id, { 'update_config': true }); 1616 } 1617 }); 1618 } 1619 dataLayer.push({ 1620 'event': 'consent_accepted_advertising', 1621 }); 1622 }, 1623 onReject: function() { 1624 gtag('consent', 'update', { 1625 ad_storage: 'denied', 1626 ad_user_data: 'denied', 1627 ad_personalization: 'denied', 1628 }); 1629 } 1630 } 1631 ], 1632 text: { 1633 banner: { 1634 description: "<p>We use cookies on our site to enhance your user experience, provide personalized content, and analyze our traffic. <a href=\"/privacy-policy/\" target=\"_blank\">Cookie Policy.</a></p>", 1635 acceptAllButtonText: "Accept all", 1636 acceptAllButtonAccessibleLabel: "Accept all cookies", 1637 rejectNonEssentialButtonText: "Reject non-essential", 1638 rejectNonEssentialButtonAccessibleLabel: "Reject non-essential", 1639 preferencesButtonText: "Preferences", 1640 preferencesButtonAccessibleLabel: "Toggle preferences" 1641 }, 1642 preferences: { 1643 title: "Customize your cookie preferences", 1644 description: "<p>We respect your right to privacy. You can choose not to allow some types of cookies. Your cookie preferences will apply across our website.</p>", 1645 creditLinkText: "", 1646 creditLinkAccessibleLabel: "" 1647 } 1648 }, 1649 position: { 1650 banner: "bottomLeft" 1651 } 1652}); 1653</script>
1653 1654 1655<!-- Clarity (restricted)-->
1656<script> 1657window._MTS_ClarityProjectId = "wc67nnmzc4"; 1658</script>
1658 1659
1660<script> 1661 1662 var ClarityAllowedUsers = [2]; 1663 var ClarityExcludedPaths = [ 1664 /^\/news\/\d+\//, 1665 /^\/contact-us/ 1666 ]; 1667 1668 var ClarityProjectId = window._MTS_ClarityProjectId || ""; 1669 1670 var ClarityIsExcluded = ClarityExcludedPaths.some(function (pattern) { 1671 return pattern.test(window.location.pathname); 1672 }); 1673 1674 if ( 1675 ClarityProjectId && 1676 typeof window._MTS_userId !== "undefined" && 1677 window._MTS_userId > 0 && 1678 (window._isAdmin === true || ClarityAllowedUsers.includes(window._MTS_userId)) && 1679 !ClarityIsExcluded 1680 ) { 1681 var rawUrl = window._MTS_SITEURL || "UnknownSite"; 1682 var siteUrl = rawUrl 1683 .replace(/^(https?:\/\/)?(www\.)?/, "") 1684 .split(".")[0] 1685 .substring(0, 16); 1686 1687 var clarityUserId = window._MTS_userId.toString(); 1688 var friendlyName = siteUrl + " - " + clarityUserId; 1689 1690 (function (c, l, a, r, i, t, y) { 1691 c[a] = c[a] || function () { 1692 (c[a].q = c[a].q || []).push(arguments); 1693 }; 1694 t = l.createElement(r); 1695 t.async = 1; 1696 t.src = "https://www.clarity.ms/tag/" + i; 1697 y = l.getElementsByTagName(r)[0]; 1698 y.parentNode.insertBefore(t, y); 1699 })(window, document, "clarity", "script", ClarityProjectId); 1700 1701 window.clarity("identify", clarityUserId, undefined, undefined, friendlyName); 1702 window.clarity("set", "site", siteUrl); 1703 window.clarity("set", "userId", clarityUserId); 1704 window.clarity("set", "isAdmin", window._isAdmin === true ? "true" : "false"); 1705 window.clarity("set", "_MTS_userId", _MTS_userId); 1706 } 1707</script>
1707 1708 1709 1710 1711 1712<!-- Favicon --> 1713<link rel="icon" type="image/x-icon" href="https://d1gpmunylt23vy.cloudfront.net/360_SixRivers_Live/0/0/0/0/133/715/133715_original" /> 1714 1715<!-- Apple Touch Icon --> 1716<link rel="apple-touch-icon" sizes="180x180" href="https://d1gpmunylt23vy.cloudfront.net/360_SixRivers_Live/0/0/0/0/133/715/133715_original" /> 1717 1718 1719<!-- Android Chrome Icons --> 1720<link rel="icon" type="image/png" sizes="192x192" href="https://d1gpmunylt23vy.cloudfront.net/360_SixRivers_Live/0/0/0/0/133/715/133715_original" /> 1721<link rel="icon" type="image/png" sizes="512x521" href="https://d1gpmunylt23vy.cloudfront.net/360_SixRivers_Live/0/0/0/0/133/715/133715_original" /> 1722<style> 1723 1724.mailer{ 1725display: none; 1726} 1727 1728html body { 1729 font-family: georgia, serif; 1730} 1731 1732#item_136 .navType:after { 1733 content: unset; 1734} 1735 1736.menuDropBgShow { 1737 box-shadow: 0px 0px 1px var(--six-main-black); 1738 margin-top: -1px; 1739 min-height: unset !important; 1740} 1741 1742.navigation_menu_widget .section_navigation_widget { 1743 background: var(--six-main-black); 1744} 1745 1746.navigation_menu_widget .section_navigation_widget a[title="Donate"] { 1747 background: var(--six-main-red) !important; 1748} 1749 1750.navigation_menu_widget .section_navigation_widget .sectionDropItem { 1751 color: var(--six-black); 1752 background: var(--six-white); 1753 font-size: 20px; 1754} 1755 1756.navigation_menu_widget .section_navigation_widget .sectionItem, 1757.navigation_menu_widget .section_navigation_widget .sectionLabel, 1758.navigation_menu_widget .section_navigation_widget .dropLink { 1759 background: var(--six-main-black) !important; 1760 color: var(--six-white) !important; 1761 font-size: 20px; 1762 font-weight: 600; 1763} 1764 1765.header .headerMainItems { 1766 padding: 10px !important; 1767} 1768 1769#nextStoryTitle, 1770#previousStoryTitle { 1771 display: none !important; 1772} 1773 1774.adPlaceholder, 1775.adBannerPlaceholder { 1776 background: var(--six-black); 1777} 1778 1779.adPlaceholder { 1780 margin: 0px auto 20px auto; 1781 width: 300px; 1782 height: 250px; 1783} 1784 1785.adBannerPlaceholder { 1786 width: 728px; 1787 height: 90px; 1788 margin: 40px auto; 1789 max-width: 100% 1790} 1791 1792.navigation_menu_widget a.item, 1793.navigation_menu_widget div.item, 1794body p { 1795 font-family: arial, sans-serif !important; 1796} 1797 1798body, 1799.masterMcWrap { 1800 background: var(--six-white); 1801} 1802 1803body .dropNavBtn i.fa-bars { 1804 text-align: center; 1805} 1806 1807body .mts_cc_heading { 1808 font-family: georgia, serif; 1809 font-size: 30px; 1810 font-weight: bold; 1811 color: var(--six-black); 1812 padding: 0px 0px 0px 0px; 1813 line-height: 1.125; 1814} 1815 1816body .news_panel_widget #news .item .photoText .photoAuthor, 1817body .news_panel_widget #news .item .photoTextw .photoAuthor, 1818body .news_panel_widget #news .item .photoText .photoDate, 1819body .news_panel_widget #news .item .photoTextw .photoDate { 1820 color: var(--six-main-black); 1821 font-family: arial; 1822} 1823 1824.trending_media_widget .trendingListCont { 1825 margin-top: 10px; 1826} 1827 1828a.trendingLink { 1829 font-size: 24px; 1830 display: flex; 1831 color: var(--six-black) !important; 1832} 1833 1834.trendingCount { 1835 font-weight: bold; 1836 line-height: .875; 1837} 1838 1839.header .section_navigation_widget.showSecNav { 1840 position: absolute !important; 1841 left: 0 !important; 1842} 1843 1844.header .searchCtr { 1845 transform: translateY(0px); 1846 -webkit-transform: translateY(0px); 1847 -moz-transform: translateY(0px); 1848} 1849 1850.header .searchCtr.showSearch { 1851 transform: translateY(calc(100%)); 1852 -webkit-transform: translateY(calc(100%)); 1853 -moz-transform: translateY(calc(100%)); 1854} 1855 1856body .section_navigation_widget .mts_cc_heading, 1857body .desktopNavSection .sectionLabel { 1858 display: none !important; 1859} 1860 1861body .navigation_menu_widget a.mdItem .dropDownElement .item, 1862body .navigation_menu_widget .mdItem .dropDownElement .item { 1863 color: #000000; 1864} 1865 1866.sectionDropItem[title="Opinions Main"], 1867.sectionDropItem[title="News Main"], 1868.sectionDropItem[title="Living Main"], 1869.sectionDropItem[title="Sports Main"], 1870.sectionDropItem[title="Tri-Cities Scene Main"] { 1871 font-weight: bold; 1872} 1873 1874.backToTop { 1875 background: #eeeeee; 1876 border: solid 1px #000000; 1877 border-radius: 5px; 1878 position: sticky; 1879 bottom: 20px; 1880 left: calc(100% - 20px); 1881 z-index: 151; 1882 aspect-ratio: 1/1; 1883 display: flex; 1884 flex-direction: column; 1885 color: var(--six-main-black); 1886 align-items: center; 1887 justify-content: center; 1888 text-transform: uppercase; 1889 gap: 5px; 1890 padding: 10px; 1891 width: 48px; 1892 height: 48px; 1893 text-align: center; 1894 cursor: pointer; 1895 transition: background 250ms; 1896 margin-top: 20px; 1897} 1898 1899.backToTop:hover { 1900 background: #dddddd; 1901} 1902 1903.backToTop i { 1904 font-size: 20px; 1905} 1906 1907.backToTop span { 1908 font-family: arial, sans-serif; 1909 font-size: 14px; 1910 font-weight: 600; 1911 display: none; 1912} 1913 1914.srAd { 1915 margin: 0px auto 20px auto; 1916} 1917 1918@media (min-width: 768px) { 1919 .backToTop { 1920 width: 96px; 1921 height: 96px; 1922 } 1923 1924 .backToTop span { 1925 display: block; 1926 } 1927} 1928 1929@media (min-width: 1024px) { 1930 .header #navbar { 1931 align-self: center; 1932 } 1933 1934 .header .headerMainItems { 1935 padding: 5px !important; 1936 } 1937 1938 .mainNav, 1939 .navigation_menu_widget { 1940 height: calc(100%); 1941 } 1942 1943 .header .searchCtr.showSearch { 1944 transform: translateY(calc(100% + 14px)) !important; 1945 -webkit-transform: translateY(calc(100% + 14px)) !important; 1946 -moz-transform: translateY(calc(100% + 14px)) !important; 1947 } 1948} 1949</style> 1950
1951<script> 1952$(document).one('widgetsloaded', function() { 1953 const url = window.location.href; 1954 const targetPaths = ['/admin', '/layout-admin', '/news/editor', '/archive/search']; 1955 1956 if (targetPaths.some(path => url.includes(path))) { 1957 document.body.style.fontFamily = "roboto, sans-serif"; 1958 } 1959 1960 let searchBtn = $(".searchBtn"); 1961 searchBtn.on("click", function() { 1962 1963 }); 1964 1965 let headerWidth = $("header").width(); 1966 let navWidth = $(".navigationContainer").width(); 1967 let navPos = $(".navigationContainer").scrollLeft(); 1968 let leftVal = headerWidth - (navPos + navWidth); 1969 1970 // Wait until the element exists in the DOM 1971 function watchSectionNav() { 1972 const target = document.querySelector(".section_navigation_widget"); 1973 if (!target) { 1974 requestAnimationFrame(watchSectionNav); 1975 return; 1976 } 1977 1978 // Create a MutationObserver 1979 const observer = new MutationObserver(mutations => { 1980 mutations.forEach(mutation => { 1981 if (mutation.attributeName === "class") { 1982 if (target.classList.contains("showSecNav")) { 1983 target.style.left = `${-leftVal}px`; 1984 } else { 1985 target.removeAttribute("style") // runs on removal too 1986 } 1987 } 1988 }); 1989 }); 1990 1991 // Start observing class attribute changes 1992 observer.observe(target, { attributes: true, attributeFilter: ["class"] }); 1993 } 1994 1995 watchSectionNav(); 1996}); 1997</script>
1997 1998
1999<script> 2000$(document).one('widgetsloaded', function() { 2001 //Set last visited page for URL redirect based on login 2002 if (!window.location.pathname.includes('/user/login')) 2003 { 2004 let urlQuery = `?target=${window.location.pathname + window.location.search + window.location.hash}`; 2005 localStorage.setItem('lastVisitedURL', urlQuery); 2006 } 2007 2008 let lastVisitedUrl = localStorage.getItem('lastVisitedURL'); 2009 console.log(lastVisitedUrl); 2010 $("a[href='/user/login']").attr("href", `/user/login/${lastVisitedUrl}`); 2011 2012(function() { 2013 const targetSrc = "https://media-sixrivers.mynews360.com/noimage/block/213/"; 2014 2015 function checkImages() { 2016 document.querySelectorAll('.blockImgCtr img').forEach(img => { 2017 if (img.src === targetSrc) { 2018 const parent = img.closest('.blockImgCtr'); 2019 if (parent) parent.style.display = 'none'; 2020 } 2021 }); 2022 } 2023 2024 // Run immediately in case elements already exist 2025 checkImages(); 2026 2027 // Watch for new elements being added to the DOM 2028 const observer = new MutationObserver(() => checkImages()); 2029 observer.observe(document.body, { childList: true, subtree: true }); 2030})(); 2031}); 2032</script>
2032 2033 2034<!-- GOOGLE ADS TAG (gtag.js) -->
vendor: 65 bytes, lines 2034-2035
2034 2035<script async src="https://www.googletagmanager.com/gtag/js?id=
2035G-K9ZBRND062
vendor: 13 bytes, lines 2035-2036
2035"></script> 2036
2036<script>
vendor: 127 bytes, line 2036
2036window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', '
2036G-K9ZBRND062
vendor: 4 bytes, line 2036
2036');
2036</script>
2036 2037 2038<!--//DIDNA AD CONFIGURATION-->
2039<script> 2040const url = window.location.href; 2041const targetPaths = ['/admin', '/layout-admin', '/news/editor', '/archive/search', '/manage', '/mtsAdmin', '/upload-ad', '/photos', '/mtsadmin']; 2042 2043var DIDNA_CONFIG = { 2044 pageTargeting: { 2045 pos: ['rectangle-one', 'cube-one', 'cube-two', 'sidebar-top'] 2046 } 2047}; 2048</script>
vendor: 1 bytes, line 2048
2048
2049<script async='async' type='text/javascript' src='https://storage.googleapis.com/didna_hb/six_rivers_media/johnsoncitypresscom/didna_config.js'></script>
2049 2050 2051<!--BROADSTREET AD--> 2052<style> 2053.broadstreet-dynamic-scrolling + broadstreet-zone-container { 2054 height: 0; 2055} 2056</style>
2057<script src="https://cdn.broadstreetads.com/init-2.min.js"></script>
vendor: 1 bytes, line 2057
2057
2058<script>broadstreet.watch({ networkId: 9387 })</script>
2058 2059
2060<script> 2061$(document).one("widgetsloaded", function() { 2062 if (!targetPaths.some(path => url.includes(path))) { 2063 let body = $("body"); 2064 let mainContent = $(".masterMcWrap"); 2065 let broadstreet = `<broadstreet-zone zone-id="170347" uri-keywords="true" soft-keywords="true"></broadstreet-zone>`; 2066 2067 $(broadstreet).prependTo(body); 2068 2069 let backToTop = `<div class="backToTop"><i class="fas fa-chevron-up"></i><span>Back to top</span></div>`; 2070 $(backToTop).appendTo(mainContent); 2071 } 2072 2073 $(".backToTop").on("click", function() { 2074 window.scrollTo({ 2075 top : 0, 2076 behavior : "smooth" 2077 }); 2078 }); 2079}); 2080</script>
2080 2081
2082<script> 2083//User login / logout 2084$(document).one("widgetsloaded", function( ) { 2085 let user = _MTS_userId; 2086 let login = (user !== null && user > -1 && user !== undefined ? `<a href="/signout.aspx" class="sectionItem">Logout</a>` : `<a href="/live-content/subscribe" class="sectionItem">Subscribe</a><a href="/user/login" class="sectionItem">Login</a>`); 2087 let dNav = $(".desktopNavSection").first(); 2088 let mNav = $(".mobileNavSection").first(); 2089 $(login).prependTo(dNav); 2090 $(login).prependTo(mNav); 2091}); 2092</script>
2092 2093
2094<script> 2095$(document).one("widgetsloaded", function() { 2096function updateMenuHeight() { 2097 const menu = document.querySelector('.menuDropBgShow'); 2098 const sportsList = document.querySelector('.sportsList'); 2099 if (!menu || !sportsList) return; 2100 2101 const visibleSubLists = Array.from(sportsList.querySelectorAll('.subList')) 2102 .filter(el => el.offsetParent !== null); // visible only 2103 2104 // Set height based on number of visible subList items 2105 menu.style.height = `${visibleSubLists.length * 50}px`; 2106 } 2107 2108 // Observe DOM changes (for menuDropBgShow or subList updates) 2109 const observer = new MutationObserver(() => { 2110 updateMenuHeight(); 2111 }); 2112 2113 observer.observe(document.body, { 2114 childList: true, 2115 subtree: true, 2116 attributes: true, 2117 attributeFilter: ['style', 'class'] 2118 }); 2119 2120 // Run initially if elements are already present 2121 let match = window.matchMedia("(min-width: 1024px)").matches; 2122 if(match) { 2123 updateMenuHeight(); 2124 } 2125 2126//ADJUST NAVIGATION HOVER TITLE TO REFLECT TARGET ATTRIBUTE 2127const cleanNonBlankNavTitles = () => { 2128 document.querySelectorAll('a.desktopNavItem:not([target="_blank"])').forEach(anchor => { 2129 if (anchor.title && /in new tab$/i.test(anchor.title)) { 2130 anchor.title = anchor.title.replace(/\s*in new tab$/i, ''); 2131 } 2132 }); 2133}; 2134 2135// Run immediately 2136cleanNonBlankNavTitles(); 2137 2138// Watch for dynamically added anchors 2139const titleObserver = new MutationObserver(() => cleanNonBlankNavTitles()); 2140titleObserver.observe(document.body, { childList: true, subtree: true }); 2141 2142 document.querySelectorAll('.sectionDropItem').forEach(el => { 2143 const href = el.getAttribute('href'); 2144 if (href && (href.startsWith('http://') || href.startsWith('https://'))) { 2145 el.setAttribute('target', '_blank'); 2146 } 2147 }); 2148}); 2149</script>
2149 2150
2151<script> 2152//SET PROPER URL TO "NOT A SUBSCRIBER" LINK ON LOGIN PAGE 2153$(document).one("widgetsloaded", function() { 2154if (window.location.href.includes('/user/login')) { 2155 const subObserver = new MutationObserver(() => { 2156 const subElement = document.querySelector('[title="Not a Subscriber"]'); 2157 if (subElement) { 2158 subElement .setAttribute('href', '/live-content/subscribe'); 2159 subObserver.disconnect(); // stop watching once done 2160 } 2161 }); 2162 2163 subObserver.observe(document.body, { 2164 childList: true, 2165 subtree: true 2166 }); 2167} 2168}); 2169</script>
2169 2170
2171<script> 2172$(document).one("widgetsloaded", function() { 2173 let userProfileUpdate = window.location.href.includes("/user/edit"); 2174 if (userProfileUpdate) { 2175 let link = "https://sixrivers.newzware.com/ss70v2/sixrivers/common/template.jsp?autoLogout=N&nwmodule=main&nwpage=main&skin=jcp"; 2176 let modBtn = $("#newPasswordField a"); 2177 modBtn.attr("href", link).attr("target", "_blank").addClass("mts_cc_button button").css({"padding": "10px 20px"}); 2178 2179 let coverageContainer = $("#coverageContainer"); 2180 let parentRows = [ 2181 "#changeEmail", 2182 "#changeName", 2183 "#changeTwoFactor", 2184 "#changeGender", 2185 "#changeDOB", 2186 "#changeZip" 2187 ]; 2188 2189 for(i = 0; i < parentRows.length; i++) { 2190 $(`${parentRows[i]}`).closest(".setRow").hide(); 2191 } 2192 2193 coverageContainer.hide(); 2194 } 2195}); 2196</script>
2196 2197 2198 2199 2200 2201 2202 2203 2204 <link rel="shortcut icon" href="https://media-sixrivers.mynews360.com/images/custom/213/favicon.ico" /> 2205 2206 <link rel="stylesheet" type="text/css" href="https://media-sixrivers.mynews360.com/css/?custom=true&pid=213" /> 2207 2208 <link rel="stylesheet" type="text/css" href="https://media-sixrivers.mynews360.com/css/oneColumn.css?v=1.14.5.35260" /> 2209 <link rel="Stylesheet" type="text/css" href="https://media-sixrivers.mynews360.com/css/?v=1.14.5.35260&pid=213" /> 2210 2211
2211<script type="text/javascript"> 2212 _MTS_cssList.push("css/jQueryExtensions/jquery-ui.css", "css/popUpDialog.css"); 2213 _MTS_jsList.push("js/signin.js", "js/popUpDialog.js", "js/oneCol.js"); 2214 var _timeout = 1140000; 2215 var _sessionTimeout = 1200000; 2216 var __redirectTo = "/live-content/about-us/"; 2217 var _COMMON_isTablet = false; 2218 var _encodedPathAndQuery = "%2flive-content%2fabout-us%2f", 2219 _MTS_SEOALT = "About Us Logo", 2220 _homePageUrl = "/"; 2221 </script>
2221 2222 2223 2224<link rel="stylesheet" type="text/css" href="https://media-sixrivers.mynews360.com/css/plugins/mediaElement/mediaelementplayer.css?v=1.14.5.35260" /> 2225 2226<style type="text/css"> 2227#user_container { 2228 background: var(--pres-main-bg-light); 2229 padding-bottom: 20px; 2230 padding: 0 1%; 2231} 2232 2233.customPageLink { 2234 margin: 2% 0 0; 2235} 2236 2237#user_container img, 2238#user_container audio { 2239 max-width: 100% !important; 2240 height: auto; 2241} 2242 2243#user_container { 2244 background-color: inherit; 2245} 2246 2247.custom_page_content_widget { 2248 background: var(--pres-main-bg-light); 2249} 2250 2251.custom_page_content_widget:before, 2252.custom_page_content_widget:after { 2253 content:""; 2254 display: table; 2255} 2256 2257.custom_page_content_widget:after { 2258 clear: both; 2259} 2260 2261.customContent { 2262 float: left; 2263 width: 70%; 2264 margin: 0px 1% 0px 1%; 2265 background: var(--pres-main-bg-light); 2266} 2267 2268.extraContent { 2269 float: left; 2270 width: 26%; 2271 margin: 0px 1% 0px 1%; 2272} 2273 2274@media all and (min-width: 768px) and (max-width: 1024px) { 2275 .customContent { 2276 width: 100%; 2277 } 2278 2279 .extraContent { 2280 width: 100%; 2281 text-align: center; 2282 } 2283} 2284 2285@media all and (min-width: 320px) and (max-width: 767px) { 2286 .customContent { 2287 width: 100%; 2288 } 2289 2290 .extraContent { 2291 width: 100%; 2292 text-align: center; 2293 } 2294 2295 .customContent * { 2296 max-width: 100%; 2297 } 2298 2299 .customContent img { 2300 max-width: unset !important; 2301 } 2302} 2303</style> 2304
2305<script type="text/javascript" src="https://media-sixrivers.mynews360.com/js/plugins/mediaElement/mediaelement-and-player.min.js?v=1.14.5.35260"></script>
2305 2306
2307<script type="text/javascript"> 2308 $(document).one("widgetsloaded", function () 2309 { 2310 $("audio").mediaelementplayer(); 2311 }); 2312</script>
2312 2313 2314 2315 2316 2317<title> 2318 About Johnsonn City Press 2319</title><meta name="description" content="Read about the history of Johnson City Press and how it has evolved throughout the years" /></head> 2320 2321 2322<body > 2323 2324 <div class="sitewideUserAlert"> 2325 <p id="userAlertMessage"></p> 2326 <div class="sitewideUserAlertButtons"> 2327 <button id="hideSiteWide">Okay</button> 2328 <button id="closeSiteWide">Close and Never Show Again</button> 2329 </div> 2330 </div> 2331 2332 2333 2334 2335 2336 <div class="plBackground"></div> 2337 <div id="fb-root"></div> 2338 2339 2340 2341 <noscript>You must have javascript enabled to view this site.</noscript> 2342 2343 <div class="alwaysMobileBg"></div> 2344 2345 <div class="busySpinnerBg"> 2346 <div class="closeSpinner"><i class="fas fa-times"></i></div> 2347 <img class="busySpinner" src="https://media-sixrivers.mynews360.com/images/busySpinner.gif" alt="Loading" /> 2348 </div> 2349 2350 2351 <div class="navigation_admin_menu_widget"> 2352 <input type="hidden" name="id" value="" /> 2353 <input type="hidden" name="abovethefold" value="true" /> 2354 </div> 2355 2356 <div class="custom_header_widget"> 2357 <input type="hidden" name="abovethefold" value="true" /> 2358 </div> 2359 2360
2361<script type="text/javascript"> 2362 _MTS_jsList.push("js/content/mobileSelectors.js"); 2363</script>
2363 2364 <div class="emailRejected" style="display: none;"> 2365 <div class="rejectTop"> 2366 <div class="rejectedTitle">Email Rejected!</div> 2367 <div class="rejectHide">x</div> 2368 </div> 2369 <div class="rejectedInfo"> 2370 We attempted to send a notification to your email address but we were unable to verify that you provided a valid email address. 2371 Please visit <a title="Link to my profile" class="emailLink" href="/user/edit/">my profile</a> to update your email address if you wish to receive notifications. 2372 Otherwise, <a title="Disable notifications" class="emailLink" href="javascript:fireEmailRejected()"> disable notifications</a> and hide this message. 2373 </div> 2374 </div> 2375 2376 2377 2378 <div class="masterMcWrap" role="main"> 2379 <div id="logged_nav"> 2380 2381 2382 2383 </div> 2384 <div id="timeout"> 2385 <div class="tText n"> 2386 Your session was unable to be renewed and will be expiring in <span id="tTimer">0</span> seconds. 2387 Click <span id="tRenew">here</span> to attempt to renew your session. 2388 2389 <div id="tStatus"></div> 2390 </div> 2391 </div> 2392 2393 2394 2395<div class='innerSec group'><div id='mts_r_0' class='widget_region' style='text-align:center'><input type='hidden' name='reg_width' value='100.00' /><input type='hidden' name='reg_margin_left' value='0.00' /><input type='hidden' name='reg_margin_right' value='0.00' /><input type='hidden' name='reg_width_med' value='100.00' /><input type='hidden' name='reg_margin_left_med' value='0.00' /><input type='hidden' name='reg_margin_right_med' value='0.00' /><input type='hidden' name='reg_width_tablet' value='100.00' /><input type='hidden' name='reg_margin_left_tablet' value='0.00' /><input type='hidden' name='reg_margin_right_tablet' value='0.00' /><input type='hidden' name='reg_pixel' value='False' /><input type='hidden' name='reg_innerSec' value='True' /><div id='mts_c_0' class='widget_column' style='display:inline-block;vertical-align:top;text-align:initial;'><input type='hidden' name='col_width' value='100.00' /><input type='hidden' name='col_margin_left' value='0.00' /><input type='hidden' name='col_margin_right' value='0.00' /><input type='hidden' name='col_width_med' value='100.00' /><input type='hidden' name='col_margin_left_med' value='0.00' /><input type='hidden' name='col_margin_right_med' value='0.00' /><input type='hidden' name='col_width_tablet' value='100.00' /><input type='hidden' name='col_margin_left_tablet' value='0.00' /><input type='hidden' name='col_margin_right_tablet' value='0.00' /><input type='hidden' name='col_pixel' value='False' /><div class='custom_break_widget'><style> 2396html, body {visibility: hidden; opacity: 0;} 2397</style> 2398
2399<script> 2400$(document).one("widgetsloaded", function() { 2401 setTimeout(function() { 2402 $("html, body").css({"visibility": "visible", "opacity": "1"}) 2403 }, 2) 2404}) 2405</script>
2405</div><div class='custom_break_widget'><div id="ad-1397307" style="margin: 20px auto 40px auto;"></div>
2406<script> 2407var didna = window.didna || {cmd: []}; 2408didna.cmd.push(function(){ 2409 didna.createAdUnits({ 2410 id: "ad-1397307", 2411 "adUnitPath": "/22870547579/johnsoncitypress.com/homepage", 2412 "size": [728, 90], 2413 "sizeMap": [ 2414 [[1200, 0], [[1170, 90], [970, 90], [728, 90]]], 2415 [[992, 0], [[970, 90], [728, 90]]], 2416 [[768, 0], [[728, 90], [320, 50]]], 2417 [[320, 0], [[320, 50]]] 2418 ], 2419 targeting:{'pos': "rectangle-one"} 2420 }); 2421}); 2422</script>
2422</div><div class='custom_page_content_widget'><input type='hidden' name='pageTitle' value='About Us' /></div></div></div></div> 2423 2424 </div> 2425 2426 2427 2428 <div class="fullAdView"> 2429 </div> 2430 <div class="fullPageAd"> 2431 2432 2433 <div class="adOptions"> 2434 <div class="adCounter"> 2435 <div class="loadingAd">Loading...</div> <img class="mts_lazy" width="324" height="20" data-original="https://media-sixrivers.mynews360.com/images/ajax-loader.gif" alt="" /> 2436 </div> 2437 <div id="skipAd" class="adBtn"> 2438 View Page in Progress 2439 </div> 2440 </div> 2441 </div> 2442 2443 2444 2445 2446 <h1 class="heading"> 2447 About Us 2448</h1> 2449 2450 2451 2452 <div id='mts_r_0' class='widget_region' style='text-align:center'><input type='hidden' name='reg_width' value='100.00' /><input type='hidden' name='reg_margin_left' value='0.00' /><input type='hidden' name='reg_margin_right' value='0.00' /><input type='hidden' name='reg_width_med' value='100.00' /><input type='hidden' name='reg_margin_left_med' value='0.00' /><input type='hidden' name='reg_margin_right_med' value='0.00' /><input type='hidden' name='reg_width_tablet' value='100.00' /><input type='hidden' name='reg_margin_left_tablet' value='0.00' /><input type='hidden' name='reg_margin_right_tablet' value='0.00' /><input type='hidden' name='reg_pixel' value='False' /><input type='hidden' name='reg_innerSec' value='False' /><div id='mts_c_0_3' class='widget_column' style='text-align: initial;'><input type='hidden' name='col_width' value='100.00' /><input type='hidden' name='col_margin_left' value='0.00' /><input type='hidden' name='col_margin_right' value='0.00' /><input type='hidden' name='col_width_med' value='100.00' /><input type='hidden' name='col_margin_left_med' value='0.00' /><input type='hidden' name='col_margin_right_med' value='0.00' /><input type='hidden' name='col_width_tablet' value='100.00' /><input type='hidden' name='col_margin_left_tablet' value='0.00' /><input type='hidden' name='col_margin_right_tablet' value='0.00' /><input type='hidden' name='col_pixel' value='False' /><div class='custom_break_widget'><style> 2453.customFooterInner { 2454 background: var(--six-main-black); 2455 color: var(--six-white); 2456 width: 100%; 2457 display: flex; 2458 flex-direction: column; 2459 justify-content: center; 2460 align-items: center; 2461 padding: 50px 30px; 2462 gap: 30px; 2463} 2464 2465.footerContent { 2466 max-width: 1280px; 2467 display: flex; 2468 flex-direction: column; 2469 gap: 40px; 2470} 2471 2472.footerBlock, 2473.footerInfoBlock,
2474.footerPubBlock { 2475 display: flex; 2476 flex-direction: column; 2477} 2478 2479.footerBlock { 2480 gap: 20px; 2481} 2482 2483.footerInfoBlock { 2484 gap: 10px; 2485} 2486 2487.footerPubBlock { 2488 gap: 30px; 2489} 2490 2491.footerLogoMain { 2492 width: 300px; 2493 max-width: 100%; 2494} 2495 2496.footerLogoImage { 2497 width:100%; 2498} 2499 2500.footerShareInfo { 2501 display: flex; 2502 flex-direction: row; 2503 font-size: 24px; 2504 gap: 20px; 2505} 2506 2507.footerHeading { 2508 font-size: 32px; 2509 font-family: georgia, serif; 2510} 2511 2512.footerContent a.footerLink, 2513.footerContent a.fa-brands, 2514.footerContent a.sixRiversFooterLink { 2515 color: var(--six-white); 2516} 2517 2518.footerContent a.footerLink:hover, 2519.footerContent a.fa-brands:hover { 2520 color: var(--six-main-red); 2521} 2522 2523.borderTop { 2524 border-top: solid 1px var(--six-white); 2525 padding-top: 20px; 2526} 2527 2528.footerPubImage { 2529 max-width:100%; 2530} 2531 2532@media (min-width: 768px) { 2533 .customFooterInner { 2534 gap: 40px; 2535 } 2536 2537 .footerContent { 2538 flex-direction: row; 2539 } 2540 2541 .footerContent .footerBlock { 2542 width: calc(33.333% - 14px); 2543 } 2544} 2545 2546</style> 2547 2548<div class="customFooter"> 2549 <div class="customFooterInner"> 2550 <div class="footerContent"> 2551 <div class="footerBlock"> 2552 <a class="footerLogoMain" href="/"> 2553 <img class="footerLogoImage" src="https://media-sixrivers.mynews360.com//images/custom/213/logo.png" alt="" /> 2554 </a> 2555 <div class="footerInfoBlock"> 2556 <span>Johnson City Press</span> 2557 <span>105 East Walnut Street Suite 10</span> 2558 <span>Johnson City, TN 37601</span> 2559 <span>Phone: <a class="mts_cc_text" href="tel:4237221330" title="Call Johnson City Phone Number">423-722-1330</a></span> 2560 <span>Email: <a class="mts_cc_text" href="mailto:[email protected]" title="E-mail Johnson city at [email protected]">[email protected]</a></span> 2561 </div> 2562 <div class="footerShareInfo"> 2563 <a class="fa-brands fa-facebook-f" href="https://www.facebook.com/JohnsonCityPress/" target="_blank"></a> 2564 <a class="fa-brands fa-x-twitter" href="http://twitter.com/jcpress/" target="_blank"></a> 2565 <a class="fa-brands fa-linkedin" href="https://www.linkedin.com/company/johnsoncitypress/" target="_blank"></a> 2566 <a class="fa-brands fa-youtube" href="https://www.youtube.com/channel/UCYZixCNzcgknXLPdHUXQPXw" target="_blank"></a> 2567 <a class="fa-brands fa-tiktok" href="https://www.tiktok.com/@johnsoncitypress" target="_blank"></a> 2568 <a class="fa-brands fa-instagram" href="https://www.instagram.com/johnson_city_press/" target="_blank"></a> 2569 </div> 2570 </div> 2571 <div class="footerBlock"> 2572 <div class="footerHeading"><a class="sixRiversFooterLink" href="https://www.sixriversmedia.com/" target="_blank">Six Rivers Media LLC</a></div> 2573 <div class="footerPubBlock"> 2574 <a class="footerPubLink" title="Johnson City Press link" href="https://www.timesnews.net/" target="_blank"><img class="footerPubImage" src="https://d1gpmunylt23vy.cloudfront.net/360_SixRivers_Live/0/0/0/0/118/575/118575_original" alt="Johnson City Press Logo" /></a> 2575 <a class="footerPubLink" title="The Tomahawk link" href="https://www.thetomahawk.com/" target="_blank"><img class="footerPubImage" src="https://d1gpmunylt23vy.cloudfront.net/360_SixRivers_Live/0/0/0/0/27/545/27545_original" alt="The Tomahawk Logo" /></a> 2576 <a class="footerPubLink" title="The Erwin Record link" href="https://www.erwinrecord.net/" target="_blank"><img class="footerPubImage" src="https://d1gpmunylt23vy.cloudfront.net/360_SixRivers_Live/0/0/0/0/27/543/27543_original" alt="The Erwin Logo" /></a> 2577 </div> 2578 </div> 2579 <div class="footerBlock"> 2580 <div class="footerHeading">Quick Links:</div> 2581 <div class="footerInfoBlock"> 2582 <a class="footerLink" href="/live-content/about us">About Us</a> 2583 <a class="footerLink" href="https://www.sixriversmedia.com/contact-us/#johnson_city_press" target="_blank">Contact Us</a> 2584 <!--<a class="footerLink" href="/live-content/archives">Archives</a>--> 2585 <a class="footerLink" href="https://sixrivers.newzware.com/myad/sixrivers/common/template.jsp" target="_blank">Advertise</a> 2586 <!--<a class="footerLink" href="/live-content/faq">FAQ</a>--> 2587 <a class="footerLink" href="/live-content/subscribe">Subscribe</a> 2588 </div> 2589 </div> 2590 </div> 2591 <div class="footerContent borderTop"> 2592 <div class="copyright"> 2593 © 2025 Johnson City Press 105 East Walnut Street Suite 10 Johnson City, TN 37601 | <a class="footerLink" href="/live-content/terms of use">Terms of Use</a> | <a class="footerLink" href="/live-content/privacy policy">Privacy Policy</a> | <a class="footerLink" href="#" onclick="document.getElementById('silktide-cookie-icon').click(); return false;">Cookie Preferences 2594 </a> 2595 </div> 2596 </div> 2597 </div> 2598</div></div></div></div> 2599 2600
2600<script type="text/javascript"> 2601 _MTS_cssList.push("css/plugins/chosen/chosen.min.css"); 2602 _MTS_jsList.push("js/ajax.js", "js/jQueryExtensions/jquery-ui.js", "js/jQueryExtensions/touch-punch.js", "js/jQueryExtensions/jquery.lazyload.js", "js/plugins/chosen/chosen.jquery.min.js", "js/common.js"); 2603 2604 _MTS_jsList.push("js/smartBanner.js"); 2605 2606 _imageSizes = {"SiteWideMxW":1280,"SiteWideMxH":720,"SlideShowMxW":864,"SlideShowMxH":486,"ThumbnailMxW":600,"ThumbnailMxH":337,"TeamLogoMxW":250,"TeamLogoMxH":250}; 2607 var _MTS_adSlot = ""; 2608 _MTS_VERSION = "1.14.5.35260"; 2609 2610 2611 2612 </script>
2612 2613 2614 2615
2615<script type="text/javascript" src="https://media-sixrivers.mynews360.com/js/widgets/main.js?v=1.14.5.35260&weburi=https://johnsoncitypress.com/&portalid=213&mediauri=https://media-sixrivers.mynews360.com/"></script>
2615 2616 2617</body> 2618</html> 2619
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.