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