1<!doctype html> 2<html lang="en"> 3 4<head> 5 <!-- Performance Optimizations --> 6 <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin> 7 <link rel="preconnect" href="https://code.jquery.com" crossorigin> 8 <link rel="dns-prefetch" href="https://cdn.jsdelivr.net"> 9 <link rel="dns-prefetch" href="https://code.jquery.com"> 10 <link rel="dns-prefetch" href="https://maxcdn.bootstrapcdn.com"> 11 <link rel="preload" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" as="style"> 12 <!-- Required meta tags --> 13 <meta charset="utf-8"> 14 <title>Free Online Newspaper Subscrption (VIA e-mail)</title> 15 <meta name="viewport" content="width=device-width, initial-scale=1"> 16 17 18 <meta name="keywords" content="SWVA sun, Local News, Swva Sports, Breaking News, Obituaries, Public Notices"> 19 <meta name="description" content="SWVA Local Online Newspaper"> 20 21 <link rel="shortcut icon" href="/favicon.ico?v=1790187371"> 22
22<script type="text/javascript" language="javascript" src="/lib/bl2.js"></script>
22 23 24 <!-- bootstrap --> 25 <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> 26
26<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
26 27 <link type="text/css" rel="stylesheet" href="https://bulletlink.com/bootstrap.css"> 28 <!-- /bootstrap --> 29 30 <!-- jQuery --> 31
31<script src="https://code.jquery.com/jquery-1.7.min.js" integrity="sha256-/05Jde9AMAT4/o5ZAI23rUf1SxDYTHLrkOco0eyRV84=" crossorigin="anonymous"></script>
31 32 33 <!-- system --> 34
34<script type="text/javascript" language="javascript" src="/settings.js?v=1790187371"></script>
34 35
35<script>function SParameters(){return '1';}</script>
35 36
36<script type="text/javascript" language="javascript" src="/articles.js?v=1790187371"></script>
36 37
37<script type="text/javascript" language="javascript" src="/ads.js?v=1790187371"></script>
37 38
38<script type="text/javascript" language="javascript" src="/menus.js?v=1790187371"></script>
38 39
39<script type="text/javascript" language="javascript" src="/sections.js?v=1790187371"></script>
39 40
40<script type="text/javascript" language="javascript" src="/polls.js?v=1790187371"></script>
40 41
41<script type="text/javascript" language="javascript" src="/menu_horizontal.js?v=1790187371"></script>
41 42 <!-- /system --> 43 44 <!-- fontAwesome--> 45 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" /> 46 <!-- /fontAwesome--> 47 48 <!-- general --> 49
49<script type="text/javascript" language="javascript" src="/jscript1.js?v=1790187371"></script>
49 50 <link type="text/css" rel="stylesheet" href="/custom.css?v=1790187371"> 51
51<script type="text/javascript" language="javascript" src="/custom.js?v=1790187371"></script>
51 52 <!-- /general --> 53 54 <!--StartMH--> 55 <!--MetaSharing--> 56 <!--EndMH--> 57 58 <!-- live-Builder --> 59
59<script type="text/javascript" src="/ufields.js"></script>
59 60 <!-- /live-Builder --> 61 <meta property="og:image" content="https://swvasun.com/logo.jpg"/> 62<!-- Google tag (gtag.js) -->
vendor: 65 bytes, lines 62-63
62 63<script async src="https://www.googletagmanager.com/gtag/js?id=
63G-WJW2XMLVK9
vendor: 19 bytes, line 63
63" defer></script>
64<script>
vendor: 130 bytes, lines 65-68
65window.dataLayer = window.dataLayer || []; 66function gtag(){dataLayer.push(arguments);} 67gtag('js', new Date()); 68gtag('config', '
68G-WJW2XMLVK9
vendor: 5 bytes, line 68
68');
69</script>
vendor: 2 bytes, line 69
69
70<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-1521277811821952" 71crossorigin="anonymous" defer></script>
71 72<meta name="google-site-verification" content="ZWleqlOYPt0wm05jtSHIjposIojO4ID1mzFoLwoHm8M" /> 73<!-- This site is converting visitors into subscribers and customers with OptinMonster - https://optinmonster.com -->
74<script>(function(d,u,ac){var s=d.createElement('script');s.type='text/javascript';s.src='https://a.omappapi.com/app/js/api.min.js';s.async=true;s.dataset.user=u;s.dataset.account=ac;d.getElementsByTagName('head')[0].appendChild(s);})(document,171153,185538);</script>
74 75<!-- / https://optinmonster.com --> 76 77<style>:root{--cms-theme-color: #555;}</style><link rel="stylesheet" href="/sys-popup.css?v=1790187371"><style id="universal-submit-spinner"> 78.form-submit-spinner{display:inline-block;width:16px;height:16px;border:2px solid rgba(255,255,255,.4);border-top-color:#fff;border-radius:50%;animation:frmSpin .7s linear infinite;vertical-align:middle;margin-right:6px} 79@keyframes frmSpin{to{transform:rotate(360deg)}} 80</style></head> 81 82<body id="blbodymain" class="blbody" data-submenu="{{SubMenuId}}"><a href="https://swvasun.com/cdn-cgi/content?id=WuBjsqb.v4iyJkJzrDQ0RfjWLhkAnJ_eCuZWIbLPDEc-1790658886.1171563-1.2.1.1-Mne10IxvPPqCQZbkGRJaJSUEs0zTqzhJJg_FVpTgHM4BQpgY8LP2WoE3Dn3TR5k1" aria-hidden="true" rel="nofollow noopener" style="display: none !important; visibility: hidden !important"></a> 83 <div class="mainbody"> 84 85<!-- Popup - start --> 86<div class="Ad22"><div data-cms-block="adgroup-22" data-cms-block-label="Advertisement 22" data-cms-el="adgroup" data-cms-adgroup="22">
86<script type="text/javascript" language="JavaScript">AdGroup22();</script>
86</div></div>
87<script> 88if (readCookie("subs-popup-" + ReadSubmenu())) { 89 // document.querySelector("iframe[src*='&pform={{NewsViaEmail2}}']").closest("#f_Popup4").classList.add("d-none"); 90 // document.body.style.overflow = "visible"; 91} else { 92 createCookie("subs-popup-" + ReadSubmenu(), "Yes"); 93} 94</script>
94 95<!-- Popup - end --> 96 97 <!-- stycky ads--> 98 <span class="cus-sticky-ads"><div data-cms-block="adgroup-1" data-cms-block-label="Advertisement 1" data-cms-el="adgroup" data-cms-adgroup="1">
98<script type="text/javascript" language="JavaScript">AdGroup1();</script>
98</div><div data-cms-block="adgroup-2" data-cms-block-label="Advertisement 2" data-cms-el="adgroup" data-cms-adgroup="2">
98<script type="text/javascript" language="JavaScript">AdGroup2();</script>
98</div><div data-cms-block="adgroup-3" data-cms-block-label="Advertisement 3" data-cms-el="adgroup" data-cms-adgroup="3">
98<script type="text/javascript" language="JavaScript">AdGroup3();</script>
98</div></span> 99 <!-- /stycky ads--> 100 <div class="container-xxl mt-2"> 101 <!-- top-links --> 102 <div class="row mb-3 border-bottom pb-2 border-2"> 103 <div class="bl-top-links col-sm-4 float-start"> 104 <div class="float-start"> 105 <!-- search--> 106
106<script type="text/javascript" language="JavaScript">GetGoogleCustomSearch();</script>
106 107 <a class="search-link text-decoration-none text-black fs-6 fw-bold me-3 border rounded p-1 px-2 bl-toplink-1-133-searchlink" href="javascript:void(0)" data-bs-toggle="tooltip" data-bs-placement="right" title="Click to Search Articles..."><i class="fa fa-search" aria-hidden="true"></i> SEARCH</a> 108 <div class="search_content"> 109 <div class="search_box"><gcse:searchbox></gcse:searchbox></div> 110 <div class="search_results"><gcse:searchresults></gcse:searchresults></div> 111 <div class="search_remove"> 112 <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16"> 113 <path fill-rule="evenodd" d="M13.854 2.146a.5.5 0 0 1 0 .708l-11 11a.5.5 0 0 1-.708-.708l11-11a.5.5 0 0 1 .708 0Z"/> 114 <path fill-rule="evenodd" d="M2.146 2.146a.5.5 0 0 0 0 .708l11 11a.5.5 0 0 0 .708-.708l-11-11a.5.5 0 0 0-.708 0Z"/> 115 </svg> 116 </div> 117 </div> 118
118<script> 119 document.getElementsByClassName('search-link')[0].addEventListener("click", function() { 120 document.getElementById("gsc-i-id1").setAttribute("placeholder", "Search for..."); 121 document.getElementsByClassName('search_content')[0].classList.add("search-flex"); 122 document.getElementsByClassName('search_remove')[0].style.display = "block"; 123 document.getElementsByClassName('gsc-results-close-btn')[0].addEventListener("click", function() { 124 document.getElementsByClassName('search_content')[0].classList.remove("search-flex"); 125 }); 126 }); 127 document.getElementsByClassName('search_remove')[0].addEventListener("click", function() { 128 document.getElementsByClassName('search_content')[0].classList.remove("search-flex"); 129 document.getElementsByClassName('search_remove')[0].style.display = "none"; }); 130 </script>
130 131 <style> 132 .gsc-adBlock {display: none !important;} 133 #gsc-i-id1{color:#000!important} 134 #gsc-i-id1::placeholder{color:#555!important;opacity:1;font-size:inherit!important} 135 .search_content{display:flex;display:-webkit-flex;-ms-display:flex;align-items:center;-webkit-align-items:center;-ms-align-items:center;justify-content:center;-webkit-justify-content:center;-ms-justify-content:center;background-color:rgba(255,255,255,.98);height:100%;position:fixed;top:100%;opacity:0;left:0;width:100%;z-index:2147483647;transition: 400ms linear;} 136 .search-flex{top: 0;opacity: 1;display:flex;display:-webkit-flex;-ms-display:flex;align-items:center;-webkit-align-items:center;-ms-align-items:center;justify-content:center;-webkit-justify-content:center;-ms-justify-content:center;transition: 300ms linear;} 137 .search_remove{cursor:pointer;user-select:none;position:absolute;top:10px;left:3%;} 138 .search_remove:hover{color:gray} 139 .gsc-control-cse.gsc-control-cse-en{background-color:transparent;border-width:0;position:absolute}.search_box{border-bottom:2px solid #000;width:70%;padding-bottom:6px} 140 .gsib_b,.gsst_a{display:none!important} 141 .gscb_a{display:none!important} 142 .gsc-input{background-image:none!important} 143 .gsc-input{background-color:transparent!important} 144 .gsc-input-box{background-color:transparent!important;border-bottom:0 solid #ff4500!important;border-width:0!important} 145 .gsc-input{border-width:0!important;color:#fff!important;font-size:20px!important} 146 .gsc-adBlock{display:none!important} 147 .search-icon-desk{cursor:pointer} 148 .search-icon-desk{float:right;height:54px;margin-right:10px} 149 .search-icon-desk i{border:1px solid #ddd;border-radius:4px;color:#000;display:block;line-height:35px;margin-top:9px;padding:0 12px} 150 .search-icon-desk i:hover{color:#79655d} 151 .gsc-results-wrapper-overlay.gsc-results-wrapper-visible {width: 100%;left: 0;top: 0;height: 100%;} 152 .gcsc-branding {display: none;} 153 .gsc-search-button.gsc-search-button-v2{padding:0 18px;line-height:35px;display:inline-block!important;background:#ddd;border-radius:5px;border-color:#555} 154 .gsc-search-button{width:auto!important;float:right!important}.gsc-search-button.gsc-search-button-v2:hover{background:#ddd!important} 155 .gsc-search-button-v2 svg{fill:#000!important} 156 .gsc-search-button.gsc-search-button-v2:hover{background:#05a2d3!important;border-color:#006899!important} 157 .gsc-search-button.gsc-search-button-v2:hover svg{fill:#fff!important} 158 </style> 159 <!-- /search--> 160 <a class="text-decoration-none text-black fs-6 me-3 bl-toplink-1-133-link" href="/about-us-p374-25.htm">ABOUT</a> 161 <a class="text-decoration-none text-black fs-6 me-3 bl-toplink-1-133-link" href="/ContactUs">CONTACT</a> 162 <a class="text-decoration-none text-black fs-6 me-3 bl-toplink-1-133-link" href="/SWVAsun">SIGN ME UP</a> 163 164 165 </div> 166 </div> 167 <div class="cus-social-links col-sm-4 float-sm-end d-flex justify-content-center d-sm-inline-block"> 168 <div class="float-sm-start"> 169 <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://www.facebook.com/swvasun/" target="_blank"><i class="fa fa-facebook-square" aria-hidden="true"></i></a> 170 <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://twitter.com/swvasun" target="_blank"><svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-twitter-x" viewBox="0 0 16 16" style="padding: 3px;background: #212529;fill: #fff;border-radius: 4px;display: inline-block;transform: translateY(-2px);" width="20" height="22"><path d="M12.6.75h2.454l-5.36 6.142L16 15.25h-4.937l-3.867-5.07-4.425 5.07H.316l5.733-6.57L0 .75h5.063l3.495 4.633L12.601.75Zm-.86 13.028h1.36L4.323 2.145H2.865z"></path></svg></a> 171 <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://www.linkedin.com/company/swva-media-llc/" target="_blank"><i class="fa fa-linkedin-square" aria-hidden="true"></i></a> 172 <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://youtube.com/@southwestvirginiasun8601" target="_blank"><i class="fa fa-youtube-play" aria-hidden="true"></i></a> 173 </div> 174 </div> 175 </div> 176 <!-- /top-links --> 177 <!-- logo--> 178 <!-- Logo + AdGroup16 (centered) --> 179<div class="row mb-3 align-items-center"> 180 <!-- Left section: Logo + Ad16 --> 181 <div class="col-md-12 text-center"> 182 <div class="mb-2"> 183 <div data-cms-el="logo">
183<script type="text/javascript" language="JavaScript">GetLogo();</script>
183</div> 184 </div> 185 <div> 186 <div data-cms-block="adgroup-16" data-cms-block-label="Advertisement 16" data-cms-el="adgroup" data-cms-adgroup="16">
186<script type="text/javascript" language="JavaScript">AdGroup16();</script>
186</div> 187 </div> 188 </div> 189 190 <!-- Right section: Ad29 --> 191 192</div> 193 194 195 <div class="row mb-3"> 196 <div class="col-12 px-0 d-flex justify-content-center border-top border-bottom border-2"> 197
197<script type="text/javascript" language="JavaScript"> 198 GetMenuH(); 199 </script>
199 200 </div> 201 </div> 202 <!-- /menu --> 203<div class="cus-column-133-row row mb-3 border-bottom"> 204 <div class="cus-column-133-1 col-lg-9 pe-lg-3"> 205<div data-cms-popup-root="1"><style> 206#CustomForm {background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='32' viewBox='0 0 16 32'%3E%3Cg fill='%23c9d1cb' fill-opacity='0.16'%3E%3Cpath fill-rule='evenodd' d='M0 24h4v2H0v-2zm0 4h6v2H0v-2zm0-8h2v2H0v-2zM0 0h4v2H0V0zm0 4h2v2H0V4zm16 20h-6v2h6v-2zm0 4H8v2h8v-2zm0-8h-4v2h4v-2zm0-20h-6v2h6V0zm0 4h-4v2h4V4zm-2 12h2v2h-2v-2zm0-8h2v2h-2V8zM2 8h10v2H2V8zm0 8h10v2H2v-2zm-2-4h14v2H0v-2zm4-8h6v2H4V4zm0 16h6v2H4v-2zM6 0h2v2H6V0zm0 24h2v2H6v-2z'/%3E%3C/g%3E%3C/svg%3E");background-attachment: fixed;} 207.form-check-label:hover {color: #0d6efd;cursor: pointer;} 208.cus-form-loader .cus-form-loading {display: block !important;} 209.cus-form-loader .formbody fieldset, .cus-form-loader .system_text.footer_text {opacity: 0.5;pointer-events: none;} 210#cus-form-button-loader {display:none;} 211.cus-form-loader footer, .cus-form-loader button {cursor: no-drop;} 212.fast-spin {-webkit-animation: fa-spin 1s infinite linear;animation: fa-spin 1s infinite linear;} 213.cus-form-loader #SUBMIT1 {display:none;} 214.cus-form-loader #cus-form-button-loader {display:inline-block;} 215.form-floating > .form-control:focus ~ label {color: #0d6efd !important;} 216.form-control:not(:disabled):not([readonly])::file-selector-button {position: absolute;right: 0;border-radius: 5px !important;} 217.input-file-preview {display: none;} 218.input-file-preview img {max-width: 30%;max-height: 200px;border: 1px solid #ced4da;border-radius: 5px;padding: 5px;box-sizing: border-box;cursor: zoom-in;} 219.w-96 {width: 96% !important;} 220.p-valid {color: green;} 221.p-valid:before {position: relative;left: -10px;content: "â";} 222.p-invalid {color: red;} 223.p-invalid:before {position: relative;left: -10px;content: "â";font-size: 0.875rem !important;} 224.open-eye, .close-eye {position: absolute;right: 2%;top: 50%;transform: translate(0,-50%);cursor: pointer;} 225.open-eye i:hover, .close-eye i:hover {color: gray !important;} 226.cus-form-help:before {content: "\f05a";font-family: FontAwesome;padding-left: 0.5rem;padding-right: 0.5rem;} 227.cus-form-help {display: none;} 228.cus-form-help:empty {display: none !important;} 229.form-control:focus ~ .cus-form-help {display: block;} 230.formdivider.formdivider_custom {border-left: 5px solid #ffc107;} 231.form-floating > .form-control {caret-color: #0d6efd;} 232</style> 233<style id="force-form-styles" data-version="2026-01-26-v2"> 234 textarea, textarea.form-control, textarea.formfieldinput { min-height: 120px !important; height: 120px !important; } 235 236 /* Enhanced Spinner Styles - More visible and animated */ 237 .form-spinner-ring { 238 display: inline-block; 239 width: 18px; 240 height: 18px; 241 border: 3px solid rgba(255,255,255,0.4); 242 border-top-color: #fff; 243 border-radius: 50%; 244 animation: formSpin 0.7s linear infinite; 245 margin-right: 8px; 246 vertical-align: middle; 247 } 248 @keyframes formSpin { 249 0% { transform: rotate(0deg); } 250 100% { transform: rotate(360deg); } 251 } 252 253 /* Submit Button Loading State */ 254 button.btn-loading, input.btn-loading { 255 position: relative; 256 pointer-events: none; 257 opacity: 0.85; 258 } 259 button.btn-loading::after { 260 content: ''; 261 position: absolute; 262 width: 18px; 263 height: 18px; 264 top: 50%; 265 left: 12px; 266 margin-top: -9px; 267 border: 3px solid rgba(255,255,255,0.4); 268 border-top-color: #fff; 269 border-radius: 50%; 270 animation: formSpin 0.7s linear infinite; 271 } 272 273 /* Form Overlay during submission */ 274 .form-loading-overlay { 275 position: absolute; 276 top: 0; 277 left: 0; 278 right: 0; 279 bottom: 0; 280 background: rgba(255,255,255,0.7); 281 display: flex; 282 align-items: center; 283 justify-content: center; 284 z-index: 9999; 285 border-radius: inherit; 286 } 287 .form-loading-overlay .spinner-container { 288 display: flex; 289 flex-direction: column; 290 align-items: center; 291 gap: 12px; 292 padding: 30px; 293 background: white; 294 border-radius: 12px; 295 box-shadow: 0 4px 20px rgba(0,0,0,0.15); 296 } 297 .form-loading-overlay .spinner-large { 298 width: 40px; 299 height: 40px; 300 border: 4px solid #e0e0e0; 301 border-top-color: #007bff; 302 border-radius: 50%; 303 animation: formSpin 0.8s linear infinite; 304 } 305 .form-loading-overlay .loading-text { 306 color: #333; 307 font-size: 14px; 308 font-weight: 500; 309 } 310 311 /* Bootstrap 5 Floating Label Fix - Force proper behavior */ 312 .form-floating > .form-control:focus ~ label, 313 .form-floating > .form-control:not(:placeholder-shown) ~ label, 314 .form-floating > .form-select ~ label { 315 opacity: 0.65 !important; 316 transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem) !important; 317 } 318 .form-floating > .form-control::placeholder { 319 color: transparent !important; 320 } 321 .form-floating > label { 322 position: absolute !important; 323 top: 0 !important; 324 left: 0 !important; 325 height: 100% !important; 326 padding: 1rem 0.75rem !important; 327 pointer-events: none !important; 328 border: 1px solid transparent !important; 329 transform-origin: 0 0 !important; 330 transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out !important; 331 } 332 </style> 333<style>.grecaptcha-badge{visibility:hidden!important;position:fixed!important;bottom:14px!important;right:14px!important;}</style>
334<script src="/iframe-resizer-master/js/iframeResizer.contentWindow.js"></script>
vendor: 1 bytes, line 334
334
335<script type="text/javascript" language="javascript" src="https://swvasun.com/lib/bl.js"></script>
vendor: 1 bytes, line 335
335
336<script> 337function ChangeInputFocus(obj, evt, cname) { 338/*if (evt.type == "focus") 339obj.className = cname; 340else if (evt.type == "blur") 341/*obj.className = cname;*/ 342} 343</script>
vendor: 1 bytes, line 343
343
344<script src="https://recaptcha.net/recaptcha/api.js?render=6LdXmfgUAAAAAJNuEHBxVCY0w9eA73hvaWsdgPlM"></script>
vendor: 1 bytes, line 344
344
345<script> 346(function(){ 347 function setToken(t){ 348 var els = document.querySelectorAll('.g-recaptcha-token'); 349 for (var i = 0; i < els.length; i++) els[i].value = t; 350 } 351 function refresh(){ 352 if (typeof grecaptcha === 'undefined') return; 353 grecaptcha.ready(function(){ 354 grecaptcha.execute('6LdXmfgUAAAAAJNuEHBxVCY0w9eA73hvaWsdgPlM', {action: 'submit'}).then(setToken); 355 }); 356 } 357 // Submit-time minter. Login pages call this in their submit handler and await it, 358 // so the request always carries a freshly-minted token instead of reading the 359 // pre-filled hidden field â which may still be empty when a user with saved 360 // credentials presses Enter before the page-load mint resolves (-> recaptcha_missing, 361 // a hard block). Resolves to a fresh token, or falls back to whatever's already in 362 // the field (and never hangs the form: 3s timeout, and resolves if grecaptcha is 363 // unavailable). Also updates the hidden field so FormData-based submits pick it up. 364 window.cmsMintCaptchaToken = function(){ 365 return new Promise(function(resolve){ 366 var els = document.querySelectorAll('.g-recaptcha-token'); 367 var fallback = (els[0] && els[0].value) || ''; 368 var done = false; 369 var to = setTimeout(function(){ if(!done){ done = true; resolve(fallback); } }, 3000); 370 function fin(v){ if(done) return; done = true; clearTimeout(to); setToken(v); resolve(v); } 371 function attempt(){ 372 if (typeof grecaptcha === 'undefined' || !grecaptcha.execute) return false; 373 try { 374 grecaptcha.ready(function(){ 375 grecaptcha.execute('6LdXmfgUAAAAAJNuEHBxVCY0w9eA73hvaWsdgPlM', {action: 'submit'}) 376 .then(function(t){ fin(t || fallback); }) 377 .catch(function(){ fin(fallback); }); 378 }); 379 return true; 380 } catch(_) { return false; } 381 } 382 // grecaptcha may still be loading -- common when the form is rendered 383 // inside a popup, where api.js was injected only moments ago. Poll until 384 // it's ready (or the 3s timeout fires) instead of bailing immediately. 385 if (!attempt()) { 386 var iv = setInterval(function(){ 387 if (done) { clearInterval(iv); return; } 388 if (attempt()) clearInterval(iv); 389 }, 150); 390 } 391 }); 392 }; 393 refresh(); 394 setTimeout(refresh, 5000); 395 setInterval(refresh, 120000); 396})(); 397</script>
397 398<div class="formbody"> 399<div class="body p-2"> 400<!--FormError--> 401<!--FormMessage--> 402<form class="custom-form p-3 mx-0 border rounded" enctype="multipart/form-data" autocomplete="off" id="CustomForm" method="post" name="CustomForm" onsubmit="return unifiedSubmitForm(event)"> 403<div aria-hidden="true" style="position:absolute;left:-9999px;top:-9999px;height:0;width:0;overflow:hidden;"> 404 <label for="website_url_hp">Website (leave blank)</label> 405 <input type="text" name="website_url" id="website_url_hp" tabindex="-1" autocomplete="off" value=""> 406</div> 407<input type="hidden" name="token" class="g-recaptcha-token" value=""> 408<!--FKeys--> 409<input type="hidden" name="SystemEmailSubject" value="SWVAsun.com: Online Newspaper Subscription"> 410<input type="hidden" name="SystemEmailConfirmMessage" value="Your message has been forwarded to appropriate personnel. Thank you."> 411<input type="hidden" name="SystemEmailFormat" value="HTML"> 412<input type="hidden" name="SystemEmailTo" value="[email protected]"> 413<input type="hidden" name="SystemEmailCC" value=""> 414<center class="fw-bold mb-3 fs-3 text-secondary">Free Online Newspaper Subscrption (VIA e-mail)</center> 415<fieldset> 416<div class="system_text Header_text mb-5 text-center"><html><head></head><body><html><head></head><center style="box-sizing: border-box; font-family: system-ui, -apple-system, " segoe="" ui",="" roboto,="" "="" helvetica="" neue",="" arial,="" noto="" sans",="" liberation="" sans-serif,="" apple="" color="" emoji",="" ui="" symbol",="" emoji";="" background-color:="" #ffffff;="" 1rem="" !important;="" font-size:="" calc(1.="" 3rem="" +="" 0.6vw)="" font-weight:="" 700="" color:="" #="" 6c757d="" !important;"=""><br /></center><fieldset style="box-sizing: border-box; color: #212529;" segoe="" ui",="" roboto,="" "="" helvetica="" neue",="" arial,="" noto="" sans",="" liberation="" sans-serif,="" apple="" color="" emoji",="" ui="" symbol",="" emoji";="" font-size:="" 16px;="" background-color:="" #ffffff;"=""><div style="box-sizing: border-box; text-align: center !important;"><h1 style="box-sizing: border-box; font-size: calc(1.375rem + 1.5vw);"><center style="box-sizing: border-box;"><u style="font-size: 18pt;"><span style="font-size: 14pt;">SWVAsun.com is your new online hometown newspaper.</span></u></center></h1><div><center style="box-sizing: border-box;"><u style="font-size: 18pt;"><span style="font-size: 14pt;"><strong></strong></span></u></center></div><br style="box-sizing: border-box;" /><center style="box-sizing: border-box;"></center></div></fieldset> 417<!-- Form Script v2026-01-26-v2 --> 418<!-- Modern Popup Modal for Messages --> 419<div id="form-message-modal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.7); z-index:99999; align-items:center; justify-content:center; padding:20px;"> 420 <div style="background:#fff; min-width:320px; max-width:400px; border-radius:12px; padding:24px; box-shadow:0 25px 50px -12px rgba(0,0,0,0.5);"> 421 <div id="form-message-text" style="margin-bottom:20px; font-size:15px; color:#333; text-align:center; line-height:1.5;"></div> 422 <button id="form-message-ok" style="width:100%; padding:12px 20px; font-size:14px; font-weight:600; background:#007bff; color:white; border:none; border-radius:8px; cursor:pointer; transition:all 0.2s ease;" onmouseover="this.style.background='#0056b3'" onmouseout="this.style.background='#007bff'">OK</button> 423 </div> 424</div> 425
426<script> 427// Resolve the URL to POST the form to. On a normal page load the form lives at 428// its own URL, so window.location.pathname is correct. But when the form is 429// opened inside a popup (sys-popup.js), the page URL is the HOST page, not the 430// form's URL -- sys-popup stamps the real form path onto the form as 431// data-form-action, which we prefer when present. 432function cmsResolvePostUrl(form) { 433 var f = form || document.querySelector('form'); 434 var a = f && f.getAttribute && f.getAttribute('data-form-action'); 435 return a || window.location.pathname; 436} 437 438// Modern message popup function 439// onClose callback is called when user clicks OK (useful for resetting button on error) 440function showFormMessage(text, isSuccess = false, onClose = null) { 441 const modal = document.getElementById('form-message-modal'); 442 const modalMsg = document.getElementById('form-message-text'); 443 const modalOk = document.getElementById('form-message-ok'); 444 445 if (modal && modalMsg && modalOk) { 446 modalMsg.innerHTML = isSuccess 447 ? '<div style="display:flex;align-items:center;justify-content:center;gap:12px;margin-bottom:20px;"><div style="width:50px;height:50px;background:linear-gradient(135deg,#28a745,#20c997);border-radius:50%;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 15px rgba(40,167,69,0.3);flex-shrink:0;"><span style="color:white;font-size:28px;font-weight:bold;">â</span></div><span style="color:#28a745;font-size:28px;font-weight:600;">Success</span></div>' + text 448 : text; 449 modal.style.display = 'flex'; 450 modalOk.onclick = function() { 451 modal.style.display = 'none'; 452 if (isSuccess) { 453 (window.top || window).location.href = '/'; 454 } else if (onClose) { 455 onClose(); 456 } 457 }; 458 // Also close on backdrop click 459 modal.onclick = function(e) { 460 if (e.target === modal) { 461 modal.style.display = 'none'; 462 if (isSuccess) { 463 (window.top || window).location.href = '/'; 464 } else if (onClose) { 465 onClose(); 466 } 467 } 468 }; 469 } else { 470 // Fallback to alert if modal not found 471 alert(text); 472 if (isSuccess) { 473 (window.top || window).location.href = '/'; 474 } else if (onClose) { 475 onClose(); 476 } 477 } 478} 479 480// Accept.js card input modal for Authorize.net 481async function showAcceptJsCardInput(clientConfig, form, originalFormData, paymentResult) { 482 console.log('[forms] Loading Accept.js for card tokenization'); 483 484 // Load Accept.js script dynamically 485 if (!window.Accept) { 486 await new Promise((resolve, reject) => { 487 const script = document.createElement('script'); 488 script.src = clientConfig.jsUrl; 489 script.onload = resolve; 490 script.onerror = () => reject(new Error('Failed to load Accept.js')); 491 document.head.appendChild(script); 492 }); 493 } 494 495 // Create card input modal 496 const modalHtml = ` 497 <div id="acceptjs-modal" style="position:fixed;inset:0;background:rgba(0,0,0,0.7);z-index:99999;display:flex;align-items:center;justify-content:center;padding:20px;"> 498 <div style="background:#fff;max-width:400px;width:100%;border-radius:12px;padding:30px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.5);"> 499 <h3 style="margin:0 0 20px;color:#333;">Payment Information</h3> 500 <p style="margin:0 0 20px;color:#666;">Amount: <strong>$${paymentResult.amount}</strong></p> 501 502 <div style="margin-bottom:15px;"> 503 <label style="display:block;margin-bottom:5px;font-weight:600;color:#333;">Card Number *</label> 504 <input type="text" id="ajs-card-number" placeholder="4111 1111 1111 1111" maxlength="19" 505 style="width:100%;padding:12px;border:1px solid #ccc;border-radius:4px;font-size:16px;box-sizing:border-box;"> 506 </div> 507 508 <div style="display:flex;gap:15px;margin-bottom:15px;"> 509 <div style="flex:1;"> 510 <label style="display:block;margin-bottom:5px;font-weight:600;color:#333;">Exp Month *</label> 511 <select id="ajs-exp-month" style="width:100%;padding:12px;border:1px solid #ccc;border-radius:4px;font-size:16px;"> 512 <option value="">MM</option> 513 ${[...Array(12)].map((_,i) => '<option value="'+String(i+1).padStart(2,'0')+'">'+String(i+1).padStart(2,'0')+'</option>').join('')} 514 </select> 515 </div> 516 <div style="flex:1;"> 517 <label style="display:block;margin-bottom:5px;font-weight:600;color:#333;">Exp Year *</label> 518 <select id="ajs-exp-year" style="width:100%;padding:12px;border:1px solid #ccc;border-radius:4px;font-size:16px;"> 519 <option value="">YYYY</option> 520 ${[...Array(15)].map((_,i) => { const y=new Date().getFullYear()+i; return '<option value="'+y+'">'+y+'</option>'; }).join('')} 521 </select> 522 </div> 523 <div style="width:100px;"> 524 <label style="display:block;margin-bottom:5px;font-weight:600;color:#333;">CVV *</label> 525 <input type="text" id="ajs-cvv" placeholder="123" maxlength="4" 526 style="width:100%;padding:12px;border:1px solid #ccc;border-radius:4px;font-size:16px;box-sizing:border-box;"> 527 </div> 528 </div> 529 530 <div id="ajs-error" style="color:#dc3545;margin-bottom:15px;
530display:none;"></div> 531 532 <div style="display:flex;gap:10px;"> 533 <button type="button" id="ajs-cancel" style="flex:1;padding:12px;background:#6c757d;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:16px;">Cancel</button> 534 <button type="button" id="ajs-submit" style="flex:1;padding:12px;background:#28a745;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:16px;">Pay Now</button> 535 </div> 536 </div> 537 </div> 538 `; 539 540 document.body.insertAdjacentHTML('beforeend', modalHtml); 541 542 const modal = document.getElementById('acceptjs-modal'); 543 const cardInput = document.getElementById('ajs-card-number'); 544 const cvvInput = document.getElementById('ajs-cvv'); 545 const errorDiv = document.getElementById('ajs-error'); 546 547 // Format card number 548 cardInput.addEventListener('input', function(e) { 549 let v = e.target.value.replace(/\s+/g, '').replace(/[^0-9]/g, ''); 550 let f = ''; 551 for (let i = 0; i < v.length; i++) { if (i > 0 && i % 4 === 0) f += ' '; f += v[i]; } 552 e.target.value = f; 553 }); 554 555 // Only numbers in CVV 556 cvvInput.addEventListener('input', function(e) { 557 e.target.value = e.target.value.replace(/[^0-9]/g, ''); 558 }); 559 560 // Cancel button - also reset the submit button 561 document.getElementById('ajs-cancel').onclick = function() { 562 modal.remove(); 563 // Reset the original form's submit button 564 const submitBtn = form.querySelector('button[type="submit"], #SUBMIT1, input[type="submit"]'); 565 if (submitBtn) { 566 submitBtn.disabled = false; 567 if (submitBtn.tagName === 'INPUT') { 568 submitBtn.value = 'Submit'; 569 } else { 570 submitBtn.innerHTML = 'Submit'; 571 } 572 } 573 }; 574 575 // Submit button 576 document.getElementById('ajs-submit').onclick = async function() { 577 const cardNumber = cardInput.value.replace(/\s+/g, ''); 578 const expMonth = document.getElementById('ajs-exp-month').value; 579 const expYear = document.getElementById('ajs-exp-year').value; 580 const cvv = cvvInput.value; 581 582 // Validate 583 if (!cardNumber || cardNumber.length < 13) { 584 errorDiv.textContent = 'Please enter a valid card number'; 585 errorDiv.style.display = 'block'; 586 return; 587 } 588 if (!expMonth || !expYear) { 589 errorDiv.textContent = 'Please select expiration date'; 590 errorDiv.style.display = 'block'; 591 return; 592 } 593 if (!cvv || cvv.length < 3) { 594 errorDiv.textContent = 'Please enter CVV'; 595 errorDiv.style.display = 'block'; 596 return; 597 } 598 599 errorDiv.style.display = 'none'; 600 this.disabled = true; 601 this.innerHTML = '<span class="form-spinner-ring" style="border-color:rgba(255,255,255,0.4);border-top-color:#fff;"></span> Processing...'; 602 603 // Test card detection - skip Accept.js tokenization 604 var TEST_CARDS_V3 = ['4111111111111111', '4000000000000000', '5500000000000004', '370000000000002', '6011000000000004']; 605 if (TEST_CARDS_V3.indexOf(cardNumber) !== -1) { 606 console.log('[forms] Test card detected - skipping tokenization'); 607 originalFormData.append('dataDescriptor', 'TEST_CARD'); 608 originalFormData.append('dataValue', 'TEST'); 609 originalFormData.append('pf-card-number-input', cardNumber); 610 611 try { 612 const testResp = await fetch(cmsResolvePostUrl(), { 613 method: 'POST', 614 body: originalFormData, 615 headers: { 'Accept': 'application/json' } 616 }); 617 const testResult = await testResp.json(); 618 modal.remove(); 619 if (testResult.success && testResult.isPaymentComplete) { 620 if (testResult.subscriberToken) { 621 try { 622 var tp2 = JSON.parse(atob(testResult.subscriberToken.split('.')[1])); 623 var ma2 = tp2.exp ? (tp2.exp - Math.floor(Date.now() / 1000)) : (30 * 24 * 60 * 60); 624 document.cookie = 'subscriber_token=' + encodeURIComponent(testResult.subscriberToken) + '; path=/; max-age=' + ma2 + '; SameSite=Lax'; 625 } catch (e) { /* ignore */ } 626 } 627 var msg = testResult.confirmMessage 628 ? testResult.confirmMessage + '<br><br><small>Transaction ID: ' + testResult.transactionId + '</small>' 629 : 'Test payment successful! Transaction ID: ' + testResult.transactionId; 630 var retUrl = null; 631 try { retUrl = localStorage.getItem('subscriber_return_url'); } catch (e) { /* ignore */ } 632 if (!retUrl) { try { retUrl = new URLSearchParams(window.location.search).get('return_url'); } catch (e) { /* ignore */ } } 633 if (retUrl) { 634 try { localStorage.removeItem('subscriber_return_url'); } catch (e) { /* ignore */ } 635 msg += '<p style="margin-top:15px;color:#666;">Redirecting you back to your article...</p>'; 636 showFormMessage(msg, true); 637 setTimeout(function() { window.location.href = retUrl; }, 2000); 638 } else { 639 showFormMessage(msg, true); 640 } 641 form.reset(); 642 } else { 643 showFormMessage(testResult.error || 'Payment failed.', false); 644 } 645 } catch (e) { 646 modal.remove(); 647 showFormMessage('Network error. Please try again.', false); 648 } 649 return; 650 } else { 651 // Build Accept.js request 652 const secureData = { 653 authData: { 654 clientKey: clientConfig.clientKey, 655 apiLoginID: clientConfig.apiLoginId 656 }, 657 cardData: { 658 cardNumber: cardNumber, 659 month: expMonth, 660 year: expYear, 661 cardCode: cvv 662 } 663 }; 664 665 // Tokenize via Accept.js 666 Accept.dispatchData(secureData, async function(response) { 667 if (response.messages.resultCode === 'Error') { 668 const errorText = response.messages.message.map(m => m.text).join(', '); 669 errorDiv.textContent = errorText; 670 errorDiv.style.display = 'block'; 671 const ajsBtn = document.getElementById('ajs-submit'); 672 ajsBtn.disabled = false;
673 ajsBtn.innerHTML = 'Pay Now'; 674 return; 675 } 676 677 console.log('[forms] Card tokenized successfully, resubmitting form'); 678 679 // Add token to form data and resubmit 680 originalFormData.append('dataDescriptor', response.opaqueData.dataDescriptor); 681 originalFormData.append('dataValue', response.opaqueData.dataValue); 682 683 try { 684 const response2 = await fetch(cmsResolvePostUrl(), { 685 method: 'POST', 686 body: originalFormData, 687 headers: { 'Accept': 'application/json' } 688 }); 689 const result2 = await response2.json(); 690 691 modal.remove(); 692 693 // Get the submit button to reset on error 694 const submitBtn = form.querySelector('button[type="submit"], #SUBMIT1, input[type="submit"]'); 695 const resetButton = function() { 696 if (submitBtn) { 697 submitBtn.disabled = false; 698 if (submitBtn.tagName === 'INPUT') { 699 submitBtn.value = 'Submit'; 700 } else { 701 submitBtn.innerHTML = 'Submit'; 702 } 703 } 704 }; 705 706 if (result2.success && result2.isPaymentComplete) { 707 // Auto-login: set subscriber_token cookie if provided 708 if (result2.subscriberToken) { 709 try { 710 var tp = JSON.parse(atob(result2.subscriberToken.split('.')[1])); 711 var ma = tp.exp ? (tp.exp - Math.floor(Date.now() / 1000)) : (30 * 24 * 60 * 60); 712 document.cookie = 'subscriber_token=' + encodeURIComponent(result2.subscriberToken) + '; path=/; max-age=' + ma + '; SameSite=Lax'; 713 console.log('[forms] Auto-login: subscriber_token cookie set (Accept.js path)'); 714 } catch (e) { console.warn('[forms] Auto-login cookie error', e); } 715 } 716 // Build success message with custom confirm message if available 717 let successMsg = 'Payment successful! Transaction ID: ' + result2.transactionId; 718 if (result2.confirmMessage) { 719 successMsg = result2.confirmMessage + '<br><br><small>Transaction ID: ' + result2.transactionId + '</small>'; 720 } 721 var retUrl2 = null; 722 try { retUrl2 = localStorage.getItem('subscriber_return_url'); } catch (e) { /* ignore */ } 723 if (!retUrl2) { try { retUrl2 = new URLSearchParams(window.location.search).get('return_url'); } catch (e) { /* ignore */ } } 724 if (retUrl2) { 725 try { localStorage.removeItem('subscriber_return_url'); } catch (e) { /* ignore */ } 726 successMsg += '<p style="margin-top:15px;color:#666;">Redirecting you back to your article...</p>'; 727 showFormMessage(successMsg, true); 728 setTimeout(function() { window.location.href = retUrl2; }, 2000); 729 } else { 730 showFormMessage(successMsg, true); 731 } 732 form.reset(); 733 } else { 734 showFormMessage(result2.error || 'Payment failed. Please try again.', false, resetButton); 735 } 736 } catch (e) { 737 modal.remove(); 738 const submitBtn = form.querySelector('button[type="submit"], #SUBMIT1, input[type="submit"]'); 739 showFormMessage('Network error. Please try again.', false, function() { 740 if (submitBtn) { 741 submitBtn.disabled = false; 742 if (submitBtn.tagName === 'INPUT') { 743 submitBtn.value = 'Submit'; 744 } else { 745 submitBtn.innerHTML = 'Submit'; 746 } 747 } 748 }); 749 } 750 }); 751 } // end else (real card tokenization) 752 }; 753} 754 755// Initialize File Uploader on load to handle image cropping/uploading. 756// Defined as a named function (not an inline DOMContentLoaded callback) so it can 757// also run immediately when the DOM is ALREADY parsed -- e.g. when this form is 758// injected into a popup after DOMContentLoaded has already fired. Without that, 759// the uploader (image cropper) never initializes inside the modal. 760async function cmsInitFormUploader() { 761 // Restore form data if user cancelled payment 762 try { 763 const pendingData = sessionStorage.getItem('_pendingFormData'); 764 if (pendingData) { 765 const formData = JSON.parse(pendingData); 766 const form = document.getElementById('CustomForm') || document.querySelector('form'); 767 if (form) { 768 for (const [key, value] of Object.entries(formData)) { 769 if (value && typeof value === 'string') { 770 const field = form.querySelector('[name="' + key + '"]'); 771 if (field) { 772 if (field.tagName === 'SELECT') { 773 field.value = value; 774 } else if (field.type !== 'file' && field.type !== 'hidden') { 775 field.value = value; 776 } 777 } 778 } 779 } 780 console.log('[forms] Restored form data from cancelled payment'); 781 } 782 // Clear the stored data 783 sessionStorage.removeItem('_pendingFormData'); 784 sessionStorage.removeItem('_pendingFormUrl'); 785 } 786 } catch (e) { 787 console.error('[forms] Error restoring form data:', e); 788 } 789 790 try { 791 const { UnifiedFileUploader } = await import('/sys-components-UnifiedFileUploader.js?v=' + Date.now()); 792 window.unifiedUploader = new UnifiedFileUploader(); 793 window.unifiedUploader.init(); 794 } catch (e) { 795 console.error('Failed to init uploader:', e); 796 } 797}
798// Normal page load: wait for DOMContentLoaded. Popup: the form is injected after 799// DOMContentLoaded already fired, so run immediately when the DOM is already 800// parsed -- otherwise the uploader (image cropper) never initializes in the 801// modal. The earlier empty-box / stuck-button symptom was FontAwesome 4 vs 6 802// (the FA6 spinner glyph was missing); the form now injects FA6, so the cropper 803// controls and spinner render and the uploader completes normally here too. 804if (document.readyState === 'loading') { 805 document.addEventListener('DOMContentLoaded', cmsInitFormUploader); 806} else { 807 cmsInitFormUploader(); 808} 809 810async function unifiedSubmitForm(event) { 811 console.log('[forms] unifiedSubmitForm called v5 - 2026-01-26 Enhanced spinner'); 812 if (event) { event.preventDefault(); event.stopPropagation(); } 813 814 // Use event.target if available (most reliable) 815 const form = (event && event.target && event.target.tagName === 'FORM') ? event.target : (document.getElementById('CustomForm') || document.querySelector('form')); 816 817 // Enforce native constraint validation (required / type=email / pattern ...) 818 // BEFORE anything else. This handler preventDefault()s the native submit on its 819 // first line, which also bypasses the browser's own required-field check -- so 820 // without this call a blank required field would fetch-POST straight through 821 // (legacy custom forms had no client-side guard at all). reportValidity() focuses 822 // the first invalid field, shows the browser's validation bubble, and bails. 823 // Runs before the submit button is put into its spinner/disabled state so a 824 // blocked submit leaves the form fully usable. 825 if (form && typeof form.reportValidity === 'function' && !form.reportValidity()) { 826 return false; 827 } 828 829 // Ensure any processed files are in the form before submission 830 if (window.unifiedUploader && window.unifiedUploader.ensureProcessedFilesInForm) { 831 window.unifiedUploader.ensureProcessedFilesInForm(); 832 } 833 834 const btn = form.querySelector('button[type="submit"], #SUBMIT1, input[type="submit"]'); 835 const originalHtml = btn ? (btn.tagName === 'INPUT' ? btn.value : btn.innerHTML) : 'Submit'; 836 837 // Show loading state with spinner 838 if (btn) { 839 btn.disabled = true; 840 if (btn.tagName === 'INPUT') { 841 // Inputs can't hold an inline span, so use the class-based ::after spinner. 842 btn.classList.add('btn-loading'); 843 btn.value = ' Processing...'; 844 btn.style.paddingLeft = '35px'; 845 } else { 846 // Buttons: the inline ring span is the single spinner. Do NOT add the 847 // btn-loading class here -- button.btn-loading::after renders a SECOND 848 // spinner, which produced two spinning icons at once on submit. Keep the 849 // disabled look via inline styles instead (robust even in popups where the 850 // injected spinner CSS may be absent). 851 btn.style.pointerEvents = 'none'; 852 btn.style.opacity = '0.85'; 853 btn.innerHTML = '<span class="form-spinner-ring"></span> Processing...'; 854 } 855 } 856 857 // Single spinner only: the disabled submit button already shows a spinner 858 // ("Processing..."), so we intentionally do NOT add the full-form overlay 859 // spinner here -- it produced two spinning icons at once (most visible in the 860 // popup). overlay stays null; the cleanup checks below are guarded for it. 861 let overlay = null; 862 try { 863 // Mint a fresh reCAPTCHA token before reading the form. On popup-rendered 864 // forms the on-load mint may not have fired yet (api.js was injected only 865 // moments ago by sys-popup's executeScripts), so without this the hidden 866 // token field is still empty and the server blocks as recaptcha_missing. 867 if (typeof window.cmsMintCaptchaToken === 'function') { 868 try { await window.cmsMintCaptchaToken(); } catch (e) {} 869 } 870 const formData = new FormData(form); 871 872 // Capture display TEXT for all select, radio, and checkbox elements 873 // Add as fieldname_text so email shows human-readable labels instead of raw values 874 form.querySelectorAll('select').forEach(function(select) { 875 if (select.name && select.selectedIndex >= 0) { 876 if (select.multiple) { 877 // Multi-select: join the text of EVERY selected option, not just the first 878 var multiTexts = Array.prototype.map.call(select.selectedOptions, function(o) { return o.text; }); 879 formData.append(select.name + '_text', multiTexts.join(', ')); 880 } else { 881 const selectedOption = select.options[select.selectedIndex]; 882 if (selectedOption) { 883 formData.append(select.name + '_text', selectedOption.text); 884 } 885 } 886 } 887 }); 888 // Capture checked radio button labels 889 var radiosDone = {}; 890 form.querySelectorAll('input[type="radio"]:checked').forEach(function(radio) { 891 if (radio.name && !radiosDone[radio.name]) { 892 radiosDone[radio.name] = true; 893 var label = form.querySelector('label[for="' + radio.id + '"]'); 894 if (label) { 895 formData.append(radio.name + '_text', label.textContent.trim()); 896 } 897 } 898 }); 899 // Capture checked checkbox labels 900 var checkboxTexts = {}; 901 form.querySelectorAll('input[type="checkbox"]:checked').forEach(function(cb) { 902 if (cb.name) { 903 var cleanName = cb.name.replace('[]', ''); 904 var label = form.querySelector('label[for="' + cb.id + '"]'); 905 var text = label ? label.textContent.trim() : (cb.value === 'on' ? 'Yes' : cb.value); 906 if (!checkboxTexts[cleanName]) checkboxTexts[cleanName] = []; 907 checkboxTexts[cleanName].push(text); 908 } 909 });
910 Object.keys(checkboxTexts).forEach(function(name) { 911 formData.append(name + '_text', checkboxTexts[name].join(', ')); 912 }); 913 const response = await fetch(cmsResolvePostUrl(form), { 914 method: 'POST', 915 body: formData, 916 headers: { 'Accept': 'application/json' } 917 }); 918 const result = await response.json(); 919 console.log('[forms] v3 Server response:', JSON.stringify(result)); 920 console.log('[forms] v3 Keys in result:', Object.keys(result).join(', ')); 921 console.log('[forms] v3 requiresCardInput:', result.requiresCardInput, 'clientConfig:', !!result.clientConfig); 922 console.log('[forms] v3 isPaymentRedirect:', result.isPaymentRedirect, 'redirectUrl:', result.redirectUrl); 923 if (result.success) { 924 // PRIORITY 0: Check if payment is already complete (Authorize.net Accept.js) 925 if (result.isPaymentComplete) { 926 console.log('[forms] Payment complete! Transaction:', result.transactionId); 927 928 // Auto-login: set subscriber_token cookie if provided 929 if (result.subscriberToken) { 930 try { 931 var tokenPayload = JSON.parse(atob(result.subscriberToken.split('.')[1])); 932 var maxAge = tokenPayload.exp ? (tokenPayload.exp - Math.floor(Date.now() / 1000)) : (30 * 24 * 60 * 60); 933 document.cookie = 'subscriber_token=' + encodeURIComponent(result.subscriberToken) + '; path=/; max-age=' + maxAge + '; SameSite=Lax'; 934 console.log('[forms] Auto-login: subscriber_token cookie set'); 935 } catch (e) { 936 console.warn('[forms] Auto-login: failed to set cookie', e); 937 } 938 } 939 940 // Build success message with custom confirm message if available 941 let successMsg = 'Payment successful! Transaction ID: ' + result.transactionId; 942 if (result.confirmMessage) { 943 successMsg = result.confirmMessage + '<br><br><small>Transaction ID: ' + result.transactionId + '</small>'; 944 } 945 946 // Redirect back to article if return URL is available (from paywall subscribe flow) 947 var returnUrl = null; 948 try { 949 returnUrl = localStorage.getItem('subscriber_return_url'); 950 } catch (e) { /* ignore */ } 951 // Also check URL query param 952 if (!returnUrl) { 953 try { 954 var params = new URLSearchParams(window.location.search); 955 returnUrl = params.get('return_url'); 956 } catch (e) { /* ignore */ } 957 } 958 959 if (returnUrl) { 960 try { localStorage.removeItem('subscriber_return_url'); } catch (e) { /* ignore */ } 961 // Show brief success message then redirect 962 successMsg += '<p style="margin-top:15px;color:#666;">Redirecting you back to your article...</p>'; 963 showFormMessage(successMsg, true); 964 setTimeout(function() { window.location.href = returnUrl; }, 2000); 965 } else { 966 showFormMessage(successMsg, true); 967 } 968 form.reset(); 969 return; 970 } 971 972 // PRIORITY 1: Check for payment redirect FIRST (Stripe Checkout) 973 // Payment forms MUST redirect to the payment gateway before showing any message 974 if (result.isPaymentRedirect && result.redirectUrl) { 975 console.log('[forms] Payment redirect detected, redirecting to:', result.redirectUrl); 976 window.location.href = result.redirectUrl; 977 return; 978 } 979 980 // PRIORITY 1.5: Check if card input is required (Authorize.net Accept.js)
981 console.log('[forms] v3 Checking requiresCardInput:', result.requiresCardInput, 'clientConfig exists:', !!result.clientConfig); 982 if (result.requiresCardInput && result.clientConfig) { 983 console.log('[forms] v3 Card input required! Showing Accept.js modal...'); 984 try { 985 await showAcceptJsCardInput(result.clientConfig, form, formData, result); 986 console.log('[forms] v3 showAcceptJsCardInput completed'); 987 } catch (modalError) { 988 console.error('[forms] v3 showAcceptJsCardInput error:', modalError); 989 } 990 return; 991 } 992 993 // PRIORITY 2: Check for regular redirect URL 994 if (result.redirectUrl && result.redirectUrl !== window.location.href) { 995 console.log('[forms] Redirecting to:', result.redirectUrl); 996 window.location.href = result.redirectUrl; 997 return; 998 } 999 1000 // PRIORITY 3: Show thanks content (email_confirm_message, etc.) 1001 if (result.thanksContent) { 1002 // CRITICAL: Scroll to top BEFORE replacing content to avoid layout shifts 1003 window.scrollTo({ top: 0, behavior: 'smooth' }); 1004 1005 // Check if standalone thank you page is requested 1006 if (result.standaloneThankYou) { 1007 // Replace entire page content with standalone thank you page 1008 document.body.innerHTML = '<div style="min-height:100vh;display:flex;align-items:center;justify-content:center;background:#f5f5f5;padding:20px;"><div style="max-width:800px;width:100%;background:#fff;border-radius:12px;box-shadow:0 4px 20px rgba(0,0,0,0.1);padding:40px;">' + result.thanksContent + '</div></div>'; 1009 window.scrollTo({ top: 0, behavior: 'instant' }); 1010 return; 1011 } 1012 1013 // Replace form content with thanks message (embedded mode) 1014 form.innerHTML = '<div id="form-thanks-message" style="padding:40px;text-align:center;min-height:200px">' + result.thanksContent + '</div>'; 1015 1016 // CRITICAL: Force scroll to top using multiple methods for maximum compatibility 1017 const forceScrollToTop = () => { 1018 console.log('[forms] Executing robust scroll-to-top'); 1019 1020 // 1. Standard window scroll 1021 window.scrollTo({ top: 0, behavior: 'smooth' }); 1022 1023 // 2. Element-based scroll (most reliable when embedded) 1024 const thanksEl = document.getElementById('form-thanks-message'); 1025 if (thanksEl) { 1026 thanksEl.scrollIntoView({ behavior: 'smooth', block: 'start' }); 1027 } 1028 1029 // 3. Recursive parent scroll (for nested scrollable containers) 1030 try { 1031 let parent = form.parentElement; 1032 while (parent && parent !== document.body) { 1033 if (parent.scrollHeight > parent.clientHeight) { 1034 console.log('[forms] Resetting parent scroll:', parent); 1035 parent.scrollTop = 0; 1036 } 1037 parent = parent.parentElement; 1038 } 1039 } catch (e) {} 1040 1041 // 4. Fallback for older/mobile browsers 1042 document.body.scrollTop = 0; 1043 document.documentElement.scrollTop = 0; 1044 1045 // 5. Hash trick to force top 1046 if (window.location.hash !== '') { 1047 window.location.hash = ''; 1048 } 1049 1050 // 6. If inside iframe, try to scroll parent window 1051 try { 1052 if (window.parent && window.parent !== window) { 1053 window.parent.scrollTo({ top: 0, behavior: 'smooth' }); 1054 } 1055 } catch (e) {} 1056 }; 1057 1058 // Execute in multiple phases to ensure layout is settled 1059 forceScrollToTop(); 1060 requestAnimationFrame(forceScrollToTop); 1061 setTimeout(forceScrollToTop, 100); 1062 setTimeout(forceScrollToTop, 500); 1063 setTimeout(forceScrollToTop, 1000); 1064 setTimeout(forceScrollToTop, 2000); 1065 } else { 1066 // Default: redirect to home 1067 window.location.href = "/"; 1068 } 1069 } else { 1070 // Remove overlay and reset button on error 1071 if (overlay && overlay.parentNode) overlay.remove(); 1072 showFormMessage(result.error || "Submission failed"); 1073 if (btn) { 1074 btn.disabled = false;
1075 btn.classList.remove('btn-loading'); 1076 btn.style.paddingLeft = ''; 1077 btn.style.pointerEvents = ''; 1078 btn.style.opacity = ''; 1079 if (btn.tagName === 'INPUT') { 1080 btn.value = originalHtml; 1081 } else { 1082 btn.innerHTML = originalHtml; 1083 } 1084 } 1085 } 1086 } catch (e) { 1087 console.error(e); 1088 // Remove overlay and reset button on network error 1089 if (overlay && overlay.parentNode) overlay.remove(); 1090 showFormMessage("Network error. Please check your connection and try again."); 1091 if (btn) { 1092 btn.disabled = false; 1093 btn.classList.remove('btn-loading'); 1094 btn.style.paddingLeft = ''; 1095 btn.style.pointerEvents = ''; 1096 btn.style.opacity = ''; 1097 if (btn.tagName === 'INPUT') { 1098 btn.value = originalHtml; 1099 } else { 1100 btn.innerHTML = originalHtml; 1101 } 1102 } 1103 } 1104 return false; 1105} 1106 1107// ========== STRIPE PAYMENT SUCCESS HANDLER ========== 1108// Check for payment success redirect from Stripe on page load 1109(function checkStripePaymentSuccess() { 1110 const urlParams = new URLSearchParams(window.location.search); 1111 const paymentStatus = urlParams.get('payment'); 1112 const sessionId = urlParams.get('session_id'); 1113 const returnUrl = urlParams.get('return_url'); 1114 1115 if (paymentStatus === 'success' && sessionId) { 1116 console.log('[forms] Detected Stripe payment success, session:', sessionId); 1117 console.log('[forms] Return URL:', returnUrl || 'none'); 1118 1119 // Show loading message 1120 showFormMessage('Processing payment confirmation...'); 1121 1122 // Fetch session details from our API 1123 fetch((typeof __CMS_BASE_PATH !== 'undefined' ? __CMS_BASE_PATH : '') + '/api/payment/session/' + encodeURIComponent(sessionId)) 1124 .then(response => response.json()) 1125 .then(data => { 1126 if (data.success) { 1127 const amount = data.amount ? '$' + parseFloat(data.amount).toFixed(2) : ''; 1128 const txId = data.transaction_id || sessionId; 1129 1130 // Build success message 1131 let msg = '<div style="margin-bottom:15px;font-size:16px;">Your subscription has been activated!</div>'; 1132 msg += '<div style="margin-bottom:15px;font-size:18px;font-weight:600;">Thank you for subscribing.</div>'; 1133 if (amount) { 1134 msg += '<div style="margin-bottom:10px;color:#666;">Amount: <strong>' + amount + '</strong></div>'; 1135 } 1136 if (data.description && data.description !== 'Payment') { 1137 msg += '<div style="margin-bottom:10px;color:#666;">Plan: <strong>' + data.description + '</strong></div>'; 1138 } 1139 msg += '<div style="background:#e8f5e9;padding:10px;border-radius:4px;margin-top:15px;"><strong>Transaction ID:</strong> <span style="font-family:monospace;user-select:all;">' + txId + '</span></div>'; 1140 1141 // If there's a return URL, add redirect notice 1142 if (returnUrl) { 1143 msg += '<div style="margin-top:15px;color:#666;font-size:14px;">Redirecting you back to your article in 3 seconds...</div>'; 1144 } 1145 1146 showFormMessage(msg, true); 1147 1148 // Clean up URL (remove query params) 1149 if (window.history && window.history.replaceState) { 1150 const cleanUrl = window.location.pathname; 1151 window.history.replaceState({}, document.title, cleanUrl); 1152 } 1153 1154 // Redirect to return URL after 3 seconds (back to the article) 1155 if (returnUrl) { 1156 setTimeout(function() { 1157 // Ensure return URL is same origin for security 1158 try { 1159 const returnUrlObj = new URL(returnUrl, window.location.origin); 1160 if (returnUrlObj.origin === window.location.origin) { 1161 window.location.href = returnUrl; 1162 } 1163 } catch (e) { 1164 // If it starts with /, treat as relative URL 1165 if (returnUrl.startsWith('/')) { 1166 window.location.href = returnUrl; 1167 } 1168 } 1169 }, 3000); 1170 } 1171 } else { 1172 showFormMessage('Payment was processed but we could not retrieve details. Your payment was successful.', true); 1173 // Still redirect if return URL exists 1174 if (returnUrl) { 1175 setTimeout(function() { window.location.href = returnUrl; }, 3000); 1176 } 1177 } 1178 }) 1179 .catch(err => { 1180 console.error('[forms] Error fetching session:', err); 1181 // Still show success even if API fails - payment went through 1182 showFormMessage('<div style="margin-bottom:15px;">Payment successful!</div><div style="background:#e8f5e9;padding:10px;border-radius:4px;"><strong>Session ID:</strong> <span style="font-family:monospace;">' + sessionId + '</span></div>', true); 1183 // Still redirect if return URL exists 1184 if (returnUrl) { 1185 setTimeout(function() { window.location.href = returnUrl; }, 3000); 1186 } 1187 }); 1188 } else if (paymentStatus === 'cancelled') { 1189 showFormMessage('Payment was cancelled. You can try again when ready.'); 1190 // Clean up URL 1191 if (window.history && window.history.replaceState) { 1192 const cleanUrl = window.location.pathname; 1193 window.history.replaceState({}, document.title, cleanUrl); 1194 } 1195 } 1196})(); 1197</script>
vendor: 1 bytes, line 1197
1197
1198<script> 1199// Form data restoration (runs on page load) - reads from COOKIE 1200(function() { 1201 console.log('[forms] Restoration script running...'); 1202 console.log('[forms] Current cookies:', document.cookie); 1203 try { 1204 var cookies = document.cookie.split('; '); 1205 var pendingCookie = null; 1206 for (var i = 0; i < cookies.length; i++) { 1207 if (cookies[i].indexOf('_pendingFormData=') === 0) { 1208 pendingCookie = cookies[i]; 1209 break; 1210 } 1211 } 1212 console.log('[forms] Found pending cookie:', !!pendingCookie); 1213 if (pendingCookie) { 1214 var cookieValue = pendingCookie.substring('_pendingFormData='.length); 1215 console.log('[forms] Cookie value length:', cookieValue.length); 1216 var formData = JSON.parse(decodeURIComponent(cookieValue)); 1217 console.log('[forms] Parsed form data:', Object.keys(formData)); 1218 var form = document.getElementById('CustomForm') || document.querySelector('form'); 1219 console.log('[forms] Found form:', !!form, form ? form.id : 'no id'); 1220 if (form) { 1221 Object.keys(formData).forEach(function(key) { 1222 var value = formData[key]; 1223 if (value && typeof value === 'string') { 1224 var field = form.querySelector('[name="' + key + '"]'); 1225 if (field) { 1226 console.log('[forms] Restoring field:', key, '=', value.substring(0, 20)); 1227 if (field.tagName === 'SELECT') { 1228 field.value = value; 1229 } else if (field.type !== 'file' && field.type !== 'hidden') { 1230 field.value = value; 1231 } 1232 // Trigger change event for floating labels 1233 field.dispatchEvent(new Event('input', { bubbles: true })); 1234 field.dispatchEvent(new Event('change', { bubbles: true })); 1235 } 1236 } 1237 }); 1238 console.log('[forms] Form data restored successfully'); 1239 } 1240 // Clear the cookies 1241 document.cookie = '_pendingFormData=; path=/; max-age=0'; 1242 document.cookie = '_pendingFormUrl=; path=/; max-age=0'; 1243 console.log('[forms] Cookies cleared'); 1244 } 1245 } catch (e) { 1246 console.error('[forms] Error restoring form data:', e); 1247 } 1248})(); 1249</script>
vendor: 1 bytes, line 1249
1249
1250<script> 1251(function(){ 1252 document.addEventListener('submit',function(e){ 1253 var form=e.target;if(!form||form.tagName!=='FORM')return; 1254 var btn=form.querySelector('button[type="submit"],input[type="submit"],.survey-btn-submit,#SUBMIT1'); 1255 if(!btn||btn.disabled)return; 1256 btn.disabled=true; 1257 if(btn.tagName==='INPUT'){btn.value=' Submitting...';} 1258 else{btn.innerHTML='<span class="form-submit-spinner"></span> Submitting...';} 1259 },true); 1260})(); 1261</script>
1261</body></html></div> 1262 1263 1264 1265<section class="w-96 mb-3" style="margin-left:2%" data-bs-toggle="tooltip" data-bs-placement="auto" title=""> 1266<div class="input w-100 form-floating"> 1267<INPUT NAME="Email" VALUE="" id="Email" maxlength="" placeholder=" " type="Email" class="formfieldinput formfieldinput_custom form-control" required> 1268<label for="Email" class="form-label text-muted">* Email</label> 1269</div> 1270</section> 1271 1272 1273 1274 1275</fieldset> 1276<footer class="text-center mt-3"> 1277<button class="button btn btn-primary shadow text-capitalize" id="SUBMIT1" type="submit" onclick="document.getElementById('CustomForm').classList.add('was-validated');"><span class="py-1 px-3 d-inline-block">submit</span></button> 1278<i id="cus-form-button-loader" class='fa fa-circle-o-notch fa-spin fast-spin fs-1 text-primary'></i> 1279</footer> 1280<div class="system_text footer_text mt-5 mb-3 text-center">
1280<script>document.querySelector("#Document") && document.querySelector("#Document").removeAttribute("accept");</script>
1280</div> 1281</form> 1282</div>
1283<script language="javascript">GetGoogleAnalytics('FORM:SWVAsun');</script>
1283 1284<!-- Tooltip -->
1285<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
vendor: 2 bytes, line 1285
1285
1286<script> 1287var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')) 1288var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) { 1289return new bootstrap.Tooltip(tooltipTriggerEl) 1290}) 1291</script>
1291 1292<!-- /Tooltip --> 1293</div> 1294</div> 1295<div class="w-100 d-block"><div data-cms-block="adgroup-30" data-cms-block-label="Advertisement 30" data-cms-el="adgroup" data-cms-adgroup="30">
1295<script type="text/javascript" language="JavaScript">AdGroup30();</script>
1295</div></div> 1296</div> 1297 <div class="cus-column-133-2 col-lg-3 ps-lg-3 border-start"> 1298 <div data-cms-block="adgroup-29" data-cms-block-label="Advertisement 29" data-cms-el="adgroup" data-cms-adgroup="29">
1298<script type="text/javascript" language="JavaScript">AdGroup29();</script>
1298</div><div data-cms-block="adgroup-20" data-cms-block-label="Advertisement 20" data-cms-el="adgroup" data-cms-adgroup="20">
1298<script type="text/javascript" language="JavaScript">AdGroup20();</script>
1298</div><div data-cms-block="poll-1" data-cms-block-label="Poll 1" data-cms-el="poll" data-poll-id="1">
1298<script type="text/javascript" language="JavaScript">GetPoll1();</script>
1298</div> 1299<div data-cms-block="section-file-29" data-cms-block-label="Section 29" data-cms-el="section" data-cms-section="29"><div class="cus-photogallery-133"> 1300 <div class="cus-default-menu-bar"> 1301 <div class="text-uppercase fw-bold px-0 mb-2 text-black cus-133-label"> 1302 <span> 1303 <span class="cus-default-submenu">Swva Sun Video</span> 1304 </span> 1305 </div> 1306 </div> 1307 <div class="row mx-0 hp-parent"> 1308 1309 <div class="col-sm-12 col-lg-4 px-1 mb-2 hpe-in-video-g-yt-id" data-article="15589" data-cms-article-id="15589" data-url="sun-spotlight-for-feb-p15589-29.htm" data-menu="GALLERY" data-submenu="Swva Sun Video" data-date="02_07_2026"> 1310 <div class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden"> 1311 <a class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden" href="javascript:void(0);" onclick="OpenYouTube(`https://open.substack.com/pub/swvasun/p/sun-spotlight-for-the-week-of-feb?r=7ctp54&utm_campaign=post&utm_medium=web&showWelcomeOnShare=true`.trim());"> 1312 <div class="ratio-16-9"> 1313 <div class="img-content cus-dark-img"> 1314 <img class="cus-videogallery-29-img img-fluid lazy loaded" src="https://img.youtube.com/vi/https://open.substack.com/pub/swvasun/p/sun-spotlight-for-the-week-of-feb?r=7ctp54&utm_campaign=post&utm_medium=web&showWelcomeOnShare=true/maxresdefault.jpg" data-body="https://open.substack.com/pub/swvasun/p/sun-spotlight-for-the-week-of-feb?r=7ctp54&utm_campaign=post&utm_medium=web&showWelcomeOnShare=true" data-src="/05-02-2026-01-26-25-pm-3456539.jpg" alt="Sun Spotlight for Feb. 1-7" data-was-processed="true" loading="lazy"> 1315 </div> 1316 </div> 1317 <span class="cus-videogallery-29-play position-absolute translate-middle top-50 start-50"> 1318 <i class="fa fa-play fs-1 text-white text-shadow-1" aria-hidden="true"></i> 1319 </span> 1320 <p class="cus-videogallery-29-heading mb-0 bg-dark text-white p-2 fs-6 lh-lg fw-bold" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="Sun Spotlight for Feb. 1-7"> 1321 <span class="line-1">Sun Spotlight for Feb. 1-7</span> 1322 </p> 1323 </a> 1324 </div> 1325 </div> 1326 1327 <div class="col-sm-12 col-lg-4 px-1 mb-2 hpe-in-video-g-yt-id" data-article="8871" data-cms-article-id="8871" data-url="wytheville-parks-and-rec-maroon-silver-vs-rural-retreat-black-p8871-29.htm" data-menu="GALLERY" data-submenu="Swva Sun Video" data-date="
132706_10_2024"> 1328 <div class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden"> 1329 <a class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden" href="javascript:void(0);" onclick="OpenYouTube(`-2rZwiaTiQ0`.trim());"> 1330 <div class="ratio-16-9"> 1331 <div class="img-content cus-dark-img"> 1332 <img class="cus-videogallery-29-img img-fluid lazy loaded" src="https://img.youtube.com/vi/-2rZwiaTiQ0/maxresdefault.jpg" data-body="-2rZwiaTiQ0" data-src="/10-06-2024-08-51-49-pm-2030388.jpg" alt="5/6/7 Wytheville Parks and Rec Maroon Silver vs. Rural Retreat Black" data-was-processed="true" loading="lazy"> 1333 </div> 1334 </div> 1335 <span class="cus-videogallery-29-play position-absolute translate-middle top-50 start-50"> 1336 <i class="fa fa-play fs-1 text-white text-shadow-1" aria-hidden="true"></i> 1337 </span> 1338 <p class="cus-videogallery-29-heading mb-0 bg-dark text-white p-2 fs-6 lh-lg fw-bold" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="5/6/7 Wytheville Parks and Rec Maroon Silver vs. Rural Retreat Black"> 1339 <span class="line-1">5/6/7 Wytheville Parks and Rec Maroon Silver vs. Rural Retreat Black</span> 1340 </p> 1341 </a> 1342 </div> 1343 </div> 1344 1345 <div class="col-sm-12 col-lg-4 px-1 mb-2 hpe-in-video-g-yt-id" data-article="111" data-cms-article-id="111" data-url="the-fourth-is-with-wytheville-p111-29.htm" data-menu="GALLERY" data-submenu="Swva Sun Video" data-date="
134504_22_2024"> 1346 <div class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden"> 1347 <a class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden" href="javascript:void(0);" onclick="OpenYouTube(`rnh5RDc7usk`.trim());"> 1348 <div class="ratio-16-9"> 1349 <div class="img-content cus-dark-img"> 1350 <img class="cus-videogallery-29-img img-fluid lazy loaded" src="https://img.youtube.com/vi/rnh5RDc7usk/maxresdefault.jpg" data-body="rnh5RDc7usk" data-src="/no-image.png" alt="The Fourth is with Wytheville" data-was-processed="true" loading="lazy"> 1351 </div> 1352 </div> 1353 <span class="cus-videogallery-29-play position-absolute translate-middle top-50 start-50"> 1354 <i class="fa fa-play fs-1 text-white text-shadow-1" aria-hidden="true"></i> 1355 </span> 1356 <p class="cus-videogallery-29-heading mb-0 bg-dark text-white p-2 fs-6 lh-lg fw-bold" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="The Fourth is with Wytheville"> 1357 <span class="line-1">The Fourth is with Wytheville</span> 1358 </p> 1359 </a> 1360 </div> 1361 </div> 1362 1363 <div class="col-sm-12 col-lg-4 px-1 mb-2 hpe-in-video-g-yt-id" data-article="112" data-cms-article-id="112" data-url="trail-talk-chasing-waterfalls-in-smyth-county-p112-29.htm" data-menu="GALLERY" data-submenu="Swva Sun Video" data-date="
136304_22_2024"> 1364 <div class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden"> 1365 <a class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden" href="javascript:void(0);" onclick="OpenYouTube(`UmbIwjjST8E`.trim());"> 1366 <div class="ratio-16-9"> 1367 <div class="img-content cus-dark-img"> 1368 <img class="cus-videogallery-29-img img-fluid lazy loaded" src="https://img.youtube.com/vi/UmbIwjjST8E/maxresdefault.jpg" data-body="UmbIwjjST8E" data-src="/no-image.png" alt="Trail Talk: Chasing Waterfalls in Smyth County" data-was-processed="true" loading="lazy"> 1369 </div> 1370 </div> 1371 <span class="cus-videogallery-29-play position-absolute translate-middle top-50 start-50"> 1372 <i class="fa fa-play fs-1 text-white text-shadow-1" aria-hidden="true"></i> 1373 </span> 1374 <p class="cus-videogallery-29-heading mb-0 bg-dark text-white p-2 fs-6 lh-lg fw-bold" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="Trail Talk: Chasing Waterfalls in Smyth County"> 1375 <span class="line-1">Trail Talk: Chasing Waterfalls in Smyth County</span> 1376 </p> 1377 </a> 1378 </div> 1379 </div> 1380 1381 <div class="col-sm-12 col-lg-4 px-1 mb-2 hpe-in-video-g-yt-id" data-article="62" data-cms-article-id="62" data-url="wytheville-nd-and-rd-grade-flag-football-p62-29.htm" data-menu="GALLERY" data-submenu="Swva Sun Video" data-date="
138104_15_2024"> 1382 <div class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden"> 1383 <a class="cus-videogallery-29-link position-relative d-block text-decoration-none border rounded overflow-hidden" href="javascript:void(0);" onclick="OpenYouTube(`DZXFNIbWTRQ`.trim());"> 1384 <div class="ratio-16-9"> 1385 <div class="img-content cus-dark-img"> 1386 <img class="cus-videogallery-29-img img-fluid lazy loaded" src="https://img.youtube.com/vi/DZXFNIbWTRQ/maxresdefault.jpg" data-body="DZXFNIbWTRQ" data-src="/no-image.png" alt="Wytheville 2nd and 3rd Grade Flag Football" data-was-processed="true" loading="lazy"> 1387 </div> 1388 </div> 1389 <span class="cus-videogallery-29-play position-absolute translate-middle top-50 start-50"> 1390 <i class="fa fa-play fs-1 text-white text-shadow-1" aria-hidden="true"></i> 1391 </span> 1392 <p class="cus-videogallery-29-heading mb-0 bg-dark text-white p-2 fs-6 lh-lg fw-bold" data-bs-toggle="tooltip" data-bs-placement="bottom" title="" data-bs-original-title="Wytheville 2nd and 3rd Grade Flag Football"> 1393 <span class="line-1">Wytheville 2nd and 3rd Grade Flag Football</span> 1394 </p> 1395 </a> 1396 </div> 1397 </div> 1398 1399 </div> 1400</div> 1401<style> 1402@import url("https://fonts.googleapis.com/css2?family=PT+Sans:wght@700&display=swap"); 1403 1404.cus-29-label { 1405 font-family: pt sans, sans-serif; 1406 border-bottom: 4px solid #bdcde3; 1407} 1408 1409.cus-29-label>span { 1410 position: relative; 1411} 1412 1413.cus-29-label>span:before { 1414 background: #dc3545; 1415 position: absolute; 1416 display: inline-block; 1417 content: ""; 1418 width: 100%; 1419 height: 4px; 1420 bottom: -6px; 1421} 1422 1423.cus-videogallery-29-link:hover .cus-videogallery-29-play i { 1424 transform: scale(1.2); 1425 transition: 200ms linear; 1426} 1427 1428.cus-videogallery-29-play i { 1429 transition: 100ms linear; 1430} 1431</style>
1432<script> 1433/* SubMenu Title */ 1434if (ReadSubmenu() == 29) { 1435 document.title = "Swva Sun Video"; 1436} /* If Full URL used instead of just ID*/ 1437var vu = document.getElementsByClassName("cus-videogallery-29-img"); 1438for (i = 0; i < vu.length; i++) { 1439 if (vu[i].src.split("http").length > 2) { 1440 /*Full URL*/ 1441 var tu = vu[i].getAttribute("data-body"); 1442 if (tu.indexOf("embed") != -1 && tu.indexOf("you") != -1) { 1443 /*YouTube*/ 1444 tu = tu.split("/")[4].slice(0, 11); 1445 vu[i].src = `https://img.youtube.com/vi/${tu}/maxresdefault.jpg`; 1446 } else if (tu.indexOf("watch") != -1 && tu.indexOf("you") != -1) { 1447 /*YouTube*/ 1448 var bx = new URL(tu); 1449 tu = bx.searchParams.get(`v`).slice(0, 11); 1450 vu[i].src = `https://img.youtube.com/vi/${tu}/maxresdefault.jpg`; 1451 } else if (tu.indexOf("vimeo") != -1 && tu.indexOf("player.vimeo") == -1) { 1452 /*Vimeo*/ 1453 tu = tu.split("/")[3]; 1454 vu[i].src = `https://vumbnail.com/${tu}.jpg`; 1455 } else { 1456 /*Other*/ 1457 vu[i].src = vu[i].getAttribute("data-src"); 1458 } 1459 } 1460} 1461 1462function OpenYouTube(id) { 1463 if (!document.getElementById('f_YT_button')) { 1464 if (id.indexOf("/") != -1) { 1465 /*Full URL*/ 1466 if (id.indexOf("embed") != -1 && tu.indexOf("you") != -1) { 1467 /*Youtube Video*/ 1468 id = id.split("/")[4].slice(0, 11); 1469 var msg = `<iframe id="f-mfp-iframe" class="f-mfp-iframe" allowfullscreen="" src="https://www.youtube.com/embed/${id}?autoplay=1" scrolling="no" frameborder="0"></iframe>`; 1470 } else if (id.indexOf("watch") != -1 && tu.indexOf("you") != -1) { 1471 /*Youtube Video*/ 1472 var bx = new URL(id); 1473 id = bx.searchParams.get(`v`).slice(0, 11); 1474 var msg = `<iframe id="f-mfp-iframe" class="f-mfp-iframe" allowfullscreen="" src="https://www.youtube.com/embed/${id}?autoplay=1" scrolling="no" frameborder="0"></iframe>`; 1475 } else if (id.indexOf("vimeo") != -1 && id.indexOf("player.vimeo") == -1) { 1476 /*Vimeo Video*/ 1477 id = id.split("/")[3]; 1478 var msg = `<iframe id="f-mfp-iframe" class="f-mfp-iframe" allowfullscreen="" src="https://player.vimeo.com/video/${id}?autoplay=1" scrolling="no" frameborder="0"></iframe>`; 1479 } else { 1480 /*Other Video*/ 1481 var msg = `<iframe id="f-mfp-iframe" class="f-mfp-iframe" allowfullscreen="" src="${id}?autoplay=1" scrolling="no" frameborder="0"></iframe>`; 1482 } 1483 } else { 1484 var msg = `<iframe id="f-mfp-iframe" class="f-mfp-iframe" allowfullscreen="" src="https://www.youtube.com/embed/${id}?autoplay=1" scrolling="no" frameborder="0"></iframe>`; 1485 } 1486 document.getElementsByTagName("body")[0].insertAdjacentHTML(`beforeend`, `<button id='f_YT_button' type='button' data-bs-toggle='modal' data-bs-target='#f_YT' style='display:none;'></button><div class='f_YT_box modal fade' id='f_YT' data-bs-backdrop='static' data-bs-keyboard='false' tabindex='-1' aria-labelledby='f_YTLabel' aria-hidden='true'><div class='modal-dialog modal-dialog-centered mx-auto'><div class='modal-content' id='YT_parent'><button type='button' class='f_YT_close btn-close position-absolute' data-bs-dismiss='modal' aria-label='Close'><svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='#fff' class='bi bi-x-lg' viewBox='0 0 16 16'><path d='M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z'/></svg></button><div class='modal-body text-center' style='white-space: pre-wrap;'><p id='f_loader'><i class='fa fa-spinner fa-spin' aria-hidden='true'></i></p>${msg}</div></div></div><style>#YT_parent{width:70vw;height:39.43vw}.modal-dialog{max-width:none;display:flex;align-items:center;justify-content:center}
1486.modal-dialog-scrollable .modal-content {max-height: none;overflow:visible;}.modal-body {padding:0;} .f_YT_close{right:-1rem;z-index:999;top:-1rem;background-color:red;border-radius:50px;padding:.5rem;opacity:1;box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.2);background-image:none;color:#fff;display:flex;justify-content:center;align-items:center;font-weight:700;font-size:18px}.f_YT_close:hover{color:#fff;background-color: #333;opacity:1} .f-mfp-iframe {width:100%;height:100%;}#f_loader{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%)}#f_loader i{font-size:4rem;color:red;opacity:0.8}@media (max-width:576px){#YT_parent{width:85vw;height:48vw}}</style></div>`); 1487 document.getElementById('f-mfp-iframe').onload = function () { 1488 document.getElementById("f_loader").remove(); 1489 }; 1490 document.getElementById('f_YT_button').click(); 1491 document.getElementsByClassName('f_YT_close')[0].addEventListener('click', function () { 1492 document.getElementById('f_YT_button').remove(); 1493 document.getElementsByClassName('f_YT_box')[0].remove(); 1494 }); 1495 } 1496} 1497</script>
1497</div> 1498 <div data-cms-block="adgroup-11" data-cms-block-label="Advertisement 11" data-cms-el="adgroup" data-cms-adgroup="11">
1498<script type="text/javascript" language="JavaScript">AdGroup11();</script>
1498</div> 1499 <div data-cms-block="adgroup-28" data-cms-block-label="Advertisement 28" data-cms-el="adgroup" data-cms-adgroup="28">
1499<script type="text/javascript" language="JavaScript">AdGroup28();</script>
1499</div> 1500 <div data-cms-block="adgroup-13" data-cms-block-label="Advertisement 13" data-cms-el="adgroup" data-cms-adgroup="13">
1500<script type="text/javascript" language="JavaScript">AdGroup13();</script>
1500</div> 1501 </div> 1502</div> 1503 1504<footer class="row py-3 mt-3" style="border-top: 2px dotted #dedede; color: #000;"> 1505 <div class="col-3 cus-social-links d-flex justify-content-left position-relative mb-2"> 1506 <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://www.facebook.com/swvasun/" target="_blank"><i class="fa fa-facebook-square" aria-hidden="true"></i></a> 1507 <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://twitter.com/swvasun" target="_blank"><svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-twitter-x" viewBox="0 0 16 16" style="padding: 3px;background: #212529;fill: #fff;border-radius: 4px;display: inline-block;transform: translateY(-2px);" width="20" height="22"><path d="M12.6.75h2.454l-5.36 6.142L16 15.25h-4.937l-3.867-5.07-4.425 5.07H.316l5.733-6.57L0 .75h5.063l3.495 4.633L12.601.75Zm-.86 13.028h1.36L4.323 2.145H2.865z"></path></svg></a> 1508 <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://www.linkedin.com/company/swva-media-llc/" target="_blank"><i class="fa fa-linkedin-square" aria-hidden="true"></i></a> 1509 <a class="text-decoration-none text-dark rounded ms-3 fs-4 d-inline-block lh-1 cus-social-1-133-icon" href="https://youtube.com/@southwestvirginiasun8601" target="_blank"><i class="fa fa-youtube-play" aria-hidden="true"></i></a> 1510 </div> 1511 <div class="col-lg-8 col-12 position-relative mb-2"> 1512<div class="col-12 ms-4">Swva Media is a proud member of the following organizations:</div> 1513<div class="col-12"> <div data-cms-block="adgroup-21" data-cms-block-label="Advertisement 21" data-cms-el="adgroup" data-cms-adgroup="21">
1513<script type="text/javascript" language="JavaScript">AdGroup21();</script>
1513</div></div> 1514 </div> 1515 <div class="col-12 d-flex justify-content-center position-relative mb-2"> 1516 <div data-cms-block="section-4" data-cms-block-label="Section 4" data-cms-el="section" data-cms-section="4">
1516<script type="text/javascript">Section4();</script>
1516</div> 1517 </div> 1518 <div class="col-12 d-flex justify-content-center position-relative mb-2">
1519<script type="text/javascript">Section5();</script>
1519 1520 </div> 1521</footer> 1522 1523 1524 </div> 1525 </div> 1526 <!-- go to top --> 1527 <div class="cus-scroll-top position-fixed end-0 bg-dark text-white fs-4 px-2" style="cursor: pointer;bottom: auto;transition: 400ms linear;" data-bs-toggle="tooltip" data-bs-placement="top" title="Go to top"><i class="fa fa-angle-up"></i></div> 1528
1528<script> 1529 if (document.getElementsByClassName("cus-scroll-top")) { 1530 window.addEventListener("scroll", function() { 1531 if (document.body.scrollTop > 600 || document.documentElement.scrollTop > 600) { 1532 document.getElementsByClassName('cus-scroll-top')[0].style.bottom = 0; 1533 } else { 1534 document.getElementsByClassName('cus-scroll-top')[0].style.bottom = "-100px"; 1535 } 1536 }); 1537 document.getElementsByClassName('cus-scroll-top')[0].addEventListener('click', function() { 1538 window.scrollTo(0, 0); 1539 }); 1540 } 1541 </script>
1541 1542 <!-- /go to top --> 1543 <div class="cus-g-analytics-133">
1543<script language="javascript">GetGoogleAnalytics('');</script>
1543</div> 1544 <!-- tooltip --> 1545
1545<script> 1546 var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')) 1547 var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) { 1548 return new bootstrap.Tooltip(tooltipTriggerEl) 1549 }); 1550 </script>
1550 1551 <!-- /tooltip -->
1552<script defer src="/sys-popup.js?v=1790187371"></script>
1552</body> 1553<!--Template-130--> 1554 1555</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.